Implement testRenderFrame() for the VTMetal renderer

This can be used to (hopefully) detect cases where importing the decoded frames onto the target GPU fails.

See #1885
This commit is contained in:
Cameron Gutman
2026-05-14 00:34:32 -05:00
parent 92fb7f3b71
commit 7d6ce0b4cc
@@ -398,15 +398,12 @@ public:
return m_SwMappingTextures[planeIndex]; return m_SwMappingTextures[planeIndex];
} }
// Caller frees frame after we return bool createTexturesFromFrame(AVFrame* frame, std::array<CVMetalTextureRef, MAX_VIDEO_PLANES>& cvMetalTextures)
virtual void renderFrameIntoDrawable(AVFrame* frame, id<CAMetalDrawable> drawable) {
{ @autoreleasepool { SDL_assert(frame->format == AV_PIX_FMT_VIDEOTOOLBOX);
std::array<CVMetalTextureRef, MAX_VIDEO_PLANES> cvMetalTextures;
size_t planes = getFramePlaneCount(frame);
SDL_assert(planes <= MAX_VIDEO_PLANES);
if (frame->format == AV_PIX_FMT_VIDEOTOOLBOX) {
CVPixelBufferRef pixBuf = reinterpret_cast<CVPixelBufferRef>(frame->data[3]); CVPixelBufferRef pixBuf = reinterpret_cast<CVPixelBufferRef>(frame->data[3]);
size_t planes = getFramePlaneCount(frame);
// Create Metal textures for the planes of the CVPixelBuffer // Create Metal textures for the planes of the CVPixelBuffer
for (size_t i = 0; i < planes; i++) { for (size_t i = 0; i < planes; i++) {
@@ -431,7 +428,7 @@ public:
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Unknown pixel format: %x", "Unknown pixel format: %x",
CVPixelBufferGetPixelFormatType(pixBuf)); CVPixelBufferGetPixelFormatType(pixBuf));
return; return false;
} }
CVReturn err = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, m_TextureCache, pixBuf, nullptr, fmt, CVReturn err = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, m_TextureCache, pixBuf, nullptr, fmt,
@@ -440,12 +437,53 @@ public:
i, i,
&cvMetalTextures[i]); &cvMetalTextures[i]);
if (err != kCVReturnSuccess) { if (err != kCVReturnSuccess) {
for (size_t j = 0; j < i; j++) {
CFRelease(cvMetalTextures[j]);
}
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"CVMetalTextureCacheCreateTextureFromImage() failed: %d", "CVMetalTextureCacheCreateTextureFromImage() failed: %d",
err); err);
return; return false;
} }
} }
return true;
}
bool testRenderFrame(AVFrame *frame) override
{ @autoreleasepool {
if (frame->format == AV_PIX_FMT_VIDEOTOOLBOX) {
std::array<CVMetalTextureRef, MAX_VIDEO_PLANES> cvMetalTextures;
size_t planes = getFramePlaneCount(frame);
SDL_assert(planes <= MAX_VIDEO_PLANES);
// Test that we can actually create Metal textures from the CVPixelBufferRef
if (!createTexturesFromFrame(frame, cvMetalTextures)) {
return false;
}
for (size_t i = 0; i < planes; i++) {
CFRelease(cvMetalTextures[i]);
}
}
else {
// Mapping software frames should always work
}
return true;
}}
// Caller frees frame after we return
virtual void renderFrameIntoDrawable(AVFrame* frame, id<CAMetalDrawable> drawable)
{ @autoreleasepool {
std::array<CVMetalTextureRef, MAX_VIDEO_PLANES> cvMetalTextures;
size_t planes = getFramePlaneCount(frame);
SDL_assert(planes <= MAX_VIDEO_PLANES);
if (frame->format == AV_PIX_FMT_VIDEOTOOLBOX) {
if (!createTexturesFromFrame(frame, cvMetalTextures)) {
return;
}
} }
// Prepare a render pass to render into the next drawable // Prepare a render pass to render into the next drawable