Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[REG-2176] Skip graphics capture if graphics not available #354

Merged
merged 7 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,10 @@ private static RenderTexture GetRenderTexture()

private void UpdateGameFacePixelHash()
{
if (_isActive)
// If we are running in -nographics mode, the async task below fails, causing an exception inside
// the AsyncGPUReadback.Request that is difficult to catch. This ensures that the image data
// is only read when we have graphics
if (_isActive && SystemInfo.graphicsDeviceType != GraphicsDeviceType.Null)
{
// have to re-get this every time because it changes on resolution and other screen changes that update the gameface render target
var cohtmlViewTexture = GetRenderTexture();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,10 +255,24 @@ public void WaitForCompletion()
}

/**
* <summary>Calls the onSuccess callback when the readback request finishes or if data is already available</summary>
* <summary>
* Calls the onSuccess callback when the readback request finishes or if data is already available.
* If the system is running in a no graphics mode, this will instead just immediately complete the
* action.
* </summary>
*/
public void GetCurrentScreenshotWithCallback(long segmentNumber, Action<(byte[], int, int)?> onCompletion)
{

// When we don't have graphics available, we immediate invoke the callback with a null value. With how
// we use this function now, this needs to happen so the tick data writing task correctly saves the
// resulting data.
if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Null && onCompletion != null)
{
onCompletion.Invoke(null);
return;
}

var frame = UnityEngine.Time.frameCount;
lock (SyncLock)
{
Expand Down Expand Up @@ -325,39 +339,39 @@ private IEnumerator UpdateGPUData(int frame, Action<(byte[], int, int)?> onCompl
{
ScreenCapture.CaptureScreenshotIntoRenderTexture(_screenShotTexture);
var readbackRequest = AsyncGPUReadback.Request(_screenShotTexture, 0, GraphicsFormat.R8G8B8A8_SRGB, request =>
{
if (!request.hasError)
{
var pixels = request.GetData<Color32>();
var copyBuffer = _copyBuffer.Value; // uses a threadlocal to avoid re-allocating this on every readback
if (SystemInfo.graphicsUVStartsAtTop)
if (!request.hasError)
{
// the pixels from the GPU are upside down, we need to reverse this for it to be right side up
var halfHeight = screenHeight / 2;
for (var i = 0; i <= halfHeight; i++)
var pixels = request.GetData<Color32>();
var copyBuffer = _copyBuffer.Value; // uses a threadlocal to avoid re-allocating this on every readback
if (SystemInfo.graphicsUVStartsAtTop)
{
// swap rows
// bottom row to buffer
NativeArray<Color32>.Copy(pixels, i * screenWidth, copyBuffer, 0, screenWidth);
// top row to bottom
NativeArray<Color32>.Copy(pixels, (screenHeight - i - 1) * screenWidth, pixels, i * screenWidth, screenWidth);
// buffer to top row
NativeArray<Color32>.Copy(copyBuffer, 0, pixels, (screenHeight - i - 1) * screenWidth, screenWidth);
}
} //else.. we're fine
// the pixels from the GPU are upside down, we need to reverse this for it to be right side up
var halfHeight = screenHeight / 2;
for (var i = 0; i <= halfHeight; i++)
{
// swap rows
// bottom row to buffer
NativeArray<Color32>.Copy(pixels, i * screenWidth, copyBuffer, 0, screenWidth);
// top row to bottom
NativeArray<Color32>.Copy(pixels, (screenHeight - i - 1) * screenWidth, pixels, i * screenWidth, screenWidth);
// buffer to top row
NativeArray<Color32>.Copy(copyBuffer, 0, pixels, (screenHeight - i - 1) * screenWidth, screenWidth);
}
} //else.. we're fine

var imageOutput = ImageConversion.EncodeNativeArrayToJPG(pixels, theGraphicsFormat, (uint)screenWidth, (uint)screenHeight);
var imageOutput = ImageConversion.EncodeNativeArrayToJPG(pixels, theGraphicsFormat, (uint)screenWidth, (uint)screenHeight);

RGDebug.LogDebug($"ScreenshotCapture - Captured screenshot for frame # {frame}");
AddFrame(frame, (imageOutput.ToArray(), screenWidth, screenHeight));
}
else
{
RGDebug.LogWarning($"ScreenshotCapture - Error capturing screenshot for frame # {frame}");
AddFrame(frame, null);
}
HandleCompletedActionCallbacks();
});
RGDebug.LogDebug($"ScreenshotCapture - Captured screenshot for frame # {frame}");
AddFrame(frame, (imageOutput.ToArray(), screenWidth, screenHeight));
}
else
{
RGDebug.LogWarning($"ScreenshotCapture - Error capturing screenshot for frame # {frame}");
AddFrame(frame, null);
}
HandleCompletedActionCallbacks();
});
// update from null to the real request
GPUReadbackRequests[frame] = readbackRequest;

Expand Down
Loading