buffer.cpp

cross platform rendering playground

src/backend/metal/buffer.cpp

2.89 KB
#include <math.h>
#ifndef INFINITY
#define INFINITY __builtin_huge_valf()
#endif
#include <Foundation/Foundation.hpp>
#include <Metal/Metal.hpp>

#include "backend/metal/mt_api.h"
#include "core/logger.h"

namespace rhi {

bool create_buffer(Device &device, rhi::BufferDesc &desc, Buffer &buffer) {
    MTL::StorageMode storage = MTL::StorageModePrivate;
    if (desc.memory == rhi::BufferMemType::Upload || desc.memory == rhi::BufferMemType::Readback) {
        storage = MTL::StorageModeShared;
    }
    MTL::Buffer *handle = device.handle->newBuffer(desc.size, storage);
    if (!handle) {
        VEL_ERROR("Failed to create Metal buffer ({} bytes)", desc.size);
        return false;
    }

    buffer.desc = desc;
    buffer.handle = handle;
    if (!desc.name.empty()) {
        handle->setLabel(NS::String::string(desc.name.c_str(), NS::UTF8StringEncoding));
    }
    buffer.address = handle->gpuAddress();
    buffer.mapped = (storage == MTL::StorageModeShared) ? handle->contents() : nullptr;
    mt::reside(device, handle);
    return true;
}

void destroy_buffer(Device &device, Buffer &buffer) {
    if (buffer.handle) {
        mt::unreside(device, buffer.handle);
        buffer.handle->release();
        buffer.handle = nullptr;
    }
    buffer.address = 0;
    buffer.mapped = nullptr;
}

u64 buffer_device_address(Device &device, Buffer &buffer, u64 offset) {
    (void)device;
    if (offset > buffer.desc.size) {
        VEL_ERROR("buffer_device_address: offset {} exceeds buffer size {}", offset, buffer.desc.size);
        return 0;
    }
    if (!buffer.handle) {
        return 0;
    }
    return buffer.handle->gpuAddress() + offset;
}

void buffer_flush(Device &device, Buffer &buffer, u64 offset, u64 size) {
    // upload/readback buffers are shared (CPU-coherent), private buffers are
    // never CPU-mapped nice little no-ops
    (void)device;
    (void)buffer;
    (void)offset;
    (void)size;
}

void buffer_invalidate(Device &device, Buffer &buffer, u64 offset, u64 size) {
    (void)device;
    (void)buffer;
    (void)offset;
    (void)size;
}

bool create_buffer_view(Device &device, const BufferViewDesc &desc, BufferView &out) {
    (void)device;
    out.buffer = desc.buffer;
    out.desc = desc;
    out.handle = desc.buffer ? desc.buffer->handle : nullptr;
    // bda. no slot.
    out.slot = 0;
    if (!out.handle) {
        VEL_ERROR("create_buffer_view: null buffer");
        return false;
    }
    return true;
}

u64 handle_id(Device &device, BufferView &view) {
    if (!view.buffer) {
        VEL_ERROR("handle_id: buffer view has no buffer");
        return 0;
    }
    return buffer_device_address(device, *view.buffer, view.desc.offset);
}

void destroy_buffer_view(Device &device, BufferView &view) {
    (void)device;
    view.slot = UINT64_MAX;
    view.handle = nullptr;
    view.buffer = nullptr;
}

bool valid(const BufferView &view) {
    return view.handle != nullptr;
}

} // namespace rhi