/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "rsContext.h"
#include "rsSampler.h"
#include "rs.h"

using namespace android;
using namespace android::renderscript;


Sampler::Sampler(Context *rsc) : ObjectBase(rsc) {
    // Should not get called.
    rsAssert(0);
}

Sampler::Sampler(Context *rsc,
                 RsSamplerValue magFilter,
                 RsSamplerValue minFilter,
                 RsSamplerValue wrapS,
                 RsSamplerValue wrapT,
                 RsSamplerValue wrapR,
                 float aniso) : ObjectBase(rsc) {
    mHal.state.magFilter = magFilter;
    mHal.state.minFilter = minFilter;
    mHal.state.wrapS = wrapS;
    mHal.state.wrapT = wrapT;
    mHal.state.wrapR = wrapR;
    mHal.state.aniso = aniso;

    mRSC->mHal.funcs.sampler.init(mRSC, this);
}

Sampler::~Sampler() {
    mRSC->mHal.funcs.sampler.destroy(mRSC, this);
}

void Sampler::preDestroy() const {
    auto &samplers = mRSC->mStateSampler.mAllSamplers;

    for (auto sampleIter = samplers.begin(), endIter = samplers.end();
         sampleIter != endIter; sampleIter++) {

        if (this == *sampleIter) {
            samplers.erase(sampleIter);
            return;
        }
    }
}

void Sampler::bindToContext(SamplerState *ss, uint32_t slot) {
    ss->mSamplers[slot].set(this);
    mBoundSlot = slot;
}

void Sampler::unbindFromContext(SamplerState *ss) {
    int32_t slot = mBoundSlot;
    mBoundSlot = -1;
    ss->mSamplers[slot].clear();
}

void Sampler::serialize(Context *rsc, OStream *stream) const {
}

Sampler *Sampler::createFromStream(Context *rsc, IStream *stream) {
    return nullptr;
}

ObjectBaseRef<Sampler> Sampler::getSampler(Context *rsc,
                                           RsSamplerValue magFilter,
                                           RsSamplerValue minFilter,
                                           RsSamplerValue wrapS,
                                           RsSamplerValue wrapT,
                                           RsSamplerValue wrapR,
                                           float aniso) {
    ObjectBaseRef<Sampler> returnRef;
    ObjectBase::asyncLock();
    for (uint32_t ct = 0; ct < rsc->mStateSampler.mAllSamplers.size(); ct++) {
        Sampler *existing = rsc->mStateSampler.mAllSamplers[ct];
        if (existing->mHal.state.magFilter != magFilter) continue;
        if (existing->mHal.state.minFilter != minFilter ) continue;
        if (existing->mHal.state.wrapS != wrapS) continue;
        if (existing->mHal.state.wrapT != wrapT) continue;
        if (existing->mHal.state.wrapR != wrapR) continue;
        if (existing->mHal.state.aniso != aniso) continue;
        returnRef.set(existing);
        ObjectBase::asyncUnlock();
        return returnRef;
    }
    ObjectBase::asyncUnlock();

    void* allocMem = rsc->mHal.funcs.allocRuntimeMem(sizeof(Sampler), 0);
    if (!allocMem) {
        rsc->setError(RS_ERROR_FATAL_DRIVER, "Couldn't allocate memory for Allocation");
        return nullptr;
    }

    Sampler *s = new (allocMem) Sampler(rsc, magFilter, minFilter, wrapS, wrapT, wrapR, aniso);
    returnRef.set(s);

#ifdef RS_FIND_OFFSETS
    ALOGE("pointer for sampler: %p", s);
    ALOGE("pointer for sampler.drv: %p", &s->mHal.drv);
#endif

    ObjectBase::asyncLock();
    rsc->mStateSampler.mAllSamplers.push_back(s);
    ObjectBase::asyncUnlock();

    return returnRef;
}

void Sampler::operator delete(void* ptr) {
    if (ptr) {
        Sampler *s = (Sampler*) ptr;
        s->getContext()->mHal.funcs.freeRuntimeMem(ptr);
    }
}


////////////////////////////////

namespace android {
namespace renderscript {

RsSampler rsi_SamplerCreate(Context * rsc,
                            RsSamplerValue magFilter,
                            RsSamplerValue minFilter,
                            RsSamplerValue wrapS,
                            RsSamplerValue wrapT,
                            RsSamplerValue wrapR,
                            float aniso) {
    ObjectBaseRef<Sampler> s = Sampler::getSampler(rsc, magFilter, minFilter,
                                                   wrapS, wrapT, wrapR, aniso);
    s->incUserRef();
    return s.get();
}

}}
