@@ -363,6 +363,74 @@ std::shared_ptr<GPUExternalTexture> GPUDevice::importExternalTexture(
363363 " null" );
364364 }
365365
366+ return std::make_shared<GPUExternalTexture>(
367+ std::move (external), std::move (memory), std::move (texture),
368+ std::move (descriptor->source ), std::move (label));
369+ #elif defined(__ANDROID__)
370+ // 1. Import the AHardwareBuffer as SharedTextureMemory. For YUV AHBs this
371+ // yields a Dawn texture in the implementation-defined OpaqueYCbCrAndroid
372+ // format; for RGBA AHBs, a regular single-plane texture.
373+ wgpu::SharedTextureMemoryDescriptor memDesc{};
374+ std::string label = descriptor->label .value_or (" external-texture" );
375+ if (!label.empty ()) {
376+ memDesc.label = wgpu::StringView (label.c_str (), label.size ());
377+ }
378+ wgpu::SharedTextureMemoryAHardwareBufferDescriptor platformDesc{};
379+ platformDesc.handle = frame.handle ;
380+ memDesc.nextInChain = &platformDesc;
381+ auto memory = _instance.ImportSharedTextureMemory (&memDesc);
382+ if (memory == nullptr ) {
383+ throw std::runtime_error (
384+ " GPUDevice::importExternalTexture(): ImportSharedTextureMemory "
385+ " returned null. Is 'shared-texture-memory-ahardware-buffer' enabled?" );
386+ }
387+
388+ // 2. Create the texture. No descriptor: Dawn picks the right format
389+ // (OpaqueYCbCrAndroid for YUV, R8 / RGBA8 / ... for color AHBs).
390+ auto texture = memory.CreateTexture ();
391+ if (texture == nullptr ) {
392+ throw std::runtime_error (
393+ " GPUDevice::importExternalTexture(): CreateTexture returned null" );
394+ }
395+
396+ // 3. Begin access. Vulkan requires us to advertise the incoming VkImage
397+ // layout (UNDEFINED is fine for the first acquisition of an AHB whose
398+ // contents we expect Dawn to read as-is).
399+ wgpu::SharedTextureMemoryBeginAccessDescriptor begin{};
400+ begin.initialized = true ;
401+ begin.concurrentRead = false ;
402+ wgpu::SharedTextureMemoryVkImageLayoutBeginState beginLayout{};
403+ begin.nextInChain = &beginLayout;
404+ if (!memory.BeginAccess (texture, &begin)) {
405+ throw std::runtime_error (
406+ " GPUDevice::importExternalTexture(): BeginAccess failed" );
407+ }
408+
409+ // 4. Build the ExternalTextureDescriptor. Unlike iOS we do *not* split
410+ // planes or pass an explicit YUV→RGB matrix: when the underlying texture
411+ // is OpaqueYCbCrAndroid, Dawn routes sampling through a Vulkan
412+ // SamplerYcbcrConversion that does the conversion implicitly, driven by
413+ // the AHB's own format metadata. This is the "passthrough external
414+ // texture" pattern from Dawn's tests
415+ // (utils::MakePassthroughExternalTexture).
416+ wgpu::ExternalTextureDescriptor extDesc{};
417+ if (!label.empty ()) {
418+ extDesc.label = wgpu::StringView (label.c_str (), label.size ());
419+ }
420+ extDesc.plane0 = texture.CreateView ();
421+ extDesc.cropOrigin = {0 , 0 };
422+ extDesc.cropSize = {frame.width , frame.height };
423+ extDesc.apparentSize = {frame.width , frame.height };
424+
425+ auto external = _instance.CreateExternalTexture (&extDesc);
426+ if (external == nullptr ) {
427+ wgpu::SharedTextureMemoryEndAccessState state{};
428+ (void )memory.EndAccess (texture, &state);
429+ throw std::runtime_error (
430+ " GPUDevice::importExternalTexture(): CreateExternalTexture returned "
431+ " null" );
432+ }
433+
366434 return std::make_shared<GPUExternalTexture>(
367435 std::move (external), std::move (memory), std::move (texture),
368436 std::move (descriptor->source ), std::move (label));
0 commit comments