sampler.cpp

cross platform rendering playground

src/backend/metal/sampler.cpp

2.38 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 {

static MTL::SamplerMinMagFilter to_filter(rhi::SamplerFilter filter) {
    switch (filter) {
    case rhi::SamplerFilter::POINT:
        return MTL::SamplerMinMagFilterNearest;
    case rhi::SamplerFilter::LINEAR:
    case rhi::SamplerFilter::ANISOTROPIC:
    default:
        return MTL::SamplerMinMagFilterLinear;
    }
}

static MTL::SamplerAddressMode to_address(rhi::SamplerAddressMode mode) {
    switch (mode) {
    case rhi::SamplerAddressMode::WRAP:
        return MTL::SamplerAddressModeRepeat;
    case rhi::SamplerAddressMode::MIRROR:
        return MTL::SamplerAddressModeMirrorRepeat;
    case rhi::SamplerAddressMode::CLAMP:
        return MTL::SamplerAddressModeClampToEdge;
    case rhi::SamplerAddressMode::BORDER:
    default:
        return MTL::SamplerAddressModeClampToEdge;
    }
}

bool create_sampler(Device &device, SamplerDesc &desc, Sampler &sampler) {
    MTL::SamplerDescriptor *sd = MTL::SamplerDescriptor::alloc()->init();
    sd->setMinFilter(to_filter(desc.filter));
    sd->setMagFilter(to_filter(desc.filter));
    sd->setSAddressMode(to_address(desc.address));
    sd->setTAddressMode(to_address(desc.address));
    if (desc.use_mips) {
        sd->setMipFilter(MTL::SamplerMipFilterLinear);
    }

    MTL::SamplerState *state = device.handle->newSamplerState(sd);
    sd->release();
    if (!state) {
        VEL_ERROR("Failed to create Metal sampler state");
        return false;
    }

    sampler.handle = state;
    if (!desc.name.empty()) {
        state->setLabel(NS::String::string(desc.name.c_str(), NS::UTF8StringEncoding));
    }
    sampler.slot = mt::write_sampler(device, sampler);
    return true;
}

u64 handle_id(Device &device, Sampler &sampler) {
    if (sampler.slot == UINT64_MAX) {
        VEL_ERROR("handle_id: sampler carries no heap slot");
        return 0;
    }
    return mt::heap_sampler_id(device, sampler.slot);
}

void destroy_sampler(Device &device, Sampler &sampler) {
    mt::free_sampler(device, sampler.slot);
    sampler.slot = UINT64_MAX;
    if (sampler.handle) {
        sampler.handle->release();
        sampler.handle = nullptr;
    }
}

bool valid(const Sampler &sampler) {
    return sampler.handle != nullptr;
}

} // namespace rhi