mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2026-05-19 16:10:35 +00:00
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:
@@ -398,6 +398,81 @@ public:
|
|||||||
return m_SwMappingTextures[planeIndex];
|
return m_SwMappingTextures[planeIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool createTexturesFromFrame(AVFrame* frame, std::array<CVMetalTextureRef, MAX_VIDEO_PLANES>& cvMetalTextures)
|
||||||
|
{
|
||||||
|
SDL_assert(frame->format == AV_PIX_FMT_VIDEOTOOLBOX);
|
||||||
|
|
||||||
|
CVPixelBufferRef pixBuf = reinterpret_cast<CVPixelBufferRef>(frame->data[3]);
|
||||||
|
size_t planes = getFramePlaneCount(frame);
|
||||||
|
|
||||||
|
// Create Metal textures for the planes of the CVPixelBuffer
|
||||||
|
for (size_t i = 0; i < planes; i++) {
|
||||||
|
MTLPixelFormat fmt;
|
||||||
|
|
||||||
|
switch (CVPixelBufferGetPixelFormatType(pixBuf)) {
|
||||||
|
case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
|
||||||
|
case kCVPixelFormatType_444YpCbCr8BiPlanarVideoRange:
|
||||||
|
case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
|
||||||
|
case kCVPixelFormatType_444YpCbCr8BiPlanarFullRange:
|
||||||
|
fmt = (i == 0) ? MTLPixelFormatR8Unorm : MTLPixelFormatRG8Unorm;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kCVPixelFormatType_420YpCbCr10BiPlanarFullRange:
|
||||||
|
case kCVPixelFormatType_444YpCbCr10BiPlanarFullRange:
|
||||||
|
case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange:
|
||||||
|
case kCVPixelFormatType_444YpCbCr10BiPlanarVideoRange:
|
||||||
|
fmt = (i == 0) ? MTLPixelFormatR16Unorm : MTLPixelFormatRG16Unorm;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Unknown pixel format: %x",
|
||||||
|
CVPixelBufferGetPixelFormatType(pixBuf));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CVReturn err = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, m_TextureCache, pixBuf, nullptr, fmt,
|
||||||
|
CVPixelBufferGetWidthOfPlane(pixBuf, i),
|
||||||
|
CVPixelBufferGetHeightOfPlane(pixBuf, i),
|
||||||
|
i,
|
||||||
|
&cvMetalTextures[i]);
|
||||||
|
if (err != kCVReturnSuccess) {
|
||||||
|
for (size_t j = 0; j < i; j++) {
|
||||||
|
CFRelease(cvMetalTextures[j]);
|
||||||
|
}
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"CVMetalTextureCacheCreateTextureFromImage() failed: %d",
|
||||||
|
err);
|
||||||
|
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
|
// Caller frees frame after we return
|
||||||
virtual void renderFrameIntoDrawable(AVFrame* frame, id<CAMetalDrawable> drawable)
|
virtual void renderFrameIntoDrawable(AVFrame* frame, id<CAMetalDrawable> drawable)
|
||||||
{ @autoreleasepool {
|
{ @autoreleasepool {
|
||||||
@@ -406,45 +481,8 @@ public:
|
|||||||
SDL_assert(planes <= MAX_VIDEO_PLANES);
|
SDL_assert(planes <= MAX_VIDEO_PLANES);
|
||||||
|
|
||||||
if (frame->format == AV_PIX_FMT_VIDEOTOOLBOX) {
|
if (frame->format == AV_PIX_FMT_VIDEOTOOLBOX) {
|
||||||
CVPixelBufferRef pixBuf = reinterpret_cast<CVPixelBufferRef>(frame->data[3]);
|
if (!createTexturesFromFrame(frame, cvMetalTextures)) {
|
||||||
|
return;
|
||||||
// Create Metal textures for the planes of the CVPixelBuffer
|
|
||||||
for (size_t i = 0; i < planes; i++) {
|
|
||||||
MTLPixelFormat fmt;
|
|
||||||
|
|
||||||
switch (CVPixelBufferGetPixelFormatType(pixBuf)) {
|
|
||||||
case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
|
|
||||||
case kCVPixelFormatType_444YpCbCr8BiPlanarVideoRange:
|
|
||||||
case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
|
|
||||||
case kCVPixelFormatType_444YpCbCr8BiPlanarFullRange:
|
|
||||||
fmt = (i == 0) ? MTLPixelFormatR8Unorm : MTLPixelFormatRG8Unorm;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case kCVPixelFormatType_420YpCbCr10BiPlanarFullRange:
|
|
||||||
case kCVPixelFormatType_444YpCbCr10BiPlanarFullRange:
|
|
||||||
case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange:
|
|
||||||
case kCVPixelFormatType_444YpCbCr10BiPlanarVideoRange:
|
|
||||||
fmt = (i == 0) ? MTLPixelFormatR16Unorm : MTLPixelFormatRG16Unorm;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Unknown pixel format: %x",
|
|
||||||
CVPixelBufferGetPixelFormatType(pixBuf));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CVReturn err = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, m_TextureCache, pixBuf, nullptr, fmt,
|
|
||||||
CVPixelBufferGetWidthOfPlane(pixBuf, i),
|
|
||||||
CVPixelBufferGetHeightOfPlane(pixBuf, i),
|
|
||||||
i,
|
|
||||||
&cvMetalTextures[i]);
|
|
||||||
if (err != kCVReturnSuccess) {
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"CVMetalTextureCacheCreateTextureFromImage() failed: %d",
|
|
||||||
err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user