Files
UnrealEngineUWP/Engine/Source/Runtime/RenderCore/Private/RenderUtils.cpp
Gil Gribb 80f6fa5fa7 Copying //UE4/Dev-Rendering to //UE4/Dev-Main (Source: //UE4/Dev-Rendering @ 3231693)
#lockdown Nick.Penwarden
#rb none

==========================
MAJOR FEATURES + CHANGES
==========================

Change 3219796 on 2016/12/02 by Rolando.Caloca

	DR - vk - Increase timeout to 60ms

Change 3219884 on 2016/12/02 by Daniel.Wright

	Assert to help track down rare crash locking capsule indirect shadow vertex buffer

Change 3219885 on 2016/12/02 by Daniel.Wright

	Fixed saving a package that doesn't exist on disk but exists in p4 at a newer revision when the user chooses 'Mark Writable'

Change 3219886 on 2016/12/02 by Daniel.Wright

	Don't create projected shadows when r.ShadowQuality is 0
	* Fixes crash in the forward path trying to render shadows
	* In the deferred path, the shadowmap was still being rendered and only the projection skipped, now all cost will be skipped

Change 3219887 on 2016/12/02 by Daniel.Wright

	Changed ClearRenderTarget2D default alpha to 1, which is necessary for correct compositing

Change 3219893 on 2016/12/02 by Daniel.Wright

	AMD AGS library with approved TPS
	Disabled DFAO on AMD pre-GCN PC video cards to workaround a driver bug which won't be fixed (Radeon 6xxx and below)

Change 3219913 on 2016/12/02 by Daniel.Wright

	Level unload of a lighting scenario propagates the lighting scenario change - fixes crash when precomputed lighting volume data gets unloaded

Change 3220029 on 2016/12/02 by Daniel.Wright

	Async shader compiling now recreates scene proxies which are affected by the material which was compiled.  This fixes crashes which were occuring as proxies cache various material properties, but applying compiled materials would not update these cached properties (bRequiresAdjacencyInformation).
	* A new ensure has been added in FMeshElementCollector::AddMesh and FBatchingSPDI::DrawMesh to catch attempts to render with a material not reported in GetUsedMaterials
	* Fixed UParticleSystemComponent::GetUsedMaterials and UMaterialBillboardComponent::GetUsedMaterials
	* FMaterialUpdateContext should be changed to use the same pattern, but that hasn't been done yet

Change 3220108 on 2016/12/02 by Daniel.Wright

	Fixed shadowmap channel assignment for stationary lights which are not in a lighting scenario level, when a lighting scenario level is present

Change 3220504 on 2016/12/03 by Mark.Satterthwaite

	Metal Desktop Tessellation support from Unicorn.
	- Apple: Metal tessellation support added to MetalShaderFormat, MetalRHI and incl. changes to engine runtime/shaders for Desktop renderer and enabled in ElementalDemo by default (OS X 10.11 will run SM4).
	- Epic: Support for different Metal shader standards on Mac, iOS & tvOS which required moving some RHI functions around as this is a project setting and not a compile-time constant.
	- Epic: Fragment shader UAV support, which is also tied to newer Metal shader standard like Tessellation.
	- Epic: Significant refactor of MetalRHI's internals to clearly separate state-caching from render-pass management and command-encoding.
	- Epic: Internal MetalRHI validation code is now cleanly separated out into custom implementations of the Metal @protocol's and is on by default.
	- Epic: Various fixes to Layered Rendering for Metal.
	- Omits Mobile Tessellation support which needs further revision.

Change 3220881 on 2016/12/04 by Mark.Satterthwaite

	Compiles fixes for iOS & static analysis fixes from Windows.

Change 3221180 on 2016/12/05 by Guillaume.Abadie

	Avoid compiling PreviousFrameSwitch's both Current Frame and Previous Frame inputs every time.

Change 3221217 on 2016/12/05 by Chris.Bunner

	More NVAPI warning fixups.

Change 3221219 on 2016/12/05 by Chris.Bunner

	When comparing overriden properties used to force instance recompilation we need to check against the base material, not assume the immediate parent.
	#jira UE-37792

Change 3221220 on 2016/12/05 by Chris.Bunner

	Exported GetAllStaticSwitchParamNames and GetAllStaticComponentMaskParamNames.
	#jira UE-35132

Change 3221221 on 2016/12/05 by Chris.Bunner

	PR #2785: Fix comment typo in RendererInterface.h (Contributed by dustin-biser)
	#jira UE-35760

Change 3221223 on 2016/12/05 by Chris.Bunner

	Default to include dev-code when compiling material preview stats.
	#jira UE-20321

Change 3221534 on 2016/12/05 by Rolando.Caloca

	DR - Added FDynamicRHI::GetName()

Change 3221833 on 2016/12/05 by Chris.Bunner

	Set correct output extent on PostProcessUpscale (allows users to extend chain correctly).
	#jira UE-36989

Change 3221852 on 2016/12/05 by Chris.Bunner

	32-bit/ch EXR screenshot and frame dump output.
	Fixed row increment bug in 128-bit/px surface format readback.
	#jira UE-37962

Change 3222059 on 2016/12/05 by Rolando.Caloca

	DR - vk - Fix memory type not found

Change 3222104 on 2016/12/05 by Rolando.Caloca

	DR - Lambdaize
	- Added quicker method to check if system textures are initialized

Change 3222290 on 2016/12/05 by Mark.Satterthwaite

	Trivial fixes to reporting Metal shader pipeline errors - need to check if Hull & Domain exist.

Change 3222864 on 2016/12/06 by Rolando.Caloca

	DR - Fix mem leak when exiting

Change 3222873 on 2016/12/06 by Rolando.Caloca

	DR - vk - Minor info to help track down leaks

Change 3222875 on 2016/12/06 by Rolando.Caloca

	DR - Fix mem leak with VisualizeTexture
	#jira UE-39360

Change 3223226 on 2016/12/06 by Chris.Bunner

	Static analysis warning workaround.

Change 3223235 on 2016/12/06 by Ben.Woodhouse

	Integrate from NREAL: Set a custom projection matrix on a SceneCapture2D

Change 3223343 on 2016/12/06 by Chris.Bunner

	Moved HLOD persistent data to viewstate to fix per-view compatability.
	#jira UE-37539

Change 3223349 on 2016/12/06 by Chris.Bunner

	Fixed HLOD with FreezeRendering command.
	#jira UE-29839

Change 3223371 on 2016/12/06 by Michael.Trepka

	Removed obsolete check() in FMetalSurface constructor

Change 3223450 on 2016/12/06 by Chris.Bunner

	Added explicit ScRGB output device selection rather than Nvidia-only hardcoded checks. Allows easier support for Mac and other devices moving forward.

Change 3223638 on 2016/12/06 by Michael.Trepka

	Restored part of the check() in FMetalSurface constructor removed in CL 3223371

Change 3223642 on 2016/12/06 by Mark.Satterthwaite

	Experimental Metal EDR/HDR output support for Mac (iOS/tvOS need custom formats & shaders so they are not supported yet).
	- Only available on macOS Sierra (10.12) for Macs with HDR displays (e.g. Retina iMacs).
	- Enable with -metaledr command-line argument as it is off-by-default.
	- Sets up the CAMetalLayer & the back-buffer for RGBA_FP16 output on Mac using DCI-P3 as the color gamut and ACES 1000 nit ScRGB output encoding.

Change 3223830 on 2016/12/06 by Rolando.Caloca

	DR - vk - Better error when finding an invalid Vulkan driver
	#jira UE-37495

Change 3223869 on 2016/12/06 by Rolando.Caloca

	DR - vk - Reuse fences

Change 3223906 on 2016/12/06 by Guillaume.Abadie

	Fix alpha through TempAA artifact causing a small darker edge layouts.

Change 3224199 on 2016/12/06 by Mark.Satterthwaite

	Fix a dumb copy-paste error from the HDR changes to Metal.

Change 3224220 on 2016/12/06 by Mark.Satterthwaite

	Fix various errors with Metal UAV & Render-Pass Restart support so that we can use the Pixel Shader culling for DistanceField effects.
	- Unfortunately Metal requires that a texture be bound to start a render-pass, so reuse the dummy depth-stencil surface from the problematic editor preview tile rendering.

Change 3224236 on 2016/12/06 by Mark.Satterthwaite

	IWYU CIS compile fix for iOS.

Change 3224366 on 2016/12/06 by Mark.Satterthwaite

	Simplify some of the changes from CL# 3224220 so that we don't perform unnecessary clears.
	- If the RenderPass is broken to issue compute or blit operations then treat the cached RenderTargetsInfo as invalid, unless the RenderPass is restarted.
	- This guarantees that we don't erroneously ignore calls to SetRenderTargets if the calling code issues a dispatch between two RenderPasses that use the same RenderTargetsInfo.

Change 3224416 on 2016/12/06 by Uriel.Doyon

	New default implementation for UPrimitiveComponent::GetStreamingTextureInfo using a conservative heuristic where the textures are stretched across the bounds.
	Optimized UPrimitiveComponent::GetStreamingTextureInfoWithNULLRemoval by not handling registered components with no proxy (essentially hidden game / collision primitives).

	Added blueprint support for texture streaming built data through FStaticMeshComponentInstanceData.

	Fix for material texture streaming data not being available on some cooked builds.

	Enabled split requests on all texture load requests (first loading everything visible and then loaded everything not visible).
	This is controlled by "r.Streaming.MinMipForSplitRequest" which defines the minimum mip for which to allow splitting.
	Forced residency are now loaded in two steps (visible, then forced), improving reactiveness.

	Updated "stat streaming" to include "UnkownRefMips" which represent texture with no known component referencing them,
	and also "LastRenderTimeMips" which related to timed primitives.
	Changed "Forced Mips" so that it only shows mips that are loaded become of forced residency.

	"Texture Streaming Build" now updates the map check after execution.

	Removed Orphaned texture logic as this has  become irrelevant with the latest retention priority logic.

	Updated "r.streaming.usenewmetrics" so that it shows behavior before and after 4.12 improvements.

Change 3224532 on 2016/12/07 by Uriel.Doyon

	Integrated CL 3223965 :

	Building texture streaming data for materials does not wait for pending shaders to finish compilation anymore.
	Added more options to allow the user to cancel this build also.

Change 3224714 on 2016/12/07 by Ben.Woodhouse

	Cherry pick CL 3223972 from //fortnite/main:

	Disable Geometry shader onchip on XB1. This saves 4ms for a single shadow casting point light @ 512x512 (4.8ms to 1.8ms)

Change 3224715 on 2016/12/07 by Ben.Woodhouse

	New version of d3dx12.h from Microsoft which incorporates my suggested static analysis fixes. This avoids us diverging from the official version

Change 3224975 on 2016/12/07 by Rolando.Caloca

	DR - vk - Dump improvements

Change 3225012 on 2016/12/07 by Rolando.Caloca

	DR - Show warning if trying to use num samples != (1,2,4,8,16)

Change 3225126 on 2016/12/07 by Chris.Bunner

	Added 'force 128-bit rendering pipeline' to high-res screenshot tool.
	#jira UE-39345

Change 3225449 on 2016/12/07 by Chris.Bunner

	Updated engine rendering defaults to better match current best practices.
	#jira UE-38081

Change 3225485 on 2016/12/07 by Chris.Bunner

	Moved QuantizeSceneBufferSize to RenderCore and added call for PostProcess settings. Fixes screenpercentage out-of-bounds reads in some cases.
	#jira UE-19394

Change 3225486 on 2016/12/07 by Chris.Bunner

	Only disable TAA during HighResScreenshots if we don't have a reasonable frame-delay enabled.

Change 3225505 on 2016/12/07 by Daniel.Wright

	Fixed exponential height fog disappearing with no skybox

Change 3225655 on 2016/12/07 by Benjamin.Hyder

	Updating TM-Shadermodels to include Translucent lighting, Two sided, updated cloth animation, and adjusted lighting.

Change 3225668 on 2016/12/07 by Chris.Bunner

	Dirty owning packages when user manually forces regeneration of all reflection captures.
	#jira UE-38759

Change 3226139 on 2016/12/07 by Rolando.Caloca

	DR - Fix recompute tangents disabling skin cache
	- Make some macros into lambdas
	#jira UE-39143

Change 3226212 on 2016/12/07 by Daniel.Wright

	Features which require a full prepass use DDM_AllOpaque instead of DDM_AllOccluders, which can be skipped if the component has bUseAsOccluder=false

Change 3226213 on 2016/12/07 by Daniel.Wright

	Scene Capture 2D can specify a global clip plane, which is useful for portals
	* Requires the global clip plane project setting to be enabled

Change 3226214 on 2016/12/07 by Daniel.Wright

	Improved deferred shadowing with MSAA by upsampling light attenuation intelligently in the base pass
	* If the current fragment's depth doesn't match what was used for deferred shadowing, the neighbor (cross pattern) with the nearest depth's shadowing is used
	* Edge artifacts can still occur where the upsample fails or the shadow factor was computed per-sample due to depth / stencil testing
	* Indirect Occlusion from capsule shadows also uses the nearest depth neighbor UV for no extra cost
	* Base pass on 970 GTX 1.69ms -> 1.85ms (.16ms) in RoboRecall

Change 3226258 on 2016/12/07 by Rolando.Caloca

	DR - Typo fix

Change 3226259 on 2016/12/07 by Rolando.Caloca

	DR - compile fix
	#jira UE-39143

Change 3226932 on 2016/12/08 by Chris.Bunner

	Re-saved Infiltrator maps to update reflection captures.
	#jira UE-38759

Change 3227063 on 2016/12/08 by Mark.Satterthwaite

	For Metal platforms ONLY temporarily disable USE_LIGHT_GRID_REFLECTION_CAPTURE_CULLING to avoid UE-37436 while the Nvidia driver team investigate why this doesn't work for them but does for the others. This won't affect non-Metal platforms and the intent is to revert this prior to 4.16 provided we can work through the problem with Nvidia.
	#jira UE-37436

Change 3227120 on 2016/12/08 by Gil.Gribb

	Merging //UE4/Dev-Main@3226895 to Dev-Rendering (//UE4/Dev-Rendering)

Change 3227211 on 2016/12/08 by Arne.Schober

	DR - UE-38585 - Fixing crash where HierInstStaticMesh duplication fails. Also reverting the fix from UE-28189 which is redundant.

Change 3227257 on 2016/12/08 by Marc.Olano

	Extension to PseudoVolumeTexture for more flexible layout
	Change by ryan.brucks

Change 3227286 on 2016/12/08 by Rolando.Caloca

	DR - Fix crash when using custom expressions and using reserved keywords
	#jira UE-39311

Change 3227376 on 2016/12/08 by Mark.Satterthwaite

	Must not include a private header inside the MenuStack public header as that causes compile errors in plugins.

Change 3227415 on 2016/12/08 by Mark.Satterthwaite

	Fix shader compilation due to my disabling of USE_LIGHT_GRID_REFLECTION_CAPTURE_CULLING on Metal - InstancedCompositeTileReflectionCaptureIndices needs to be defined even though Metal doesn't support instanced-stereo rendering.

Change 3227516 on 2016/12/08 by Daniel.Wright

	Implemented UWidgetComponent::GetUsedMaterials

Change 3227521 on 2016/12/08 by Guillaume.Abadie

	Fixes post process volume's indirect lighting color.

	#jira UE-38888

Change 3227567 on 2016/12/08 by Marc.Olano

	New upscale filters: Lanczos-2 (new default), Lanczos-3 and Gaussian Unsharp Mask

Change 3227628 on 2016/12/08 by Daniel.Wright

	Removed redundant ResolveSceneDepthTexture from the merge

Change 3227635 on 2016/12/08 by Daniel.Wright

	Forward renderer supports shadowing from movable lights and light functions
	* Only 4 shadow casting movable or stationary lights can overlap at any point in space, otherwise the movable lights will lose their shadows and an on-screen message will be displayed
	* Light functions only work on shadow casting lights since they need a shadowmap channel to be assigned

Change 3227660 on 2016/12/08 by Rolando.Caloca

	DR - vk - Fix r.MobileMSAA on Vulkan
	- r.MobileMSAA is now read-only (to be fixed on 4.16)
	- Show time for PSO creation hitches
	#jira UE-39184

Change 3227704 on 2016/12/08 by Mark.Satterthwaite

	Fix Mac HDR causing incorrect output color encoding being used, HDR support is now entirely off unless you pass -metaledr which will enable it regardless of whether the current display supports HDR (as we haven't written the detection code yet). Fixed the LUT/UI compositing along the way - Mac Metal wasn't using volume LUT as it should have been, RHISupportsVertexShaderLayer now correctly returns false for non-Mac Metal platforms.

Change 3227705 on 2016/12/08 by Daniel.Wright

	Replaced built-in samplers in the nearest depth translucency upsample because the built-in samplers are no longer bound on PC (cl 2852426)

Change 3227787 on 2016/12/08 by Chris.Bunner

	Added extent clear to motion blur pass to catch misized buffers bringing in errors.
	Added early out to clear call when excluded region matches RT region.
	#jira UE-39437

Change 3228177 on 2016/12/08 by Marc.Olano

	Fix DCC sqrt(int) error

Change 3228285 on 2016/12/08 by Chris.Bunner

	Back out changelist 3225449.
	#jira UE-39528

Change 3228680 on 2016/12/09 by Gil.Gribb

	Merging //UE4/Dev-Main@3228528 to Dev-Rendering (//UE4/Dev-Rendering)

Change 3228940 on 2016/12/09 by Mark.Satterthwaite

	Editor fixes for 4.15:
	- PostProcessTonemap can't fail to bind a texture to the ColorLUT or the subsequent rendering will be garbage: the changes for optimising stereo rendering forgot to account for the Editor's use of Views without States for the asset preview thumbnails. Amended the CombineLUT post-processing to allocate a local output texture when there's no ViewState and read from this when this situation arises which makes everything function again.
	- Don't start render-passes without a valid render-target-array in MetalRHI.

Change 3228950 on 2016/12/09 by Mark.Satterthwaite

	Make GPUSkinCache run on Mac Metal - it wasn't working because it was forcibly disabled on all platforms but for Windows D3D 11.
	- Fixed the Skeleton editor tree trying to access a widget before it has been constructed.
	- Enable GPUSkinCache for Metal SM5: doesn't render correctly, even on AMD, so needs Radar's filing and investigation.
	#jira UE-39256

Change 3229013 on 2016/12/09 by Mark.Satterthwaite

	Further tidy up in SSkeletonTreeView as suggested by Nick.A.

Change 3229101 on 2016/12/09 by Chris.Bunner

	Log compile error fix and updated cvar comments.

Change 3229236 on 2016/12/09 by Ben.Woodhouse

	XB1 D3D11 and D3D12: Use the DXGI frame statistics to get accurate GPU time unaffected by bubbles

Change 3229430 on 2016/12/09 by Ben.Woodhouse

	PR #2680: Optimized histogram generation. (Contributed by PjotrSvetachov)

	Profiled on nvidia 980GTX (2x faster), and on XB1 (marginally faster)

Change 3229580 on 2016/12/09 by Marcus.Wassmer

	DepthBoundsTest for AMD.

Change 3229701 on 2016/12/09 by Michael.Trepka

	Changed "OS X" to "macOS" in few places where we display it and updated the code that asks users to update to latest version to check for 10.12.2

Change 3229706 on 2016/12/09 by Chris.Bunner

	Added GameUserSettings controls for HDR display output.
	Removed Metal commandline as this should replace the need for it.

Change 3229774 on 2016/12/09 by Michael.Trepka

	Disabled OpenGL on Mac. -opengl is now ignored, we always use Metal. On old Macs that do not support Metal we show a message saying that the app requires Metal and exit.

Change 3229819 on 2016/12/09 by Chris.Bunner

	Updated engine rendering defaults to better match current best practices.
	#jira UE-38081

Change 3229948 on 2016/12/09 by Rolando.Caloca

	DR - Fix d3d debug error
	#jira UE-39589

Change 3230341 on 2016/12/11 by Mark.Satterthwaite

	Don't fatally assert that the game-thread stalled waiting for the rendering thread in the Editor executable, even when running -game as the rendering thread can take a while to respond if shaders need to be compiled.
	#jira UE-39613

Change 3230860 on 2016/12/12 by Marcus.Wassmer

	Experimental Nvidia AFR support.

Change 3230930 on 2016/12/12 by Mark.Satterthwaite

	Disable RHICmdList state-caching on Mac - Metal already does this internally and depends on receiving all state changes in order to function.

Change 3231252 on 2016/12/12 by Marcus.Wassmer

	Fix NumGPU detection. (SLI only crash)

Change 3231486 on 2016/12/12 by Mark.Satterthwaite

	Fix a stupid mistake in MetalStateCache::CommitResourceTable that would unnecessarily rebind samplers.

Change 3231661 on 2016/12/12 by Mark.Satterthwaite

	Retain the RHI samplers in MetalRHI to guarantee lifetime.

[CL 3231696 by Gil Gribb in Main branch]
2016-12-12 17:47:42 -05:00

921 lines
28 KiB
C++

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
#include "RenderUtils.h"
#include "Containers/ResourceArray.h"
#include "Containers/DynamicRHIResourceArray.h"
#include "RenderResource.h"
const uint16 GCubeIndices[12*3] =
{
0, 2, 3,
0, 3, 1,
4, 5, 7,
4, 7, 6,
0, 1, 5,
0, 5, 4,
2, 6, 7,
2, 7, 3,
0, 4, 6,
0, 6, 2,
1, 3, 7,
1, 7, 5,
};
/** X=127.5, Y=127.5, Z=1/127.5f, W=-1.0 */
const VectorRegister GVectorPackingConstants = MakeVectorRegister( 127.5f, 127.5f, 1.0f/127.5f, -1.0f );
/** Zero Normal **/
FPackedNormal FPackedNormal::ZeroNormal(127, 127, 127, 127);
//
// FPackedNormal serializer
//
FArchive& operator<<(FArchive& Ar,FPackedNormal& N)
{
Ar << N.Vector.Packed;
return Ar;
}
FArchive& operator<<(FArchive& Ar, FPackedRGB10A2N& N)
{
Ar << N.Vector.Packed;
return Ar;
}
FArchive& operator<<(FArchive& Ar, FPackedRGBA16N& N)
{
Ar << N.X;
Ar << N.Y;
Ar << N.Z;
Ar << N.W;
return Ar;
}
//
// Pixel format information.
//
FPixelFormatInfo GPixelFormats[PF_MAX] =
{
// Name BlockSizeX BlockSizeY BlockSizeZ BlockBytes NumComponents PlatformFormat Supported UnrealFormat
{ TEXT("unknown"), 0, 0, 0, 0, 0, 0, 0, PF_Unknown },
{ TEXT("A32B32G32R32F"), 1, 1, 1, 16, 4, 0, 1, PF_A32B32G32R32F },
{ TEXT("B8G8R8A8"), 1, 1, 1, 4, 4, 0, 1, PF_B8G8R8A8 },
{ TEXT("G8"), 1, 1, 1, 1, 1, 0, 1, PF_G8 },
{ TEXT("G16"), 1, 1, 1, 2, 1, 0, 1, PF_G16 },
{ TEXT("DXT1"), 4, 4, 1, 8, 3, 0, 1, PF_DXT1 },
{ TEXT("DXT3"), 4, 4, 1, 16, 4, 0, 1, PF_DXT3 },
{ TEXT("DXT5"), 4, 4, 1, 16, 4, 0, 1, PF_DXT5 },
{ TEXT("UYVY"), 2, 1, 1, 4, 4, 0, 0, PF_UYVY },
{ TEXT("FloatRGB"), 1, 1, 1, 0, 3, 0, 1, PF_FloatRGB },
{ TEXT("FloatRGBA"), 1, 1, 1, 8, 4, 0, 1, PF_FloatRGBA },
{ TEXT("DepthStencil"), 1, 1, 1, 0, 1, 0, 0, PF_DepthStencil },
{ TEXT("ShadowDepth"), 1, 1, 1, 4, 1, 0, 0, PF_ShadowDepth },
{ TEXT("R32_FLOAT"), 1, 1, 1, 4, 1, 0, 1, PF_R32_FLOAT },
{ TEXT("G16R16"), 1, 1, 1, 4, 2, 0, 1, PF_G16R16 },
{ TEXT("G16R16F"), 1, 1, 1, 4, 2, 0, 1, PF_G16R16F },
{ TEXT("G16R16F_FILTER"), 1, 1, 1, 4, 2, 0, 1, PF_G16R16F_FILTER },
{ TEXT("G32R32F"), 1, 1, 1, 8, 2, 0, 1, PF_G32R32F },
{ TEXT("A2B10G10R10"), 1, 1, 1, 4, 4, 0, 1, PF_A2B10G10R10 },
{ TEXT("A16B16G16R16"), 1, 1, 1, 8, 4, 0, 1, PF_A16B16G16R16 },
{ TEXT("D24"), 1, 1, 1, 4, 1, 0, 1, PF_D24 },
{ TEXT("PF_R16F"), 1, 1, 1, 2, 1, 0, 1, PF_R16F },
{ TEXT("PF_R16F_FILTER"), 1, 1, 1, 2, 1, 0, 1, PF_R16F_FILTER },
{ TEXT("BC5"), 4, 4, 1, 16, 2, 0, 1, PF_BC5 },
{ TEXT("V8U8"), 1, 1, 1, 2, 2, 0, 1, PF_V8U8 },
{ TEXT("A1"), 1, 1, 1, 1, 1, 0, 0, PF_A1 },
{ TEXT("FloatR11G11B10"), 1, 1, 1, 0, 3, 0, 0, PF_FloatR11G11B10 },
{ TEXT("A8"), 1, 1, 1, 1, 1, 0, 1, PF_A8 },
{ TEXT("R32_UINT"), 1, 1, 1, 4, 1, 0, 1, PF_R32_UINT },
{ TEXT("R32_SINT"), 1, 1, 1, 4, 1, 0, 1, PF_R32_SINT },
// IOS Support
{ TEXT("PVRTC2"), 8, 4, 1, 8, 4, 0, 0, PF_PVRTC2 },
{ TEXT("PVRTC4"), 4, 4, 1, 8, 4, 0, 0, PF_PVRTC4 },
{ TEXT("R16_UINT"), 1, 1, 1, 2, 1, 0, 1, PF_R16_UINT },
{ TEXT("R16_SINT"), 1, 1, 1, 2, 1, 0, 1, PF_R16_SINT },
{ TEXT("R16G16B16A16_UINT"),1, 1, 1, 8, 4, 0, 1, PF_R16G16B16A16_UINT},
{ TEXT("R16G16B16A16_SINT"),1, 1, 1, 8, 4, 0, 1, PF_R16G16B16A16_SINT},
{ TEXT("R5G6B5_UNORM"), 1, 1, 1, 2, 3, 0, 1, PF_R5G6B5_UNORM },
{ TEXT("R8G8B8A8"), 1, 1, 1, 4, 4, 0, 1, PF_R8G8B8A8 },
{ TEXT("A8R8G8B8"), 1, 1, 1, 4, 4, 0, 1, PF_A8R8G8B8 },
{ TEXT("BC4"), 4, 4, 1, 8, 1, 0, 1, PF_BC4 },
{ TEXT("R8G8"), 1, 1, 1, 2, 2, 0, 1, PF_R8G8 },
{ TEXT("ATC_RGB"), 4, 4, 1, 8, 3, 0, 0, PF_ATC_RGB },
{ TEXT("ATC_RGBA_E"), 4, 4, 1, 16, 4, 0, 0, PF_ATC_RGBA_E },
{ TEXT("ATC_RGBA_I"), 4, 4, 1, 16, 4, 0, 0, PF_ATC_RGBA_I },
{ TEXT("X24_G8"), 1, 1, 1, 1, 1, 0, 0, PF_X24_G8 },
{ TEXT("ETC1"), 4, 4, 1, 8, 3, 0, 0, PF_ETC1 },
{ TEXT("ETC2_RGB"), 4, 4, 1, 8, 3, 0, 0, PF_ETC2_RGB },
{ TEXT("ETC2_RGBA"), 4, 4, 1, 16, 4, 0, 0, PF_ETC2_RGBA },
{ TEXT("PF_R32G32B32A32_UINT"),1, 1, 1, 16, 4, 0, 1, PF_R32G32B32A32_UINT},
{ TEXT("PF_R16G16_UINT"), 1, 1, 1, 4, 4, 0, 1, PF_R16G16_UINT},
// ASTC support
{ TEXT("ASTC_4x4"), 4, 4, 1, 16, 4, 0, 0, PF_ASTC_4x4 },
{ TEXT("ASTC_6x6"), 6, 6, 1, 16, 4, 0, 0, PF_ASTC_6x6 },
{ TEXT("ASTC_8x8"), 8, 8, 1, 16, 4, 0, 0, PF_ASTC_8x8 },
{ TEXT("ASTC_10x10"), 10, 10, 1, 16, 4, 0, 0, PF_ASTC_10x10 },
{ TEXT("ASTC_12x12"), 12, 12, 1, 16, 4, 0, 0, PF_ASTC_12x12 },
{ TEXT("BC6H"), 4, 4, 1, 16, 3, 0, 1, PF_BC6H },
{ TEXT("BC7"), 4, 4, 1, 16, 4, 0, 1, PF_BC7 },
{ TEXT("R8_UINT"), 1, 1, 1, 1, 1, 0, 1, PF_R8_UINT },
};
static struct FValidatePixelFormats
{
FValidatePixelFormats()
{
for (int32 X = 0; X < ARRAY_COUNT(GPixelFormats); ++X)
{
// Make sure GPixelFormats has an entry for every unreal format
check(X == GPixelFormats[X].UnrealFormat);
}
}
} ValidatePixelFormats;
//
// CalculateImageBytes
//
SIZE_T CalculateImageBytes(uint32 SizeX,uint32 SizeY,uint32 SizeZ,uint8 Format)
{
if ( Format == PF_A1 )
{
// The number of bytes needed to store all 1 bit pixels in a line is the width of the image divided by the number of bits in a byte
uint32 BytesPerLine = SizeX / 8;
// The number of actual bytes in a 1 bit image is the bytes per line of pixels times the number of lines
return sizeof(uint8) * BytesPerLine * SizeY;
}
else if( SizeZ > 0 )
{
return (SizeX / GPixelFormats[Format].BlockSizeX) * (SizeY / GPixelFormats[Format].BlockSizeY) * (SizeZ / GPixelFormats[Format].BlockSizeZ) * GPixelFormats[Format].BlockBytes;
}
else
{
return (SizeX / GPixelFormats[Format].BlockSizeX) * (SizeY / GPixelFormats[Format].BlockSizeY) * GPixelFormats[Format].BlockBytes;
}
}
//
// FWhiteTexture implementation
//
/**
* A solid-colored 1x1 texture.
*/
template <int32 R, int32 G, int32 B, int32 A>
class FColoredTexture : public FTexture
{
public:
// FResource interface.
virtual void InitRHI() override
{
// Create the texture RHI.
FRHIResourceCreateInfo CreateInfo;
FTexture2DRHIRef Texture2D = RHICreateTexture2D(1, 1, PF_B8G8R8A8, 1, 1, TexCreate_ShaderResource, CreateInfo);
TextureRHI = Texture2D;
// Write the contents of the texture.
uint32 DestStride;
FColor* DestBuffer = (FColor*)RHILockTexture2D(Texture2D, 0, RLM_WriteOnly, DestStride, false);
*DestBuffer = FColor(R, G, B, A);
RHIUnlockTexture2D(Texture2D, 0, false);
// Create the sampler state RHI resource.
FSamplerStateInitializerRHI SamplerStateInitializer(SF_Point,AM_Wrap,AM_Wrap,AM_Wrap);
SamplerStateRHI = RHICreateSamplerState(SamplerStateInitializer);
}
/** Returns the width of the texture in pixels. */
virtual uint32 GetSizeX() const override
{
return 1;
}
/** Returns the height of the texture in pixels. */
virtual uint32 GetSizeY() const override
{
return 1;
}
};
FTexture* GWhiteTexture = new TGlobalResource<FColoredTexture<255,255,255,255> >;
FTexture* GBlackTexture = new TGlobalResource<FColoredTexture<0,0,0,255> >;
/**
* Bulk data interface for providing a single black color used to initialize a
* volume texture.
*/
class FBlackVolumeTextureResourceBulkDataInterface : public FResourceBulkDataInterface
{
public:
/** Default constructor. */
FBlackVolumeTextureResourceBulkDataInterface()
: Color(0)
{
}
/**
* Returns a pointer to the bulk data.
*/
virtual const void* GetResourceBulkData() const override
{
return &Color;
}
/**
* @return size of resource memory
*/
virtual uint32 GetResourceBulkDataSize() const override
{
return sizeof(Color);
}
/**
* Free memory after it has been used to initialize RHI resource
*/
virtual void Discard() override
{
}
private:
/** Storage for the color. */
FColor Color;
};
/**
* A class representing a 1x1x1 black volume texture.
*/
class FBlackVolumeTexture : public FTexture
{
public:
/**
* Initialize RHI resources.
*/
virtual void InitRHI() override
{
if (GSupportsTexture3D)
{
// Create the texture.
FBlackVolumeTextureResourceBulkDataInterface BlackTextureBulkData;
FRHIResourceCreateInfo CreateInfo(&BlackTextureBulkData);
FTexture3DRHIRef Texture3D = RHICreateTexture3D(1,1,1,PF_B8G8R8A8,1,TexCreate_ShaderResource,CreateInfo);
TextureRHI = Texture3D;
// Create the sampler state.
FSamplerStateInitializerRHI SamplerStateInitializer(SF_Point,AM_Wrap,AM_Wrap,AM_Wrap);
SamplerStateRHI = RHICreateSamplerState(SamplerStateInitializer);
}
}
/**
* Return the size of the texture in the X dimension.
*/
virtual uint32 GetSizeX() const override
{
return 1;
}
/**
* Return the size of the texture in the Y dimension.
*/
virtual uint32 GetSizeY() const override
{
return 1;
}
};
/** Global black volume texture resource. */
FTexture* GBlackVolumeTexture = new TGlobalResource<FBlackVolumeTexture>();
class FBlackArrayTexture : public FTexture
{
public:
// FResource interface.
virtual void InitRHI() override
{
if (GetFeatureLevel() >= ERHIFeatureLevel::SM4)
{
// Create the texture RHI.
FBlackVolumeTextureResourceBulkDataInterface BlackTextureBulkData;
FRHIResourceCreateInfo CreateInfo(&BlackTextureBulkData);
FTexture2DArrayRHIRef TextureArray = RHICreateTexture2DArray(1, 1, 1, PF_B8G8R8A8, 1, TexCreate_ShaderResource, CreateInfo);
TextureRHI = TextureArray;
// Create the sampler state RHI resource.
FSamplerStateInitializerRHI SamplerStateInitializer(SF_Point,AM_Wrap,AM_Wrap,AM_Wrap);
SamplerStateRHI = RHICreateSamplerState(SamplerStateInitializer);
}
}
/** Returns the width of the texture in pixels. */
virtual uint32 GetSizeX() const override
{
return 1;
}
/** Returns the height of the texture in pixels. */
virtual uint32 GetSizeY() const override
{
return 1;
}
};
FTexture* GBlackArrayTexture = new TGlobalResource<FBlackArrayTexture>;
//
// FMipColorTexture implementation
//
/**
* A texture that has a different solid color in each mip-level
*/
class FMipColorTexture : public FTexture
{
public:
enum
{
NumMips = 12
};
static const FColor MipColors[NumMips];
// FResource interface.
virtual void InitRHI() override
{
// Create the texture RHI.
int32 TextureSize = 1 << (NumMips - 1);
FRHIResourceCreateInfo CreateInfo;
FTexture2DRHIRef Texture2D = RHICreateTexture2D(TextureSize,TextureSize,PF_B8G8R8A8,NumMips,1,TexCreate_ShaderResource,CreateInfo);
TextureRHI = Texture2D;
// Write the contents of the texture.
uint32 DestStride;
int32 Size = TextureSize;
for ( int32 MipIndex=0; MipIndex < NumMips; ++MipIndex )
{
FColor* DestBuffer = (FColor*)RHILockTexture2D(Texture2D, MipIndex, RLM_WriteOnly, DestStride, false);
for ( int32 Y=0; Y < Size; ++Y )
{
for ( int32 X=0; X < Size; ++X )
{
DestBuffer[X] = MipColors[NumMips - 1 - MipIndex];
}
DestBuffer += DestStride / sizeof(FColor);
}
RHIUnlockTexture2D(Texture2D, MipIndex, false);
Size >>= 1;
}
// Create the sampler state RHI resource.
FSamplerStateInitializerRHI SamplerStateInitializer(SF_Point,AM_Wrap,AM_Wrap,AM_Wrap);
SamplerStateRHI = RHICreateSamplerState(SamplerStateInitializer);
}
/** Returns the width of the texture in pixels. */
virtual uint32 GetSizeX() const override
{
int32 TextureSize = 1 << (NumMips - 1);
return TextureSize;
}
/** Returns the height of the texture in pixels. */
// PVS-Studio notices that the implementation of GetSizeX is identical to this one
// and warns us. In this case, it is intentional, so we disable the warning:
virtual uint32 GetSizeY() const override //-V524
{
int32 TextureSize = 1 << (NumMips - 1);
return TextureSize;
}
};
const FColor FMipColorTexture::MipColors[NumMips] =
{
FColor( 80, 80, 80, 0 ), // Mip 0: 1x1 (dark grey)
FColor( 200, 200, 200, 0 ), // Mip 1: 2x2 (light grey)
FColor( 200, 200, 0, 0 ), // Mip 2: 4x4 (medium yellow)
FColor( 255, 255, 0, 0 ), // Mip 3: 8x8 (yellow)
FColor( 160, 255, 40, 0 ), // Mip 4: 16x16 (light green)
FColor( 0, 255, 0, 0 ), // Mip 5: 32x32 (green)
FColor( 0, 255, 200, 0 ), // Mip 6: 64x64 (cyan)
FColor( 0, 170, 170, 0 ), // Mip 7: 128x128 (light blue)
FColor( 60, 60, 255, 0 ), // Mip 8: 256x256 (dark blue)
FColor( 255, 0, 255, 0 ), // Mip 9: 512x512 (pink)
FColor( 255, 0, 0, 0 ), // Mip 10: 1024x1024 (red)
FColor( 255, 130, 0, 0 ), // Mip 11: 2048x2048 (orange)
};
RENDERCORE_API FTexture* GMipColorTexture = new FMipColorTexture;
RENDERCORE_API int32 GMipColorTextureMipLevels = FMipColorTexture::NumMips;
// 4: 8x8 cubemap resolution, shader needs to use the same value as preprocessing
RENDERCORE_API const uint32 GDiffuseConvolveMipLevel = 4;
//
// FWhiteTextureCube implementation
//
/** A solid color cube texture. */
class FSolidColorTextureCube : public FTexture
{
public:
FSolidColorTextureCube(const FColor& InColor, EPixelFormat InPixelFormat = PF_B8G8R8A8)
: Color(InColor)
, PixelFormat(InPixelFormat)
{}
// FRenderResource interface.
virtual void InitRHI() override
{
// Create the texture RHI.
FRHIResourceCreateInfo CreateInfo;
FTextureCubeRHIRef TextureCube = RHICreateTextureCube(1, PixelFormat,1,0,CreateInfo);
TextureRHI = TextureCube;
// Write the contents of the texture.
for(uint32 FaceIndex = 0;FaceIndex < 6;FaceIndex++)
{
uint32 DestStride;
FColor* DestBuffer = (FColor*)RHILockTextureCubeFace(TextureCube, FaceIndex, 0, 0, RLM_WriteOnly, DestStride, false);
*DestBuffer = Color;
RHIUnlockTextureCubeFace(TextureCube, FaceIndex, 0, 0, false);
}
// Create the sampler state RHI resource.
FSamplerStateInitializerRHI SamplerStateInitializer(SF_Point,AM_Wrap,AM_Wrap,AM_Wrap);
SamplerStateRHI = RHICreateSamplerState(SamplerStateInitializer);
}
/** Returns the width of the texture in pixels. */
virtual uint32 GetSizeX() const override
{
return 1;
}
/** Returns the height of the texture in pixels. */
virtual uint32 GetSizeY() const override
{
return 1;
}
private:
FColor Color;
EPixelFormat PixelFormat;
};
/** A white cube texture. */
class FWhiteTextureCube : public FSolidColorTextureCube
{
public:
FWhiteTextureCube() : FSolidColorTextureCube(FColor::White) {}
};
FTexture* GWhiteTextureCube = new TGlobalResource<FWhiteTextureCube>;
/** A black cube texture. */
class FBlackTextureCube : public FSolidColorTextureCube
{
public:
FBlackTextureCube(): FSolidColorTextureCube(FColor::Black) {}
};
FTexture* GBlackTextureCube = new TGlobalResource<FBlackTextureCube>;
/** A black cube texture. */
class FBlackTextureDepthCube : public FSolidColorTextureCube
{
public:
FBlackTextureDepthCube() : FSolidColorTextureCube(FColor::Black, PF_ShadowDepth) {}
};
FTexture* GBlackTextureDepthCube = new TGlobalResource<FBlackTextureDepthCube>;
class FBlackCubeArrayTexture : public FTexture
{
public:
// FResource interface.
virtual void InitRHI() override
{
if (GetFeatureLevel() >= ERHIFeatureLevel::SM5)
{
// Create the texture RHI.
FRHIResourceCreateInfo CreateInfo;
FTextureCubeRHIRef TextureCubeArray = RHICreateTextureCubeArray(1,1,PF_B8G8R8A8,1,TexCreate_ShaderResource,CreateInfo);
TextureRHI = TextureCubeArray;
for(uint32 FaceIndex = 0;FaceIndex < 6;FaceIndex++)
{
uint32 DestStride;
FColor* DestBuffer = (FColor*)RHILockTextureCubeFace(TextureCubeArray, FaceIndex, 0, 0, RLM_WriteOnly, DestStride, false);
// Note: alpha is used by reflection environment to say how much of the foreground texture is visible, so 0 says it is completely invisible
*DestBuffer = FColor(0, 0, 0, 0);
RHIUnlockTextureCubeFace(TextureCubeArray, FaceIndex, 0, 0, false);
}
// Create the sampler state RHI resource.
FSamplerStateInitializerRHI SamplerStateInitializer(SF_Point,AM_Wrap,AM_Wrap,AM_Wrap);
SamplerStateRHI = RHICreateSamplerState(SamplerStateInitializer);
}
}
/** Returns the width of the texture in pixels. */
virtual uint32 GetSizeX() const override
{
return 1;
}
/** Returns the height of the texture in pixels. */
virtual uint32 GetSizeY() const override
{
return 1;
}
};
FTexture* GBlackCubeArrayTexture = new TGlobalResource<FBlackCubeArrayTexture>;
/*
3 XYZ packed in 4 bytes. (11:11:10 for X:Y:Z)
*/
/**
* operator FVector - unpacked to -1 to 1
*/
FPackedPosition::operator FVector() const
{
return FVector(Vector.X/1023.f, Vector.Y/1023.f, Vector.Z/511.f);
}
/**
* operator VectorRegister
*/
VectorRegister FPackedPosition::GetVectorRegister() const
{
FVector UnpackedVect = *this;
VectorRegister VectorToUnpack = VectorLoadFloat3_W0(&UnpackedVect);
return VectorToUnpack;
}
/**
* Pack this vector(-1 to 1 for XYZ) to 4 bytes XYZ(11:11:10)
*/
void FPackedPosition::Set( const FVector& InVector )
{
check (FMath::Abs<float>(InVector.X) <= 1.f && FMath::Abs<float>(InVector.Y) <= 1.f && FMath::Abs<float>(InVector.Z) <= 1.f);
#if !WITH_EDITORONLY_DATA
// This should not happen in Console - this should happen during Cooking in PC
check (false);
#else
// Too confusing to use .5f - wanted to use the last bit!
// Change to int for easier read
Vector.X = FMath::Clamp<int32>(FMath::TruncToInt(InVector.X * 1023.0f),-1023,1023);
Vector.Y = FMath::Clamp<int32>(FMath::TruncToInt(InVector.Y * 1023.0f),-1023,1023);
Vector.Z = FMath::Clamp<int32>(FMath::TruncToInt(InVector.Z * 511.0f),-511,511);
#endif
}
/**
* operator << serialize
*/
FArchive& operator<<(FArchive& Ar,FPackedPosition& N)
{
// Save N.Packed
return Ar << N.Packed;
}
void CalcMipMapExtent3D( uint32 TextureSizeX, uint32 TextureSizeY, uint32 TextureSizeZ, EPixelFormat Format, uint32 MipIndex, uint32& OutXExtent, uint32& OutYExtent, uint32& OutZExtent )
{
OutXExtent = FMath::Max<uint32>(TextureSizeX >> MipIndex, GPixelFormats[Format].BlockSizeX);
OutYExtent = FMath::Max<uint32>(TextureSizeY >> MipIndex, GPixelFormats[Format].BlockSizeY);
OutZExtent = FMath::Max<uint32>(TextureSizeZ >> MipIndex, GPixelFormats[Format].BlockSizeZ);
}
SIZE_T CalcTextureMipMapSize3D( uint32 TextureSizeX, uint32 TextureSizeY, uint32 TextureSizeZ, EPixelFormat Format, uint32 MipIndex )
{
uint32 XExtent;
uint32 YExtent;
uint32 ZExtent;
CalcMipMapExtent3D(TextureSizeX, TextureSizeY, TextureSizeZ, Format, MipIndex, XExtent, YExtent, ZExtent);
// Offset MipExtent to round up result
XExtent += GPixelFormats[Format].BlockSizeX - 1;
YExtent += GPixelFormats[Format].BlockSizeY - 1;
ZExtent += GPixelFormats[Format].BlockSizeZ - 1;
const uint32 XPitch = (XExtent / GPixelFormats[Format].BlockSizeX) * GPixelFormats[Format].BlockBytes;
const uint32 NumRows = YExtent / GPixelFormats[Format].BlockSizeY;
const uint32 NumLayers = ZExtent / GPixelFormats[Format].BlockSizeZ;
return NumLayers * NumRows * XPitch;
}
SIZE_T CalcTextureSize3D( uint32 SizeX, uint32 SizeY, uint32 SizeZ, EPixelFormat Format, uint32 MipCount )
{
SIZE_T Size = 0;
for ( uint32 MipIndex=0; MipIndex < MipCount; ++MipIndex )
{
Size += CalcTextureMipMapSize3D(SizeX,SizeY,SizeZ,Format,MipIndex);
}
return Size;
}
FIntPoint CalcMipMapExtent( uint32 TextureSizeX, uint32 TextureSizeY, EPixelFormat Format, uint32 MipIndex )
{
return FIntPoint(FMath::Max<uint32>(TextureSizeX >> MipIndex, GPixelFormats[Format].BlockSizeX), FMath::Max<uint32>(TextureSizeY >> MipIndex, GPixelFormats[Format].BlockSizeY));
}
SIZE_T CalcTextureMipWidthInBlocks(uint32 TextureSizeX, EPixelFormat Format, uint32 MipIndex)
{
const uint32 BlockSizeX = GPixelFormats[Format].BlockSizeX;
const uint32 WidthInTexels = FMath::Max<uint32>(TextureSizeX >> MipIndex, 1);
const uint32 WidthInBlocks = (WidthInTexels + BlockSizeX - 1) / BlockSizeX;
return WidthInBlocks;
}
SIZE_T CalcTextureMipHeightInBlocks(uint32 TextureSizeY, EPixelFormat Format, uint32 MipIndex)
{
const uint32 BlockSizeY = GPixelFormats[Format].BlockSizeY;
const uint32 HeightInTexels = FMath::Max<uint32>(TextureSizeY >> MipIndex, 1);
const uint32 HeightInBlocks = (HeightInTexels + BlockSizeY - 1) / BlockSizeY;
return HeightInBlocks;
}
SIZE_T CalcTextureMipMapSize( uint32 TextureSizeX, uint32 TextureSizeY, EPixelFormat Format, uint32 MipIndex )
{
const uint32 WidthInBlocks = CalcTextureMipWidthInBlocks(TextureSizeX, Format, MipIndex);
const uint32 HeightInBlocks = CalcTextureMipHeightInBlocks(TextureSizeY, Format, MipIndex);
return WidthInBlocks * HeightInBlocks * GPixelFormats[Format].BlockBytes;
}
SIZE_T CalcTextureSize( uint32 SizeX, uint32 SizeY, EPixelFormat Format, uint32 MipCount )
{
SIZE_T Size = 0;
for ( uint32 MipIndex=0; MipIndex < MipCount; ++MipIndex )
{
Size += CalcTextureMipMapSize(SizeX,SizeY,Format,MipIndex);
}
return Size;
}
void CopyTextureData2D(const void* Source,void* Dest,uint32 SizeY,EPixelFormat Format,uint32 SourceStride,uint32 DestStride)
{
const uint32 BlockSizeY = GPixelFormats[Format].BlockSizeY;
const uint32 NumBlocksY = (SizeY + BlockSizeY - 1) / BlockSizeY;
// a DestStride of 0 means to use the SourceStride
if(SourceStride == DestStride || DestStride == 0)
{
// If the source and destination have the same stride, copy the data in one block.
FMemory::Memcpy(Dest,Source,NumBlocksY * SourceStride);
}
else
{
// If the source and destination have different strides, copy each row of blocks separately.
const uint32 NumBytesPerRow = FMath::Min<uint32>(SourceStride, DestStride);
for(uint32 BlockY = 0;BlockY < NumBlocksY;++BlockY)
{
FMemory::Memcpy(
(uint8*)Dest + DestStride * BlockY,
(uint8*)Source + SourceStride * BlockY,
NumBytesPerRow
);
}
}
}
/** Helper functions for text output of texture properties... */
#ifndef CASE_ENUM_TO_TEXT
#define CASE_ENUM_TO_TEXT(txt) case txt: return TEXT(#txt);
#endif
#ifndef TEXT_TO_ENUM
#define TEXT_TO_ENUM(eVal, txt) if (FCString::Stricmp(TEXT(#eVal), txt) == 0) return eVal;
#endif
const TCHAR* GetPixelFormatString(EPixelFormat InPixelFormat)
{
switch (InPixelFormat)
{
FOREACH_ENUM_EPIXELFORMAT(CASE_ENUM_TO_TEXT)
default:
return TEXT("PF_Unknown");
}
}
EPixelFormat GetPixelFormatFromString(const TCHAR* InPixelFormatStr)
{
#define TEXT_TO_PIXELFORMAT(f) TEXT_TO_ENUM(f, InPixelFormatStr);
FOREACH_ENUM_EPIXELFORMAT(TEXT_TO_PIXELFORMAT)
#undef TEXT_TO_PIXELFORMAT
return PF_Unknown;
}
const TCHAR* GetCubeFaceName(ECubeFace Face)
{
switch(Face)
{
case CubeFace_PosX:
return TEXT("PosX");
case CubeFace_NegX:
return TEXT("NegX");
case CubeFace_PosY:
return TEXT("PosY");
case CubeFace_NegY:
return TEXT("NegY");
case CubeFace_PosZ:
return TEXT("PosZ");
case CubeFace_NegZ:
return TEXT("NegZ");
default:
return TEXT("");
}
}
ECubeFace GetCubeFaceFromName(const FString& Name)
{
// not fast but doesn't have to be
if(Name.EndsWith(TEXT("PosX")))
{
return CubeFace_PosX;
}
else if(Name.EndsWith(TEXT("NegX")))
{
return CubeFace_NegX;
}
else if(Name.EndsWith(TEXT("PosY")))
{
return CubeFace_PosY;
}
else if(Name.EndsWith(TEXT("NegY")))
{
return CubeFace_NegY;
}
else if(Name.EndsWith(TEXT("PosZ")))
{
return CubeFace_PosZ;
}
else if(Name.EndsWith(TEXT("NegZ")))
{
return CubeFace_NegZ;
}
return CubeFace_MAX;
}
class FVector4VertexDeclaration : public FRenderResource
{
public:
FVertexDeclarationRHIRef VertexDeclarationRHI;
virtual void InitRHI() override
{
FVertexDeclarationElementList Elements;
Elements.Add(FVertexElement(0, 0, VET_Float4, 0, sizeof(FVector4)));
VertexDeclarationRHI = RHICreateVertexDeclaration(Elements);
}
virtual void ReleaseRHI() override
{
VertexDeclarationRHI.SafeRelease();
}
};
TGlobalResource<FVector4VertexDeclaration> GVector4VertexDeclaration;
RENDERCORE_API FVertexDeclarationRHIRef& GetVertexDeclarationFVector4()
{
return GVector4VertexDeclaration.VertexDeclarationRHI;
}
class FVector3VertexDeclaration : public FRenderResource
{
public:
FVertexDeclarationRHIRef VertexDeclarationRHI;
virtual void InitRHI() override
{
FVertexDeclarationElementList Elements;
Elements.Add(FVertexElement(0, 0, VET_Float3, 0, sizeof(FVector)));
VertexDeclarationRHI = RHICreateVertexDeclaration(Elements);
}
virtual void ReleaseRHI() override
{
VertexDeclarationRHI.SafeRelease();
}
};
TGlobalResource<FVector3VertexDeclaration> GVector3VertexDeclaration;
RENDERCORE_API FVertexDeclarationRHIRef& GetVertexDeclarationFVector3()
{
return GVector3VertexDeclaration.VertexDeclarationRHI;
}
RENDERCORE_API bool PlatformSupportsSimpleForwardShading(EShaderPlatform Platform)
{
static const auto SupportSimpleForwardShadingCVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.SupportSimpleForwardShading"));
// Scalability feature only needed / used on PC
return IsPCPlatform(Platform) && SupportSimpleForwardShadingCVar->GetValueOnAnyThread() != 0;
}
RENDERCORE_API bool IsSimpleForwardShadingEnabled(EShaderPlatform Platform)
{
static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.SimpleForwardShading"));
return CVar->GetValueOnAnyThread() != 0 && PlatformSupportsSimpleForwardShading(Platform);
}
RENDERCORE_API bool IsForwardShadingEnabled(ERHIFeatureLevel::Type FeatureLevel)
{
static const auto CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.ForwardShading"));
return CVar->GetValueOnAnyThread() != 0
// Culling uses compute shader
&& FeatureLevel >= ERHIFeatureLevel::SM5;
}
class FUnitCubeVertexBuffer : public FVertexBuffer
{
public:
/**
* Initialize the RHI for this rendering resource
*/
void InitRHI() override
{
const int32 NumVerts = 8;
TResourceArray<FVector4, VERTEXBUFFER_ALIGNMENT> Verts;
Verts.SetNumUninitialized(NumVerts);
for (uint32 Z = 0; Z < 2; Z++)
{
for (uint32 Y = 0; Y < 2; Y++)
{
for (uint32 X = 0; X < 2; X++)
{
const FVector4 Vertex = FVector4(
(X ? -1 : 1),
(Y ? -1 : 1),
(Z ? -1 : 1),
1.0f
);
Verts[GetCubeVertexIndex(X, Y, Z)] = Vertex;
}
}
}
uint32 Size = Verts.GetResourceDataSize();
// Create vertex buffer. Fill buffer with initial data upon creation
FRHIResourceCreateInfo CreateInfo(&Verts);
VertexBufferRHI = RHICreateVertexBuffer(Size, BUF_Static, CreateInfo);
}
};
class FUnitCubeIndexBuffer : public FIndexBuffer
{
public:
/**
* Initialize the RHI for this rendering resource
*/
void InitRHI() override
{
TResourceArray<uint16, INDEXBUFFER_ALIGNMENT> Indices;
int32 NumIndices = ARRAY_COUNT(GCubeIndices);
Indices.AddUninitialized(NumIndices);
FMemory::Memcpy(Indices.GetData(), GCubeIndices, NumIndices * sizeof(uint16));
const uint32 Size = Indices.GetResourceDataSize();
const uint32 Stride = sizeof(uint16);
// Create index buffer. Fill buffer with initial data upon creation
FRHIResourceCreateInfo CreateInfo(&Indices);
IndexBufferRHI = RHICreateIndexBuffer(Stride, Size, BUF_Static, CreateInfo);
}
};
static TGlobalResource<FUnitCubeVertexBuffer> GUnitCubeVertexBuffer;
static TGlobalResource<FUnitCubeIndexBuffer> GUnitCubeIndexBuffer;
RENDERCORE_API FVertexBufferRHIRef& GetUnitCubeVertexBuffer()
{
return GUnitCubeVertexBuffer.VertexBufferRHI;
}
RENDERCORE_API FIndexBufferRHIRef& GetUnitCubeIndexBuffer()
{
return GUnitCubeIndexBuffer.IndexBufferRHI;
}
RENDERCORE_API void QuantizeSceneBufferSize(int32& InOutBufferSizeX, int32& InOutBufferSizeY)
{
// Ensure sizes are dividable by DividableBy to get post processing effects with lower resolution working well
const uint32 DividableBy = 4;
const uint32 Mask = ~(DividableBy - 1);
InOutBufferSizeX = (InOutBufferSizeX + DividableBy - 1) & Mask;
InOutBufferSizeY = (InOutBufferSizeY + DividableBy - 1) & Mask;
}