/*
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

// This is a GPU-backend specific test.

#include "tests/Test.h"

#include "include/gpu/GrTexture.h"
#include "src/gpu/GrContextPriv.h"
#include "src/gpu/GrProxyProvider.h"
#include "src/gpu/GrRenderTargetProxy.h"
#include "src/gpu/GrResourceProvider.h"
#include "src/gpu/GrSurfaceProxy.h"
#include "src/gpu/GrTextureProxy.h"
#include "tests/TestUtils.h"

static const int kWidthHeight = 128;

static sk_sp<GrTextureProxy> make_deferred(GrContext* context) {
    GrProxyProvider* proxyProvider = context->priv().proxyProvider();
    const GrCaps* caps = context->priv().caps();

    GrSurfaceDesc desc;
    desc.fWidth = kWidthHeight;
    desc.fHeight = kWidthHeight;
    desc.fConfig = kRGBA_8888_GrPixelConfig;

    const GrBackendFormat format = caps->getDefaultBackendFormat(GrColorType::kRGBA_8888,
                                                                 GrRenderable::kYes);
    return proxyProvider->createProxy(format, desc, GrRenderable::kYes, 1,
                                      kBottomLeft_GrSurfaceOrigin, GrMipMapped::kNo,
                                      SkBackingFit::kApprox, SkBudgeted::kYes, GrProtected::kNo);
}

static sk_sp<GrTextureProxy> make_wrapped(GrContext* context) {
    GrProxyProvider* proxyProvider = context->priv().proxyProvider();

    return proxyProvider->testingOnly_createInstantiatedProxy(
            {kWidthHeight, kWidthHeight}, GrColorType::kRGBA_8888, GrRenderable::kYes, 1,
            kBottomLeft_GrSurfaceOrigin, SkBackingFit::kExact, SkBudgeted::kNo, GrProtected::kNo);
}

DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ProxyRefTest, reporter, ctxInfo) {
    GrResourceProvider* resourceProvider = ctxInfo.grContext()->priv().resourceProvider();

    for (auto make : { make_deferred, make_wrapped }) {
        // An extra ref
        {
            sk_sp<GrTextureProxy> proxy((*make)(ctxInfo.grContext()));
            if (proxy) {
                sk_sp<GrTextureProxy> extraRef(proxy);

                int backingRefs = proxy->isInstantiated() ? 1 : -1;

                CheckSingleThreadedProxyRefs(reporter, proxy.get(), 2, backingRefs);

                proxy->instantiate(resourceProvider);

                CheckSingleThreadedProxyRefs(reporter, proxy.get(), 2, 1);
            }
            CheckSingleThreadedProxyRefs(reporter, proxy.get(), 1, 1);
        }

        // Multiple normal refs
        {
            sk_sp<GrTextureProxy> proxy((*make)(ctxInfo.grContext()));
            if (proxy.get()) {
                proxy->ref();
                proxy->ref();

                int backingRefs = proxy->isInstantiated() ? 1 : -1;

                CheckSingleThreadedProxyRefs(reporter, proxy.get(), 3, backingRefs);

                proxy->instantiate(resourceProvider);

                CheckSingleThreadedProxyRefs(reporter, proxy.get(), 3, 1);

                proxy->unref();
                proxy->unref();
            }
            CheckSingleThreadedProxyRefs(reporter, proxy.get(), 1, 1);
        }

        // Continue using (reffing) proxy after instantiation
        {
            sk_sp<GrTextureProxy> proxy((*make)(ctxInfo.grContext()));
            if (proxy) {
                sk_sp<GrTextureProxy> firstExtraRef(proxy);

                int backingRefs = proxy->isInstantiated() ? 1 : -1;

                CheckSingleThreadedProxyRefs(reporter, proxy.get(), 2, backingRefs);

                proxy->instantiate(resourceProvider);

                CheckSingleThreadedProxyRefs(reporter, proxy.get(), 2, 1);

                sk_sp<GrTextureProxy> secondExtraRef(proxy);
                CheckSingleThreadedProxyRefs(reporter, proxy.get(), 3, 1);
            }
            CheckSingleThreadedProxyRefs(reporter, proxy.get(), 1, 1);
        }
    }
}
