232 lines
6.4 KiB
C#
232 lines
6.4 KiB
C#
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
using System.Collections;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Copyright 2012-2021 RenderHeads Ltd. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
namespace RenderHeads.Media.AVProMovieCapture
|
|
{
|
|
/// <summary>
|
|
/// Capture from the screen (backbuffer). Everything is captured as it appears on the screen, including IMGUI rendering.
|
|
/// This component waits for the frame to be completely rendered and then captures it.
|
|
/// </summary>
|
|
[AddComponentMenu("AVPro Movie Capture/Capture From Screen", 0)]
|
|
public class CaptureFromScreen : CaptureBase
|
|
{
|
|
//private const int NewFrameSleepTimeMs = 6;
|
|
[SerializeField] bool _captureMouseCursor = false;
|
|
[SerializeField] MouseCursor _mouseCursor = null;
|
|
|
|
private System.IntPtr _targetNativePointer = System.IntPtr.Zero;
|
|
private RenderTexture _resolveTexture = null;
|
|
private CommandBuffer _commandBuffer = null;
|
|
|
|
public bool CaptureMouseCursor
|
|
{
|
|
get { return _captureMouseCursor; }
|
|
set { _captureMouseCursor = value; }
|
|
}
|
|
|
|
public MouseCursor MouseCursor
|
|
{
|
|
get { return _mouseCursor; }
|
|
set { _mouseCursor = value; }
|
|
}
|
|
|
|
public override bool PrepareCapture()
|
|
{
|
|
if (_capturing)
|
|
{
|
|
return false;
|
|
}
|
|
#if UNITY_EDITOR_WIN || (!UNITY_EDITOR && UNITY_STANDALONE_WIN)
|
|
if (SystemInfo.graphicsDeviceVersion.StartsWith("Direct3D 9"))
|
|
{
|
|
Debug.LogError("[AVProMovieCapture] Direct3D9 not yet supported, please use Direct3D11 instead.");
|
|
return false;
|
|
}
|
|
else if (SystemInfo.graphicsDeviceVersion.StartsWith("OpenGL") && !SystemInfo.graphicsDeviceVersion.Contains("emulated"))
|
|
{
|
|
Debug.LogError("[AVProMovieCapture] OpenGL not yet supported for CaptureFromScreen component, please use Direct3D11 instead. You may need to switch your build platform to Windows.");
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
if (_mouseCursor != null)
|
|
{
|
|
_mouseCursor.enabled = _captureMouseCursor;
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
if (Display.displays.Length > 1)
|
|
{
|
|
bool isSecondDisplayActive = false;
|
|
for (int i = 1; i < Display.displays.Length; i++)
|
|
{
|
|
if (Display.displays[i].active)
|
|
{
|
|
isSecondDisplayActive = true;
|
|
break;
|
|
}
|
|
}
|
|
if (isSecondDisplayActive)
|
|
{
|
|
Debug.LogError("[AVProMovieCapture] CaptureFromScreen doesn't work correctly (can cause stretching or incorrect display capture) when there are multiple displays are active. Use CaptureFromCamera instead.");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
SelectRecordingResolution(Screen.width, Screen.height);
|
|
|
|
_pixelFormat = NativePlugin.PixelFormat.RGBA32;
|
|
if (SystemInfo.graphicsDeviceVersion.StartsWith("OpenGL") && !SystemInfo.graphicsDeviceVersion.Contains("emulated"))
|
|
{
|
|
// TODO: add this back in once we have fixed opengl support
|
|
_pixelFormat = NativePlugin.PixelFormat.BGRA32;
|
|
_isTopDown = true;
|
|
}
|
|
else
|
|
{
|
|
_isTopDown = false;
|
|
|
|
if (_isDirectX11)
|
|
{
|
|
_isTopDown = false;
|
|
}
|
|
}
|
|
|
|
GenerateFilename();
|
|
|
|
return base.PrepareCapture();
|
|
}
|
|
|
|
private void CopyRenderTargetToTexture()
|
|
{
|
|
#if false
|
|
// RJT TODO: If using D3D12 we need to read the current 'Display.main.colorBuffer', pass it down
|
|
// to native and extract the texture using 'IUnityGraphicsD3D12v5::TextureFromRenderBuffer()'
|
|
// - Although, as is, this doesn't work: https://forum.unity.com/threads/direct3d12-native-plugin-render-to-screen.733025/
|
|
if (_targetNativePointer == System.IntPtr.Zero)
|
|
{
|
|
_targetNativePointer = Display.main.colorBuffer.GetNativeRenderBufferPtr();
|
|
// _targetNativePointer = Graphics.activeColorBuffer.GetNativeRenderBufferPtr();
|
|
NativePlugin.SetColourBuffer(_handle, _targetNativePointer);
|
|
}
|
|
#endif
|
|
#if true
|
|
if ((_targetNativePointer == System.IntPtr.Zero) ||
|
|
(_resolveTexture && ((_resolveTexture.width != Screen.width) || (_resolveTexture.height != Screen.height)))
|
|
)
|
|
{
|
|
FreeRenderResources();
|
|
|
|
// Create RT matching screen extents
|
|
_resolveTexture = RenderTexture.GetTemporary(Screen.width, Screen.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB, 1);
|
|
_resolveTexture.Create();
|
|
_targetNativePointer = _resolveTexture.GetNativeTexturePtr();
|
|
NativePlugin.SetTexturePointer(_handle, _targetNativePointer);
|
|
|
|
// Create command buffer
|
|
_commandBuffer = new CommandBuffer();
|
|
_commandBuffer.name = "AVPro Movie Capture copy";
|
|
_commandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, _resolveTexture);
|
|
}
|
|
#endif
|
|
|
|
Graphics.ExecuteCommandBuffer(_commandBuffer);
|
|
}
|
|
|
|
private void FreeRenderResources()
|
|
{
|
|
// Command buffer
|
|
if (_commandBuffer != null)
|
|
{
|
|
_commandBuffer.Release();
|
|
_commandBuffer = null;
|
|
}
|
|
|
|
// Resolve texture
|
|
_targetNativePointer = System.IntPtr.Zero;
|
|
if (_resolveTexture)
|
|
{
|
|
RenderTexture.ReleaseTemporary(_resolveTexture);
|
|
_resolveTexture = null;
|
|
}
|
|
}
|
|
|
|
public override void UnprepareCapture()
|
|
{
|
|
if (_handle != -1)
|
|
{
|
|
#if false
|
|
NativePlugin.SetColourBuffer(_handle, System.IntPtr.Zero);
|
|
#endif
|
|
NativePlugin.SetTexturePointer(_handle, System.IntPtr.Zero);
|
|
}
|
|
|
|
FreeRenderResources();
|
|
|
|
if (_mouseCursor != null)
|
|
{
|
|
_mouseCursor.enabled = false;
|
|
}
|
|
|
|
base.UnprepareCapture();
|
|
}
|
|
|
|
private IEnumerator FinalRenderCapture()
|
|
{
|
|
yield return _waitForEndOfFrame;
|
|
|
|
TickFrameTimer();
|
|
|
|
bool canGrab = true;
|
|
|
|
if (IsUsingMotionBlur())
|
|
{
|
|
// If the motion blur is still accumulating, don't grab this frame
|
|
canGrab = _motionBlur.IsFrameAccumulated;
|
|
}
|
|
|
|
if (canGrab && CanOutputFrame())
|
|
{
|
|
// Grab final RenderTexture into texture and encode
|
|
EncodeUnityAudio();
|
|
|
|
// RJT NOTE: Separate D3D12 path for now as it can't grab native RT
|
|
if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Direct3D12)
|
|
{
|
|
CopyRenderTargetToTexture();
|
|
RenderThreadEvent(NativePlugin.PluginEvent.CaptureFrameBuffer);
|
|
}
|
|
else
|
|
{
|
|
RenderThreadEvent(NativePlugin.PluginEvent.CaptureFrameBuffer);
|
|
|
|
// RJT NOTE: Causes screen flickering under D3D12, even if we're not doing any rendering at native level
|
|
if (SystemInfo.graphicsDeviceType != GraphicsDeviceType.Direct3D12)
|
|
{
|
|
GL.InvalidateState();
|
|
}
|
|
}
|
|
|
|
UpdateFPS();
|
|
}
|
|
|
|
RenormTimer();
|
|
|
|
//yield return null;
|
|
}
|
|
|
|
public override void UpdateFrame()
|
|
{
|
|
if (_capturing && !_paused)
|
|
{
|
|
StartCoroutine(FinalRenderCapture());
|
|
}
|
|
base.UpdateFrame();
|
|
}
|
|
}
|
|
} |