Skip to content

Commit a4fcade

Browse files
authored
Fix a few issues around readTexture and iOS camera (#1132)
* Fix issue where readTexture requests were skipped on orientation change due to extra call to bgfx::frame. * Fix invalid texture handle creation when disposing/re-creating webcam textures. * Reset should initialize a new ImplData object. * Change dispatch_sync to dispatch_async to fix hang. * Cleanup
1 parent a6b963b commit a4fcade

File tree

3 files changed

+20
-6
lines changed

3 files changed

+20
-6
lines changed

Core/Graphics/Source/DeviceImpl.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,14 @@ namespace Babylon::Graphics
173173

174174
if (m_state.Bgfx.Initialized)
175175
{
176+
// Drain readTextures queue, completing them in an error state.
177+
while (!m_readTextureRequests.empty())
178+
{
179+
auto error = arcana::make_unexpected(std::make_exception_ptr(std::system_error(std::make_error_code(std::errc::operation_canceled))));
180+
m_readTextureRequests.front().second.complete(error);
181+
m_readTextureRequests.pop();
182+
}
183+
176184
// HACK: Render one more frame to drain the before/after render work queues.
177185
StartRenderingCurrentFrame();
178186
FinishRenderingCurrentFrame();
@@ -390,8 +398,7 @@ namespace Babylon::Graphics
390398
uint32_t frameNumber{bgfx::frame()};
391399

392400
// Process read texture requests.
393-
assert(m_readTextureRequests.empty() || m_readTextureRequests.front().first >= frameNumber);
394-
while (!m_readTextureRequests.empty() && m_readTextureRequests.front().first == frameNumber)
401+
while (!m_readTextureRequests.empty() && m_readTextureRequests.front().first <= frameNumber)
395402
{
396403
m_readTextureRequests.front().second.complete();
397404
m_readTextureRequests.pop();

Plugins/NativeCamera/Source/Apple/NativeCameraImpl.mm

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,11 +189,12 @@ fragment float4 fragmentShader(RasterizerData in [[stage_in]],
189189

190190
__block arcana::task_completion_source<Camera::Impl::CameraDimensions, std::exception_ptr> taskCompletionSource{};
191191

192-
dispatch_sync(dispatch_get_main_queue(), ^{
192+
dispatch_async(dispatch_get_main_queue(), ^{
193193
CVMetalTextureCacheCreate(nullptr, nullptr, m_implData->metalDevice, nullptr, &m_implData->textureCache);
194194
m_implData->cameraTextureDelegate = [[CameraTextureDelegate alloc]init:m_implData];
195195
m_implData->avCaptureSession = [[AVCaptureSession alloc] init];
196-
196+
m_implData->textureRGBA = nil;
197+
197198
#if (TARGET_OS_IPHONE)
198199
// Loop over all available camera configurations to find a config that most closely matches the constraints.
199200
AVCaptureDevice* bestDevice{nullptr};
@@ -395,9 +396,14 @@ fragment float4 fragmentShader(RasterizerData in [[stage_in]],
395396
width = [textureY width];
396397
height = [textureY height];
397398
}
399+
400+
// Skip processing this frame if width and height are invalid.
401+
if (width == 0 || height == 0) {
402+
return;
403+
}
398404

399405
// Recreate the output texture when the camera dimensions change.
400-
if (m_cameraDimensions.width != width || m_cameraDimensions.height != height)
406+
if (m_implData->textureRGBA == nil || m_cameraDimensions.width != width || m_cameraDimensions.height != height)
401407
{
402408
MTLTextureDescriptor *textureDescriptor = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm width:width height:height mipmapped:NO];
403409
textureDescriptor.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
@@ -457,7 +463,7 @@ fragment float4 fragmentShader(RasterizerData in [[stage_in]],
457463

458464
void Camera::Impl::Close()
459465
{
460-
m_implData.reset();
466+
m_implData.reset(new ImplData);
461467
}
462468
}
463469

Plugins/NativeCapture/Source/NativeCapture.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ namespace
9090
// Reading the texture is an async operation, but everything that needs to be done prior to future write operations on that texture is completed synchronously,
9191
// so we kick off the read for the next frame prior to the read for the current frame completes.
9292

93+
// TODO: #1131 Address potential race condition during engine shutdown and ReadTextureAsync.
9394
arcana::task<void, std::exception_ptr> readCurrentFrameTask{thisRef->m_graphicsContext.ReadTextureAsync(thisRef->m_blitTextureHandle, thisRef->m_textureBuffer)
9495
.then(arcana::inline_scheduler, thisRef->m_cancellationToken, [thisRef] {
9596
thisRef->m_frameCallback(thisRef->m_textureInfo.Width, thisRef->m_textureInfo.Height, thisRef->m_textureInfo.Format, bgfx::getCaps()->originBottomLeft, thisRef->m_textureBuffer);

0 commit comments

Comments
 (0)