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

#ifndef GrMtlRenderTarget_DEFINED
#define GrMtlRenderTarget_DEFINED

#include "src/gpu/ganesh/GrRenderTarget.h"

#include "include/gpu/ganesh/GrBackendSurface.h"
#include "src/gpu/ganesh/GrGpu.h"
#include "src/gpu/ganesh/mtl/GrMtlAttachment.h"
#include "src/gpu/ganesh/mtl/GrMtlFramebuffer.h"

#import <Metal/Metal.h>

class GrMtlGpu;

class GrMtlRenderTarget: public GrRenderTarget {
public:
    // If sampleCnt is greater than 1 and the texture is single sampled, then a MSAA texture
    // is created that will resolve to the wrapped single sample texture.
    static sk_sp<GrMtlRenderTarget> MakeWrappedRenderTarget(GrMtlGpu*,
                                                            SkISize,
                                                            int sampleCnt,
                                                            id<MTLTexture>);

    ~GrMtlRenderTarget() override;

    bool canAttemptStencilAttachment(bool useMSAASurface) const override {
        SkASSERT(useMSAASurface == (this->numSamples() > 1));
        return true;
    }

    GrMtlAttachment* colorAttachment() const { return fColorAttachment.get(); }
    id<MTLTexture> colorMTLTexture() const { return fColorAttachment->mtlTexture(); }
    GrMtlAttachment* resolveAttachment() const { return fResolveAttachment.get(); }
    id<MTLTexture> resolveMTLTexture() const { return fResolveAttachment->mtlTexture(); }

    // Returns the GrMtlAttachment of the non-msaa attachment. If the color attachment has 1 sample,
    // then the color attachment will be returned. Otherwise, the resolve attachment is returned.
    GrMtlAttachment* nonMSAAAttachment() const {
        if (fColorAttachment->numSamples() == 1) {
            return fColorAttachment.get();
        } else {
            return fResolveAttachment.get();
        }
    }

    GrBackendRenderTarget getBackendRenderTarget() const override;

    GrBackendFormat backendFormat() const override;

    const GrMtlFramebuffer* getFramebuffer(bool withResolve,
                                           bool withStencil);

protected:
    GrMtlRenderTarget(GrMtlGpu* gpu,
                      SkISize,
                      sk_sp<GrMtlAttachment> colorAttachment,
                      sk_sp<GrMtlAttachment> resolveAttachment,
                      std::string_view label);

    GrMtlGpu* getMtlGpu() const;

    void onAbandon() override;
    void onRelease() override;

    // This returns zero since the memory should all be handled by the attachments
    size_t onGpuMemorySize() const override { return 0; }

    void onSetLabel() override;

    sk_sp<GrMtlAttachment> fColorAttachment;
    sk_sp<GrMtlAttachment> fResolveAttachment;

private:
    // Extra param to disambiguate from constructor used by subclasses.
    enum Wrapped { kWrapped };
    GrMtlRenderTarget(GrMtlGpu* gpu,
                      SkISize,
                      sk_sp<GrMtlAttachment> colorAttachment,
                      sk_sp<GrMtlAttachment> resolveAttachment,
                      Wrapped,
                      std::string_view label);

    bool completeStencilAttachment(GrAttachment* stencil, bool useMSAASurface) override;

    // We can have a renderpass with and without resolve attachment or stencil attachment,
    // both of these being completely orthogonal. Thus we have a total of 4 types of render passes.
    // We then cache a framebuffer for each type of these render passes.
    // TODO: add support for other flags if needed
    inline static constexpr int kNumCachedFramebuffers = 4;

    sk_sp<const GrMtlFramebuffer> fCachedFramebuffers[kNumCachedFramebuffers];


    using INHERITED = GrRenderTarget;
};


#endif

