658 lines
24 KiB
C++
658 lines
24 KiB
C++
// @lint-ignore-every LICENSELINT
|
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "OculusXRHMD_CustomPresent.h"
|
|
|
|
#if OCULUS_HMD_SUPPORTED_PLATFORMS
|
|
#include "OculusXRHMD.h"
|
|
#include "ScreenRendering.h"
|
|
#include "PipelineStateCache.h"
|
|
#include "ClearQuad.h"
|
|
#include "OculusShaders.h"
|
|
#include "CommonRenderResources.h"
|
|
#include "RHIStaticStates.h"
|
|
|
|
#if PLATFORM_ANDROID
|
|
#include "Android/AndroidJNI.h"
|
|
#include "Android/AndroidEGL.h"
|
|
#include "Android/AndroidApplication.h"
|
|
#include "Android/AndroidPlatformMisc.h"
|
|
#endif
|
|
|
|
#define VULKAN_CUBEMAP_POSITIVE_Y 2
|
|
#define VULKAN_CUBEMAP_NEGATIVE_Y 3
|
|
|
|
namespace OculusXRHMD
|
|
{
|
|
/**
|
|
* A pixel shader for rendering a textured screen element with mip maps and array slice.
|
|
*/
|
|
class FScreenPSMipLevelArray : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FScreenPSMipLevelArray, Global);
|
|
|
|
public:
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) { return true; }
|
|
|
|
FScreenPSMipLevelArray(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FGlobalShader(Initializer)
|
|
{
|
|
InTexture.Bind(Initializer.ParameterMap, TEXT("InTexture"), SPF_Mandatory);
|
|
InTextureSampler.Bind(Initializer.ParameterMap, TEXT("InTextureSampler"));
|
|
InMipLevelParameter.Bind(Initializer.ParameterMap, TEXT("MipLevel"));
|
|
InArraySliceParameter.Bind(Initializer.ParameterMap, TEXT("ArraySlice"));
|
|
}
|
|
FScreenPSMipLevelArray() {}
|
|
|
|
void SetParameters(FRHIBatchedShaderParameters& BatchedParameters, const FTexture* Texture, int ArraySlice, int MipLevel)
|
|
{
|
|
SetTextureParameter(BatchedParameters, InTexture, InTextureSampler, Texture);
|
|
SetShaderValue(BatchedParameters, InMipLevelParameter, MipLevel);
|
|
SetShaderValue(BatchedParameters, InArraySliceParameter, ArraySlice);
|
|
}
|
|
|
|
void SetParameters(FRHIBatchedShaderParameters& BatchedParameters, FRHISamplerState* SamplerStateRHI, FRHITexture* TextureRHI, int ArraySlice, int MipLevel)
|
|
{
|
|
SetTextureParameter(BatchedParameters, InTexture, InTextureSampler, SamplerStateRHI, TextureRHI);
|
|
SetShaderValue(BatchedParameters, InMipLevelParameter, MipLevel);
|
|
SetShaderValue(BatchedParameters, InArraySliceParameter, ArraySlice);
|
|
}
|
|
|
|
private:
|
|
LAYOUT_FIELD(FShaderResourceParameter, InTexture);
|
|
LAYOUT_FIELD(FShaderResourceParameter, InTextureSampler);
|
|
LAYOUT_FIELD(FShaderParameter, InMipLevelParameter);
|
|
LAYOUT_FIELD(FShaderParameter, InArraySliceParameter);
|
|
};
|
|
IMPLEMENT_SHADER_TYPE(, FScreenPSMipLevelArray, TEXT("/Plugin/OculusXR/Private/ScreenPixelShaderArraySlice.usf"), TEXT("MainMipLevel"), SF_Pixel);
|
|
|
|
/**
|
|
* A pixel shader for rendering a textured screen element with mip maps and array slice.
|
|
*/
|
|
class FScreenPSsRGBSourceMipLevelArray : public FGlobalShader
|
|
{
|
|
DECLARE_SHADER_TYPE(FScreenPSsRGBSourceMipLevelArray, Global);
|
|
|
|
public:
|
|
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) { return true; }
|
|
|
|
FScreenPSsRGBSourceMipLevelArray(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
|
|
: FGlobalShader(Initializer)
|
|
{
|
|
InTexture.Bind(Initializer.ParameterMap, TEXT("InTexture"), SPF_Mandatory);
|
|
InTextureSampler.Bind(Initializer.ParameterMap, TEXT("InTextureSampler"));
|
|
InMipLevelParameter.Bind(Initializer.ParameterMap, TEXT("MipLevel"));
|
|
InArraySliceParameter.Bind(Initializer.ParameterMap, TEXT("ArraySlice"));
|
|
}
|
|
FScreenPSsRGBSourceMipLevelArray() {}
|
|
|
|
void SetParameters(FRHIBatchedShaderParameters& BatchedParameters, const FTexture* Texture, int ArraySlice, int MipLevel)
|
|
{
|
|
SetTextureParameter(BatchedParameters, InTexture, InTextureSampler, Texture);
|
|
SetShaderValue(BatchedParameters, InMipLevelParameter, MipLevel);
|
|
SetShaderValue(BatchedParameters, InArraySliceParameter, ArraySlice);
|
|
}
|
|
|
|
void SetParameters(FRHIBatchedShaderParameters& BatchedParameters, FRHISamplerState* SamplerStateRHI, FRHITexture* TextureRHI, int ArraySlice, int MipLevel)
|
|
{
|
|
SetTextureParameter(BatchedParameters, InTexture, InTextureSampler, SamplerStateRHI, TextureRHI);
|
|
SetShaderValue(BatchedParameters, InMipLevelParameter, MipLevel);
|
|
SetShaderValue(BatchedParameters, InArraySliceParameter, ArraySlice);
|
|
}
|
|
|
|
private:
|
|
LAYOUT_FIELD(FShaderResourceParameter, InTexture);
|
|
LAYOUT_FIELD(FShaderResourceParameter, InTextureSampler);
|
|
LAYOUT_FIELD(FShaderParameter, InMipLevelParameter);
|
|
LAYOUT_FIELD(FShaderParameter, InArraySliceParameter);
|
|
};
|
|
IMPLEMENT_SHADER_TYPE(, FScreenPSsRGBSourceMipLevelArray, TEXT("/Plugin/OculusXR/Private/ScreenPixelShaderArraySlice.usf"), TEXT("MainsRGBSourceMipLevel"), SF_Pixel);
|
|
|
|
//-------------------------------------------------------------------------------------------------
|
|
// FCustomPresent
|
|
//-------------------------------------------------------------------------------------------------
|
|
|
|
FCustomPresent::FCustomPresent(class FOculusXRHMD* InOculusXRHMD, ovrpRenderAPIType InRenderAPI, EPixelFormat InDefaultPixelFormat, bool bInSupportsSRGB)
|
|
: OculusXRHMD(InOculusXRHMD)
|
|
, RenderAPI(InRenderAPI)
|
|
, DefaultPixelFormat(InDefaultPixelFormat)
|
|
, bSupportsSRGB(bInSupportsSRGB)
|
|
, bSupportsSubsampled(false)
|
|
, bIsStandaloneStereoDevice(false)
|
|
{
|
|
CheckInGameThread();
|
|
|
|
DefaultOvrpTextureFormat = GetOvrpTextureFormat(GetDefaultPixelFormat());
|
|
DefaultDepthOvrpTextureFormat = ovrpTextureFormat_None;
|
|
|
|
#if PLATFORM_ANDROID
|
|
bIsStandaloneStereoDevice = FAndroidMisc::GetDeviceMake() == FString("Oculus");
|
|
#endif
|
|
|
|
// grab a pointer to the renderer module for displaying our mirror window
|
|
static const FName RendererModuleName("Renderer");
|
|
RendererModule = FModuleManager::GetModulePtr<IRendererModule>(RendererModuleName);
|
|
}
|
|
|
|
void FCustomPresent::ReleaseResources_RHIThread()
|
|
{
|
|
CheckInRHIThread();
|
|
|
|
if (MirrorTextureRHI.IsValid())
|
|
{
|
|
FOculusXRHMDModule::GetPluginWrapper().DestroyMirrorTexture2();
|
|
MirrorTextureRHI = nullptr;
|
|
}
|
|
}
|
|
|
|
void FCustomPresent::Shutdown()
|
|
{
|
|
CheckInGameThread();
|
|
|
|
// OculusXRHMD is going away, but this object can live on until viewport is destroyed
|
|
ExecuteOnRenderThread([this]() {
|
|
ExecuteOnRHIThread([this]() {
|
|
OculusXRHMD = nullptr;
|
|
});
|
|
});
|
|
}
|
|
|
|
bool FCustomPresent::NeedsNativePresent()
|
|
{
|
|
return !bIsStandaloneStereoDevice;
|
|
}
|
|
|
|
bool FCustomPresent::Present(int32& SyncInterval)
|
|
{
|
|
CheckInRHIThread();
|
|
|
|
if (OculusXRHMD)
|
|
{
|
|
FGameFrame* Frame_RHIThread = OculusXRHMD->GetFrame_RHIThread();
|
|
if (Frame_RHIThread)
|
|
{
|
|
FinishRendering_RHIThread();
|
|
}
|
|
}
|
|
|
|
SyncInterval = 0; // VSync off
|
|
|
|
return NeedsNativePresent();
|
|
}
|
|
|
|
void FCustomPresent::UpdateMirrorTexture_RenderThread()
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_BeginRendering);
|
|
|
|
CheckInRenderThread();
|
|
|
|
const ESpectatorScreenMode MirrorWindowMode = OculusXRHMD->GetSpectatorScreenMode_RenderThread();
|
|
const FIntPoint MirrorWindowSize = OculusXRHMD->GetFrame_RenderThread()->WindowSize;
|
|
|
|
if (FOculusXRHMDModule::GetPluginWrapper().GetInitialized())
|
|
{
|
|
// Need to destroy mirror texture?
|
|
if (MirrorTextureRHI.IsValid())
|
|
{
|
|
const auto MirrorTextureSize = FIntPoint(MirrorTextureRHI->GetDesc().Extent.X, MirrorTextureRHI->GetDesc().Extent.Y);
|
|
if (MirrorWindowMode != ESpectatorScreenMode::Distorted || MirrorWindowSize != MirrorTextureSize)
|
|
{
|
|
ExecuteOnRHIThread([]() {
|
|
FOculusXRHMDModule::GetPluginWrapper().DestroyMirrorTexture2();
|
|
});
|
|
|
|
MirrorTextureRHI = nullptr;
|
|
}
|
|
}
|
|
|
|
// Need to create mirror texture?
|
|
if (!MirrorTextureRHI.IsValid() && MirrorWindowMode == ESpectatorScreenMode::Distorted && MirrorWindowSize.X != 0 && MirrorWindowSize.Y != 0)
|
|
{
|
|
const int Width = MirrorWindowSize.X;
|
|
const int Height = MirrorWindowSize.Y;
|
|
ovrpTextureHandle TextureHandle;
|
|
|
|
ExecuteOnRHIThread([&]() {
|
|
FOculusXRHMDModule::GetPluginWrapper().SetupMirrorTexture2(GetOvrpDevice(), Height, Width, GetDefaultOvrpTextureFormat(), &TextureHandle);
|
|
});
|
|
|
|
UE_LOG(LogHMD, Log, TEXT("Allocated a new mirror texture (size %d x %d)"), Width, Height);
|
|
|
|
ETextureCreateFlags TexCreateFlags = TexCreate_ShaderResource | TexCreate_RenderTargetable;
|
|
|
|
MirrorTextureRHI = CreateTexture_RenderThread(Width, Height, GetDefaultPixelFormat(), FClearValueBinding::None, 1, 1, 1, RRT_Texture2D, TextureHandle, TexCreateFlags)->GetTexture2D();
|
|
}
|
|
}
|
|
}
|
|
|
|
void FCustomPresent::FinishRendering_RHIThread()
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_FinishRendering);
|
|
CheckInRHIThread();
|
|
|
|
#if STATS
|
|
if (OculusXRHMD->GetFrame_RHIThread()->ShowFlags.Rendering)
|
|
{
|
|
ovrpAppLatencyTimings AppLatencyTimings;
|
|
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetAppLatencyTimings2(&AppLatencyTimings)))
|
|
{
|
|
SET_FLOAT_STAT(STAT_LatencyRender, AppLatencyTimings.LatencyRender * 1000.0f);
|
|
SET_FLOAT_STAT(STAT_LatencyTimewarp, AppLatencyTimings.LatencyTimewarp * 1000.0f);
|
|
SET_FLOAT_STAT(STAT_LatencyPostPresent, AppLatencyTimings.LatencyPostPresent * 1000.0f);
|
|
SET_FLOAT_STAT(STAT_ErrorRender, AppLatencyTimings.ErrorRender * 1000.0f);
|
|
SET_FLOAT_STAT(STAT_ErrorTimewarp, AppLatencyTimings.ErrorTimewarp * 1000.0f);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
OculusXRHMD->FinishRHIFrame_RHIThread();
|
|
|
|
#if PLATFORM_ANDROID
|
|
float GPUFrameTime = 0.0f;
|
|
if (OVRP_SUCCESS(FOculusXRHMDModule::GetPluginWrapper().GetGPUFrameTime(&GPUFrameTime)))
|
|
{
|
|
SubmitGPUFrameTime(GPUFrameTime);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
EPixelFormat FCustomPresent::GetPixelFormat(EPixelFormat Format) const
|
|
{
|
|
switch (Format)
|
|
{
|
|
// case PF_B8G8R8A8:
|
|
case PF_FloatRGBA:
|
|
case PF_FloatR11G11B10:
|
|
// case PF_R8G8B8A8:
|
|
case PF_G16:
|
|
case PF_R16F:
|
|
case PF_R32_FLOAT:
|
|
case PF_ShadowDepth:
|
|
case PF_D24:
|
|
return Format;
|
|
}
|
|
|
|
return GetDefaultPixelFormat();
|
|
}
|
|
|
|
EPixelFormat FCustomPresent::GetPixelFormat(ovrpTextureFormat Format) const
|
|
{
|
|
switch (Format)
|
|
{
|
|
// case ovrpTextureFormat_R8G8B8A8_sRGB:
|
|
// case ovrpTextureFormat_R8G8B8A8:
|
|
// return PF_R8G8B8A8;
|
|
case ovrpTextureFormat_R16G16B16A16_FP:
|
|
return PF_FloatRGBA;
|
|
case ovrpTextureFormat_R11G11B10_FP:
|
|
return PF_FloatR11G11B10;
|
|
// case ovrpTextureFormat_B8G8R8A8_sRGB:
|
|
// case ovrpTextureFormat_B8G8R8A8:
|
|
// return PF_B8G8R8A8;
|
|
case ovrpTextureFormat_R16:
|
|
return PF_G16; // G stands for grey here, not green, and is actually R16 in RHI
|
|
case ovrpTextureFormat_R16_FP:
|
|
return PF_R16F;
|
|
case ovrpTextureFormat_R32_FP:
|
|
return PF_R32_FLOAT;
|
|
case ovrpTextureFormat_D16:
|
|
return PF_ShadowDepth; // ShadowDepth maps to D16 in Vulkan
|
|
case ovrpTextureFormat_D24_S8:
|
|
return PF_D24;
|
|
}
|
|
|
|
return GetDefaultPixelFormat();
|
|
}
|
|
|
|
ovrpTextureFormat FCustomPresent::GetOvrpTextureFormat(EPixelFormat Format, bool usesRGB) const
|
|
{
|
|
switch (GetPixelFormat(Format))
|
|
{
|
|
case PF_B8G8R8A8:
|
|
return bSupportsSRGB && usesRGB ? ovrpTextureFormat_B8G8R8A8_sRGB : ovrpTextureFormat_B8G8R8A8;
|
|
case PF_FloatRGBA:
|
|
return ovrpTextureFormat_R16G16B16A16_FP;
|
|
case PF_FloatR11G11B10:
|
|
return ovrpTextureFormat_R11G11B10_FP;
|
|
case PF_R8G8B8A8:
|
|
return bSupportsSRGB && usesRGB ? ovrpTextureFormat_R8G8B8A8_sRGB : ovrpTextureFormat_R8G8B8A8;
|
|
case PF_G16:
|
|
return ovrpTextureFormat_R16;
|
|
case PF_R16F:
|
|
return ovrpTextureFormat_R16_FP;
|
|
case PF_R32_FLOAT:
|
|
return ovrpTextureFormat_R32_FP;
|
|
case PF_ShadowDepth:
|
|
return ovrpTextureFormat_D16;
|
|
case PF_D24:
|
|
return ovrpTextureFormat_D24_S8;
|
|
}
|
|
|
|
return ovrpTextureFormat_None;
|
|
}
|
|
|
|
bool FCustomPresent::IsSRGB(ovrpTextureFormat InFormat)
|
|
{
|
|
switch (InFormat)
|
|
{
|
|
case ovrpTextureFormat_B8G8R8A8_sRGB:
|
|
case ovrpTextureFormat_R8G8B8A8_sRGB:
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int FCustomPresent::GetSystemRecommendedMSAALevel() const
|
|
{
|
|
int SystemRecommendedMSAALevel = 1;
|
|
FOculusXRHMDModule::GetPluginWrapper().GetSystemRecommendedMSAALevel2(&SystemRecommendedMSAALevel);
|
|
return SystemRecommendedMSAALevel;
|
|
}
|
|
|
|
FXRSwapChainPtr FCustomPresent::CreateSwapChain_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, const TArray<ovrpTextureHandle>& InTextures, ETextureCreateFlags InTexCreateFlags, const TCHAR* DebugName)
|
|
{
|
|
TArray<FTextureRHIRef> RHITextureSwapChain = CreateSwapChainTextures_RenderThread(InSizeX, InSizeY, InFormat, InBinding, InNumMips, InNumSamples, InNumSamplesTileMem, InResourceType, InTextures, InTexCreateFlags, DebugName);
|
|
|
|
FTextureRHIRef RHITexture = GDynamicRHI->RHICreateAliasedTexture(RHITextureSwapChain[0]);
|
|
|
|
return CreateXRSwapChain(MoveTemp(RHITextureSwapChain), RHITexture);
|
|
}
|
|
|
|
TArray<FTextureRHIRef> FCustomPresent::CreateSwapChainTextures_RenderThread(uint32 InSizeX, uint32 InSizeY, EPixelFormat InFormat, FClearValueBinding InBinding, uint32 InNumMips, uint32 InNumSamples, uint32 InNumSamplesTileMem, ERHIResourceType InResourceType, const TArray<ovrpTextureHandle>& InTextures, ETextureCreateFlags InTexCreateFlags, const TCHAR* DebugName)
|
|
{
|
|
CheckInRenderThread();
|
|
|
|
TArray<FTextureRHIRef> RHITextureSwapChain;
|
|
{
|
|
for (int32 TextureIndex = 0; TextureIndex < InTextures.Num(); ++TextureIndex)
|
|
{
|
|
FTextureRHIRef TexRef = CreateTexture_RenderThread(InSizeX, InSizeY, InFormat, InBinding, InNumMips, InNumSamples, InNumSamplesTileMem, InResourceType, InTextures[TextureIndex], InTexCreateFlags);
|
|
|
|
FString TexName = FString::Printf(TEXT("%s (%d/%d)"), DebugName, TextureIndex, InTextures.Num());
|
|
TexRef->SetName(*TexName);
|
|
RHIBindDebugLabelName(TexRef, *TexName);
|
|
|
|
RHITextureSwapChain.Add(TexRef);
|
|
}
|
|
}
|
|
|
|
return RHITextureSwapChain;
|
|
}
|
|
|
|
void FCustomPresent::CopyTexture_RenderThread(FRHICommandListImmediate& RHICmdList, FRHITexture* DstTexture, FRHITexture* SrcTexture,
|
|
FIntRect DstRect, FIntRect SrcRect, bool bAlphaPremultiply, bool bNoAlphaWrite, bool bInvertY, bool sRGBSource, bool bInvertAlpha) const
|
|
{
|
|
CheckInRenderThread();
|
|
|
|
FIntPoint DstSize;
|
|
FIntPoint SrcSize;
|
|
|
|
if (DstTexture->GetDesc().IsTexture2D() && SrcTexture->GetDesc().IsTexture2D())
|
|
{
|
|
DstSize = FIntPoint(DstTexture->GetSizeX(), DstTexture->GetSizeY());
|
|
SrcSize = FIntPoint(SrcTexture->GetSizeX(), SrcTexture->GetSizeY());
|
|
}
|
|
else if (DstTexture->GetDesc().IsTextureCube() && SrcTexture->GetDesc().IsTextureCube())
|
|
{
|
|
DstSize = FIntPoint(DstTexture->GetSize(), DstTexture->GetSize());
|
|
SrcSize = FIntPoint(SrcTexture->GetSize(), SrcTexture->GetSize());
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (DstRect.IsEmpty())
|
|
{
|
|
DstRect = FIntRect(FIntPoint::ZeroValue, DstSize);
|
|
}
|
|
|
|
if (SrcRect.IsEmpty())
|
|
{
|
|
SrcRect = FIntRect(FIntPoint::ZeroValue, SrcSize);
|
|
}
|
|
|
|
const uint32 ViewportWidth = DstRect.Width();
|
|
const uint32 ViewportHeight = DstRect.Height();
|
|
const FIntPoint TargetSize(ViewportWidth, ViewportHeight);
|
|
float U = SrcRect.Min.X / (float)SrcSize.X;
|
|
float V = SrcRect.Min.Y / (float)SrcSize.Y;
|
|
float USize = SrcRect.Width() / (float)SrcSize.X;
|
|
float VSize = SrcRect.Height() / (float)SrcSize.Y;
|
|
|
|
#if PLATFORM_ANDROID // on android, top-left isn't 0/0 but 1/0.
|
|
if (bInvertY)
|
|
{
|
|
V = 1.0f - V;
|
|
VSize = -VSize;
|
|
}
|
|
#endif
|
|
|
|
FRHITexture* SrcTextureRHI = SrcTexture;
|
|
RHICmdList.Transition(FRHITransitionInfo(SrcTextureRHI, ERHIAccess::Unknown, ERHIAccess::SRVGraphics));
|
|
FGraphicsPipelineStateInitializer GraphicsPSOInit;
|
|
|
|
if (bInvertAlpha)
|
|
{
|
|
// write RGBA, RGB = src.rgb * 1 + dst.rgb * 0, A = src.a * 0 + dst.a * (1 - src.a)
|
|
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGBA, BO_Add, BF_One, BF_Zero, BO_Add, BF_Zero, BF_InverseSourceAlpha>::GetRHI();
|
|
}
|
|
else if (bAlphaPremultiply)
|
|
{
|
|
if (bNoAlphaWrite)
|
|
{
|
|
// for quads, write RGB, RGB = src.rgb * 1 + dst.rgb * 0
|
|
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGB, BO_Add, BF_One, BF_Zero, BO_Add, BF_One, BF_Zero>::GetRHI();
|
|
}
|
|
else
|
|
{
|
|
// for quads, write RGBA, RGB = src.rgb * src.a + dst.rgb * 0, A = src.a + dst.a * 0
|
|
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGBA, BO_Add, BF_SourceAlpha, BF_Zero, BO_Add, BF_One, BF_Zero>::GetRHI();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (bNoAlphaWrite)
|
|
{
|
|
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGB>::GetRHI();
|
|
}
|
|
else
|
|
{
|
|
// for mirror window, write RGBA, RGB = src.rgb * src.a + dst.rgb * (1 - src.a), A = src.a * 1 + dst.a * (1 - src a)
|
|
GraphicsPSOInit.BlendState = TStaticBlendState<CW_RGBA, BO_Add, BF_SourceAlpha, BF_InverseSourceAlpha, BO_Add, BF_One, BF_InverseSourceAlpha>::GetRHI();
|
|
}
|
|
}
|
|
|
|
GraphicsPSOInit.RasterizerState = TStaticRasterizerState<>::GetRHI();
|
|
GraphicsPSOInit.DepthStencilState = TStaticDepthStencilState<false, CF_Always>::GetRHI();
|
|
GraphicsPSOInit.PrimitiveType = PT_TriangleList;
|
|
|
|
const auto FeatureLevel = OculusXRHMD->GetSettings_RenderThread()->CurrentFeatureLevel;
|
|
auto ShaderMap = GetGlobalShaderMap(FeatureLevel);
|
|
TShaderMapRef<FScreenVS> VertexShader(ShaderMap);
|
|
GraphicsPSOInit.BoundShaderState.VertexDeclarationRHI = GFilterVertexDeclaration.VertexDeclarationRHI;
|
|
GraphicsPSOInit.BoundShaderState.VertexShaderRHI = VertexShader.GetVertexShader();
|
|
|
|
if (DstTexture->GetDesc().IsTexture2D())
|
|
{
|
|
sRGBSource &= EnumHasAnyFlags(SrcTexture->GetFlags(), TexCreate_SRGB);
|
|
|
|
// Need to copy over mip maps on Android since they are not generated like they are on PC
|
|
#if PLATFORM_ANDROID
|
|
uint32 NumMips = SrcTexture->GetNumMips();
|
|
#else
|
|
uint32 NumMips = 1;
|
|
#endif
|
|
|
|
const bool bUseTexArrayShader = SrcTexture->GetDesc().IsTextureArray() && DstTexture->GetDesc().IsTextureArray();
|
|
const int32 SliceCount = bUseTexArrayShader ? FMath::Min(SrcTexture->GetDesc().ArraySize, DstTexture->GetDesc().ArraySize) : 1;
|
|
|
|
for (uint32 MipIndex = 0; MipIndex < NumMips; MipIndex++)
|
|
{
|
|
FRHIRenderPassInfo RPInfo(DstTexture, ERenderTargetActions::Load_Store);
|
|
RPInfo.ColorRenderTargets[0].MipIndex = MipIndex;
|
|
|
|
for (int32 SliceIndex = 0; SliceIndex < SliceCount; ++SliceIndex)
|
|
{
|
|
RPInfo.ColorRenderTargets[0].ArraySlice = SliceIndex;
|
|
|
|
RHICmdList.BeginRenderPass(RPInfo, TEXT("CopyTexture"));
|
|
{
|
|
const uint32 MipViewportWidth = ViewportWidth >> MipIndex;
|
|
const uint32 MipViewportHeight = ViewportHeight >> MipIndex;
|
|
const FIntPoint MipTargetSize(MipViewportWidth, MipViewportHeight);
|
|
|
|
if (bNoAlphaWrite || bInvertAlpha)
|
|
{
|
|
RHICmdList.SetViewport(DstRect.Min.X, DstRect.Min.Y, 0.0f, DstRect.Max.X, DstRect.Max.Y, 1.0f);
|
|
DrawClearQuad(RHICmdList, bAlphaPremultiply ? FLinearColor::Black : FLinearColor::White);
|
|
}
|
|
|
|
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
|
|
FRHISamplerState* SamplerState = DstRect.Size() == SrcRect.Size() ? TStaticSamplerState<SF_Point>::GetRHI() : TStaticSamplerState<SF_Bilinear>::GetRHI();
|
|
|
|
if (!sRGBSource)
|
|
{
|
|
if (bUseTexArrayShader)
|
|
{
|
|
TShaderMapRef<FScreenPSMipLevelArray> PixelShader(ShaderMap);
|
|
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
|
|
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
|
|
FRHIBatchedShaderParameters& BatchedParameters = RHICmdList.GetScratchShaderParameters();
|
|
PixelShader->SetParameters(BatchedParameters, SamplerState, SrcTextureRHI, SliceIndex, MipIndex);
|
|
RHICmdList.SetBatchedShaderParameters(RHICmdList.GetBoundPixelShader(), BatchedParameters);
|
|
}
|
|
else
|
|
{
|
|
|
|
TShaderMapRef<FScreenPSMipLevel> PixelShader(ShaderMap);
|
|
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
|
|
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
|
|
#if UE_VERSION_OLDER_THAN(5, 3, 0)
|
|
PixelShader->SetParameters(RHICmdList, SamplerState, SrcTextureRHI, MipIndex);
|
|
#else
|
|
FRHIBatchedShaderParameters& BatchedParameters = RHICmdList.GetScratchShaderParameters();
|
|
PixelShader->SetParameters(BatchedParameters, SamplerState, SrcTextureRHI, MipIndex);
|
|
RHICmdList.SetBatchedShaderParameters(RHICmdList.GetBoundPixelShader(), BatchedParameters);
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (bUseTexArrayShader)
|
|
{
|
|
TShaderMapRef<FScreenPSsRGBSourceMipLevelArray> PixelShader(ShaderMap);
|
|
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
|
|
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
|
|
FRHIBatchedShaderParameters& BatchedParameters = RHICmdList.GetScratchShaderParameters();
|
|
PixelShader->SetParameters(BatchedParameters, SamplerState, SrcTextureRHI, SliceIndex, MipIndex);
|
|
RHICmdList.SetBatchedShaderParameters(RHICmdList.GetBoundPixelShader(), BatchedParameters);
|
|
}
|
|
else
|
|
{
|
|
TShaderMapRef<FScreenPSsRGBSourceMipLevel> PixelShader(ShaderMap);
|
|
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
|
|
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
|
|
#if UE_VERSION_OLDER_THAN(5, 3, 0)
|
|
PixelShader->SetParameters(RHICmdList, SamplerState, SrcTextureRHI, MipIndex);
|
|
#else
|
|
FRHIBatchedShaderParameters& BatchedParameters = RHICmdList.GetScratchShaderParameters();
|
|
PixelShader->SetParameters(BatchedParameters, SamplerState, SrcTextureRHI, MipIndex);
|
|
RHICmdList.SetBatchedShaderParameters(RHICmdList.GetBoundPixelShader(), BatchedParameters);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
RHICmdList.SetViewport(DstRect.Min.X, DstRect.Min.Y, 0.0f, DstRect.Min.X + MipViewportWidth, DstRect.Min.Y + MipViewportHeight, 1.0f);
|
|
|
|
RendererModule->DrawRectangle(
|
|
RHICmdList,
|
|
0, 0, MipViewportWidth, MipViewportHeight,
|
|
U, V, USize, VSize,
|
|
MipTargetSize,
|
|
FIntPoint(1, 1),
|
|
VertexShader,
|
|
EDRF_Default);
|
|
}
|
|
RHICmdList.EndRenderPass();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int FaceIndex = 0; FaceIndex < 6; FaceIndex++)
|
|
{
|
|
FRHIRenderPassInfo RPInfo(DstTexture, ERenderTargetActions::Load_Store);
|
|
|
|
// On Vulkan the positive and negative Y faces of the cubemap need to be flipped
|
|
if (RenderAPI == ovrpRenderAPI_Vulkan)
|
|
{
|
|
int NewFaceIndex = 0;
|
|
|
|
if (FaceIndex == VULKAN_CUBEMAP_POSITIVE_Y)
|
|
NewFaceIndex = VULKAN_CUBEMAP_NEGATIVE_Y;
|
|
else if (FaceIndex == VULKAN_CUBEMAP_NEGATIVE_Y)
|
|
NewFaceIndex = VULKAN_CUBEMAP_POSITIVE_Y;
|
|
else
|
|
NewFaceIndex = FaceIndex;
|
|
|
|
RPInfo.ColorRenderTargets[0].ArraySlice = NewFaceIndex;
|
|
}
|
|
else
|
|
{
|
|
RPInfo.ColorRenderTargets[0].ArraySlice = FaceIndex;
|
|
}
|
|
|
|
RHICmdList.BeginRenderPass(RPInfo, TEXT("CopyTextureFace"));
|
|
{
|
|
if (bNoAlphaWrite)
|
|
{
|
|
DrawClearQuad(RHICmdList, bAlphaPremultiply ? FLinearColor::Black : FLinearColor::White);
|
|
}
|
|
|
|
RHICmdList.ApplyCachedRenderTargets(GraphicsPSOInit);
|
|
|
|
TShaderMapRef<FOculusCubemapPS> PixelShader(ShaderMap);
|
|
GraphicsPSOInit.BoundShaderState.PixelShaderRHI = PixelShader.GetPixelShader();
|
|
SetGraphicsPipelineState(RHICmdList, GraphicsPSOInit, 0);
|
|
FRHISamplerState* SamplerState = DstRect.Size() == SrcRect.Size() ? TStaticSamplerState<SF_Point>::GetRHI() : TStaticSamplerState<SF_Bilinear>::GetRHI();
|
|
#if UE_VERSION_OLDER_THAN(5, 3, 0)
|
|
PixelShader->SetParameters(RHICmdList, SamplerState, SrcTextureRHI, FaceIndex);
|
|
#else
|
|
FRHIBatchedShaderParameters& BatchedParameters = RHICmdList.GetScratchShaderParameters();
|
|
PixelShader->SetParameters(BatchedParameters, SamplerState, SrcTextureRHI, FaceIndex);
|
|
RHICmdList.SetBatchedShaderParameters(RHICmdList.GetBoundPixelShader(), BatchedParameters);
|
|
#endif
|
|
|
|
RHICmdList.SetViewport(DstRect.Min.X, DstRect.Min.Y, 0.0f, DstRect.Max.X, DstRect.Max.Y, 1.0f);
|
|
|
|
RendererModule->DrawRectangle(
|
|
RHICmdList,
|
|
0, 0, ViewportWidth, ViewportHeight,
|
|
#if PLATFORM_ANDROID
|
|
U, V, USize, VSize,
|
|
#else
|
|
U, 1.0 - V, USize, -VSize,
|
|
#endif
|
|
TargetSize,
|
|
FIntPoint(1, 1),
|
|
VertexShader,
|
|
EDRF_Default);
|
|
}
|
|
RHICmdList.EndRenderPass();
|
|
}
|
|
}
|
|
}
|
|
|
|
void FCustomPresent::SubmitGPUCommands_RenderThread(FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
CheckInRenderThread();
|
|
|
|
RHICmdList.SubmitCommandsHint();
|
|
}
|
|
|
|
} // namespace OculusXRHMD
|
|
|
|
#endif //OCULUS_HMD_SUPPORTED_PLATFORMS
|