// 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(); };