You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#rnx #rb Francis.Hurteau #preflight 62878c81286cf1867a4de4d2 [CL 20346449 by danny couture in ue5-main branch]
664 lines
20 KiB
C++
664 lines
20 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
TextureCube.cpp: UTextureCube implementation.
|
|
=============================================================================*/
|
|
|
|
#include "Engine/TextureCube.h"
|
|
#include "RenderUtils.h"
|
|
#include "TextureResource.h"
|
|
#include "EngineUtils.h"
|
|
#include "DeviceProfiles/DeviceProfile.h"
|
|
#include "DeviceProfiles/DeviceProfileManager.h"
|
|
#include "Interfaces/ITargetPlatform.h"
|
|
#include "TextureCompiler.h"
|
|
#include "Misc/ScopedSlowTask.h"
|
|
#include "UObject/StrongObjectPtr.h"
|
|
#include "Engine/Public/ImageUtils.h"
|
|
#include "UObject/ReleaseObjectVersion.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "UTextureCube"
|
|
|
|
UTextureCube* UTextureCube::CreateTransient(int32 InSizeX, int32 InSizeY, EPixelFormat InFormat, const FName InName)
|
|
{
|
|
UTextureCube* NewTexture = nullptr;
|
|
if (InSizeX > 0 && InSizeY > 0 &&
|
|
(InSizeX % GPixelFormats[InFormat].BlockSizeX) == 0 &&
|
|
(InSizeY % GPixelFormats[InFormat].BlockSizeY) == 0)
|
|
{
|
|
NewTexture = NewObject<UTextureCube>(
|
|
GetTransientPackage(),
|
|
InName,
|
|
RF_Transient
|
|
);
|
|
|
|
NewTexture->SetPlatformData(new FTexturePlatformData());
|
|
NewTexture->GetPlatformData()->SizeX = InSizeX;
|
|
NewTexture->GetPlatformData()->SizeY = InSizeY;
|
|
NewTexture->GetPlatformData()->PixelFormat = InFormat;
|
|
|
|
// Allocate first mipmap.
|
|
int32 NumBlocksX = InSizeX / GPixelFormats[InFormat].BlockSizeX;
|
|
int32 NumBlocksY = InSizeY / GPixelFormats[InFormat].BlockSizeY;
|
|
FTexture2DMipMap* Mip = new FTexture2DMipMap();
|
|
NewTexture->GetPlatformData()->Mips.Add(Mip);
|
|
Mip->SizeX = InSizeX;
|
|
Mip->SizeY = InSizeY;
|
|
Mip->BulkData.Lock(LOCK_READ_WRITE);
|
|
Mip->BulkData.Realloc(6 * NumBlocksX * NumBlocksY * GPixelFormats[InFormat].BlockBytes);
|
|
Mip->BulkData.Unlock();
|
|
}
|
|
else
|
|
{
|
|
UE_LOG(LogTexture, Warning, TEXT("Invalid parameters specified for UTextureCube::CreateTransient()"));
|
|
}
|
|
return NewTexture;
|
|
}
|
|
|
|
/**
|
|
* Get the optimal placeholder to use during texture compilation
|
|
*/
|
|
static UTextureCube* GetDefaultTextureCube(const UTextureCube* Texture)
|
|
{
|
|
static TStrongObjectPtr<UTextureCube> CheckerboardTexture;
|
|
|
|
if (!CheckerboardTexture.IsValid())
|
|
{
|
|
CheckerboardTexture.Reset(FImageUtils::CreateCheckerboardCubeTexture(FColor(200, 200, 200, 128), FColor(128, 128, 128, 128)));
|
|
}
|
|
|
|
return CheckerboardTexture.Get();
|
|
}
|
|
|
|
UTextureCube::UTextureCube(const FObjectInitializer& ObjectInitializer)
|
|
: Super(ObjectInitializer)
|
|
, PrivatePlatformData(nullptr)
|
|
#if WITH_TEXTURE_PLATFORMDATA_DEPRECATIONS
|
|
, PlatformData(
|
|
[this]()-> FTexturePlatformData* { return GetPlatformData(); },
|
|
[this](FTexturePlatformData* InPlatformData) { SetPlatformData(InPlatformData); })
|
|
#endif
|
|
{
|
|
SRGB = true;
|
|
}
|
|
|
|
FTexturePlatformData** UTextureCube::GetRunningPlatformData()
|
|
{
|
|
// @todo DC GetRunningPlatformData is fundamentally unsafe but almost unused... should we replace it with Get/SetRunningPlatformData directly in the base class
|
|
return &PrivatePlatformData;
|
|
}
|
|
|
|
void UTextureCube::SetPlatformData(FTexturePlatformData* InPlatformData)
|
|
{
|
|
PrivatePlatformData = InPlatformData;
|
|
}
|
|
|
|
// Any direct access to GetPlatformData() will stall until the structure
|
|
// is safe to use. It is advisable to replace those use case with
|
|
// async aware code to avoid stalls where possible.
|
|
const FTexturePlatformData* UTextureCube::GetPlatformData() const
|
|
{
|
|
#if WITH_EDITOR
|
|
if (PrivatePlatformData && !PrivatePlatformData->IsAsyncWorkComplete())
|
|
{
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(UTextureCube::GetPlatformDataStall);
|
|
UE_LOG(LogTexture, Log, TEXT("Call to GetPlatformData() is forcing a wait on data that is not yet ready."));
|
|
|
|
FText Msg = FText::Format(LOCTEXT("WaitOnTextureCompilation", "Waiting on texture compilation {0} ..."), FText::FromString(GetName()));
|
|
FScopedSlowTask Progress(1.f, Msg, true);
|
|
Progress.MakeDialog(true);
|
|
PrivatePlatformData->FinishCache();
|
|
}
|
|
#endif // #if WITH_EDITOR
|
|
return PrivatePlatformData;
|
|
}
|
|
|
|
FTexturePlatformData* UTextureCube::GetPlatformData()
|
|
{
|
|
// For now, this is the same implementation as the const version.
|
|
const UTextureCube* ConstThis = this;
|
|
return const_cast<FTexturePlatformData*>(ConstThis->GetPlatformData());
|
|
}
|
|
|
|
void UTextureCube::Serialize(FArchive& Ar)
|
|
{
|
|
DECLARE_SCOPE_CYCLE_COUNTER(TEXT("UTextureCube::Serialize"), STAT_TextureCube_Serialize, STATGROUP_LoadTime);
|
|
|
|
Ar.UsingCustomVersion(FReleaseObjectVersion::GUID);
|
|
|
|
Super::Serialize(Ar);
|
|
|
|
FStripDataFlags StripFlags(Ar);
|
|
bool bCooked = Ar.IsCooking();
|
|
Ar << bCooked;
|
|
|
|
if (bCooked || Ar.IsCooking())
|
|
{
|
|
SerializeCookedPlatformData(Ar);
|
|
}
|
|
|
|
#if WITH_EDITORONLY_DATA
|
|
if (Ar.IsLoading() && Source.GetNumSlices() == 1 && MaxTextureSize == 0 && Ar.CustomVer(FReleaseObjectVersion::GUID) < FReleaseObjectVersion::LonglatTextureCubeDefaultMaxResolution)
|
|
{
|
|
// Previously default maximum resolution for cubemaps generated from long-lat sources was set to 512 pixels in the texture building code.
|
|
// This value is now explicitly set for cubemaps loaded from earlier versions of the stream in order to avoid texture rebuild.
|
|
MaxTextureSize = 512;
|
|
UE_LOG(LogTexture, Log, TEXT("Default maximum texture size for cubemaps generated from long-lat sources has been changed from 512 to unlimited. In order to preserve old behavior for '%s', its maximum texture size has been explicitly set to 512."), *GetPathName());
|
|
}
|
|
#endif // #if WITH_EDITORONLY_DATA
|
|
}
|
|
|
|
void UTextureCube::PostLoad()
|
|
{
|
|
#if WITH_EDITOR
|
|
if (FApp::CanEverRender())
|
|
{
|
|
if (FTextureCompilingManager::Get().IsAsyncCompilationAllowed(this))
|
|
{
|
|
// Might already have been triggered during serialization
|
|
if (!PrivatePlatformData)
|
|
{
|
|
BeginCachePlatformData();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FinishCachePlatformData();
|
|
}
|
|
}
|
|
#endif // #if WITH_EDITOR
|
|
|
|
Super::PostLoad();
|
|
}
|
|
|
|
void UTextureCube::GetAssetRegistryTags(TArray<FAssetRegistryTag>& OutTags) const
|
|
{
|
|
#if WITH_EDITOR
|
|
int32 SizeX = Source.GetSizeX();
|
|
int32 SizeY = Source.GetSizeY();
|
|
#else
|
|
int32 SizeX = 0;
|
|
int32 SizeY = 0;
|
|
#endif
|
|
|
|
const FString Dimensions = FString::Printf(TEXT("%dx%d"), SizeX, SizeY);
|
|
OutTags.Add( FAssetRegistryTag("Dimensions", Dimensions, FAssetRegistryTag::TT_Dimensional) );
|
|
OutTags.Add( FAssetRegistryTag("Format", GPixelFormats[GetPixelFormat()].Name, FAssetRegistryTag::TT_Alphabetical) );
|
|
|
|
Super::GetAssetRegistryTags(OutTags);
|
|
}
|
|
|
|
void UTextureCube::UpdateResource()
|
|
{
|
|
#if WITH_EDITOR
|
|
// Recache platform data if the source has changed.
|
|
if (FTextureCompilingManager::Get().IsAsyncCompilationAllowed(this))
|
|
{
|
|
BeginCachePlatformData();
|
|
}
|
|
else
|
|
{
|
|
CachePlatformData();
|
|
}
|
|
#endif // #if WITH_EDITOR
|
|
|
|
// Route to super.
|
|
Super::UpdateResource();
|
|
}
|
|
|
|
FString UTextureCube::GetDesc()
|
|
{
|
|
return FString::Printf(TEXT("Cube: %dx%d [%s]"),
|
|
GetSizeX(),
|
|
GetSizeY(),
|
|
GPixelFormats[GetPixelFormat()].Name
|
|
);
|
|
}
|
|
|
|
uint32 UTextureCube::CalcTextureMemorySize( int32 MipCount ) const
|
|
{
|
|
uint32 Size = 0;
|
|
if (GetPlatformData())
|
|
{
|
|
int32 SizeX = GetSizeX();
|
|
int32 SizeY = GetSizeY();
|
|
int32 NumMips = GetNumMips();
|
|
EPixelFormat Format = GetPixelFormat();
|
|
|
|
ensureMsgf(SizeX == SizeY, TEXT("Cubemap faces expected to be square. Actual sizes are: %i, %i"), SizeX, SizeY);
|
|
|
|
// Figure out what the first mip to use is.
|
|
int32 FirstMip = FMath::Max( 0, NumMips - MipCount );
|
|
FIntPoint MipExtents = CalcMipMapExtent(SizeX, SizeY, Format, FirstMip);
|
|
|
|
uint32 TextureAlign = 0;
|
|
uint64 TextureSize = RHICalcTextureCubePlatformSize(MipExtents.X, Format, FMath::Max( 1, MipCount ), TexCreate_None, FRHIResourceCreateInfo(GetPlatformData()->GetExtData()), TextureAlign);
|
|
Size = (uint32)TextureSize;
|
|
}
|
|
return Size;
|
|
}
|
|
|
|
uint32 UTextureCube::CalcTextureMemorySizeEnum( ETextureMipCount Enum ) const
|
|
{
|
|
if ( Enum == TMC_ResidentMips || Enum == TMC_AllMipsBiased )
|
|
{
|
|
return CalcTextureMemorySize( GetNumMips() - GetCachedLODBias() );
|
|
}
|
|
else
|
|
{
|
|
return CalcTextureMemorySize( GetNumMips() );
|
|
}
|
|
}
|
|
|
|
// While compiling the platform data in editor, we will return the
|
|
// placeholders value to ensure rendering works as expected and that
|
|
// there are no thread-unsafe access to the platform data being built.
|
|
// Any process requiring a fully up-to-date platform data is expected to
|
|
// call FTextureCompiler:Get().FinishCompilation on UTexture first.
|
|
int32 UTextureCube::GetSizeX() const
|
|
{
|
|
if (PrivatePlatformData)
|
|
{
|
|
#if WITH_EDITOR
|
|
if (IsDefaultTexture())
|
|
{
|
|
return GetDefaultTextureCube(this)->GetSizeX();
|
|
}
|
|
#endif
|
|
return PrivatePlatformData->SizeX;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32 UTextureCube::GetSizeY() const
|
|
{
|
|
if (PrivatePlatformData)
|
|
{
|
|
#if WITH_EDITOR
|
|
if (IsDefaultTexture())
|
|
{
|
|
return GetDefaultTextureCube(this)->GetSizeY();
|
|
}
|
|
#endif
|
|
return PrivatePlatformData->SizeY;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32 UTextureCube::GetNumMips() const
|
|
{
|
|
if (PrivatePlatformData)
|
|
{
|
|
#if WITH_EDITOR
|
|
if (IsDefaultTexture())
|
|
{
|
|
return GetDefaultTextureCube(this)->GetNumMips();
|
|
}
|
|
#endif
|
|
return PrivatePlatformData->Mips.Num();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
EPixelFormat UTextureCube::GetPixelFormat() const
|
|
{
|
|
if (PrivatePlatformData)
|
|
{
|
|
#if WITH_EDITOR
|
|
if (IsDefaultTexture())
|
|
{
|
|
return GetDefaultTextureCube(this)->GetPixelFormat();
|
|
}
|
|
#endif
|
|
return PrivatePlatformData->PixelFormat;
|
|
}
|
|
return PF_Unknown;
|
|
}
|
|
|
|
class FTextureCubeResource : public FTextureResource
|
|
{
|
|
/** The FName of the LODGroup-specific stat */
|
|
FName LODGroupStatName;
|
|
|
|
public:
|
|
/**
|
|
* Minimal initialization constructor.
|
|
* @param InOwner - The UTextureCube which this FTextureCubeResource represents.
|
|
*/
|
|
FTextureCubeResource(UTextureCube* InOwner)
|
|
: Owner(InOwner)
|
|
, TextureSize(0)
|
|
, ProxiedResource(nullptr)
|
|
{
|
|
//Initialize the MipData array
|
|
for ( int32 FaceIndex=0;FaceIndex<6; FaceIndex++)
|
|
{
|
|
for( int32 MipIndex=0; MipIndex<UE_ARRAY_COUNT(MipData[FaceIndex]); MipIndex++ )
|
|
{
|
|
MipData[FaceIndex][MipIndex] = NULL;
|
|
}
|
|
}
|
|
|
|
check(Owner->GetNumMips() > 0);
|
|
|
|
TIndirectArray<FTexture2DMipMap>& Mips = InOwner->GetPlatformData()->Mips;
|
|
const int32 FirstMipTailIndex = Mips.Num() - FMath::Max(1, InOwner->GetPlatformData()->GetNumMipsInTail());
|
|
for (int32 MipIndex = 0; MipIndex <= FirstMipTailIndex; MipIndex++)
|
|
{
|
|
FTexture2DMipMap& Mip = Mips[MipIndex];
|
|
if( Mip.BulkData.GetBulkDataSize() <= 0 )
|
|
{
|
|
UE_LOG(LogTexture, Error, TEXT("Corrupt texture [%s]! Missing bulk data for MipIndex=%d"),*InOwner->GetFullName(),MipIndex );
|
|
}
|
|
else
|
|
{
|
|
TextureSize += Mip.BulkData.GetBulkDataSize();
|
|
uint32 MipSize = Mip.BulkData.GetBulkDataSize() / 6;
|
|
|
|
uint8* In = (uint8*)Mip.BulkData.Lock(LOCK_READ_ONLY);
|
|
|
|
for(uint32 Face = 0; Face < 6; ++Face)
|
|
{
|
|
MipData[Face][MipIndex] = FMemory::Malloc(MipSize);
|
|
FMemory::Memcpy(MipData[Face][MipIndex], In + MipSize * Face, MipSize);
|
|
}
|
|
|
|
Mip.BulkData.Unlock();
|
|
}
|
|
}
|
|
STAT( LODGroupStatName = TextureGroupStatFNames[InOwner->LODGroup] );
|
|
}
|
|
|
|
/**
|
|
* Minimal initialization constructor.
|
|
* @param InOwner - The UTextureCube which this FTextureCubeResource represents.
|
|
* @param InProxiedResource - The resource to proxy.
|
|
*/
|
|
FTextureCubeResource(UTextureCube* InOwner, const FTextureCubeResource* InProxiedResource)
|
|
: Owner(InOwner)
|
|
, TextureSize(0)
|
|
, ProxiedResource(InProxiedResource)
|
|
{
|
|
//Initialize the MipData array
|
|
for (int32 FaceIndex = 0; FaceIndex < 6; FaceIndex++)
|
|
{
|
|
for (int32 MipIndex = 0; MipIndex < UE_ARRAY_COUNT(MipData[FaceIndex]); MipIndex++)
|
|
{
|
|
MipData[FaceIndex][MipIndex] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Destructor, freeing MipData in the case of resource being destroyed without ever
|
|
* having been initialized by the rendering thread via InitRHI.
|
|
*/
|
|
~FTextureCubeResource()
|
|
{
|
|
// Make sure we're not leaking memory if InitRHI has never been called.
|
|
for (int32 i=0; i<6; i++)
|
|
{
|
|
for( int32 MipIndex=0; MipIndex<UE_ARRAY_COUNT(MipData[i]); MipIndex++ )
|
|
{
|
|
// free any mip data that was copied
|
|
if( MipData[i][MipIndex] )
|
|
{
|
|
FMemory::Free( MipData[i][MipIndex] );
|
|
}
|
|
MipData[i][MipIndex] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Called when the resource is initialized. This is only called by the rendering thread.
|
|
*/
|
|
virtual void InitRHI() override
|
|
{
|
|
if (ProxiedResource)
|
|
{
|
|
TextureCubeRHI = ProxiedResource->GetTextureCubeRHI();
|
|
TextureRHI = TextureCubeRHI;
|
|
SamplerStateRHI = ProxiedResource->SamplerStateRHI;
|
|
RHIUpdateTextureReference(Owner->TextureReference.TextureReferenceRHI, TextureRHI);
|
|
return;
|
|
}
|
|
|
|
INC_DWORD_STAT_BY( STAT_TextureMemory, TextureSize );
|
|
INC_DWORD_STAT_FNAME_BY( LODGroupStatName, TextureSize );
|
|
|
|
// Create the RHI texture.
|
|
const ETextureCreateFlags TexCreateFlags = (Owner->SRGB ? TexCreate_SRGB : TexCreate_None) | (Owner->bNotOfflineProcessed ? TexCreate_None : TexCreate_OfflineProcessed);
|
|
const FString Name = Owner->GetPathName();
|
|
|
|
const FRHITextureCreateDesc Desc =
|
|
FRHITextureCreateDesc::CreateCube(*Name)
|
|
.SetExtent(Owner->GetSizeX())
|
|
.SetFormat(Owner->GetPixelFormat())
|
|
.SetNumMips(Owner->GetNumMips())
|
|
.SetFlags(TexCreateFlags)
|
|
.SetExtData(Owner->GetPlatformData() ? Owner->GetPlatformData()->GetExtData() : 0);
|
|
|
|
TextureCubeRHI = RHICreateTexture(Desc);
|
|
|
|
TextureRHI = TextureCubeRHI;
|
|
TextureRHI->SetName(Owner->GetFName());
|
|
RHIBindDebugLabelName(TextureRHI, *Name);
|
|
RHIUpdateTextureReference(Owner->TextureReference.TextureReferenceRHI,TextureRHI);
|
|
|
|
// Read the mip-levels into the RHI texture.
|
|
int32 NumMips = Owner->GetNumMips();
|
|
check(NumMips < MAX_TEXTURE_MIP_COUNT);
|
|
for( int32 FaceIndex=0; FaceIndex<6; FaceIndex++ )
|
|
{
|
|
for(int32 MipIndex=0; MipIndex < NumMips; MipIndex++)
|
|
{
|
|
if( MipData[FaceIndex][MipIndex] != NULL )
|
|
{
|
|
uint32 DestStride;
|
|
void* TheMipData = RHILockTextureCubeFace( TextureCubeRHI, FaceIndex, 0, MipIndex, RLM_WriteOnly, DestStride, false );
|
|
GetData( FaceIndex, MipIndex, TheMipData, DestStride );
|
|
RHIUnlockTextureCubeFace( TextureCubeRHI, FaceIndex, 0, MipIndex, false );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create the sampler state RHI resource.
|
|
FSamplerStateInitializerRHI SamplerStateInitializer
|
|
(
|
|
(ESamplerFilter)UDeviceProfileManager::Get().GetActiveProfile()->GetTextureLODSettings()->GetSamplerFilter( Owner ),
|
|
AM_Clamp,
|
|
AM_Clamp,
|
|
AM_Clamp
|
|
);
|
|
SamplerStateRHI = GetOrCreateSamplerState(SamplerStateInitializer);
|
|
|
|
// Set the greyscale format flag appropriately.
|
|
EPixelFormat PixelFormat = Owner->GetPixelFormat();
|
|
bGreyScaleFormat = (PixelFormat == PF_G8) || (PixelFormat == PF_BC4);
|
|
}
|
|
|
|
virtual void ReleaseRHI() override
|
|
{
|
|
DEC_DWORD_STAT_BY( STAT_TextureMemory, TextureSize );
|
|
DEC_DWORD_STAT_FNAME_BY( LODGroupStatName, TextureSize );
|
|
RHIUpdateTextureReference(Owner->TextureReference.TextureReferenceRHI, nullptr);
|
|
TextureCubeRHI.SafeRelease();
|
|
FTextureResource::ReleaseRHI();
|
|
}
|
|
|
|
/** Returns the width of the texture in pixels. */
|
|
virtual uint32 GetSizeX() const override
|
|
{
|
|
if (ProxiedResource)
|
|
{
|
|
return ProxiedResource->GetSizeX();
|
|
}
|
|
|
|
return Owner->GetSizeX();
|
|
}
|
|
|
|
/** Returns the height of the texture in pixels. */
|
|
virtual uint32 GetSizeY() const override
|
|
{
|
|
if (ProxiedResource)
|
|
{
|
|
return ProxiedResource->GetSizeY();
|
|
}
|
|
|
|
return Owner->GetSizeY();
|
|
}
|
|
|
|
/**
|
|
* Accessor
|
|
* @return Texture2DRHI
|
|
*/
|
|
FTextureCubeRHIRef GetTextureCubeRHI() const
|
|
{
|
|
return TextureCubeRHI;
|
|
}
|
|
|
|
virtual bool IsProxy() const override { return ProxiedResource != nullptr; }
|
|
|
|
const FTextureCubeResource* GetProxiedResource() const { return ProxiedResource; }
|
|
private:
|
|
/** A reference to the texture's RHI resource as a cube-map texture. */
|
|
FTextureCubeRHIRef TextureCubeRHI;
|
|
|
|
/** Local copy/ cache of mip data. Only valid between creation and first call to InitRHI */
|
|
void* MipData[6][MAX_TEXTURE_MIP_COUNT];
|
|
|
|
/** The UTextureCube which this resource represents. */
|
|
const UTextureCube* Owner;
|
|
|
|
// Cached texture size for stats. */
|
|
int32 TextureSize;
|
|
|
|
const FTextureCubeResource* const ProxiedResource;
|
|
/**
|
|
* Writes the data for a single mip-level into a destination buffer.
|
|
* @param FaceIndex The index of the face of the mip-level to read.
|
|
* @param MipIndex The index of the mip-level to read.
|
|
* @param Dest The address of the destination buffer to receive the mip-level's data.
|
|
* @param DestPitch Number of bytes per row
|
|
*/
|
|
void GetData( int32 FaceIndex, int32 MipIndex, void* Dest, uint32 DestPitch )
|
|
{
|
|
check(MipIndex < MAX_TEXTURE_MIP_COUNT);
|
|
check( MipData[FaceIndex][MipIndex] );
|
|
|
|
// for platforms that returned 0 pitch from Lock, we need to just use the bulk data directly, never do
|
|
// runtime block size checking, conversion, or the like
|
|
if (DestPitch == 0)
|
|
{
|
|
FMemory::Memcpy(Dest, MipData[FaceIndex][MipIndex], Owner->GetPlatformData()->Mips[MipIndex].BulkData.GetBulkDataSize() / 6);
|
|
}
|
|
else
|
|
{
|
|
EPixelFormat PixelFormat = Owner->GetPixelFormat();
|
|
uint32 NumRows = 0;
|
|
uint32 SrcPitch = 0;
|
|
uint32 BlockSizeX = GPixelFormats[PixelFormat].BlockSizeX; // Block width in pixels
|
|
uint32 BlockSizeY = GPixelFormats[PixelFormat].BlockSizeY; // Block height in pixels
|
|
uint32 BlockBytes = GPixelFormats[PixelFormat].BlockBytes;
|
|
|
|
FIntPoint MipExtent = CalcMipMapExtent(Owner->GetSizeX(), Owner->GetSizeY(), PixelFormat, MipIndex);
|
|
|
|
uint32 NumColumns = (MipExtent.X + BlockSizeX - 1) / BlockSizeX; // Num-of columns in the source data (in blocks)
|
|
NumRows = (MipExtent.Y + BlockSizeY - 1) / BlockSizeY; // Num-of rows in the source data (in blocks)
|
|
SrcPitch = NumColumns * BlockBytes; // Num-of bytes per row in the source data
|
|
|
|
SIZE_T MipSizeInBytes = CalcTextureMipMapSize(MipExtent.X, MipExtent.Y, PixelFormat, 0);
|
|
|
|
if (SrcPitch == DestPitch)
|
|
{
|
|
|
|
// Copy data, not taking into account stride!
|
|
FMemory::Memcpy(Dest, MipData[FaceIndex][MipIndex], MipSizeInBytes);
|
|
}
|
|
else
|
|
{
|
|
// Copy data, taking the stride into account!
|
|
uint8 *Src = (uint8*) MipData[FaceIndex][MipIndex];
|
|
uint8 *Dst = (uint8*) Dest;
|
|
for ( uint32 Row=0; Row < NumRows; ++Row )
|
|
{
|
|
FMemory::Memcpy( Dst, Src, SrcPitch );
|
|
Src += SrcPitch;
|
|
Dst += DestPitch;
|
|
}
|
|
check( (PTRINT(Src) - PTRINT(MipData[FaceIndex][MipIndex])) == PTRINT(MipSizeInBytes) );
|
|
}
|
|
}
|
|
|
|
FMemory::Free( MipData[FaceIndex][MipIndex] );
|
|
MipData[FaceIndex][MipIndex] = NULL;
|
|
}
|
|
};
|
|
|
|
FTextureResource* UTextureCube::CreateResource()
|
|
{
|
|
#if WITH_EDITOR
|
|
if (!IsAsyncCacheComplete())
|
|
{
|
|
FTextureCompilingManager::Get().AddTextures({ this });
|
|
|
|
return new FTextureCubeResource(this, (const FTextureCubeResource*)GetDefaultTextureCube(this)->GetResource());
|
|
}
|
|
#endif
|
|
|
|
FTextureResource* NewResource = NULL;
|
|
if (GetNumMips() > 0)
|
|
{
|
|
NewResource = new FTextureCubeResource(this);
|
|
}
|
|
return NewResource;
|
|
}
|
|
|
|
void UTextureCube::GetResourceSizeEx(FResourceSizeEx& CumulativeResourceSize)
|
|
{
|
|
Super::GetResourceSizeEx(CumulativeResourceSize);
|
|
|
|
if (CumulativeResourceSize.GetResourceSizeMode() == EResourceSizeMode::Exclusive)
|
|
{
|
|
// Use only loaded mips
|
|
CumulativeResourceSize.AddDedicatedVideoMemoryBytes(CalcTextureMemorySizeEnum(TMC_ResidentMips));
|
|
}
|
|
else
|
|
{
|
|
// Use all possible mips
|
|
CumulativeResourceSize.AddDedicatedVideoMemoryBytes(CalcTextureMemorySizeEnum(TMC_AllMipsBiased));
|
|
}
|
|
}
|
|
|
|
bool UTextureCube::NeedsLoadForTargetPlatform(const ITargetPlatform* TargetPlatform) const
|
|
{
|
|
// TC_EncodedReflectionCapture is used only for EncodedCapture for Mobile and is hidden for the user.
|
|
if (CompressionSettings == TC_EncodedReflectionCapture)
|
|
{
|
|
const static FName EncodedHDR(TEXT("EncodedHDR"));
|
|
TArray<FName> Formats;
|
|
|
|
TargetPlatform->GetReflectionCaptureFormats(Formats);
|
|
|
|
return Formats.Contains(EncodedHDR);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
bool UTextureCube::IsDefaultTexture() const
|
|
{
|
|
return (PrivatePlatformData && !PrivatePlatformData->IsAsyncWorkComplete()) || (GetResource() && GetResource()->IsProxy());
|
|
}
|
|
|
|
uint32 UTextureCube::GetMaximumDimension() const
|
|
{
|
|
return GetMaxCubeTextureDimension();
|
|
}
|
|
#endif // #if WITH_EDITOR
|
|
|
|
#undef LOCTEXT_NAMESPACE |