<commit_before>#include "uinput_device.h"

#include "ros/ros.h"
#include <linux/input.h>
#include <linux/uinput.h>
#include <linux/types.h>
#include <algorithm>
#include <fcntl.h>
#include <stdio.h>
#include <sstream>
#include <string>

#include "util.h"
#include <lg_msg_defs/EvdevEvent.h>
#include <lg_msg_defs/EvdevEvents.h>
#include <lg_msg_defs/EvdevDeviceInfo.h>

// emulate a typical ELO touchscreen
const __s32 MIN_TRACKING_ID = 0;
const __s32 MAX_TRACKING_ID = 65535;
const __s32 MIN_SLOT = 0;
const __s32 MAX_SLOT = 7;

UinputDeviceInitError::UinputDeviceInitError(const char* msg): msg_(msg) {}
UinputDeviceInitError::UinputDeviceInitError(const std::string& msg): msg_(msg) {}
UinputDeviceInitError::~UinputDeviceInitError() throw() {}
const char* UinputDeviceInitError::what() const throw() {
  return msg_.c_str();
}

/**
 * \brief Constructor
 * \param device_name Human-readable name for the virtual device.
 */
UinputDevice::UinputDevice(const std::string& device_name, bool translate_to_multitouch):
  fd_(-1),
  device_name_(device_name),
  translate_to_multitouch_(translate_to_multitouch),
  offscreen_x_(0),
  offscreen_y_(0)
{}

/**
 * \brief Creates the uinput device.
 * \param info Information about the source device.
 * \return true if successful.
 */
bool UinputDevice::Init(const lg_msg_defs::EvdevDeviceInfoResponse& info) {
  int fd;

  // open the special uinput device
  fd = open(UinputDeviceConstants::UINPUT_PATH, O_WRONLY | O_NONBLOCK);
  if (fd < 0) {
    perror("opening the uinput node");
    return false;
  }

  try {
    InitDevice_(fd, info);
  } catch (UinputDeviceInitError& e) {
    ROS_ERROR_STREAM(e.what());
    close(fd);
    return false;
  }

  // fd is now a handle for the user device
  fd_ = fd;
  return true;
}

/**
 * \brief Internal helper for creating the uinput device.
 *
 * Throws UinputDeviceInitError on failure.
 *
 * \param fd File descriptor to operate on.
 * \param info Information about the source device.
 */
void UinputDevice::InitDevice_(int fd, const lg_msg_defs::EvdevDeviceInfoResponse& info) {
  struct uinput_user_dev uidev;
  int status;

  // initialize the user device struct
  memset(&uidev, 0, sizeof(uidev));

  // set allowed device types and codes
  std::size_t i;
  std::size_t sz;
  sz = info.types.size();
  for (i = 0; i < sz; i++) {
    EnableCode_(fd, UI_SET_EVBIT, info.types[i]);
  }

  sz = info.key_codes.size();
  for (i = 0; i < sz; i++) {
    __u16 code = info.key_codes[i];

    if (translate_to_multitouch_ && code == BTN_LEFT) {
      code = BTN_TOUCH;
    }

    EnableCode_(fd, UI_SET_KEYBIT, code);
  }

  sz = info.rel_codes.size();
  for (i = 0; i < sz; i++) {
    EnableCode_(fd, UI_SET_RELBIT, info.rel_codes[i]);
  }

  sz = info.abs_codes.size();
  for (i = 0; i < sz; i++) {
    __u16 code = info.abs_codes[i];

    if (i > info.abs_min.size() || i > info.abs_max.size()) {
      std::ostringstream error_msg;
      error_msg << "Device info missing abs_min or abs_max for abs code " << code << " at index " << i;
      throw UinputDeviceInitError(error_msg.str());
    }
    EnableCode_(fd, UI_SET_ABSBIT, code);
    uidev.absmax[code] = info.abs_max[i];
    uidev.absmin[code] = info.abs_min[i];

    // set offscreen coords to maximums
    if (code == ABS_X) {
      offscreen_x_ = info.abs_max[i];
    } else if (code == ABS_Y) {
      offscreen_y_ = info.abs_max[i];
    }

    if (translate_to_multitouch_) {
      if (code == ABS_X) {
        EnableCode_(fd, UI_SET_ABSBIT, ABS_MT_POSITION_X);
        uidev.absmax[ABS_MT_POSITION_X] = info.abs_max[i];
        uidev.absmin[ABS_MT_POSITION_X] = info.abs_min[i];
      } else if (code == ABS_Y) {
        EnableCode_(fd, UI_SET_ABSBIT, ABS_MT_POSITION_Y);
        uidev.absmax[ABS_MT_POSITION_Y] = info.abs_max[i];
        uidev.absmin[ABS_MT_POSITION_Y] = info.abs_min[i];
      }
    }
  }

  if (translate_to_multitouch_) {
    EnableCode_(fd, UI_SET_ABSBIT, ABS_MT_TRACKING_ID);
    uidev.absmax[ABS_MT_TRACKING_ID] = MAX_TRACKING_ID;
    uidev.absmin[ABS_MT_TRACKING_ID] = MIN_TRACKING_ID;
    EnableCode_(fd, UI_SET_ABSBIT, ABS_MT_SLOT);
    uidev.absmax[ABS_MT_TRACKING_ID] = MAX_SLOT;
    uidev.absmin[ABS_MT_TRACKING_ID] = MIN_SLOT;
  }

  // set the device name
  strncpy(uidev.name, device_name_.c_str(), UINPUT_MAX_NAME_SIZE);

  // set more device attributes
  uidev.id.bustype = info.bustype;
  uidev.id.vendor = info.vendor;
  uidev.id.product = info.product;
  uidev.id.version = info.version;

  // write the device information
  status = write(fd, &uidev, sizeof(uidev));
  if (status != sizeof(uidev)) {
    throw UinputDeviceInitError("Error writing to uinput device");
  }

  // create the device
  status = ioctl(fd, UI_DEV_CREATE);
  if (status != 0) {
    throw UinputDeviceInitError("Error on ioctl UI_DEV_CREATE");
  }

  ROS_DEBUG(
    "Created device: %s with vendor: %d product: %d version: %d",
    uidev.name, uidev.id.vendor, uidev.id.product, uidev.id.version
  );
}

/**
 * \brief Shortcut for enabling an event type or code during virtual device setup.
 *
 * Throws UinputDeviceInitError on failure.
 *
 * \param fd File descriptor to write to.
 * \param codeBits Bitmask describing which type of event code to enable.
 * \param code Event code to be enabled.
 */
void UinputDevice::EnableCode_(int fd, int codeBits, int code) {
  int status = ioctl(fd, codeBits, code);
  if (status != 0) {
    std::ostringstream error_msg;
    error_msg << "Failed to enable code " << codeBits << ":" << code;
    throw UinputDeviceInitError(error_msg.str());
  }
}

/**
 * \brief Waits for the virtual device to appear in the xinput list.
 *
 * Breaks if ROS is shutdown.
 *
 * \return true if the device is available.
 */
bool UinputDevice::WaitForXinput() {
  using util::exec;

  const unsigned int MAX_INTERVAL = 999999;// usec
  unsigned int interval = 10000; // usec

  std::ostringstream cmd;
  cmd << "xinput query-state '" << device_name_ << "'";

  while (true) {
    usleep(std::min(interval, MAX_INTERVAL));

    if (!ros::ok()) {
      return false;
    }

    int status = system(cmd.str().c_str());
    if (status == 0) {
      return true;
    }

    interval *= 2;
    if (interval > (MAX_INTERVAL*5)) {
      ROS_ERROR("Couldn't find device after many attempts... shutting down");
      ros::shutdown();
    }
  }
}

/**
 * \brief Floats the xinput device pointer.
 * \return true if successful.
 */
bool UinputDevice::FloatPointer() const {
  std::ostringstream cmd;
  cmd << "/usr/bin/xinput float '" << device_name_ << "'";

  int status = system(cmd.str().c_str());
  return status == 0;
}

/**
 * \brief Handles a ROS message containing a vector of events.
 *
 * Implicitly writes a SYN event after the incoming events.
 *
 * Shuts down ROS upon failure.
 *
 * \param msg A message describing one or more evdev events.
 */
void UinputDevice::HandleEventMessage(const lg_msg_defs::EvdevEvents::Ptr& msg) {
  if (fd_ < 0) {
    ROS_ERROR("Tried to handle an event message, but UinputDevice was not initialized");
    ros::shutdown();
    return;
  }

  std::size_t num_events = msg->events.size();

  if (translate_to_multitouch_) {
    for (int i = 0; i < num_events; i++) {
      lg_msg_defs::EvdevEvent ev = msg->events[i];

      __u16 type = ev.type;
      __u16 code = ev.code;
      __s32 value = ev.value;

      if (type == EV_KEY) {
        if (code == BTN_LEFT) {
          if (value == 1) {
            if (!WriteEvent_(EV_ABS, ABS_MT_TRACKING_ID, 1)) {
              ROS_ERROR("Error while writing an event to the device");
              ros::shutdown();
              return;
            }
          } else if (value == 0) {
            if (!WriteEvent_(EV_ABS, ABS_MT_TRACKING_ID, -1)) {
              ROS_ERROR("Error while writing an event to the device");
              ros::shutdown();
              return;
            }
          }
        }
      }
      else if (type == EV_ABS) {
        if (code == ABS_X) {
          if (!WriteEvent_(EV_ABS, ABS_MT_POSITION_X, value)) {
            ROS_ERROR("Error while writing an event to the device");
            ros::shutdown();
            return;
          }
        }
        else if (code == ABS_Y) {
          if (!WriteEvent_(EV_ABS, ABS_MT_POSITION_Y, value)) {
            ROS_ERROR("Error while writing an event to the device");
            ros::shutdown();
            return;
          }
        }
      }
    }
  }

  for (int i = 0; i < num_events; i++) {
    lg_msg_defs::EvdevEvent ev = msg->events[i];

    __u16 type = ev.type;
    __u16 code = ev.code;
    __s32 value = ev.value;

    if (translate_to_multitouch_) {
      if (type == EV_KEY && code == BTN_LEFT) {
        code = BTN_TOUCH;
      }
    }

    if (!WriteEvent_(type, code, value)) {
      ROS_ERROR("Error while writing an event to the device");
      ros::shutdown();
      return;
    }

  }

  // force an EV_SYN after each message
  if (!WriteEvent_(EV_SYN, SYN_REPORT, 0)) {
    ROS_ERROR("Error while writing a SYN event");
    ros::shutdown();
    return;
  }
}

/**
 * \brief Zeroes the ABS position to clear the cursor.
 */
void UinputDevice::Zero() {
  WriteEvent_(EV_ABS, ABS_X, offscreen_x_);
  WriteEvent_(EV_ABS, ABS_Y, offscreen_y_);
  WriteEvent_(EV_SYN, SYN_REPORT, 0);
}

/*
 * \brief Writes an event to the virtual device.
 * \param type Event type.
 * \param code Event code.
 * \param value Event value.
 * \return true if successful.
 */
bool UinputDevice::WriteEvent_(__u16 type, __u16 code, __s32 value) {
  struct input_event ev;

  memset(&ev, 0, sizeof(ev));

  ev.type = type;
  ev.code = code;
  ev.value = value;

  int num_wrote = write(fd_, &ev, sizeof(ev));

  if (num_wrote != sizeof(ev)) {
    return false;
  }

  ROS_DEBUG(
    "Wrote type: %d code: %d value: %d",
    ev.type, ev.code, ev.value
  );

  return true;
}
<commit_msg>Fix multitouch spoofing for TOUCH codes<commit_after>#include "uinput_device.h"

#include "ros/ros.h"
#include <linux/input.h>
#include <linux/uinput.h>
#include <linux/types.h>
#include <algorithm>
#include <fcntl.h>
#include <stdio.h>
#include <sstream>
#include <string>

#include "util.h"
#include <lg_msg_defs/EvdevEvent.h>
#include <lg_msg_defs/EvdevEvents.h>
#include <lg_msg_defs/EvdevDeviceInfo.h>

// emulate a typical ELO touchscreen
const __s32 MIN_TRACKING_ID = 0;
const __s32 MAX_TRACKING_ID = 65535;
const __s32 MIN_SLOT = 0;
const __s32 MAX_SLOT = 7;

UinputDeviceInitError::UinputDeviceInitError(const char* msg): msg_(msg) {}
UinputDeviceInitError::UinputDeviceInitError(const std::string& msg): msg_(msg) {}
UinputDeviceInitError::~UinputDeviceInitError() throw() {}
const char* UinputDeviceInitError::what() const throw() {
  return msg_.c_str();
}

/**
 * \brief Constructor
 * \param device_name Human-readable name for the virtual device.
 */
UinputDevice::UinputDevice(const std::string& device_name, bool translate_to_multitouch):
  fd_(-1),
  device_name_(device_name),
  translate_to_multitouch_(translate_to_multitouch),
  offscreen_x_(0),
  offscreen_y_(0)
{}

/**
 * \brief Creates the uinput device.
 * \param info Information about the source device.
 * \return true if successful.
 */
bool UinputDevice::Init(const lg_msg_defs::EvdevDeviceInfoResponse& info) {
  int fd;

  // open the special uinput device
  fd = open(UinputDeviceConstants::UINPUT_PATH, O_WRONLY | O_NONBLOCK);
  if (fd < 0) {
    perror("opening the uinput node");
    return false;
  }

  try {
    InitDevice_(fd, info);
  } catch (UinputDeviceInitError& e) {
    ROS_ERROR_STREAM(e.what());
    close(fd);
    return false;
  }

  // fd is now a handle for the user device
  fd_ = fd;
  return true;
}

/**
 * \brief Internal helper for creating the uinput device.
 *
 * Throws UinputDeviceInitError on failure.
 *
 * \param fd File descriptor to operate on.
 * \param info Information about the source device.
 */
void UinputDevice::InitDevice_(int fd, const lg_msg_defs::EvdevDeviceInfoResponse& info) {
  struct uinput_user_dev uidev;
  int status;

  // initialize the user device struct
  memset(&uidev, 0, sizeof(uidev));

  // set allowed device types and codes
  std::size_t i;
  std::size_t sz;
  sz = info.types.size();
  for (i = 0; i < sz; i++) {
    EnableCode_(fd, UI_SET_EVBIT, info.types[i]);
  }

  sz = info.key_codes.size();
  for (i = 0; i < sz; i++) {
    __u16 code = info.key_codes[i];

    if (translate_to_multitouch_ && code == BTN_LEFT) {
      code = BTN_TOUCH;
    }

    EnableCode_(fd, UI_SET_KEYBIT, code);
  }

  sz = info.rel_codes.size();
  for (i = 0; i < sz; i++) {
    EnableCode_(fd, UI_SET_RELBIT, info.rel_codes[i]);
  }

  sz = info.abs_codes.size();
  for (i = 0; i < sz; i++) {
    __u16 code = info.abs_codes[i];

    if (i > info.abs_min.size() || i > info.abs_max.size()) {
      std::ostringstream error_msg;
      error_msg << "Device info missing abs_min or abs_max for abs code " << code << " at index " << i;
      throw UinputDeviceInitError(error_msg.str());
    }
    EnableCode_(fd, UI_SET_ABSBIT, code);
    uidev.absmax[code] = info.abs_max[i];
    uidev.absmin[code] = info.abs_min[i];

    // set offscreen coords to maximums
    if (code == ABS_X) {
      offscreen_x_ = info.abs_max[i];
    } else if (code == ABS_Y) {
      offscreen_y_ = info.abs_max[i];
    }

    if (translate_to_multitouch_) {
      if (code == ABS_X) {
        EnableCode_(fd, UI_SET_ABSBIT, ABS_MT_POSITION_X);
        uidev.absmax[ABS_MT_POSITION_X] = info.abs_max[i];
        uidev.absmin[ABS_MT_POSITION_X] = info.abs_min[i];
      } else if (code == ABS_Y) {
        EnableCode_(fd, UI_SET_ABSBIT, ABS_MT_POSITION_Y);
        uidev.absmax[ABS_MT_POSITION_Y] = info.abs_max[i];
        uidev.absmin[ABS_MT_POSITION_Y] = info.abs_min[i];
      }
    }
  }

  if (translate_to_multitouch_) {
    EnableCode_(fd, UI_SET_ABSBIT, ABS_MT_TRACKING_ID);
    uidev.absmax[ABS_MT_TRACKING_ID] = MAX_TRACKING_ID;
    uidev.absmin[ABS_MT_TRACKING_ID] = MIN_TRACKING_ID;
    EnableCode_(fd, UI_SET_ABSBIT, ABS_MT_SLOT);
    uidev.absmax[ABS_MT_TRACKING_ID] = MAX_SLOT;
    uidev.absmin[ABS_MT_TRACKING_ID] = MIN_SLOT;
  }

  // set the device name
  strncpy(uidev.name, device_name_.c_str(), UINPUT_MAX_NAME_SIZE);

  // set more device attributes
  uidev.id.bustype = info.bustype;
  uidev.id.vendor = info.vendor;
  uidev.id.product = info.product;
  uidev.id.version = info.version;

  // write the device information
  status = write(fd, &uidev, sizeof(uidev));
  if (status != sizeof(uidev)) {
    throw UinputDeviceInitError("Error writing to uinput device");
  }

  // create the device
  status = ioctl(fd, UI_DEV_CREATE);
  if (status != 0) {
    throw UinputDeviceInitError("Error on ioctl UI_DEV_CREATE");
  }

  ROS_DEBUG(
    "Created device: %s with vendor: %d product: %d version: %d",
    uidev.name, uidev.id.vendor, uidev.id.product, uidev.id.version
  );
}

/**
 * \brief Shortcut for enabling an event type or code during virtual device setup.
 *
 * Throws UinputDeviceInitError on failure.
 *
 * \param fd File descriptor to write to.
 * \param codeBits Bitmask describing which type of event code to enable.
 * \param code Event code to be enabled.
 */
void UinputDevice::EnableCode_(int fd, int codeBits, int code) {
  int status = ioctl(fd, codeBits, code);
  if (status != 0) {
    std::ostringstream error_msg;
    error_msg << "Failed to enable code " << codeBits << ":" << code;
    throw UinputDeviceInitError(error_msg.str());
  }
}

/**
 * \brief Waits for the virtual device to appear in the xinput list.
 *
 * Breaks if ROS is shutdown.
 *
 * \return true if the device is available.
 */
bool UinputDevice::WaitForXinput() {
  using util::exec;

  const unsigned int MAX_INTERVAL = 999999;// usec
  unsigned int interval = 10000; // usec

  std::ostringstream cmd;
  cmd << "xinput query-state '" << device_name_ << "'";

  while (true) {
    usleep(std::min(interval, MAX_INTERVAL));

    if (!ros::ok()) {
      return false;
    }

    int status = system(cmd.str().c_str());
    if (status == 0) {
      return true;
    }

    interval *= 2;
    if (interval > (MAX_INTERVAL*5)) {
      ROS_ERROR("Couldn't find device after many attempts... shutting down");
      ros::shutdown();
    }
  }
}

/**
 * \brief Floats the xinput device pointer.
 * \return true if successful.
 */
bool UinputDevice::FloatPointer() const {
  std::ostringstream cmd;
  cmd << "/usr/bin/xinput float '" << device_name_ << "'";

  int status = system(cmd.str().c_str());
  return status == 0;
}

/**
 * \brief Handles a ROS message containing a vector of events.
 *
 * Implicitly writes a SYN event after the incoming events.
 *
 * Shuts down ROS upon failure.
 *
 * \param msg A message describing one or more evdev events.
 */
void UinputDevice::HandleEventMessage(const lg_msg_defs::EvdevEvents::Ptr& msg) {
  if (fd_ < 0) {
    ROS_ERROR("Tried to handle an event message, but UinputDevice was not initialized");
    ros::shutdown();
    return;
  }

  std::size_t num_events = msg->events.size();

  if (translate_to_multitouch_) {
    for (int i = 0; i < num_events; i++) {
      lg_msg_defs::EvdevEvent ev = msg->events[i];

      __u16 type = ev.type;
      __u16 code = ev.code;
      __s32 value = ev.value;

      if (type == EV_KEY) {
        if (code == BTN_LEFT || code == BTN_TOUCH) {
          if (value == 1) {
            if (!WriteEvent_(EV_ABS, ABS_MT_TRACKING_ID, 1)) {
              ROS_ERROR("Error while writing an event to the device");
              ros::shutdown();
              return;
            }
          } else if (value == 0) {
            if (!WriteEvent_(EV_ABS, ABS_MT_TRACKING_ID, -1)) {
              ROS_ERROR("Error while writing an event to the device");
              ros::shutdown();
              return;
            }
          }
        }
      }
      else if (type == EV_ABS) {
        if (code == ABS_X) {
          if (!WriteEvent_(EV_ABS, ABS_MT_POSITION_X, value)) {
            ROS_ERROR("Error while writing an event to the device");
            ros::shutdown();
            return;
          }
        }
        else if (code == ABS_Y) {
          if (!WriteEvent_(EV_ABS, ABS_MT_POSITION_Y, value)) {
            ROS_ERROR("Error while writing an event to the device");
            ros::shutdown();
            return;
          }
        }
      }
    }
  }

  for (int i = 0; i < num_events; i++) {
    lg_msg_defs::EvdevEvent ev = msg->events[i];

    __u16 type = ev.type;
    __u16 code = ev.code;
    __s32 value = ev.value;

    if (translate_to_multitouch_) {
      if (type == EV_KEY && code == BTN_LEFT) {
        code = BTN_TOUCH;
      }
    }

    if (!WriteEvent_(type, code, value)) {
      ROS_ERROR("Error while writing an event to the device");
      ros::shutdown();
      return;
    }

  }

  // force an EV_SYN after each message
  if (!WriteEvent_(EV_SYN, SYN_REPORT, 0)) {
    ROS_ERROR("Error while writing a SYN event");
    ros::shutdown();
    return;
  }
}

/**
 * \brief Zeroes the ABS position to clear the cursor.
 */
void UinputDevice::Zero() {
  WriteEvent_(EV_ABS, ABS_X, offscreen_x_);
  WriteEvent_(EV_ABS, ABS_Y, offscreen_y_);
  WriteEvent_(EV_SYN, SYN_REPORT, 0);
}

/*
 * \brief Writes an event to the virtual device.
 * \param type Event type.
 * \param code Event code.
 * \param value Event value.
 * \return true if successful.
 */
bool UinputDevice::WriteEvent_(__u16 type, __u16 code, __s32 value) {
  struct input_event ev;

  memset(&ev, 0, sizeof(ev));

  ev.type = type;
  ev.code = code;
  ev.value = value;

  int num_wrote = write(fd_, &ev, sizeof(ev));

  if (num_wrote != sizeof(ev)) {
    return false;
  }

  ROS_DEBUG(
    "Wrote type: %d code: %d value: %d",
    ev.type, ev.code, ev.value
  );

  return true;
}
<|endoftext|>


<commit_before>//===------ MemoryBuiltins.cpp - Identify calls to memory builtins --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This family of functions identifies calls to builtin functions that allocate
// or free memory.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/MemoryBuiltins.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Module.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Target/TargetData.h"
using namespace llvm;

//===----------------------------------------------------------------------===//
//  malloc Call Utility Functions.
//

/// isMalloc - Returns true if the value is either a malloc call or a
/// bitcast of the result of a malloc call.
bool llvm::isMalloc(const Value *I) {
  return extractMallocCall(I) || extractMallocCallFromBitCast(I);
}

static bool isMallocCall(const CallInst *CI) {
  if (!CI)
    return false;

  Function *Callee = CI->getCalledFunction();
  if (Callee == 0 || !Callee->isDeclaration() || Callee->getName() != "malloc")
    return false;

  // Check malloc prototype.
  // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin
  // attribute will exist.
  const FunctionType *FTy = Callee->getFunctionType();
  if (FTy->getNumParams() != 1)
    return false;
  if (IntegerType *ITy = dyn_cast<IntegerType>(FTy->param_begin()->get())) {
    if (ITy->getBitWidth() != 32 && ITy->getBitWidth() != 64)
      return false;
    return true;
  }

  return false;
}

/// extractMallocCall - Returns the corresponding CallInst if the instruction
/// is a malloc call.  Since CallInst::CreateMalloc() only creates calls, we
/// ignore InvokeInst here.
const CallInst *llvm::extractMallocCall(const Value *I) {
  const CallInst *CI = dyn_cast<CallInst>(I);
  return (isMallocCall(CI)) ? CI : NULL;
}

CallInst *llvm::extractMallocCall(Value *I) {
  CallInst *CI = dyn_cast<CallInst>(I);
  return (isMallocCall(CI)) ? CI : NULL;
}

static bool isBitCastOfMallocCall(const BitCastInst *BCI) {
  if (!BCI)
    return false;

  return isMallocCall(dyn_cast<CallInst>(BCI->getOperand(0)));
}

/// extractMallocCallFromBitCast - Returns the corresponding CallInst if the
/// instruction is a bitcast of the result of a malloc call.
CallInst *llvm::extractMallocCallFromBitCast(Value *I) {
  BitCastInst *BCI = dyn_cast<BitCastInst>(I);
  return (isBitCastOfMallocCall(BCI)) ? cast<CallInst>(BCI->getOperand(0))
                                      : NULL;
}

const CallInst *llvm::extractMallocCallFromBitCast(const Value *I) {
  const BitCastInst *BCI = dyn_cast<BitCastInst>(I);
  return (isBitCastOfMallocCall(BCI)) ? cast<CallInst>(BCI->getOperand(0))
                                      : NULL;
}

static Value *computeArraySize(const CallInst *CI, const TargetData *TD,
                               bool LookThroughSExt = false) {
  if (!CI)
    return NULL;

  // The size of the malloc's result type must be known to determine array size.
  const Type *T = getMallocAllocatedType(CI);
  if (!T || !T->isSized() || !TD)
    return NULL;

  unsigned ElementSize = TD->getTypeAllocSize(T);
  if (const StructType *ST = dyn_cast<StructType>(T))
    ElementSize = TD->getStructLayout(ST)->getSizeInBytes();

  // If malloc call's arg can be determined to be a multiple of ElementSize,
  // return the multiple.  Otherwise, return NULL.
  Value *MallocArg = CI->getArgOperand(0);
  Value *Multiple = NULL;
  if (ComputeMultiple(MallocArg, ElementSize, Multiple,
                      LookThroughSExt))
    return Multiple;

  return NULL;
}

/// isArrayMalloc - Returns the corresponding CallInst if the instruction
/// is a call to malloc whose array size can be determined and the array size
/// is not constant 1.  Otherwise, return NULL.
const CallInst *llvm::isArrayMalloc(const Value *I, const TargetData *TD) {
  const CallInst *CI = extractMallocCall(I);
  Value *ArraySize = computeArraySize(CI, TD);

  if (ArraySize &&
      ArraySize != ConstantInt::get(CI->getArgOperand(0)->getType(), 1))
    return CI;

  // CI is a non-array malloc or we can't figure out that it is an array malloc.
  return NULL;
}

/// getMallocType - Returns the PointerType resulting from the malloc call.
/// The PointerType depends on the number of bitcast uses of the malloc call:
///   0: PointerType is the calls' return type.
///   1: PointerType is the bitcast's result type.
///  >1: Unique PointerType cannot be determined, return NULL.
const PointerType *llvm::getMallocType(const CallInst *CI) {
  assert(isMalloc(CI) && "getMallocType and not malloc call");

  const PointerType *MallocType = NULL;
  unsigned NumOfBitCastUses = 0;

  // Determine if CallInst has a bitcast use.
  for (Value::const_use_iterator UI = CI->use_begin(), E = CI->use_end();
       UI != E; )
    if (const BitCastInst *BCI = dyn_cast<BitCastInst>(*UI++)) {
      MallocType = cast<PointerType>(BCI->getDestTy());
      NumOfBitCastUses++;
    }

  // Malloc call has 1 bitcast use, so type is the bitcast's destination type.
  if (NumOfBitCastUses == 1)
    return MallocType;

  // Malloc call was not bitcast, so type is the malloc function's return type.
  if (NumOfBitCastUses == 0)
    return cast<PointerType>(CI->getType());

  // Type could not be determined.
  return NULL;
}

/// getMallocAllocatedType - Returns the Type allocated by malloc call.
/// The Type depends on the number of bitcast uses of the malloc call:
///   0: PointerType is the malloc calls' return type.
///   1: PointerType is the bitcast's result type.
///  >1: Unique PointerType cannot be determined, return NULL.
const Type *llvm::getMallocAllocatedType(const CallInst *CI) {
  const PointerType *PT = getMallocType(CI);
  return PT ? PT->getElementType() : NULL;
}

/// getMallocArraySize - Returns the array size of a malloc call.  If the
/// argument passed to malloc is a multiple of the size of the malloced type,
/// then return that multiple.  For non-array mallocs, the multiple is
/// constant 1.  Otherwise, return NULL for mallocs whose array size cannot be
/// determined.
Value *llvm::getMallocArraySize(CallInst *CI, const TargetData *TD,
                                bool LookThroughSExt) {
  assert(isMalloc(CI) && "getMallocArraySize and not malloc call");
  return computeArraySize(CI, TD, LookThroughSExt);
}

//===----------------------------------------------------------------------===//
//  free Call Utility Functions.
//

/// isFreeCall - Returns non-null if the value is a call to the builtin free()
const CallInst *llvm::isFreeCall(const Value *I) {
  const CallInst *CI = dyn_cast<CallInst>(I);
  if (!CI)
    return 0;
  Function *Callee = CI->getCalledFunction();
  if (Callee == 0 || !Callee->isDeclaration() || Callee->getName() != "free")
    return 0;

  // Check free prototype.
  // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin
  // attribute will exist.
  const FunctionType *FTy = Callee->getFunctionType();
  if (!FTy->getReturnType()->isVoidTy())
    return 0;
  if (FTy->getNumParams() != 1)
    return 0;
  if (FTy->param_begin()->get() != Type::getInt8PtrTy(Callee->getContext()))
    return 0;

  return CI;
}
<commit_msg>Add C++ global operator {new,new[],delete,delete[]}(unsigned {int,long}) to the memory builtins as equivalent to malloc/free.<commit_after>//===------ MemoryBuiltins.cpp - Identify calls to memory builtins --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This family of functions identifies calls to builtin functions that allocate
// or free memory.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/MemoryBuiltins.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Module.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Target/TargetData.h"
using namespace llvm;

//===----------------------------------------------------------------------===//
//  malloc Call Utility Functions.
//

/// isMalloc - Returns true if the value is either a malloc call or a
/// bitcast of the result of a malloc call.
bool llvm::isMalloc(const Value *I) {
  return extractMallocCall(I) || extractMallocCallFromBitCast(I);
}

static bool isMallocCall(const CallInst *CI) {
  if (!CI)
    return false;

  Function *Callee = CI->getCalledFunction();
  if (Callee == 0 || !Callee->isDeclaration())
    return false;
  if (Callee->getName() != "malloc" &&
      Callee->getName() != "_Znwj" && Callee->getName() != "_Znwm" &&
      Callee->getName() != "_Znaj" && Callee->getName() != "_Znam")
    return false;

  // Check malloc prototype.
  // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin
  // attribute will exist.
  const FunctionType *FTy = Callee->getFunctionType();
  if (FTy->getNumParams() != 1)
    return false;
  if (IntegerType *ITy = dyn_cast<IntegerType>(FTy->param_begin()->get())) {
    if (ITy->getBitWidth() != 32 && ITy->getBitWidth() != 64)
      return false;
    return true;
  }

  return false;
}

/// extractMallocCall - Returns the corresponding CallInst if the instruction
/// is a malloc call.  Since CallInst::CreateMalloc() only creates calls, we
/// ignore InvokeInst here.
const CallInst *llvm::extractMallocCall(const Value *I) {
  const CallInst *CI = dyn_cast<CallInst>(I);
  return (isMallocCall(CI)) ? CI : NULL;
}

CallInst *llvm::extractMallocCall(Value *I) {
  CallInst *CI = dyn_cast<CallInst>(I);
  return (isMallocCall(CI)) ? CI : NULL;
}

static bool isBitCastOfMallocCall(const BitCastInst *BCI) {
  if (!BCI)
    return false;

  return isMallocCall(dyn_cast<CallInst>(BCI->getOperand(0)));
}

/// extractMallocCallFromBitCast - Returns the corresponding CallInst if the
/// instruction is a bitcast of the result of a malloc call.
CallInst *llvm::extractMallocCallFromBitCast(Value *I) {
  BitCastInst *BCI = dyn_cast<BitCastInst>(I);
  return (isBitCastOfMallocCall(BCI)) ? cast<CallInst>(BCI->getOperand(0))
                                      : NULL;
}

const CallInst *llvm::extractMallocCallFromBitCast(const Value *I) {
  const BitCastInst *BCI = dyn_cast<BitCastInst>(I);
  return (isBitCastOfMallocCall(BCI)) ? cast<CallInst>(BCI->getOperand(0))
                                      : NULL;
}

static Value *computeArraySize(const CallInst *CI, const TargetData *TD,
                               bool LookThroughSExt = false) {
  if (!CI)
    return NULL;

  // The size of the malloc's result type must be known to determine array size.
  const Type *T = getMallocAllocatedType(CI);
  if (!T || !T->isSized() || !TD)
    return NULL;

  unsigned ElementSize = TD->getTypeAllocSize(T);
  if (const StructType *ST = dyn_cast<StructType>(T))
    ElementSize = TD->getStructLayout(ST)->getSizeInBytes();

  // If malloc call's arg can be determined to be a multiple of ElementSize,
  // return the multiple.  Otherwise, return NULL.
  Value *MallocArg = CI->getArgOperand(0);
  Value *Multiple = NULL;
  if (ComputeMultiple(MallocArg, ElementSize, Multiple,
                      LookThroughSExt))
    return Multiple;

  return NULL;
}

/// isArrayMalloc - Returns the corresponding CallInst if the instruction
/// is a call to malloc whose array size can be determined and the array size
/// is not constant 1.  Otherwise, return NULL.
const CallInst *llvm::isArrayMalloc(const Value *I, const TargetData *TD) {
  const CallInst *CI = extractMallocCall(I);
  Value *ArraySize = computeArraySize(CI, TD);

  if (ArraySize &&
      ArraySize != ConstantInt::get(CI->getArgOperand(0)->getType(), 1))
    return CI;

  // CI is a non-array malloc or we can't figure out that it is an array malloc.
  return NULL;
}

/// getMallocType - Returns the PointerType resulting from the malloc call.
/// The PointerType depends on the number of bitcast uses of the malloc call:
///   0: PointerType is the calls' return type.
///   1: PointerType is the bitcast's result type.
///  >1: Unique PointerType cannot be determined, return NULL.
const PointerType *llvm::getMallocType(const CallInst *CI) {
  assert(isMalloc(CI) && "getMallocType and not malloc call");

  const PointerType *MallocType = NULL;
  unsigned NumOfBitCastUses = 0;

  // Determine if CallInst has a bitcast use.
  for (Value::const_use_iterator UI = CI->use_begin(), E = CI->use_end();
       UI != E; )
    if (const BitCastInst *BCI = dyn_cast<BitCastInst>(*UI++)) {
      MallocType = cast<PointerType>(BCI->getDestTy());
      NumOfBitCastUses++;
    }

  // Malloc call has 1 bitcast use, so type is the bitcast's destination type.
  if (NumOfBitCastUses == 1)
    return MallocType;

  // Malloc call was not bitcast, so type is the malloc function's return type.
  if (NumOfBitCastUses == 0)
    return cast<PointerType>(CI->getType());

  // Type could not be determined.
  return NULL;
}

/// getMallocAllocatedType - Returns the Type allocated by malloc call.
/// The Type depends on the number of bitcast uses of the malloc call:
///   0: PointerType is the malloc calls' return type.
///   1: PointerType is the bitcast's result type.
///  >1: Unique PointerType cannot be determined, return NULL.
const Type *llvm::getMallocAllocatedType(const CallInst *CI) {
  const PointerType *PT = getMallocType(CI);
  return PT ? PT->getElementType() : NULL;
}

/// getMallocArraySize - Returns the array size of a malloc call.  If the
/// argument passed to malloc is a multiple of the size of the malloced type,
/// then return that multiple.  For non-array mallocs, the multiple is
/// constant 1.  Otherwise, return NULL for mallocs whose array size cannot be
/// determined.
Value *llvm::getMallocArraySize(CallInst *CI, const TargetData *TD,
                                bool LookThroughSExt) {
  assert(isMalloc(CI) && "getMallocArraySize and not malloc call");
  return computeArraySize(CI, TD, LookThroughSExt);
}

//===----------------------------------------------------------------------===//
//  free Call Utility Functions.
//

/// isFreeCall - Returns non-null if the value is a call to the builtin free()
const CallInst *llvm::isFreeCall(const Value *I) {
  const CallInst *CI = dyn_cast<CallInst>(I);
  if (!CI)
    return 0;
  Function *Callee = CI->getCalledFunction();
  if (Callee == 0 || !Callee->isDeclaration())
    return 0;

  if (Callee->getName() != "free" &&
      Callee->getName() != "_Zdlj" && Callee->getName() != "_Zdlm" &&
      Callee->getName() != "_Zdaj" && Callee->getName() != "_Zdam")
    return 0;

  // Check free prototype.
  // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin
  // attribute will exist.
  const FunctionType *FTy = Callee->getFunctionType();
  if (!FTy->getReturnType()->isVoidTy())
    return 0;
  if (FTy->getNumParams() != 1)
    return 0;
  if (FTy->param_begin()->get() != Type::getInt8PtrTy(Callee->getContext()))
    return 0;

  return CI;
}
<|endoftext|>


<commit_before>// Shor's algorithm
// Source: ./examples/shor.cpp
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <vector>

#include "qpp.h"

int main() {
    using namespace qpp;
    bigint N = 15; // number to factor
    bigint a = rand(static_cast<bigint>(3), N - 1); // random co-prime with N
    while (gcd(a, N) != 1) {
        a = rand(static_cast<bigint>(3), N - 1);
    }
    // qubits required for half of the circuit, in total we need 2n qubits
    // if you know the order 'r' of 'a', then you can take the smallest 'n' s.t.
    // 2^n >= 2 * r^2, i.e. n = ceil(log2(2 * r^2))
    idx n = static_cast<idx>(std::ceil(2 * std::log2(N)));
    idx D = static_cast<idx>(std::llround(std::pow(2, n))); // dimension 2^n

    std::cout << ">> Factoring N = " << N << " with coprime a = " << a << '\n';
    std::cout << ">> n = " << n << ", D = 2^n = " << D << " and 2^(2n) = ";
    std::cout << D * D << '\n';

    // vector with labels of the first half of the qubits
    std::vector<idx> first_subsys(n);
    std::iota(std::begin(first_subsys), std::end(first_subsys), 0);

    // vector with labels of the second half of the qubits
    std::vector<idx> second_subsys(n);
    std::iota(std::begin(second_subsys), std::end(second_subsys), n);

    // QUANTUM STAGE
    // prepare the initial state |0>^\otimes n \otimes |0...01>
    ket psi = kron(st.zero(2 * n - 1), 1_ket);

    // apply Hadamards H^\otimes n on first half of the qubits
    for (idx i = 0; i < n; ++i) {
        psi = apply(psi, gt.H, {i});
    }

    // perform the modular exponentiation as a sequence of
    // modular multiplications
    for (idx i = 0; i < n; ++i) {
        // compute 2^(n-i-1) mod N
        idx j = static_cast<idx>(std::llround(std::pow(2, n - i - 1)));
        // compute the a^(2^(n-i-1)) mod N
        idx aj = modpow(a, j, N);
        // apply the controlled modular multiplication
        psi = applyCTRL(psi, gt.MODMUL(aj, N, n), {i}, second_subsys);
    }

    // apply inverse QFT on first half of the qubits
    psi = applyINVQFT(psi, first_subsys);
    // END QUANTUM STAGE

    // FIRST MEASUREMENT STAGE
    auto measured1 = measure_seq(psi, first_subsys); // measure first n qubits
    auto list_results1 = std::get<0>(measured1);     // measurement results
    auto prob1 = std::get<1>(measured1); // probability of the result
    idx n1 = multiidx2n(list_results1, std::vector<idx>(n, 2)); // binary to int
    double x1 = static_cast<double>(n1) / D;

    std::cout << ">> First measurement:  " << disp(list_results1, " ") << " ";
    std::cout << "i.e. j = " << n1 << " with probability " << prob1;
    std::cout << '\n';

    bool failed = true;
    idx r1, c1;
    for (auto&& elem : convergents(x1, 10)) {
        std::tie(c1, r1) = elem;
        double c1r1 = static_cast<double>(c1) / r1;
        if (abs(x1 - c1r1) < 1. / std::pow(2, (n - 1) / 2.)) {
            failed = false;
            break;
        }
    }
    if (failed) {
        std::cout << ">> Factoring failed at stage 1, please try again!\n";
        std::exit(EXIT_FAILURE);
    }
    // END FIRST MEASUREMENT STAGE

    // SECOND MEASUREMENT STAGE
    auto measured2 = measure_seq(psi, first_subsys); // measure first n qubits
    auto list_results2 = std::get<0>(measured2);     // measurement results
    auto prob2 = std::get<1>(measured2); // probability of the result
    idx n2 = multiidx2n(list_results2, std::vector<idx>(n, 2)); // binary to int
    double x2 = static_cast<double>(n2) / D;

    std::cout << ">> Second measurement: " << disp(list_results2, " ") << " ";
    std::cout << "i.e. j = " << n2 << " with probability " << prob2;
    std::cout << '\n';

    failed = true;
    idx r2, c2;
    for (auto&& elem : convergents(x2, 10)) {
        std::tie(c2, r2) = elem;
        double c2r2 = static_cast<double>(c2) / r2;
        if (abs(x2 - c2r2) < 1. / std::pow(2, (n - 1) / 2.)) {
            failed = false;
            break;
        }
    }
    if (failed) {
        std::cout << ">> Factoring failed at stage 2, please try again!\n";
        std::exit(EXIT_FAILURE);
    }
    // END SECOND MEASUREMENT STAGE

    // THIRD POST-PROCESSING STAGE
    idx r = lcm(r1, r2); // candidate order of a mod N
    std::cout << ">> r = " << r << '\n';
    if (r % 2 == 0 && modpow(a, r / 2, N) != static_cast<bigint>(N - 1)) {
        std::cout << ">> Possible factors: ";
        std::cout << gcd(modpow(a, r / 2, N) - 1, N) << " ";
        std::cout << gcd(modpow(a, r / 2, N) + 1, N) << '\n';
    } else {
        std::cout << ">> Factoring failed at stage 3, please try again!\n";
        std::exit(EXIT_FAILURE);
    }
    // END THIRD POST-PROCESSING STAGE
}
<commit_msg>commit<commit_after>// Shor's algorithm
// Source: ./examples/shor.cpp
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <tuple>
#include <vector>

#include "qpp.h"

int main() {
    using namespace qpp;
    bigint N = 15; // number to factor
    bigint a = rand(static_cast<bigint>(3), N - 1); // random co-prime with N
    while (gcd(a, N) != 1) {
        a = rand(static_cast<bigint>(3), N - 1);
    }
    // qubits required for half of the circuit, in total we need 2n qubits
    // if you know the order 'r' of 'a', then you can take the smallest 'n' s.t.
    // 2^n >= 2 * r^2, i.e. n = ceil(log2(2 * r^2))
    idx n = static_cast<idx>(std::ceil(2 * std::log2(N)));
    idx D = static_cast<idx>(std::llround(std::pow(2, n))); // dimension 2^n

    std::cout << ">> Factoring N = " << N << " with coprime a = " << a << '\n';
    std::cout << ">> n = " << n << ", D = 2^n = " << D << " and 2^(2n) = ";
    std::cout << D * D << '\n';

    // vector with labels of the first half of the qubits
    std::vector<idx> first_subsys(n);
    std::iota(std::begin(first_subsys), std::end(first_subsys), 0);

    // vector with labels of the second half of the qubits
    std::vector<idx> second_subsys(n);
    std::iota(std::begin(second_subsys), std::end(second_subsys), n);

    // QUANTUM STAGE
    // prepare the initial state |0>^\otimes n \otimes |0...01>
    ket psi = kron(st.zero(2 * n - 1), 1_ket);

    // apply Hadamards H^\otimes n on first half of the qubits
    for (idx i = 0; i < n; ++i) {
        psi = apply(psi, gt.H, {i});
    }

    // perform the modular exponentiation as a sequence of
    // modular multiplications
    for (idx i = 0; i < n; ++i) {
        // compute 2^(n-i-1) mod N
        idx j = static_cast<idx>(std::llround(std::pow(2, n - i - 1)));
        // compute the a^(2^(n-i-1)) mod N
        idx aj = modpow(a, j, N);
        // apply the controlled modular multiplication
        psi = applyCTRL(psi, gt.MODMUL(aj, N, n), {i}, second_subsys);
    }

    // apply inverse QFT on first half of the qubits
    psi = applyINVQFT(psi, first_subsys);
    // END QUANTUM STAGE

    // FIRST MEASUREMENT STAGE
    auto measured1 = measure_seq(psi, first_subsys); // measure first n qubits
    auto list_results1 = std::get<0>(measured1);     // measurement results
    auto prob1 = std::get<1>(measured1); // probability of the result
    idx n1 = multiidx2n(list_results1, std::vector<idx>(n, 2)); // binary to int
    double x1 = static_cast<double>(n1) / D;

    std::cout << ">> First measurement:  " << disp(list_results1, " ") << " ";
    std::cout << "i.e. j = " << n1 << " with probability " << prob1;
    std::cout << '\n';

    bool failed = true;
    idx r1, c1;
    for (auto&& elem : convergents(x1, 10)) {
        std::tie(c1, r1) = elem;
        double c1r1 = static_cast<double>(c1) / r1;
        if (abs(x1 - c1r1) < 1. / std::pow(2, (n - 1) / 2.)) {
            failed = false;
            break;
        }
    }
    if (failed) {
        std::cout << ">> Factoring failed at stage 1, please try again!\n";
        std::exit(EXIT_FAILURE);
    }
    // END FIRST MEASUREMENT STAGE

    // SECOND MEASUREMENT STAGE
    auto measured2 = measure_seq(psi, first_subsys); // measure first n qubits
    auto list_results2 = std::get<0>(measured2);     // measurement results
    auto prob2 = std::get<1>(measured2); // probability of the result
    idx n2 = multiidx2n(list_results2, std::vector<idx>(n, 2)); // binary to int
    double x2 = static_cast<double>(n2) / D;

    std::cout << ">> Second measurement: " << disp(list_results2, " ") << " ";
    std::cout << "i.e. j = " << n2 << " with probability " << prob2;
    std::cout << '\n';

    failed = true;
    idx r2, c2;
    for (auto&& elem : convergents(x2, 10)) {
        std::tie(c2, r2) = elem;
        double c2r2 = static_cast<double>(c2) / r2;
        if (abs(x2 - c2r2) < 1. / std::pow(2, (n - 1) / 2.)) {
            failed = false;
            break;
        }
    }
    if (failed) {
        std::cout << ">> Factoring failed at stage 2, please try again!\n";
        std::exit(EXIT_FAILURE);
    }
    // END SECOND MEASUREMENT STAGE

    // THIRD POST-PROCESSING STAGE
    idx r = lcm(r1, r2); // candidate order of a mod N
    std::cout << ">> r = " << r << '\n';
    if (r % 2 == 0 && modpow(a, r / 2, N) != static_cast<bigint>(N - 1)) {
        std::cout << ">> Possible factors: ";
        std::cout << gcd(modpow(a, r / 2, N) - 1, N) << " ";
        std::cout << gcd(modpow(a, r / 2, N) + 1, N) << '\n';
    } else {
        std::cout << ">> Factoring failed at stage 3, please try again!\n";
        std::exit(EXIT_FAILURE);
    }
    // END THIRD POST-PROCESSING STAGE
}
<|endoftext|>


<commit_before>///
/// A simple clang plugin which will translate the given C file into Zomp
/// definitions
///

#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/AST.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "llvm/Support/raw_ostream.h"

using namespace clang;

namespace {

static std::string errorType(const char* msg)
{
    return std::string("error_t(\"") + msg + "\")";
}

static std::string zompTypeName(const Type* t)
{
    if( t == 0 )
    {
        return "type_was_null";
    }

    if( const BuiltinType* bt = dyn_cast<BuiltinType>(t) )
    {
        switch(bt->getKind())
        {
        case BuiltinType::Void: return "void";
        case BuiltinType::UShort: return "c_ushort";
        case BuiltinType::UInt: return "c_uint";
        case BuiltinType::ULong: return "c_ulong";
        case BuiltinType::ULongLong: return "c_ulong_long";
        case BuiltinType::UInt128: return "u128";
        case BuiltinType::Short: return "c_short";
        case BuiltinType::Int: return "c_int";
        case BuiltinType::Long: return "c_long";
        case BuiltinType::LongLong: return "c_long_long";
        case BuiltinType::Int128: return "s128";
        case BuiltinType::Float: return "float";
        case BuiltinType::Double: return "double";
        case BuiltinType::LongDouble: return "c_long_double";

        case BuiltinType::Char_U: return "c_implicit_uchar";
        case BuiltinType::Char_S: return "c_implicit_schar";
        case BuiltinType::UChar: return "c_uchar";
        case BuiltinType::SChar: return "c_schar";

        case BuiltinType::WChar_U:
        case BuiltinType::Char16:
        case BuiltinType::Char32:
        case BuiltinType::WChar_S:

        case BuiltinType::NullPtr:
        case BuiltinType::Dependent:
        case BuiltinType::Overload:

        case BuiltinType::ObjCId:
        case BuiltinType::ObjCClass:
        case BuiltinType::ObjCSel:

        default:
            return "UnsupportedBuiltinType";
        }
    }
    else if( const PointerType* pt = dyn_cast<PointerType>(t) )
    {
        QualType base_type = pt->getPointeeType();
        return zompTypeName(base_type.getTypePtrOrNull()) + "*";
    }
    else if( const ArrayType* at = dyn_cast<ArrayType>(t) )
    {
        assert( at );
        return errorType( "bindgen does not support array types, yet" );
    }
    else if( const FunctionType* ft = dyn_cast<FunctionType>(t) )
    {
        assert( ft );
        return errorType("bindgen does not support function types, yet" );
    }
    else if( const TypedefType* tt = dyn_cast<TypedefType>(t) )
    {
        return tt->getDecl()->getName();
        // return zompTypeName(
            // tt->getDecl()->getCanonicalDecl()->getUnderlyingType().getTypePtrOrNull() );
    }
    else if( const EnumType* et = dyn_cast<EnumType>(t) )
    {
        return et->getDecl()->getNameAsString();
    }
    else if( const RecordType* rt = dyn_cast<RecordType>(t) )
    {
        return rt->getDecl()->getNameAsString();
    }
    else
    {
        return errorType("type not understood by bindgen");
    }
}

static std::string zompTypeName( const QualType& qual_type )
{
    std::string base_name = zompTypeName( qual_type.getTypePtrOrNull() );
    std::string name = base_name;

    if( qual_type.isConstQualified() )
    {
        name = "/* const */" + name;
    }

    if( qual_type.isRestrictQualified() )
    {
        name = "/* restrict */" + name;
    }

    if( qual_type.isVolatileQualified() )
    {
        name = "/* volatile */" + name;
    }

    return name;
}

/** Visitor which will handle every top level declaration */
class GenBindingsConsumer : public ASTConsumer
{
    ASTContext* m_context;
    SourceManager* m_src_manager;
    FileID m_main_file_id;

public:
    GenBindingsConsumer() : m_context(0), m_src_manager(0)
    {
    }

    virtual void Initialize(ASTContext &context)
    {
        m_context = &context;
        m_src_manager = &context.getSourceManager();
        m_main_file_id = m_src_manager->getMainFileID();

        const char* main_file_name = m_src_manager->getFileEntryForID( m_main_file_id )->getName();
        llvm::outs() << "///\n";
        llvm::outs() << "/// Zomp bindings for " << main_file_name << "\n";
        llvm::outs() << "///\n";
        llvm::outs() << "\n";
    }

    virtual void HandleTopLevelDecl(DeclGroupRef DG)
    {
        for (DeclGroupRef::iterator i = DG.begin(), e = DG.end(); i != e; ++i)
        {
            const Decl *D = *i;

            const TranslationUnitDecl* tu = D->getTranslationUnitDecl();
            if( !tu ) {
                continue;
            }

            const SourceLocation& loc = D->getLocation();
            if( m_src_manager->getFileID(loc) != m_main_file_id)
            {
                continue;
            }

            handleAs<VarDecl>(D) ||
                handleAs<FunctionDecl>(D) ||
                handleAs<TypedefDecl>(D) ||
                handleAs<RecordDecl>(D) ||
                handleAs<EnumDecl>(D) ||
                handleUnknown(D);
        }
    }

private:

    enum HandlingResult { Handled, CouldNotHandle };

    template<typename T>
    bool handleAs(const Decl* D)
    {
        const T* typed_decl = dyn_cast<T>(D);
        if(typed_decl)
        {
            const bool result = handle(typed_decl) == Handled;
            // llvm::outs() << "\n";
            return result;
        }
        else
        {
            return false;
        }
    }

    HandlingResult handle(const FunctionDecl* func_decl)
    {
        bool ignore = func_decl->isCXXClassMember()
            || func_decl->isCXXInstanceMember()
            || func_decl->isVariadic()
            || func_decl->isMain();

        if(ignore) {
            return CouldNotHandle;
        }

        llvm::outs() << "nativeFn ";
        llvm::outs() << zompTypeName( func_decl->getResultType() ) << " ";
        llvm::outs() << func_decl->getNameAsString() << "(";
        bool first_param = true;
        for( FunctionDecl::param_const_iterator param_i = func_decl->param_begin(),
                 pend = func_decl->param_end( );
             param_i != pend;
             ++param_i, first_param = false )
        {
            ParmVarDecl* param = *param_i;

            if( !first_param ) {
                llvm::outs() << ", ";
            }

            QualType typesrc = param->getTypeSourceInfo()->getType();
            const Type* type = typesrc.getTypePtrOrNull();

            llvm::outs() << zompTypeName(type);

            if( param->getIdentifier() )
            {
                llvm::outs() << " "
                             << param->getNameAsString();
            }

            if ( param->hasDefaultArg() )
            {
                llvm::outs() << " /* = ... */";
            }
        }
        llvm::outs() << ")\n";

        return Handled;
    }

    HandlingResult handle(const VarDecl* var_decl)
    {
        llvm::outs() << "nativeVar "
            << zompTypeName( var_decl->getTypeSourceInfo()->getType() )
            << " "
            << var_decl->getNameAsString()
            << "\n";

        return Handled;
    }

    bool handle(const TypedefDecl* type_decl)
    {
        QualType typesrc = type_decl->getUnderlyingType();
        const Type* type = typesrc.getTypePtrOrNull();
        std::string zomp_name = zompTypeName(type);

        bool handled = false;

        if( type )
        {
            if( zomp_name.empty() )
            {
                if( const RecordType* record_type = dyn_cast<RecordType>(type) )
                {
                    handled = handle( record_type->getDecl(), type_decl->getName() );
                }
                else if( const EnumType* enum_type = dyn_cast<EnumType>(type) )
                {
                    handled = handle( enum_type->getDecl(), type_decl->getName() );
                }
            }
            else
            {
                llvm::outs()
                    << "nativeTypedef "
                    << type_decl->getName()
                    << " " << zomp_name << "\n";
                handled = true;
            }
        }

        if( !handled )
        {
            llvm::outs()
                << "// ignoring typedef " << type_decl->getName() << "\n";
        }

        return Handled;
    }

    bool handle(const RecordDecl* record_decl, llvm::StringRef name = "" )
    {
        if( name == "" )
        {
            name = record_decl->getName();
        }

        if( record_decl->isAnonymousStructOrUnion() ||
            name.empty() )
        {
            llvm::outs() << "// ignoring anonymous struct\n";
            return Handled;
        }

        if( record_decl->isDefinition() )
        {
            llvm::outs() << "nativeStruct " << name << ":\n";

            typedef RecordDecl::field_iterator FieldIter;
            for( FieldIter fi = record_decl->field_begin(), fi_end = record_decl->field_end();
                 fi != fi_end;
                 ++fi )
            {
                const FieldDecl& field = **fi;
                if( field.isBitField() )
                {
                    llvm::outs() << "  // ignored bitfield, not supported\n";
                }
                else
                {
                    llvm::outs()
                        << "  "
                        << zompTypeName( field.getType() )
                        << " "
                        << field.getName()
                        << "\n";
                }
            }

            llvm::outs() << "end\n";
        }
        else
        {
            llvm::outs() << "nativeStruct " << name << "\n";
        }

        return Handled;
    }

    bool handle(const EnumDecl* enum_decl, llvm::StringRef name = "")
    {
        if( name == "" )
        {
            name = enum_decl->getName();
        }

        if( name.empty() )
        {
            llvm::outs() << "// ignoring name-less enum\n";
        }
        else if( enum_decl->isComplete() )
        {
            llvm::outs()
                << "nativeEnum "
                << name << " "
                << zompTypeName( enum_decl->getPromotionType() )
                << ":\n";

            typedef EnumDecl::enumerator_iterator EnumIter;
            for( EnumIter variant = enum_decl->enumerator_begin(), vend = enum_decl->enumerator_end();
                 variant != vend;
                 ++variant )
            {
                EnumConstantDecl* ecd = *variant;

                llvm::outs()
                    << "  "
                    << ecd->getName() << " "
                    << ecd->getInitVal()
                    << "\n";
            }

            llvm::outs() << "end\n";
        }
        else
        {
            llvm::outs()
                << "nativeEnum "
                << name
                << "\n";
        }

        return Handled;
    }

    bool handleUnknown(const Decl* D)
    {
        if(const NamedDecl* n = dyn_cast<NamedDecl>(D))
        {
            llvm::outs() << "// ignored " << n->getNameAsString() << "\n";
        }
        else
        {
            llvm::outs() << "// ignored nameless declaration\n";
        }

        return Handled;
    }
};

/** The plugin class. Will instantiate GenBindingsConsumer and run it */
class GenBindingsAction : public PluginASTAction
{
protected:
    ASTConsumer *CreateASTConsumer(CompilerInstance &CI, llvm::StringRef)
    {
        return new GenBindingsConsumer();
    }

    bool ParseArgs(
        const CompilerInstance &CI,
        const std::vector<std::string>& args )
    {
        for (unsigned i = 0, e = args.size(); i != e; ++i) {
            llvm::errs() << "PrintFunctionNames arg = " << args[i] << "\n";

            // Example error handling.
            if (args[i] == "-an-error") {
                Diagnostic &D = CI.getDiagnostics();
                unsigned DiagID = D.getCustomDiagID(
                    Diagnostic::Error, "invalid argument '" + args[i] + "'");
                D.Report(DiagID);
                return false;
            }
        }
        if (args.size() && args[0] == "help")
            PrintHelp(llvm::errs());

        return true;
    }

    void PrintHelp(llvm::raw_ostream& ros)
    {
        ros << "Translates declarations of a C file into Zomp declarations.\n"
            "This makes it easy to use C libaries from Zomp.";
    }
};

} // anonymous namespace

static FrontendPluginRegistry::Add<GenBindingsAction> X("gen-zomp-bindings", "Generate Zomp bindings");

<commit_msg>Fixing error handling in bindgen<commit_after>///
/// A simple clang plugin which will translate the given C file into Zomp
/// definitions
///

#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/AST.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "llvm/Support/raw_ostream.h"

using namespace clang;

namespace {

static std::string errorType(const char* msg)
{
    return std::string("error_t(\"") + msg + "\")";
}

static std::string zompTypeName(const Type* t)
{
    if( t == 0 )
    {
        return "type_was_null";
    }

    if( const BuiltinType* bt = dyn_cast<BuiltinType>(t) )
    {
        switch(bt->getKind())
        {
        case BuiltinType::Void: return "void";
        case BuiltinType::UShort: return "c_ushort";
        case BuiltinType::UInt: return "c_uint";
        case BuiltinType::ULong: return "c_ulong";
        case BuiltinType::ULongLong: return "c_ulong_long";
        case BuiltinType::UInt128: return "u128";
        case BuiltinType::Short: return "c_short";
        case BuiltinType::Int: return "c_int";
        case BuiltinType::Long: return "c_long";
        case BuiltinType::LongLong: return "c_long_long";
        case BuiltinType::Int128: return "s128";
        case BuiltinType::Float: return "float";
        case BuiltinType::Double: return "double";
        case BuiltinType::LongDouble: return "c_long_double";

        case BuiltinType::Char_U: return "c_implicit_uchar";
        case BuiltinType::Char_S: return "c_implicit_schar";
        case BuiltinType::UChar: return "c_uchar";
        case BuiltinType::SChar: return "c_schar";

        case BuiltinType::WChar_U:
        case BuiltinType::Char16:
        case BuiltinType::Char32:
        case BuiltinType::WChar_S:

        case BuiltinType::NullPtr:
        case BuiltinType::Dependent:
        case BuiltinType::Overload:

        case BuiltinType::ObjCId:
        case BuiltinType::ObjCClass:
        case BuiltinType::ObjCSel:

        default:
            return "UnsupportedBuiltinType";
        }
    }
    else if( const PointerType* pt = dyn_cast<PointerType>(t) )
    {
        QualType base_type = pt->getPointeeType();
        return zompTypeName(base_type.getTypePtrOrNull()) + "*";
    }
    else if( const ArrayType* at = dyn_cast<ArrayType>(t) )
    {
        assert( at );
        return errorType( "bindgen does not support array types, yet" );
    }
    else if( const FunctionType* ft = dyn_cast<FunctionType>(t) )
    {
        assert( ft );
        return errorType("bindgen does not support function types, yet" );
    }
    else if( const TypedefType* tt = dyn_cast<TypedefType>(t) )
    {
        return tt->getDecl()->getName();
        // return zompTypeName(
            // tt->getDecl()->getCanonicalDecl()->getUnderlyingType().getTypePtrOrNull() );
    }
    else if( const EnumType* et = dyn_cast<EnumType>(t) )
    {
        return et->getDecl()->getNameAsString();
    }
    else if( const RecordType* rt = dyn_cast<RecordType>(t) )
    {
        return rt->getDecl()->getNameAsString();
    }
    else
    {
        return errorType("type not understood by bindgen");
    }
}

static std::string zompTypeName( const QualType& qual_type )
{
    std::string base_name = zompTypeName( qual_type.getTypePtrOrNull() );
    std::string name = base_name;

    if( qual_type.isConstQualified() )
    {
        name = "/* const */" + name;
    }

    if( qual_type.isRestrictQualified() )
    {
        name = "/* restrict */" + name;
    }

    if( qual_type.isVolatileQualified() )
    {
        name = "/* volatile */" + name;
    }

    return name;
}

/** Visitor which will handle every top level declaration */
class GenBindingsConsumer : public ASTConsumer
{
    ASTContext* m_context;
    SourceManager* m_src_manager;
    FileID m_main_file_id;

public:
    GenBindingsConsumer() : m_context(0), m_src_manager(0)
    {
    }

    virtual void Initialize(ASTContext &context)
    {
        m_context = &context;
        m_src_manager = &context.getSourceManager();
        m_main_file_id = m_src_manager->getMainFileID();

        const char* main_file_name = m_src_manager->getFileEntryForID( m_main_file_id )->getName();
        llvm::outs() << "///\n";
        llvm::outs() << "/// Zomp bindings for " << main_file_name << "\n";
        llvm::outs() << "///\n";
        llvm::outs() << "\n";
    }

    virtual void HandleTopLevelDecl(DeclGroupRef DG)
    {
        for (DeclGroupRef::iterator i = DG.begin(), e = DG.end(); i != e; ++i)
        {
            const Decl *D = *i;

            const TranslationUnitDecl* tu = D->getTranslationUnitDecl();
            if( !tu ) {
                continue;
            }

            const SourceLocation& loc = D->getLocation();
            if( m_src_manager->getFileID(loc) != m_main_file_id)
            {
                continue;
            }

            handleAs<VarDecl>(D) ||
                handleAs<FunctionDecl>(D) ||
                handleAs<TypedefDecl>(D) ||
                handleAs<RecordDecl>(D) ||
                handleAs<EnumDecl>(D) ||
                handleUnknown(D);
        }
    }

private:

    enum HandlingResult { Handled, CouldNotHandle };

    template<typename T>
    bool handleAs(const Decl* D)
    {
        const T* typed_decl = dyn_cast<T>(D);
        if(typed_decl)
        {
            const bool result = handle(typed_decl) == Handled;
            // llvm::outs() << "\n";
            return result;
        }
        else
        {
            return false;
        }
    }

    HandlingResult handle(const FunctionDecl* func_decl)
    {
        bool ignore = func_decl->isCXXClassMember()
            || func_decl->isCXXInstanceMember()
            || func_decl->isVariadic()
            || func_decl->isMain();

        if(ignore) {
            return CouldNotHandle;
        }

        llvm::outs() << "nativeFn ";
        llvm::outs() << zompTypeName( func_decl->getResultType() ) << " ";
        llvm::outs() << func_decl->getNameAsString() << "(";
        bool first_param = true;
        for( FunctionDecl::param_const_iterator param_i = func_decl->param_begin(),
                 pend = func_decl->param_end( );
             param_i != pend;
             ++param_i, first_param = false )
        {
            ParmVarDecl* param = *param_i;

            if( !first_param ) {
                llvm::outs() << ", ";
            }

            QualType typesrc = param->getTypeSourceInfo()->getType();
            const Type* type = typesrc.getTypePtrOrNull();

            llvm::outs() << zompTypeName(type);

            if( param->getIdentifier() )
            {
                llvm::outs() << " "
                             << param->getNameAsString();
            }

            if ( param->hasDefaultArg() )
            {
                llvm::outs() << " /* = ... */";
            }
        }
        llvm::outs() << ")\n";

        return Handled;
    }

    HandlingResult handle(const VarDecl* var_decl)
    {
        llvm::outs() << "nativeVar "
            << zompTypeName( var_decl->getTypeSourceInfo()->getType() )
            << " "
            << var_decl->getNameAsString()
            << "\n";

        return Handled;
    }

    HandlingResult handle(const TypedefDecl* type_decl)
    {
        QualType typesrc = type_decl->getUnderlyingType();
        const Type* type = typesrc.getTypePtrOrNull();
        std::string zomp_name = zompTypeName(type);

        bool handled = false;

        if( type )
        {
            if( zomp_name.empty() )
            {
                if( const RecordType* record_type = dyn_cast<RecordType>(type) )
                {
                    handled = handle( record_type->getDecl(), type_decl->getName() ) == Handled;
                }
                else if( const EnumType* enum_type = dyn_cast<EnumType>(type) )
                {
                    handled = handle( enum_type->getDecl(), type_decl->getName() ) == Handled;
                }
            }
            else
            {
                llvm::outs()
                    << "nativeTypedef "
                    << type_decl->getName()
                    << " " << zomp_name << "\n";
                handled = true;
            }
        }

        if( !handled )
        {
            llvm::outs()
                << "// ignoring typedef " << type_decl->getName() << "\n";
        }

        return Handled;
    }

    HandlingResult handle(const RecordDecl* record_decl, llvm::StringRef name = "" )
    {
        if( name == "" )
        {
            name = record_decl->getName();
        }

        if( record_decl->isAnonymousStructOrUnion() ||
            name.empty() )
        {
            llvm::outs() << "// ignoring anonymous struct\n";
        }
        else if( record_decl->isDefinition() )
        {
            llvm::outs() << "nativeStruct " << name << ":\n";

            typedef RecordDecl::field_iterator FieldIter;
            for( FieldIter fi = record_decl->field_begin(), fi_end = record_decl->field_end();
                 fi != fi_end;
                 ++fi )
            {
                const FieldDecl& field = **fi;
                if( field.isBitField() )
                {
                    llvm::outs() << "  // ignored bitfield, not supported\n";
                }
                else
                {
                    llvm::outs()
                        << "  "
                        << zompTypeName( field.getType() )
                        << " "
                        << field.getName()
                        << "\n";
                }
            }

            llvm::outs() << "end\n";
        }
        else
        {
            llvm::outs() << "nativeStruct " << name << "\n";
        }

        return Handled;
    }

    HandlingResult handle(const EnumDecl* enum_decl, llvm::StringRef name = "")
    {
        if( name == "" )
        {
            name = enum_decl->getName();
        }

        if( name.empty() )
        {
            llvm::outs() << "// ignoring name-less enum\n";
        }
        else if( enum_decl->isComplete() )
        {
            llvm::outs()
                << "nativeEnum "
                << name << " "
                << zompTypeName( enum_decl->getPromotionType() )
                << ":\n";

            typedef EnumDecl::enumerator_iterator EnumIter;
            for( EnumIter variant = enum_decl->enumerator_begin(), vend = enum_decl->enumerator_end();
                 variant != vend;
                 ++variant )
            {
                EnumConstantDecl* ecd = *variant;

                llvm::outs()
                    << "  "
                    << ecd->getName() << " "
                    << ecd->getInitVal()
                    << "\n";
            }

            llvm::outs() << "end\n";
        }
        else
        {
            llvm::outs()
                << "nativeEnum "
                << name
                << "\n";
        }

        return Handled;
    }

    bool handleUnknown(const Decl* D)
    {
        if(const NamedDecl* n = dyn_cast<NamedDecl>(D))
        {
            llvm::outs() << "// ignored " << n->getNameAsString() << "\n";
        }
        else
        {
            llvm::outs() << "// ignored nameless declaration\n";
        }

        return Handled;
    }
};

/** The plugin class. Will instantiate GenBindingsConsumer and run it */
class GenBindingsAction : public PluginASTAction
{
protected:
    ASTConsumer *CreateASTConsumer(CompilerInstance &CI, llvm::StringRef)
    {
        return new GenBindingsConsumer();
    }

    bool ParseArgs(
        const CompilerInstance &CI,
        const std::vector<std::string>& args )
    {
        for (unsigned i = 0, e = args.size(); i != e; ++i) {
            llvm::errs() << "PrintFunctionNames arg = " << args[i] << "\n";

            // Example error handling.
            if (args[i] == "-an-error") {
                Diagnostic &D = CI.getDiagnostics();
                unsigned DiagID = D.getCustomDiagID(
                    Diagnostic::Error, "invalid argument '" + args[i] + "'");
                D.Report(DiagID);
                return false;
            }
        }
        if (args.size() && args[0] == "help")
            PrintHelp(llvm::errs());

        return true;
    }

    void PrintHelp(llvm::raw_ostream& ros)
    {
        ros << "Translates declarations of a C file into Zomp declarations.\n"
            "This makes it easy to use C libaries from Zomp.";
    }
};

} // anonymous namespace

static FrontendPluginRegistry::Add<GenBindingsAction> X("gen-zomp-bindings", "Generate Zomp bindings");

<|endoftext|>


<commit_before>#include "app.h"
#include "gphotogrid.h"
#include "gputil.h"
#include <iostream>
#include <sstream>
#include <wx/timer.h>
#include <wx/mstream.h>

MainFrame::MainFrame(const wxString& title, App& app) :
		wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(1024, 768)), app(app) {
	create_menus();
	create_panels();

#ifdef LOOP_TIMER
	//timer = new RenderTimer(*this);
	//timer->start();
#else
	frames = 0;
	lasttime = Clock::now();

	enableRender(true);
	Bind(wxEVT_IDLE, &MainFrame::onIdle, this);
#endif
}

#ifdef LOOP_TIMER
RenderTimer::RenderTimer(MainFrame& root) : root(root) {
}
void RenderTimer::Notify() {
	std::cout << "NOTIF" << std::endl;
	root.refresh();
}
void RenderTimer::start() {
	Start(10);
}
#else
void MainFrame::onIdle(wxIdleEvent& ev) {
	//std::cout<<"idle"<<std::endl;
	refresh();
	ev.RequestMore();
}
#endif

// read params from camera 0 and set the same for others
void MainFrame::readCameraParams() {
	bool fol = timeline->getFollow();
	timeline->Destroy();
	timeline = new Timeline(this, app.numcams(), fol);
	GetSizer()->Add(timeline, 1, wxEXPAND);
	Layout();

	if (app.numcams() > 0) {
		// assume that all cameras are the same, use only zeroth

		auto aperture = app.cams[0].config()["aperture"].get<gp::Aperture>();
		for (size_t i = 1; i < app.numcams(); i++)
			setRadioConfig<gp::Aperture>(i, aperture.index());
		options->setSelections(0, aperture.choices(), aperture.index());

		auto shutter = app.cams[0].config()["shutterspeed"].get<gp::ShutterSpeed>();
		for (size_t i = 1; i < app.numcams(); i++)
			setRadioConfig<gp::ShutterSpeed>(i, shutter.index());
		options->setSelections(1, shutter.choices(), shutter.index());

		auto iso = app.cams[0].config()["iso"].get<gp::Iso>();
		for (size_t i = 1; i < app.numcams(); i++)
			setRadioConfig<gp::Iso>(i, iso.index());
		options->setSelections(2, iso.choices(), iso.index());
	}

	Refresh();
}

void MainFrame::create_panels() {
	auto horsizer = new wxBoxSizer(wxHORIZONTAL);
	// opts lots thinner than image panel
	horsizer->Add(options = new OptionsPanel(this), 1, wxEXPAND);
	horsizer->Add(create_imagegrid(), 4, wxEXPAND);
	auto versizer = new wxBoxSizer(wxVERTICAL);
	versizer->Add(horsizer, 4, wxEXPAND);
	versizer->Add(timeline = new Timeline(this, app.numcams()));
	SetSizer(versizer);

	readCameraParams();
}

wxSizer* MainFrame::create_imagegrid() {
	int rows = 3, cols = 3;
	auto sizer = new wxGridSizer(cols, wxSize(2, 2));
	for (int i = 0; i < rows * cols; i++) {
		auto panel = new ImagePanel(this);
		images.push_back(panel);
		sizer->Add(panel, 1, wxEXPAND);
	}
	return sizer;
}

void MainFrame::create_menus() {
	wxMenu *menuFile = new wxMenu();
	menuFile->AppendSeparator();
	menuFile->Append(1, "foo");
	menuFile->Append(2, "bar");
	menuFile->Append(wxID_EXIT);

	wxMenuBar *menuBar = new wxMenuBar();
	menuBar->Append(menuFile, "&File");

	SetMenuBar(menuBar);

	CreateStatusBar();
	SetStatusText("Hello world");

	Bind(wxEVT_COMMAND_MENU_SELECTED, &MainFrame::onMenu, this, 1);
	Bind(wxEVT_COMMAND_MENU_SELECTED, &MainFrame::onExit, this, wxID_EXIT);
}

void MainFrame::slider(int id, int value) {
	std::cout << "slider " << id << " to " << value << std::endl;
	if (id < 0 || id > 2)
		throw std::out_of_range("slider index bug");

	std::vector<std::thread> setters(app.numcams());
	for (size_t cam = 0; cam < app.numcams(); cam++) {
		setters[cam] = std::thread([=]() {
			switch (id) {
			case 0:
				setRadioConfig<gp::Aperture>(cam, value);
				break;
			case 1:
				setRadioConfig<gp::ShutterSpeed>(cam, value);
				break;
			case 2:
				setRadioConfig<gp::Iso>(cam, value);
				break;
			}
		});
	}
	for (auto& thr: setters)
		thr.join();
}

template <class Obj>
void MainFrame::setRadioConfig(int cam, int value) {
	auto cfg = app.cams[cam].config()[Obj::gpname];
	auto radio = cfg.template get<Obj>();

	if (value >= 0 && value < radio.size()) {
		radio.set(value);
		cfg.set(radio);
		std::cout << "cam " << cam << " new " << Obj::gpname << " " << radio.text() << std::endl;
	}
}

void MainFrame::reloadGphoto() {
	assert(!app.previewfeed.enabled());
	app.reloadGphoto();
	for (auto& impanel: images) {
		impanel->clearImage();
	}
	readCameraParams();
}

void MainFrame::refresh() {
	updatePhotos();
	for (auto im: images) {
		im->Refresh();
	}
	framecalc();
}

float MainFrame::time_since(MainFrame::Clock::time_point now, MainFrame::Clock::time_point before) const {
	typedef std::chrono::duration<float> fsec;
	fsec fs = now - before;
	return fs.count();
}

void MainFrame::framecalc() {
	auto clock = Clock::now();
	float secs = time_since(clock, lasttime);
	frames++;

	if (secs > 5.0f) {
		std::cout << frames << " in " << secs << " secs = " << (frames / secs) << " fps" << std::endl;
		frames = 0;
		lasttime = clock;
	}
}
void MainFrame::updatePhotos() {
	// if no sources, no update needed
	if (app.numcams() == 0 || !app.previewfeed.enabled())
		return;

	// all have the same size
	auto newsize = images[0]->GetSize();

	for (size_t i = 0; i < std::min(app.numcams(), images.size()); i++) {
		PreviewFeed::TimedJpegBuffer capture;
		// test if there is anything
		if (!app.previewfeed.getQueue(i).try_pop(capture))
			continue;
		// log timestamps, and slurp further ones, until got the latest
		do {
			timeline->insert(i, time_since(capture.second, renderinittime));
			numpics[i]++;
		} while (app.previewfeed.getQueue(i).try_pop(capture));

		wxMemoryInputStream stream(&capture.first[0], capture.first.size());
		wxImage im(stream, wxBITMAP_TYPE_JPEG);
		// XXX: aspect ratio correction?
		im.Rescale(newsize.GetWidth(), newsize.GetHeight(), wxIMAGE_QUALITY_NEAREST);
		images[i]->setImage(im, i < app.camNames.size() ? app.camNames[i] : "");
	}

	std::stringstream ss;
	ss << app.numcams() << " cameras; frames per cam:";
	for (size_t i = 0; i < numpics.size(); i++) {
		ss << " " << i << ":" << numpics[i];
	}
	SetStatusText(ss.str());
}

void MainFrame::enableRender(bool enable) {
	if (enable) {
		renderinittime = Clock::now();
		numpics = std::vector<int>(app.numcams());
		timeline->clear();
		app.previewfeed.enable();
	} else {
		app.previewfeed.disable();
	}
}
void MainFrame::syncGrabbers(bool sync) {
	app.previewfeed.setsync(sync);
}

void MainFrame::timelineFollow(bool follow) {
	timeline->followInsertions(follow);
}

void MainFrame::onMenu(wxCommandEvent&) {
	std::cout << "menu" << std::endl;
}
void MainFrame::onExit(wxCommandEvent&) {
	Close(true);
}
<commit_msg>gpgrid: reorient images if the setting is given<commit_after>#include "app.h"
#include "gphotogrid.h"
#include "gputil.h"
#include <iostream>
#include <sstream>
#include <wx/timer.h>
#include <wx/mstream.h>

MainFrame::MainFrame(const wxString& title, App& app) :
		wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(1024, 768)), app(app) {
	create_menus();
	create_panels();

#ifdef LOOP_TIMER
	//timer = new RenderTimer(*this);
	//timer->start();
#else
	frames = 0;
	lasttime = Clock::now();

	enableRender(true);
	Bind(wxEVT_IDLE, &MainFrame::onIdle, this);
#endif
}

#ifdef LOOP_TIMER
RenderTimer::RenderTimer(MainFrame& root) : root(root) {
}
void RenderTimer::Notify() {
	std::cout << "NOTIF" << std::endl;
	root.refresh();
}
void RenderTimer::start() {
	Start(10);
}
#else
void MainFrame::onIdle(wxIdleEvent& ev) {
	//std::cout<<"idle"<<std::endl;
	refresh();
	ev.RequestMore();
}
#endif

// read params from camera 0 and set the same for others
void MainFrame::readCameraParams() {
	bool fol = timeline->getFollow();
	timeline->Destroy();
	timeline = new Timeline(this, app.numcams(), fol);
	GetSizer()->Add(timeline, 1, wxEXPAND);
	Layout();

	if (app.numcams() > 0) {
		// assume that all cameras are the same, use only zeroth

		auto aperture = app.cams[0].config()["aperture"].get<gp::Aperture>();
		for (size_t i = 1; i < app.numcams(); i++)
			setRadioConfig<gp::Aperture>(i, aperture.index());
		options->setSelections(0, aperture.choices(), aperture.index());

		auto shutter = app.cams[0].config()["shutterspeed"].get<gp::ShutterSpeed>();
		for (size_t i = 1; i < app.numcams(); i++)
			setRadioConfig<gp::ShutterSpeed>(i, shutter.index());
		options->setSelections(1, shutter.choices(), shutter.index());

		auto iso = app.cams[0].config()["iso"].get<gp::Iso>();
		for (size_t i = 1; i < app.numcams(); i++)
			setRadioConfig<gp::Iso>(i, iso.index());
		options->setSelections(2, iso.choices(), iso.index());
	}

	Refresh();
}

void MainFrame::create_panels() {
	auto horsizer = new wxBoxSizer(wxHORIZONTAL);
	// opts lots thinner than image panel
	horsizer->Add(options = new OptionsPanel(this), 1, wxEXPAND);
	horsizer->Add(create_imagegrid(), 4, wxEXPAND);
	auto versizer = new wxBoxSizer(wxVERTICAL);
	versizer->Add(horsizer, 4, wxEXPAND);
	versizer->Add(timeline = new Timeline(this, app.numcams()));
	SetSizer(versizer);

	readCameraParams();
}

wxSizer* MainFrame::create_imagegrid() {
	int rows = 3, cols = 3;
	auto sizer = new wxGridSizer(cols, wxSize(2, 2));
	for (int i = 0; i < rows * cols; i++) {
		auto panel = new ImagePanel(this);
		images.push_back(panel);
		sizer->Add(panel, 1, wxEXPAND);
	}
	return sizer;
}

void MainFrame::create_menus() {
	wxMenu *menuFile = new wxMenu();
	menuFile->AppendSeparator();
	menuFile->Append(1, "foo");
	menuFile->Append(2, "bar");
	menuFile->Append(wxID_EXIT);

	wxMenuBar *menuBar = new wxMenuBar();
	menuBar->Append(menuFile, "&File");

	SetMenuBar(menuBar);

	CreateStatusBar();
	SetStatusText("Hello world");

	Bind(wxEVT_COMMAND_MENU_SELECTED, &MainFrame::onMenu, this, 1);
	Bind(wxEVT_COMMAND_MENU_SELECTED, &MainFrame::onExit, this, wxID_EXIT);
}

void MainFrame::slider(int id, int value) {
	std::cout << "slider " << id << " to " << value << std::endl;
	if (id < 0 || id > 2)
		throw std::out_of_range("slider index bug");

	std::vector<std::thread> setters(app.numcams());
	for (size_t cam = 0; cam < app.numcams(); cam++) {
		setters[cam] = std::thread([=]() {
			switch (id) {
			case 0:
				setRadioConfig<gp::Aperture>(cam, value);
				break;
			case 1:
				setRadioConfig<gp::ShutterSpeed>(cam, value);
				break;
			case 2:
				setRadioConfig<gp::Iso>(cam, value);
				break;
			}
		});
	}
	for (auto& thr: setters)
		thr.join();
}

template <class Obj>
void MainFrame::setRadioConfig(int cam, int value) {
	auto cfg = app.cams[cam].config()[Obj::gpname];
	auto radio = cfg.template get<Obj>();

	if (value >= 0 && value < radio.size()) {
		radio.set(value);
		cfg.set(radio);
		std::cout << "cam " << cam << " new " << Obj::gpname << " " << radio.text() << std::endl;
	}
}

void MainFrame::reloadGphoto() {
	assert(!app.previewfeed.enabled());
	app.reloadGphoto();
	for (auto& impanel: images) {
		impanel->clearImage();
	}
	readCameraParams();
}

void MainFrame::refresh() {
	updatePhotos();
	for (auto im: images) {
		im->Refresh();
	}
	framecalc();
}

float MainFrame::time_since(MainFrame::Clock::time_point now, MainFrame::Clock::time_point before) const {
	typedef std::chrono::duration<float> fsec;
	fsec fs = now - before;
	return fs.count();
}

void MainFrame::framecalc() {
	auto clock = Clock::now();
	float secs = time_since(clock, lasttime);
	frames++;

	if (secs > 5.0f) {
		std::cout << frames << " in " << secs << " secs = " << (frames / secs) << " fps" << std::endl;
		frames = 0;
		lasttime = clock;
	}
}
void MainFrame::updatePhotos() {
	// if no sources, no update needed
	if (app.numcams() == 0 || !app.previewfeed.enabled())
		return;

	// all have the same size
	auto newsize = images[0]->GetSize();

	for (size_t i = 0; i < std::min(app.numcams(), images.size()); i++) {
		PreviewFeed::TimedJpegBuffer capture;
		// test if there is anything
		if (!app.previewfeed.getQueue(i).try_pop(capture))
			continue;
		// log timestamps, and slurp further ones, until got the latest
		do {
			timeline->insert(i, time_since(capture.second, renderinittime));
			numpics[i]++;
		} while (app.previewfeed.getQueue(i).try_pop(capture));

		wxMemoryInputStream stream(&capture.first[0], capture.first.size());
		wxImage im(stream, wxBITMAP_TYPE_JPEG);
		// XXX: aspect ratio correction?
		if (i < app.camOrientations.size()) {
			if (app.camOrientations[i] == "90")
				im = im.Rotate90();
			else if (app.camOrientations[i] == "-90"
					|| app.camOrientations[i] == "270")
				im = im.Rotate90(false);
			else if (app.camOrientations[i] == "180"
					|| app.camOrientations[i] == "-180")
				im = im.Rotate180();
		}
		im.Rescale(newsize.GetWidth(), newsize.GetHeight(), wxIMAGE_QUALITY_NEAREST);
		images[i]->setImage(im, i < app.camNames.size() ? app.camNames[i] : "");
	}

	std::stringstream ss;
	ss << app.numcams() << " cameras; frames per cam:";
	for (size_t i = 0; i < numpics.size(); i++) {
		ss << " " << i << ":" << numpics[i];
	}
	SetStatusText(ss.str());
}

void MainFrame::enableRender(bool enable) {
	if (enable) {
		renderinittime = Clock::now();
		numpics = std::vector<int>(app.numcams());
		timeline->clear();
		app.previewfeed.enable();
	} else {
		app.previewfeed.disable();
	}
}
void MainFrame::syncGrabbers(bool sync) {
	app.previewfeed.setsync(sync);
}

void MainFrame::timelineFollow(bool follow) {
	timeline->followInsertions(follow);
}

void MainFrame::onMenu(wxCommandEvent&) {
	std::cout << "menu" << std::endl;
}
void MainFrame::onExit(wxCommandEvent&) {
	Close(true);
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/renderer_host/image_transport_factory_android.h"

#include "base/lazy_instance.h"
#include "base/memory/singleton.h"
#include "base/strings/stringprintf.h"
#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
#include "content/browser/renderer_host/compositor_impl_android.h"
#include "content/common/gpu/client/gl_helper.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
#include "content/common/gpu/gpu_process_launch_causes.h"
#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "ui/gfx/android/device_display_info.h"
#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"

namespace content {

base::LazyInstance<ObserverList<ImageTransportFactoryAndroidObserver> >::Leaky
    g_factory_observers = LAZY_INSTANCE_INITIALIZER;

class GLContextLostListener
    : public WebKit::WebGraphicsContext3D::WebGraphicsContextLostCallback {
 public:
  // WebGraphicsContextLostCallback implementation.
  virtual void onContextLost() OVERRIDE;
 private:
  static void DidLoseContext();
};

namespace {

using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;

static ImageTransportFactoryAndroid* g_factory = NULL;

class DirectGLImageTransportFactory : public ImageTransportFactoryAndroid {
 public:
  DirectGLImageTransportFactory();
  virtual ~DirectGLImageTransportFactory();

  virtual uint32_t InsertSyncPoint() OVERRIDE { return 0; }
  virtual void WaitSyncPoint(uint32_t sync_point) OVERRIDE {}
  virtual uint32_t CreateTexture() OVERRIDE {
    return context_->createTexture();
  }
  virtual void DeleteTexture(uint32_t id) OVERRIDE {
    context_->deleteTexture(id);
  }
  virtual void AcquireTexture(
      uint32 texture_id, const signed char* mailbox_name) OVERRIDE {}
  virtual WebKit::WebGraphicsContext3D* GetContext3D() OVERRIDE {
    return context_.get();
  }
  virtual GLHelper* GetGLHelper() OVERRIDE { return NULL; }

 private:
  scoped_ptr<WebKit::WebGraphicsContext3D> context_;

  DISALLOW_COPY_AND_ASSIGN(DirectGLImageTransportFactory);
};

DirectGLImageTransportFactory::DirectGLImageTransportFactory() {
  WebKit::WebGraphicsContext3D::Attributes attrs;
  attrs.shareResources = true;
  attrs.noAutomaticFlushes = true;
  context_ = webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl::
      CreateViewContext(attrs, NULL);
  context_->setContextLostCallback(context_lost_listener_.get());
  if (context_->makeContextCurrent())
    context_->pushGroupMarkerEXT(
        base::StringPrintf("DirectGLImageTransportFactory-%p",
                           context_.get()).c_str());
}

DirectGLImageTransportFactory::~DirectGLImageTransportFactory() {
  context_->setContextLostCallback(NULL);
}

class CmdBufferImageTransportFactory : public ImageTransportFactoryAndroid {
 public:
  CmdBufferImageTransportFactory();
  virtual ~CmdBufferImageTransportFactory();

  virtual uint32_t InsertSyncPoint() OVERRIDE;
  virtual void WaitSyncPoint(uint32_t sync_point) OVERRIDE;
  virtual uint32_t CreateTexture() OVERRIDE;
  virtual void DeleteTexture(uint32_t id) OVERRIDE;
  virtual void AcquireTexture(
      uint32 texture_id, const signed char* mailbox_name) OVERRIDE;
  virtual WebKit::WebGraphicsContext3D* GetContext3D() OVERRIDE {
    return context_.get();
  }
  virtual GLHelper* GetGLHelper() OVERRIDE;

 private:
  scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context_;
  scoped_ptr<GLHelper> gl_helper_;

  DISALLOW_COPY_AND_ASSIGN(CmdBufferImageTransportFactory);
};

CmdBufferImageTransportFactory::CmdBufferImageTransportFactory() {
  WebKit::WebGraphicsContext3D::Attributes attrs;
  attrs.shareResources = true;
  GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance();
  GURL url("chrome://gpu/ImageTransportFactoryAndroid");
  base::WeakPtr<WebGraphicsContext3DSwapBuffersClient> swap_client;
  context_.reset(new WebGraphicsContext3DCommandBufferImpl(0, // offscreen
                                                           url,
                                                           factory,
                                                           swap_client));
  static const size_t kBytesPerPixel = 4;
  gfx::DeviceDisplayInfo display_info;
  size_t full_screen_texture_size_in_bytes =
      display_info.GetDisplayHeight() *
      display_info.GetDisplayWidth() *
      kBytesPerPixel;
  context_->setContextLostCallback(context_lost_listener_.get());
  context_->Initialize(
      attrs,
      false,
      CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE,
      64 * 1024,  // command buffer size
      std::min(full_screen_texture_size_in_bytes,
               kDefaultStartTransferBufferSize),
      kDefaultMinTransferBufferSize,
      std::min(3 * full_screen_texture_size_in_bytes,
               kDefaultMaxTransferBufferSize));

  if (context_->makeContextCurrent())
    context_->pushGroupMarkerEXT(
        base::StringPrintf("CmdBufferImageTransportFactory-%p",
                           context_.get()).c_str());
}

CmdBufferImageTransportFactory::~CmdBufferImageTransportFactory() {
  context_->setContextLostCallback(NULL);
}

uint32_t CmdBufferImageTransportFactory::InsertSyncPoint() {
  if (!context_->makeContextCurrent()) {
    LOG(ERROR) << "Failed to make helper context current.";
    return 0;
  }
  return context_->insertSyncPoint();
}

void CmdBufferImageTransportFactory::WaitSyncPoint(uint32_t sync_point) {
  if (!context_->makeContextCurrent()) {
    LOG(ERROR) << "Failed to make helper context current.";
    return;
  }
  context_->waitSyncPoint(sync_point);
}

uint32_t CmdBufferImageTransportFactory::CreateTexture() {
  if (!context_->makeContextCurrent()) {
    LOG(ERROR) << "Failed to make helper context current.";
    return false;
  }
  return context_->createTexture();
}

void CmdBufferImageTransportFactory::DeleteTexture(uint32_t id) {
  if (!context_->makeContextCurrent()) {
    LOG(ERROR) << "Failed to make helper context current.";
    return;
  }
  context_->deleteTexture(id);
}

void CmdBufferImageTransportFactory::AcquireTexture(
    uint32 texture_id, const signed char* mailbox_name) {
  if (!context_->makeContextCurrent()) {
    LOG(ERROR) << "Failed to make helper context current.";
    return;
  }
  context_->bindTexture(GL_TEXTURE_2D, texture_id);
  context_->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox_name);
  context_->flush();
}

GLHelper* CmdBufferImageTransportFactory::GetGLHelper() {
  if (!gl_helper_)
    gl_helper_.reset(new GLHelper(context_.get()));

  return gl_helper_.get();
}

}  // anonymous namespace

// static
ImageTransportFactoryAndroid* ImageTransportFactoryAndroid::GetInstance() {
  if (!g_factory) {
    if (CompositorImpl::UsesDirectGL())
      g_factory = new DirectGLImageTransportFactory();
    else
      g_factory = new CmdBufferImageTransportFactory();
  }

  return g_factory;
}

ImageTransportFactoryAndroid::ImageTransportFactoryAndroid()
    : context_lost_listener_(new GLContextLostListener()) {}

ImageTransportFactoryAndroid::~ImageTransportFactoryAndroid() {}

void ImageTransportFactoryAndroid::AddObserver(
    ImageTransportFactoryAndroidObserver* observer) {
  g_factory_observers.Get().AddObserver(observer);
}

void ImageTransportFactoryAndroid::RemoveObserver(
    ImageTransportFactoryAndroidObserver* observer) {
  g_factory_observers.Get().RemoveObserver(observer);
}

void GLContextLostListener::onContextLost() {
  // Need to post a task because the command buffer client cannot be deleted
  // from within this callback.
  LOG(ERROR) << "Context lost.";
  base::MessageLoop::current()->PostTask(
      FROM_HERE,
      base::Bind(&GLContextLostListener::DidLoseContext));
}

void GLContextLostListener::DidLoseContext() {
  delete g_factory;
  g_factory = NULL;
  FOR_EACH_OBSERVER(ImageTransportFactoryAndroidObserver,
      g_factory_observers.Get(),
      OnLostResources());
}

} // namespace content
<commit_msg>Set the start buffer size for the helper context to 64K<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/renderer_host/image_transport_factory_android.h"

#include "base/lazy_instance.h"
#include "base/memory/singleton.h"
#include "base/strings/stringprintf.h"
#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
#include "content/browser/renderer_host/compositor_impl_android.h"
#include "content/common/gpu/client/gl_helper.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
#include "content/common/gpu/gpu_process_launch_causes.h"
#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "ui/gfx/android/device_display_info.h"
#include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"

namespace content {

base::LazyInstance<ObserverList<ImageTransportFactoryAndroidObserver> >::Leaky
    g_factory_observers = LAZY_INSTANCE_INITIALIZER;

class GLContextLostListener
    : public WebKit::WebGraphicsContext3D::WebGraphicsContextLostCallback {
 public:
  // WebGraphicsContextLostCallback implementation.
  virtual void onContextLost() OVERRIDE;
 private:
  static void DidLoseContext();
};

namespace {

using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;

static ImageTransportFactoryAndroid* g_factory = NULL;

class DirectGLImageTransportFactory : public ImageTransportFactoryAndroid {
 public:
  DirectGLImageTransportFactory();
  virtual ~DirectGLImageTransportFactory();

  virtual uint32_t InsertSyncPoint() OVERRIDE { return 0; }
  virtual void WaitSyncPoint(uint32_t sync_point) OVERRIDE {}
  virtual uint32_t CreateTexture() OVERRIDE {
    return context_->createTexture();
  }
  virtual void DeleteTexture(uint32_t id) OVERRIDE {
    context_->deleteTexture(id);
  }
  virtual void AcquireTexture(
      uint32 texture_id, const signed char* mailbox_name) OVERRIDE {}
  virtual WebKit::WebGraphicsContext3D* GetContext3D() OVERRIDE {
    return context_.get();
  }
  virtual GLHelper* GetGLHelper() OVERRIDE { return NULL; }

 private:
  scoped_ptr<WebKit::WebGraphicsContext3D> context_;

  DISALLOW_COPY_AND_ASSIGN(DirectGLImageTransportFactory);
};

DirectGLImageTransportFactory::DirectGLImageTransportFactory() {
  WebKit::WebGraphicsContext3D::Attributes attrs;
  attrs.shareResources = true;
  attrs.noAutomaticFlushes = true;
  context_ = webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl::
      CreateViewContext(attrs, NULL);
  context_->setContextLostCallback(context_lost_listener_.get());
  if (context_->makeContextCurrent())
    context_->pushGroupMarkerEXT(
        base::StringPrintf("DirectGLImageTransportFactory-%p",
                           context_.get()).c_str());
}

DirectGLImageTransportFactory::~DirectGLImageTransportFactory() {
  context_->setContextLostCallback(NULL);
}

class CmdBufferImageTransportFactory : public ImageTransportFactoryAndroid {
 public:
  CmdBufferImageTransportFactory();
  virtual ~CmdBufferImageTransportFactory();

  virtual uint32_t InsertSyncPoint() OVERRIDE;
  virtual void WaitSyncPoint(uint32_t sync_point) OVERRIDE;
  virtual uint32_t CreateTexture() OVERRIDE;
  virtual void DeleteTexture(uint32_t id) OVERRIDE;
  virtual void AcquireTexture(
      uint32 texture_id, const signed char* mailbox_name) OVERRIDE;
  virtual WebKit::WebGraphicsContext3D* GetContext3D() OVERRIDE {
    return context_.get();
  }
  virtual GLHelper* GetGLHelper() OVERRIDE;

 private:
  scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context_;
  scoped_ptr<GLHelper> gl_helper_;

  DISALLOW_COPY_AND_ASSIGN(CmdBufferImageTransportFactory);
};

CmdBufferImageTransportFactory::CmdBufferImageTransportFactory() {
  WebKit::WebGraphicsContext3D::Attributes attrs;
  attrs.shareResources = true;
  GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance();
  GURL url("chrome://gpu/ImageTransportFactoryAndroid");
  base::WeakPtr<WebGraphicsContext3DSwapBuffersClient> swap_client;
  context_.reset(new WebGraphicsContext3DCommandBufferImpl(0, // offscreen
                                                           url,
                                                           factory,
                                                           swap_client));
  static const size_t kBytesPerPixel = 4;
  gfx::DeviceDisplayInfo display_info;
  size_t full_screen_texture_size_in_bytes =
      display_info.GetDisplayHeight() *
      display_info.GetDisplayWidth() *
      kBytesPerPixel;
  context_->setContextLostCallback(context_lost_listener_.get());
  context_->Initialize(
      attrs,
      false,
      CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE,
      64 * 1024,  // command buffer size
      64 * 1024,  // starting buffer size
      64 * 1024,  // min buffer size
      std::min(3 * full_screen_texture_size_in_bytes,
               kDefaultMaxTransferBufferSize));

  if (context_->makeContextCurrent())
    context_->pushGroupMarkerEXT(
        base::StringPrintf("CmdBufferImageTransportFactory-%p",
                           context_.get()).c_str());
}

CmdBufferImageTransportFactory::~CmdBufferImageTransportFactory() {
  context_->setContextLostCallback(NULL);
}

uint32_t CmdBufferImageTransportFactory::InsertSyncPoint() {
  if (!context_->makeContextCurrent()) {
    LOG(ERROR) << "Failed to make helper context current.";
    return 0;
  }
  return context_->insertSyncPoint();
}

void CmdBufferImageTransportFactory::WaitSyncPoint(uint32_t sync_point) {
  if (!context_->makeContextCurrent()) {
    LOG(ERROR) << "Failed to make helper context current.";
    return;
  }
  context_->waitSyncPoint(sync_point);
}

uint32_t CmdBufferImageTransportFactory::CreateTexture() {
  if (!context_->makeContextCurrent()) {
    LOG(ERROR) << "Failed to make helper context current.";
    return false;
  }
  return context_->createTexture();
}

void CmdBufferImageTransportFactory::DeleteTexture(uint32_t id) {
  if (!context_->makeContextCurrent()) {
    LOG(ERROR) << "Failed to make helper context current.";
    return;
  }
  context_->deleteTexture(id);
}

void CmdBufferImageTransportFactory::AcquireTexture(
    uint32 texture_id, const signed char* mailbox_name) {
  if (!context_->makeContextCurrent()) {
    LOG(ERROR) << "Failed to make helper context current.";
    return;
  }
  context_->bindTexture(GL_TEXTURE_2D, texture_id);
  context_->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox_name);
  context_->flush();
}

GLHelper* CmdBufferImageTransportFactory::GetGLHelper() {
  if (!gl_helper_)
    gl_helper_.reset(new GLHelper(context_.get()));

  return gl_helper_.get();
}

}  // anonymous namespace

// static
ImageTransportFactoryAndroid* ImageTransportFactoryAndroid::GetInstance() {
  if (!g_factory) {
    if (CompositorImpl::UsesDirectGL())
      g_factory = new DirectGLImageTransportFactory();
    else
      g_factory = new CmdBufferImageTransportFactory();
  }

  return g_factory;
}

ImageTransportFactoryAndroid::ImageTransportFactoryAndroid()
    : context_lost_listener_(new GLContextLostListener()) {}

ImageTransportFactoryAndroid::~ImageTransportFactoryAndroid() {}

void ImageTransportFactoryAndroid::AddObserver(
    ImageTransportFactoryAndroidObserver* observer) {
  g_factory_observers.Get().AddObserver(observer);
}

void ImageTransportFactoryAndroid::RemoveObserver(
    ImageTransportFactoryAndroidObserver* observer) {
  g_factory_observers.Get().RemoveObserver(observer);
}

void GLContextLostListener::onContextLost() {
  // Need to post a task because the command buffer client cannot be deleted
  // from within this callback.
  LOG(ERROR) << "Context lost.";
  base::MessageLoop::current()->PostTask(
      FROM_HERE,
      base::Bind(&GLContextLostListener::DidLoseContext));
}

void GLContextLostListener::DidLoseContext() {
  delete g_factory;
  g_factory = NULL;
  FOR_EACH_OBSERVER(ImageTransportFactoryAndroidObserver,
      g_factory_observers.Get(),
      OnLostResources());
}

} // namespace content
<|endoftext|>