From 3c1fd427ebd2c3937502e68bd67914ee76951461 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 28 Jun 2021 15:56:32 +0200 Subject: [PATCH] Add support for programmable samplers in shaders --- Source/Engine/Graphics/Config.h | 6 + Source/Engine/Graphics/GPUContext.h | 8 ++ Source/Engine/Graphics/GPUDevice.h | 7 + Source/Engine/Graphics/GPULimits.h | 5 + Source/Engine/Graphics/GPUResource.h | 2 +- ...USamplerDescription.cpp => GPUSampler.cpp} | 80 +++++++++-- Source/Engine/Graphics/Textures/GPUSampler.h | 58 ++++++++ .../Textures/GPUSamplerDescription.cs | 76 +++++++++++ .../Graphics/Textures/GPUSamplerDescription.h | 84 ++++++------ .../DirectX/DX11/GPUContextDX11.cpp | 10 ++ .../DirectX/DX11/GPUContextDX11.h | 1 + .../DirectX/DX11/GPUDeviceDX11.cpp | 8 ++ .../DirectX/DX11/GPUDeviceDX11.h | 1 + .../DirectX/DX11/GPUSamplerDX11.cpp | 128 ++++++++++++++++++ .../DirectX/DX11/GPUSamplerDX11.h | 31 +++++ .../DirectX/DX12/GPUContextDX12.cpp | 88 +++++++++--- .../DirectX/DX12/GPUContextDX12.h | 5 + .../DirectX/DX12/GPUDeviceDX12.cpp | 36 ++++- .../DirectX/DX12/GPUDeviceDX12.h | 3 + .../DirectX/DX12/GPUSamplerDX12.cpp | 124 +++++++++++++++++ .../DirectX/DX12/GPUSamplerDX12.h | 32 +++++ .../GraphicsDevice/Null/GPUContextNull.h | 4 + .../GraphicsDevice/Null/GPUDeviceNull.cpp | 7 + .../GraphicsDevice/Null/GPUDeviceNull.h | 1 + .../GraphicsDevice/Null/GPUSamplerNull.h | 23 ++++ .../Vulkan/GPUContextVulkan.cpp | 22 ++- .../GraphicsDevice/Vulkan/GPUContextVulkan.h | 4 +- .../GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp | 19 ++- .../GraphicsDevice/Vulkan/GPUDeviceVulkan.h | 27 +--- .../Vulkan/GPUSamplerVulkan.cpp | 56 ++++++++ .../GraphicsDevice/Vulkan/GPUSamplerVulkan.h | 31 +++++ 31 files changed, 866 insertions(+), 121 deletions(-) rename Source/Engine/Graphics/Textures/{GPUSamplerDescription.cpp => GPUSampler.cpp} (53%) create mode 100644 Source/Engine/Graphics/Textures/GPUSampler.h create mode 100644 Source/Engine/Graphics/Textures/GPUSamplerDescription.cs create mode 100644 Source/Engine/GraphicsDevice/DirectX/DX11/GPUSamplerDX11.cpp create mode 100644 Source/Engine/GraphicsDevice/DirectX/DX11/GPUSamplerDX11.h create mode 100644 Source/Engine/GraphicsDevice/DirectX/DX12/GPUSamplerDX12.cpp create mode 100644 Source/Engine/GraphicsDevice/DirectX/DX12/GPUSamplerDX12.h create mode 100644 Source/Engine/GraphicsDevice/Null/GPUSamplerNull.h create mode 100644 Source/Engine/GraphicsDevice/Vulkan/GPUSamplerVulkan.cpp create mode 100644 Source/Engine/GraphicsDevice/Vulkan/GPUSamplerVulkan.h diff --git a/Source/Engine/Graphics/Config.h b/Source/Engine/Graphics/Config.h index 88fbc780d..54004cdc0 100644 --- a/Source/Engine/Graphics/Config.h +++ b/Source/Engine/Graphics/Config.h @@ -14,6 +14,12 @@ // Maximum amount of binded unordered access resources at the same time #define GPU_MAX_UA_BINDED 2 +// Maximum amount of binded texture sampler resources at the same time +#define GPU_MAX_SAMPLER_BINDED 16 + +// Amount of initial slots used for global samplers (static, 4 common samplers + 2 comparision samplers) +#define GPU_STATIC_SAMPLERS_COUNT 6 + // Maximum amount of binded vertex buffers at the same time #define GPU_MAX_VB_BINDED 4 diff --git a/Source/Engine/Graphics/GPUContext.h b/Source/Engine/Graphics/GPUContext.h index 5e1219fa2..c46e81d46 100644 --- a/Source/Engine/Graphics/GPUContext.h +++ b/Source/Engine/Graphics/GPUContext.h @@ -16,6 +16,7 @@ class GPUShaderProgramCS; class GPUBuffer; class GPUPipelineState; class GPUTexture; +class GPUSampler; class GPUDevice; class GPUResource; class GPUResourceView; @@ -396,6 +397,13 @@ public: /// The index buffer. API_FUNCTION() virtual void BindIB(GPUBuffer* indexBuffer) = 0; + /// + /// Binds the texture sampler to the pipeline. + /// + /// The slot index. + /// The sampler. + API_FUNCTION() virtual void BindSampler(int32 slot, GPUSampler* sampler) = 0; + public: /// diff --git a/Source/Engine/Graphics/GPUDevice.h b/Source/Engine/Graphics/GPUDevice.h index 8290df1aa..45dd77c06 100644 --- a/Source/Engine/Graphics/GPUDevice.h +++ b/Source/Engine/Graphics/GPUDevice.h @@ -18,6 +18,7 @@ class GPUShader; class GPUTimerQuery; class GPUTexture; class GPUBuffer; +class GPUSampler; class GPUPipelineState; class GPUSwapChain; class Shader; @@ -360,6 +361,12 @@ public: /// The buffer. API_FUNCTION() virtual GPUBuffer* CreateBuffer(const StringView& name = StringView::Empty) = 0; + /// + /// Creates the texture sampler. + /// + /// The sampler. + API_FUNCTION() virtual GPUSampler* CreateSampler() = 0; + /// /// Creates the native window swap chain. /// diff --git a/Source/Engine/Graphics/GPULimits.h b/Source/Engine/Graphics/GPULimits.h index 401ce5178..0bf9c1437 100644 --- a/Source/Engine/Graphics/GPULimits.h +++ b/Source/Engine/Graphics/GPULimits.h @@ -314,4 +314,9 @@ DECLARE_SCRIPTING_TYPE_MINIMAL(GPULimits); /// The maximum size of the cube texture (both width and height). /// API_FIELD() int32 MaximumTextureCubeSize; + + /// + /// The maximum degree of anisotropic filtering used for texture sampling. + /// + API_FIELD() float MaximumSamplerAnisotropy; }; diff --git a/Source/Engine/Graphics/GPUResource.h b/Source/Engine/Graphics/GPUResource.h index 5d4eff81c..5f5a01d41 100644 --- a/Source/Engine/Graphics/GPUResource.h +++ b/Source/Engine/Graphics/GPUResource.h @@ -22,7 +22,7 @@ public: /// /// GPU Resources types. /// - DECLARE_ENUM_9(ResourceType, RenderTarget, Texture, CubeTexture, VolumeTexture, Buffer, Shader, PipelineState, Descriptor, Query); + DECLARE_ENUM_10(ResourceType, RenderTarget, Texture, CubeTexture, VolumeTexture, Buffer, Shader, PipelineState, Descriptor, Query, Sampler); /// /// GPU Resources object types. Used to detect Texture objects from subset of Types: RenderTarget, Texture, CubeTexture, VolumeTexture which use the same API object. diff --git a/Source/Engine/Graphics/Textures/GPUSamplerDescription.cpp b/Source/Engine/Graphics/Textures/GPUSampler.cpp similarity index 53% rename from Source/Engine/Graphics/Textures/GPUSamplerDescription.cpp rename to Source/Engine/Graphics/Textures/GPUSampler.cpp index e4b868cc6..87a2e7924 100644 --- a/Source/Engine/Graphics/Textures/GPUSamplerDescription.cpp +++ b/Source/Engine/Graphics/Textures/GPUSampler.cpp @@ -1,20 +1,23 @@ // Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. +#include "GPUSampler.h" #include "GPUSamplerDescription.h" #include "Engine/Core/Types/String.h" +#include "Engine/Graphics/GPUDevice.h" + +GPUSamplerDescription GPUSamplerDescription::New(GPUSamplerFilter filter, GPUSamplerAddressMode addressMode) +{ + GPUSamplerDescription desc; + desc.Clear(); + desc.Filter = filter; + desc.AddressU = desc.AddressV = desc.AddressW = addressMode; + return desc; +} void GPUSamplerDescription::Clear() { - Filter = GPUSamplerFilter::Point; - AddressU = GPUSamplerAddressMode::Wrap; - AddressV = GPUSamplerAddressMode::Wrap; - AddressW = GPUSamplerAddressMode::Wrap; - MipBias = 0; - MaxAnisotropy = 0; - MinMipLevel = 0; + Platform::MemoryClear(this, sizeof(GPUSamplerDescription)); MaxMipLevel = MAX_float; - BorderColor = GPUSamplerBorderColor::TransparentBlack; - SamplerComparisonFunction = GPUSamplerCompareFunction::Never; } bool GPUSamplerDescription::Equals(const GPUSamplerDescription& other) const @@ -28,12 +31,12 @@ bool GPUSamplerDescription::Equals(const GPUSamplerDescription& other) const && MinMipLevel == other.MinMipLevel && MaxMipLevel == other.MaxMipLevel && BorderColor == other.BorderColor - && SamplerComparisonFunction == other.SamplerComparisonFunction; + && ComparisonFunction == other.ComparisonFunction; } String GPUSamplerDescription::ToString() const { - return String::Format(TEXT("Filter: {}, Address: {}x{}x{}, MipBias: {}, MaxAnisotropy: {}, MinMipLevel: {}, MaxMipLevel: {}, BorderColor: {}, SamplerComparisonFunction: {}"), + return String::Format(TEXT("Filter: {}, Address: {}x{}x{}, MipBias: {}, MaxAnisotropy: {}, MinMipLevel: {}, MaxMipLevel: {}, BorderColor: {}, ComparisonFunction: {}"), (int32)Filter, (int32)AddressU, (int32)AddressV, @@ -43,7 +46,7 @@ String GPUSamplerDescription::ToString() const MinMipLevel, MaxMipLevel, (int32)BorderColor, - (int32)SamplerComparisonFunction); + (int32)ComparisonFunction); } uint32 GetHash(const GPUSamplerDescription& key) @@ -57,6 +60,57 @@ uint32 GetHash(const GPUSamplerDescription& key) hashCode = (hashCode * 397) ^ (uint32)key.MinMipLevel; hashCode = (hashCode * 397) ^ (uint32)key.MaxMipLevel; hashCode = (hashCode * 397) ^ (uint32)key.BorderColor; - hashCode = (hashCode * 397) ^ (uint32)key.SamplerComparisonFunction; + hashCode = (hashCode * 397) ^ (uint32)key.ComparisonFunction; return hashCode; } + +GPUSampler* GPUSampler::Spawn(const SpawnParams& params) +{ + return GPUDevice::Instance->CreateSampler(); +} + +GPUSampler* GPUSampler::New() +{ + return GPUDevice::Instance->CreateSampler(); +} + +GPUSampler::GPUSampler() +{ +} + +bool GPUSampler::Init(const GPUSamplerDescription& desc) +{ + ReleaseGPU(); + _desc = desc; + if (OnInit()) + { + ReleaseGPU(); + LOG(Warning, "Cannot initialize sampler. Description: {0}", desc.ToString()); + return true; + } + return false; +} + +String GPUSampler::ToString() const +{ +#if GPU_ENABLE_RESOURCE_NAMING + return String::Format(TEXT("Sampler {0}, {1}"), GetName(), _desc.ToString()); +#else + return TEXT("Sampler"); +#endif +} + +GPUResource::ResourceType GPUSampler::GetResourceType() const +{ + return ResourceType::Sampler; +} + +GPUResource::ObjectType GPUSampler::GetObjectType() const +{ + return ObjectType::Other; +} + +void GPUSampler::OnReleaseGPU() +{ + _desc.Clear(); +} diff --git a/Source/Engine/Graphics/Textures/GPUSampler.h b/Source/Engine/Graphics/Textures/GPUSampler.h new file mode 100644 index 000000000..70d2f40ea --- /dev/null +++ b/Source/Engine/Graphics/Textures/GPUSampler.h @@ -0,0 +1,58 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +#include "GPUSamplerDescription.h" +#include "../GPUResource.h" + +/// +/// GPU texture sampler object. +/// +/// +API_CLASS(Sealed) class FLAXENGINE_API GPUSampler : public GPUResource +{ +DECLARE_SCRIPTING_TYPE_NO_SPAWN(GPUSampler); + static GPUSampler* Spawn(const SpawnParams& params); + static GPUSampler* New(); + +protected: + + GPUSamplerDescription _desc; + + GPUSampler(); + +public: + + /// + /// Gets sampler description structure. + /// + API_PROPERTY() const GPUSamplerDescription& GetDescription() const + { + return _desc; + } + +public: + + /// + /// Creates new sampler. + /// + /// The sampler description. + /// True if cannot create sampler, otherwise false. + API_FUNCTION() bool Init(API_PARAM(Ref) const GPUSamplerDescription& desc); + +protected: + + virtual bool OnInit() = 0; + +public: + + // [GPUResource] + String ToString() const override; + ResourceType GetResourceType() const final override; + ObjectType GetObjectType() const final override; + +protected: + + // [GPUResource] + void OnReleaseGPU() override; +}; diff --git a/Source/Engine/Graphics/Textures/GPUSamplerDescription.cs b/Source/Engine/Graphics/Textures/GPUSamplerDescription.cs new file mode 100644 index 000000000..c20f51c0e --- /dev/null +++ b/Source/Engine/Graphics/Textures/GPUSamplerDescription.cs @@ -0,0 +1,76 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +using System; + +namespace FlaxEngine +{ + partial struct GPUSamplerDescription : IEquatable + { + /// + /// Clears description. + /// + public void Clear() + { + this = new GPUSamplerDescription(); + MaxMipLevel = float.MaxValue; + } + + /// + /// Creates a new with default settings. + /// + /// The filtering method. + /// The addressing mode. + /// A new instance of class. + public static GPUSamplerDescription New(GPUSamplerFilter filter = GPUSamplerFilter.Point, GPUSamplerAddressMode addressMode = GPUSamplerAddressMode.Wrap) + { + return new GPUSamplerDescription + { + Filter = filter, + AddressU = addressMode, + AddressV = addressMode, + AddressW = addressMode, + MaxMipLevel = float.MaxValue, + }; + } + + /// + public bool Equals(GPUSamplerDescription other) + { + return Filter == other.Filter && + AddressU == other.AddressU && + AddressV == other.AddressV && + AddressW == other.AddressW && + Mathf.NearEqual(MipBias, other.MipBias) && + Mathf.NearEqual(MinMipLevel, other.MinMipLevel) && + Mathf.NearEqual(MaxMipLevel, other.MaxMipLevel) && + MaxAnisotropy == other.MaxAnisotropy && + BorderColor == other.BorderColor && + ComparisonFunction == other.ComparisonFunction; + } + + /// + public override bool Equals(object obj) + { + return obj is GPUSamplerDescription other && Equals(other); + } + + /// + public override int GetHashCode() + { + unchecked + { + var hashCode = (int)Filter; + hashCode = (hashCode * 397) ^ (int)AddressU; + hashCode = (hashCode * 397) ^ (int)AddressV; + hashCode = (hashCode * 397) ^ (int)AddressW; + hashCode = (hashCode * 397) ^ (int)MipBias; + hashCode = (hashCode * 397) ^ (int)MinMipLevel; + hashCode = (hashCode * 397) ^ (int)MaxMipLevel; + hashCode = (hashCode * 397) ^ MaxAnisotropy; + hashCode = (hashCode * 397) ^ (int)BorderColor; + hashCode = (hashCode * 397) ^ (int)ComparisonFunction; + return hashCode; + } + } + } +} diff --git a/Source/Engine/Graphics/Textures/GPUSamplerDescription.h b/Source/Engine/Graphics/Textures/GPUSamplerDescription.h index 1b91b419c..2674e88a9 100644 --- a/Source/Engine/Graphics/Textures/GPUSamplerDescription.h +++ b/Source/Engine/Graphics/Textures/GPUSamplerDescription.h @@ -4,49 +4,57 @@ #include "Engine/Graphics/Enums.h" -class String; - /// /// GPU sampler filter modes. /// -enum class GPUSamplerFilter +API_ENUM() enum class GPUSamplerFilter { + /// Filter using the nearest found pixel. Texture appears pixelated. Point = 0, + /// Filter using the linear average of the nearby pixels. Texture appears blurry. Bilinear = 1, + /// Filter using the linear average of the nearby pixels and nearby mipmaps. Texture appears blurry. Trilinear = 2, + /// Filter using the anisotropic filtering that improves quality when viewing textures at a steep angles. Texture appears sharp at extreme viewing angles. Anisotropic = 3, - MAX + API_ENUM(Attributes="HideInEditor") MAX }; /// /// GPU sampler address modes. /// -enum class GPUSamplerAddressMode +API_ENUM() enum class GPUSamplerAddressMode { + /// Texture coordinates wrap back to the valid range. Wrap = 0, + /// Texture coordinates are clamped within the valid range. Clamp = 1, + /// Texture coordinates flip every time the size of the valid range is passed. Mirror = 2, + /// Texture coordinates outside of the valid range will return a separately set border color. Border = 3, - MAX + API_ENUM(Attributes="HideInEditor") MAX }; /// /// GPU sampler comparision function types. /// -enum class GPUSamplerCompareFunction +API_ENUM() enum class GPUSamplerCompareFunction { + /// Never pass the comparison. Never = 0, + /// If the source data is less than the destination data, the comparison passes. Less = 1, - MAX + API_ENUM(Attributes="HideInEditor") MAX }; /// /// GPU sampler border color types. /// -enum class GPUSamplerBorderColor +API_ENUM() enum class GPUSamplerBorderColor { /// /// Indicates black, with the alpha component as fully transparent. @@ -63,105 +71,93 @@ enum class GPUSamplerBorderColor /// OpaqueWhite = 2, - Maximum + API_ENUM(Attributes="HideInEditor") MAX }; /// /// A common description for all samplers. /// -struct FLAXENGINE_API GPUSamplerDescription +API_STRUCT() struct FLAXENGINE_API GPUSamplerDescription { -public: +DECLARE_SCRIPTING_TYPE_MINIMAL(GPUSamplerDescription); /// /// The filtering method to use when sampling a texture. /// - GPUSamplerFilter Filter; + API_FIELD() GPUSamplerFilter Filter; /// /// The addressing mode for outside [0..1] range for U coordinate. /// - GPUSamplerAddressMode AddressU; + API_FIELD() GPUSamplerAddressMode AddressU; /// /// The addressing mode for outside [0..1] range for V coordinate. /// - GPUSamplerAddressMode AddressV; + API_FIELD() GPUSamplerAddressMode AddressV; /// /// The addressing mode for outside [0..1] range for W coordinate. /// - GPUSamplerAddressMode AddressW; + API_FIELD() GPUSamplerAddressMode AddressW; /// /// The mip bias to be added to mipmap LOD calculation. /// - float MipBias; + API_FIELD() float MipBias; /// /// The minimum mip map level that will be used, where 0 is the highest resolution mip level. /// - float MinMipLevel; + API_FIELD() float MinMipLevel; /// /// The maximum mip map level that will be used, where 0 is the highest resolution mip level. To have no upper limit on LOD set this to a large value such as MAX_float. /// - float MaxMipLevel; + API_FIELD() float MaxMipLevel; /// /// The maximum anisotropy value. /// - int32 MaxAnisotropy; + API_FIELD() int32 MaxAnisotropy; /// /// The border color to use if Border is specified for AddressU, AddressV, or AddressW. /// - GPUSamplerBorderColor BorderColor; + API_FIELD() GPUSamplerBorderColor BorderColor; /// /// A function that compares sampled data against existing sampled data. /// - GPUSamplerCompareFunction SamplerComparisonFunction; + API_FIELD() GPUSamplerCompareFunction ComparisonFunction; public: /// - /// Clears description to the default values. + /// Creates a new with default settings. /// + /// The filtering method. + /// The addressing mode. + /// A new instance of class. + static GPUSamplerDescription New(GPUSamplerFilter filter = GPUSamplerFilter::Point, GPUSamplerAddressMode addressMode = GPUSamplerAddressMode::Wrap); + +public: + void Clear(); + bool Equals(const GPUSamplerDescription& other) const; + String ToString() const; public: - /// - /// Compares with other instance of SamplerDescription - /// - /// The other object to compare. - /// True if objects are the same, otherwise false. - bool Equals(const GPUSamplerDescription& other) const; - - /// - /// Implements the operator ==. - /// - /// The other description. - /// The result of the operator. FORCE_INLINE bool operator==(const GPUSamplerDescription& other) const { return Equals(other); } - /// - /// Implements the operator !=. - /// - /// The other description. - /// The result of the operator. FORCE_INLINE bool operator!=(const GPUSamplerDescription& other) const { return !Equals(other); } - -public: - - String ToString() const; }; uint32 GetHash(const GPUSamplerDescription& key); diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp index b0cc5cb63..0998ac4d6 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.cpp @@ -8,6 +8,7 @@ #include "GPUPipelineStateDX11.h" #include "GPUTextureDX11.h" #include "GPUBufferDX11.h" +#include "GPUSamplerDX11.h" #include "Engine/GraphicsDevice/DirectX/RenderToolsDX.h" #include "Engine/Core/Math/Viewport.h" #include "Engine/Core/Math/Rectangle.h" @@ -384,6 +385,15 @@ void GPUContextDX11::BindIB(GPUBuffer* indexBuffer) } } +void GPUContextDX11::BindSampler(int32 slot, GPUSampler* sampler) +{ + const auto samplerDX11 = sampler ? static_cast(sampler)->SamplerState : nullptr; + _context->VSSetSamplers(slot, 1, &samplerDX11); + _context->DSSetSamplers(slot, 1, &samplerDX11); + _context->PSSetSamplers(slot, 1, &samplerDX11); + _context->CSSetSamplers(slot, 1, &samplerDX11); +} + void GPUContextDX11::UpdateCB(GPUConstantBuffer* cb, const void* data) { ASSERT(data && cb); diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.h b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.h index dffeae00c..0ec811565 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUContextDX11.h @@ -122,6 +122,7 @@ public: void BindUA(int32 slot, GPUResourceView* view) override; void BindVB(const Span& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr) override; void BindIB(GPUBuffer* indexBuffer) override; + void BindSampler(int32 slot, GPUSampler* sampler) override; void UpdateCB(GPUConstantBuffer* cb, const void* data) override; void Dispatch(GPUShaderProgramCS* shader, uint32 threadGroupCountX, uint32 threadGroupCountY, uint32 threadGroupCountZ) override; void DispatchIndirect(GPUShaderProgramCS* shader, GPUBuffer* bufferForArgs, uint32 offsetForArgs) override; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp index b0db7da93..935d8a7c0 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp @@ -9,6 +9,7 @@ #include "GPUTextureDX11.h" #include "GPUTimerQueryDX11.h" #include "GPUBufferDX11.h" +#include "GPUSamplerDX11.h" #include "GPUSwapChainDX11.h" #include "Engine/Core/Log.h" #include "Engine/Core/Utilities.h" @@ -324,6 +325,7 @@ bool GPUDeviceDX11::Init() limits.MaximumTexture2DArraySize = D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; limits.MaximumTexture3DSize = D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; limits.MaximumTextureCubeSize = D3D11_REQ_TEXTURECUBE_DIMENSION; + limits.MaximumSamplerAnisotropy = D3D11_DEFAULT_MAX_ANISOTROPY; } else { @@ -346,6 +348,7 @@ bool GPUDeviceDX11::Init() limits.MaximumTexture2DArraySize = D3D10_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; limits.MaximumTexture3DSize = D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; limits.MaximumTextureCubeSize = D3D10_REQ_TEXTURECUBE_DIMENSION; + limits.MaximumSamplerAnisotropy = D3D10_DEFAULT_MAX_ANISOTROPY; } for (int32 i = 0; i < static_cast(PixelFormat::MAX); i++) @@ -685,6 +688,11 @@ GPUBuffer* GPUDeviceDX11::CreateBuffer(const StringView& name) return New(this, name); } +GPUSampler* GPUDeviceDX11::CreateSampler() +{ + return New(this); +} + GPUSwapChain* GPUDeviceDX11::CreateSwapChain(Window* window) { return New(this, window); diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.h b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.h index d75c0b88a..08f770514 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.h @@ -99,6 +99,7 @@ public: GPUPipelineState* CreatePipelineState() override; GPUTimerQuery* CreateTimerQuery() override; GPUBuffer* CreateBuffer(const StringView& name) override; + GPUSampler* CreateSampler() override; GPUSwapChain* CreateSwapChain(Window* window) override; }; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUSamplerDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUSamplerDX11.cpp new file mode 100644 index 000000000..4927523a4 --- /dev/null +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUSamplerDX11.cpp @@ -0,0 +1,128 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#if GRAPHICS_API_DIRECTX11 + +#include "GPUSamplerDX11.h" + +D3D11_TEXTURE_ADDRESS_MODE ToDX11(GPUSamplerAddressMode value) +{ + switch (value) + { + case GPUSamplerAddressMode::Wrap: + return D3D11_TEXTURE_ADDRESS_WRAP; + case GPUSamplerAddressMode::Clamp: + return D3D11_TEXTURE_ADDRESS_CLAMP; + case GPUSamplerAddressMode::Mirror: + return D3D11_TEXTURE_ADDRESS_MIRROR; + case GPUSamplerAddressMode::Border: + return D3D11_TEXTURE_ADDRESS_BORDER; + default: + return (D3D11_TEXTURE_ADDRESS_MODE)-1; + } +} + +bool GPUSamplerDX11::OnInit() +{ + D3D11_SAMPLER_DESC samplerDesc; + if (_desc.ComparisonFunction == GPUSamplerCompareFunction::Never) + { + switch (_desc.Filter) + { + case GPUSamplerFilter::Point: + samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; + break; + case GPUSamplerFilter::Bilinear: + samplerDesc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; + break; + case GPUSamplerFilter::Trilinear: + samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + break; + case GPUSamplerFilter::Anisotropic: + samplerDesc.Filter = D3D11_FILTER_ANISOTROPIC; + break; + default: + return true; + } + } + else + { + switch (_desc.Filter) + { + case GPUSamplerFilter::Point: + samplerDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT; + break; + case GPUSamplerFilter::Bilinear: + samplerDesc.Filter = D3D11_FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT; + break; + case GPUSamplerFilter::Trilinear: + samplerDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR; + break; + case GPUSamplerFilter::Anisotropic: + samplerDesc.Filter = D3D11_FILTER_COMPARISON_ANISOTROPIC; + break; + default: + return true; + } + } + samplerDesc.AddressU = ToDX11(_desc.AddressU); + samplerDesc.AddressV = ToDX11(_desc.AddressV); + samplerDesc.AddressW = ToDX11(_desc.AddressW); + samplerDesc.MipLODBias = _desc.MipBias; + samplerDesc.MaxAnisotropy = _desc.MaxAnisotropy; + switch (_desc.ComparisonFunction) + { + case GPUSamplerCompareFunction::Never: + samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + break; + case GPUSamplerCompareFunction::Less: + samplerDesc.ComparisonFunc = D3D11_COMPARISON_LESS; + break; + default: + return true; + } + switch (_desc.BorderColor) + { + case GPUSamplerBorderColor::TransparentBlack: + samplerDesc.BorderColor[0] = 0; + samplerDesc.BorderColor[1] = 0; + samplerDesc.BorderColor[2] = 0; + samplerDesc.BorderColor[3] = 0; + break; + case GPUSamplerBorderColor::OpaqueBlack: + samplerDesc.BorderColor[0] = 0; + samplerDesc.BorderColor[1] = 0; + samplerDesc.BorderColor[2] = 0; + samplerDesc.BorderColor[3] = 1.0f; + break; + case GPUSamplerBorderColor::OpaqueWhite: + samplerDesc.BorderColor[0] = 1.0f; + samplerDesc.BorderColor[1] = 1.0f; + samplerDesc.BorderColor[2] = 1.0f; + samplerDesc.BorderColor[3] = 1.0f; + break; + default: + return true; + } + samplerDesc.MinLOD = _desc.MinMipLevel; + samplerDesc.MaxLOD = _desc.MaxMipLevel; + HRESULT result = _device->GetDevice()->CreateSamplerState(&samplerDesc, &SamplerState); + LOG_DIRECTX_RESULT_WITH_RETURN(result); + ASSERT(SamplerState != nullptr); + _memoryUsage = sizeof(D3D11_SAMPLER_DESC); + + return false; +} + +void GPUSamplerDX11::OnReleaseGPU() +{ + if (SamplerState) + { + SamplerState->Release(); + SamplerState = nullptr; + } + + // Base + GPUSampler::OnReleaseGPU(); +} + +#endif diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUSamplerDX11.h b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUSamplerDX11.h new file mode 100644 index 000000000..b21ab9a61 --- /dev/null +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUSamplerDX11.h @@ -0,0 +1,31 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Engine/Graphics/Textures/GPUSampler.h" +#include "GPUDeviceDX11.h" + +#if GRAPHICS_API_DIRECTX11 + +/// +/// Sampler object for DirectX 11 backend. +/// +class GPUSamplerDX11 : public GPUResourceBase +{ +public: + + GPUSamplerDX11(GPUDeviceDX11* device) + : GPUResourceBase(device, StringView::Empty) + { + } + + ID3D11SamplerState* SamplerState = nullptr; + +protected: + + // [GPUSampler] + bool OnInit() override; + void OnReleaseGPU() override; +}; + +#endif diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp index ffa0a5550..60f90dca0 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.cpp @@ -11,6 +11,7 @@ #include "UploadBufferDX12.h" #include "GPUTextureDX12.h" #include "GPUBufferDX12.h" +#include "GPUSamplerDX12.h" #include "CommandQueueDX12.h" #include "DescriptorHeapDX12.h" #include "Engine/Graphics/RenderTask.h" @@ -74,6 +75,7 @@ GPUContextDX12::GPUContextDX12(GPUDeviceDX12* device, D3D12_COMMAND_LIST_TYPE ty , _rtDirtyFlag(0) , _psDirtyFlag(0) , _cbDirtyFlag(0) + , _samplersDirtyFlag(0) , _rtDepth(nullptr) , _ibHandle(nullptr) { @@ -213,6 +215,7 @@ void GPUContextDX12::Reset() _currentState = nullptr; _rtDirtyFlag = false; _cbDirtyFlag = false; + _samplersDirtyFlag = false; _rtCount = 0; _rtDepth = nullptr; _srMaskDirtyGraphics = 0; @@ -226,8 +229,9 @@ void GPUContextDX12::Reset() Platform::MemoryClear(_srHandles, sizeof(_srHandles)); Platform::MemoryClear(_uaHandles, sizeof(_uaHandles)); Platform::MemoryClear(_vbHandles, sizeof(_vbHandles)); - Platform::MemoryClear(&_ibHandle, sizeof(_ibHandle)); + _ibHandle = nullptr; Platform::MemoryClear(&_cbHandles, sizeof(_cbHandles)); + Platform::MemoryClear(&_samplers, sizeof(_samplers)); _swapChainsUsed = 0; // Bind Root Signature @@ -235,7 +239,7 @@ void GPUContextDX12::Reset() _commandList->SetComputeRootSignature(_device->GetRootSignature()); // Bind heaps - ID3D12DescriptorHeap* ppHeaps[] = { _device->RingHeap_CBV_SRV_UAV.GetHeap() }; + ID3D12DescriptorHeap* ppHeaps[] = { _device->RingHeap_CBV_SRV_UAV.GetHeap(), _device->RingHeap_Sampler.GetHeap() }; _commandList->SetDescriptorHeaps(ARRAY_COUNT(ppHeaps), ppHeaps); } @@ -449,28 +453,58 @@ void GPUContextDX12::flushUAVs() void GPUContextDX12::flushCBs() { - // Check if need to flush constant buffers - if (_cbDirtyFlag) + if (!_cbDirtyFlag) + return; + _cbDirtyFlag = false; + for (uint32 slotIndex = 0; slotIndex < ARRAY_COUNT(_cbHandles); slotIndex++) { - // Clear flag - _cbDirtyFlag = false; - - // Flush with the driver - for (uint32 slotIndex = 0; slotIndex < ARRAY_COUNT(_cbHandles); slotIndex++) + auto cb = _cbHandles[slotIndex]; + if (cb) { - auto cb = _cbHandles[slotIndex]; - if (cb) - { - ASSERT(cb->GPUAddress != 0); - if (_isCompute) - _commandList->SetComputeRootConstantBufferView(slotIndex, cb->GPUAddress); - else - _commandList->SetGraphicsRootConstantBufferView(slotIndex, cb->GPUAddress); - } + ASSERT(cb->GPUAddress != 0); + if (_isCompute) + _commandList->SetComputeRootConstantBufferView(slotIndex, cb->GPUAddress); + else + _commandList->SetGraphicsRootConstantBufferView(slotIndex, cb->GPUAddress); } } } +void GPUContextDX12::flushSamplers() +{ + if (!_samplersDirtyFlag) + return; + _samplersDirtyFlag = false; + int32 lastSlot = -1; + for (int32 slotIndex = ARRAY_COUNT(_samplers) - 1; slotIndex >= 0; slotIndex--) + { + auto sampler = _samplers[slotIndex]; + if (sampler) + { + lastSlot = slotIndex; + break; + } + } + if (lastSlot < 0) + return; + const uint32 samplersCount = lastSlot + 1; + D3D12_CPU_DESCRIPTOR_HANDLE srcDescriptorRangeStarts[ARRAY_COUNT(_samplers)]; + for (uint32 i = 0; i < samplersCount; i++) + { + const auto handle = _samplers[i]; + if (handle != nullptr) + { + srcDescriptorRangeStarts[i] = handle->HandleCPU; + } + } + auto allocation = _device->RingHeap_Sampler.AllocateTable(samplersCount); + _device->GetDevice()->CopyDescriptors(1, &allocation.CPU, &samplersCount, samplersCount, srcDescriptorRangeStarts, nullptr, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); + if (_isCompute) + _commandList->SetComputeRootDescriptorTable(4, allocation.GPU); + else + _commandList->SetGraphicsRootDescriptorTable(4, allocation.GPU); +} + void GPUContextDX12::flushRBs() { #if DX12_ENABLE_RESOURCE_BARRIERS_BATCHING @@ -563,6 +597,7 @@ void GPUContextDX12::OnDrawCall() flushRBs(); flushPS(); flushCBs(); + flushSamplers(); #if BUILD_DEBUG // Additional verification of the state @@ -835,8 +870,8 @@ void GPUContextDX12::BindUA(int32 slot, GPUResourceView* view) { ASSERT(slot >= 0 && slot < GPU_MAX_UA_BINDED); _uaHandles[slot] = view ? (IShaderResourceDX12*)view->GetNativePtr() : nullptr; - if (view) - *view->LastRenderTime = _lastRenderTime; + if (view) + *view->LastRenderTime = _lastRenderTime; } void GPUContextDX12::BindVB(const Span& vertexBuffers, const uint32* vertexBuffersOffsets) @@ -890,6 +925,17 @@ void GPUContextDX12::BindIB(GPUBuffer* indexBuffer) } } +void GPUContextDX12::BindSampler(int32 slot, GPUSampler* sampler) +{ + ASSERT(slot >= GPU_STATIC_SAMPLERS_COUNT && slot < GPU_MAX_SAMPLER_BINDED); + const auto handle = sampler ? static_cast(sampler) : nullptr; + if (_samplers[slot - GPU_STATIC_SAMPLERS_COUNT] != handle) + { + _samplersDirtyFlag = true; + _samplers[slot - GPU_STATIC_SAMPLERS_COUNT] = handle; + } +} + void GPUContextDX12::UpdateCB(GPUConstantBuffer* cb, const void* data) { ASSERT(data && cb); @@ -927,6 +973,7 @@ void GPUContextDX12::Dispatch(GPUShaderProgramCS* shader, uint32 threadGroupCoun flushUAVs(); flushRBs(); flushCBs(); + flushSamplers(); auto shaderDX12 = (GPUShaderProgramCSDX12*)shader; auto computeState = shaderDX12->GetOrCreateState(); @@ -959,6 +1006,7 @@ void GPUContextDX12::DispatchIndirect(GPUShaderProgramCS* shader, GPUBuffer* buf flushUAVs(); flushRBs(); flushCBs(); + flushSamplers(); auto shaderDX12 = (GPUShaderProgramCSDX12*)shader; auto computeState = shaderDX12->GetOrCreateState(); diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.h b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.h index b102cfa6b..1d5fa2f42 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUContextDX12.h @@ -12,6 +12,7 @@ class GPUDeviceDX12; class GPUPipelineStateDX12; class GPUBufferDX12; +class GPUSamplerDX12; class GPUConstantBufferDX12; class GPUTextureViewDX12; @@ -51,6 +52,7 @@ private: int32 _rtDirtyFlag : 1; int32 _psDirtyFlag : 1; int32 _cbDirtyFlag : 1; + int32 _samplersDirtyFlag : 1; GPUTextureViewDX12* _rtDepth; GPUTextureViewDX12* _rtHandles[GPU_MAX_RT_BINDED]; @@ -62,6 +64,7 @@ private: D3D12_VERTEX_BUFFER_VIEW _vbViews[GPU_MAX_VB_BINDED]; D3D12_RESOURCE_BARRIER _rbBuffer[DX12_RB_BUFFER_SIZE]; GPUConstantBufferDX12* _cbHandles[GPU_MAX_CB_BINDED]; + GPUSamplerDX12* _samplers[GPU_MAX_SAMPLER_BINDED - GPU_STATIC_SAMPLERS_COUNT]; public: @@ -136,6 +139,7 @@ private: void flushRTVs(); void flushUAVs(); void flushCBs(); + void flushSamplers(); void flushRBs(); void flushPS(); void OnDrawCall(); @@ -167,6 +171,7 @@ public: void BindUA(int32 slot, GPUResourceView* view) override; void BindVB(const Span& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr) override; void BindIB(GPUBuffer* indexBuffer) override; + void BindSampler(int32 slot, GPUSampler* sampler) override; void UpdateCB(GPUConstantBuffer* cb, const void* data) override; void Dispatch(GPUShaderProgramCS* shader, uint32 threadGroupCountX, uint32 threadGroupCountY, uint32 threadGroupCountZ) override; void DispatchIndirect(GPUShaderProgramCS* shader, GPUBuffer* bufferForArgs, uint32 offsetForArgs) override; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp index fa5e698d5..67f6dae5c 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp @@ -9,6 +9,7 @@ #include "GPUTextureDX12.h" #include "GPUTimerQueryDX12.h" #include "GPUBufferDX12.h" +#include "GPUSamplerDX12.h" #include "GPUSwapChainDX12.h" #include "Engine/Engine/Engine.h" #include "Engine/Engine/CommandLine.h" @@ -191,7 +192,9 @@ GPUDeviceDX12::GPUDeviceDX12(IDXGIFactory4* dxgiFactory, GPUAdapterDX* adapter) , Heap_CBV_SRV_UAV(this, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 4 * 1024, false) , Heap_RTV(this, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 1 * 1024, false) , Heap_DSV(this, D3D12_DESCRIPTOR_HEAP_TYPE_DSV, 64, false) + , Heap_Sampler(this, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, 128, false) , RingHeap_CBV_SRV_UAV(this, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 512 * 1024, true) + , RingHeap_Sampler(this, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, 1 * 1024, true) { } @@ -350,6 +353,7 @@ bool GPUDeviceDX12::Init() limits.MaximumTexture2DArraySize = D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; limits.MaximumTexture3DSize = D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; limits.MaximumTextureCubeSize = D3D12_REQ_TEXTURECUBE_DIMENSION; + limits.MaximumSamplerAnisotropy = D3D12_DEFAULT_MAX_ANISOTROPY; for (int32 i = 0; i < static_cast(PixelFormat::MAX); i++) { @@ -379,6 +383,8 @@ bool GPUDeviceDX12::Init() _mainContext = New(this, D3D12_COMMAND_LIST_TYPE_DIRECT); if (RingHeap_CBV_SRV_UAV.Init()) return true; + if (RingHeap_Sampler.Init()) + return true; // Create empty views D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc; @@ -458,7 +464,7 @@ bool GPUDeviceDX12::Init() // TODO: maybe create set of different root signatures? for UAVs, for compute, for simple drawing, for post fx? { // Descriptor tables - D3D12_DESCRIPTOR_RANGE r[2]; + D3D12_DESCRIPTOR_RANGE r[3]; // TODO: separate ranges for pixel/vertex visibility and one shared for all? { D3D12_DESCRIPTOR_RANGE& range = r[0]; @@ -476,9 +482,17 @@ bool GPUDeviceDX12::Init() range.RegisterSpace = 0; range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; } + { + D3D12_DESCRIPTOR_RANGE& range = r[2]; + range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; + range.NumDescriptors = GPU_MAX_SAMPLER_BINDED - GPU_STATIC_SAMPLERS_COUNT; + range.BaseShaderRegister = GPU_STATIC_SAMPLERS_COUNT; + range.RegisterSpace = 0; + range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; + } // Root parameters - D3D12_ROOT_PARAMETER rootParameters[4]; + D3D12_ROOT_PARAMETER rootParameters[5]; { D3D12_ROOT_PARAMETER& rootParam = rootParameters[0]; rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; @@ -507,11 +521,18 @@ bool GPUDeviceDX12::Init() rootParam.DescriptorTable.NumDescriptorRanges = 1; rootParam.DescriptorTable.pDescriptorRanges = &r[1]; } - - // TODO: describe visibilities for the static samples, maybe use all pixel? or again pixel + all combo? + { + D3D12_ROOT_PARAMETER& rootParam = rootParameters[4]; + rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + rootParam.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + rootParam.DescriptorTable.NumDescriptorRanges = 1; + rootParam.DescriptorTable.pDescriptorRanges = &r[2]; + } // Static samplers D3D12_STATIC_SAMPLER_DESC staticSamplers[6]; + static_assert(GPU_STATIC_SAMPLERS_COUNT == ARRAY_COUNT(staticSamplers), "Update static samplers setup."); + // TODO: describe visibilities for the static samples, maybe use all pixel? or again pixel + all combo? // Linear Clamp staticSamplers[0].Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; staticSamplers[0].AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; @@ -718,7 +739,9 @@ void GPUDeviceDX12::Dispose() Heap_CBV_SRV_UAV.ReleaseGPU(); Heap_RTV.ReleaseGPU(); Heap_DSV.ReleaseGPU(); + Heap_Sampler.ReleaseGPU(); RingHeap_CBV_SRV_UAV.ReleaseGPU(); + RingHeap_Sampler.ReleaseGPU(); SAFE_DELETE(UploadBuffer); SAFE_DELETE(DrawIndirectCommandSignature); SAFE_DELETE(_mainContext); @@ -766,6 +789,11 @@ GPUBuffer* GPUDeviceDX12::CreateBuffer(const StringView& name) return New(this, name); } +GPUSampler* GPUDeviceDX12::CreateSampler() +{ + return New(this); +} + GPUSwapChain* GPUDeviceDX12::CreateSwapChain(Window* window) { return New(this, window); diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.h b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.h index f14305ea7..bf0641e21 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.h @@ -141,7 +141,9 @@ public: DescriptorHeapPoolDX12 Heap_CBV_SRV_UAV; DescriptorHeapPoolDX12 Heap_RTV; DescriptorHeapPoolDX12 Heap_DSV; + DescriptorHeapPoolDX12 Heap_Sampler; DescriptorHeapRingBufferDX12 RingHeap_CBV_SRV_UAV; + DescriptorHeapRingBufferDX12 RingHeap_Sampler; public: @@ -188,6 +190,7 @@ public: GPUPipelineState* CreatePipelineState() override; GPUTimerQuery* CreateTimerQuery() override; GPUBuffer* CreateBuffer(const StringView& name) override; + GPUSampler* CreateSampler() override; GPUSwapChain* CreateSwapChain(Window* window) override; }; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUSamplerDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUSamplerDX12.cpp new file mode 100644 index 000000000..eb4e701d8 --- /dev/null +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUSamplerDX12.cpp @@ -0,0 +1,124 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#if GRAPHICS_API_DIRECTX12 + +#include "GPUSamplerDX12.h" + +D3D12_TEXTURE_ADDRESS_MODE ToDX12(GPUSamplerAddressMode value) +{ + switch (value) + { + case GPUSamplerAddressMode::Wrap: + return D3D12_TEXTURE_ADDRESS_MODE_WRAP; + case GPUSamplerAddressMode::Clamp: + return D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + case GPUSamplerAddressMode::Mirror: + return D3D12_TEXTURE_ADDRESS_MODE_MIRROR; + case GPUSamplerAddressMode::Border: + return D3D12_TEXTURE_ADDRESS_MODE_BORDER; + default: + return (D3D12_TEXTURE_ADDRESS_MODE)-1; + } +} + +bool GPUSamplerDX12::OnInit() +{ + D3D12_SAMPLER_DESC samplerDesc; + if (_desc.ComparisonFunction == GPUSamplerCompareFunction::Never) + { + switch (_desc.Filter) + { + case GPUSamplerFilter::Point: + samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; + break; + case GPUSamplerFilter::Bilinear: + samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT; + break; + case GPUSamplerFilter::Trilinear: + samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; + break; + case GPUSamplerFilter::Anisotropic: + samplerDesc.Filter = D3D12_FILTER_ANISOTROPIC; + break; + default: + return true; + } + } + else + { + switch (_desc.Filter) + { + case GPUSamplerFilter::Point: + samplerDesc.Filter = D3D12_FILTER_COMPARISON_MIN_MAG_MIP_POINT; + break; + case GPUSamplerFilter::Bilinear: + samplerDesc.Filter = D3D12_FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT; + break; + case GPUSamplerFilter::Trilinear: + samplerDesc.Filter = D3D12_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR; + break; + case GPUSamplerFilter::Anisotropic: + samplerDesc.Filter = D3D12_FILTER_COMPARISON_ANISOTROPIC; + break; + default: + return true; + } + } + samplerDesc.AddressU = ToDX12(_desc.AddressU); + samplerDesc.AddressV = ToDX12(_desc.AddressV); + samplerDesc.AddressW = ToDX12(_desc.AddressW); + samplerDesc.MipLODBias = _desc.MipBias; + samplerDesc.MaxAnisotropy = _desc.MaxAnisotropy; + switch (_desc.ComparisonFunction) + { + case GPUSamplerCompareFunction::Never: + samplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; + break; + case GPUSamplerCompareFunction::Less: + samplerDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_LESS; + break; + default: + return true; + } + switch (_desc.BorderColor) + { + case GPUSamplerBorderColor::TransparentBlack: + samplerDesc.BorderColor[0] = 0; + samplerDesc.BorderColor[1] = 0; + samplerDesc.BorderColor[2] = 0; + samplerDesc.BorderColor[3] = 0; + break; + case GPUSamplerBorderColor::OpaqueBlack: + samplerDesc.BorderColor[0] = 0; + samplerDesc.BorderColor[1] = 0; + samplerDesc.BorderColor[2] = 0; + samplerDesc.BorderColor[3] = 1.0f; + break; + case GPUSamplerBorderColor::OpaqueWhite: + samplerDesc.BorderColor[0] = 1.0f; + samplerDesc.BorderColor[1] = 1.0f; + samplerDesc.BorderColor[2] = 1.0f; + samplerDesc.BorderColor[3] = 1.0f; + break; + default: + return true; + } + samplerDesc.MinLOD = _desc.MinMipLevel; + samplerDesc.MaxLOD = _desc.MaxMipLevel; + _device->Heap_Sampler.AllocateSlot(Slot.Heap, Slot.Index); + HandleCPU = Slot.CPU(); + _device->GetDevice()->CreateSampler(&samplerDesc, HandleCPU); + _memoryUsage = sizeof(D3D12_SAMPLER_DESC); + + return false; +} + +void GPUSamplerDX12::OnReleaseGPU() +{ + Slot.Release(); + + // Base + GPUSampler::OnReleaseGPU(); +} + +#endif diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUSamplerDX12.h b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUSamplerDX12.h new file mode 100644 index 000000000..5b565669a --- /dev/null +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUSamplerDX12.h @@ -0,0 +1,32 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Engine/Graphics/Textures/GPUSampler.h" +#include "GPUDeviceDX12.h" + +#if GRAPHICS_API_DIRECTX12 + +/// +/// Sampler object for DirectX 12 backend. +/// +class GPUSamplerDX12 : public GPUResourceDX12 +{ +public: + + GPUSamplerDX12(GPUDeviceDX12* device) + : GPUResourceDX12(device, StringView::Empty) + { + } + + DescriptorHeapWithSlotsDX12::Slot Slot; + D3D12_CPU_DESCRIPTOR_HANDLE HandleCPU; + +protected: + + // [GPUSampler] + bool OnInit() override; + void OnReleaseGPU() override; +}; + +#endif diff --git a/Source/Engine/GraphicsDevice/Null/GPUContextNull.h b/Source/Engine/GraphicsDevice/Null/GPUContextNull.h index f45417976..96f2e9485 100644 --- a/Source/Engine/GraphicsDevice/Null/GPUContextNull.h +++ b/Source/Engine/GraphicsDevice/Null/GPUContextNull.h @@ -108,6 +108,10 @@ public: { } + void BindSampler(int32 slot, GPUSampler* sampler) override + { + } + void UpdateCB(GPUConstantBuffer* cb, const void* data) override { } diff --git a/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.cpp b/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.cpp index fa266a34a..4a5cd23fc 100644 --- a/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.cpp +++ b/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.cpp @@ -10,6 +10,7 @@ #include "GPUPipelineStateNull.h" #include "GPUTimerQueryNull.h" #include "GPUBufferNull.h" +#include "GPUSamplerNull.h" #include "GPUSwapChainNull.h" GPUDeviceNull::GPUDeviceNull() @@ -66,6 +67,7 @@ bool GPUDeviceNull::Init() limits.MaximumTexture2DArraySize = 512; limits.MaximumTexture3DSize = 2048; limits.MaximumTextureCubeSize = 16384; + limits.MaximumSamplerAnisotropy = 0; for (int32 i = 0; i < static_cast(PixelFormat::MAX); i++) { @@ -177,6 +179,11 @@ GPUBuffer* GPUDeviceNull::CreateBuffer(const StringView& name) return New(); } +GPUSampler* GPUDeviceNull::CreateSampler() +{ + return New(); +} + GPUSwapChain* GPUDeviceNull::CreateSwapChain(Window* window) { return New(window); diff --git a/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.h b/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.h index 2562a2744..7c3894fa4 100644 --- a/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.h +++ b/Source/Engine/GraphicsDevice/Null/GPUDeviceNull.h @@ -46,6 +46,7 @@ public: GPUPipelineState* CreatePipelineState() override; GPUTimerQuery* CreateTimerQuery() override; GPUBuffer* CreateBuffer(const StringView& name) override; + GPUSampler* CreateSampler() override; GPUSwapChain* CreateSwapChain(Window* window) override; }; diff --git a/Source/Engine/GraphicsDevice/Null/GPUSamplerNull.h b/Source/Engine/GraphicsDevice/Null/GPUSamplerNull.h new file mode 100644 index 000000000..c54852a90 --- /dev/null +++ b/Source/Engine/GraphicsDevice/Null/GPUSamplerNull.h @@ -0,0 +1,23 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +#if GRAPHICS_API_NULL + +#include "Engine/Graphics/Textures/GPUSampler.h" + +/// +/// Sampler object for Null backend. +/// +class GPUSamplerNull : public GPUSampler +{ +protected: + + // [GPUSampler] + bool OnInit() override + { + return false; + } +}; + +#endif diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp index 6e73ec157..8ee07b70e 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.cpp @@ -8,6 +8,7 @@ #include "Engine/Core/Math/Color.h" #include "GPUBufferVulkan.h" #include "GPUShaderVulkan.h" +#include "GPUSamplerVulkan.h" #include "GPUPipelineStateVulkan.h" #include "Engine/Profiler/RenderStats.h" #include "GPUShaderProgramVulkan.h" @@ -447,7 +448,8 @@ void GPUContextVulkan::UpdateDescriptorSets(const SpirvShaderDescriptorInfo& des case VK_DESCRIPTOR_TYPE_SAMPLER: { // Sampler - const VkSampler sampler = _device->HelperResources.GetStaticSampler((HelperResourcesVulkan::StaticSamplers)descriptor.Slot); + const VkSampler sampler = _samplerHandles[descriptor.Slot]; + ASSERT(sampler); needsWrite |= dsWriter.WriteSampler(descriptorIndex, sampler); break; } @@ -715,8 +717,6 @@ void GPUContextVulkan::FrameBegin() _psDirtyFlag = 0; _rtDirtyFlag = 0; _cbDirtyFlag = 0; - _srDirtyFlag = 0; - _uaDirtyFlag = 0; _rtCount = 0; _vbCount = 0; _renderPass = nullptr; @@ -726,6 +726,8 @@ void GPUContextVulkan::FrameBegin() Platform::MemoryClear(_cbHandles, sizeof(_cbHandles)); Platform::MemoryClear(_srHandles, sizeof(_srHandles)); Platform::MemoryClear(_uaHandles, sizeof(_uaHandles)); + Platform::MemoryCopy(_samplerHandles, _device->HelperResources.GetStaticSamplers(), sizeof(VkSampler) * GPU_STATIC_SAMPLERS_COUNT); + Platform::MemoryClear(_samplerHandles + GPU_STATIC_SAMPLERS_COUNT, sizeof(_samplerHandles) - sizeof(VkSampler) * GPU_STATIC_SAMPLERS_COUNT); #if VULKAN_RESET_QUERY_POOLS // Reset pending queries @@ -916,13 +918,11 @@ void GPUContextVulkan::SetRenderTarget(GPUTextureView* rt, GPUBuffer* uaOutput) void GPUContextVulkan::ResetSR() { - _srDirtyFlag = false; Platform::MemoryClear(_srHandles, sizeof(_srHandles)); } void GPUContextVulkan::ResetUA() { - _uaDirtyFlag = false; Platform::MemoryClear(_uaHandles, sizeof(_uaHandles)); } @@ -951,7 +951,6 @@ void GPUContextVulkan::BindSR(int32 slot, GPUResourceView* view) const auto handle = view ? (DescriptorOwnerResourceVulkan*)view->GetNativePtr() : nullptr; if (_srHandles[slot] != handle) { - _srDirtyFlag = true; _srHandles[slot] = handle; if (view) *view->LastRenderTime = _lastRenderTime; @@ -964,7 +963,6 @@ void GPUContextVulkan::BindUA(int32 slot, GPUResourceView* view) const auto handle = view ? (DescriptorOwnerResourceVulkan*)view->GetNativePtr() : nullptr; if (_uaHandles[slot] != handle) { - _uaDirtyFlag = true; _uaHandles[slot] = handle; if (view) *view->LastRenderTime = _lastRenderTime; @@ -997,6 +995,16 @@ void GPUContextVulkan::BindIB(GPUBuffer* indexBuffer) vkCmdBindIndexBuffer(cmdBuffer->GetHandle(), ibVulkan, 0, indexBuffer->GetFormat() == PixelFormat::R32_UInt ? VK_INDEX_TYPE_UINT32 : VK_INDEX_TYPE_UINT16); } +void GPUContextVulkan::BindSampler(int32 slot, GPUSampler* sampler) +{ + ASSERT(slot >= 0 && slot < GPU_MAX_SR_BINDED); + const auto handle = sampler ? ((GPUSamplerVulkan*)sampler)->Sampler : nullptr; + if (_samplerHandles[slot] != handle) + { + _samplerHandles[slot] = handle; + } +} + void GPUContextVulkan::UpdateCB(GPUConstantBuffer* cb, const void* data) { ASSERT(data && cb); diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.h index da2054ab3..f4ba1deeb 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUContextVulkan.h @@ -94,8 +94,6 @@ private: int32 _psDirtyFlag : 1; int32 _rtDirtyFlag : 1; int32 _cbDirtyFlag : 1; - int32 _srDirtyFlag : 1; - int32 _uaDirtyFlag : 1; int32 _rtCount; int32 _vbCount; @@ -107,6 +105,7 @@ private: DescriptorOwnerResourceVulkan* _cbHandles[GPU_MAX_CB_BINDED]; DescriptorOwnerResourceVulkan* _srHandles[GPU_MAX_SR_BINDED]; DescriptorOwnerResourceVulkan* _uaHandles[GPU_MAX_UA_BINDED]; + VkSampler _samplerHandles[GPU_MAX_SAMPLER_BINDED]; DescriptorOwnerResourceVulkan** _handles[(int32)SpirvShaderResourceBindingType::MAX]; typedef Array DescriptorPoolArray; @@ -188,6 +187,7 @@ public: void BindUA(int32 slot, GPUResourceView* view) override; void BindVB(const Span& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr) override; void BindIB(GPUBuffer* indexBuffer) override; + void BindSampler(int32 slot, GPUSampler* sampler) override; void UpdateCB(GPUConstantBuffer* cb, const void* data) override; void Dispatch(GPUShaderProgramCS* shader, uint32 threadGroupCountX, uint32 threadGroupCountY, uint32 threadGroupCountZ) override; void DispatchIndirect(GPUShaderProgramCS* shader, GPUBuffer* bufferForArgs, uint32 offsetForArgs) override; diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp index 2ad04d2cb..c2582ad95 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp @@ -13,6 +13,7 @@ #include "GPUTextureVulkan.h" #include "GPUTimerQueryVulkan.h" #include "GPUBufferVulkan.h" +#include "GPUSamplerVulkan.h" #include "GPUSwapChainVulkan.h" #include "RenderToolsVulkan.h" #include "QueueVulkan.h" @@ -369,7 +370,7 @@ void DeferredDeletionQueueVulkan::ReleaseResources(bool deleteImmediately) #undef SWITCH_CASE default: #if !BUILD_RELEASE - CRASH; + CRASH; #endif break; } @@ -730,8 +731,9 @@ void InitSampler(VkSamplerCreateInfo& createInfo, bool supportsMirrorClampToEdge createInfo.compareOp = RenderToolsVulkan::ToVulkanSamplerCompareFunction(compareFunction); } -VkSampler HelperResourcesVulkan::GetStaticSampler(StaticSamplers type) +VkSampler* HelperResourcesVulkan::GetStaticSamplers() { + static_assert(GPU_STATIC_SAMPLERS_COUNT == 6, "Update static samplers setup."); if (!_staticSamplers[0]) { const bool supportsMirrorClampToEdge = GPUDeviceVulkan::OptionalDeviceExtensions.HasMirrorClampToEdge; @@ -769,8 +771,7 @@ VkSampler HelperResourcesVulkan::GetStaticSampler(StaticSamplers type) InitSampler(createInfo, supportsMirrorClampToEdge, GPUSamplerFilter::Trilinear, GPUSamplerAddressMode::Clamp, GPUSamplerAddressMode::Clamp, GPUSamplerAddressMode::Clamp, GPUSamplerCompareFunction::Less); VALIDATE_VULKAN_RESULT(vkCreateSampler(_device->Device, &createInfo, nullptr, &_staticSamplers[5])); } - - return _staticSamplers[static_cast(type)]; + return _staticSamplers; } GPUTextureVulkan* HelperResourcesVulkan::GetDummyTexture(SpirvShaderResourceType type) @@ -797,7 +798,7 @@ GPUTextureVulkan* HelperResourcesVulkan::GetDummyTexture(SpirvShaderResourceType index = 5; break; default: - CRASH; + CRASH; return nullptr; } @@ -1172,7 +1173,7 @@ GPUDevice* GPUDeviceVulkan::Create() volkLoadInstance(Instance); #endif -// Setup debug layer + // Setup debug layer #if VULKAN_USE_DEBUG_LAYER SetupDebugLayerCallback(); #endif @@ -1692,6 +1693,7 @@ bool GPUDeviceVulkan::Init() limits.MaximumTexture2DArraySize = PhysicalDeviceLimits.maxImageArrayLayers; limits.MaximumTexture3DSize = PhysicalDeviceLimits.maxImageDimension3D; limits.MaximumTextureCubeSize = PhysicalDeviceLimits.maxImageDimensionCube; + limits.MaximumSamplerAnisotropy = PhysicalDeviceLimits.maxSamplerAnisotropy; for (int32 i = 0; i < static_cast(PixelFormat::MAX); i++) { @@ -1957,6 +1959,11 @@ GPUBuffer* GPUDeviceVulkan::CreateBuffer(const StringView& name) return New(this, name); } +GPUSampler* GPUDeviceVulkan::CreateSampler() +{ + return New(this); +} + GPUSwapChain* GPUDeviceVulkan::CreateSwapChain(Window* window) { return New(this, window); diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h index 882c803b5..4b3bf7093 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h @@ -385,46 +385,24 @@ public: /// class HelperResourcesVulkan { -public: - - enum class StaticSamplers - { - SamplerLinearClamp =0, - SamplerPointClamp = 1, - SamplerLinearWrap = 2, - SamplerPointWrap = 3, - ShadowSampler = 4, - ShadowSamplerPCF = 5, - - MAX - }; - private: GPUDeviceVulkan* _device; GPUTextureVulkan* _dummyTextures[6]; GPUBufferVulkan* _dummyBuffer; GPUBufferVulkan* _dummyVB; - VkSampler _staticSamplers[static_cast(StaticSamplers::MAX)]; + VkSampler _staticSamplers[GPU_STATIC_SAMPLERS_COUNT]; public: - /// - /// Initializes a new instance of the class. - /// - /// The graphics device. HelperResourcesVulkan(GPUDeviceVulkan* device); public: - VkSampler GetStaticSampler(StaticSamplers type); - + VkSampler* GetStaticSamplers(); GPUTextureVulkan* GetDummyTexture(SpirvShaderResourceType type); - GPUBufferVulkan* GetDummyBuffer(); - GPUBufferVulkan* GetDummyVertexBuffer(); - void Dispose(); }; @@ -739,6 +717,7 @@ public: GPUPipelineState* CreatePipelineState() override; GPUTimerQuery* CreateTimerQuery() override; GPUBuffer* CreateBuffer(const StringView& name) override; + GPUSampler* CreateSampler() override; GPUSwapChain* CreateSwapChain(Window* window) override; }; diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUSamplerVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUSamplerVulkan.cpp new file mode 100644 index 000000000..17571f1ed --- /dev/null +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUSamplerVulkan.cpp @@ -0,0 +1,56 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#if GRAPHICS_API_VULKAN + +#include "GPUSamplerVulkan.h" +#include "RenderToolsVulkan.h" + +bool GPUSamplerVulkan::OnInit() +{ + VkSamplerCreateInfo createInfo; + RenderToolsVulkan::ZeroStruct(createInfo, VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO); + createInfo.magFilter = RenderToolsVulkan::ToVulkanMagFilterMode(_desc.Filter); + createInfo.minFilter = RenderToolsVulkan::ToVulkanMinFilterMode(_desc.Filter); + createInfo.mipmapMode = RenderToolsVulkan::ToVulkanMipFilterMode(_desc.Filter); + const bool supportsMirrorClampToEdge = GPUDeviceVulkan::OptionalDeviceExtensions.HasMirrorClampToEdge; + createInfo.addressModeU = RenderToolsVulkan::ToVulkanWrapMode(_desc.AddressU, supportsMirrorClampToEdge); + createInfo.addressModeV = RenderToolsVulkan::ToVulkanWrapMode(_desc.AddressV, supportsMirrorClampToEdge); + createInfo.addressModeW = RenderToolsVulkan::ToVulkanWrapMode(_desc.AddressW, supportsMirrorClampToEdge); + createInfo.mipLodBias = _desc.MipBias; + createInfo.anisotropyEnable = _desc.Filter == GPUSamplerFilter::Anisotropic ? VK_TRUE : VK_FALSE; + createInfo.maxAnisotropy = (float)_desc.MaxAnisotropy; + createInfo.compareEnable = _desc.ComparisonFunction != GPUSamplerCompareFunction::Never ? VK_TRUE : VK_FALSE; + createInfo.compareOp = RenderToolsVulkan::ToVulkanSamplerCompareFunction(_desc.ComparisonFunction); + createInfo.minLod = _desc.MinMipLevel; + createInfo.maxLod = _desc.MaxMipLevel; + switch (_desc.BorderColor) + { + case GPUSamplerBorderColor::TransparentBlack: + createInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; + break; + case GPUSamplerBorderColor::OpaqueBlack: + createInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; + break; + case GPUSamplerBorderColor::OpaqueWhite: + createInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + break; + default: + return true; + } + VALIDATE_VULKAN_RESULT(vkCreateSampler(_device->Device, &createInfo, nullptr, &Sampler)); + return false; +} + +void GPUSamplerVulkan::OnReleaseGPU() +{ + if (Sampler != VK_NULL_HANDLE) + { + _device->DeferredDeletionQueue.EnqueueResource(DeferredDeletionQueueVulkan::Buffer, Sampler); + Sampler = VK_NULL_HANDLE; + } + + // Base + GPUSampler::OnReleaseGPU(); +} + +#endif diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUSamplerVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/GPUSamplerVulkan.h new file mode 100644 index 000000000..6473cc62e --- /dev/null +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUSamplerVulkan.h @@ -0,0 +1,31 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +#if GRAPHICS_API_VULKAN + +#include "Engine/Graphics/Textures/GPUSampler.h" +#include "GPUDeviceVulkan.h" + +/// +/// Sampler object for Vulkan backend. +/// +class GPUSamplerVulkan : public GPUResourceVulkan +{ +public: + + GPUSamplerVulkan(GPUDeviceVulkan* device) + : GPUResourceVulkan(device, StringView::Empty) + { + } + + VkSampler Sampler = VK_NULL_HANDLE; + +protected: + + // [GPUSamplerVulkan] + bool OnInit() override; + void OnReleaseGPU() override; +}; + +#endif