The readback of the pixels show that the rendertarget is properly filled after a few iterations. However, when I implemented render to an existing texture , for some reason, I need to call
asyncRescaleAndReadPixels after the draw call otherwise the texture is not updated. Any pointer on that? I tried pushing a backendfence to the queue to no avail.
Here is the graphite+dawn code, for which I didn't manage to get a working render :
dawnProcSetProcs(&dawn::native::GetProcs());
Context = new webgpuContext();
std::vector<const char*> enableToggleNames;
enableToggleNames.reserve(1);
std::vector<const char*> disabledToggleNames;
disabledToggleNames.reserve(1);
wgpu::DawnTogglesDescriptor toggles;
toggles.enabledToggles = enableToggleNames.data();
toggles.enabledToggleCount = enableToggleNames.size();
toggles.disabledToggles = disabledToggleNames.data();
toggles.disabledToggleCount = disabledToggleNames.size();
wgpu::InstanceDescriptor instanceDescriptor{};
instanceDescriptor.nextInChain = &toggles;
instanceDescriptor.capabilities.timedWaitAnyEnable = true;
Context->Instance = wgpu::CreateInstance(&instanceDescriptor);
if (Context->Instance == nullptr) {
//UE_LOG(SkiaIntegration, Error, TEXT("dawn webgpu Instance creation failed!"));
return;
}
// Synchronously request the adapter.
wgpu::RequestAdapterOptions reqAdapterOptions = {};
//reqAdapterOptions.backendType = wgpu::BackendType::D3D12;
reqAdapterOptions.backendType = wgpu::BackendType::D3D12;
auto callback = [](wgpu::RequestAdapterStatus status, wgpu::Adapter adapter, const char* message, void* userdata) {
if (status != wgpu::RequestAdapterStatus::Success) {
//UE_LOG(SkiaIntegration, Error, TEXT("dawn webgpu Failed to get an adapter:%s"), UTF8_TO_TCHAR(message));
return;
}
*static_cast<wgpu::Adapter*>(userdata) = adapter;
};
auto callbackMode = wgpu::CallbackMode::WaitAnyOnly;
void* userdata = &Context->Adapter;
Context->Instance.WaitAny(Context->Instance.RequestAdapter(&reqAdapterOptions, callbackMode, callback, userdata), UINT64_MAX);
if (Context->Adapter == nullptr) {
//UE_LOG(SkiaIntegration, Error, TEXT("dawn webgpu RequestAdapter failed!"));
return;
}
wgpu::DawnAdapterPropertiesPowerPreference power_props{};
wgpu::AdapterInfo info{};
info.nextInChain = &power_props;
Context->Adapter.GetInfo(&info);
std::vector<wgpu::FeatureName> requiredFeatures = {
wgpu::FeatureName::SharedTextureMemoryDXGISharedHandle,
wgpu::FeatureName::SharedFenceDXGISharedHandle,
wgpu::FeatureName::DawnInternalUsages,
wgpu::FeatureName::FlexibleTextureViews,
wgpu::FeatureName::Snorm16TextureFormats,
wgpu::FeatureName::Unorm16TextureFormats
};
wgpu::DeviceDescriptor deviceDescriptor;
deviceDescriptor.requiredFeatures = requiredFeatures.data();
deviceDescriptor.requiredFeatureCount = requiredFeatures.size();
deviceDescriptor.SetUncapturedErrorCallback([](const wgpu::Device&, wgpu::ErrorType type, wgpu::StringView message) {
//UE_LOG(SkiaIntegration, Error, TEXT("dawn error : %s"), UTF8_TO_TCHAR(message.data));
});
Context->Device = Context->Adapter.CreateDevice(&deviceDescriptor);
Context->Device.SetLoggingCallback([](wgpu::LoggingType type, wgpu::StringView message) {
//UE_LOG(SkiaIntegration, Error, TEXT("wgpu error : %s"), UTF8_TO_TCHAR(message.data));
});
using namespace skgpu::graphite;
DawnBackendContext contextDesc;
contextDesc.fInstance = Context->Instance;
contextDesc.fDevice = Context->Device;
contextDesc.fQueue = Context->Device.GetQueue();
ContextOptions options;
Context->SkiaContext = ContextFactory::MakeDawn(contextDesc, options);
Context->Recorder = Context->SkiaContext->makeRecorder();
SkISize planeDimensions = SkISize::Make(1024, 1024);
SkImageInfo infos = SkImageInfo::Make(SkISize::Make(1024, 1024), SkColorInfo(SkColorType::kBGRA_8888_SkColorType, SkAlphaType::kOpaque_SkAlphaType, SkColorSpace::MakeSRGB()));
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
sk_sp<SkSurface> gpuSurface = SkSurfaces::RenderTarget(Context->Recorder.get(), infos, skgpu::Mipmapped::kNo, &props, "skia_rt");
if (!gpuSurface)
{
//UE_LOG(SkiaIntegration, Error, TEXT("Failed to wrap backend"));
return;
}
Context->Surface = gpuSurface;
SkCanvas* gpuCanvas = Context->Surface->getCanvas();
draw(gpuCanvas);
Context->Instance.ProcessEvents();
Context->SkiaContext->submit(skgpu::graphite::SyncToCpu::kYes);
Context->Instance.ProcessEvents();
Context->SkiaContext->asyncRescaleAndReadPixels(Context->Surface.get(), Context->Surface->imageInfo(), SkIRect::MakeSize(Context->Surface->imageInfo().dimensions()), SkImage::RescaleGamma::kSrc, SkImage::RescaleMode::kNearest, [](SkSurface::ReadPixelsContext, std::unique_ptr<const SkSurface::AsyncReadResult> result) {
const uint8_t* pixData = reinterpret_cast<const uint8_t*>(result->data(0));
}, this);
Context->SkiaContext->submit(skgpu::graphite::SyncToCpu::kYes);
Context->SkiaContext->checkAsyncWorkCompletion();
Any idea why the graphite version (which I would rather use) won't update render to the provided rendertarget (the readback of the pixels is always black) ?
I can provide the complete integration into the sample if required.