// Copyright Epic Games, Inc. All Rights Reserved. #include "WebBrowserTextureResource.h" #include "DeviceProfiles/DeviceProfile.h" #include "DeviceProfiles/DeviceProfileManager.h" #include "ExternalTexture.h" #include "PipelineStateCache.h" #include "SceneUtils.h" #include "Shader.h" #include "StaticBoundShaderState.h" #include "RenderUtils.h" #include "RHIStaticStates.h" #include "ExternalTexture.h" #include "WebBrowserTexture.h" #define WebBrowserTextureRESOURCE_TRACE_RENDER 0 DEFINE_LOG_CATEGORY(LogWebBrowserTexture); /* FWebBrowserTextureResource structors *****************************************************************************/ FWebBrowserTextureResource::FWebBrowserTextureResource(UWebBrowserTexture& InOwner, FIntPoint& InOwnerDim, SIZE_T& InOwnerSize) : Cleared(false) , CurrentClearColor(FLinearColor::Transparent) , Owner(InOwner) , OwnerDim(InOwnerDim) , OwnerSize(InOwnerSize) { UE_LOG(LogWebBrowserTexture, VeryVerbose, TEXT("FWebBrowserTextureResource:FWebBrowserTextureResource %d %d"), OwnerDim.X, OwnerDim.Y); } /* FWebBrowserTextureResource interface *****************************************************************************/ void FWebBrowserTextureResource::Render(const FRenderParams& Params) { check(IsInRenderingThread()); TSharedPtr SampleSource = Params.SampleSource.Pin(); if (SampleSource.IsValid()) { // get the most current sample to be rendered TSharedPtr Sample; bool SampleValid = false; while (SampleSource->Peek(Sample) && Sample.IsValid()) { SampleValid = SampleSource->Dequeue(Sample); } if (!SampleValid) { return; // no sample to render } check(Sample.IsValid()); // render the sample CopySample(Sample, Params.ClearColor); if (!GSupportsImageExternal && Params.PlayerGuid.IsValid()) { FTextureRHIRef VideoTexture = (FTextureRHIRef)Owner.TextureReference.TextureReferenceRHI; FExternalTextureRegistry::Get().RegisterExternalTexture(Params.PlayerGuid, VideoTexture, SamplerStateRHI, Sample->GetScaleRotation(), Sample->GetOffset()); } } else if (!Cleared) { ClearTexture(Params.ClearColor); if (!GSupportsImageExternal && Params.PlayerGuid.IsValid()) { FTextureRHIRef VideoTexture = (FTextureRHIRef)Owner.TextureReference.TextureReferenceRHI; FExternalTextureRegistry::Get().RegisterExternalTexture(Params.PlayerGuid, VideoTexture, SamplerStateRHI, FLinearColor(1.0f, 0.0f, 0.0f, 1.0f), FLinearColor(0.0f, 0.0f, 0.0f, 0.0f)); } } } /* FRenderTarget interface *****************************************************************************/ FIntPoint FWebBrowserTextureResource::GetSizeXY() const { return FIntPoint(Owner.GetWidth(), Owner.GetHeight()); } /* FTextureResource interface *****************************************************************************/ FString FWebBrowserTextureResource::GetFriendlyName() const { return Owner.GetPathName(); } uint32 FWebBrowserTextureResource::GetSizeX() const { return Owner.GetWidth(); } uint32 FWebBrowserTextureResource::GetSizeY() const { return Owner.GetHeight(); } void FWebBrowserTextureResource::InitRHI(FRHICommandListBase& RHICmdList) { // create the sampler state FSamplerStateInitializerRHI SamplerStateInitializer( (ESamplerFilter)UDeviceProfileManager::Get().GetActiveProfile()->GetTextureLODSettings()->GetSamplerFilter(&Owner), (Owner.AddressX == TA_Wrap) ? AM_Wrap : ((Owner.AddressX == TA_Clamp) ? AM_Clamp : AM_Mirror), (Owner.AddressY == TA_Wrap) ? AM_Wrap : ((Owner.AddressY == TA_Clamp) ? AM_Clamp : AM_Mirror), AM_Wrap ); SamplerStateRHI = RHICreateSamplerState(SamplerStateInitializer); } void FWebBrowserTextureResource::ReleaseRHI() { Cleared = false; InputTarget.SafeRelease(); OutputTarget.SafeRelease(); RenderTargetTextureRHI.SafeRelease(); TextureRHI.SafeRelease(); UpdateTextureReference(nullptr); } /* FWebBrowserTextureResource implementation *****************************************************************************/ void FWebBrowserTextureResource::ClearTexture(const FLinearColor& ClearColor) { UE_LOG(LogWebBrowserTexture, VeryVerbose, TEXT("FWebBrowserTextureResource:ClearTexture")); // create output render target if we don't have one yet const ETextureCreateFlags OutputCreateFlags = ETextureCreateFlags::SRGB; if ((ClearColor != CurrentClearColor) || !OutputTarget.IsValid() || !EnumHasAllFlags(OutputTarget->GetFlags(), OutputCreateFlags)) { const FRHITextureCreateDesc Desc = FRHITextureCreateDesc::Create2D(TEXT("FWebBrowserTextureResource")) .SetExtent(2, 2) .SetFormat(PF_B8G8R8A8) .SetFlags(OutputCreateFlags | ETextureCreateFlags::RenderTargetable | ETextureCreateFlags::ShaderResource) .SetInitialState(ERHIAccess::SRVMask) .SetClearValue(FClearValueBinding(ClearColor)); OutputTarget = RHICreateTexture(Desc); CurrentClearColor = ClearColor; UpdateResourceSize(); } if (RenderTargetTextureRHI != OutputTarget) { UpdateTextureReference(OutputTarget); } // draw the clear color FRHICommandListImmediate& CommandList = FRHICommandListExecutor::GetImmediateCommandList(); { CommandList.Transition(FRHITransitionInfo(RenderTargetTextureRHI, ERHIAccess::Unknown, ERHIAccess::RTV)); ClearRenderTarget(CommandList, RenderTargetTextureRHI); CommandList.Transition(FRHITransitionInfo(RenderTargetTextureRHI, ERHIAccess::RTV, ERHIAccess::SRVMask)); } Cleared = true; } void FWebBrowserTextureResource::CopySample(const TSharedPtr& Sample, const FLinearColor& ClearColor) { FRHITexture* SampleTexture = Sample->GetTexture(); FRHITexture* SampleTexture2D = (SampleTexture != nullptr) ? SampleTexture->GetTexture2D() : nullptr; // If the sample already provides a texture resource, we simply use that // as the output render target. If the sample only provides raw data, then // we create our own output render target and copy the data into it. if (SampleTexture2D != nullptr) { UE_LOG(LogWebBrowserTexture, VeryVerbose, TEXT("FWebBrowserTextureResource:CopySample 1")); // use sample's texture as the new render target. if (TextureRHI != SampleTexture2D) { UE_LOG(LogWebBrowserTexture, VeryVerbose, TEXT("FWebBrowserTextureResource:CopySample 11")); UpdateTextureReference(SampleTexture2D); OutputTarget.SafeRelease(); UpdateResourceSize(); } } else { UE_LOG(LogWebBrowserTexture, VeryVerbose, TEXT("FWebBrowserTextureResource:CopySample 2")); // create a new output render target if necessary const ETextureCreateFlags OutputCreateFlags = TexCreate_SRGB; const FIntPoint SampleDim = Sample->GetDim(); if ((ClearColor != CurrentClearColor) || !OutputTarget.IsValid() || (OutputTarget->GetSizeXY() != SampleDim) || ((OutputTarget->GetFlags() & OutputCreateFlags) != OutputCreateFlags)) { UE_LOG(LogWebBrowserTexture, VeryVerbose, TEXT("FWebBrowserTextureResource:CopySample 1")); const FRHITextureCreateDesc Desc = FRHITextureCreateDesc::Create2D(TEXT("FWebBrowserTextureResource")) .SetExtent(SampleDim) .SetFormat(PF_B8G8R8A8) .SetFlags(OutputCreateFlags | ETextureCreateFlags::RenderTargetable | ETextureCreateFlags::ShaderResource) .SetInitialState(ERHIAccess::SRVMask) .SetClearValue(FClearValueBinding(ClearColor)); OutputTarget = RHICreateTexture(Desc); CurrentClearColor = ClearColor; UpdateResourceSize(); } if (RenderTargetTextureRHI != OutputTarget) { UpdateTextureReference(OutputTarget); } UE_LOG(LogWebBrowserTexture, VeryVerbose, TEXT("WebBrowserTextureResource:CopySample: %d x %d"), SampleDim.X, SampleDim.Y); // copy sample data to output render target FUpdateTextureRegion2D Region(0, 0, 0, 0, SampleDim.X, SampleDim.Y); RHIUpdateTexture2D(RenderTargetTextureRHI.GetReference(), 0, Region, Sample->GetStride(), (uint8*)Sample->GetBuffer()); } Cleared = false; } void FWebBrowserTextureResource::UpdateResourceSize() { UE_LOG(LogWebBrowserTexture, VeryVerbose, TEXT("FWebBrowserTextureResource:UpdateResourceSize")); SIZE_T ResourceSize = 0; if (InputTarget.IsValid()) { ResourceSize += CalcTextureSize(InputTarget->GetSizeX(), InputTarget->GetSizeY(), InputTarget->GetFormat(), 1); } if (OutputTarget.IsValid()) { ResourceSize += CalcTextureSize(OutputTarget->GetSizeX(), OutputTarget->GetSizeY(), OutputTarget->GetFormat(), 1); } OwnerSize = ResourceSize; } void FWebBrowserTextureResource::UpdateTextureReference(FRHITexture* NewTexture) { TextureRHI = NewTexture; RenderTargetTextureRHI = NewTexture; RHIUpdateTextureReference(Owner.TextureReference.TextureReferenceRHI, NewTexture); if (RenderTargetTextureRHI != nullptr) { OwnerDim = FIntPoint(RenderTargetTextureRHI->GetSizeX(), RenderTargetTextureRHI->GetSizeY()); } else { OwnerDim = FIntPoint::ZeroValue; } UE_LOG(LogWebBrowserTexture, VeryVerbose, TEXT("FWebBrowserTextureResource:UpdateTextureReference: %d x %d"), OwnerDim.X, OwnerDim.Y); }