<commit_before>#include "xchainer/device.h"

#include <algorithm>
#include <type_traits>

#include "xchainer/array.h"
#include "xchainer/context.h"
#include "xchainer/error.h"
#include "xchainer/native/native_backend.h"
#include "xchainer/routines/creation.h"

namespace xchainer {
namespace {

thread_local Device* t_default_device = nullptr;
static_assert(std::is_pod<decltype(t_default_device)>::value, "t_default_device must be POD");

}  // namespace

void Device::CheckDevicesCompatible(const Array& array) {
    if (this != &array.device()) {
        throw DeviceError{"Device (", name(), ") is not compatible with array's device (", array.device().name(), ")."};
    }
}

namespace internal {

Device* GetDefaultDeviceNoExcept() noexcept { return t_default_device; }

}  // namespace internal

Device& GetDefaultDevice() {
    if (t_default_device == nullptr) {
        t_default_device = &GetDefaultContext().GetDevice({native::NativeBackend::kDefaultName, 0});
    }
    return *t_default_device;
}

void SetDefaultDevice(Device* device) {
    if (device != nullptr && &device->backend().context() != &GetDefaultContext()) {
        throw ContextError{"Context mismatch between default device and default context."};
    }
    t_default_device = device;
}

namespace {

// Differentiable mean.
// TODO(niboshi): Move to routines
Array Mean(const Array& a, const Axes& axis, bool keepdims) {
    return a.Sum(axis, keepdims) / xchainer::internal::CountItemsAlongAxes(a.shape(), axis);
}

// Differentiable variance.
// TODO(niboshi): Move to routines
Array Var(const Array& a, const Array& mean, const Axes& axis, bool keepdims) {
    Array diff = a - mean;
    return Mean(diff * diff, axis, keepdims);
}

// Differentiable sqrt.
// TODO(niboshi): Move to routines
Array Sqrt(const Array& x) {
    Array out = EmptyLike(x, x.device());
    x.device().Sqrt(x, out);
    // TODO(niboshi): Implement backward
    return out;
}

// Differentiable reciprocal.
// TODO(niboshi): Move to routines
Array Reciprocal(const Array& x) { return OnesLike(x, x.device()) / x; }

struct ApplyBatchNormResult {
    Array out;
    Array mean;
    Array var;
    Array inv_std;
};

ApplyBatchNormResult ApplyFixedBatchNorm(
        const Array& x, const Array& gamma, const Array& beta, Array mean, Array var, Scalar eps, const Axes& axis) {
#ifndef NDEBUG
    {
        Shape reduced_shape = xchainer::internal::ReduceShape(x.shape(), axis, true);
        assert(gamma.shape() == reduced_shape);
        assert(beta.shape() == reduced_shape);

        int64_t reduced_total_size = reduced_shape.GetTotalSize();
        assert(mean.GetTotalSize() == reduced_total_size);
        assert(var.GetTotalSize() == reduced_total_size);

        assert(mean.IsConstant());
        assert(var.IsConstant());
    }
#endif  // NDEBUG
    Array x_const = x.AsConstant();
    Array inv_std = Reciprocal(Sqrt(var + eps));

    Array out = (x_const - mean) * inv_std * gamma.AsConstant() + beta.AsConstant();

    return {std::move(out), std::move(mean), std::move(var), std::move(inv_std)};
}

ApplyBatchNormResult ApplyBatchNorm(const Array& x, const Array& gamma, const Array& beta, Scalar eps, const Axes& axis) {
    Array x_const = x.AsConstant();
    Array x_mean = Mean(x_const, axis, true);
    Array x_var = Var(x_const, x_mean, axis, true);

    return ApplyFixedBatchNorm(x_const, gamma, beta, std::move(x_mean), std::move(x_var), eps, axis);
}

}  // namespace

Array GenericBatchNormForwardBackward::Forward(
        const Array& x,
        const Array& gamma,
        const Array& beta,
        const Array& running_mean,
        const Array& running_var,
        Scalar eps,
        Scalar decay,
        const Axes& axis) {
    ApplyBatchNormResult result = ApplyBatchNorm(x, gamma, beta, eps, axis);
    Array& out = result.out;
    Array& x_mean = result.mean;
    Array& x_var = result.var;
    Array& x_inv_std = result.inv_std;

    Scalar inv_decay = Scalar{1.0 - static_cast<double>(decay)};
    int64_t n = x.GetTotalSize() / gamma.GetTotalSize();
    running_mean *= decay;
    running_mean += inv_decay * x_mean;
    running_var *= decay;
    running_var += inv_decay * (static_cast<double>(n) / std::max(n - 1, int64_t{1})) * x_var;

    x_mean_ = std::make_shared<Array>(x_mean);
    x_inv_std_ = std::make_shared<Array>(x_inv_std);
    return std::move(out);
}

std::array<Array, 3> GenericBatchNormForwardBackward::Backward(
        const Array& x, const Array& gamma, const Array& gout, Scalar /*eps*/, const Axes& axis) {
    // Note: x_inv_std_ has the information of eps.
    const Array x_const = x.AsConstant();
    const Array gamma_const = gamma.AsConstant();
    const Array gout_const = gout.AsConstant();
    const Array& x_mean = *x_mean_;
    const Array& x_inv_std = *x_inv_std_;

    double inv_n = 1.0 / (x.GetTotalSize() / gamma.GetTotalSize());
    Array x_hat = (x_const - x_mean) * x_inv_std;
    Array ggamma = (gout_const * x_hat).Sum(axis);
    Array gbeta = gout_const.Sum(axis);
    Array gx = (gamma_const * x_inv_std) * (gout_const - (x_hat * ggamma + gbeta) * inv_n);

    axis_ = axis;
    x_ = std::make_shared<Array>(x);
    gamma_ = std::make_shared<Array>(gamma);
    gx_ = std::make_shared<Array>(gx);
    ggamma_ = std::make_shared<Array>(ggamma);
    gout_ = std::make_shared<Array>(gout);

    return {std::move(gx), std::move(ggamma), std::move(gbeta)};
}

std::array<Array, 3> GenericBatchNormForwardBackward::DoubleBackward(const Array& ggx, const Array& gggamma, const Array& ggbeta) {
    const Array& gout = *gout_;
    const Array& x = *x_;
    const Array& gamma = *gamma_;
    const Array& x_inv_std = *x_inv_std_;
    const Array& x_mean = *x_mean_;
    const Axes& axis = axis_;
    const Array& gx = *gx_;
    const Array& ggamma = *ggamma_;

    // Auxiliary values
    double inv_n = 1.0 / (x.GetTotalSize() / gamma.GetTotalSize());
    Array r = (gx * ggx).Sum(axis);
    Array coeff = gamma * x_inv_std;
    Array coeff_m = coeff * inv_n;
    Array x_hat = (x - x_mean) * x_inv_std;

    Array gggamma2 = gggamma - coeff_m * (x_hat * ggx).Sum(axis);
    Array ggbeta2 = ggbeta - coeff_m * ggx.Sum(axis);

    Array gx_hat2 = gggamma2 * gout - coeff_m * ggamma * ggx;
    Array gstd2 = -x_inv_std * (r + (x_hat * gx_hat2).Sum(axis));
    Array gmean2 = -x_inv_std * gx_hat2.Sum(axis);
    Array gx2 = x_inv_std * gx_hat2 + inv_n * (gmean2 + x_hat * gstd2);
    Array ggy2 = gggamma2 * x_hat + ggbeta2 + coeff * ggx;

    Array ggamma2 = r / gamma;

    return {std::move(gx2), std::move(ggamma2), std::move(ggy2)};
}

Array Device::FixedBatchNorm(
        const Array& x, const Array& gamma, const Array& beta, const Array& mean, const Array& var, Scalar eps, const Axes& axis) {
    ApplyBatchNormResult result = ApplyFixedBatchNorm(x, gamma, beta, mean, var, eps, axis);
    return std::move(result.out);
}

}  // namespace xchainer
<commit_msg>Changed ApplyBatchNormResult to have only out and inv_std<commit_after>#include "xchainer/device.h"

#include <algorithm>
#include <type_traits>

#include "xchainer/array.h"
#include "xchainer/context.h"
#include "xchainer/error.h"
#include "xchainer/native/native_backend.h"
#include "xchainer/routines/creation.h"

namespace xchainer {
namespace {

thread_local Device* t_default_device = nullptr;
static_assert(std::is_pod<decltype(t_default_device)>::value, "t_default_device must be POD");

}  // namespace

void Device::CheckDevicesCompatible(const Array& array) {
    if (this != &array.device()) {
        throw DeviceError{"Device (", name(), ") is not compatible with array's device (", array.device().name(), ")."};
    }
}

namespace internal {

Device* GetDefaultDeviceNoExcept() noexcept { return t_default_device; }

}  // namespace internal

Device& GetDefaultDevice() {
    if (t_default_device == nullptr) {
        t_default_device = &GetDefaultContext().GetDevice({native::NativeBackend::kDefaultName, 0});
    }
    return *t_default_device;
}

void SetDefaultDevice(Device* device) {
    if (device != nullptr && &device->backend().context() != &GetDefaultContext()) {
        throw ContextError{"Context mismatch between default device and default context."};
    }
    t_default_device = device;
}

namespace {

// Differentiable mean.
// TODO(niboshi): Move to routines
Array Mean(const Array& a, const Axes& axis, bool keepdims) {
    return a.Sum(axis, keepdims) / xchainer::internal::CountItemsAlongAxes(a.shape(), axis);
}

// Differentiable variance.
// TODO(niboshi): Move to routines
Array Var(const Array& a, const Array& mean, const Axes& axis, bool keepdims) {
    Array diff = a - mean;
    return Mean(diff * diff, axis, keepdims);
}

// Differentiable sqrt.
// TODO(niboshi): Move to routines
Array Sqrt(const Array& x) {
    Array out = EmptyLike(x, x.device());
    x.device().Sqrt(x, out);
    // TODO(niboshi): Implement backward
    return out;
}

// Differentiable reciprocal.
// TODO(niboshi): Move to routines
Array Reciprocal(const Array& x) { return OnesLike(x, x.device()) / x; }

struct ApplyBatchNormResult {
    Array out;
    Array inv_std;
};

ApplyBatchNormResult ApplyBatchNorm(
        const Array& x, const Array& gamma, const Array& beta, const Array& mean, const Array& var, Scalar eps, const Axes& axis) {
#ifndef NDEBUG
    {
        Shape reduced_shape = xchainer::internal::ReduceShape(x.shape(), axis, true);
        assert(gamma.shape() == reduced_shape);
        assert(beta.shape() == reduced_shape);

        int64_t reduced_total_size = reduced_shape.GetTotalSize();
        assert(mean.GetTotalSize() == reduced_total_size);
        assert(var.GetTotalSize() == reduced_total_size);

        assert(x.IsConstant());
        assert(mean.IsConstant());
        assert(var.IsConstant());
    }
#endif  // NDEBUG
    Array inv_std = Reciprocal(Sqrt(var + eps));

    Array out = (x - mean) * inv_std * gamma.AsConstant() + beta.AsConstant();

    return {std::move(out), std::move(inv_std)};
}

}  // namespace

Array GenericBatchNormForwardBackward::Forward(
        const Array& x,
        const Array& gamma,
        const Array& beta,
        const Array& running_mean,
        const Array& running_var,
        Scalar eps,
        Scalar decay,
        const Axes& axis) {
    Array x_const = x.AsConstant();
    Array x_mean = Mean(x_const, axis, true);
    Array x_var = Var(x_const, x_mean, axis, true);

    ApplyBatchNormResult result = ApplyBatchNorm(x_const, gamma, beta, x_mean, x_var, eps, axis);
    Array& out = result.out;
    Array& x_inv_std = result.inv_std;

    Scalar inv_decay = Scalar{1.0 - static_cast<double>(decay)};
    int64_t n = x.GetTotalSize() / gamma.GetTotalSize();
    running_mean *= decay;
    running_mean += inv_decay * x_mean;
    running_var *= decay;
    running_var += inv_decay * (static_cast<double>(n) / std::max(n - 1, int64_t{1})) * x_var;

    x_mean_ = std::make_shared<Array>(x_mean);
    x_inv_std_ = std::make_shared<Array>(x_inv_std);
    return std::move(out);
}

std::array<Array, 3> GenericBatchNormForwardBackward::Backward(
        const Array& x, const Array& gamma, const Array& gout, Scalar /*eps*/, const Axes& axis) {
    // Note: x_inv_std_ has the information of eps.
    const Array x_const = x.AsConstant();
    const Array gamma_const = gamma.AsConstant();
    const Array gout_const = gout.AsConstant();
    const Array& x_mean = *x_mean_;
    const Array& x_inv_std = *x_inv_std_;

    double inv_n = 1.0 / (x.GetTotalSize() / gamma.GetTotalSize());
    Array x_hat = (x_const - x_mean) * x_inv_std;
    Array ggamma = (gout_const * x_hat).Sum(axis);
    Array gbeta = gout_const.Sum(axis);
    Array gx = (gamma_const * x_inv_std) * (gout_const - (x_hat * ggamma + gbeta) * inv_n);

    axis_ = axis;
    x_ = std::make_shared<Array>(x);
    gamma_ = std::make_shared<Array>(gamma);
    gx_ = std::make_shared<Array>(gx);
    ggamma_ = std::make_shared<Array>(ggamma);
    gout_ = std::make_shared<Array>(gout);

    return {std::move(gx), std::move(ggamma), std::move(gbeta)};
}

std::array<Array, 3> GenericBatchNormForwardBackward::DoubleBackward(const Array& ggx, const Array& gggamma, const Array& ggbeta) {
    const Array& gout = *gout_;
    const Array& x = *x_;
    const Array& gamma = *gamma_;
    const Array& x_inv_std = *x_inv_std_;
    const Array& x_mean = *x_mean_;
    const Axes& axis = axis_;
    const Array& gx = *gx_;
    const Array& ggamma = *ggamma_;

    // Auxiliary values
    double inv_n = 1.0 / (x.GetTotalSize() / gamma.GetTotalSize());
    Array r = (gx * ggx).Sum(axis);
    Array coeff = gamma * x_inv_std;
    Array coeff_m = coeff * inv_n;
    Array x_hat = (x - x_mean) * x_inv_std;

    Array gggamma2 = gggamma - coeff_m * (x_hat * ggx).Sum(axis);
    Array ggbeta2 = ggbeta - coeff_m * ggx.Sum(axis);

    Array gx_hat2 = gggamma2 * gout - coeff_m * ggamma * ggx;
    Array gstd2 = -x_inv_std * (r + (x_hat * gx_hat2).Sum(axis));
    Array gmean2 = -x_inv_std * gx_hat2.Sum(axis);
    Array gx2 = x_inv_std * gx_hat2 + inv_n * (gmean2 + x_hat * gstd2);
    Array ggy2 = gggamma2 * x_hat + ggbeta2 + coeff * ggx;

    Array ggamma2 = r / gamma;

    return {std::move(gx2), std::move(ggamma2), std::move(ggy2)};
}

Array Device::FixedBatchNorm(
        const Array& x, const Array& gamma, const Array& beta, const Array& mean, const Array& var, Scalar eps, const Axes& axis) {
    ApplyBatchNormResult result = ApplyBatchNorm(x.AsConstant(), gamma, beta, mean.AsConstant(), var.AsConstant(), eps, axis);
    return std::move(result.out);
}

}  // namespace xchainer
<|endoftext|>


<commit_before>#include "xchainer/memory.h"

#include <cassert>

#ifdef XCHAINER_ENABLE_CUDA
#include <cuda.h>
#include <cuda_runtime.h>
#endif  // XCHAINER_ENABLE_CUDA

#include "xchainer/backend.h"
#ifdef XCHAINER_ENABLE_CUDA
#include "xchainer/cuda/cuda_runtime.h"
#endif  // XCHAINER_ENABLE_CUDA
#include "xchainer/device.h"
#include "xchainer/error.h"

namespace xchainer {
namespace internal {

bool IsPointerCudaMemory(const void* ptr) {
#ifdef XCHAINER_ENABLE_CUDA
    cudaPointerAttributes attr = {};
    cudaError_t status = cudaPointerGetAttributes(&attr, ptr);
    switch (status) {
        case cudaSuccess:
            if (attr.isManaged) {
                return true;
            } else {
                throw XchainerError("Non-managed GPU memory is not supported");
            }
        case cudaErrorInvalidValue:
            return false;
        default:
            cuda::CheckError(status);
            break;
    }
    assert(false);  // should never be reached
#else
    (void)ptr;  // unused
    return false;
#endif  // XCHAINER_ENABLE_CUDA
}

std::shared_ptr<void> Allocate(Device& device, size_t bytesize) {
    // TODO(sonots): Use device.backend->Allocate()
    if (device.backend()->GetName() == "native") {
        return std::make_unique<uint8_t[]>(bytesize);
#ifdef XCHAINER_ENABLE_CUDA
    } else if (device.backend()->GetName() == "cuda") {
        void* raw_ptr = nullptr;
        // Be careful to be exception-safe, i.e., do not throw before creating shared_ptr
        cudaError_t status = cudaMallocManaged(&raw_ptr, bytesize, cudaMemAttachGlobal);
        if (status == cudaSuccess) {
            return std::shared_ptr<void>{raw_ptr, cudaFree};
        } else {
            cuda::Throw(status);
        }
        assert(false);  // should never be reached
#endif                  // XCHAINER_ENABLE_CUDA
    } else {
        throw DeviceError("invalid device");
    }
}

void MemoryCopy(void* dst_ptr, const void* src_ptr, size_t bytesize) {
#ifdef XCHAINER_ENABLE_CUDA
    bool is_dst_cuda_memory = IsPointerCudaMemory(dst_ptr);
    bool is_src_cuda_memory = IsPointerCudaMemory(src_ptr);
    if (is_dst_cuda_memory) {
        if (is_src_cuda_memory) {
            // Copy from device to device is faster even in unified memory
            cuda::CheckError(cudaMemcpy(dst_ptr, src_ptr, bytesize, cudaMemcpyDeviceToDevice));
        } else {
            // For pre-6.x GPU architecture, we encountered SEGV with std::memcpy
            // ref. https://github.com/pfnet/xchainer/pull/74
            cuda::CheckError(cudaMemcpy(dst_ptr, src_ptr, bytesize, cudaMemcpyHostToDevice));
        }
    } else {
        if (is_src_cuda_memory) {
            // For pre-6.x GPU architecture, we encountered SEGV with std::memcpy
            // ref. https://github.com/pfnet/xchainer/pull/74
            cuda::CheckError(cudaMemcpy(dst_ptr, src_ptr, bytesize, cudaMemcpyDeviceToHost));
        } else {
            std::memcpy(dst_ptr, src_ptr, bytesize);
        }
    }
#else
    std::memcpy(dst_ptr, src_ptr, bytesize);
#endif  // XCHAINER_ENABLE_CUDA
}

std::shared_ptr<void> MemoryFromBuffer(Device& device, const std::shared_ptr<void>& src_ptr, size_t bytesize) {
// TODO(sonots): Use device.backend->FromBuffer()
#ifdef XCHAINER_ENABLE_CUDA
    if (device.backend()->GetName() == "native") {
        if (IsPointerCudaMemory(src_ptr.get())) {
            std::shared_ptr<void> dst_ptr = Allocate(device, bytesize);
            cuda::CheckError(cudaMemcpy(dst_ptr.get(), src_ptr.get(), bytesize, cudaMemcpyDeviceToHost));
            return dst_ptr;
        } else {
            return src_ptr;
        }
    } else if (device.backend()->GetName() == "cuda") {
        if (IsPointerCudaMemory(src_ptr.get())) {
            return src_ptr;
        } else {
            std::shared_ptr<void> dst_ptr = Allocate(device, bytesize);
            cuda::CheckError(cudaMemcpy(dst_ptr.get(), src_ptr.get(), bytesize, cudaMemcpyHostToDevice));
            return dst_ptr;
        }
    } else {
        throw DeviceError("invalid device");
    }
#else
    (void)bytesize;  // unused
    if (device.backend()->GetName() == "native") {
        return src_ptr;
    } else {
        throw DeviceError("invalid device");
    }
#endif  // XCHAINER_ENABLE_CUDA
}

}  // namespace internal
}  // namespace xchainer
<commit_msg>Fix allow operator to dot operator<commit_after>#include "xchainer/memory.h"

#include <cassert>

#ifdef XCHAINER_ENABLE_CUDA
#include <cuda.h>
#include <cuda_runtime.h>
#endif  // XCHAINER_ENABLE_CUDA

#include "xchainer/backend.h"
#ifdef XCHAINER_ENABLE_CUDA
#include "xchainer/cuda/cuda_runtime.h"
#endif  // XCHAINER_ENABLE_CUDA
#include "xchainer/device.h"
#include "xchainer/error.h"

namespace xchainer {
namespace internal {

bool IsPointerCudaMemory(const void* ptr) {
#ifdef XCHAINER_ENABLE_CUDA
    cudaPointerAttributes attr = {};
    cudaError_t status = cudaPointerGetAttributes(&attr, ptr);
    switch (status) {
        case cudaSuccess:
            if (attr.isManaged) {
                return true;
            } else {
                throw XchainerError("Non-managed GPU memory is not supported");
            }
        case cudaErrorInvalidValue:
            return false;
        default:
            cuda::CheckError(status);
            break;
    }
    assert(false);  // should never be reached
#else
    (void)ptr;  // unused
    return false;
#endif  // XCHAINER_ENABLE_CUDA
}

std::shared_ptr<void> Allocate(Device& device, size_t bytesize) {
    // TODO(sonots): Use device.backend().Allocate()
    if (device.backend().GetName() == "native") {
        return std::make_unique<uint8_t[]>(bytesize);
#ifdef XCHAINER_ENABLE_CUDA
    } else if (device.backend().GetName() == "cuda") {
        void* raw_ptr = nullptr;
        // Be careful to be exception-safe, i.e., do not throw before creating shared_ptr
        cudaError_t status = cudaMallocManaged(&raw_ptr, bytesize, cudaMemAttachGlobal);
        if (status == cudaSuccess) {
            return std::shared_ptr<void>{raw_ptr, cudaFree};
        } else {
            cuda::Throw(status);
        }
        assert(false);  // should never be reached
#endif                  // XCHAINER_ENABLE_CUDA
    } else {
        throw DeviceError("invalid device");
    }
}

void MemoryCopy(void* dst_ptr, const void* src_ptr, size_t bytesize) {
#ifdef XCHAINER_ENABLE_CUDA
    bool is_dst_cuda_memory = IsPointerCudaMemory(dst_ptr);
    bool is_src_cuda_memory = IsPointerCudaMemory(src_ptr);
    if (is_dst_cuda_memory) {
        if (is_src_cuda_memory) {
            // Copy from device to device is faster even in unified memory
            cuda::CheckError(cudaMemcpy(dst_ptr, src_ptr, bytesize, cudaMemcpyDeviceToDevice));
        } else {
            // For pre-6.x GPU architecture, we encountered SEGV with std::memcpy
            // ref. https://github.com/pfnet/xchainer/pull/74
            cuda::CheckError(cudaMemcpy(dst_ptr, src_ptr, bytesize, cudaMemcpyHostToDevice));
        }
    } else {
        if (is_src_cuda_memory) {
            // For pre-6.x GPU architecture, we encountered SEGV with std::memcpy
            // ref. https://github.com/pfnet/xchainer/pull/74
            cuda::CheckError(cudaMemcpy(dst_ptr, src_ptr, bytesize, cudaMemcpyDeviceToHost));
        } else {
            std::memcpy(dst_ptr, src_ptr, bytesize);
        }
    }
#else
    std::memcpy(dst_ptr, src_ptr, bytesize);
#endif  // XCHAINER_ENABLE_CUDA
}

std::shared_ptr<void> MemoryFromBuffer(Device& device, const std::shared_ptr<void>& src_ptr, size_t bytesize) {
// TODO(sonots): Use device.backend().FromBuffer()
#ifdef XCHAINER_ENABLE_CUDA
    if (device.backend().GetName() == "native") {
        if (IsPointerCudaMemory(src_ptr.get())) {
            std::shared_ptr<void> dst_ptr = Allocate(device, bytesize);
            cuda::CheckError(cudaMemcpy(dst_ptr.get(), src_ptr.get(), bytesize, cudaMemcpyDeviceToHost));
            return dst_ptr;
        } else {
            return src_ptr;
        }
    } else if (device.backend().GetName() == "cuda") {
        if (IsPointerCudaMemory(src_ptr.get())) {
            return src_ptr;
        } else {
            std::shared_ptr<void> dst_ptr = Allocate(device, bytesize);
            cuda::CheckError(cudaMemcpy(dst_ptr.get(), src_ptr.get(), bytesize, cudaMemcpyHostToDevice));
            return dst_ptr;
        }
    } else {
        throw DeviceError("invalid device");
    }
#else
    (void)bytesize;  // unused
    if (device.backend().GetName() == "native") {
        return src_ptr;
    } else {
        throw DeviceError("invalid device");
    }
#endif  // XCHAINER_ENABLE_CUDA
}

}  // namespace internal
}  // namespace xchainer
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Monteverdi2
  Language:  C++

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See Copyright.txt for details.

  Monteverdi2 is distributed under the CeCILL licence version 2. See
  Licence_CeCILL_V2-en.txt or
  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt for more details.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "Gui/mvdHistogramController.h"

/*****************************************************************************/
/* INCLUDE SECTION                                                           */

//
// Qt includes (sorted by alphabetic order)
//// Must be included before system/custom includes.

//
// System includes (sorted by alphabetic order)

//
// ITK includes (sorted by alphabetic order)

//
// OTB includes (sorted by alphabetic order)

//
// Monteverdi includes (sorted by alphabetic order)
#include "Core/mvdVectorImageModel.h"
#include "Gui/mvdHistogramWidget.h"

namespace mvd
{
/*
  TRANSLATOR mvd::HistogramController

  Necessary for lupdate to be aware of C++ namespaces.

  Context comment for translator.
*/

/*****************************************************************************/
/* CLASS IMPLEMENTATION SECTION                                              */

/*******************************************************************************/
HistogramController
::HistogramController( HistogramWidget* widget, QObject* parent ) :
  AbstractModelController( widget, parent )
{
}

/*******************************************************************************/
HistogramController
::~HistogramController()
{
}

/*******************************************************************************/
void
HistogramController
::Connect( AbstractModel * )
{
  // HistogramWidget* widget = GetWidget< HistogramWidget >();

  //
  // Connect GUI to controller.

  //
  // Connect controller to model.
}

/*******************************************************************************/
void
HistogramController
::Disconnect( AbstractModel * )
{
  // HistogramWidget* widget = GetWidget< HistogramWidget >();

  //
  // Disconnect controller to model.

  //
  // Disconnect GUI from controller.
}

/*******************************************************************************/
void
HistogramController
::ClearWidget()
{
  assert( GetWidget()==GetWidget< HistogramWidget >() );
  HistogramWidget* widget = GetWidget< HistogramWidget >();
  assert( widget!=NULL );

  widget->Clear();
}

/*******************************************************************************/
void
HistogramController
::virtual_ResetWidget()
{
  ResetWidget( RGBW_CHANNEL_ALL );
}

/*******************************************************************************/
void
HistogramController
::ResetWidget( RgbwChannel channel )
{
  assert( GetModel()==GetModel< VectorImageModel >() );
  VectorImageModel* imageModel = GetModel< VectorImageModel >();
  assert( imageModel!=NULL );

  HistogramModel* model = imageModel->GetHistogramModel();
  assert( model!=NULL );

  assert( GetWidget()==GetWidget< HistogramWidget >() );
  HistogramWidget* widget = GetWidget< HistogramWidget >();
  assert( widget!=NULL );

  CountType begin = 0;
  CountType end = 0;

  if( !RgbwBounds( begin, end, channel ) )
    return;

  const VectorImageSettings & settings = imageModel->GetSettings();

  widget->SetGrayscaleActivated( settings.IsGrayscaleActivated() );

  assert( std::numeric_limits< double >::has_quiet_NaN );

  for( CountType i=begin; i<end; ++i )
    {
    RgbwChannel chan = static_cast< RgbwChannel >( i );

    VectorImageSettings::ChannelVector::value_type band =
      settings.GetRgbwChannel( chan );

    size_t size = model->GetDataCount( band );

    double* x = new double[ size ];
    double* y = new double[ size ];

    double xMin = std::numeric_limits< double >::quiet_NaN();
    double yMin = std::numeric_limits< double >::quiet_NaN();
    double xMax = std::numeric_limits< double >::quiet_NaN();
    double yMax = std::numeric_limits< double >::quiet_NaN();

    model->GetData( band, x, y, xMin, xMax, yMin, yMax );

    widget->SetData( chan, x, y, size, xMin, yMin, xMax, yMax );

    widget->SetLowMarker( chan, settings.GetLowIntensity( chan ) );
    widget->SetHighMarker( chan, settings.GetHighIntensity( chan ) );

    delete x;
    x = NULL;

    delete y;
    y = NULL;
    }

  widget->RefreshScale( true );

  widget->Replot();
}

/*****************************************************************************/
/* SLOTS                                                                     */
/*****************************************************************************/
void
HistogramController
::OnRgbChannelIndexChanged( RgbwChannel channel, int )
{
  /*
  qDebug()
    << this
    << "::OnRgbChannelIndexChanged("
    << RGBW_CHANNEL_NAMES[ channel ] << ", " << band <<
    ")";
  */

  ResetWidget( channel );
}

/*****************************************************************************/
void
HistogramController
::OnGrayChannelIndexChanged( int )
{
  /*
  qDebug()
    << this
    << "::OnGrayChannelIndexChanged(" << band << ")";
  */

  ResetWidget( RGBW_CHANNEL_WHITE );
}

/*****************************************************************************/
void
HistogramController
::OnGrayscaleActivated( bool activated )
{
  /*
  qDebug()
    << this
    << "::OnGrayscaleActivated(" << activated << ")";
  */

  assert( GetWidget()==GetWidget< HistogramWidget >() );
  HistogramWidget* widget = GetWidget< HistogramWidget >();
  assert( widget!=NULL );

  widget->SetGrayscaleActivated( activated );

  widget->RefreshScale( true );
  widget->Replot();
}

/*****************************************************************************/
void
HistogramController
::OnLowIntensityChanged( RgbwChannel channel, double value, bool refresh )
{
  assert( GetWidget()==GetWidget< HistogramWidget >() );
  HistogramWidget* widget = GetWidget< HistogramWidget >();
  assert( widget!=NULL );

  widget->SetLowMarker( channel, value );

  if( refresh )
    widget->Replot();
}

/*****************************************************************************/
void
HistogramController
::OnHighIntensityChanged( RgbwChannel channel, double value, bool refresh )
{
  assert( GetWidget()==GetWidget< HistogramWidget >() );
  HistogramWidget* widget = GetWidget< HistogramWidget >();
  assert( widget!=NULL );

  widget->SetHighMarker( channel, value );

  if( refresh )
    widget->Replot();
}

/*****************************************************************************/
void
HistogramController
::OnHistogramRefreshed()
{
  ResetWidget( RGBW_CHANNEL_ALL );
}

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

} // end namespace 'mvd'
<commit_msg>BUG: Coverity-14790 fixed bad delete operator.<commit_after>/*=========================================================================

  Program:   Monteverdi2
  Language:  C++

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See Copyright.txt for details.

  Monteverdi2 is distributed under the CeCILL licence version 2. See
  Licence_CeCILL_V2-en.txt or
  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt for more details.

  This software is distributed WITHOUT ANY WARRANTY; without even
  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "Gui/mvdHistogramController.h"

/*****************************************************************************/
/* INCLUDE SECTION                                                           */

//
// Qt includes (sorted by alphabetic order)
//// Must be included before system/custom includes.

//
// System includes (sorted by alphabetic order)

//
// ITK includes (sorted by alphabetic order)

//
// OTB includes (sorted by alphabetic order)

//
// Monteverdi includes (sorted by alphabetic order)
#include "Core/mvdVectorImageModel.h"
#include "Gui/mvdHistogramWidget.h"

namespace mvd
{
/*
  TRANSLATOR mvd::HistogramController

  Necessary for lupdate to be aware of C++ namespaces.

  Context comment for translator.
*/

/*****************************************************************************/
/* CLASS IMPLEMENTATION SECTION                                              */

/*******************************************************************************/
HistogramController
::HistogramController( HistogramWidget* widget, QObject* parent ) :
  AbstractModelController( widget, parent )
{
}

/*******************************************************************************/
HistogramController
::~HistogramController()
{
}

/*******************************************************************************/
void
HistogramController
::Connect( AbstractModel * )
{
  // HistogramWidget* widget = GetWidget< HistogramWidget >();

  //
  // Connect GUI to controller.

  //
  // Connect controller to model.
}

/*******************************************************************************/
void
HistogramController
::Disconnect( AbstractModel * )
{
  // HistogramWidget* widget = GetWidget< HistogramWidget >();

  //
  // Disconnect controller to model.

  //
  // Disconnect GUI from controller.
}

/*******************************************************************************/
void
HistogramController
::ClearWidget()
{
  assert( GetWidget()==GetWidget< HistogramWidget >() );
  HistogramWidget* widget = GetWidget< HistogramWidget >();
  assert( widget!=NULL );

  widget->Clear();
}

/*******************************************************************************/
void
HistogramController
::virtual_ResetWidget()
{
  ResetWidget( RGBW_CHANNEL_ALL );
}

/*******************************************************************************/
void
HistogramController
::ResetWidget( RgbwChannel channel )
{
  assert( GetModel()==GetModel< VectorImageModel >() );
  VectorImageModel* imageModel = GetModel< VectorImageModel >();
  assert( imageModel!=NULL );

  HistogramModel* model = imageModel->GetHistogramModel();
  assert( model!=NULL );

  assert( GetWidget()==GetWidget< HistogramWidget >() );
  HistogramWidget* widget = GetWidget< HistogramWidget >();
  assert( widget!=NULL );

  CountType begin = 0;
  CountType end = 0;

  if( !RgbwBounds( begin, end, channel ) )
    return;

  const VectorImageSettings & settings = imageModel->GetSettings();

  widget->SetGrayscaleActivated( settings.IsGrayscaleActivated() );

  assert( std::numeric_limits< double >::has_quiet_NaN );

  for( CountType i=begin; i<end; ++i )
    {
    RgbwChannel chan = static_cast< RgbwChannel >( i );

    VectorImageSettings::ChannelVector::value_type band =
      settings.GetRgbwChannel( chan );

    size_t size = model->GetDataCount( band );

    double* x = new double[ size ];
    double* y = new double[ size ];

    double xMin = std::numeric_limits< double >::quiet_NaN();
    double yMin = std::numeric_limits< double >::quiet_NaN();
    double xMax = std::numeric_limits< double >::quiet_NaN();
    double yMax = std::numeric_limits< double >::quiet_NaN();

    model->GetData( band, x, y, xMin, xMax, yMin, yMax );

    widget->SetData( chan, x, y, size, xMin, yMin, xMax, yMax );

    widget->SetLowMarker( chan, settings.GetLowIntensity( chan ) );
    widget->SetHighMarker( chan, settings.GetHighIntensity( chan ) );

    delete[] x;
    x = NULL;

    delete[] y;
    y = NULL;
    }

  widget->RefreshScale( true );

  widget->Replot();
}

/*****************************************************************************/
/* SLOTS                                                                     */
/*****************************************************************************/
void
HistogramController
::OnRgbChannelIndexChanged( RgbwChannel channel, int )
{
  /*
  qDebug()
    << this
    << "::OnRgbChannelIndexChanged("
    << RGBW_CHANNEL_NAMES[ channel ] << ", " << band <<
    ")";
  */

  ResetWidget( channel );
}

/*****************************************************************************/
void
HistogramController
::OnGrayChannelIndexChanged( int )
{
  /*
  qDebug()
    << this
    << "::OnGrayChannelIndexChanged(" << band << ")";
  */

  ResetWidget( RGBW_CHANNEL_WHITE );
}

/*****************************************************************************/
void
HistogramController
::OnGrayscaleActivated( bool activated )
{
  /*
  qDebug()
    << this
    << "::OnGrayscaleActivated(" << activated << ")";
  */

  assert( GetWidget()==GetWidget< HistogramWidget >() );
  HistogramWidget* widget = GetWidget< HistogramWidget >();
  assert( widget!=NULL );

  widget->SetGrayscaleActivated( activated );

  widget->RefreshScale( true );
  widget->Replot();
}

/*****************************************************************************/
void
HistogramController
::OnLowIntensityChanged( RgbwChannel channel, double value, bool refresh )
{
  assert( GetWidget()==GetWidget< HistogramWidget >() );
  HistogramWidget* widget = GetWidget< HistogramWidget >();
  assert( widget!=NULL );

  widget->SetLowMarker( channel, value );

  if( refresh )
    widget->Replot();
}

/*****************************************************************************/
void
HistogramController
::OnHighIntensityChanged( RgbwChannel channel, double value, bool refresh )
{
  assert( GetWidget()==GetWidget< HistogramWidget >() );
  HistogramWidget* widget = GetWidget< HistogramWidget >();
  assert( widget!=NULL );

  widget->SetHighMarker( channel, value );

  if( refresh )
    widget->Replot();
}

/*****************************************************************************/
void
HistogramController
::OnHistogramRefreshed()
{
  ResetWidget( RGBW_CHANNEL_ALL );
}

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

} // end namespace 'mvd'
<|endoftext|>


<commit_before>// SurfaceGeometry.cpp

/*
 * Copyright (C) 2012 Spencer T. Parkin
 *
 * This software has been released under the MIT License.
 * See the "License.txt" file in the project root directory
 * for more information about this license.
 *
 */

#include "SurfaceGeometry.h"

//=========================================================================================
IMPLEMENT_CALCLIB_CLASS1( SurfaceGeometry, GAVisToolGeometry );

//=========================================================================================
SurfaceGeometry::SurfaceGeometry( BindType bindType, VectorMath::Surface* surface ) : GAVisToolGeometry( bindType )
{
	renderAs = RENDER_AS_SET_OF_TRACES;
	surfaceGeometryValid = false;
	this->surface = surface;
}

//=========================================================================================
/*virtual*/ SurfaceGeometry::~SurfaceGeometry( void )
{
	traceList.RemoveAll( true );
}

//=========================================================================================
/*virtual*/ void SurfaceGeometry::DecomposeFrom( const GeometricAlgebra::SumOfBlades& element )
{
	this->element.AssignSumOfBlades( element );
	surfaceGeometryValid = false;
}

//=========================================================================================
/*virtual*/ void SurfaceGeometry::ComposeTo( GeometricAlgebra::SumOfBlades& element ) const
{
	element.AssignSumOfBlades( this->element );
}

//=========================================================================================
void SurfaceGeometry::RegenerateSurfaceGeometry( void )
{
	if( renderAs == RENDER_AS_SET_OF_TRACES )
	{
		// Kill the old trace list.
		traceList.RemoveAll( true );

		VectorMath::Surface::TraceParameters traceParameters;

		// A better center would be that of the surface, if we knew how to calculate that.
		VectorMath::Zero( traceParameters.center );

		traceParameters.range = 20.0;
		traceParameters.extent = 10.0;
		traceParameters.planeCount = 30;

		VectorMath::Vector axis[3];
		int axisCount = 3;
		VectorMath::Set( axis[0], 1.0, 0.0, 0.0 );
		VectorMath::Set( axis[1], 0.0, 1.0, 0.0 );
		VectorMath::Set( axis[2], 0.0, 0.0, 1.0 );

		// Create the new trace list.
		for( int index = 0; index < axisCount; index++ )
		{
			VectorMath::Copy( traceParameters.axis, axis[ index ] );

			// Append to the trace list all traces along this axis.
			surface->GenerateTracesAlongAxis( traceParameters, traceList );
		}
	}
	else if( renderAs == RENDER_AS_TRIANGLE_MESH )
	{
		//...
	}
}

//=========================================================================================
/*virtual*/ void SurfaceGeometry::Draw( GAVisToolRender& render, bool selected )
{
	// If our trace-list is out of date, go up-date it.  Hopefully this won't take too long.
	if( !surfaceGeometryValid )
	{
		RegenerateSurfaceGeometry();
		surfaceGeometryValid = true;
	}

	if( selected )
		render.Highlight( GAVisToolRender::NORMAL_HIGHLIGHTING );
	else
		render.Highlight( GAVisToolRender::NO_HIGHLIGHTING );

	render.Color( color, alpha );

	if( renderAs == RENDER_AS_SET_OF_TRACES )
	{
		VectorMath::Surface::Trace* trace = ( VectorMath::Surface::Trace* )traceList.LeftMost();
		while( trace )
		{
			DrawTrace( trace, render );
			trace = ( VectorMath::Surface::Trace* )trace->Right();
		}
	}
	else if( renderAs == RENDER_AS_TRIANGLE_MESH )
	{
		//...
	}
}

//=========================================================================================
void SurfaceGeometry::DrawTrace( VectorMath::Surface::Trace* trace, GAVisToolRender& render )
{
	VectorMath::Surface::Point* point = 0, *nextPoint = 0;
	VectorMath::Surface::Point* firstPoint = ( VectorMath::Surface::Point* )trace->pointList.LeftMost();
	for( point = firstPoint; point; point = nextPoint )
	{
		nextPoint = ( VectorMath::Surface::Point* )point->Right();
		if( nextPoint )
			render.DrawLine( point->point, nextPoint->point );
		else if( trace->looped )
			render.DrawLine( point->point, firstPoint->point );
	}
}

//=========================================================================================
/*virtual*/ void SurfaceGeometry::CalcCenter( VectorMath::Vector& center ) const
{
	VectorMath::Zero( center );
}

//=========================================================================================
/*virtual*/ void SurfaceGeometry::Translate( const VectorMath::Vector& delta )
{
}

//=========================================================================================
/*virtual*/ void SurfaceGeometry::Rotate( const VectorMath::Vector& unitAxis, float angle )
{
}

//=========================================================================================
/*virtual*/ void SurfaceGeometry::Scale( float scale )
{
}

// SurfaceGeometry.cpp<commit_msg>adjust surface drawing parms<commit_after>// SurfaceGeometry.cpp

/*
 * Copyright (C) 2012 Spencer T. Parkin
 *
 * This software has been released under the MIT License.
 * See the "License.txt" file in the project root directory
 * for more information about this license.
 *
 */

#include "SurfaceGeometry.h"

//=========================================================================================
IMPLEMENT_CALCLIB_CLASS1( SurfaceGeometry, GAVisToolGeometry );

//=========================================================================================
SurfaceGeometry::SurfaceGeometry( BindType bindType, VectorMath::Surface* surface ) : GAVisToolGeometry( bindType )
{
	renderAs = RENDER_AS_SET_OF_TRACES;
	surfaceGeometryValid = false;
	this->surface = surface;
}

//=========================================================================================
/*virtual*/ SurfaceGeometry::~SurfaceGeometry( void )
{
	traceList.RemoveAll( true );
}

//=========================================================================================
/*virtual*/ void SurfaceGeometry::DecomposeFrom( const GeometricAlgebra::SumOfBlades& element )
{
	this->element.AssignSumOfBlades( element );
	surfaceGeometryValid = false;
}

//=========================================================================================
/*virtual*/ void SurfaceGeometry::ComposeTo( GeometricAlgebra::SumOfBlades& element ) const
{
	element.AssignSumOfBlades( this->element );
}

//=========================================================================================
void SurfaceGeometry::RegenerateSurfaceGeometry( void )
{
	if( renderAs == RENDER_AS_SET_OF_TRACES )
	{
		// Kill the old trace list.
		traceList.RemoveAll( true );

		VectorMath::Surface::TraceParameters traceParameters;

		// A better center would be that of the surface, if we knew how to calculate that.
		VectorMath::Zero( traceParameters.center );

		traceParameters.range = 15.0;
		traceParameters.extent = 8.0;
		traceParameters.planeCount = 14;

		VectorMath::Vector axis[3];
		int axisCount = 3;
		VectorMath::Set( axis[0], 1.0, 0.0, 0.0 );
		VectorMath::Set( axis[1], 0.0, 1.0, 0.0 );
		VectorMath::Set( axis[2], 0.0, 0.0, 1.0 );

		// Create the new trace list.
		for( int index = 0; index < axisCount; index++ )
		{
			VectorMath::Copy( traceParameters.axis, axis[ index ] );

			// Append to the trace list all traces along this axis.
			surface->GenerateTracesAlongAxis( traceParameters, traceList );
		}
	}
	else if( renderAs == RENDER_AS_TRIANGLE_MESH )
	{
		//...
	}
}

//=========================================================================================
/*virtual*/ void SurfaceGeometry::Draw( GAVisToolRender& render, bool selected )
{
	// If our trace-list is out of date, go up-date it.  Hopefully this won't take too long.
	if( !surfaceGeometryValid )
	{
		RegenerateSurfaceGeometry();
		surfaceGeometryValid = true;
	}

	if( selected )
		render.Highlight( GAVisToolRender::NORMAL_HIGHLIGHTING );
	else
		render.Highlight( GAVisToolRender::NO_HIGHLIGHTING );

	render.Color( color, alpha );

	if( renderAs == RENDER_AS_SET_OF_TRACES )
	{
		VectorMath::Surface::Trace* trace = ( VectorMath::Surface::Trace* )traceList.LeftMost();
		while( trace )
		{
			DrawTrace( trace, render );
			trace = ( VectorMath::Surface::Trace* )trace->Right();
		}
	}
	else if( renderAs == RENDER_AS_TRIANGLE_MESH )
	{
		//...
	}
}

//=========================================================================================
void SurfaceGeometry::DrawTrace( VectorMath::Surface::Trace* trace, GAVisToolRender& render )
{
	VectorMath::Surface::Point* point = 0, *nextPoint = 0;
	VectorMath::Surface::Point* firstPoint = ( VectorMath::Surface::Point* )trace->pointList.LeftMost();
	for( point = firstPoint; point; point = nextPoint )
	{
		nextPoint = ( VectorMath::Surface::Point* )point->Right();
		if( nextPoint )
			render.DrawLine( point->point, nextPoint->point );
		else if( trace->looped )
			render.DrawLine( point->point, firstPoint->point );
	}
}

//=========================================================================================
/*virtual*/ void SurfaceGeometry::CalcCenter( VectorMath::Vector& center ) const
{
	VectorMath::Zero( center );
}

//=========================================================================================
/*virtual*/ void SurfaceGeometry::Translate( const VectorMath::Vector& delta )
{
}

//=========================================================================================
/*virtual*/ void SurfaceGeometry::Rotate( const VectorMath::Vector& unitAxis, float angle )
{
}

//=========================================================================================
/*virtual*/ void SurfaceGeometry::Scale( float scale )
{
}

// SurfaceGeometry.cpp<|endoftext|>


<commit_before>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkLimitedLinearUndo.h"
#include <mitkRenderingManager.h>

mitk::LimitedLinearUndo::LimitedLinearUndo()
{
  // nothing to do
}

mitk::LimitedLinearUndo::~LimitedLinearUndo()
{
  m_UndoList.clear();
  m_RedoList.clear();
}

//##ModelId=3E5F5D8C00B2
bool mitk::LimitedLinearUndo::SetOperationEvent(UndoStackItem* stackItem)
{
  OperationEvent* operationEvent = dynamic_cast<OperationEvent*>(stackItem);
  if (!operationEvent) return false;

  // clear the redolist, if a new operation is saved
  if (!m_RedoList.empty())
  {
    m_RedoList.clear();
    InvokeEvent( RedoEmptyEvent() );
  }

  m_UndoList.push_back(operationEvent);

  InvokeEvent( UndoNotEmptyEvent() );

  return true;
}

bool mitk::LimitedLinearUndo::Undo(bool fine)
{
  if (fine)
  {
    // undo one object event ID
    return Undo();
  }
  else
  {
    // undo one group event ID
    int oeid = FirstObjectEventIdOfCurrentGroup(m_UndoList); // get the Object Event ID of the first item with a differnt Group ID (as seen from the end of stack)
    return Undo(oeid);
  }
}

bool mitk::LimitedLinearUndo::Undo()
{
  if(m_UndoList.empty()) return false;

  int undoObjectEventId = m_UndoList.back()->GetObjectEventId();
  return Undo( undoObjectEventId );
}

bool mitk::LimitedLinearUndo::Undo(int oeid)
{
  if(m_UndoList.empty()) return false;

  do
  {
    m_UndoList.back()->ReverseAndExecute();

    m_RedoList.push_back(m_UndoList.back());  // move to redo stack
    m_UndoList.pop_back();                    // delete last operation from undo-list
    InvokeEvent( RedoNotEmptyEvent() );

    if (m_UndoList.empty())
    {
      InvokeEvent( UndoEmptyEvent() );
      return false;
    }
  }
  while ( m_UndoList.back()->GetObjectEventId() >= oeid );

  //Update. This should belong into the ExecuteOperation() of OperationActors, but it seems not to be used everywhere
  mitk::RenderingManager::GetInstance()->RequestUpdateAll();
  return true;
}

//##ModelId=3E5F5D8C00DA
bool mitk::LimitedLinearUndo::Redo(bool)
{
  return Redo();
}

bool mitk::LimitedLinearUndo::Redo()
{
  if (m_RedoList.empty()) return false;

  int redoObjectEventId = m_RedoList.back()->GetObjectEventId();
  return Redo( redoObjectEventId );
}

bool mitk::LimitedLinearUndo::Redo(int oeid)
{
  if (m_RedoList.empty()) return false;

  do
  {
    m_RedoList.back()->ReverseAndExecute();

    m_UndoList.push_back(m_RedoList.back());
    m_RedoList.pop_back();
    InvokeEvent( UndoNotEmptyEvent() );

    if (m_RedoList.empty())
    {
      InvokeEvent( RedoEmptyEvent() );
      break;
    }
  }
  while ( m_RedoList.back()->GetObjectEventId() <= oeid );

  //Update. This should belong into the ExecuteOperation() of OperationActors, but it seems not to be used everywhere
  mitk::RenderingManager::GetInstance()->RequestUpdateAll();
  return true;
}

//##ModelId=3F04519601A4
void mitk::LimitedLinearUndo::Clear()
{
  m_UndoList.clear();
  InvokeEvent( UndoEmptyEvent() );

  m_RedoList.clear();
  InvokeEvent( RedoEmptyEvent() );
}

//##ModelId=3F04519601B5
void mitk::LimitedLinearUndo::ClearRedoList()
{
  m_RedoList.clear();
  InvokeEvent( RedoEmptyEvent() );
}

//##ModelId=3F04519601D3
bool mitk::LimitedLinearUndo::RedoListEmpty()
{
  return m_RedoList.empty();
}

int mitk::LimitedLinearUndo::GetLastObjectEventIdInList()
{
  return m_UndoList.back()->GetObjectEventId();
}

int mitk::LimitedLinearUndo::GetLastGroupEventIdInList()
{
  return m_UndoList.back()->GetGroupEventId();
}

mitk::OperationEvent* mitk::LimitedLinearUndo::GetLastOfType(OperationActor* destination, OperationType opType)
{
  // When/where is this function needed? In CoordinateSupplier...
  for ( UndoContainerRevIter iter = m_UndoList.rbegin(); iter != m_UndoList.rend(); ++iter )
  {
    OperationEvent* opEvent = dynamic_cast<OperationEvent*>(*iter);
    if (!opEvent) continue;

    if (   opEvent->GetOperation()->GetOperationType() == opType
        && opEvent->IsValid()
        && opEvent->GetDestination() == destination )
      return opEvent;
  }

  return NULL;
}

int mitk::LimitedLinearUndo::FirstObjectEventIdOfCurrentGroup(mitk::LimitedLinearUndo::UndoContainer& stack)
{
  int currentGroupEventId = stack.back()->GetGroupEventId();
  int firstObjectEventId = -1;

  for ( UndoContainerRevIter iter = stack.rbegin(); iter != stack.rend(); ++iter )
  {
    if ( (*iter)->GetGroupEventId() == currentGroupEventId )
    {
      firstObjectEventId = (*iter)->GetObjectEventId();
    }
    else break;
  }

  return firstObjectEventId;
}

<commit_msg>FIX check for NULL<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "mitkLimitedLinearUndo.h"
#include <mitkRenderingManager.h>

mitk::LimitedLinearUndo::LimitedLinearUndo()
{
  // nothing to do
}

mitk::LimitedLinearUndo::~LimitedLinearUndo()
{
  m_UndoList.clear();
  m_RedoList.clear();
}

//##ModelId=3E5F5D8C00B2
bool mitk::LimitedLinearUndo::SetOperationEvent(UndoStackItem* stackItem)
{
  OperationEvent* operationEvent = dynamic_cast<OperationEvent*>(stackItem);
  if (!operationEvent) return false;

  // clear the redolist, if a new operation is saved
  if (!m_RedoList.empty())
  {
    m_RedoList.clear();
    InvokeEvent( RedoEmptyEvent() );
  }

  m_UndoList.push_back(operationEvent);

  InvokeEvent( UndoNotEmptyEvent() );

  return true;
}

bool mitk::LimitedLinearUndo::Undo(bool fine)
{
  if (fine)
  {
    // undo one object event ID
    return Undo();
  }
  else
  {
    // undo one group event ID
    int oeid = FirstObjectEventIdOfCurrentGroup(m_UndoList); // get the Object Event ID of the first item with a differnt Group ID (as seen from the end of stack)
    return Undo(oeid);
  }
}

bool mitk::LimitedLinearUndo::Undo()
{
  if(m_UndoList.empty()) return false;

  int undoObjectEventId = m_UndoList.back()->GetObjectEventId();
  return Undo( undoObjectEventId );
}

bool mitk::LimitedLinearUndo::Undo(int oeid)
{
  if(m_UndoList.empty()) return false;

  do
  {
    m_UndoList.back()->ReverseAndExecute();

    m_RedoList.push_back(m_UndoList.back());  // move to redo stack
    m_UndoList.pop_back();                    // delete last operation from undo-list
    InvokeEvent( RedoNotEmptyEvent() );

    if (m_UndoList.empty())
    {
      InvokeEvent( UndoEmptyEvent() );
      return false;
    }
  }
  while ( m_UndoList.back()->GetObjectEventId() >= oeid );

  //Update. This should belong into the ExecuteOperation() of OperationActors, but it seems not to be used everywhere
  mitk::RenderingManager::GetInstance()->RequestUpdateAll();
  return true;
}

//##ModelId=3E5F5D8C00DA
bool mitk::LimitedLinearUndo::Redo(bool)
{
  return Redo();
}

bool mitk::LimitedLinearUndo::Redo()
{
  if (m_RedoList.empty()) return false;

  int redoObjectEventId = m_RedoList.back()->GetObjectEventId();
  return Redo( redoObjectEventId );
}

bool mitk::LimitedLinearUndo::Redo(int oeid)
{
  if (m_RedoList.empty()) return false;

  do
  {
    m_RedoList.back()->ReverseAndExecute();

    m_UndoList.push_back(m_RedoList.back());
    m_RedoList.pop_back();
    InvokeEvent( UndoNotEmptyEvent() );

    if (m_RedoList.empty())
    {
      InvokeEvent( RedoEmptyEvent() );
      break;
    }
  }
  while ( m_RedoList.back()->GetObjectEventId() <= oeid );

  //Update. This should belong into the ExecuteOperation() of OperationActors, but it seems not to be used everywhere
  mitk::RenderingManager::GetInstance()->RequestUpdateAll();
  return true;
}

//##ModelId=3F04519601A4
void mitk::LimitedLinearUndo::Clear()
{
  m_UndoList.clear();
  InvokeEvent( UndoEmptyEvent() );

  m_RedoList.clear();
  InvokeEvent( RedoEmptyEvent() );
}

//##ModelId=3F04519601B5
void mitk::LimitedLinearUndo::ClearRedoList()
{
  m_RedoList.clear();
  InvokeEvent( RedoEmptyEvent() );
}

//##ModelId=3F04519601D3
bool mitk::LimitedLinearUndo::RedoListEmpty()
{
  return m_RedoList.empty();
}

int mitk::LimitedLinearUndo::GetLastObjectEventIdInList()
{
  return m_UndoList.back()->GetObjectEventId();
}

int mitk::LimitedLinearUndo::GetLastGroupEventIdInList()
{
  return m_UndoList.back()->GetGroupEventId();
}

mitk::OperationEvent* mitk::LimitedLinearUndo::GetLastOfType(OperationActor* destination, OperationType opType)
{
  // When/where is this function needed? In CoordinateSupplier...
  for ( UndoContainerRevIter iter = m_UndoList.rbegin(); iter != m_UndoList.rend(); ++iter )
  {
    OperationEvent* opEvent = dynamic_cast<OperationEvent*>(*iter);
    if (!opEvent) continue;

    if (   opEvent->GetOperation() != NULL
        && opEvent->GetOperation()->GetOperationType() == opType
        && opEvent->IsValid()
        && opEvent->GetDestination() == destination )
      return opEvent;
  }

  return NULL;
}

int mitk::LimitedLinearUndo::FirstObjectEventIdOfCurrentGroup(mitk::LimitedLinearUndo::UndoContainer& stack)
{
  int currentGroupEventId = stack.back()->GetGroupEventId();
  int firstObjectEventId = -1;

  for ( UndoContainerRevIter iter = stack.rbegin(); iter != stack.rend(); ++iter )
  {
    if ( (*iter)->GetGroupEventId() == currentGroupEventId )
    {
      firstObjectEventId = (*iter)->GetObjectEventId();
    }
    else break;
  }

  return firstObjectEventId;
}

<|endoftext|>


<commit_before>#include <ContextQuartz2D.h>

#include <iostream>
#include <cassert>

#include <ImageIO/ImageIO.h>

using namespace canvas;
using namespace std;

Quartz2DSurface::Quartz2DSurface(Quartz2DCache * _cache, const Image & image)
  : Surface(image.getWidth(), image.getHeight(), image.getWidth(), image.getHeight(), image.getFormat().hasAlpha() ? RGBA8 : RGB8), cache(_cache) {
  assert(getActualWidth() && getActualHeight());
  size_t bitmapByteCount = 4 * getActualWidth() * getActualHeight();
  bitmapData = new unsigned char[bitmapByteCount];
  if (image.getFormat().getBytesPerPixel() == 4) {
    memcpy(bitmapData, image.getData(), bitmapByteCount);
  } else {
    for (unsigned int i = 0; i < getActualWidth() * getActualHeight(); i++) {
      bitmapData[4 * i + 0] = image.getData()[3 * i + 2];
      bitmapData[4 * i + 1] = image.getData()[3 * i + 1];
      bitmapData[4 * i + 2] = image.getData()[3 * i + 0];
      bitmapData[4 * i + 3] = 255;
    }
  }
}

Quartz2DSurface::Quartz2DSurface(Quartz2DCache * _cache, const std::string & filename)
  : Surface(0, 0, 0, 0, RGBA8), cache(_cache) {
  CGDataProviderRef provider = CGDataProviderCreateWithFilename(filename.c_str());
  CGImageRef img;
  if (filename.size() >= 4 && filename.compare(filename.size() - 4, 4, ".png") == 0) {
    img = CGImageCreateWithPNGDataProvider(provider, 0, false, kCGRenderingIntentDefault);
  } else if (filename.size() >= 4 && filename.compare(filename.size() - 4, 4, ".jpg") == 0) {
    img = CGImageCreateWithJPEGDataProvider(provider, 0, false, kCGRenderingIntentDefault);
  } else {
    cerr << "could not open file " << filename << endl;
    assert(0);
    img = 0;
  }
  if (img) {
    bool has_alpha = CGImageGetAlphaInfo(img) != kCGImageAlphaNone;
    Surface::resize(CGImageGetWidth(img), CGImageGetHeight(img), CGImageGetWidth(img), CGImageGetHeight(img), has_alpha ? RGBA8 : RGB8);
    unsigned int bitmapByteCount = 4 * getActualWidth() * getActualHeight();
    bitmapData = new unsigned char[bitmapByteCount];
    memset(bitmapData, 0, bitmapByteCount);

    initializeContext();
    flipY();
    CGContextDrawImage(gc, CGRectMake(0, 0, getActualWidth(), getActualHeight()), img);
    if (CFGetRetainCount(img) != 1) cerr << "leaking memory 1!\n";
    CGImageRelease(img);
    flipY();
  } else {
    Surface::resize(16, 16, 16, 16, RGBA8);
    unsigned int bitmapByteCount = 4 * getActualWidth() * getActualHeight();
    bitmapData = new unsigned char[bitmapByteCount];
    memset(bitmapData, 0, bitmapByteCount);
  }
  if (CFGetRetainCount(provider) != 1) cerr << "leaking memory 2!\n";
  CGDataProviderRelease(provider);
}

Quartz2DSurface::Quartz2DSurface(Quartz2DCache * _cache, const unsigned char * buffer, size_t size) : Surface(0, 0, 0, 0, RGBA8), cache(_cache) {
  CGImageRef img = 0;
  CGDataProviderRef provider = 0;
  if (isPNG(buffer, size)) {
    provider = CGDataProviderCreateWithData(0, buffer, size, 0);
    img = CGImageCreateWithPNGDataProvider(provider, 0, false, kCGRenderingIntentDefault);
  } else if (isJPEG(buffer, size)) {
    provider = CGDataProviderCreateWithData(0, buffer, size, 0);
    img = CGImageCreateWithJPEGDataProvider(provider, 0, false, kCGRenderingIntentDefault);
  } else if (isGIF(buffer, size) || isBMP(buffer, size)) {
    CFDataRef data = CFDataCreate(0, buffer, size);
    CFStringRef keys[3] = { kCGImageSourceShouldCache, kCGImageSourceCreateThumbnailFromImageIfAbsent, kCGImageSourceCreateThumbnailFromImageAlways };
    CFTypeRef values[3] = { kCFBooleanFalse, kCFBooleanFalse, kCFBooleanFalse };
    CFDictionaryRef options = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    // sizeof(keys) / sizeof(keys[0])
    auto isrc = CGImageSourceCreateWithData(data, options);
    img = CGImageSourceCreateImageAtIndex(isrc, 0, options);
    if (CFGetRetainCount(isrc) != 1) cerr << "leaking memory 3!\n";
    CFRelease(isrc);
    if (CFGetRetainCount(options) != 1) cerr << "leaking memory 4!\n";
    CFRelease(options);
    long data_retain = CFGetRetainCount(data);
    if (data_retain != 1) cerr << "leaking memory 5 (" << data_retain << ")!\n";
    CFRelease(data);
  } else if (isXML(buffer, size)) {
    cerr << "trying to render XML/HTML" << endl;
    assert(0);
  } else {
    cerr << "unhandled image type 1 = " << (int)buffer[0] << " 2 = " << (int)buffer[1] << " 3 = " << (int)buffer[2] << " 4 = " << (int)buffer[3] << " 5 = " << (int)buffer[4] << " 6 = " << (int)buffer[5] << endl;
    assert(0);
  }
  if (img) {
    bool has_alpha = CGImageGetAlphaInfo(img) != kCGImageAlphaNone;
    Surface::resize(CGImageGetWidth(img), CGImageGetHeight(img), CGImageGetWidth(img), CGImageGetHeight(img), has_alpha ? RGBA8 : RGB8);
    unsigned int bitmapByteCount = 4 * getActualWidth() * getActualHeight();
    bitmapData = new unsigned char[bitmapByteCount];
    memset(bitmapData, 0, bitmapByteCount);

    initializeContext();
    flipY();
    CGContextDrawImage(gc, CGRectMake(0, 0, getActualWidth(), getActualHeight()), img);
    flipY();
  } else {
    Surface::resize(16, 16, 16, 16, RGBA8);
    unsigned int bitmapByteCount = 4 * getActualWidth() * getActualHeight();
    bitmapData = new unsigned char[bitmapByteCount];
    memset(bitmapData, 0, bitmapByteCount);
  }
  if (img) {
    if (CFGetRetainCount(img) != 1) cerr << "leaking CGImage!\n";
    CGImageRelease(img);
  }
  if (provider) {
    if (CFGetRetainCount(provider) != 1) cerr << "leaking CGDataProvider!\n";
    CGDataProviderRelease(provider);
  }
}

void
Quartz2DSurface::sendPath(const Path2D & path, float scale) {
  initializeContext();
  CGContextBeginPath(gc);
  for (auto pc : path.getData()) {
    switch (pc.type) {
    case PathComponent::MOVE_TO: CGContextMoveToPoint(gc, pc.x0 * scale + 0.5, pc.y0 * scale + 0.5); break;
    case PathComponent::LINE_TO: CGContextAddLineToPoint(gc, pc.x0 * scale + 0.5, pc.y0 * scale + 0.5); break;
    case PathComponent::ARC: CGContextAddArc(gc, pc.x0 * scale + 0.5, pc.y0 * scale + 0.5, pc.radius * scale, pc.sa, pc.ea, pc.anticlockwise); break;
    case PathComponent::CLOSE: CGContextClosePath(gc); break;
    }
  }
}

void
Quartz2DSurface::renderPath(RenderMode mode, const Path2D & path, const Style & style, float lineWidth, Operator op, float display_scale, float globalAlpha, float shadowBlur, float shadowOffsetX, float shadowOffsetY, const Color & shadowColor, const Path2D & clipPath) {
  initializeContext();

  bool has_shadow = shadowBlur > 0.0f || shadowOffsetX != 0.0f || shadowOffsetY != 0.0f;
  if (has_shadow || !clipPath.empty()) {
    CGContextSaveGState(gc);
  }
  if (!clipPath.empty()) {
    sendPath(clipPath, display_scale);
    CGContextClip(gc);
  }
  if (has_shadow) {
    setShadow(shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, display_scale);
  }

  switch (op) {
  case SOURCE_OVER:
    CGContextSetBlendMode(gc, kCGBlendModeNormal);
    break;
  case COPY:
    CGContextSetBlendMode(gc, kCGBlendModeCopy);
    break;
  }
  switch (mode) {
  case STROKE:
    sendPath(path, display_scale);
    CGContextSetRGBStrokeColor(gc, style.color.red,
			       style.color.green,
			       style.color.blue,
			       style.color.alpha * globalAlpha);
    CGContextSetLineWidth(gc, lineWidth * display_scale);
    CGContextStrokePath(gc);
    break;
  case FILL:
    if (style.getType() == Style::LINEAR_GRADIENT) {
      const std::map<float, Color> & colors = style.getColors();
      if (!colors.empty()) {
	std::map<float, Color>::const_iterator it0 = colors.begin(), it1 = colors.end();
	it1--;
	const Color & c0 = it0->second, c1 = it1->second;

	size_t num_locations = 2;
	CGFloat locations[2] = { 0.0, 1.0 };
	CGFloat components[8] = {
	  c0.red, c0.green, c0.blue, c0.alpha * globalAlpha,
	  c1.red, c1.green, c1.blue, c1.alpha * globalAlpha
	};

	CGGradientRef myGradient = CGGradientCreateWithColorComponents(cache->getColorSpace(), components, locations, num_locations);

        CGContextSaveGState(gc);
        sendPath(path, display_scale);
        CGContextClip(gc);

	CGPoint myStartPoint, myEndPoint;
	myStartPoint.x = style.x0 * display_scale;
	myStartPoint.y = style.y0 * display_scale;
	myEndPoint.x = style.x1 * display_scale;
	myEndPoint.y = style.y1 * display_scale;
	CGContextDrawLinearGradient(gc, myGradient, myStartPoint, myEndPoint, 0);

        CGContextRestoreGState(gc);

	if (CFGetRetainCount(myGradient) != 1) cerr << "leaking memory 7!\n";
	CGGradientRelease(myGradient);
      }
    } else {
      sendPath(path, display_scale);
      CGContextSetRGBFillColor(gc, style.color.red,
			       style.color.green,
			       style.color.blue,
			       style.color.alpha * globalAlpha);
      CGContextFillPath(gc);
    }
  }
  if (op != SOURCE_OVER) {
    CGContextSetBlendMode(gc, kCGBlendModeNormal);
  }
  if (has_shadow || !clipPath.empty()) {
    CGContextRestoreGState(gc);
  }
}

void
ContextQuartz2d::resize(unsigned int _logical_width, unsigned int _logical_height, unsigned int _actual_width, unsigned int _actual_height, InternalFormat _format) {
  Surface::resize(_logical_width, _logical_height, _actual_width, _actual_height, _format);

  if (gc) {
    if (CFGetRetainCount(gc) != 1) std::cerr << "leaking memory E!\n";
    CGContextRelease(gc);
    gc = 0;
  }
  delete[] bitmapData;

  assert(getActualWidth() && getActualHeight());
  unsigned int bitmapByteCount = 4 * getActualWidth() * getActualHeight();
  bitmapData = new unsigned char[bitmapByteCount];
  memset(bitmapData, 0, bitmapByteCount);
}

void
ContextQuartz2d::drawImage(const Image & _img, const Point & p, double w, double h, float displayScale, float globalAlpha, float shadowBlur, float shadowOffsetX, float shadowOffsetY, const Color & shadowColor, const Path2D & clipPath, bool imageSmoothingEnabled) {
  initializeContext();
  bool has_shadow = shadowBlur > 0.0f || shadowOffsetX != 0.0f || shadowOffsetY != 0.0f;
  if (has_shadow || !clipPath.empty()) {
    CGContextSaveGState(gc);
  }
  if (!clipPath.empty()) {
    sendPath(clipPath, displayScale);
    CGContextClip(gc);
  }
  if (has_shadow) {
    setShadow(shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, displayScale);
  }
  auto & format = _img.getFormat();
  CGDataProviderRef provider = CGDataProviderCreateWithData(0, _img.getData(), format.getBytesPerPixel() * _img.getWidth() * _img.getHeight(), 0);
  assert(format.getBytesPerPixel() == 4);
  auto f = (format.hasAlpha() ? kCGImageAlphaPremultipliedLast : kCGImageAlphaNoneSkipLast);
  CGImageRef img = CGImageCreate(_img.getWidth(), _img.getHeight(), 8, format.getBytesPerPixel() * 8, format.getBytesPerPixel() * _img.getWidth(), cache->getColorSpace(), f, provider, 0, imageSmoothingEnabled, kCGRenderingIntentDefault);
  assert(img);
  flipY();
  if (globalAlpha < 1.0f) CGContextSetAlpha(gc, globalAlpha);
  CGContextDrawImage(gc, CGRectMake(displayScale * p.x, getActualHeight() - 1 - displayScale * (p.y + h), displayScale * w, displayScale * h), img);
  if (globalAlpha < 1.0f) CGContextSetAlpha(gc, 1.0f);
  flipY();

  if (CFGetRetainCount(img) != 1) std::cerr << "leaking memory O!\n";
  CGImageRelease(img);
  if (CFGetRetainCount(provider) != 1) std::cerr << "leaking memory P!\n";
  CGDataProviderRelease(provider);
  if (has_shadow || !clipPath.empty()) {
    CGContextRestoreGState(gc);
  }
}
<commit_msg>change Image::getFormat() to Image::getImageFormat(), fix wrong class names<commit_after>#include <ContextQuartz2D.h>

#include <iostream>
#include <cassert>

#include <ImageIO/ImageIO.h>

using namespace canvas;
using namespace std;

Quartz2DSurface::Quartz2DSurface(Quartz2DCache * _cache, const Image & image)
  : Surface(image.getWidth(), image.getHeight(), image.getWidth(), image.getHeight(), image.getImageFormat().hasAlpha() ? RGBA8 : RGB8), cache(_cache) {
  assert(getActualWidth() && getActualHeight());
  size_t bitmapByteCount = 4 * getActualWidth() * getActualHeight();
  bitmapData = new unsigned char[bitmapByteCount];
  if (image.getImageFormat().getBytesPerPixel() == 4) {
    memcpy(bitmapData, image.getData(), bitmapByteCount);
  } else {
    for (unsigned int i = 0; i < getActualWidth() * getActualHeight(); i++) {
      bitmapData[4 * i + 0] = image.getData()[3 * i + 2];
      bitmapData[4 * i + 1] = image.getData()[3 * i + 1];
      bitmapData[4 * i + 2] = image.getData()[3 * i + 0];
      bitmapData[4 * i + 3] = 255;
    }
  }
}

Quartz2DSurface::Quartz2DSurface(Quartz2DCache * _cache, const std::string & filename)
  : Surface(0, 0, 0, 0, RGBA8), cache(_cache) {
  CGDataProviderRef provider = CGDataProviderCreateWithFilename(filename.c_str());
  CGImageRef img;
  if (filename.size() >= 4 && filename.compare(filename.size() - 4, 4, ".png") == 0) {
    img = CGImageCreateWithPNGDataProvider(provider, 0, false, kCGRenderingIntentDefault);
  } else if (filename.size() >= 4 && filename.compare(filename.size() - 4, 4, ".jpg") == 0) {
    img = CGImageCreateWithJPEGDataProvider(provider, 0, false, kCGRenderingIntentDefault);
  } else {
    cerr << "could not open file " << filename << endl;
    assert(0);
    img = 0;
  }
  if (img) {
    bool has_alpha = CGImageGetAlphaInfo(img) != kCGImageAlphaNone;
    Surface::resize(CGImageGetWidth(img), CGImageGetHeight(img), CGImageGetWidth(img), CGImageGetHeight(img), has_alpha ? RGBA8 : RGB8);
    unsigned int bitmapByteCount = 4 * getActualWidth() * getActualHeight();
    bitmapData = new unsigned char[bitmapByteCount];
    memset(bitmapData, 0, bitmapByteCount);

    initializeContext();
    flipY();
    CGContextDrawImage(gc, CGRectMake(0, 0, getActualWidth(), getActualHeight()), img);
    if (CFGetRetainCount(img) != 1) cerr << "leaking memory 1!\n";
    CGImageRelease(img);
    flipY();
  } else {
    Surface::resize(16, 16, 16, 16, RGBA8);
    unsigned int bitmapByteCount = 4 * getActualWidth() * getActualHeight();
    bitmapData = new unsigned char[bitmapByteCount];
    memset(bitmapData, 0, bitmapByteCount);
  }
  if (CFGetRetainCount(provider) != 1) cerr << "leaking memory 2!\n";
  CGDataProviderRelease(provider);
}

Quartz2DSurface::Quartz2DSurface(Quartz2DCache * _cache, const unsigned char * buffer, size_t size) : Surface(0, 0, 0, 0, RGBA8), cache(_cache) {
  CGImageRef img = 0;
  CGDataProviderRef provider = 0;
  if (isPNG(buffer, size)) {
    provider = CGDataProviderCreateWithData(0, buffer, size, 0);
    img = CGImageCreateWithPNGDataProvider(provider, 0, false, kCGRenderingIntentDefault);
  } else if (isJPEG(buffer, size)) {
    provider = CGDataProviderCreateWithData(0, buffer, size, 0);
    img = CGImageCreateWithJPEGDataProvider(provider, 0, false, kCGRenderingIntentDefault);
  } else if (isGIF(buffer, size) || isBMP(buffer, size)) {
    CFDataRef data = CFDataCreate(0, buffer, size);
    CFStringRef keys[3] = { kCGImageSourceShouldCache, kCGImageSourceCreateThumbnailFromImageIfAbsent, kCGImageSourceCreateThumbnailFromImageAlways };
    CFTypeRef values[3] = { kCFBooleanFalse, kCFBooleanFalse, kCFBooleanFalse };
    CFDictionaryRef options = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    // sizeof(keys) / sizeof(keys[0])
    auto isrc = CGImageSourceCreateWithData(data, options);
    img = CGImageSourceCreateImageAtIndex(isrc, 0, options);
    if (CFGetRetainCount(isrc) != 1) cerr << "leaking memory 3!\n";
    CFRelease(isrc);
    if (CFGetRetainCount(options) != 1) cerr << "leaking memory 4!\n";
    CFRelease(options);
    long data_retain = CFGetRetainCount(data);
    if (data_retain != 1) cerr << "leaking memory 5 (" << data_retain << ")!\n";
    CFRelease(data);
  } else if (isXML(buffer, size)) {
    cerr << "trying to render XML/HTML" << endl;
    assert(0);
  } else {
    cerr << "unhandled image type 1 = " << (int)buffer[0] << " 2 = " << (int)buffer[1] << " 3 = " << (int)buffer[2] << " 4 = " << (int)buffer[3] << " 5 = " << (int)buffer[4] << " 6 = " << (int)buffer[5] << endl;
    assert(0);
  }
  if (img) {
    bool has_alpha = CGImageGetAlphaInfo(img) != kCGImageAlphaNone;
    Surface::resize(CGImageGetWidth(img), CGImageGetHeight(img), CGImageGetWidth(img), CGImageGetHeight(img), has_alpha ? RGBA8 : RGB8);
    unsigned int bitmapByteCount = 4 * getActualWidth() * getActualHeight();
    bitmapData = new unsigned char[bitmapByteCount];
    memset(bitmapData, 0, bitmapByteCount);

    initializeContext();
    flipY();
    CGContextDrawImage(gc, CGRectMake(0, 0, getActualWidth(), getActualHeight()), img);
    flipY();
  } else {
    Surface::resize(16, 16, 16, 16, RGBA8);
    unsigned int bitmapByteCount = 4 * getActualWidth() * getActualHeight();
    bitmapData = new unsigned char[bitmapByteCount];
    memset(bitmapData, 0, bitmapByteCount);
  }
  if (img) {
    if (CFGetRetainCount(img) != 1) cerr << "leaking CGImage!\n";
    CGImageRelease(img);
  }
  if (provider) {
    if (CFGetRetainCount(provider) != 1) cerr << "leaking CGDataProvider!\n";
    CGDataProviderRelease(provider);
  }
}

void
Quartz2DSurface::sendPath(const Path2D & path, float scale) {
  initializeContext();
  CGContextBeginPath(gc);
  for (auto pc : path.getData()) {
    switch (pc.type) {
    case PathComponent::MOVE_TO: CGContextMoveToPoint(gc, pc.x0 * scale + 0.5, pc.y0 * scale + 0.5); break;
    case PathComponent::LINE_TO: CGContextAddLineToPoint(gc, pc.x0 * scale + 0.5, pc.y0 * scale + 0.5); break;
    case PathComponent::ARC: CGContextAddArc(gc, pc.x0 * scale + 0.5, pc.y0 * scale + 0.5, pc.radius * scale, pc.sa, pc.ea, pc.anticlockwise); break;
    case PathComponent::CLOSE: CGContextClosePath(gc); break;
    }
  }
}

void
Quartz2DSurface::renderPath(RenderMode mode, const Path2D & path, const Style & style, float lineWidth, Operator op, float display_scale, float globalAlpha, float shadowBlur, float shadowOffsetX, float shadowOffsetY, const Color & shadowColor, const Path2D & clipPath) {
  initializeContext();

  bool has_shadow = shadowBlur > 0.0f || shadowOffsetX != 0.0f || shadowOffsetY != 0.0f;
  if (has_shadow || !clipPath.empty()) {
    CGContextSaveGState(gc);
  }
  if (!clipPath.empty()) {
    sendPath(clipPath, display_scale);
    CGContextClip(gc);
  }
  if (has_shadow) {
    setShadow(shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, display_scale);
  }

  switch (op) {
  case SOURCE_OVER:
    CGContextSetBlendMode(gc, kCGBlendModeNormal);
    break;
  case COPY:
    CGContextSetBlendMode(gc, kCGBlendModeCopy);
    break;
  }
  switch (mode) {
  case STROKE:
    sendPath(path, display_scale);
    CGContextSetRGBStrokeColor(gc, style.color.red,
			       style.color.green,
			       style.color.blue,
			       style.color.alpha * globalAlpha);
    CGContextSetLineWidth(gc, lineWidth * display_scale);
    CGContextStrokePath(gc);
    break;
  case FILL:
    if (style.getType() == Style::LINEAR_GRADIENT) {
      const std::map<float, Color> & colors = style.getColors();
      if (!colors.empty()) {
	std::map<float, Color>::const_iterator it0 = colors.begin(), it1 = colors.end();
	it1--;
	const Color & c0 = it0->second, c1 = it1->second;

	size_t num_locations = 2;
	CGFloat locations[2] = { 0.0, 1.0 };
	CGFloat components[8] = {
	  c0.red, c0.green, c0.blue, c0.alpha * globalAlpha,
	  c1.red, c1.green, c1.blue, c1.alpha * globalAlpha
	};

	CGGradientRef myGradient = CGGradientCreateWithColorComponents(cache->getColorSpace(), components, locations, num_locations);

        CGContextSaveGState(gc);
        sendPath(path, display_scale);
        CGContextClip(gc);

	CGPoint myStartPoint, myEndPoint;
	myStartPoint.x = style.x0 * display_scale;
	myStartPoint.y = style.y0 * display_scale;
	myEndPoint.x = style.x1 * display_scale;
	myEndPoint.y = style.y1 * display_scale;
	CGContextDrawLinearGradient(gc, myGradient, myStartPoint, myEndPoint, 0);

        CGContextRestoreGState(gc);

	if (CFGetRetainCount(myGradient) != 1) cerr << "leaking memory 7!\n";
	CGGradientRelease(myGradient);
      }
    } else {
      sendPath(path, display_scale);
      CGContextSetRGBFillColor(gc, style.color.red,
			       style.color.green,
			       style.color.blue,
			       style.color.alpha * globalAlpha);
      CGContextFillPath(gc);
    }
  }
  if (op != SOURCE_OVER) {
    CGContextSetBlendMode(gc, kCGBlendModeNormal);
  }
  if (has_shadow || !clipPath.empty()) {
    CGContextRestoreGState(gc);
  }
}

void
Quartz2DSurface::resize(unsigned int _logical_width, unsigned int _logical_height, unsigned int _actual_width, unsigned int _actual_height, InternalFormat _format) {
  Surface::resize(_logical_width, _logical_height, _actual_width, _actual_height, _format);

  if (gc) {
    if (CFGetRetainCount(gc) != 1) std::cerr << "leaking memory E!\n";
    CGContextRelease(gc);
    gc = 0;
  }
  delete[] bitmapData;

  assert(getActualWidth() && getActualHeight());
  unsigned int bitmapByteCount = 4 * getActualWidth() * getActualHeight();
  bitmapData = new unsigned char[bitmapByteCount];
  memset(bitmapData, 0, bitmapByteCount);
}

void
Quartz2DSurface::drawImage(const Image & _img, const Point & p, double w, double h, float displayScale, float globalAlpha, float shadowBlur, float shadowOffsetX, float shadowOffsetY, const Color & shadowColor, const Path2D & clipPath, bool imageSmoothingEnabled) {
  initializeContext();
  bool has_shadow = shadowBlur > 0.0f || shadowOffsetX != 0.0f || shadowOffsetY != 0.0f;
  if (has_shadow || !clipPath.empty()) {
    CGContextSaveGState(gc);
  }
  if (!clipPath.empty()) {
    sendPath(clipPath, displayScale);
    CGContextClip(gc);
  }
  if (has_shadow) {
    setShadow(shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, displayScale);
  }
  auto format = _img.getImageFormat();
  CGDataProviderRef provider = CGDataProviderCreateWithData(0, _img.getData(), format.getBytesPerPixel() * _img.getWidth() * _img.getHeight(), 0);
  assert(format.getBytesPerPixel() == 4);
  auto f = (format.hasAlpha() ? kCGImageAlphaPremultipliedLast : kCGImageAlphaNoneSkipLast);
  CGImageRef img = CGImageCreate(_img.getWidth(), _img.getHeight(), 8, format.getBytesPerPixel() * 8, format.getBytesPerPixel() * _img.getWidth(), cache->getColorSpace(), f, provider, 0, imageSmoothingEnabled, kCGRenderingIntentDefault);
  assert(img);
  flipY();
  if (globalAlpha < 1.0f) CGContextSetAlpha(gc, globalAlpha);
  CGContextDrawImage(gc, CGRectMake(displayScale * p.x, getActualHeight() - 1 - displayScale * (p.y + h), displayScale * w, displayScale * h), img);
  if (globalAlpha < 1.0f) CGContextSetAlpha(gc, 1.0f);
  flipY();

  if (CFGetRetainCount(img) != 1) std::cerr << "leaking memory O!\n";
  CGImageRelease(img);
  if (CFGetRetainCount(provider) != 1) std::cerr << "leaking memory P!\n";
  CGDataProviderRelease(provider);
  if (has_shadow || !clipPath.empty()) {
    CGContextRestoreGState(gc);
  }
}
<|endoftext|>


<commit_before>#include "Convolution.hpp"

extern "C"
mlopenStatus_t mlopenCreateConvolutionDescriptor(
		mlopenConvolutionDescriptor_t *convDesc) {

	if(convDesc == nullptr) {
		return mlopenStatusBadParm;
	}

	try {
		*convDesc = new mlopenConvolutionDescriptor();
	} catch (mlopenStatus_t status) {
		return status;
	}

	return mlopenStatusSuccess;
}

extern "C"
mlopenStatus_t mlopenInitConvolutionDescriptor(mlopenConvolutionDescriptor_t convDesc,
		mlopenConvolutionMode_t	mode,
		int						pad_h,
		int						pad_w,
		int						u,
		int						v,
		int						upscalex,
		int						upscaley) {

	if(convDesc == nullptr) {
		return mlopenStatusBadParm;
	}
	if(pad_h < 0 || pad_w < 0) {
		return mlopenStatusBadParm;
	}
	if(u < 0 || v < 0) {
		return mlopenStatusBadParm;
	}

	convDesc->_mode		= mode;
	convDesc->_pad_h	= pad_h;
	convDesc->_pad_w	= pad_w;
	convDesc->_u		= u;
	convDesc->_v		= v;
	convDesc->_upscalex = upscalex;
	convDesc->_upscaley = upscaley;

	return mlopenStatusSuccess;
}

extern "C"
mlopenStatus_t mlopenGetConvolutionDescriptor(mlopenConvolutionDescriptor_t convDesc,
		mlopenConvolutionMode_t *mode,
		int						*pad_h,
		int						*pad_w,
		int						*u,
		int						*v,
		int						*upscalex,
		int						*upscaley) {
	if(convDesc == nullptr) {
		return mlopenStatusBadParm;
	}

	*mode		= convDesc->_mode;
	*pad_h		= convDesc->_pad_h;
	*pad_w		= convDesc->_pad_w;
	*u			= convDesc->_u;
	*v			= convDesc->_v;
	*upscalex	= convDesc->_upscalex;
	*upscaley	= convDesc->_upscaley;

	return mlopenStatusSuccess;
}

extern "C"
mlopenStatus_t mlopenGetConvolutionForwardOutputDim(mlopenConvolutionDescriptor_t convDesc,
		const mlopenTensorDescriptor_t	inputTensorDesc,
		const mlopenTensorDescriptor_t	filterDesc,
		int								*n,
		int								*c,
		int								*h,
		int								*w) {

	return convDesc->GetForwardOutputDim(inputTensorDesc,
			filterDesc,
			n,
			c,
			h,
			w);
}

extern "C"
mlopenStatus_t mlopenDestroyConvolutionDescriptor(mlopenConvolutionDescriptor_t convDesc) {
	try {
		delete convDesc;
	} catch (mlopenStatus_t status) {
		return status;
	}
	return mlopenStatusSuccess;
}

extern "C"
mlopenStatus_t mlopenFindConvolutionForwardAlgorithm(mlopenHandle_t handle,
		const mlopenTensorDescriptor_t		xDesc,
		const void							*x,
		const mlopenTensorDescriptor_t		wDesc,
		const void							*w,
		const mlopenConvolutionDescriptor_t	convDesc,
		const mlopenTensorDescriptor_t		yDesc,
		const void							*y,
		const int							requestAlgoCount,
		int									*returnedAlgoCount,
		mlopenConvAlgoPerf_t				*perfResults,
		mlopenConvPreference_t				preference,
		void								*workSpace,
		size_t								workSpaceSize) {

	return convDesc->FindConvFwdAlgorithm(handle,
			xDesc,
			DataCast(x),
			wDesc,
			DataCast(w),
			yDesc,
			DataCast(y),
			requestAlgoCount,
			returnedAlgoCount,
			perfResults,
			preference,
			workSpace,
			workSpaceSize);

}

extern "C"
mlopenStatus_t mlopenConvolutionForward(mlopenHandle_t handle,
		const void							*alpha,
		const mlopenTensorDescriptor_t		xDesc,
		const void							*x,
		const mlopenTensorDescriptor_t		wDesc,
		const void							*w,
		const mlopenConvolutionDescriptor_t convDesc,
		mlopenConvFwdAlgorithm_t			algo,
		const void							*beta,
		const mlopenTensorDescriptor_t		 yDesc,
		void								*y,
		void								*workSpace,
		size_t								workSpaceSize) {

	return convDesc->ConvolutionForward(handle,
			alpha,
			xDesc,
			DataCast(x),
			wDesc,
			DataCast(w),
			algo,
			beta,
			yDesc,
			DataCast(y),
			workSpace,
			workSpaceSize);

}

extern "C"
mlopenStatus_t mlopenFindConvolutionBackwardDataAlgorithm(mlopenHandle_t handle,
		const mlopenTensorDescriptor_t		dyDesc,
		const void							*dy,
		const mlopenTensorDescriptor_t		wDesc,
		const void							*w,
		const mlopenConvolutionDescriptor_t	convDesc,
		const mlopenTensorDescriptor_t		dxDesc,
		const void							*dx,
		const int							requestAlgoCount,
		int									*returnedAlgoCount,
		mlopenConvAlgoPerf_t				*perfResults,
		mlopenConvPreference_t				preference,
		void								*workSpace,
		size_t								workSpaceSize) {

	return convDesc->FindConvBwdDataAlgorithm(handle,
			dyDesc,
			DataCast(dy),
			wDesc,
			DataCast(w),
			dxDesc,
			DataCast(dx),
			requestAlgoCount,
			returnedAlgoCount,
			perfResults,
			preference,
			workSpace,
			workSpaceSize);
}

extern "C"
mlopenStatus_t mlopenConvolutionBackwardData(mlopenHandle_t handle,
		const void							*alpha,
		const mlopenTensorDescriptor_t		dyDesc,
		const void							*dy,
		const mlopenTensorDescriptor_t		wDesc,
		const void							*w,
		const mlopenConvolutionDescriptor_t convDesc,
		mlopenConvBwdDataAlgorithm_t		algo,
		const void							*beta,
		const mlopenTensorDescriptor_t		dxDesc,
		void								*dx,
		void								*workSpace,
		size_t								workSpaceSize) {

	return convDesc->ConvolutionBackwardData(handle,
			alpha,
			dyDesc,
			DataCast(dy),
			wDesc,
			DataCast(w),
			algo,
			beta,
			dxDesc,
			DataCast(dx),
			workSpace,
			workSpaceSize);
}

<commit_msg>Update convulution api to use error handling<commit_after>#include "Convolution.hpp"
#include <errors.hpp>

extern "C"
mlopenStatus_t mlopenCreateConvolutionDescriptor(
		mlopenConvolutionDescriptor_t *convDesc) {

	return mlopen::try_([&] {
		mlopen::deref(convDesc) = new mlopenConvolutionDescriptor();
	});
}

extern "C"
mlopenStatus_t mlopenInitConvolutionDescriptor(mlopenConvolutionDescriptor_t convDesc,
		mlopenConvolutionMode_t	mode,
		int						pad_h,
		int						pad_w,
		int						u,
		int						v,
		int						upscalex,
		int						upscaley) {

	if(convDesc == nullptr) {
		return mlopenStatusBadParm;
	}
	if(pad_h < 0 || pad_w < 0) {
		return mlopenStatusBadParm;
	}
	if(u < 0 || v < 0) {
		return mlopenStatusBadParm;
	}

	return mlopen::try_([&] {
		convDesc->_mode		= mode;
		convDesc->_pad_h	= pad_h;
		convDesc->_pad_w	= pad_w;
		convDesc->_u		= u;
		convDesc->_v		= v;
		convDesc->_upscalex = upscalex;
		convDesc->_upscaley = upscaley;
	});
}

extern "C"
mlopenStatus_t mlopenGetConvolutionDescriptor(mlopenConvolutionDescriptor_t convDesc,
		mlopenConvolutionMode_t *mode,
		int						*pad_h,
		int						*pad_w,
		int						*u,
		int						*v,
		int						*upscalex,
		int						*upscaley) {

	return mlopen::try_([&] {
		mlopen::deref(mode)		= convDesc->_mode;
		mlopen::deref(pad_h)		= convDesc->_pad_h;
		mlopen::deref(pad_w)		= convDesc->_pad_w;
		mlopen::deref(u)			= convDesc->_u;
		mlopen::deref(v)			= convDesc->_v;
		mlopen::deref(upscalex)	= convDesc->_upscalex;
		mlopen::deref(upscaley)	= convDesc->_upscaley;
	});
}

extern "C"
mlopenStatus_t mlopenGetConvolutionForwardOutputDim(mlopenConvolutionDescriptor_t convDesc,
		const mlopenTensorDescriptor_t	inputTensorDesc,
		const mlopenTensorDescriptor_t	filterDesc,
		int								*n,
		int								*c,
		int								*h,
		int								*w) {

	return mlopen::try_([&] {
		convDesc->GetForwardOutputDim(inputTensorDesc,
				filterDesc,
				n,
				c,
				h,
				w);
	});

}

extern "C"
mlopenStatus_t mlopenDestroyConvolutionDescriptor(mlopenConvolutionDescriptor_t convDesc) {
	return mlopen::try_([&] {
		delete convDesc;
	});
}

extern "C"
mlopenStatus_t mlopenFindConvolutionForwardAlgorithm(mlopenHandle_t handle,
		const mlopenTensorDescriptor_t		xDesc,
		const void							*x,
		const mlopenTensorDescriptor_t		wDesc,
		const void							*w,
		const mlopenConvolutionDescriptor_t	convDesc,
		const mlopenTensorDescriptor_t		yDesc,
		const void							*y,
		const int							requestAlgoCount,
		int									*returnedAlgoCount,
		mlopenConvAlgoPerf_t				*perfResults,
		mlopenConvPreference_t				preference,
		void								*workSpace,
		size_t								workSpaceSize) {

	return mlopen::try_([&] {
		convDesc->FindConvFwdAlgorithm(handle,
				xDesc,
				DataCast(x),
				wDesc,
				DataCast(w),
				yDesc,
				DataCast(y),
				requestAlgoCount,
				returnedAlgoCount,
				perfResults,
				preference,
				workSpace,
				workSpaceSize);
	});

}

extern "C"
mlopenStatus_t mlopenConvolutionForward(mlopenHandle_t handle,
		const void							*alpha,
		const mlopenTensorDescriptor_t		xDesc,
		const void							*x,
		const mlopenTensorDescriptor_t		wDesc,
		const void							*w,
		const mlopenConvolutionDescriptor_t convDesc,
		mlopenConvFwdAlgorithm_t			algo,
		const void							*beta,
		const mlopenTensorDescriptor_t		 yDesc,
		void								*y,
		void								*workSpace,
		size_t								workSpaceSize) {

	return mlopen::try_([&] {
		convDesc->ConvolutionForward(handle,
				alpha,
				xDesc,
				DataCast(x),
				wDesc,
				DataCast(w),
				algo,
				beta,
				yDesc,
				DataCast(y),
				workSpace,
				workSpaceSize);
	});

}

extern "C"
mlopenStatus_t mlopenFindConvolutionBackwardDataAlgorithm(mlopenHandle_t handle,
		const mlopenTensorDescriptor_t		dyDesc,
		const void							*dy,
		const mlopenTensorDescriptor_t		wDesc,
		const void							*w,
		const mlopenConvolutionDescriptor_t	convDesc,
		const mlopenTensorDescriptor_t		dxDesc,
		const void							*dx,
		const int							requestAlgoCount,
		int									*returnedAlgoCount,
		mlopenConvAlgoPerf_t				*perfResults,
		mlopenConvPreference_t				preference,
		void								*workSpace,
		size_t								workSpaceSize) {

	return mlopen::try_([&] {
		convDesc->FindConvBwdDataAlgorithm(handle,
				dyDesc,
				DataCast(dy),
				wDesc,
				DataCast(w),
				dxDesc,
				DataCast(dx),
				requestAlgoCount,
				returnedAlgoCount,
				perfResults,
				preference,
				workSpace,
				workSpaceSize);
	});

}

extern "C"
mlopenStatus_t mlopenConvolutionBackwardData(mlopenHandle_t handle,
		const void							*alpha,
		const mlopenTensorDescriptor_t		dyDesc,
		const void							*dy,
		const mlopenTensorDescriptor_t		wDesc,
		const void							*w,
		const mlopenConvolutionDescriptor_t convDesc,
		mlopenConvBwdDataAlgorithm_t		algo,
		const void							*beta,
		const mlopenTensorDescriptor_t		dxDesc,
		void								*dx,
		void								*workSpace,
		size_t								workSpaceSize) {

	return mlopen::try_([&] {
		convDesc->ConvolutionBackwardData(handle,
				alpha,
				dyDesc,
				DataCast(dy),
				wDesc,
				DataCast(w),
				algo,
				beta,
				dxDesc,
				DataCast(dx),
				workSpace,
				workSpaceSize);
	});

}

<|endoftext|>