Repository: google/filament
File: filament/backend/src/metal/MetalHandles.mm (Objective-C++)

Code before:
                    [encoder setSamplerState:sampler atIndex:binding.binding * 2 + 1];
                    continue;
                }

                auto const& textureBinding = textures[binding.binding];
                [encoder setTexture:textureBinding.texture atIndex:binding.binding * 2];
                SamplerState samplerState { .samplerParams = textureBinding.sampler };
                id<MTLSamplerState> sampler =
                        driver->mContext->samplerStateCache.getOrCreateState(samplerState);
                [encoder setSamplerState:sampler atIndex:binding.binding * 2 + 1];
                break;
            }
            case DescriptorType::INPUT_ATTACHMENT:
                assert_invariant(false);
                break;
        }
    }

    return buffer.get();
}

MetalMemoryMappedBuffer::MetalMemoryMappedBuffer(HandleAllocatorMTL& handleAllocator, BufferObjectHandle boh, size_t offset, size_t size,
    MapBufferAccessFlags access) noexcept : boh(boh), access(access) {
    MetalBufferObject* bo = handleAllocator.handle_cast<MetalBufferObject*>(boh);
    MetalBuffer* buffer = bo->getBuffer();
    id<MTLBuffer> mtlBuffer = buffer->getGpuBufferForDraw();

    assert_invariant(bo);
    assert_invariant(offset + size <= bo->byteCount);
    assert_invariant(mtlBuffer.storageMode != MTLStorageModePrivate);

    mtl.vaddr = static_cast<char*>(mtlBuffer.contents) + offset;
    mtl.size = size;
    mtl.offset = offset;
}

MetalMemoryMappedBuffer::~MetalMemoryMappedBuffer() = default;

void MetalMemoryMappedBuffer::unmap(HandleAllocatorMTL& handleAllocator) {
#if !defined(FILAMENT_IOS) && defined(__x86_64__)
    // Managed memory requires didModifyRange to synchronize changes to the GPU. This is specific to Intel Macs.
    MetalBufferObject* const bo = handleAllocator.handle_cast<MetalBufferObject*>(boh);
    assert_invariant(bo);
    MetalBuffer* buffer = bo->getBuffer();
    id<MTLBuffer> mtlBuffer = buffer->getGpuBufferForDraw();
    if (mtlBuffer && mtlBuffer.storageMode == MTLStorageModeManaged) {
        [mtlBuffer didModifyRange:NSMakeRange(mtl.offset, mtl.size)];
    }
#endif
    // Shared memory on UMA systems is coherent; no explicit synchronization is required.
}

Review comment (suggestion):
Technically `getGpuBufferForDraw` can return `nil`, though I think `mCpuBuffer` is never used anymore (see the commented-out code [here in MetalBuffer.mm](https://github.com/google/filament/blob/main/filament/backend/src/metal/MetalBuffer.mm#L50)) and can be safely removed. Do you mind cleaning that up? That way we can be guaranteed that `mtlBuffer` is non-nil here.

Code after:
                    [encoder setSamplerState:sampler atIndex:binding.binding * 2 + 1];
                    continue;
                }

                auto const& textureBinding = textures[binding.binding];
                [encoder setTexture:textureBinding.texture atIndex:binding.binding * 2];
                SamplerState samplerState { .samplerParams = textureBinding.sampler };
                id<MTLSamplerState> sampler =
                        driver->mContext->samplerStateCache.getOrCreateState(samplerState);
                [encoder setSamplerState:sampler atIndex:binding.binding * 2 + 1];
                break;
            }
            case DescriptorType::INPUT_ATTACHMENT:
                assert_invariant(false);
                break;
        }
    }

    return buffer.get();
}

MetalMemoryMappedBuffer::MetalMemoryMappedBuffer(MetalBufferObject* bo, size_t offset, size_t size,
    MapBufferAccessFlags access) noexcept : access(access) {
    MetalBuffer* buffer = bo->getBuffer();
    assert_invariant(buffer);
    id<MTLBuffer> mtlBuffer = buffer->getGpuBufferForDraw();

    assert_invariant(offset + size <= bo->byteCount);
    assert_invariant(mtlBuffer.storageMode != MTLStorageModePrivate);

    mtl.bo = bo;
    mtl.vaddr = static_cast<char*>(mtlBuffer.contents) + offset;
    mtl.size = size;
    mtl.offset = offset;
}

MetalMemoryMappedBuffer::~MetalMemoryMappedBuffer() = default;

void MetalMemoryMappedBuffer::unmap() {
#if !defined(FILAMENT_IOS) && defined(__x86_64__)
    // Managed memory requires didModifyRange to synchronize changes to the GPU. This is specific to Intel Macs.
    MetalBuffer* buffer = bo->getBuffer();
    id<MTLBuffer> mtlBuffer = buffer->getGpuBufferForDraw();
    if (mtlBuffer && mtlBuffer.storageMode == MTLStorageModeManaged) {
        [mtlBuffer didModifyRange:NSMakeRange(mtl.offset, mtl.size)];
    }
#endif
    // Shared memory on UMA systems is coherent; no explicit synchronization is required.
}

void MetalMemoryMappedBuffer::copy(MetalDriver& mtld, size_t offset, BufferDescriptor&& data) const {