欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 旅游 > Skia使用Dawn后端在Windows窗口中绘图

Skia使用Dawn后端在Windows窗口中绘图

2025/2/23 13:37:59 来源:https://blog.csdn.net/liulun/article/details/145342491  浏览:    关键词:Skia使用Dawn后端在Windows窗口中绘图

首先创建一个Windows窗口,如下代码所示:

void WindowMain::createWindow()
{static bool isWcexReg = false;static const TCHAR clsName[] = L"SkiaApp";static WNDCLASSEX wcex;auto hinstance = GetModuleHandle(NULL);if (!isWcexReg) {wcex.cbSize = sizeof(WNDCLASSEX);wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;wcex.lpfnWndProc = &WindowMain::wndProc;wcex.cbClsExtra = 0;wcex.cbWndExtra = 0;wcex.hInstance = hinstance;wcex.hIcon = LoadIcon(hinstance, IDI_APPLICATION);wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);wcex.lpszMenuName = nullptr;wcex.lpszClassName = clsName;wcex.hIconSm = LoadIcon(hinstance, IDI_APPLICATION);if (!RegisterClassEx(&wcex)) {return;}isWcexReg = true;}hwnd = CreateWindowEx(NULL, clsName, clsName, WS_OVERLAPPEDWINDOW,x, y, w, h, nullptr, nullptr, hinstance, nullptr);SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);
}

接着创建Dawn实例:

void WindowMain::initDawnInstance()
{WGPUInstanceDescriptor desc{};desc.features.timedWaitAnyEnable = true;dawnInstance = std::make_unique<dawn::native::Instance>(&desc);
}

然后创建Dawn设备:

void WindowMain::initDawnDevice()
{DawnProcTable backendProcs = dawn::native::GetProcs();dawnProcSetProcs(&backendProcs);static constexpr const char* kToggles[] = {"allow_unsafe_apis","use_user_defined_labels_in_backend","disable_robustness", //禁用这玩意儿,提升性能"use_tint_ir",};wgpu::DawnTogglesDescriptor togglesDesc;togglesDesc.enabledToggleCount = std::size(kToggles) - 1;togglesDesc.enabledToggles = kToggles;wgpu::RequestAdapterOptions adapterOptions;adapterOptions.backendType = wgpu::BackendType::D3D11;adapterOptions.featureLevel = wgpu::FeatureLevel::Core;adapterOptions.nextInChain = &togglesDesc;std::vector<dawn::native::Adapter> adapters = dawnInstance->EnumerateAdapters(&adapterOptions);if (adapters.empty()) {return;}wgpu::Adapter adapter = adapters[0].Get();std::vector<wgpu::FeatureName> features;if (adapter.HasFeature(wgpu::FeatureName::MSAARenderToSingleSampled)) {features.push_back(wgpu::FeatureName::MSAARenderToSingleSampled);}if (adapter.HasFeature(wgpu::FeatureName::TransientAttachments)) {features.push_back(wgpu::FeatureName::TransientAttachments);}if (adapter.HasFeature(wgpu::FeatureName::Unorm16TextureFormats)) {features.push_back(wgpu::FeatureName::Unorm16TextureFormats);}if (adapter.HasFeature(wgpu::FeatureName::DualSourceBlending)) {features.push_back(wgpu::FeatureName::DualSourceBlending);}if (adapter.HasFeature(wgpu::FeatureName::FramebufferFetch)) {features.push_back(wgpu::FeatureName::FramebufferFetch);}if (adapter.HasFeature(wgpu::FeatureName::BufferMapExtendedUsages)) {features.push_back(wgpu::FeatureName::BufferMapExtendedUsages);}if (adapter.HasFeature(wgpu::FeatureName::TextureCompressionETC2)) {features.push_back(wgpu::FeatureName::TextureCompressionETC2);}if (adapter.HasFeature(wgpu::FeatureName::TextureCompressionBC)) {features.push_back(wgpu::FeatureName::TextureCompressionBC);}if (adapter.HasFeature(wgpu::FeatureName::R8UnormStorage)) {features.push_back(wgpu::FeatureName::R8UnormStorage);}if (adapter.HasFeature(wgpu::FeatureName::DawnLoadResolveTexture)) {features.push_back(wgpu::FeatureName::DawnLoadResolveTexture);}if (adapter.HasFeature(wgpu::FeatureName::DawnPartialLoadResolveTexture)) {features.push_back(wgpu::FeatureName::DawnPartialLoadResolveTexture);}wgpu::DeviceDescriptor deviceDescriptor;deviceDescriptor.requiredFeatures = features.data();deviceDescriptor.requiredFeatureCount = features.size();deviceDescriptor.nextInChain = &togglesDesc;deviceDescriptor.SetDeviceLostCallback(wgpu::CallbackMode::AllowSpontaneous,[](const wgpu::Device&, wgpu::DeviceLostReason reason, const char* message) {if (reason != wgpu::DeviceLostReason::Destroyed &&reason != wgpu::DeviceLostReason::InstanceDropped) {SK_ABORT("Device lost: %s\n", message);}});deviceDescriptor.SetUncapturedErrorCallback([](const wgpu::Device&, wgpu::ErrorType, const char* message) {SkDebugf("Device error: %s\n", message);SkASSERT(false);});dawnDevice = adapter.CreateDevice(&deviceDescriptor);
}

然后创建Dawn表面(注意,dawnSurface不是Skia的SkSurface)

void WindowMain::initDawnSurface()
{wgpu::SurfaceDescriptorFromWindowsHWND surfaceChainedDesc;surfaceChainedDesc.hwnd = hwnd;surfaceChainedDesc.hinstance = GetModuleHandle(nullptr);wgpu::SurfaceDescriptor surfaceDesc;surfaceDesc.nextInChain = &surfaceChainedDesc;dawnSurface = wgpu::Instance(dawnInstance->Get()).CreateSurface(&surfaceDesc);
}

然后创建绘图上下文和Recorder

void WindowMain::initGraphite()
{skgpu::graphite::DawnBackendContext backendContext;backendContext.fInstance = wgpu::Instance(dawnInstance->Get());backendContext.fDevice = dawnDevice;backendContext.fQueue = dawnDevice.GetQueue();skgpu::graphite::ContextOptions fContextOptions;graphiteContext = skgpu::graphite::ContextFactory::MakeDawn(backendContext, fContextOptions);if (!graphiteContext) {SkASSERT(false);return;}graphiteRecorder = graphiteContext->makeRecorder();
}

然后配置Dawn表面(改变窗口大小时,也得调用这个方法)

void WindowMain::configSurface()
{    wgpu::SurfaceConfiguration config;config.device = dawnDevice;config.format = surfaceFormat;config.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding |wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst;config.width = w;config.height = h;//wgpu::PresentMode::Immediate 立即渲染会撕裂//wgpu::PresentMode::Fifo 渲染的帧内容会进入一个 FIFO(先进先出)队列,等待显示器的垂直同步信号(VSync)后再显示到屏幕上。config.presentMode = wgpu::PresentMode::Fifo;dawnSurface.Configure(&config);
}

在窗口中绘图:

case WM_PAINT:{PAINTSTRUCT ps;BeginPaint(hWnd, &ps);auto surface = win->getSurface();win->paint(surface->getCanvas());win->flush();EndPaint(hWnd, &ps);return 0;
}

每次绘图都要重新获取Skia的Surface 

sk_sp<SkSurface> WindowMain::getSurface()
{wgpu::SurfaceTexture surfaceTexture;dawnSurface.GetCurrentTexture(&surfaceTexture);auto texture = surfaceTexture.texture;skgpu::graphite::DawnTextureInfo info(1,skgpu::Mipmapped::kNo, surfaceFormat, wgpu::TextureUsage::None, wgpu::TextureAspect::All);auto backendTex = skgpu::graphite::BackendTextures::MakeDawn(texture.Get());auto surface = SkSurfaces::WrapBackendTexture(graphiteRecorder.get(),backendTex, kBGRA_8888_SkColorType, displayParams.fColorSpace, &displayParams.fSurfaceProps);return surface;
}

下面是绘图逻辑: 

void WindowMain::paint(SkCanvas* canvas)
{canvas->clear(0xFFFFFFFF);SkPaint paint;paint.setColor(SK_ColorRED);SkRect rect = SkRect::MakeXYWH(w - 150, h - 150, 140, 140);canvas->drawRect(rect, paint);
}

最后把绘图内容同步到窗口中

void WindowMain::flush()
{std::unique_ptr<skgpu::graphite::Recording> recording = graphiteRecorder->snap();if (recording) {skgpu::graphite::InsertRecordingInfo info;info.fRecording = recording.get();graphiteContext->insertRecording(info);graphiteContext->submit(skgpu::graphite::SyncToCpu::kNo);}dawnSurface.Present();
}

这个示例代码有一个小问题,就是改变窗口大小时,窗口画面更新不流畅,如下图所示:

目前我还没找到好得解决办法,希望懂的老师不吝赐教,必有重谢。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词