Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/gpu/metal/mtl_context.mm')
-rw-r--r--source/blender/gpu/metal/mtl_context.mm229
1 files changed, 206 insertions, 23 deletions
diff --git a/source/blender/gpu/metal/mtl_context.mm b/source/blender/gpu/metal/mtl_context.mm
index 94f5682b11b..64a44c6f718 100644
--- a/source/blender/gpu/metal/mtl_context.mm
+++ b/source/blender/gpu/metal/mtl_context.mm
@@ -22,7 +22,7 @@ namespace blender::gpu {
bool MTLTemporaryBufferRange::requires_flush()
{
- /* We do not need to flush shared memory */
+ /* We do not need to flush shared memory. */
return this->options & MTLResourceStorageModeManaged;
}
@@ -49,15 +49,86 @@ MTLContext::MTLContext(void *ghost_window)
/* Init debug. */
debug::mtl_debug_init();
+ /* Initialise command buffer state. */
+ this->main_command_buffer.prepare(this);
+
+ /* Frame management. */
+ is_inside_frame_ = false;
+
+ /* Create FrameBuffer handles. */
+ MTLFrameBuffer *mtl_front_left = new MTLFrameBuffer(this, "front_left");
+ MTLFrameBuffer *mtl_back_left = new MTLFrameBuffer(this, "back_left");
+ this->front_left = mtl_front_left;
+ this->back_left = mtl_back_left;
+ this->active_fb = this->back_left;
+ /* Prepare platform and capabilities. (Note: With METAL, this needs to be done after CTX
+ * initialisation). */
+ MTLBackend::platform_init(this);
+ MTLBackend::capabilities_init(this);
/* Initialize Metal modules. */
this->state_manager = new MTLStateManager(this);
- /* TODO(Metal): Implement. */
+ /* Initialise texture read/update structures. */
+ this->get_texture_utils().init();
+
+ /* Bound Samplers struct. */
+ for (int i = 0; i < MTL_MAX_TEXTURE_SLOTS; i++) {
+ samplers_.mtl_sampler[i] = nil;
+ samplers_.mtl_sampler_flags[i] = DEFAULT_SAMPLER_STATE;
+ }
+
+ /* Initialise samplers. */
+ for (uint i = 0; i < GPU_SAMPLER_MAX; i++) {
+ MTLSamplerState state;
+ state.state = static_cast<eGPUSamplerState>(i);
+ sampler_state_cache_[i] = this->generate_sampler_from_state(state);
+ }
}
MTLContext::~MTLContext()
{
- /* TODO(Metal): Implement. */
+ BLI_assert(this == reinterpret_cast<MTLContext *>(GPU_context_active_get()));
+ /* Ensure rendering is complete command encoders/command buffers are freed. */
+ if (MTLBackend::get()->is_inside_render_boundary()) {
+ this->finish();
+
+ /* End frame. */
+ if (is_inside_frame_) {
+ this->end_frame();
+ }
+ }
+ /* Release update/blit shaders. */
+ this->get_texture_utils().cleanup();
+
+ /* Release Sampler States. */
+ for (int i = 0; i < GPU_SAMPLER_MAX; i++) {
+ if (sampler_state_cache_[i] != nil) {
+ [sampler_state_cache_[i] release];
+ sampler_state_cache_[i] = nil;
+ }
+ }
+}
+
+void MTLContext::begin_frame()
+{
+ BLI_assert(MTLBackend::get()->is_inside_render_boundary());
+ if (is_inside_frame_) {
+ return;
+ }
+
+ /* Begin Command buffer for next frame. */
+ is_inside_frame_ = true;
+}
+
+void MTLContext::end_frame()
+{
+ BLI_assert(is_inside_frame_);
+
+ /* Ensure pre-present work is commited. */
+ this->flush();
+
+ /* Increment frame counter. */
+ is_inside_frame_ = false;
}
void MTLContext::check_error(const char *info)
@@ -90,26 +161,83 @@ void MTLContext::memory_statistics_get(int *total_mem, int *free_mem)
*free_mem = 0;
}
-id<MTLCommandBuffer> MTLContext::get_active_command_buffer()
+void MTLContext::framebuffer_bind(MTLFrameBuffer *framebuffer)
{
- /* TODO(Metal): Implement. */
- return nil;
+ /* We do not yet begin the pass -- We defer beginning the pass until a draw is requested. */
+ BLI_assert(framebuffer);
+ this->active_fb = framebuffer;
}
-/* Render Pass State and Management */
-void MTLContext::begin_render_pass()
+void MTLContext::framebuffer_restore()
{
- /* TODO(Metal): Implement. */
+ /* Bind default framebuffer from context --
+ * We defer beginning the pass until a draw is requested. */
+ this->active_fb = this->back_left;
}
-void MTLContext::end_render_pass()
+
+id<MTLRenderCommandEncoder> MTLContext::ensure_begin_render_pass()
{
- /* TODO(Metal): Implement. */
+ BLI_assert(this);
+
+ /* Ensure the rendering frame has started. */
+ if (!is_inside_frame_) {
+ this->begin_frame();
+ }
+
+ /* Check whether a framebuffer is bound. */
+ if (!this->active_fb) {
+ BLI_assert(false && "No framebuffer is bound!");
+ return this->main_command_buffer.get_active_render_command_encoder();
+ }
+
+ /* Ensure command buffer workload submissions are optimal --
+ * Though do not split a batch mid-IMM recording */
+ /* TODO(Metal): Add IMM Check once MTLImmediate has been implemented. */
+ if (this->main_command_buffer.do_break_submission()/*&&
+ !((MTLImmediate *)(this->imm))->imm_is_recording()*/) {
+ this->flush();
+ }
+
+ /* Begin pass or perform a pass switch if the active framebuffer has been changed, or if the
+ * framebuffer state has been modified (is_dirty). */
+ if (!this->main_command_buffer.is_inside_render_pass() ||
+ this->active_fb != this->main_command_buffer.get_active_framebuffer() ||
+ this->main_command_buffer.get_active_framebuffer()->get_dirty()) {
+
+ /* Validate bound framebuffer before beginning render pass. */
+ if (!static_cast<MTLFrameBuffer *>(this->active_fb)->validate_render_pass()) {
+ MTL_LOG_WARNING("Framebuffer validation failed, falling back to default framebuffer\n");
+ this->framebuffer_restore();
+
+ if (!static_cast<MTLFrameBuffer *>(this->active_fb)->validate_render_pass()) {
+ MTL_LOG_ERROR("CRITICAL: DEFAULT FRAMEBUFFER FAIL VALIDATION!!\n");
+ }
+ }
+
+ /* Begin RenderCommandEncoder on main CommandBuffer. */
+ bool new_render_pass = false;
+ id<MTLRenderCommandEncoder> new_enc =
+ this->main_command_buffer.ensure_begin_render_command_encoder(
+ static_cast<MTLFrameBuffer *>(this->active_fb), true, &new_render_pass);
+ if (new_render_pass) {
+ /* Flag context pipeline state as dirty - dynamic pipeline state need re-applying. */
+ this->pipeline_state.dirty_flags = MTL_PIPELINE_STATE_ALL_FLAG;
+ }
+ return new_enc;
+ }
+ BLI_assert(!this->main_command_buffer.get_active_framebuffer()->get_dirty());
+ return this->main_command_buffer.get_active_render_command_encoder();
}
-bool MTLContext::is_render_pass_active()
+MTLFrameBuffer *MTLContext::get_current_framebuffer()
{
- /* TODO(Metal): Implement. */
- return false;
+ MTLFrameBuffer *last_bound = static_cast<MTLFrameBuffer *>(this->active_fb);
+ return last_bound ? last_bound : this->get_default_framebuffer();
+}
+
+MTLFrameBuffer *MTLContext::get_default_framebuffer()
+{
+ return static_cast<MTLFrameBuffer *>(this->back_left);
}
/** \} */
@@ -200,13 +328,68 @@ void MTLContext::pipeline_state_init()
MTLStencilOperationKeep;
}
+void MTLContext::set_viewport(int origin_x, int origin_y, int width, int height)
+{
+ BLI_assert(this);
+ BLI_assert(width > 0);
+ BLI_assert(height > 0);
+ BLI_assert(origin_x >= 0);
+ BLI_assert(origin_y >= 0);
+ bool changed = (this->pipeline_state.viewport_offset_x != origin_x) ||
+ (this->pipeline_state.viewport_offset_y != origin_y) ||
+ (this->pipeline_state.viewport_width != width) ||
+ (this->pipeline_state.viewport_height != height);
+ this->pipeline_state.viewport_offset_x = origin_x;
+ this->pipeline_state.viewport_offset_y = origin_y;
+ this->pipeline_state.viewport_width = width;
+ this->pipeline_state.viewport_height = height;
+ if (changed) {
+ this->pipeline_state.dirty_flags = (this->pipeline_state.dirty_flags |
+ MTL_PIPELINE_STATE_VIEWPORT_FLAG);
+ }
+}
+
+void MTLContext::set_scissor(int scissor_x, int scissor_y, int scissor_width, int scissor_height)
+{
+ BLI_assert(this);
+ bool changed = (this->pipeline_state.scissor_x != scissor_x) ||
+ (this->pipeline_state.scissor_y != scissor_y) ||
+ (this->pipeline_state.scissor_width != scissor_width) ||
+ (this->pipeline_state.scissor_height != scissor_height) ||
+ (this->pipeline_state.scissor_enabled != true);
+ this->pipeline_state.scissor_x = scissor_x;
+ this->pipeline_state.scissor_y = scissor_y;
+ this->pipeline_state.scissor_width = scissor_width;
+ this->pipeline_state.scissor_height = scissor_height;
+ this->pipeline_state.scissor_enabled = (scissor_width > 0 && scissor_height > 0);
+
+ if (changed) {
+ this->pipeline_state.dirty_flags = (this->pipeline_state.dirty_flags |
+ MTL_PIPELINE_STATE_SCISSOR_FLAG);
+ }
+}
+
+void MTLContext::set_scissor_enabled(bool scissor_enabled)
+{
+ /* Only turn on Scissor if requested scissor region is valid */
+ scissor_enabled = scissor_enabled && (this->pipeline_state.scissor_width > 0 &&
+ this->pipeline_state.scissor_height > 0);
+
+ bool changed = (this->pipeline_state.scissor_enabled != scissor_enabled);
+ this->pipeline_state.scissor_enabled = scissor_enabled;
+ if (changed) {
+ this->pipeline_state.dirty_flags = (this->pipeline_state.dirty_flags |
+ MTL_PIPELINE_STATE_SCISSOR_FLAG);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
/** \name Texture State Management
* \{ */
-void MTLContext::texture_bind(gpu::MTLTexture *mtl_texture, unsigned int texture_unit)
+void MTLContext::texture_bind(gpu::MTLTexture *mtl_texture, uint texture_unit)
{
BLI_assert(this);
BLI_assert(mtl_texture);
@@ -226,7 +409,7 @@ void MTLContext::texture_bind(gpu::MTLTexture *mtl_texture, unsigned int texture
mtl_texture->is_bound_ = true;
}
-void MTLContext::sampler_bind(MTLSamplerState sampler_state, unsigned int sampler_unit)
+void MTLContext::sampler_bind(MTLSamplerState sampler_state, uint sampler_unit)
{
BLI_assert(this);
if (sampler_unit < 0 || sampler_unit >= GPU_max_textures() ||
@@ -271,14 +454,14 @@ void MTLContext::texture_unbind_all()
id<MTLSamplerState> MTLContext::get_sampler_from_state(MTLSamplerState sampler_state)
{
- BLI_assert((unsigned int)sampler_state >= 0 && ((unsigned int)sampler_state) < GPU_SAMPLER_MAX);
- return this->sampler_state_cache_[(unsigned int)sampler_state];
+ BLI_assert((uint)sampler_state >= 0 && ((uint)sampler_state) < GPU_SAMPLER_MAX);
+ return sampler_state_cache_[(uint)sampler_state];
}
id<MTLSamplerState> MTLContext::generate_sampler_from_state(MTLSamplerState sampler_state)
{
/* Check if sampler already exists for given state. */
- id<MTLSamplerState> st = this->sampler_state_cache_[(unsigned int)sampler_state];
+ id<MTLSamplerState> st = sampler_state_cache_[(uint)sampler_state];
if (st != nil) {
return st;
}
@@ -318,7 +501,7 @@ id<MTLSamplerState> MTLContext::generate_sampler_from_state(MTLSamplerState samp
descriptor.supportArgumentBuffers = true;
id<MTLSamplerState> state = [this->device newSamplerStateWithDescriptor:descriptor];
- this->sampler_state_cache_[(unsigned int)sampler_state] = state;
+ sampler_state_cache_[(uint)sampler_state] = state;
BLI_assert(state != nil);
[descriptor autorelease];
@@ -328,10 +511,10 @@ id<MTLSamplerState> MTLContext::generate_sampler_from_state(MTLSamplerState samp
id<MTLSamplerState> MTLContext::get_default_sampler_state()
{
- if (this->default_sampler_state_ == nil) {
- this->default_sampler_state_ = this->get_sampler_from_state(DEFAULT_SAMPLER_STATE);
+ if (default_sampler_state_ == nil) {
+ default_sampler_state_ = this->get_sampler_from_state(DEFAULT_SAMPLER_STATE);
}
- return this->default_sampler_state_;
+ return default_sampler_state_;
}
/** \} */