// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
#pragma once
#include "Engine/Scripting/ScriptingObject.h"
#include "Engine/Core/Types/Span.h"
#include "Engine/Core/Math/Rectangle.h"
#include "Engine/Core/Math/Viewport.h"
#include "PixelFormat.h"
#include "Config.h"
class GPUConstantBuffer;
class GPUShaderProgramCS;
class GPUBuffer;
class GPUPipelineState;
class GPUTexture;
class GPUSampler;
class GPUDevice;
class GPUResource;
class GPUResourceView;
class GPUTextureView;
class GPUBufferView;
// Gets the GPU texture view. Checks if pointer is not null and texture has one or more mip levels loaded.
#define GET_TEXTURE_VIEW_SAFE(t) (t && t->ResidentMipLevels() > 0 ? t->View() : nullptr)
///
/// The GPU dispatch indirect command arguments data.
///
API_STRUCT() struct GPUDispatchIndirectArgs
{
DECLARE_SCRIPTING_TYPE_NO_SPAWN(GPUDispatchIndirectArgs);
///
/// The X dimension of dispatch size.
///
API_FIELD() uint32 ThreadGroupCountX;
///
/// The Y dimension of dispatch size.
///
API_FIELD() uint32 ThreadGroupCountY;
///
/// The Z dimension of dispatch size.
///
API_FIELD() uint32 ThreadGroupCountZ;
};
///
/// The GPU draw indirect command arguments data.
///
API_STRUCT() struct GPUDrawIndirectArgs
{
DECLARE_SCRIPTING_TYPE_NO_SPAWN(GPUDrawIndirectArgs);
///
/// The number of vertices to draw for each instance.
///
API_FIELD() uint32 VerticesCount;
///
/// The number of instances to draw.
///
API_FIELD() uint32 InstanceCount;
///
/// An offset added to each vertex index.
///
API_FIELD() uint32 StartVertex;
///
/// An offset added to each instance index.
///
API_FIELD() uint32 StartInstance;
};
///
/// The GPU draw indexed indirect command arguments data.
///
API_STRUCT() struct GPUDrawIndexedIndirectArgs
{
DECLARE_SCRIPTING_TYPE_NO_SPAWN(GPUDrawIndexedIndirectArgs);
///
/// The number of indices to draw for each instance.
///
API_FIELD() uint32 IndicesCount;
///
/// The number of instances to draw.
///
API_FIELD() uint32 InstanceCount;
///
/// An offset into the index buffer where drawing should begin.
///
API_FIELD() uint32 StartIndex;
///
/// An offset added to each vertex index.
///
API_FIELD() uint32 StartVertex;
///
/// An offset added to each instance index.
///
API_FIELD() uint32 StartInstance;
};
///
/// Interface for GPU device context that can record and send graphics commands to the GPU in a sequence.
///
API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API GPUContext : public ScriptingObject
{
DECLARE_SCRIPTING_TYPE_NO_SPAWN(GPUContext);
private:
GPUDevice* _device;
protected:
double _lastRenderTime = -1;
GPUContext(GPUDevice* device);
public:
///
/// Gets the graphics device.
///
FORCE_INLINE GPUDevice* GetDevice() const
{
return _device;
}
public:
///
/// Begins new frame and enters commands collecting mode.
///
virtual void FrameBegin();
///
/// Ends the current frame rendering.
///
virtual void FrameEnd();
public:
#if GPU_ALLOW_PROFILE_EVENTS
///
/// Begins the profile event.
///
/// The name.
virtual void EventBegin(const Char* name)
{
}
///
/// Ends the last profile event.
///
virtual void EventEnd()
{
}
#endif
public:
///
/// Gets the native pointer to the underlying graphics device context. It's a low-level platform-specific handle.
///
API_PROPERTY() virtual void* GetNativePtr() const = 0;
///
/// Determines whether depth buffer is binded to the pipeline.
///
/// true if depth buffer is binded; otherwise, false.
virtual bool IsDepthBufferBinded() = 0;
public:
///
/// Clears texture surface with a color. Supports volumetric textures and texture arrays (including cube textures).
///
/// The target surface.
/// The clear color.
API_FUNCTION() virtual void Clear(GPUTextureView* rt, const Color& color) = 0;
///
/// Clears depth buffer.
///
/// The depth buffer to clear.
/// The clear depth value.
/// The clear stencil value.
API_FUNCTION() virtual void ClearDepth(GPUTextureView* depthBuffer, float depthValue = 1.0f, uint8 stencilValue = 0) = 0;
///
/// Clears an unordered access buffer with a float value.
///
/// The buffer to clear.
/// The clear value.
API_FUNCTION() virtual void ClearUA(GPUBuffer* buf, const Float4& value) = 0;
///
/// Clears an unordered access buffer with a unsigned value.
///
/// The buffer to clear.
/// The clear value.
virtual void ClearUA(GPUBuffer* buf, const uint32 value[4]) = 0;
///
/// Clears an unordered access texture with a unsigned value.
///
/// The texture to clear.
/// The clear value.
virtual void ClearUA(GPUTexture* texture, const uint32 value[4]) = 0;
///
/// Clears an unordered access texture with a float value.
///
/// The texture to clear.
/// The clear value.
virtual void ClearUA(GPUTexture* texture, const Float4& value) = 0;
public:
///
/// Updates the buffer data.
///
/// The destination buffer to write to.
/// The pointer to the data.
/// The data size (in bytes) to write.
/// The offset (in bytes) from the buffer start to copy data to.
API_FUNCTION() virtual void UpdateBuffer(GPUBuffer* buffer, const void* data, uint32 size, uint32 offset = 0) = 0;
///
/// Copies the buffer data.
///
/// The destination buffer to write to.
/// The source buffer to read from.
/// The size of data to copy (in bytes).
/// The offset (in bytes) from the destination buffer start to copy data to.
/// The offset (in bytes) from the source buffer start to copy data from.
API_FUNCTION() virtual void CopyBuffer(GPUBuffer* dstBuffer, GPUBuffer* srcBuffer, uint32 size, uint32 dstOffset = 0, uint32 srcOffset = 0) = 0;
///
/// Updates the texture data.
///
/// The destination texture.
/// The destination surface index in the texture array.
/// The absolute index of the mip map to update.
/// The pointer to the data.
/// The row pitch (in bytes) of the input data.
/// The slice pitch (in bytes) of the input data.
API_FUNCTION() virtual void UpdateTexture(GPUTexture* texture, int32 arrayIndex, int32 mipIndex, const void* data, uint32 rowPitch, uint32 slicePitch) = 0;
///
/// Copies region of the texture.
///
/// The destination resource.
/// The destination subresource index.
/// The x-coordinate of the upper left corner of the destination region.
/// The y-coordinate of the upper left corner of the destination region.
/// The z-coordinate of the upper left corner of the destination region.
/// The source resource.
/// The source subresource index.
API_FUNCTION() virtual void CopyTexture(GPUTexture* dstResource, uint32 dstSubresource, uint32 dstX, uint32 dstY, uint32 dstZ, GPUTexture* srcResource, uint32 srcSubresource) = 0;
///
/// Resets the counter buffer to zero (hidden by the driver).
///
/// The buffer.
API_FUNCTION() virtual void ResetCounter(GPUBuffer* buffer) = 0;
///
/// Copies the counter buffer value.
///
/// The destination buffer.
/// The destination aligned byte offset.
/// The source buffer.
API_FUNCTION() virtual void CopyCounter(GPUBuffer* dstBuffer, uint32 dstOffset, GPUBuffer* srcBuffer) = 0;
///
/// Copies the resource data (whole resource).
///
/// The destination resource.
/// The source resource.
API_FUNCTION() virtual void CopyResource(GPUResource* dstResource, GPUResource* srcResource) = 0;
///
/// Copies the subresource data.
///
/// The destination resource.
/// The destination subresource index.
/// The source resource.
/// The source subresource index.
API_FUNCTION() virtual void CopySubresource(GPUResource* dstResource, uint32 dstSubresource, GPUResource* srcResource, uint32 srcSubresource) = 0;
public:
///
/// Unbinds all the render targets and flushes the change with the driver (used to prevent driver detection of resource hazards, eg. when down-scaling the texture).
///
API_FUNCTION() virtual void ResetRenderTarget() = 0;
///
/// Sets the render target to the output.
///
/// The render target.
API_FUNCTION() virtual void SetRenderTarget(GPUTextureView* rt) = 0;
///
/// Sets the render target and the depth buffer to the output.
///
/// The depth buffer.
/// The render target.
API_FUNCTION() virtual void SetRenderTarget(GPUTextureView* depthBuffer, GPUTextureView* rt) = 0;
///
/// Sets the render targets and the depth buffer to the output.
///
/// The depth buffer (can be null).
/// The array with render targets to bind.
API_FUNCTION() virtual void SetRenderTarget(GPUTextureView* depthBuffer, const Span& rts) = 0;
///
/// Sets the blend factor that modulate values for a pixel shader, render target, or both.
///
/// Blend factors, one for each RGBA component.
API_FUNCTION() virtual void SetBlendFactor(const Float4& value) = 0;
///
/// Sets the reference value for depth stencil tests.
///
/// Reference value to perform against when doing a depth-stencil test.
API_FUNCTION() virtual void SetStencilRef(uint32 value) = 0;
public:
///
/// Unbinds all shader resource slots and flushes the change with the driver (used to prevent driver detection of resource hazards, eg. when down-scaling the texture).
///
API_FUNCTION() virtual void ResetSR() = 0;
///
/// Unbinds all unordered access resource slots and flushes the change with the driver (used to prevent driver detection of resource hazards, eg. when down-scaling the texture).
///
API_FUNCTION() virtual void ResetUA() = 0;
///
/// Unbinds all constant buffer slots and flushes the change with the driver (used to prevent driver detection of resource hazards, eg. when down-scaling the texture).
///
API_FUNCTION() virtual void ResetCB() = 0;
///
/// Unbinds shader resource slot.
///
/// The slot index.
FORCE_INLINE void UnBindSR(int32 slot)
{
BindSR(slot, static_cast(nullptr));
}
///
/// Unbinds unordered access resource slot.
///
/// The slot index.
FORCE_INLINE void UnBindUA(int32 slot)
{
BindUA(slot, static_cast(nullptr));
}
///
/// Unbinds constant buffer slot.
///
/// The slot index.
FORCE_INLINE void UnBindCB(int32 slot)
{
BindCB(slot, nullptr);
}
///
/// Binds the texture to the shader resource slot.
///
/// The slot index.
/// The GPU texture.
API_FUNCTION() void BindSR(int32 slot, GPUTexture* t);
///
/// Binds the resource view to the shader resource slot (texture view or buffer view).
///
/// The slot index.
/// The resource view.
API_FUNCTION() virtual void BindSR(int32 slot, GPUResourceView* view) = 0;
///
/// Binds the resource view to the unordered access slot (texture view or buffer view).
///
/// The slot index.
/// The resource view.
API_FUNCTION() virtual void BindUA(int32 slot, GPUResourceView* view) = 0;
///
/// Binds the constant buffer to the slot.
///
/// The slot index.
/// The constant buffer.
API_FUNCTION() virtual void BindCB(int32 slot, GPUConstantBuffer* cb) = 0;
///
/// Binds the vertex buffers to the pipeline.
///
/// The array of vertex buffers to use.
/// The optional array of byte offsets from the vertex buffers begins. Can be used to offset the vertex data when reusing the same buffer allocation for multiple geometry objects.
API_FUNCTION() virtual void BindVB(const Span& vertexBuffers, const uint32* vertexBuffersOffsets = nullptr) = 0;
///
/// Binds the index buffer to the pipeline.
///
/// 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:
///
/// Updates the constant buffer data.
///
/// The constant buffer.
/// The pointer to the data.
API_FUNCTION() virtual void UpdateCB(GPUConstantBuffer* cb, const void* data) = 0;
public:
///
/// Executes a command list from a thread group.
///
/// The compute shader program to execute.
/// The number of groups dispatched in the x direction.
/// The number of groups dispatched in the y direction.
/// The number of groups dispatched in the z direction.
API_FUNCTION() virtual void Dispatch(GPUShaderProgramCS* shader, uint32 threadGroupCountX, uint32 threadGroupCountY, uint32 threadGroupCountZ) = 0;
///
/// Executes a command list from a thread group. Buffer must contain GPUDispatchIndirectArgs.
///
/// The compute shader program to execute.
/// The buffer with drawing arguments.
/// The aligned byte offset for arguments.
API_FUNCTION() virtual void DispatchIndirect(GPUShaderProgramCS* shader, GPUBuffer* bufferForArgs, uint32 offsetForArgs) = 0;
///
/// Resolves the multisampled texture by performing a copy of the resource into a non-multisampled resource.
///
/// The source multisampled texture. Must be multisampled.
/// The destination texture. Must be single-sampled.
/// The source sub-resource index.
/// The destination sub-resource index.
/// The format. Indicates how the multisampled resource will be resolved to a single-sampled resource.
API_FUNCTION() virtual void ResolveMultisample(GPUTexture* sourceMultisampleTexture, GPUTexture* destTexture, int32 sourceSubResource = 0, int32 destSubResource = 0, PixelFormat format = PixelFormat::Unknown) = 0;
///
/// Draws the fullscreen triangle (using single triangle). Use instance count parameter to render more than one instance of the triangle.
///
/// The instance count. Use SV_InstanceID in vertex shader to detect volume slice plane index.
API_FUNCTION() void DrawFullscreenTriangle(int32 instanceCount = 1);
///
/// Draws the specified source texture to destination render target (using fullscreen triangle). Copies contents with resizing and format conversion support. Uses linear texture sampling.
///
/// The destination texture.
/// The source texture.
API_FUNCTION() void Draw(GPUTexture* dst, GPUTexture* src);
///
/// Draws the specified texture to render target (using fullscreen triangle). Copies contents with resizing and format conversion support. Uses linear texture sampling.
///
/// The texture.
API_FUNCTION() void Draw(GPUTexture* rt);
///
/// Draws the specified texture to render target (using fullscreen triangle). Copies contents with resizing and format conversion support. Uses linear texture sampling.
///
/// The texture view.
API_FUNCTION() void Draw(GPUTextureView* rt);
///
/// Draws non-indexed, non-instanced primitives.
///
/// A value added to each index before reading a vertex from the vertex buffer.
/// The vertices count.
API_FUNCTION() FORCE_INLINE void Draw(uint32 startVertex, uint32 verticesCount)
{
DrawInstanced(verticesCount, 1, 0, startVertex);
}
///
/// Draws the instanced primitives.
///
/// The vertices count.
/// Number of instances to draw.
/// A value added to each index before reading per-instance data from a vertex buffer.
/// A value added to each index before reading a vertex from the vertex buffer.
API_FUNCTION() virtual void DrawInstanced(uint32 verticesCount, uint32 instanceCount, int32 startInstance = 0, int32 startVertex = 0) = 0;
///
/// Draws the indexed primitives.
///
/// The indices count.
/// A value added to each index before reading a vertex from the vertex buffer.
/// The location of the first index read by the GPU from the index buffer.
API_FUNCTION() FORCE_INLINE void DrawIndexed(uint32 indicesCount, int32 startVertex = 0, int32 startIndex = 0)
{
DrawIndexedInstanced(indicesCount, 1, 0, startVertex, startIndex);
}
///
/// Draws the indexed, instanced primitives.
///
/// The indices count.
/// Number of instances to draw.
/// A value added to each index before reading per-instance data from a vertex buffer.
/// A value added to each index before reading a vertex from the vertex buffer.
/// The location of the first index read by the GPU from the index buffer.
API_FUNCTION() virtual void DrawIndexedInstanced(uint32 indicesCount, uint32 instanceCount, int32 startInstance = 0, int32 startVertex = 0, int32 startIndex = 0) = 0;
///
/// Draws the instanced GPU-generated primitives. Buffer must contain GPUDrawIndirectArgs.
///
/// The buffer with drawing arguments.
/// The aligned byte offset for arguments.
API_FUNCTION() virtual void DrawInstancedIndirect(GPUBuffer* bufferForArgs, uint32 offsetForArgs) = 0;
///
/// Draws the instanced GPU-generated indexed primitives. Buffer must contain GPUDrawIndexedIndirectArgs.
///
/// The buffer with drawing arguments.
/// The aligned byte offset for arguments.
API_FUNCTION() virtual void DrawIndexedInstancedIndirect(GPUBuffer* bufferForArgs, uint32 offsetForArgs) = 0;
public:
///
/// Sets the rendering viewport and scissor rectangle.
///
/// The width (in pixels).
/// The height (in pixels).
API_FUNCTION() FORCE_INLINE void SetViewportAndScissors(float width, float height)
{
const Viewport viewport(0.0f, 0.0f, width, height);
SetViewport(viewport);
const Rectangle rect(0.0f, 0.0f, width, height);
SetScissor(rect);
}
///
/// Sets the rendering viewport and scissor rectangle.
///
/// The viewport (in pixels).
API_FUNCTION() FORCE_INLINE void SetViewportAndScissors(const Viewport& viewport)
{
SetViewport(viewport);
const Rectangle rect(viewport.Location.X, viewport.Location.Y, viewport.Width, viewport.Height);
SetScissor(rect);
}
///
/// Sets the rendering viewport.
///
/// The width (in pixels).
/// The height (in pixels).
API_FUNCTION() FORCE_INLINE void SetViewport(float width, float height)
{
const Viewport viewport(0.0f, 0.0f, width, height);
SetViewport(viewport);
}
///
/// Sets the rendering viewport.
///
/// The viewport (in pixels).
API_FUNCTION() virtual void SetViewport(API_PARAM(Ref) const Viewport& viewport) = 0;
///
/// Sets the scissor rectangle.
///
/// The scissor rectangle (in pixels).
API_FUNCTION() virtual void SetScissor(API_PARAM(Ref) const Rectangle& scissorRect) = 0;
public:
///
/// Sets the graphics pipeline state.
///
/// The state to bind.
API_FUNCTION() virtual void SetState(GPUPipelineState* state) = 0;
///
/// Gets the current pipeline state binded to the graphics pipeline.
///
/// The current state.
API_FUNCTION() virtual GPUPipelineState* GetState() const = 0;
///
/// Clears the context state.
///
API_FUNCTION() virtual void ClearState() = 0;
///
/// Flushes the internal cached context state with a command buffer.
///
API_FUNCTION() virtual void FlushState() = 0;
///
/// Flushes the command buffer (calls GPU execution).
///
API_FUNCTION() virtual void Flush() = 0;
///
/// Sets the state of the resource (or subresource).
///
virtual void SetResourceState(GPUResource* resource, uint64 state, int32 subresource = -1);
///
/// Forces graphics backend to rebind descriptors after command list was used by external graphics library.
///
virtual void ForceRebindDescriptors();
};