/*****************************************************************************/
// Copyright 2006-2019 Adobe Systems Incorporated
// All Rights Reserved.
//
// NOTICE:  Adobe permits you to use, modify, and distribute this file in
// accordance with the terms of the Adobe license agreement accompanying it.
/*****************************************************************************/

#include "dng_filter_task.h"

#include "dng_bottlenecks.h"
#include "dng_exceptions.h"
#include "dng_image.h"
#include "dng_memory.h"
#include "dng_tag_types.h"
#include "dng_tag_values.h"
#include "dng_utils.h"

/*****************************************************************************/

dng_filter_task::dng_filter_task (const char *name,
                                  const dng_image &srcImage,
                                  dng_image &dstImage)

    :   dng_area_task (name)

    ,   fSrcImage     (srcImage)
    ,   fDstImage     (dstImage)

    ,   fSrcPlane     (0                    )
    ,   fSrcPlanes    (srcImage.Planes    ())
    ,   fSrcPixelType (srcImage.PixelType ())

    ,   fDstPlane     (0                    )
    ,   fDstPlanes    (dstImage.Planes    ())
    ,   fDstPixelType (dstImage.PixelType ())

    ,   fSrcRepeat    (1, 1)
    ,   fSrcTileSize  (0, 0)

    {

    }

/*****************************************************************************/

dng_filter_task::~dng_filter_task ()
    {

    }

/*****************************************************************************/

void dng_filter_task::Start (uint32 threadCount,
                             const dng_rect & /* dstArea */,
                             const dng_point &tileSize,
                             dng_memory_allocator *allocator,
                             dng_abort_sniffer * /* sniffer */)
    {

    fSrcTileSize = SrcTileSize (tileSize);

    uint32 srcBufferSize = ComputeBufferSize (fSrcPixelType,
                                              fSrcTileSize,
                                              fSrcPlanes,
                                              padSIMDBytes);

    uint32 dstBufferSize = ComputeBufferSize (fDstPixelType,
                                              tileSize,
                                              fDstPlanes,
                                              padSIMDBytes);

    for (uint32 threadIndex = 0; threadIndex < threadCount; threadIndex++)
        {

        fSrcBuffer [threadIndex] . Reset (allocator->Allocate (srcBufferSize));

        fDstBuffer [threadIndex] . Reset (allocator->Allocate (dstBufferSize));

        // Zero buffers so any pad bytes have defined values.

        DoZeroBytes (fSrcBuffer [threadIndex]->Buffer      (),
                     fSrcBuffer [threadIndex]->LogicalSize ());

        DoZeroBytes (fDstBuffer [threadIndex]->Buffer      (),
                     fDstBuffer [threadIndex]->LogicalSize ());

        }

    }

/*****************************************************************************/

void dng_filter_task::Process (uint32 threadIndex,
                               const dng_rect &area,
                               dng_abort_sniffer * /* sniffer */)
    {

    // Find source area for this destination area.

    dng_rect srcArea = SrcArea (area);

    // Safety check.

    int32 src_area_w;
    int32 src_area_h;

    if (!ConvertUint32ToInt32 (srcArea.W (),
                               &src_area_w) ||
        !ConvertUint32ToInt32 (srcArea.H (),
                               &src_area_h) ||
        src_area_w > fSrcTileSize.h ||
        src_area_h > fSrcTileSize.v)
        {

        ThrowMemoryFull ("Area exceeds tile size.");

        }

    // Setup srcBuffer.

    dng_pixel_buffer srcBuffer (srcArea,
                                fSrcPlane,
                                fSrcPlanes,
                                fSrcPixelType,
                                pcRowInterleavedAlignSIMD,
                                fSrcBuffer [threadIndex]->Buffer ());

    // Setup dstBuffer.

    dng_pixel_buffer dstBuffer (area,
                                fDstPlane,
                                fDstPlanes,
                                fDstPixelType,
                                pcRowInterleavedAlignSIMD,
                                fDstBuffer [threadIndex]->Buffer ());

    // Get source pixels.

    fSrcImage.Get (srcBuffer,
                   dng_image::edge_repeat,
                   fSrcRepeat.v,
                   fSrcRepeat.h);

    // Process area.

    ProcessArea (threadIndex,
                 srcBuffer,
                 dstBuffer);

    // Save result pixels.

    fDstImage.Put (dstBuffer);

    }

/*****************************************************************************/
