Metal: Fix requestScreenShot to use FrameBufferHandle. Closes #3249. (#3843)

This commit is contained in:
Branimir Karadžić
2026-07-22 23:41:56 -07:00
committed by GitHub
parent c2fb64201b
commit bb7edaa038
2 changed files with 106 additions and 56 deletions

View File

@@ -836,7 +836,6 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
, m_variableRateShadingSupported(false)
, m_supportsDepthClipMode(false)
, m_depthClamp(false)
, m_screenshotTarget(NULL)
, m_screenshotBlitRenderPipelineState(NULL)
, m_commandBuffer(NULL)
, m_blitCommandEncoder(NULL)
@@ -1546,16 +1545,20 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
void requestScreenShot(FrameBufferHandle _handle, const char* _filePath) override
{
BX_UNUSED(_handle);
SwapChainMtl* swapChain = isValid(_handle)
? m_frameBuffers[_handle.idx].m_swapChain
: m_mainFrameBuffer.m_swapChain
;
if (NULL == m_screenshotTarget)
if (NULL == swapChain
|| NULL == swapChain->m_screenshotTarget)
{
return;
}
m_blitCommandEncoder = getBlitCommandEncoder();
#if BX_PLATFORM_OSX
m_blitCommandEncoder->synchronizeResource(m_screenshotTarget);
m_blitCommandEncoder->synchronizeResource(swapChain->m_screenshotTarget);
#endif // BX_PLATFORM_OSX
m_blitCommandEncoder->endEncoding();
m_blitCommandEncoder = NULL;
@@ -1563,23 +1566,24 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
m_cmd.kick(false, true);
m_commandBuffer = 0;
const uint32_t width = m_screenshotTarget->width();
const uint32_t height = m_screenshotTarget->height();
const uint8_t bpp = bimg::getBitsPerPixel(bimg::TextureFormat::Enum(m_resolution.formatColor) );
const uint32_t width = swapChain->m_screenshotTarget->width();
const uint32_t height = swapChain->m_screenshotTarget->height();
const TextureFormat::Enum format = swapChain->m_colorFormat;
const uint8_t bpp = bimg::getBitsPerPixel(bimg::TextureFormat::Enum(format) );
const uint32_t pitch = width * bpp / 8;
const uint32_t size = height*pitch;
uint8_t* data = (uint8_t*)bx::alloc(g_allocator, size);
MTL::Region region(0, 0, 0, width, height, 1);
m_screenshotTarget->getBytes(data, pitch, 0, region, 0, 0);
swapChain->m_screenshotTarget->getBytes(data, pitch, 0, region, 0, 0);
g_callback->screenShot(
_filePath
, m_screenshotTarget->width()
, m_screenshotTarget->height()
, width
, height
, pitch
, m_resolution.formatColor
, format
, data
, size
, false
@@ -1943,7 +1947,10 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
{
if (NULL != m_capture)
{
if (NULL == m_screenshotTarget)
SwapChainMtl* swapChain = m_mainFrameBuffer.m_swapChain;
if (NULL == swapChain
|| NULL == swapChain->m_screenshotTarget)
{
return;
}
@@ -1958,7 +1965,7 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
const uint8_t bpp = bimg::getBitsPerPixel(bimg::TextureFormat::Enum(m_resolution.formatColor) );
const uint32_t pitch = m_resolution.width * bpp / 8;
m_screenshotTarget->getBytes(m_capture, pitch, 0, region, 0, 0);
swapChain->m_screenshotTarget->getBytes(m_capture, pitch, 0, region, 0, 0);
m_commandBuffer = m_cmd.alloc();
@@ -2274,15 +2281,15 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
if (NULL != swapChain->m_backBufferColorMsaa)
{
_renderPassDescriptor->colorAttachments()->object(0)->setTexture(swapChain->m_backBufferColorMsaa);
_renderPassDescriptor->colorAttachments()->object(0)->setResolveTexture(NULL != m_screenshotTarget
? m_screenshotTarget
_renderPassDescriptor->colorAttachments()->object(0)->setResolveTexture(NULL != swapChain->m_screenshotTarget
? swapChain->m_screenshotTarget
: swapChain->currentDrawableTexture()
);
}
else
{
_renderPassDescriptor->colorAttachments()->object(0)->setTexture(NULL != m_screenshotTarget
? m_screenshotTarget
_renderPassDescriptor->colorAttachments()->object(0)->setTexture(NULL != swapChain->m_screenshotTarget
? swapChain->m_screenshotTarget
: swapChain->currentDrawableTexture()
);
}
@@ -3341,7 +3348,6 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
MTL::VertexDescriptor* m_vertexDescriptor;
MTL::SamplerDescriptor* m_samplerDescriptor;
MTL::Texture* m_screenshotTarget;
ShaderMtl m_screenshotBlitProgramVsh;
ShaderMtl m_screenshotBlitProgramFsh;
ProgramMtl m_screenshotBlitProgram;
@@ -4286,6 +4292,7 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
MTL_RELEASE(m_drawable, 0);
MTL_RELEASE(m_drawableTexture, 0);
MTL_RELEASE(m_screenshotTarget, 0);
releaseBackBuffer();
}
@@ -4474,6 +4481,8 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
: _depthFormat
;
m_colorFormat = formatColor;
const int32_t sampleCount = s_msaa[(resetFlags & BGFX_RESET_MSAA_MASK)>>BGFX_RESET_MSAA_SHIFT];
#if BX_PLATFORM_OSX
@@ -5138,52 +5147,76 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
updateResolution(_render->m_resolution);
if (0 != _render->m_numScreenShots
|| NULL != m_capture)
for (uint32_t ii = 0, num = m_numWindows; ii < num; ++ii)
{
if (m_screenshotTarget)
FrameBufferMtl& frameBuffer = 0 == ii
? m_mainFrameBuffer
: m_frameBuffers[m_windows[ii].idx]
;
SwapChainMtl* swapChain = frameBuffer.m_swapChain;
if (NULL == swapChain)
{
if (m_screenshotTarget->width() != m_resolution.width
|| m_screenshotTarget->height() != m_resolution.height)
{
MTL_RELEASE(m_screenshotTarget, 0);
}
continue;
}
if (NULL == m_screenshotTarget)
const uint16_t fbhIdx = 0 == ii ? kInvalidHandle : m_windows[ii].idx;
bool needScreenshot = 0 == ii && NULL != m_capture;
for (uint8_t jj = 0, numShots = _render->m_numScreenShots; jj < numShots && !needScreenshot; ++jj)
{
MTL::TextureDescriptor* desc = newTextureDescriptor();
needScreenshot = _render->m_screenShot[jj].handle.idx == fbhIdx;
}
desc->setTextureType(MTL::TextureType2D);
desc->setPixelFormat(getSwapChainPixelFormat(m_mainFrameBuffer.m_swapChain) );
desc->setWidth(m_resolution.width);
desc->setHeight(m_resolution.height);
desc->setDepth(1);
desc->setMipmapLevelCount(1);
desc->setSampleCount(1);
desc->setArrayLength(1);
const uint32_t width = 0 == ii ? m_resolution.width : frameBuffer.m_width;
const uint32_t height = 0 == ii ? m_resolution.height : frameBuffer.m_height;
if (s_renderMtl->m_hasCPUCacheModesAndStorageModes)
if (needScreenshot)
{
if (NULL != swapChain->m_screenshotTarget
&& (swapChain->m_screenshotTarget->width() != width
|| swapChain->m_screenshotTarget->height() != height) )
{
desc->setCpuCacheMode(MTL::CPUCacheModeDefaultCache);
desc->setStorageMode(BX_ENABLED(BX_PLATFORM_IOS) || BX_ENABLED(BX_PLATFORM_VISIONOS)
? MTL::StorageModeShared
: MTL::StorageModeManaged)
;
desc->setUsage(MTL::TextureUsage(0
| MTL::TextureUsageRenderTarget
| MTL::TextureUsageShaderRead
) );
MTL_RELEASE(swapChain->m_screenshotTarget, 0);
}
m_screenshotTarget = m_device->newTexture(desc);
MTL_RELEASE(desc, 0);
if (NULL == swapChain->m_screenshotTarget)
{
MTL::TextureDescriptor* desc = newTextureDescriptor();
desc->setTextureType(MTL::TextureType2D);
desc->setPixelFormat(getSwapChainPixelFormat(swapChain) );
desc->setWidth(width);
desc->setHeight(height);
desc->setDepth(1);
desc->setMipmapLevelCount(1);
desc->setSampleCount(1);
desc->setArrayLength(1);
if (s_renderMtl->m_hasCPUCacheModesAndStorageModes)
{
desc->setCpuCacheMode(MTL::CPUCacheModeDefaultCache);
desc->setStorageMode(BX_ENABLED(BX_PLATFORM_IOS) || BX_ENABLED(BX_PLATFORM_VISIONOS)
? MTL::StorageModeShared
: MTL::StorageModeManaged)
;
desc->setUsage(MTL::TextureUsage(0
| MTL::TextureUsageRenderTarget
| MTL::TextureUsageShaderRead
) );
}
swapChain->m_screenshotTarget = m_device->newTexture(desc);
MTL_RELEASE(desc, 0);
}
}
else
{
MTL_RELEASE(swapChain->m_screenshotTarget, 0);
}
}
else
{
MTL_RELEASE(m_screenshotTarget, 0);
}
m_uniformScratchBuffer.begin();
@@ -6369,10 +6402,23 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
}
}
if (m_screenshotTarget)
for (uint32_t ii = 0, num = m_numWindows; ii < num; ++ii)
{
FrameBufferMtl& frameBuffer = 0 == ii
? m_mainFrameBuffer
: m_frameBuffers[m_windows[ii].idx]
;
SwapChainMtl* swapChain = frameBuffer.m_swapChain;
if (NULL == swapChain
|| NULL == swapChain->m_screenshotTarget)
{
continue;
}
MTL::RenderPassDescriptor* renderPassDescriptor = newRenderPassDescriptor();
renderPassDescriptor->colorAttachments()->object(0)->setTexture(NULL != m_mainFrameBuffer.m_swapChain ? m_mainFrameBuffer.m_swapChain->currentDrawableTexture() : NULL);
renderPassDescriptor->colorAttachments()->object(0)->setTexture(swapChain->currentDrawableTexture() );
renderPassDescriptor->colorAttachments()->object(0)->setStoreAction(MTL::StoreActionStore);
rce = m_commandBuffer->renderCommandEncoder(renderPassDescriptor);
@@ -6397,7 +6443,7 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
);
rce->setFragmentSamplerState(samplerState, 0);
rce->setFragmentTexture(m_screenshotTarget, 0);
rce->setFragmentTexture(swapChain->m_screenshotTarget, 0);
rce->drawPrimitives(MTL::PrimitiveTypeTriangle, 0, 3, 1);

View File

@@ -492,10 +492,12 @@ namespace bgfx { namespace mtl
: m_metalLayer(NULL)
, m_drawable(NULL)
, m_drawableTexture(NULL)
, m_screenshotTarget(NULL)
, m_backBufferColorMsaa()
, m_backBufferDepth()
, m_backBufferStencil()
, m_maxAnisotropy(0)
, m_colorFormat(TextureFormat::Count)
{
}
@@ -513,6 +515,7 @@ namespace bgfx { namespace mtl
CA::MetalDrawable* m_drawable;
MTL::Texture* m_drawableTexture;
MTL::Texture* m_screenshotTarget;
MTL::Texture* m_backBufferColorMsaa;
MTL::Texture* m_backBufferDepth;
@@ -520,6 +523,7 @@ namespace bgfx { namespace mtl
uint32_t m_maxAnisotropy;
void* m_nwh;
TextureFormat::Enum m_colorFormat;
};
struct FrameBufferMtl