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

#include "Benchmark.h"
#include "Resources.h"
#include "SkCanvas.h"
#include "SkData.h"
#include "SkImageGenerator.h"
#include "SkImageDecoder.h"
#include "SkOSFile.h"
#include "SkPixelRef.h"

#ifndef SK_IGNORE_ETC1_SUPPORT

#include "etc1.h"

// This takes the etc1 data pointed to by orig, and copies it `factor` times in each
// dimension. The return value is the new data or nullptr on error.
static etc1_byte* create_expanded_etc1_bitmap(const uint8_t* orig, int factor) {
    SkASSERT(orig);
    SkASSERT(factor > 1);

    const etc1_byte* origData = reinterpret_cast<const etc1_byte*>(orig);
    if (!etc1_pkm_is_valid(orig)) {
        return nullptr;
    }

    etc1_uint32 origWidth = etc1_pkm_get_width(origData);
    etc1_uint32 origHeight = etc1_pkm_get_height(origData);

    // The width and height must be aligned along block boundaries
    static const etc1_uint32 kETC1BlockWidth = 4;
    static const etc1_uint32 kETC1BlockHeight = 4;
    if ((origWidth % kETC1BlockWidth) != 0 ||
        (origHeight % kETC1BlockHeight) != 0) {
        return nullptr;
    }

    // The picture must be at least as large as a block.
    if (origWidth <= kETC1BlockWidth || origHeight <= kETC1BlockHeight) {
        return nullptr;
    }

    etc1_uint32 newWidth = origWidth * factor;
    etc1_uint32 newHeight = origHeight * factor;

    etc1_uint32 newDataSz = etc1_get_encoded_data_size(newWidth, newHeight);
    etc1_byte* newData = reinterpret_cast<etc1_byte *>(
        sk_malloc_throw(newDataSz + ETC_PKM_HEADER_SIZE));
    etc1_pkm_format_header(newData, newWidth, newHeight);

    etc1_byte* copyInto = newData;

    copyInto += ETC_PKM_HEADER_SIZE;
    origData += ETC_PKM_HEADER_SIZE;

    etc1_uint32 origBlocksX = (origWidth >> 2);
    etc1_uint32 origBlocksY = (origHeight >> 2);
    etc1_uint32 newBlocksY = (newHeight >> 2);
    etc1_uint32 origRowSzInBytes = origBlocksX * ETC1_ENCODED_BLOCK_SIZE;

    for (etc1_uint32 j = 0; j < newBlocksY; ++j) {
        const etc1_byte* rowStart = origData + ((j % origBlocksY) * origRowSzInBytes);
        for(etc1_uint32 i = 0; i < newWidth; i += origWidth) {
            memcpy(copyInto, rowStart, origRowSzInBytes);
            copyInto += origRowSzInBytes;
        }
    }
    return newData;
}

// This is the base class for all of the benches in this file. In general
// the ETC1 benches should all be working on the same data. Due to the
// simplicity of the PKM file, that data is the 128x128 mandrill etc1
// compressed texture repeated by some factor (currently 8 -> 1024x1024)
class ETCBitmapBenchBase : public Benchmark {
public:
    ETCBitmapBenchBase() : fPKMData(loadPKM()) {
        if (nullptr == fPKMData) {
            SkDebugf("Could not load PKM data!\n");
        }
    }

protected:
    SkAutoDataUnref fPKMData;

private:
    SkData* loadPKM() {
        SkString pkmFilename = GetResourcePath("mandrill_128.pkm");
        // Expand the data
        SkAutoDataUnref fileData(SkData::NewFromFileName(pkmFilename.c_str()));
        if (nullptr == fileData) {
            SkDebugf("Could not open the file. Did you forget to set the resourcePath?\n");
            return nullptr;
        }

        const etc1_uint32 kExpansionFactor = 8;
        etc1_byte* expandedETC1 =
            create_expanded_etc1_bitmap(fileData->bytes(), kExpansionFactor);
        if (nullptr == expandedETC1) {
            SkDebugf("Error expanding ETC1 data by factor of %d\n", kExpansionFactor);
            return nullptr;
        }

        etc1_uint32 width = etc1_pkm_get_width(expandedETC1);
        etc1_uint32 height = etc1_pkm_get_width(expandedETC1);
        etc1_uint32 dataSz = ETC_PKM_HEADER_SIZE + etc1_get_encoded_data_size(width, height);
        return SkData::NewFromMalloc(expandedETC1, dataSz);
    }

    typedef Benchmark INHERITED;
};

// This is the rendering benchmark. Prior to rendering the data, create a
// bitmap using the etc1 data.
class ETCBitmapBench : public ETCBitmapBenchBase {
public:
    ETCBitmapBench(bool decompress, Backend backend)
        : fDecompress(decompress), fBackend(backend) { }

    bool isSuitableFor(Backend backend) override {
        return SkToBool(fImage) && backend == this->fBackend;
    }

protected:
    const char* onGetName() override {
        if (kGPU_Backend == this->fBackend) {
            if (this->fDecompress) {
                return "etc1bitmap_render_gpu_decompressed";
            } else {
                return "etc1bitmap_render_gpu_compressed";
            }
        } else {
            SkASSERT(kRaster_Backend == this->fBackend);
            if (this->fDecompress) {
                return "etc1bitmap_render_raster_decompressed";
            } else {
                return "etc1bitmap_render_raster_compressed";
            }
        }
    }

    void onDelayedSetup() override {
        if (nullptr == fPKMData) {
            SkDebugf("Failed to load PKM data!\n");
            return;
        }

        if (fDecompress) {
            SkAutoTDelete<SkImageGenerator> gen(SkImageGenerator::NewFromEncoded(fPKMData));
            gen->generateBitmap(&fBitmap);
        } else {
            fImage.reset(SkImage::NewFromEncoded(fPKMData));
        }
    }

    void onDraw(int loops, SkCanvas* canvas) override {
        for (int i = 0; i < loops; ++i) {
            if (fDecompress) {
                canvas->drawBitmap(this->fBitmap, 0, 0, nullptr);
            } else {
                canvas->drawImage(fImage, 0, 0, nullptr);
            }
        }
    }

protected:
    SkBitmap fBitmap;
    SkAutoTUnref<SkImage> fImage;

    bool decompress() const { return fDecompress; }
    Backend backend() const { return fBackend; }
private:
    const bool fDecompress;
    const Backend fBackend;
    typedef ETCBitmapBenchBase INHERITED;
};

// This benchmark is identical to the previous benchmark, but it explicitly forces
// an upload to the GPU before each draw call. We do this by notifying the bitmap
// that the pixels have changed (even though they haven't).
class ETCBitmapUploadBench : public ETCBitmapBench {
public:
    ETCBitmapUploadBench(bool decompress, Backend backend)
        : ETCBitmapBench(decompress, backend) { }

protected:
    const char* onGetName() override {
        if (kGPU_Backend == this->backend()) {
            if (this->decompress()) {
                return "etc1bitmap_upload_gpu_decompressed";
            } else {
                return "etc1bitmap_upload_gpu_compressed";
            }
        } else {
            SkASSERT(kRaster_Backend == this->backend());
            if (this->decompress()) {
                return "etc1bitmap_upload_raster_decompressed";
            } else {
                return "etc1bitmap_upload_raster_compressed";
            }
        }
    }

    void onDraw(int loops, SkCanvas* canvas) override {
        SkPixelRef* pr = fBitmap.pixelRef();
        for (int i = 0; i < loops; ++i) {
            if (pr) {
                pr->notifyPixelsChanged();
            }
            canvas->drawBitmap(this->fBitmap, 0, 0, nullptr);
        }
    }

private:
    typedef ETCBitmapBench INHERITED;
};

DEF_BENCH(return new ETCBitmapBench(false, Benchmark::kRaster_Backend);)
DEF_BENCH(return new ETCBitmapBench(true, Benchmark::kRaster_Backend);)

DEF_BENCH(return new ETCBitmapBench(false, Benchmark::kGPU_Backend);)
DEF_BENCH(return new ETCBitmapBench(true, Benchmark::kGPU_Backend);)

DEF_BENCH(return new ETCBitmapUploadBench(false, Benchmark::kRaster_Backend);)
DEF_BENCH(return new ETCBitmapUploadBench(true, Benchmark::kRaster_Backend);)

DEF_BENCH(return new ETCBitmapUploadBench(false, Benchmark::kGPU_Backend);)
DEF_BENCH(return new ETCBitmapUploadBench(true, Benchmark::kGPU_Backend);)

#endif  // SK_IGNORE_ETC1_SUPPORT
