diff options
Diffstat (limited to 'drivers/metal/metal_objects.mm')
-rw-r--r-- | drivers/metal/metal_objects.mm | 172 |
1 files changed, 124 insertions, 48 deletions
diff --git a/drivers/metal/metal_objects.mm b/drivers/metal/metal_objects.mm index 563f3692e4..e213c586e1 100644 --- a/drivers/metal/metal_objects.mm +++ b/drivers/metal/metal_objects.mm @@ -98,6 +98,9 @@ void MDCommandBuffer::bind_pipeline(RDD::PipelineID p_pipeline) { MDRenderPipeline *rp = (MDRenderPipeline *)p; if (render.encoder == nil) { + // This error would happen if the render pass failed. + ERR_FAIL_NULL_MSG(render.desc, "Render pass descriptor is null."); + // This condition occurs when there are no attachments when calling render_next_subpass() // and is due to the SUPPORTS_FRAGMENT_SHADER_WITH_ONLY_SIDE_EFFECTS flag. render.desc.defaultRasterSampleCount = static_cast<NSUInteger>(rp->sample_count); @@ -225,8 +228,9 @@ void MDCommandBuffer::render_bind_uniform_set(RDD::UniformSetID p_uniform_set, R void MDCommandBuffer::render_clear_attachments(VectorView<RDD::AttachmentClear> p_attachment_clears, VectorView<Rect2i> p_rects) { DEV_ASSERT(type == MDCommandBufferStateType::Render); - uint32_t vertex_count = p_rects.size() * 6; + const MDSubpass &subpass = render.get_subpass(); + uint32_t vertex_count = p_rects.size() * 6 * subpass.view_count; simd::float4 vertices[vertex_count]; simd::float4 clear_colors[ClearAttKey::ATTACHMENT_COUNT]; @@ -237,6 +241,9 @@ void MDCommandBuffer::render_clear_attachments(VectorView<RDD::AttachmentClear> ClearAttKey key; key.sample_count = render.pass->get_sample_count(); + if (subpass.view_count > 1) { + key.enable_layered_rendering(); + } float depth_value = 0; uint32_t stencil_value = 0; @@ -247,7 +254,7 @@ void MDCommandBuffer::render_clear_attachments(VectorView<RDD::AttachmentClear> if (attClear.aspect.has_flag(RDD::TEXTURE_ASPECT_COLOR_BIT)) { attachment_index = attClear.color_attachment; } else { - attachment_index = render.pass->subpasses[render.current_subpass].depth_stencil_reference.attachment; + attachment_index = subpass.depth_stencil_reference.attachment; } MDAttachment const &mda = render.pass->attachments[attachment_index]; @@ -312,6 +319,13 @@ void MDCommandBuffer::render_clear_attachments(VectorView<RDD::AttachmentClear> void MDCommandBuffer::_render_set_dirty_state() { _render_bind_uniform_sets(); + MDSubpass const &subpass = render.get_subpass(); + if (subpass.view_count > 1) { + uint32_t view_range[2] = { 0, subpass.view_count }; + [render.encoder setVertexBytes:view_range length:sizeof(view_range) atIndex:VIEW_MASK_BUFFER_INDEX]; + [render.encoder setFragmentBytes:view_range length:sizeof(view_range) atIndex:VIEW_MASK_BUFFER_INDEX]; + } + if (render.dirty.has_flag(RenderState::DIRTY_PIPELINE)) { [render.encoder setRenderPipelineState:render.pipeline->state]; } @@ -494,36 +508,40 @@ uint32_t MDCommandBuffer::_populate_vertices(simd::float4 *p_vertices, uint32_t simd::float4 vtx; uint32_t idx = p_index; - vtx.z = 0.0; - vtx.w = (float)1; + uint32_t endLayer = render.get_subpass().view_count; + + for (uint32_t layer = 0; layer < endLayer; layer++) { + vtx.z = 0.0; + vtx.w = (float)layer; - // Top left vertex - First triangle. - vtx.y = topPos; - vtx.x = leftPos; - p_vertices[idx++] = vtx; + // Top left vertex - First triangle. + vtx.y = topPos; + vtx.x = leftPos; + p_vertices[idx++] = vtx; - // Bottom left vertex. - vtx.y = bottomPos; - vtx.x = leftPos; - p_vertices[idx++] = vtx; + // Bottom left vertex. + vtx.y = bottomPos; + vtx.x = leftPos; + p_vertices[idx++] = vtx; - // Bottom right vertex. - vtx.y = bottomPos; - vtx.x = rightPos; - p_vertices[idx++] = vtx; + // Bottom right vertex. + vtx.y = bottomPos; + vtx.x = rightPos; + p_vertices[idx++] = vtx; - // Bottom right vertex - Second triangle. - p_vertices[idx++] = vtx; + // Bottom right vertex - Second triangle. + p_vertices[idx++] = vtx; - // Top right vertex. - vtx.y = topPos; - vtx.x = rightPos; - p_vertices[idx++] = vtx; + // Top right vertex. + vtx.y = topPos; + vtx.x = rightPos; + p_vertices[idx++] = vtx; - // Top left vertex. - vtx.y = topPos; - vtx.x = leftPos; - p_vertices[idx++] = vtx; + // Top left vertex. + vtx.y = topPos; + vtx.x = leftPos; + p_vertices[idx++] = vtx; + } return idx; } @@ -550,8 +568,7 @@ void MDCommandBuffer::render_begin_pass(RDD::RenderPassID p_render_pass, RDD::Fr void MDCommandBuffer::_end_render_pass() { MDFrameBuffer const &fb_info = *render.frameBuffer; - MDRenderPass const &pass_info = *render.pass; - MDSubpass const &subpass = pass_info.subpasses[render.current_subpass]; + MDSubpass const &subpass = render.get_subpass(); PixelFormats &pf = device_driver->get_pixel_formats(); @@ -559,11 +576,11 @@ void MDCommandBuffer::_end_render_pass() { uint32_t color_index = subpass.color_references[i].attachment; uint32_t resolve_index = subpass.resolve_references[i].attachment; DEV_ASSERT((color_index == RDD::AttachmentReference::UNUSED) == (resolve_index == RDD::AttachmentReference::UNUSED)); - if (color_index == RDD::AttachmentReference::UNUSED || !fb_info.textures[color_index]) { + if (color_index == RDD::AttachmentReference::UNUSED || !fb_info.has_texture(color_index)) { continue; } - id<MTLTexture> resolve_tex = fb_info.textures[resolve_index]; + id<MTLTexture> resolve_tex = fb_info.get_texture(resolve_index); CRASH_COND_MSG(!flags::all(pf.getCapabilities(resolve_tex.pixelFormat), kMTLFmtCapsResolve), "not implemented: unresolvable texture types"); // see: https://github.com/KhronosGroup/MoltenVK/blob/d20d13fe2735adb845636a81522df1b9d89c0fba/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm#L407 @@ -574,7 +591,7 @@ void MDCommandBuffer::_end_render_pass() { void MDCommandBuffer::_render_clear_render_area() { MDRenderPass const &pass = *render.pass; - MDSubpass const &subpass = pass.subpasses[render.current_subpass]; + MDSubpass const &subpass = render.get_subpass(); // First determine attachments that should be cleared. LocalVector<RDD::AttachmentClear> clears; @@ -621,9 +638,14 @@ void MDCommandBuffer::render_next_subpass() { MDFrameBuffer const &fb = *render.frameBuffer; MDRenderPass const &pass = *render.pass; - MDSubpass const &subpass = pass.subpasses[render.current_subpass]; + MDSubpass const &subpass = render.get_subpass(); MTLRenderPassDescriptor *desc = MTLRenderPassDescriptor.renderPassDescriptor; + + if (subpass.view_count > 1) { + desc.renderTargetArrayLength = subpass.view_count; + } + PixelFormats &pf = device_driver->get_pixel_formats(); uint32_t attachmentCount = 0; @@ -640,7 +662,7 @@ void MDCommandBuffer::render_next_subpass() { bool has_resolve = resolveIdx != RDD::AttachmentReference::UNUSED; bool can_resolve = true; if (resolveIdx != RDD::AttachmentReference::UNUSED) { - id<MTLTexture> resolve_tex = fb.textures[resolveIdx]; + id<MTLTexture> resolve_tex = fb.get_texture(resolveIdx); can_resolve = flags::all(pf.getCapabilities(resolve_tex.pixelFormat), kMTLFmtCapsResolve); if (can_resolve) { ca.resolveTexture = resolve_tex; @@ -651,7 +673,9 @@ void MDCommandBuffer::render_next_subpass() { MDAttachment const &attachment = pass.attachments[idx]; - id<MTLTexture> tex = fb.textures[idx]; + id<MTLTexture> tex = fb.get_texture(idx); + ERR_FAIL_NULL_MSG(tex, "Frame buffer color texture is null."); + if ((attachment.type & MDAttachmentType::Color)) { if (attachment.configureDescriptor(ca, pf, subpass, tex, render.is_rendering_entire_area, has_resolve, can_resolve, false)) { Color clearColor = render.clear_values[idx].color; @@ -664,7 +688,8 @@ void MDCommandBuffer::render_next_subpass() { attachmentCount += 1; uint32_t idx = subpass.depth_stencil_reference.attachment; MDAttachment const &attachment = pass.attachments[idx]; - id<MTLTexture> tex = fb.textures[idx]; + id<MTLTexture> tex = fb.get_texture(idx); + ERR_FAIL_NULL_MSG(tex, "Frame buffer depth / stencil texture is null."); if (attachment.type & MDAttachmentType::Depth) { MTLRenderPassDepthAttachmentDescriptor *da = desc.depthAttachment; if (attachment.configureDescriptor(da, pf, subpass, tex, render.is_rendering_entire_area, false, false, false)) { @@ -704,8 +729,15 @@ void MDCommandBuffer::render_draw(uint32_t p_vertex_count, uint32_t p_base_vertex, uint32_t p_first_instance) { DEV_ASSERT(type == MDCommandBufferStateType::Render); + ERR_FAIL_NULL_MSG(render.pipeline, "No pipeline set for render command buffer."); + _render_set_dirty_state(); + MDSubpass const &subpass = render.get_subpass(); + if (subpass.view_count > 1) { + p_instance_count *= subpass.view_count; + } + DEV_ASSERT(render.dirty == 0); id<MTLRenderCommandEncoder> enc = render.encoder; @@ -753,8 +785,15 @@ void MDCommandBuffer::render_draw_indexed(uint32_t p_index_count, int32_t p_vertex_offset, uint32_t p_first_instance) { DEV_ASSERT(type == MDCommandBufferStateType::Render); + ERR_FAIL_NULL_MSG(render.pipeline, "No pipeline set for render command buffer."); + _render_set_dirty_state(); + MDSubpass const &subpass = render.get_subpass(); + if (subpass.view_count > 1) { + p_instance_count *= subpass.view_count; + } + id<MTLRenderCommandEncoder> enc = render.encoder; uint32_t index_offset = render.index_offset; @@ -772,6 +811,8 @@ void MDCommandBuffer::render_draw_indexed(uint32_t p_index_count, void MDCommandBuffer::render_draw_indexed_indirect(RDD::BufferID p_indirect_buffer, uint64_t p_offset, uint32_t p_draw_count, uint32_t p_stride) { DEV_ASSERT(type == MDCommandBufferStateType::Render); + ERR_FAIL_NULL_MSG(render.pipeline, "No pipeline set for render command buffer."); + _render_set_dirty_state(); id<MTLRenderCommandEncoder> enc = render.encoder; @@ -796,6 +837,8 @@ void MDCommandBuffer::render_draw_indexed_indirect_count(RDD::BufferID p_indirec void MDCommandBuffer::render_draw_indirect(RDD::BufferID p_indirect_buffer, uint64_t p_offset, uint32_t p_draw_count, uint32_t p_stride) { DEV_ASSERT(type == MDCommandBufferStateType::Render); + ERR_FAIL_NULL_MSG(render.pipeline, "No pipeline set for render command buffer."); + _render_set_dirty_state(); id<MTLRenderCommandEncoder> enc = render.encoder; @@ -815,6 +858,42 @@ void MDCommandBuffer::render_draw_indirect_count(RDD::BufferID p_indirect_buffer ERR_FAIL_MSG("not implemented"); } +void MDCommandBuffer::render_end_pass() { + DEV_ASSERT(type == MDCommandBufferStateType::Render); + + render.end_encoding(); + render.reset(); + type = MDCommandBufferStateType::None; +} + +#pragma mark - RenderState + +void MDCommandBuffer::RenderState::reset() { + pass = nil; + frameBuffer = nil; + pipeline = nil; + current_subpass = UINT32_MAX; + render_area = {}; + is_rendering_entire_area = false; + desc = nil; + encoder = nil; + index_buffer = nil; + index_type = MTLIndexTypeUInt16; + dirty = DIRTY_NONE; + uniform_sets.clear(); + uniform_set_mask = 0; + clear_values.clear(); + viewports.clear(); + scissors.clear(); + blend_constants.reset(); + vertex_buffers.clear(); + vertex_offsets.clear(); + // Keep the keys, as they are likely to be used again. + for (KeyValue<StageResourceUsage, LocalVector<__unsafe_unretained id<MTLResource>>> &kv : resource_usage) { + kv.value.clear(); + } +} + void MDCommandBuffer::RenderState::end_encoding() { if (encoder == nil) { return; @@ -844,6 +923,8 @@ void MDCommandBuffer::RenderState::end_encoding() { encoder = nil; } +#pragma mark - ComputeState + void MDCommandBuffer::ComputeState::end_encoding() { if (encoder == nil) { return; @@ -864,14 +945,6 @@ void MDCommandBuffer::ComputeState::end_encoding() { encoder = nil; } -void MDCommandBuffer::render_end_pass() { - DEV_ASSERT(type == MDCommandBufferStateType::Render); - - render.end_encoding(); - render.reset(); - type = MDCommandBufferStateType::None; -} - #pragma mark - Compute void MDCommandBuffer::compute_bind_uniform_set(RDD::UniformSetID p_uniform_set, RDD::ShaderID p_shader, uint32_t p_set_index) { @@ -945,8 +1018,11 @@ void MDComputeShader::encode_push_constant_data(VectorView<uint32_t> p_data, MDC [enc setBytes:ptr length:length atIndex:push_constants.binding]; } -MDRenderShader::MDRenderShader(CharString p_name, Vector<UniformSet> p_sets, MDLibrary *_Nonnull p_vert, MDLibrary *_Nonnull p_frag) : - MDShader(p_name, p_sets), vert(p_vert), frag(p_frag) { +MDRenderShader::MDRenderShader(CharString p_name, + bool p_needs_view_mask_buffer, + Vector<UniformSet> p_sets, + MDLibrary *_Nonnull p_vert, MDLibrary *_Nonnull p_frag) : + MDShader(p_name, p_sets), needs_view_mask_buffer(p_needs_view_mask_buffer), vert(p_vert), frag(p_frag) { } void MDRenderShader::encode_push_constant_data(VectorView<uint32_t> p_data, MDCommandBuffer *p_cb) { @@ -1281,7 +1357,7 @@ typedef struct { typedef struct { float4 v_position [[position]]; - uint layer; + uint layer%s; } VaryingsPos; vertex VaryingsPos vertClear(AttributesPos attributes [[stage_in]], constant ClearColorsIn& ccIn [[buffer(0)]]) { @@ -1290,7 +1366,7 @@ vertex VaryingsPos vertClear(AttributesPos attributes [[stage_in]], constant Cle varyings.layer = uint(attributes.a_position.w); return varyings; } -)", ClearAttKey::DEPTH_INDEX]; +)", p_key.is_layered_rendering_enabled() ? " [[render_target_array_index]]" : "", ClearAttKey::DEPTH_INDEX]; return new_func(msl, @"vertClear", nil); } @@ -1580,7 +1656,7 @@ void ShaderCacheEntry::notify_free() const { self->_library = library; self->_error = error; if (error) { - ERR_PRINT(String(U"Error compiling shader %s: %s").format(entry->name.get_data(), error.localizedDescription.UTF8String)); + ERR_PRINT(vformat(U"Error compiling shader %s: %s", entry->name.get_data(), error.localizedDescription.UTF8String)); } { |