| // Copyright 2021 The IREE Authors | |
| // | |
| // Licensed under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| #include "experimental/webgpu/buffer.h" | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <string.h> | |
| #include "experimental/webgpu/webgpu_device.h" | |
| #include "iree/base/api.h" | |
| #include "iree/hal/buffer_transfer.h" | |
| // TODO(benvanik): decouple via injection. | |
| #include "experimental/webgpu/simple_allocator.h" | |
| typedef struct iree_hal_webgpu_buffer_t { | |
| iree_hal_buffer_t base; | |
| iree_hal_device_t* device; // unowned | |
| WGPUBuffer handle; | |
| bool is_mapped; | |
| } iree_hal_webgpu_buffer_t; | |
| extern const iree_hal_buffer_vtable_t iree_hal_webgpu_buffer_vtable; | |
| static iree_hal_webgpu_buffer_t* iree_hal_webgpu_buffer_cast( | |
| iree_hal_buffer_t* base_value) { | |
| IREE_HAL_ASSERT_TYPE(base_value, &iree_hal_webgpu_buffer_vtable); | |
| return (iree_hal_webgpu_buffer_t*)base_value; | |
| } | |
| iree_status_t iree_hal_webgpu_buffer_wrap( | |
| iree_hal_device_t* device, iree_hal_allocator_t* device_allocator, | |
| iree_hal_memory_type_t memory_type, iree_hal_memory_access_t allowed_access, | |
| iree_hal_buffer_usage_t allowed_usage, iree_device_size_t allocation_size, | |
| iree_device_size_t byte_offset, iree_device_size_t byte_length, | |
| WGPUBuffer handle, iree_allocator_t host_allocator, | |
| iree_hal_buffer_t** out_buffer) { | |
| IREE_ASSERT_ARGUMENT(device); | |
| IREE_ASSERT_ARGUMENT(device_allocator); | |
| IREE_ASSERT_ARGUMENT(handle); | |
| IREE_ASSERT_ARGUMENT(out_buffer); | |
| *out_buffer = NULL; | |
| IREE_TRACE_ZONE_BEGIN(z0); | |
| iree_hal_webgpu_buffer_t* buffer = NULL; | |
| iree_status_t status = | |
| iree_allocator_malloc(host_allocator, sizeof(*buffer), (void**)&buffer); | |
| if (iree_status_is_ok(status)) { | |
| iree_hal_buffer_initialize(host_allocator, device_allocator, &buffer->base, | |
| allocation_size, byte_offset, byte_length, | |
| memory_type, allowed_access, allowed_usage, | |
| &iree_hal_webgpu_buffer_vtable, &buffer->base); | |
| buffer->device = device; | |
| buffer->handle = handle; | |
| *out_buffer = &buffer->base; | |
| } | |
| IREE_TRACE_ZONE_END(z0); | |
| return status; | |
| } | |
| static void iree_hal_webgpu_buffer_destroy(iree_hal_buffer_t* base_buffer) { | |
| iree_hal_webgpu_buffer_t* buffer = iree_hal_webgpu_buffer_cast(base_buffer); | |
| iree_allocator_t host_allocator = base_buffer->host_allocator; | |
| IREE_TRACE_ZONE_BEGIN(z0); | |
| if (buffer->is_mapped) { | |
| wgpuBufferUnmap(buffer->handle); | |
| } | |
| // NOTE: this immediately destroys the buffer (in theory) and it must not be | |
| // in use. That's ok because we also have that requirement in the HAL. | |
| wgpuBufferDestroy(buffer->handle); | |
| iree_allocator_free(host_allocator, buffer); | |
| IREE_TRACE_ZONE_END(z0); | |
| } | |
| WGPUBuffer iree_hal_webgpu_buffer_handle(const iree_hal_buffer_t* base_buffer) { | |
| iree_hal_buffer_t* allocated_buffer = | |
| iree_hal_buffer_allocated_buffer(base_buffer); | |
| iree_hal_webgpu_buffer_t* buffer = | |
| iree_hal_webgpu_buffer_cast((iree_hal_buffer_t*)allocated_buffer); | |
| IREE_ASSERT_ARGUMENT(buffer); | |
| return buffer->handle; | |
| } | |
| static iree_status_t iree_hal_webgpu_buffer_map_range( | |
| iree_hal_buffer_t* base_buffer, iree_hal_mapping_mode_t mapping_mode, | |
| iree_hal_memory_access_t memory_access, | |
| iree_device_size_t local_byte_offset, iree_device_size_t local_byte_length, | |
| iree_hal_buffer_mapping_t* mapping) { | |
| // WebGPU does not allow for synchronous buffer mapping. | |
| // Use wgpuBufferMapAsync directly to avoid this emulation. | |
| iree_hal_webgpu_buffer_t* buffer = iree_hal_webgpu_buffer_cast(base_buffer); | |
| return iree_hal_buffer_emulated_map_range( | |
| buffer->device, base_buffer, mapping_mode, memory_access, | |
| local_byte_offset, local_byte_length, mapping); | |
| } | |
| static iree_status_t iree_hal_webgpu_buffer_unmap_range( | |
| iree_hal_buffer_t* base_buffer, iree_device_size_t local_byte_offset, | |
| iree_device_size_t local_byte_length, iree_hal_buffer_mapping_t* mapping) { | |
| // WebGPU does not allow for synchronous buffer mapping. | |
| // Use wgpuBufferMapAsync directly to avoid this emulation. | |
| iree_hal_webgpu_buffer_t* buffer = iree_hal_webgpu_buffer_cast(base_buffer); | |
| return iree_hal_buffer_emulated_unmap_range(buffer->device, base_buffer, | |
| local_byte_offset, | |
| local_byte_length, mapping); | |
| } | |
| static iree_status_t iree_hal_webgpu_buffer_invalidate_range( | |
| iree_hal_buffer_t* base_buffer, iree_device_size_t local_byte_offset, | |
| iree_device_size_t local_byte_length) { | |
| // Nothing to do. | |
| return iree_ok_status(); | |
| } | |
| static iree_status_t iree_hal_webgpu_buffer_flush_range( | |
| iree_hal_buffer_t* base_buffer, iree_device_size_t local_byte_offset, | |
| iree_device_size_t local_byte_length) { | |
| // Nothing to do. | |
| return iree_ok_status(); | |
| } | |
| const iree_hal_buffer_vtable_t iree_hal_webgpu_buffer_vtable = { | |
| .destroy = iree_hal_webgpu_buffer_destroy, | |
| .map_range = iree_hal_webgpu_buffer_map_range, | |
| .unmap_range = iree_hal_webgpu_buffer_unmap_range, | |
| .invalidate_range = iree_hal_webgpu_buffer_invalidate_range, | |
| .flush_range = iree_hal_webgpu_buffer_flush_range, | |
| }; |