diff options
author | Lukas Stockner <lukas.stockner@freenet.de> | 2022-10-30 00:41:21 +0300 |
---|---|---|
committer | Lukas Stockner <lukas.stockner@freenet.de> | 2022-10-30 01:14:59 +0300 |
commit | bc37e8d8399eef686b71341aa90eced9bc117786 (patch) | |
tree | 92e4af388150209df9bc44e2cba6f2f303aa7baf /source/blender/gpu/metal/mtl_context.hh | |
parent | 552abb838c76d44a0d7d1226b59a1ab381e88386 (diff) | |
parent | d1d2f002c7caaf4ab457ec27bbc44666d7aac624 (diff) |
Merge remote-tracking branch 'origin/master' into principled-v2
Diffstat (limited to 'source/blender/gpu/metal/mtl_context.hh')
-rw-r--r-- | source/blender/gpu/metal/mtl_context.hh | 153 |
1 files changed, 126 insertions, 27 deletions
diff --git a/source/blender/gpu/metal/mtl_context.hh b/source/blender/gpu/metal/mtl_context.hh index 0db87bf5da5..6229afcef79 100644 --- a/source/blender/gpu/metal/mtl_context.hh +++ b/source/blender/gpu/metal/mtl_context.hh @@ -3,7 +3,6 @@ /** \file * \ingroup gpu */ - #pragma once #include "MEM_guardedalloc.h" @@ -13,11 +12,17 @@ #include "GPU_common_types.h" #include "GPU_context.h" +#include "intern/GHOST_Context.h" +#include "intern/GHOST_ContextCGL.h" +#include "intern/GHOST_Window.h" + #include "mtl_backend.hh" #include "mtl_capabilities.hh" #include "mtl_common.hh" #include "mtl_framebuffer.hh" #include "mtl_memory.hh" +#include "mtl_shader.hh" +#include "mtl_shader_interface.hh" #include "mtl_texture.hh" #include <Cocoa/Cocoa.h> @@ -33,7 +38,6 @@ namespace blender::gpu { /* Forward Declarations */ class MTLContext; class MTLCommandBufferManager; -class MTLShader; class MTLUniformBuf; /* Structs containing information on current binding state for textures and samplers. */ @@ -41,7 +45,7 @@ struct MTLTextureBinding { bool used; /* Same value as index in bindings array. */ - uint texture_slot_index; + uint slot_index; gpu::MTLTexture *texture_resource; }; @@ -57,9 +61,10 @@ struct MTLSamplerBinding { /* Metal Context Render Pass State -- Used to track active RenderCommandEncoder state based on * bound MTLFrameBuffer's.Owned by MTLContext. */ -struct MTLRenderPassState { +class MTLRenderPassState { friend class MTLContext; + public: MTLRenderPassState(MTLContext &context, MTLCommandBufferManager &command_buffer_manager) : ctx(context), cmd(command_buffer_manager){}; @@ -174,9 +179,9 @@ struct MTLContextDepthStencilState { bool has_depth_target; bool has_stencil_target; - /* TODO(Metal): Consider optimizing this function using memcmp. + /* TODO(Metal): Consider optimizing this function using `memcmp`. * Un-used, but differing, stencil state leads to over-generation - * of state objects when doing trivial compare. */ + * of state objects when doing trivial compare. */ bool operator==(const MTLContextDepthStencilState &other) const { bool depth_state_equality = (has_depth_target == other.has_depth_target && @@ -247,7 +252,7 @@ struct MTLContextTextureUtils { /* Depth texture updates are not directly supported with Blit operations, similarly, we cannot * use a compute shader to write to depth, so we must instead render to a depth target. * These processes use vertex/fragment shaders to render texture data from an intermediate - * source, in order to prime the depth buffer*/ + * source, in order to prime the depth buffer. */ blender::Map<DepthTextureUpdateRoutineSpecialisation, GPUShader *> depth_2d_update_shaders; GPUShader *fullscreen_blit_shader = nullptr; @@ -347,7 +352,7 @@ struct MTLSamplerArray { { uint32_t hash = this->num_samplers; for (int i = 0; i < this->num_samplers; i++) { - hash ^= (uint32_t)this->mtl_sampler_flags[i] << (i % 3); + hash ^= uint32_t(this->mtl_sampler_flags[i]) << (i % 3); } return hash; } @@ -357,7 +362,7 @@ typedef enum MTLPipelineStateDirtyFlag { MTL_PIPELINE_STATE_NULL_FLAG = 0, /* Whether we need to call setViewport. */ MTL_PIPELINE_STATE_VIEWPORT_FLAG = (1 << 0), - /* Whether we need to call setScissor.*/ + /* Whether we need to call setScissor. */ MTL_PIPELINE_STATE_SCISSOR_FLAG = (1 << 1), /* Whether we need to update/rebind active depth stencil state. */ MTL_PIPELINE_STATE_DEPTHSTENCIL_FLAG = (1 << 2), @@ -564,18 +569,55 @@ class MTLCommandBufferManager { }; /** MTLContext -- Core render loop and state management. **/ -/* NOTE(Metal): Partial MTLContext stub to provide wrapper functionality - * for work-in-progress MTL* classes. */ +/* NOTE(Metal): Partial #MTLContext stub to provide wrapper functionality + * for work-in-progress `MTL*` classes. */ class MTLContext : public Context { friend class MTLBackend; + friend class MTLRenderPassState; + + public: + /* Swap-chain and latency management. */ + static std::atomic<int> max_drawables_in_flight; + static std::atomic<int64_t> avg_drawable_latency_us; + static int64_t frame_latency[MTL_FRAME_AVERAGE_COUNT]; + + public: + /* Shaders and Pipeline state. */ + MTLContextGlobalShaderPipelineState pipeline_state; + + /* Metal API Resource Handles. */ + id<MTLCommandQueue> queue = nil; + id<MTLDevice> device = nil; + +#ifndef NDEBUG + /* Label for Context debug name assignment. */ + NSString *label = nil; +#endif + + /* Memory Management. */ + MTLScratchBufferManager memory_manager; + static MTLBufferPool global_memory_manager; + + /* CommandBuffer managers. */ + MTLCommandBufferManager main_command_buffer; private: + /* Parent Context. */ + GHOST_ContextCGL *ghost_context_; + + /* Render Passes and Frame-buffers. */ + id<MTLTexture> default_fbo_mtltexture_ = nil; + gpu::MTLTexture *default_fbo_gputexture_ = nullptr; + + /* Depth-stencil state cache. */ + blender::Map<MTLContextDepthStencilState, id<MTLDepthStencilState>> depth_stencil_state_cache; + /* Compute and specialization caches. */ MTLContextTextureUtils texture_utils_; /* Texture Samplers. */ - /* Cache of generated MTLSamplerState objects based on permutations of `eGPUSamplerState`. */ + /* Cache of generated #MTLSamplerState objects based on permutations of `eGPUSamplerState`. */ id<MTLSamplerState> sampler_state_cache_[GPU_SAMPLER_MAX]; id<MTLSamplerState> default_sampler_state_ = nil; @@ -595,23 +637,20 @@ class MTLContext : public Context { gpu::MTLBuffer *visibility_buffer_ = nullptr; bool visibility_is_dirty_ = false; - public: - /* Shaders and Pipeline state. */ - MTLContextGlobalShaderPipelineState pipeline_state; - - /* Metal API Resource Handles. */ - id<MTLCommandQueue> queue = nil; - id<MTLDevice> device = nil; - - /* Memory Management */ - MTLScratchBufferManager memory_manager; - static MTLBufferPool global_memory_manager; + /* Null buffers for empty/uninitialized bindings. + * Null attribute buffer follows default attribute format of OpenGL Backend. */ + id<MTLBuffer> null_buffer_; /* All zero's. */ + id<MTLBuffer> null_attribute_buffer_; /* Value float4(0.0,0.0,0.0,1.0). */ - /* CommandBuffer managers. */ - MTLCommandBufferManager main_command_buffer; + /** Dummy Resources */ + /* Maximum of 32 texture types. Though most combinations invalid. */ + gpu::MTLTexture *dummy_textures_[GPU_TEXTURE_BUFFER] = {nullptr}; + GPUVertFormat dummy_vertformat_; + GPUVertBuf *dummy_verts_ = nullptr; + public: /* GPUContext interface. */ - MTLContext(void *ghost_window); + MTLContext(void *ghost_window, void *ghost_context); ~MTLContext(); static void check_error(const char *info); @@ -667,6 +706,35 @@ class MTLContext : public Context { void pipeline_state_init(); MTLShader *get_active_shader(); + /* These functions ensure that the current RenderCommandEncoder has + * the correct global state assigned. This should be called prior + * to every draw call, to ensure that all state is applied and up + * to date. We handle: + * + * - Buffer bindings (Vertex buffers, Uniforms, UBOs, transform feedback) + * - Texture bindings + * - Sampler bindings (+ argument buffer bindings) + * - Dynamic Render pipeline state (on encoder) + * - Baking Pipeline State Objects (PSOs) for current shader, based + * on final pipeline state. + * + * `ensure_render_pipeline_state` will return false if the state is + * invalid and cannot be applied. This should cancel a draw call. */ + bool ensure_render_pipeline_state(MTLPrimitiveType prim_type); + bool ensure_uniform_buffer_bindings( + id<MTLRenderCommandEncoder> rec, + const MTLShaderInterface *shader_interface, + const MTLRenderPipelineStateInstance *pipeline_state_instance); + void ensure_texture_bindings(id<MTLRenderCommandEncoder> rec, + MTLShaderInterface *shader_interface, + const MTLRenderPipelineStateInstance *pipeline_state_instance); + void ensure_depth_stencil_state(MTLPrimitiveType prim_type); + + id<MTLBuffer> get_null_buffer(); + id<MTLBuffer> get_null_attribute_buffer(); + gpu::MTLTexture *get_dummy_texture(eGPUTextureType type); + void free_dummy_resources(); + /* State assignment. */ void set_viewport(int origin_x, int origin_y, int width, int height); void set_scissor(int scissor_x, int scissor_y, int scissor_width, int scissor_height); @@ -678,7 +746,7 @@ class MTLContext : public Context { /* Flag whether the visibility buffer for query results * has changed. This requires a new RenderPass in order - * to update.*/ + * to update. */ bool is_visibility_dirty() const; /* Reset dirty flag state for visibility buffer. */ @@ -714,6 +782,37 @@ class MTLContext : public Context { { return MTLContext::global_memory_manager; } + + /* Swap-chain and latency management. */ + static void latency_resolve_average(int64_t frame_latency_us) + { + int64_t avg = 0; + int64_t frame_c = 0; + for (int i = MTL_FRAME_AVERAGE_COUNT - 1; i > 0; i--) { + MTLContext::frame_latency[i] = MTLContext::frame_latency[i - 1]; + avg += MTLContext::frame_latency[i]; + frame_c += (MTLContext::frame_latency[i] > 0) ? 1 : 0; + } + MTLContext::frame_latency[0] = frame_latency_us; + avg += MTLContext::frame_latency[0]; + if (frame_c > 0) { + avg /= frame_c; + } + else { + avg = 0; + } + MTLContext::avg_drawable_latency_us = avg; + } + + private: + void set_ghost_context(GHOST_ContextHandle ghostCtxHandle); + void set_ghost_window(GHOST_WindowHandle ghostWinHandle); }; +/* GHOST Context callback and present. */ +void present(MTLRenderPassDescriptor *blit_descriptor, + id<MTLRenderPipelineState> blit_pso, + id<MTLTexture> swapchain_texture, + id<CAMetalDrawable> drawable); + } // namespace blender::gpu |