// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. #pragma once #include "Engine/Graphics/GPUResource.h" #include "GPUTextureDescription.h" class GPUContext; class GPUTask; class TextureMipData; class TextureData; template class DataContainer; typedef DataContainer BytesContainer; class Task; /// /// Defines a view for the surface, full resource or any of the sub-parts. Can be used to define a single subresource of the texture, volume texture or texture array. Used to render to the texture and/or use textures in the shaders. /// API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API GPUTextureView : public GPUResourceView { DECLARE_SCRIPTING_TYPE_NO_SPAWN(GPUTextureView); protected: GPUResource* _parent = nullptr; PixelFormat _format = PixelFormat::Unknown; MSAALevel _msaa = MSAALevel::None; GPUTextureView() : GPUResourceView(SpawnParams(Guid::New(), TypeInitializer)) { } FORCE_INLINE void Init(GPUResource* parent, PixelFormat format, MSAALevel msaa) { _parent = parent; _format = format; _msaa = msaa; if (parent) LastRenderTime = &parent->LastRenderTime; } public: /// /// Gets parent GPU resource owning that view. /// API_PROPERTY() FORCE_INLINE GPUResource* GetParent() const { return _parent; } /// /// Gets the view format. /// API_PROPERTY() FORCE_INLINE PixelFormat GetFormat() const { return _format; } /// /// Gets view MSAA level. /// API_PROPERTY() FORCE_INLINE MSAALevel GetMSAA() const { return _msaa; } }; /// /// The GPU texture resource object. This class is able to create 2D/3D textures, volume textures and render targets. /// API_CLASS(Sealed) class FLAXENGINE_API GPUTexture : public GPUResource { DECLARE_SCRIPTING_TYPE_NO_SPAWN(GPUTexture); static GPUTexture* Spawn(const SpawnParams& params); static GPUTexture* New(); protected: int32 _residentMipLevels; bool _sRGB, _isBlockCompressed; GPUTextureDescription _desc; GPUTexture(); public: /// /// Gets a value indicating whether this texture has any resided mip (data already uploaded to the GPU). /// API_PROPERTY() FORCE_INLINE bool HasResidentMip() const { return _residentMipLevels != 0; } /// /// Gets a value indicating whether this texture has been allocated. /// API_PROPERTY() FORCE_INLINE bool IsAllocated() const { return _desc.MipLevels > 0; } /// /// Gets texture width (in texels). /// API_PROPERTY() FORCE_INLINE int32 Width() const { return _desc.Width; } /// /// Gets texture height (in texels). /// API_PROPERTY() FORCE_INLINE int32 Height() const { return _desc.Height; } /// /// Gets texture depth (in texels). /// API_PROPERTY() FORCE_INLINE int32 Depth() const { return _desc.Depth; } /// /// Gets number of textures in the array. /// API_PROPERTY() FORCE_INLINE int32 ArraySize() const { return _desc.ArraySize; } /// /// Gets multi-sampling parameters for the texture. /// API_PROPERTY() FORCE_INLINE MSAALevel MultiSampleLevel() const { return _desc.MultiSampleLevel; } /// /// Gets number of mipmap levels in the texture. /// API_PROPERTY() FORCE_INLINE int32 MipLevels() const { return _desc.MipLevels; } /// /// Gets the number of resident mipmap levels in the texture (already uploaded to the GPU). /// API_PROPERTY() FORCE_INLINE int32 ResidentMipLevels() const { return _residentMipLevels; } /// /// Gets the index of the highest resident mip map (may be equal to MipLevels if no mip has been uploaded). Note: mip=0 is the highest (top quality). /// API_PROPERTY() FORCE_INLINE int32 HighestResidentMipIndex() const { return MipLevels() - ResidentMipLevels(); } /// /// Gets texture data format. /// API_PROPERTY() FORCE_INLINE PixelFormat Format() const { return _desc.Format; } /// /// Gets flags of the texture. /// API_PROPERTY() FORCE_INLINE GPUTextureFlags Flags() const { return _desc.Flags; } /// /// Gets texture dimensions. /// API_PROPERTY() FORCE_INLINE TextureDimensions Dimensions() const { return _desc.Dimensions; } /// /// Gets texture description structure. /// API_PROPERTY() FORCE_INLINE const GPUTextureDescription& GetDescription() const { return _desc; } public: /// /// Gets a value indicating whether this texture is a render target. /// FORCE_INLINE bool IsRenderTarget() const { return _desc.IsRenderTarget(); } /// /// Gets a value indicating whether this texture is a shader resource. /// FORCE_INLINE bool IsShaderResource() const { return _desc.IsShaderResource(); } /// /// Gets a value indicating whether this texture is a depth stencil. /// FORCE_INLINE bool IsDepthStencil() const { return _desc.IsDepthStencil(); } /// /// Gets a value indicating whether this texture is a unordered access. /// FORCE_INLINE bool IsUnorderedAccess() const { return _desc.IsUnorderedAccess(); } /// /// Gets a value indicating whether this instance has per mip level views. /// FORCE_INLINE bool HasPerMipViews() const { return _desc.HasPerMipViews(); } /// /// Gets a value indicating whether this instance has per slice views. /// FORCE_INLINE bool HasPerSliceViews() const { return _desc.HasPerSliceViews(); } /// /// Gets a value indicating whether this instance is a multi sample texture. /// FORCE_INLINE bool IsMultiSample() const { return _desc.IsMultiSample(); } /// /// Gets a value indicating whether this instance is a cubemap texture. /// FORCE_INLINE bool IsCubeMap() const { return _desc.Dimensions == TextureDimensions::CubeTexture; } /// /// Gets a value indicating whether this instance is a volume texture. /// FORCE_INLINE bool IsVolume() const { return _desc.Dimensions == TextureDimensions::VolumeTexture; } /// /// Gets a value indicating whether this instance is an array texture. /// FORCE_INLINE bool IsArray() const { return _desc.ArraySize != 1; } /// /// Checks if texture contains sRGB colors data. /// FORCE_INLINE bool IsSRGB() const { return _sRGB; } /// /// Checks if texture is normal texture asset (not render target or unordered access or depth buffer or sth else). /// FORCE_INLINE bool IsRegularTexture() const { return _desc.Flags == GPUTextureFlags::ShaderResource; } /// /// Checks if texture is a staging buffer (supports direct CPU access). /// bool IsStaging() const; /// /// Gets a boolean indicating whether this is a using a block compress format (BC1, BC2, BC3, BC4, BC5, BC6H, BC7, etc.). /// FORCE_INLINE bool IsBlockCompressed() const { return _isBlockCompressed; } public: /// /// Gets the texture total size in pixels. /// API_PROPERTY() Float2 Size() const; /// /// Gets the texture total size in pixels (with depth). /// API_PROPERTY() Float3 Size3() const; /// /// Returns true if texture has size that is power of two. /// /// True if texture has size that is power of two. API_PROPERTY() bool IsPowerOfTwo() const; /// /// Gets the texture mip map dimensions. /// /// Mip level index (zero-based where 0 is top texture surface). /// The calculated mip level width (in pixels). /// The calculated mip level height (in pixels). API_FUNCTION() void GetMipSize(int32 mipLevelIndex, API_PARAM(Out) int32& mipWidth, API_PARAM(Out) int32& mipHeight) const; /// /// Gets the texture mip map dimensions. /// /// Mip level index (zero-based where 0 is top texture surface). /// The calculated mip level width (in pixels). /// The calculated mip level height (in pixels). /// The calculated mip level depth (in pixels). API_FUNCTION() void GetMipSize(int32 mipLevelIndex, API_PARAM(Out) int32& mipWidth, API_PARAM(Out) int32& mipHeight, API_PARAM(Out) int32& mipDepth) const; /// /// Gets current texture size (uploaded to the GPU and in use). /// /// The current width (in pixels). /// The current height (in pixels). void GetResidentSize(int32& width, int32& height) const; /// /// Gets current texture size (uploaded to the GPU and in use). /// /// The current width (in pixels). /// The current height (in pixels). /// The current depth (in pixels). void GetResidentSize(int32& width, int32& height, int32& depth) const; public: /// /// Calculates mip map row pitch (in bytes). /// /// Index of the mip. /// Row pitch. uint32 RowPitch(int32 mipIndex = 0) const; /// /// Calculates mip map slice pitch (in bytes). /// /// Index of the mip. /// Slice pitch. uint32 SlicePitch(int32 mipIndex = 0) const; /// /// Computes row and slice pitch of the mip map. /// /// Index of the mip. /// The row pitch. /// The slice pitch. void ComputePitch(int32 mipIndex, uint32& rowPitch, uint32& slicePitch) const; /// /// Calculates the size of a particular mip. /// /// The size. /// The mip level. /// Mip size. int32 CalculateMipSize(int32 size, int32 mipLevel) const; public: int32 ComputeSubresourceSize(int32 subresource, int32 rowAlign, int32 sliceAlign) const; int32 ComputeBufferOffset(int32 subresource, int32 rowAlign, int32 sliceAlign) const; int32 ComputeBufferTotalSize(int32 rowAlign, int32 sliceAlign) const; int32 ComputeSlicePitch(int32 mipLevel, int32 rowAlign) const; int32 ComputeRowPitch(int32 mipLevel, int32 rowAlign) const; public: /// /// Gets the view to the first surface (only for 2D textures). /// /// The view to the main texture surface. API_FUNCTION() FORCE_INLINE GPUTextureView* View() const { return View(0); } /// /// Gets the view to the surface at index in an array. /// /// /// To use per depth/array slice view you need to specify the when creating the resource. /// /// The index of the surface in an array (or depth slice index). /// The view to the surface at index in an array. API_FUNCTION() virtual GPUTextureView* View(int32 arrayOrDepthIndex) const = 0; /// /// Gets the view to the mip map surface at index in an array. /// /// /// To use per mip map view you need to specify the when creating the resource. /// /// The index of the surface in an array (or depth slice index). /// Index of the mip level. /// The view to the surface at index in an array. API_FUNCTION() virtual GPUTextureView* View(int32 arrayOrDepthIndex, int32 mipMapIndex) const = 0; /// /// Gets the view to the array of surfaces /// /// /// To use array texture view you need to create render target as an array. /// /// The view to the array of surfaces. API_FUNCTION() virtual GPUTextureView* ViewArray() const = 0; /// /// Gets the view to the volume texture (3D). /// /// /// To use volume texture view you need to create render target as a volume resource (3D texture with Depth > 1). /// /// The view to the volume texture. API_FUNCTION() virtual GPUTextureView* ViewVolume() const = 0; /// /// Gets the view to the texture as read-only depth/stencil buffer. Valid only if graphics device supports it and the texture uses depth/stencil. /// /// The view to the depth-stencil resource descriptor as read-only depth. API_FUNCTION() virtual GPUTextureView* ViewReadOnlyDepth() const = 0; /// /// Implicit conversion to the first surface (only for 2D textures). /// /// The view to the main texture surface. FORCE_INLINE operator GPUTextureView*() const { return View(0); } public: /// /// Initializes a texture resource (allocates the GPU memory and performs the resource setup). /// /// The texture description. /// True if cannot create texture, otherwise false. API_FUNCTION() bool Init(API_PARAM(Ref) const GPUTextureDescription& desc); /// /// Creates new staging readback texture with the same dimensions and properties as a source texture (but without a data transferred; warning: caller must delete object). /// /// The staging readback texture. GPUTexture* ToStagingReadback() const; /// /// Creates new staging upload texture with the same dimensions and properties as a source texture (but without a data transferred; warning: caller must delete object). /// /// The staging upload texture. GPUTexture* ToStagingUpload() const; /// /// Resizes the texture. It must be created first. /// /// The width. /// The height. /// The new texture format. Use Unknown to remain texture format unchanged. /// True if fails, otherwise false. API_FUNCTION() bool Resize(int32 width, int32 height, PixelFormat format = PixelFormat::Unknown) { const auto depth = IsAllocated() ? Depth() : 1; return Resize(width, height, depth, format); } /// /// Resizes the texture. It must be created first. /// /// The width. /// The height. /// The depth. /// The new texture format. Use Unknown to remain texture format unchanged. /// True if fails, otherwise false. API_FUNCTION() bool Resize(int32 width, int32 height, int32 depth, PixelFormat format = PixelFormat::Unknown); public: /// /// Gets the native pointer to the underlying resource. It's a low-level platform-specific handle. /// /// The pointer. API_PROPERTY() virtual void* GetNativePtr() const = 0; /// /// Uploads mip map data to the GPU. Creates async GPU task. /// /// Data to upload (it must be valid for the next a few frames due to GPU latency and async works executing) /// Mip level index. /// If true, the data will be copied to the async execution task instead of using the input pointer provided. /// Created async task or null if cannot. GPUTask* UploadMipMapAsync(const BytesContainer& data, int32 mipIndex, bool copyData = false); /// /// Uploads mip map data to the GPU. Creates async GPU task. /// /// Data to upload (it must be valid for the next a few frames due to GPU latency and async works executing) /// Mip level index. /// The data row pitch. /// The data slice pitch. /// If true, the data will be copied to the async execution task instead of using the input pointer provided. /// Created async task or null if cannot. GPUTask* UploadMipMapAsync(const BytesContainer& data, int32 mipIndex, int32 rowPitch, int32 slicePitch, bool copyData = false); /// /// Stops current thread execution to gather texture data from the GPU. /// /// The result data. /// True if cannot download data, otherwise false. bool DownloadData(TextureData& result); /// /// Creates GPU async task that will gather texture data from the GPU. /// /// The result data. /// Download data task (not started yet). Task* DownloadDataAsync(TextureData& result); /// /// Gets texture mipmap data (raw bytes). Can be used only with textures created with Staging flag. /// /// Array slice index. /// Mip map index. /// Output mip data. /// Output mip data row pitch to use. Use 0 to use the pitch from the internal GPU storage. /// True if failed, otherwise false. virtual bool GetData(int32 arrayIndex, int32 mipMapIndex, TextureMipData& data, uint32 mipRowPitch = 0) = 0; /// /// Sets the number of resident mipmap levels in the texture (already uploaded to the GPU). /// API_PROPERTY() void SetResidentMipLevels(int32 count); /// /// Event called when texture residency gets changed. Texture Mip gets loaded into GPU memory and is ready to use. /// Delegate ResidentMipsChanged; protected: virtual bool OnInit() = 0; uint64 calculateMemoryUsage() const; virtual void OnResidentMipsChanged() = 0; public: // [GPUResource] String ToString() const override; GPUResourceType GetResourceType() const final override; protected: // [GPUResource] void OnReleaseGPU() override; };