<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 Kevin Fiedler
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
#include <time.h>
#include <iostream>

#include "system_stats.h"
#include "unix_functions.h"
#include "ini.h"

using namespace std;

#define MAX_TIME 120

#define PATHC 2
const string PATH[] = {"/usr/local/etc/serverstatus.conf", "/etc/serverstatus.conf"};

// writes the path to the config file into the submitted parameter:
bool getConfigFilePath(string &output) {
  for (int i = 0; i < PATHC; i++) {
    if (FileExists(PATH[i])) {
      output = PATH[i];
      return true;
    }
  }
  return false;
}

int main(int argc, char *argv[]) {

  // Load configuration
  string _configpath;
  if (!getConfigFilePath(_configpath)) {
    printf("Could not find a configuration file. \nMake sure a file called \"serverstatus.conf\" is located at \"/usr/local/etc/\" or \"/etc/\". \n");
    exit(EXIT_FAILURE);
  }

  /***************************************************************
  *** ServerStatus differentiates between two modes:
  ***  1) The main mode is starting without any parameters:
  ***     It then creates a daemon that keeps running in the
  ***     background until the OS shuts down or the process
  ***     is killed
  ***  2) The secound mode is starting with paramteres:
  ***     Right now that only enables configuration mode.
  ***     Open "serverstatus --config" or "serverstatus -c"
  ***************************************************************/

  if ((argc > 0) && (strcmp(argv[1],"start") != 0)) {
    // MODE 2:

    // Change into config mode:
    if ((strcmp(argv[1], "--config") == 0) || (strcmp(argv[1], "-c") == 0)) {
      // TODO!
      exit(EXIT_SUCCESS);
    }

    // kill any running instances of serverstatus
    if (strcmp(argv[1], "stop") == 0) {
      string cmd = "pgrep serverstatus";
      if (getCmdOutput(&cmd[0]) != "") {
        cmd = "killall serverstatus";
        getCmdOutput(&cmd[0]);
        printf("Process serverstatus stopped. \n");
        exit(EXIT_SUCCESS);
      }

    }

  } else {
    // MODE 1:
    // Start a daemon process and read the system statistics in the background

    // check of an instance of serverstatus is already running in the background
    string cmd = "pgrep serverstatus";
	if (getCmdOutput(&cmd[0]) != "") {
      printf("Daemon is running already. \n");
      exit(EXIT_FAILURE);
    }

    pid_t pid, sid;

    pid = fork();

    // could not create child process
    if (pid < 0) { exit(EXIT_FAILURE); }

    // child process created: terminate parent
    if (pid > 0) { exit(EXIT_SUCCESS); }

    umask(0);

    // using syslog local1 for this daemon
    //setlogmask(LOG_UPTO (LOG_NOTICE));
    openlog("ServerStatus", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);

    syslog(LOG_NOTICE, "Started by User %d", getuid());

    sid = setsid();
    if (sid < 0) {
      syslog (LOG_ERR, "Error: Could not create new sid for child process");
      exit(EXIT_FAILURE);
    }
    syslog(LOG_DEBUG, "New SID for child process created.");

    if ((chdir("/")) < 0) {
      syslog (LOG_ERR, "Error: Could not change working directory.");
      exit(EXIT_FAILURE);
    }
    syslog(LOG_DEBUG, "Changed working directory to root directory.");

    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);

    // variables
    int i = 0;
    int elapsedTime = 0;

    time_t startTime,endTime;

    INI ini(_configpath);

    int hdd_interval = ini.readInt("HDD", "interval");
    int mount_interval = ini.readInt("Mount", "interval");
    int cpu_interval = ini.readInt("CPU", "interval");
    int load_interval = ini.readInt("Load", "interval");
    int memory_interval = ini.readInt("Memory", "interval");

    syslog(LOG_DEBUG, "Configuration file loaded.");

    // create system stat classes
    SystemStats cpu(CPU, _configpath);
    SystemStats load(Load, _configpath);
    SystemStats hdd(HDD, _configpath);
    SystemStats mount(Mount, _configpath);
    SystemStats mem(Memory, _configpath);

    syslog(LOG_DEBUG, "Class objects created.");

    // the main loop: here comes all the stuff that has to be repeated
    // the loop fires once every minute
    while(1) {

      // get the duration of function calling...
      startTime = clock();

      if (i % hdd_interval == 0) {
        hdd.readStatus();
      }

      if (i % mount_interval == 0) {
        mount.readStatus();
      }

      if (i % cpu_interval == 0) {
        cpu.readStatus();
      }

      if (i % load_interval == 0) {
        load.readStatus();
      }

      if (i % memory_interval == 0) {
        mem.readStatus();
      }

      // update counter
      if (i < MAX_TIME) { i++; }
      else { i = 0; }

      syslog (LOG_DEBUG, "loop no. %d finished", i);

      // now calculate how long we have to sleep
      endTime = clock();
      elapsedTime = (endTime - startTime)/CLOCKS_PER_SEC;

      sleep(60 - elapsedTime);  // let each loop last one minute
    }

    closelog();
    exit(EXIT_SUCCESS);
  }
}<commit_msg>Added configuration<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 Kevin Fiedler
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
#include <time.h>
#include <iostream>
#include <limits>

#include "system_stats.h"
#include "unix_functions.h"
#include "ini.h"

using namespace std;

#define MAX_TIME 120

#define PATHC 2
const string PATH[] = {"/usr/local/etc/serverstatus.conf", "/etc/serverstatus.conf"};

// writes the path to the config file into the submitted parameter:
bool getConfigFilePath(string &output) {
  for (int i = 0; i < PATHC; i++) {
    if (FileExists(PATH[i])) {
      output = PATH[i];
      return true;
    }
  }
  return false;
}

void flush_cin() {
  cin.clear();
  cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}

void configureOption(const string &configFile, const string section, const string description, const int defaultInterval) {
  // load ini-file:
  INI ini(configFile);

  system("clear");
  printf("============================================================= \n");
  printf("== Start the configuration for %s: \n", description.c_str());
  printf("============================================================= \n \n");

  flush_cin();
  char _char_input = 'Y';
  string _input;

  do {
    printf("Do you want to activate to read %s? [Y/n] ", description.c_str());
    scanf("%c", &_char_input);
  } while ((_char_input != 'Y') && (_char_input != 'y') && (_char_input != 'N') && (_char_input != 'n') && (_char_input != 10 ));

  if ((_char_input == 'Y') || (_char_input == 'y') || (_char_input == 10)) {

    int _numeric_value, _element_count;
    bool _valid = false;

    // read interval
    while( !_valid ) {
      printf("Enter the interval in which the %s shell be read (in minutes): [default %d] ", description.c_str(), defaultInterval);
      cin >> _input;

      if ((_numeric_value = atoi(_input.c_str())) == 0) {
        printf("You entered an invalid input. Please enter a numeric value greater than zero.\n");
      } else {
	    _valid = true;
        ini.writeInt(section, "interval", _numeric_value);
      }
      flush_cin();
    }

    _valid = false;
    // read array size
    while( !_valid ) {
      printf("Enter how many old values should be stored: [default 30] ");
      cin >> _input;

      if ((_numeric_value = atoi(_input.c_str())) == 0) {
        printf("You entered an invalid input. Please enter a numeric value greater than zero.\n");
      } else {
	    _valid = true;
        ini.writeInt(section, "elements", _numeric_value);
      }
      flush_cin();
    }

    _valid = false;
    // read element count
    while( !_valid ) {
      printf("Enter how many different values exist (e.g. 2 cores, 5 discs, ...): ");
      cin >> _input;

      if ((_element_count = atoi(_input.c_str())) == 0) {
        printf("You entered an invalid input. Please enter a numeric value greater than zero.\n");
      } else {
	    _valid = true;
        ini.writeInt(section, "count", _element_count);
      }
      flush_cin();
    }

    // read description and command for each element
    for (int i = 0; i < _element_count; i++) {

        printf("Enter a description for element no. %d: ", i+1);
        getline(cin, _input);
        //flush_cin();
        ini.writeString(section, "desc" + IntToStr(i+1), _input);

        printf("Enter a shell command that returns a integer or float value for element no. %d: ", i+1);
        getline(cin, _input);
        //flush_cin();
        ini.writeString(section, "cmd" + IntToStr(i+1), _input);
    }

    printf("\n%s configuration successful. \nPress any key to exit. \n", description.c_str());
    scanf("%c", &_char_input);

  } else {
    // setting the count to zero deactivates the function
    ini.writeInt("CPU", "count", 0);
  }

  // save changed ini file
  ini.saveToFile(configFile);
}

void runConfiguration(const string &configFile) {
  bool _exit = false;
  while (!_exit) {
    system("clear");
    printf("\n Please enter a number to start the configuration: \n");
    printf("  1) CPU temperature \n");
    printf("  2) Load Average \n");
    printf("  3) HDD temperature \n");
    printf("  4) Disc space \n");
    printf("  5) Memory \n");
    printf("  6) Exit \n \n");
    char _input;
    scanf("%c", &_input);

    if (_input != '6') {
      // configure selected option
      switch (_input) {
        case '1': configureOption(configFile, "CPU", "CPU temperature", 5); break;
        case '2': configureOption(configFile, "Load", "Load Average", 1); break;
        case '3': configureOption(configFile, "HDD", "HDD temperature", 60); break;
        case '4': configureOption(configFile, "Mount", "disc space", 60); break;
        case '5': configureOption(configFile, "Memory", "memory", 1); break;
        default:  break;
      }
    } else { _exit = true; }
  }
}

int main(int argc, char *argv[]) {

  // Load configuration
  string _configpath;
  if (!getConfigFilePath(_configpath)) {
    printf("Could not find a configuration file. \nMake sure a file called \"serverstatus.conf\" is located at \"/usr/local/etc/\" or \"/etc/\". \n");
    exit(EXIT_FAILURE);
  }

  /***************************************************************
  *** ServerStatus differentiates between two modes:
  ***  1) The main mode is starting without any parameters:
  ***     It then creates a daemon that keeps running in the
  ***     background until the OS shuts down or the process
  ***     is killed
  ***  2) The secound mode is starting with paramteres:
  ***     Right now that only enables configuration mode.
  ***     Open "serverstatus --config" or "serverstatus -c"
  ***************************************************************/

  if ((argc > 0) && (strcmp(argv[1],"start") != 0)) {
    // MODE 2:

    // Change into config mode:
    if ((strcmp(argv[1], "--config") == 0) || (strcmp(argv[1], "-c") == 0)) {
      runConfiguration(_configpath);
      exit(EXIT_SUCCESS);
    }

    // kill any running instances of serverstatus
    if (strcmp(argv[1], "stop") == 0) {
      string cmd = "pgrep serverstatus";
      if (getCmdOutput(&cmd[0]) != "") {
        cmd = "killall serverstatus";
        getCmdOutput(&cmd[0]);
        printf("Process serverstatus stopped. \n");
        exit(EXIT_SUCCESS);
      }

    }

  } else {
    // MODE 1:
    // Start a daemon process and read the system statistics in the background

    // check of an instance of serverstatus is already running in the background
    string cmd = "pgrep serverstatus";
	if (getCmdOutput(&cmd[0]) != "") {
      printf("Daemon is running already. \n");
      exit(EXIT_FAILURE);
    }

    pid_t pid, sid;

    pid = fork();

    // could not create child process
    if (pid < 0) { exit(EXIT_FAILURE); }

    // child process created: terminate parent
    if (pid > 0) { exit(EXIT_SUCCESS); }

    umask(0);

    // using syslog local1 for this daemon
    //setlogmask(LOG_UPTO (LOG_NOTICE));
    openlog("ServerStatus", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);

    syslog(LOG_NOTICE, "Started by User %d", getuid());

    sid = setsid();
    if (sid < 0) {
      syslog (LOG_ERR, "Error: Could not create new sid for child process");
      exit(EXIT_FAILURE);
    }
    syslog(LOG_DEBUG, "New SID for child process created.");

    if ((chdir("/")) < 0) {
      syslog (LOG_ERR, "Error: Could not change working directory.");
      exit(EXIT_FAILURE);
    }
    syslog(LOG_DEBUG, "Changed working directory to root directory.");

    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);

    // variables
    int i = 0;
    int elapsedTime = 0;

    time_t startTime,endTime;

    INI ini(_configpath);

    int hdd_interval = ini.readInt("HDD", "interval");
    int mount_interval = ini.readInt("Mount", "interval");
    int cpu_interval = ini.readInt("CPU", "interval");
    int load_interval = ini.readInt("Load", "interval");
    int memory_interval = ini.readInt("Memory", "interval");

    syslog(LOG_DEBUG, "Configuration file loaded.");

    // create system stat classes
    SystemStats cpu(CPU, _configpath);
    SystemStats load(Load, _configpath);
    SystemStats hdd(HDD, _configpath);
    SystemStats mount(Mount, _configpath);
    SystemStats mem(Memory, _configpath);

    syslog(LOG_DEBUG, "Class objects created.");

    // the main loop: here comes all the stuff that has to be repeated
    // the loop fires once every minute
    while(1) {

      // get the duration of function calling...
      startTime = clock();

      if (i % hdd_interval == 0) {
        hdd.readStatus();
      }

      if (i % mount_interval == 0) {
        mount.readStatus();
      }

      if (i % cpu_interval == 0) {
        cpu.readStatus();
      }

      if (i % load_interval == 0) {
        load.readStatus();
      }

      if (i % memory_interval == 0) {
        mem.readStatus();
      }

      // update counter
      if (i < MAX_TIME) { i++; }
      else { i = 0; }

      syslog (LOG_DEBUG, "loop no. %d finished", i);

      // now calculate how long we have to sleep
      endTime = clock();
      elapsedTime = (endTime - startTime)/CLOCKS_PER_SEC;

      sleep(60 - elapsedTime);  // let each loop last one minute
    }

    closelog();
    exit(EXIT_SUCCESS);
  }
}<|endoftext|>


<commit_before>
#include <cstring>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <array>

#include "config.h"

#include <mapper/mapper_cpp.h>

#ifdef HAVE_ARPA_INET_H
 #include <arpa/inet.h>
#endif

int received = 0;

void insig_handler(mapper_signal sig, mapper_id instance, const void *value,
                   int count, mapper_timetag_t *timetag)
{
    if (value) {
        printf("--> destination got %s", mapper_signal_name(sig));
        int len = mapper_signal_length(sig);
        switch (mapper_signal_type(sig)) {
            case 'i': {
                int *v = (int*)value;
                for (int i = 0; i < len; i++) {
                    printf(" %d", v[i]);
                }
                break;
            }
            case 'f': {
                float *v = (float*)value;
                for (int i = 0; i < len; i++) {
                    printf(" %f", v[i]);
                }
            }
            case 'd': {
                double *v = (double*)value;
                for (int i = 0; i < len; i++) {
                    printf(" %f", v[i]);
                }
            }
            default:
                break;
        }
        printf("\n");
    }
    received++;
}

int main(int argc, char ** argv)
{
    unsigned int i = 0;
    int result = 0;

    mapper::Device dev("mydevice");

    // make a copy of the device to check reference counting
    mapper::Device devcopy(dev);

    mapper::Signal sig = dev.add_input_signal("in1", 1, 'f', "meters", 0, 0,
                                              insig_handler);
    dev.remove_signal(sig);
    dev.add_input_signal("in2", 2, 'i', 0, 0, 0, insig_handler);
    dev.add_input_signal("in3", 2, 'i', 0, 0, 0, insig_handler);
    dev.add_input_signal("in4", 2, 'i', 0, 0, 0, insig_handler);

    sig = dev.add_output_signal("out1", 1, 'f', "na");
    dev.remove_signal(sig);
    sig = dev.add_output_signal("out2", 3, 'd', "meters");

    while (!dev.ready()) {
        dev.poll(100);
    }

    std::cout << "device " << dev.name() << " ready..." << std::endl;
    std::cout << "  ordinal: " << dev.ordinal() << std::endl;
    std::cout << "  id: " << dev.id() << std::endl;
    std::cout << "  interface: " << dev.network().interface() << std::endl;
    const struct in_addr* a = dev.network().ip4();
    if (a)
        std::cout << "  host: " << inet_ntoa(*a) << std::endl;
    std::cout << "  port: " << dev.port() << std::endl;
    std::cout << "  num_fds: " << dev.num_fds() << std::endl;
    std::cout << "  num_inputs: " << dev.num_signals(MAPPER_DIR_INCOMING) << std::endl;
    std::cout << "  num_outputs: " << dev.num_signals(MAPPER_DIR_OUTGOING) << std::endl;
    std::cout << "  num_incoming_maps: " << dev.num_maps(MAPPER_DIR_INCOMING) << std::endl;
    std::cout << "  num_outgoing_maps: " << dev.num_maps(MAPPER_DIR_OUTGOING) << std::endl;

    // access properties through the property getter
    std::cout << "name: " << (const char*)dev.property("name") << std::endl;

    int value[] = {1,2,3,4,5,6};
    dev.set_property("foo", 6, value);
    const int *tempi = dev.property("foo");
    std::cout << "foo: ";
    for (i = 0; i < 6; i++)
        std::cout << tempi[i] << " ";
    std::cout << std::endl;

    // test std::array<std::string>
    std::cout << "set and get std::array<std::string>: ";
    std::array<std::string, 3> a1 = {{"one", "two", "three"}};
    dev.set_property("foo", a1);
    const std::array<std::string, 8> a2 = dev.property("foo");
    for (i = 0; i < 8; i++)
        std::cout << a2[i] << " ";
    std::cout << std::endl;

    // test std::array<const char*>
    std::cout << "set and get std::array<const char*>: ";
    std::array<const char*, 3> a3 = {{"four", "five", "six"}};
    dev.set_property("foo", a3);
    std::array<const char*, 3> a4 = dev.property("foo");
    for (i = 0; i < a4.size(); i++)
        std::cout << a4[i] << " ";
    std::cout << std::endl;

    // test plain array of const char*
    std::cout << "set and get const char*[]: ";
    const char* a5[3] = {"seven", "eight", "nine"};
    dev.set_property("foo", 3, a5);
    const char **a6 = dev.property("foo");
    std::cout << a6[0] << " " << a6[1] << " " << a6[2] << std::endl;

    // test plain array of float
    std::cout << "set and get float[]: ";
    float a7[3] = {7.7f, 8.8f, 9.9f};
    dev.set_property("foo", 3, a7);
    const float *a8 = dev.property("foo");
    std::cout << a8[0] << " " << a8[1] << " " << a8[2] << std::endl;

    // test std::vector<const char*>
    std::cout << "set and get std::vector<const char*>: ";
    const char *a9[3] = {"ten", "eleven", "twelve"};
    std::vector<const char*> v1(a9, std::end(a9));
    dev.set_property("foo", v1);
    std::vector<const char*> v2 = dev.property("foo");
    std::cout << "foo: ";
    for (std::vector<const char*>::iterator it = v2.begin(); it != v2.end(); ++it)
        std::cout << *it << " ";
    std::cout << std::endl;

    // test std::vector<std::string>
    std::cout << "set and get std::vector<std::string>: ";
    const char *a10[3] = {"thirteen", "14", "15"};
    std::vector<std::string> v3(a10, std::end(a10));
    dev.set_property("foo", v3);
    std::vector<std::string> v4 = dev.property("foo");
    std::cout << "foo: ";
    for (std::vector<std::string>::iterator it = v4.begin(); it != v4.end(); ++it)
        std::cout << *it << " ";
    std::cout << std::endl;

    mapper::Property p("temp", "tempstring");
    dev.set_property(p);
    std::cout << p.name << ": " << (const char*)p << std::endl;

    dev.remove_property("foo");
    std::cout << "foo: " << dev.property("foo").value
        << " (should be 0x0)" << std::endl;

    std::cout << "signal: " << (const char*)sig << std::endl;

    mapper::Signal::Query qsig = dev.signals(MAPPER_DIR_INCOMING).begin();
    for (; qsig != qsig.end(); ++qsig) {
        std::cout << "input: " << (const char*)(*qsig) << std::endl;
    }

    mapper::Database db(MAPPER_OBJ_ALL);
    mapper::Map map(dev.signals(MAPPER_DIR_OUTGOING)[0],
                    dev.signals(MAPPER_DIR_INCOMING)[1]);
    map.set_mode(MAPPER_MODE_EXPRESSION).set_expression("y=x[0:1]+123");
    double d[3] = {1., 2., 3.};
    map.source().set_minimum(mapper::Property(0, 3, d));
    map.push();

    while (!map.ready()) {
        dev.poll(100);
    }

    std::vector <double> v(3);
    while (i++ < 100) {
        dev.poll(10);
        db.poll();
        v[i%3] = i;
        sig.update(v);
    }

    // try combining queries
    mapper::Device::Query qdev = db.devices("my*");
    qdev += db.devices(mapper::Property("num_inputs", 4),
                       MAPPER_OP_GREATER_THAN_OR_EQUAL);
    for (; qdev != qdev.end(); qdev++) {
        std::cout << "  r device: " << (const char*)(*qdev) << std::endl;
    }

    // check database records
    std::cout << "database records:" << std::endl;
    for (auto const &device : db.devices()) {
        std::cout << "  device: " << (const char*)device.property("name") << std::endl;
        for (auto const &signal : device.signals(MAPPER_DIR_INCOMING)) {
            std::cout << "  input signal: " << device.name()
                      << "/" << signal.name() << std::endl;
        }
        for (auto const &signal : device.signals(MAPPER_DIR_OUTGOING)) {
            std::cout << "  output signal: " << device.name()
                      << "/" << signal.name() << std::endl;
        }
    }
    for (auto const& link : db.links()) {
        std::cout << "  link: " << link.device(0).name() << " <-> "
                  << link.device(1).name() << std::endl;
    }
    for (auto const &m : db.maps()) {
        std::cout << "  map: ";
        if (m.num_slots(MAPPER_LOC_SOURCE) > 1)
            std::cout << "[";
        for (int i = 0; i < m.num_slots(MAPPER_LOC_SOURCE); i++) {
            std::cout << m.source(i).signal().device().name()
                      << "/" << m.source(i).signal().name() << ", ";
        }
        std::cout << "\b\b";
        if (m.num_slots(MAPPER_LOC_SOURCE) > 1)
            std::cout << "]";
        std::cout << " -> " << m.destination().signal().device().name()
                  << "/" << m.destination().signal().name() << std::endl;
    }

    // test some timetag manipulation
    mapper::Timetag tt1(10, 200);
    mapper::Timetag tt2(10, 300);
    if (tt1 < tt2)
        std::cout << "tt1 is less than tt2" << std::endl;
    tt1 += tt2;
    if (tt1 >= tt2)
        std::cout << "(tt1 + tt2) is greater then or equal to tt2" << std::endl;

    printf("Test %s.\n", result ? "FAILED" : "PASSED");
    return result;
}
<commit_msg>added missing break in c++ example sig handler<commit_after>
#include <cstring>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <array>

#include "config.h"

#include <mapper/mapper_cpp.h>

#ifdef HAVE_ARPA_INET_H
 #include <arpa/inet.h>
#endif

int received = 0;

void insig_handler(mapper_signal sig, mapper_id instance, const void *value,
                   int count, mapper_timetag_t *timetag)
{
    if (value) {
        printf("--> destination got %s", mapper_signal_name(sig));
        int len = mapper_signal_length(sig);
        switch (mapper_signal_type(sig)) {
            case 'i': {
                int *v = (int*)value;
                for (int i = 0; i < len; i++) {
                    printf(" %d", v[i]);
                }
                break;
            }
            case 'f': {
                float *v = (float*)value;
                for (int i = 0; i < len; i++) {
                    printf(" %f", v[i]);
                }
                break;
            }
            case 'd': {
                double *v = (double*)value;
                for (int i = 0; i < len; i++) {
                    printf(" %f", v[i]);
                }
                break;
            }
            default:
                break;
        }
        printf("\n");
    }
    received++;
}

int main(int argc, char ** argv)
{
    unsigned int i = 0;
    int result = 0;

    mapper::Device dev("mydevice");

    // make a copy of the device to check reference counting
    mapper::Device devcopy(dev);

    mapper::Signal sig = dev.add_input_signal("in1", 1, 'f', "meters", 0, 0,
                                              insig_handler);
    dev.remove_signal(sig);
    dev.add_input_signal("in2", 2, 'i', 0, 0, 0, insig_handler);
    dev.add_input_signal("in3", 2, 'i', 0, 0, 0, insig_handler);
    dev.add_input_signal("in4", 2, 'i', 0, 0, 0, insig_handler);

    sig = dev.add_output_signal("out1", 1, 'f', "na");
    dev.remove_signal(sig);
    sig = dev.add_output_signal("out2", 3, 'd', "meters");

    while (!dev.ready()) {
        dev.poll(100);
    }

    std::cout << "device " << dev.name() << " ready..." << std::endl;
    std::cout << "  ordinal: " << dev.ordinal() << std::endl;
    std::cout << "  id: " << dev.id() << std::endl;
    std::cout << "  interface: " << dev.network().interface() << std::endl;
    const struct in_addr* a = dev.network().ip4();
    if (a)
        std::cout << "  host: " << inet_ntoa(*a) << std::endl;
    std::cout << "  port: " << dev.port() << std::endl;
    std::cout << "  num_fds: " << dev.num_fds() << std::endl;
    std::cout << "  num_inputs: " << dev.num_signals(MAPPER_DIR_INCOMING) << std::endl;
    std::cout << "  num_outputs: " << dev.num_signals(MAPPER_DIR_OUTGOING) << std::endl;
    std::cout << "  num_incoming_maps: " << dev.num_maps(MAPPER_DIR_INCOMING) << std::endl;
    std::cout << "  num_outgoing_maps: " << dev.num_maps(MAPPER_DIR_OUTGOING) << std::endl;

    // access properties through the property getter
    std::cout << "name: " << (const char*)dev.property("name") << std::endl;

    int value[] = {1,2,3,4,5,6};
    dev.set_property("foo", 6, value);
    const int *tempi = dev.property("foo");
    std::cout << "foo: ";
    for (i = 0; i < 6; i++)
        std::cout << tempi[i] << " ";
    std::cout << std::endl;

    // test std::array<std::string>
    std::cout << "set and get std::array<std::string>: ";
    std::array<std::string, 3> a1 = {{"one", "two", "three"}};
    dev.set_property("foo", a1);
    const std::array<std::string, 8> a2 = dev.property("foo");
    for (i = 0; i < 8; i++)
        std::cout << a2[i] << " ";
    std::cout << std::endl;

    // test std::array<const char*>
    std::cout << "set and get std::array<const char*>: ";
    std::array<const char*, 3> a3 = {{"four", "five", "six"}};
    dev.set_property("foo", a3);
    std::array<const char*, 3> a4 = dev.property("foo");
    for (i = 0; i < a4.size(); i++)
        std::cout << a4[i] << " ";
    std::cout << std::endl;

    // test plain array of const char*
    std::cout << "set and get const char*[]: ";
    const char* a5[3] = {"seven", "eight", "nine"};
    dev.set_property("foo", 3, a5);
    const char **a6 = dev.property("foo");
    std::cout << a6[0] << " " << a6[1] << " " << a6[2] << std::endl;

    // test plain array of float
    std::cout << "set and get float[]: ";
    float a7[3] = {7.7f, 8.8f, 9.9f};
    dev.set_property("foo", 3, a7);
    const float *a8 = dev.property("foo");
    std::cout << a8[0] << " " << a8[1] << " " << a8[2] << std::endl;

    // test std::vector<const char*>
    std::cout << "set and get std::vector<const char*>: ";
    const char *a9[3] = {"ten", "eleven", "twelve"};
    std::vector<const char*> v1(a9, std::end(a9));
    dev.set_property("foo", v1);
    std::vector<const char*> v2 = dev.property("foo");
    std::cout << "foo: ";
    for (std::vector<const char*>::iterator it = v2.begin(); it != v2.end(); ++it)
        std::cout << *it << " ";
    std::cout << std::endl;

    // test std::vector<std::string>
    std::cout << "set and get std::vector<std::string>: ";
    const char *a10[3] = {"thirteen", "14", "15"};
    std::vector<std::string> v3(a10, std::end(a10));
    dev.set_property("foo", v3);
    std::vector<std::string> v4 = dev.property("foo");
    std::cout << "foo: ";
    for (std::vector<std::string>::iterator it = v4.begin(); it != v4.end(); ++it)
        std::cout << *it << " ";
    std::cout << std::endl;

    mapper::Property p("temp", "tempstring");
    dev.set_property(p);
    std::cout << p.name << ": " << (const char*)p << std::endl;

    dev.remove_property("foo");
    std::cout << "foo: " << dev.property("foo").value
        << " (should be 0x0)" << std::endl;

    std::cout << "signal: " << (const char*)sig << std::endl;

    mapper::Signal::Query qsig = dev.signals(MAPPER_DIR_INCOMING).begin();
    for (; qsig != qsig.end(); ++qsig) {
        std::cout << "input: " << (const char*)(*qsig) << std::endl;
    }

    mapper::Database db(MAPPER_OBJ_ALL);
    mapper::Map map(dev.signals(MAPPER_DIR_OUTGOING)[0],
                    dev.signals(MAPPER_DIR_INCOMING)[1]);
    map.set_mode(MAPPER_MODE_EXPRESSION).set_expression("y=x[0:1]+123");
    double d[3] = {1., 2., 3.};
    map.source().set_minimum(mapper::Property(0, 3, d));
    map.push();

    while (!map.ready()) {
        dev.poll(100);
    }

    std::vector <double> v(3);
    while (i++ < 100) {
        dev.poll(10);
        db.poll();
        v[i%3] = i;
        sig.update(v);
    }

    // try combining queries
    mapper::Device::Query qdev = db.devices("my*");
    qdev += db.devices(mapper::Property("num_inputs", 4),
                       MAPPER_OP_GREATER_THAN_OR_EQUAL);
    for (; qdev != qdev.end(); qdev++) {
        std::cout << "  r device: " << (const char*)(*qdev) << std::endl;
    }

    // check database records
    std::cout << "database records:" << std::endl;
    for (auto const &device : db.devices()) {
        std::cout << "  device: " << (const char*)device.property("name") << std::endl;
        for (auto const &signal : device.signals(MAPPER_DIR_INCOMING)) {
            std::cout << "  input signal: " << device.name()
                      << "/" << signal.name() << std::endl;
        }
        for (auto const &signal : device.signals(MAPPER_DIR_OUTGOING)) {
            std::cout << "  output signal: " << device.name()
                      << "/" << signal.name() << std::endl;
        }
    }
    for (auto const& link : db.links()) {
        std::cout << "  link: " << link.device(0).name() << " <-> "
                  << link.device(1).name() << std::endl;
    }
    for (auto const &m : db.maps()) {
        std::cout << "  map: ";
        if (m.num_slots(MAPPER_LOC_SOURCE) > 1)
            std::cout << "[";
        for (int i = 0; i < m.num_slots(MAPPER_LOC_SOURCE); i++) {
            std::cout << m.source(i).signal().device().name()
                      << "/" << m.source(i).signal().name() << ", ";
        }
        std::cout << "\b\b";
        if (m.num_slots(MAPPER_LOC_SOURCE) > 1)
            std::cout << "]";
        std::cout << " -> " << m.destination().signal().device().name()
                  << "/" << m.destination().signal().name() << std::endl;
    }

    // test some timetag manipulation
    mapper::Timetag tt1(10, 200);
    mapper::Timetag tt2(10, 300);
    if (tt1 < tt2)
        std::cout << "tt1 is less than tt2" << std::endl;
    tt1 += tt2;
    if (tt1 >= tt2)
        std::cout << "(tt1 + tt2) is greater then or equal to tt2" << std::endl;

    printf("Test %s.\n", result ? "FAILED" : "PASSED");
    return result;
}
<|endoftext|>


<commit_before>/* -*- mode:C++; -*- */
/* MyThOS: The Many-Threads Operating System
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Copyright 2016 Randolf Rotta, and contributors, BTU Cottbus-Senftenberg
 */
#pragma once

#include <cstddef> // for size_t
#include <cstdint> // for uint32_t etc
#include "util/bitfield.hh"

namespace mythos {

  class LAPICdef
  {
  public:
    enum RegisterAddr {
      REG_APICID                = 0x20,
      REG_VERSION               = 0x30,
      REG_LDR                   = 0xD0,
      REG_DFR                   = 0xE0,
      REG_SVR                   = 0xF0,
      REG_ISR                   = 0x100,
      REG_IRR                   = 0x200,
      REG_ESR                   = 0x280,
      REG_LVT_CMCI              = 0x2F0,
      REG_ICR_LOW               = 0x300,
      REG_ICR_HIGH              = 0x310,
      REG_LVT_TIMER             = 0x320,
      REG_LVT_THERMAL           = 0x330,
      REG_LVT_PERFCNT           = 0x340,
      REG_LVT_LINT0             = 0x350,
      REG_LVT_LINT1             = 0x360,
      REG_LVT_ERROR             = 0x370,
      REG_TIMER_ICR             = 0x380,
      REG_TIMER_CCR             = 0x390,
      REG_TIMER_DCR             = 0x3E0,
      REG_TASK_PRIO             = 0x80,
      REG_EOI                   = 0xB0
    };

    enum IcrDeliveryMode {
      MODE_FIXED            = 0x0,
      MODE_LOWPRIO          = 0x1,
      MODE_SMI              = 0x2,
      MODE_NMI              = 0x4,
      MODE_INIT             = 0x5,
      MODE_SIPI             = 0x6,
      MODE_EXTINT           = 0x7
    };

    enum TimerMode {
      ONESHOT               = 0x0,
      PERIODIC              = 0x1,
      TSCDEADLINE           = 0x2
    };

    enum IrcDestinationShorthand {
      ICR_DESTSHORT_NO      = 0x0,
      ICR_DESTSHORT_SELF    = 0x1,
      ICR_DESTSHORT_ALL     = 0x2,
      ICR_DESTSHORT_NOTSELF = 0x3
    };

    enum EsrStatus {
      ESR_SEND_CS  = 0x00001,
      ESR_RECV_CS  = 0x00002,
      ESR_SEND_ACC = 0x00004,
      ESR_RECV_ACC = 0x00008,
      ESR_SENDILL  = 0x00020,
      ESR_RECVILL  = 0x00040,
      ESR_ILLREGA  = 0x00080
    };

    BITFIELD_DEF(uint32_t, Register)
    UIntField<value_t,base_t, 23,9> apic_id; // REG_APICID
    UIntField<value_t,base_t, 0,8> version; // REG_VERSION
    UIntField<value_t,base_t, 16,8> max_lvt_entry; // REG_VERSION
    BoolField<value_t,base_t, 24> eio_sup_supported; // REG_VERSION EIO broadcast suppression supported
    UIntField<value_t,base_t, 0,8> vector; // REG_ICR_LOW and REG_LVT and REG_SVR
    UIntField<value_t,base_t, 8,3> delivery_mode; // REG_ICR_LOW and REG_LVT
    BoolField<value_t,base_t, 11> logical_destination; // REG_ICR_LOW
    BoolField<value_t,base_t, 12> delivery_pending; // REG_ICR_LOW and REG_LVT
    BoolField<value_t,base_t, 14> level; // REG_ICR_LOW
    BoolField<value_t,base_t, 15> level_triggered; // REG_ICR_LOW
    UIntField<value_t,base_t, 18,2> destination_shorthand; // REG_ICR_LOW
    UIntField<value_t,base_t, 16,16> destination; // REG_ICR_HIGH and REG_LDR
    UIntField<value_t,base_t, 28,4> model; // REG_DFR flat vs cluster
    UIntField<value_t,base_t, 0,4> task_prio_sub; // REG_TPR
    UIntField<value_t,base_t, 4,4> task_prio; // REG_TPR
    BoolField<value_t,base_t, 8> apic_enable; // REG_SVR
    BoolField<value_t,base_t, 9> focus_processor_checking; // REG_SVR
    BoolField<value_t,base_t, 12> eio_suppression; // REG_SVR
    BoolField<value_t,base_t, 13> pin_polarity; // REG_LVT
    BoolField<value_t,base_t, 14> remote_irr; // REG_LVT
    BoolField<value_t,base_t, 15> trigger_mode; // REG_LVT
    BoolField<value_t,base_t, 16> masked; // REG_LVT
    UIntField<value_t,base_t, 17,2> timer_mode; // REG_LVT
    Register() : value(0) {}
    BITFIELD_END

    enum {
      TIMER_DIVIDER  = 16ul,
      FREQUENCY_DIV  = 200ul
    };
  };

} // namespace mythos
<commit_msg>lapic KNC comment<commit_after>/* -*- mode:C++; -*- */
/* MyThOS: The Many-Threads Operating System
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Copyright 2016 Randolf Rotta, and contributors, BTU Cottbus-Senftenberg
 */
#pragma once

#include <cstddef> // for size_t
#include <cstdint> // for uint32_t etc
#include "util/bitfield.hh"

namespace mythos {

  class LAPICdef
  {
  public:
    enum RegisterAddr {
      REG_APICID                = 0x20,
      REG_VERSION               = 0x30,
      REG_LDR                   = 0xD0,
      REG_DFR                   = 0xE0,
      REG_SVR                   = 0xF0,
      REG_ISR                   = 0x100,
      REG_IRR                   = 0x200,
      REG_ESR                   = 0x280,
      REG_LVT_CMCI              = 0x2F0,
      REG_ICR_LOW               = 0x300,
      REG_ICR_HIGH              = 0x310,
      REG_LVT_TIMER             = 0x320,
      REG_LVT_THERMAL           = 0x330,
      REG_LVT_PERFCNT           = 0x340,
      REG_LVT_LINT0             = 0x350,
      REG_LVT_LINT1             = 0x360,
      REG_LVT_ERROR             = 0x370,
      REG_TIMER_ICR             = 0x380,
      REG_TIMER_CCR             = 0x390,
      REG_TIMER_DCR             = 0x3E0,
      REG_TASK_PRIO             = 0x80,
      REG_EOI                   = 0xB0
    };

    enum IcrDeliveryMode {
      MODE_FIXED            = 0x0,
      MODE_LOWPRIO          = 0x1,
      MODE_SMI              = 0x2,
      MODE_NMI              = 0x4,
      MODE_INIT             = 0x5,
      MODE_SIPI             = 0x6,
      MODE_EXTINT           = 0x7
    };

    enum TimerMode {
      ONESHOT               = 0x0,
      PERIODIC              = 0x1,
      TSCDEADLINE           = 0x2
    };

    enum IrcDestinationShorthand {
      ICR_DESTSHORT_NO      = 0x0,
      ICR_DESTSHORT_SELF    = 0x1,
      ICR_DESTSHORT_ALL     = 0x2,
      ICR_DESTSHORT_NOTSELF = 0x3
    };

    enum EsrStatus {
      ESR_SEND_CS  = 0x00001,
      ESR_RECV_CS  = 0x00002,
      ESR_SEND_ACC = 0x00004,
      ESR_RECV_ACC = 0x00008,
      ESR_SENDILL  = 0x00020,
      ESR_RECVILL  = 0x00040,
      ESR_ILLREGA  = 0x00080
    };

    BITFIELD_DEF(uint32_t, Register)
    UIntField<value_t,base_t, 23,9> apic_id; // KNC-specific!  // REG_APICID
    UIntField<value_t,base_t, 0,8> version; // REG_VERSION
    UIntField<value_t,base_t, 16,8> max_lvt_entry; // REG_VERSION
    BoolField<value_t,base_t, 24> eio_sup_supported; // REG_VERSION EIO broadcast suppression supported
    UIntField<value_t,base_t, 0,8> vector; // REG_ICR_LOW and REG_LVT and REG_SVR
    UIntField<value_t,base_t, 8,3> delivery_mode; // REG_ICR_LOW and REG_LVT
    BoolField<value_t,base_t, 11> logical_destination; // REG_ICR_LOW
    BoolField<value_t,base_t, 12> delivery_pending; // REG_ICR_LOW and REG_LVT
    BoolField<value_t,base_t, 14> level; // REG_ICR_LOW
    BoolField<value_t,base_t, 15> level_triggered; // REG_ICR_LOW
    UIntField<value_t,base_t, 18,2> destination_shorthand; // REG_ICR_LOW
    UIntField<value_t,base_t, 16,16> destination; // KNC-specific!  // REG_ICR_HIGH and REG_LDR
    UIntField<value_t,base_t, 28,4> model; // REG_DFR flat vs cluster
    UIntField<value_t,base_t, 0,4> task_prio_sub; // REG_TPR
    UIntField<value_t,base_t, 4,4> task_prio; // REG_TPR
    BoolField<value_t,base_t, 8> apic_enable; // REG_SVR
    BoolField<value_t,base_t, 9> focus_processor_checking; // REG_SVR
    BoolField<value_t,base_t, 12> eio_suppression; // REG_SVR
    BoolField<value_t,base_t, 13> pin_polarity; // REG_LVT
    BoolField<value_t,base_t, 14> remote_irr; // REG_LVT
    BoolField<value_t,base_t, 15> trigger_mode; // REG_LVT
    BoolField<value_t,base_t, 16> masked; // REG_LVT
    UIntField<value_t,base_t, 17,2> timer_mode; // REG_LVT
    Register() : value(0) {}
    BITFIELD_END

    enum {
      TIMER_DIVIDER  = 16ul,
      FREQUENCY_DIV  = 200ul
    };
  };

} // namespace mythos
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <string>

#include "third_party/googletest/src/include/gtest/gtest.h"

#include "./vpx_config.h"
#include "./y4menc.h"
#include "test/md5_helper.h"
#include "test/util.h"
#include "test/y4m_video_source.h"

namespace {

using std::string;

static const unsigned int kWidth = 160;
static const unsigned int kHeight = 90;
static const unsigned int kFrames = 10;

struct Y4mTestParam {
  const char *filename;
  unsigned int bit_depth;
  vpx_img_fmt format;
  const char *md5raw;
};

const Y4mTestParam kY4mTestVectors[] = {
  { "park_joy_90p_8_420.y4m", 8, VPX_IMG_FMT_I420,
    "e5406275b9fc6bb3436c31d4a05c1cab" },
  { "park_joy_90p_8_422.y4m", 8, VPX_IMG_FMT_I422,
    "284a47a47133b12884ec3a14e959a0b6" },
  { "park_joy_90p_8_444.y4m", 8, VPX_IMG_FMT_I444,
    "90517ff33843d85de712fd4fe60dbed0" },
  { "park_joy_90p_10_420.y4m", 10, VPX_IMG_FMT_I42016,
    "63f21f9f717d8b8631bd2288ee87137b" },
  { "park_joy_90p_10_422.y4m", 10, VPX_IMG_FMT_I42216,
    "48ab51fb540aed07f7ff5af130c9b605" },
  { "park_joy_90p_10_444.y4m", 10, VPX_IMG_FMT_I44416,
    "067bfd75aa85ff9bae91fa3e0edd1e3e" },
  { "park_joy_90p_12_420.y4m", 12, VPX_IMG_FMT_I42016,
    "9e6d8f6508c6e55625f6b697bc461cef" },
  { "park_joy_90p_12_422.y4m", 12, VPX_IMG_FMT_I42216,
    "b239c6b301c0b835485be349ca83a7e3" },
  { "park_joy_90p_12_444.y4m", 12, VPX_IMG_FMT_I44416,
    "5a6481a550821dab6d0192f5c63845e9" },
};

static void write_image_file(const vpx_image_t *img, FILE *file) {
  int plane, y;
  for (plane = 0; plane < 3; ++plane) {
    const unsigned char *buf = img->planes[plane];
    const int stride = img->stride[plane];
    const int bytes_per_sample = (img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1;
    const int h =
        (plane ? (img->d_h + img->y_chroma_shift) >> img->y_chroma_shift
               : img->d_h);
    const int w =
        (plane ? (img->d_w + img->x_chroma_shift) >> img->x_chroma_shift
               : img->d_w);
    for (y = 0; y < h; ++y) {
      fwrite(buf, bytes_per_sample, w, file);
      buf += stride;
    }
  }
}

class Y4mVideoSourceTest : public ::testing::TestWithParam<Y4mTestParam>,
                           public ::libvpx_test::Y4mVideoSource {
 protected:
  Y4mVideoSourceTest() : Y4mVideoSource("", 0, 0) {}

  virtual ~Y4mVideoSourceTest() { CloseSource(); }

  virtual void Init(const std::string &file_name, int limit) {
    file_name_ = file_name;
    start_ = 0;
    limit_ = limit;
    frame_ = 0;
    Begin();
  }

  // Checks y4m header information
  void HeaderChecks(unsigned int bit_depth, vpx_img_fmt_t fmt) {
    ASSERT_TRUE(input_file_ != NULL);
    ASSERT_EQ(y4m_.pic_w, (int)kWidth);
    ASSERT_EQ(y4m_.pic_h, (int)kHeight);
    ASSERT_EQ(img()->d_w, kWidth);
    ASSERT_EQ(img()->d_h, kHeight);
    ASSERT_EQ(y4m_.bit_depth, bit_depth);
    ASSERT_EQ(y4m_.vpx_fmt, fmt);
    if (fmt == VPX_IMG_FMT_I420 || fmt == VPX_IMG_FMT_I42016) {
      ASSERT_EQ(y4m_.bps, (int)y4m_.bit_depth * 3 / 2);
      ASSERT_EQ(img()->x_chroma_shift, 1U);
      ASSERT_EQ(img()->y_chroma_shift, 1U);
    }
    if (fmt == VPX_IMG_FMT_I422 || fmt == VPX_IMG_FMT_I42216) {
      ASSERT_EQ(y4m_.bps, (int)y4m_.bit_depth * 2);
      ASSERT_EQ(img()->x_chroma_shift, 1U);
      ASSERT_EQ(img()->y_chroma_shift, 0U);
    }
    if (fmt == VPX_IMG_FMT_I444 || fmt == VPX_IMG_FMT_I44416) {
      ASSERT_EQ(y4m_.bps, (int)y4m_.bit_depth * 3);
      ASSERT_EQ(img()->x_chroma_shift, 0U);
      ASSERT_EQ(img()->y_chroma_shift, 0U);
    }
  }

  // Checks MD5 of the raw frame data
  void Md5Check(const string &expected_md5) {
    ASSERT_TRUE(input_file_ != NULL);
    libvpx_test::MD5 md5;
    for (unsigned int i = start_; i < limit_; i++) {
      md5.Add(img());
      Next();
    }
    ASSERT_EQ(string(md5.Get()), expected_md5);
  }
};

TEST_P(Y4mVideoSourceTest, SourceTest) {
  const Y4mTestParam t = GetParam();
  Init(t.filename, kFrames);
  HeaderChecks(t.bit_depth, t.format);
  Md5Check(t.md5raw);
}

INSTANTIATE_TEST_CASE_P(C, Y4mVideoSourceTest,
                        ::testing::ValuesIn(kY4mTestVectors));

class Y4mVideoWriteTest : public Y4mVideoSourceTest {
 protected:
  Y4mVideoWriteTest() {}

  virtual ~Y4mVideoWriteTest() {
    delete tmpfile_;
    input_file_ = NULL;
  }

  void ReplaceInputFile(FILE *input_file) {
    CloseSource();
    frame_ = 0;
    input_file_ = input_file;
    rewind(input_file_);
    ReadSourceToStart();
  }

  // Writes out a y4m file and then reads it back
  void WriteY4mAndReadBack() {
    ASSERT_TRUE(input_file_ != NULL);
    char buf[Y4M_BUFFER_SIZE] = { 0 };
    const struct VpxRational framerate = { y4m_.fps_n, y4m_.fps_d };
    tmpfile_ = new libvpx_test::TempOutFile;
    ASSERT_TRUE(tmpfile_->file() != NULL);
    y4m_write_file_header(buf, sizeof(buf), kWidth, kHeight, &framerate,
                          y4m_.vpx_fmt, y4m_.bit_depth);
    fputs(buf, tmpfile_->file());
    for (unsigned int i = start_; i < limit_; i++) {
      y4m_write_frame_header(buf, sizeof(buf));
      fputs(buf, tmpfile_->file());
      write_image_file(img(), tmpfile_->file());
      Next();
    }
    ReplaceInputFile(tmpfile_->file());
  }

  virtual void Init(const std::string &file_name, int limit) {
    Y4mVideoSourceTest::Init(file_name, limit);
    WriteY4mAndReadBack();
  }
  libvpx_test::TempOutFile *tmpfile_;
};

TEST_P(Y4mVideoWriteTest, WriteTest) {
  const Y4mTestParam t = GetParam();
  Init(t.filename, kFrames);
  HeaderChecks(t.bit_depth, t.format);
  Md5Check(t.md5raw);
}

INSTANTIATE_TEST_CASE_P(C, Y4mVideoWriteTest,
                        ::testing::ValuesIn(kY4mTestVectors));
}  // namespace
<commit_msg>y4m_test: init members in the constructor<commit_after>/*
 *  Copyright (c) 2012 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <string>

#include "third_party/googletest/src/include/gtest/gtest.h"

#include "./vpx_config.h"
#include "./y4menc.h"
#include "test/md5_helper.h"
#include "test/util.h"
#include "test/y4m_video_source.h"

namespace {

using std::string;

static const unsigned int kWidth = 160;
static const unsigned int kHeight = 90;
static const unsigned int kFrames = 10;

struct Y4mTestParam {
  const char *filename;
  unsigned int bit_depth;
  vpx_img_fmt format;
  const char *md5raw;
};

const Y4mTestParam kY4mTestVectors[] = {
  { "park_joy_90p_8_420.y4m", 8, VPX_IMG_FMT_I420,
    "e5406275b9fc6bb3436c31d4a05c1cab" },
  { "park_joy_90p_8_422.y4m", 8, VPX_IMG_FMT_I422,
    "284a47a47133b12884ec3a14e959a0b6" },
  { "park_joy_90p_8_444.y4m", 8, VPX_IMG_FMT_I444,
    "90517ff33843d85de712fd4fe60dbed0" },
  { "park_joy_90p_10_420.y4m", 10, VPX_IMG_FMT_I42016,
    "63f21f9f717d8b8631bd2288ee87137b" },
  { "park_joy_90p_10_422.y4m", 10, VPX_IMG_FMT_I42216,
    "48ab51fb540aed07f7ff5af130c9b605" },
  { "park_joy_90p_10_444.y4m", 10, VPX_IMG_FMT_I44416,
    "067bfd75aa85ff9bae91fa3e0edd1e3e" },
  { "park_joy_90p_12_420.y4m", 12, VPX_IMG_FMT_I42016,
    "9e6d8f6508c6e55625f6b697bc461cef" },
  { "park_joy_90p_12_422.y4m", 12, VPX_IMG_FMT_I42216,
    "b239c6b301c0b835485be349ca83a7e3" },
  { "park_joy_90p_12_444.y4m", 12, VPX_IMG_FMT_I44416,
    "5a6481a550821dab6d0192f5c63845e9" },
};

static void write_image_file(const vpx_image_t *img, FILE *file) {
  int plane, y;
  for (plane = 0; plane < 3; ++plane) {
    const unsigned char *buf = img->planes[plane];
    const int stride = img->stride[plane];
    const int bytes_per_sample = (img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1;
    const int h =
        (plane ? (img->d_h + img->y_chroma_shift) >> img->y_chroma_shift
               : img->d_h);
    const int w =
        (plane ? (img->d_w + img->x_chroma_shift) >> img->x_chroma_shift
               : img->d_w);
    for (y = 0; y < h; ++y) {
      fwrite(buf, bytes_per_sample, w, file);
      buf += stride;
    }
  }
}

class Y4mVideoSourceTest : public ::testing::TestWithParam<Y4mTestParam>,
                           public ::libvpx_test::Y4mVideoSource {
 protected:
  Y4mVideoSourceTest() : Y4mVideoSource("", 0, 0) {}

  virtual ~Y4mVideoSourceTest() { CloseSource(); }

  virtual void Init(const std::string &file_name, int limit) {
    file_name_ = file_name;
    start_ = 0;
    limit_ = limit;
    frame_ = 0;
    Begin();
  }

  // Checks y4m header information
  void HeaderChecks(unsigned int bit_depth, vpx_img_fmt_t fmt) {
    ASSERT_TRUE(input_file_ != NULL);
    ASSERT_EQ(y4m_.pic_w, (int)kWidth);
    ASSERT_EQ(y4m_.pic_h, (int)kHeight);
    ASSERT_EQ(img()->d_w, kWidth);
    ASSERT_EQ(img()->d_h, kHeight);
    ASSERT_EQ(y4m_.bit_depth, bit_depth);
    ASSERT_EQ(y4m_.vpx_fmt, fmt);
    if (fmt == VPX_IMG_FMT_I420 || fmt == VPX_IMG_FMT_I42016) {
      ASSERT_EQ(y4m_.bps, (int)y4m_.bit_depth * 3 / 2);
      ASSERT_EQ(img()->x_chroma_shift, 1U);
      ASSERT_EQ(img()->y_chroma_shift, 1U);
    }
    if (fmt == VPX_IMG_FMT_I422 || fmt == VPX_IMG_FMT_I42216) {
      ASSERT_EQ(y4m_.bps, (int)y4m_.bit_depth * 2);
      ASSERT_EQ(img()->x_chroma_shift, 1U);
      ASSERT_EQ(img()->y_chroma_shift, 0U);
    }
    if (fmt == VPX_IMG_FMT_I444 || fmt == VPX_IMG_FMT_I44416) {
      ASSERT_EQ(y4m_.bps, (int)y4m_.bit_depth * 3);
      ASSERT_EQ(img()->x_chroma_shift, 0U);
      ASSERT_EQ(img()->y_chroma_shift, 0U);
    }
  }

  // Checks MD5 of the raw frame data
  void Md5Check(const string &expected_md5) {
    ASSERT_TRUE(input_file_ != NULL);
    libvpx_test::MD5 md5;
    for (unsigned int i = start_; i < limit_; i++) {
      md5.Add(img());
      Next();
    }
    ASSERT_EQ(string(md5.Get()), expected_md5);
  }
};

TEST_P(Y4mVideoSourceTest, SourceTest) {
  const Y4mTestParam t = GetParam();
  Init(t.filename, kFrames);
  HeaderChecks(t.bit_depth, t.format);
  Md5Check(t.md5raw);
}

INSTANTIATE_TEST_CASE_P(C, Y4mVideoSourceTest,
                        ::testing::ValuesIn(kY4mTestVectors));

class Y4mVideoWriteTest : public Y4mVideoSourceTest {
 protected:
  Y4mVideoWriteTest() : tmpfile_(NULL) {}

  virtual ~Y4mVideoWriteTest() {
    delete tmpfile_;
    input_file_ = NULL;
  }

  void ReplaceInputFile(FILE *input_file) {
    CloseSource();
    frame_ = 0;
    input_file_ = input_file;
    rewind(input_file_);
    ReadSourceToStart();
  }

  // Writes out a y4m file and then reads it back
  void WriteY4mAndReadBack() {
    ASSERT_TRUE(input_file_ != NULL);
    char buf[Y4M_BUFFER_SIZE] = { 0 };
    const struct VpxRational framerate = { y4m_.fps_n, y4m_.fps_d };
    tmpfile_ = new libvpx_test::TempOutFile;
    ASSERT_TRUE(tmpfile_->file() != NULL);
    y4m_write_file_header(buf, sizeof(buf), kWidth, kHeight, &framerate,
                          y4m_.vpx_fmt, y4m_.bit_depth);
    fputs(buf, tmpfile_->file());
    for (unsigned int i = start_; i < limit_; i++) {
      y4m_write_frame_header(buf, sizeof(buf));
      fputs(buf, tmpfile_->file());
      write_image_file(img(), tmpfile_->file());
      Next();
    }
    ReplaceInputFile(tmpfile_->file());
  }

  virtual void Init(const std::string &file_name, int limit) {
    Y4mVideoSourceTest::Init(file_name, limit);
    WriteY4mAndReadBack();
  }
  libvpx_test::TempOutFile *tmpfile_;
};

TEST_P(Y4mVideoWriteTest, WriteTest) {
  const Y4mTestParam t = GetParam();
  Init(t.filename, kFrames);
  HeaderChecks(t.bit_depth, t.format);
  Md5Check(t.md5raw);
}

INSTANTIATE_TEST_CASE_P(C, Y4mVideoWriteTest,
                        ::testing::ValuesIn(kY4mTestVectors));
}  // namespace
<|endoftext|>


<commit_before>// Test doesn't build on windows, because OpenGL on windows is a nightmare.
#ifdef _WIN32
#include <stdio.h>
int main() {
    printf("Skipping test on Windows\n");
    return 0;
}
#else

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <cstring>
#include "../src/runtime/mini_opengl.h"
#include "Halide.h"

extern "C" void glGenTextures(GLsizei, GLuint *);
extern "C" void glTexParameteri(GLenum, GLenum, GLint);
extern "C" void glBindTexture(GLenum, GLuint);
extern "C" void glTexImage2D(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
extern "C" GLuint glCreateProgram();
extern "C" void glAttachShader(GLuint, GLuint);
extern "C" void glLinkProgram(GLuint);
extern "C" void glGetProgramiv(GLuint, GLenum, GLint *);
extern "C" void glGetProgramInfoLog(GLuint, GLsizei, GLsizei *, GLchar *);
extern "C" GLuint glCreateShader(GLenum);
extern "C" void glShaderSource(GLuint, GLsizei, const GLchar **, const GLint *);
extern "C" void glCompileShader(GLuint);
extern "C" void glGetShaderiv(GLuint, GLenum, GLint *);
extern "C" void glGetShaderInfoLog(GLuint, GLsizei, GLsizei *, GLchar *);
extern "C" void glEnable(GLenum);
extern "C" void glDisable(GLenum);
extern "C" void glGetIntegerv(GLenum, GLint *);
extern "C" void glGetBooleanv(GLenum, GLboolean *);
extern "C" GLenum glGetError();
extern "C" void glActiveTexture(GLenum);
extern "C" void glEnableVertexAttribArray(GLuint);
extern "C" void glDisableVertexAttribArray(GLuint);
extern "C" void glUseProgram(GLuint);
extern "C" void glGenBuffers(GLsizei, GLuint *);
extern "C" void glViewport(GLint, GLint, GLsizei, GLsizei);
extern "C" void glGenFramebuffers(GLsizei, GLuint *);
extern "C" void glBindBuffer(GLenum, GLuint);
extern "C" void glBindFramebuffer(GLenum, GLuint);
extern "C" void glGenVertexArrays(GLsizei, GLuint *);
extern "C" void glBindVertexArray(GLuint);
extern "C" void glGetVertexAttribiv(GLuint, GLenum, GLint *);
extern "C" const GLubyte* glGetString(GLenum name);

// Generates an arbitrary program.
class Program
{
    public:

    static GLuint handle()
    {
        const char *vertexShader = " \
                                    attribute vec4 Position;  \
                                    attribute vec2 TexCoordIn; \
                                    varying vec2 TexCoordOut; \
                                    void main(void) {  \
                                        gl_Position = Position; \
                                        TexCoordOut = TexCoordIn; \
                                    }";

        const char *fragmentShader = " \
                                      varying vec2 TexCoordOut; \
                                      uniform sampler2D Texture; \
                                      void main(void) { \
                                          gl_FragColor = texture2D(Texture, TexCoordOut); \
                                      }";

        GLuint handle = glCreateProgram();
        glAttachShader(handle, compileShader("vertex", vertexShader, GL_VERTEX_SHADER));
        glAttachShader(handle, compileShader("fragment", fragmentShader, GL_FRAGMENT_SHADER));
        glLinkProgram(handle);

        GLint linkSuccess;
        glGetProgramiv(handle, GL_LINK_STATUS, &linkSuccess);
        if (linkSuccess == GL_FALSE) {
            GLchar messages[256];
            glGetProgramInfoLog(handle, sizeof(messages), 0, messages);
            fprintf(stderr, "Error linking program: %s\n", messages);
            exit(1);
        }

        return handle;
    }

    private:

    static GLuint compileShader(const char *label, const char *shaderString, GLenum shaderType)
    {
        const GLuint handle = glCreateShader(shaderType);
        const int len = strlen(shaderString);
        glShaderSource(handle, 1, &shaderString, &len);
        glCompileShader(handle);
        GLint compileSuccess;
        glGetShaderiv(handle, GL_COMPILE_STATUS, &compileSuccess);
        if (compileSuccess == GL_FALSE) {
            GLchar messages[256];
            glGetShaderInfoLog(handle, sizeof(messages), 0, messages);
            fprintf(stderr, "Error compiling %s shader: %s\n", label, messages);
            exit(1);
        }
        return handle;
    }
};

// Encapsulates setting OpenGL's state to arbitrary values, and checking
// whether the state matches those values.
class KnownState
{
    private:

    void gl_enable(GLenum cap, bool state)
    {
        (state ? glEnable : glDisable)(cap);
    }

    GLuint gl_gen(void (*fn)(GLsizei, GLuint *))
    {
        GLuint val;
        (*fn)(1, &val);
        return val;
    }

    void check_value(const char *operation, const char *label, GLenum pname, GLint initial)
    {
        GLint val;
        glGetIntegerv(pname, &val);
        if (val != initial) {
            fprintf(stderr, "%s did not restore %s: initial value was %d (%#x), current value is %d (%#x)\n", operation, label, initial, initial, val, val);
            errors = true;
        }
    }

    void check_value(const char *operation, const char *label, GLenum pname, GLenum initial)
    {
        check_value(operation, label, pname, (GLint) initial);
    }

    void check_value(const char *operation, const char *label, GLenum pname, GLint initial[], int n=4)
    {
        GLint val[2048];
        glGetIntegerv(pname, val);
        for (int i=0; i<n; i++) {
            if (val[i] != initial[i]) {
                fprintf(stderr, "%s did not restore %s: initial value was", operation, label);
                for (int j=0; j<n; j++) fprintf(stderr, " %d", initial[j]);
                fprintf(stderr, ", current value is");
                for (int j=0; j<n; j++) fprintf(stderr, " %d", val[j]);
                fprintf(stderr, "\n");
                errors = true;
                return;
            }
        }
    }

    void check_value(const char *operation, const char *label, GLenum pname, bool initial)
    {
        GLboolean val;
        glGetBooleanv(pname, &val);
        if (val != initial) {
            fprintf(stderr, "%s did not restore boolean %s: initial value was %s, current value is %s\n", operation, label, initial ? "true" : "false", val ? "true" : "false");
            errors = true;
        }
    }

    void check_error(const char *label)
    {
        GLenum err = glGetError();
        if (err != GL_NO_ERROR) {
            fprintf(stderr, "Error setting %s: OpenGL error %#x\n", label, err);
            errors = true;
        }
    }

    // version of OpenGL
    int gl_major_version;
    int gl_minor_version;

    GLenum initial_active_texture;
    GLint initial_viewport[4];
    GLuint initial_array_buffer_binding;
    GLuint initial_element_array_buffer_binding;
    GLuint initial_current_program;
    GLuint initial_framebuffer_binding;
    static const int ntextures = 10;
    GLuint initial_bound_textures[ntextures];
    bool initial_cull_face;
    bool initial_depth_test;

    static const int nvertex_attribs = 10;
    bool initial_vertex_attrib_array_enabled[nvertex_attribs];

    // The next two functions are stolen from opengl.cpp
    // and are used to parse the major/minor version of OpenGL
    // to see if vertex array objects are supported
    const char *parse_int(const char *str, int *val) {
        int v = 0;
        size_t i = 0;
        while (str[i] >= '0' && str[i] <= '9') {
            v = 10 * v + (str[i] - '0');
            i++;
        }
        if (i > 0) {
            *val = v;
            return &str[i];
        }
        return NULL;
    }

    const char *parse_opengl_version(const char *str, int *major, int *minor) {
        str = parse_int(str, major);
        if (str == NULL || *str != '.') {
            return NULL;
        }
        return parse_int(str + 1, minor);
    }

    GLuint initial_vertex_array_binding;

    public:

    bool errors;

    // This sets most values to generated or arbitrary values, which the
    // halide calls would be unlikely to accidentally use.  But for boolean
    // values, we want to be sure that halide is really restoring the
    // initial value, not just setting it to true or false.  So we need to
    // be able to try both.
    void setup(bool boolval)
    {
        // parse the OpenGL version
        const char *version = (const char *)glGetString(GL_VERSION);
        parse_opengl_version(version, &gl_major_version, &gl_minor_version);

        glGenTextures(ntextures, initial_bound_textures);
        for (int i=0; i<ntextures; i++) {
            glActiveTexture(GL_TEXTURE0 + i);
            glBindTexture(GL_TEXTURE_2D, initial_bound_textures[i]);
        }
        glActiveTexture(initial_active_texture = GL_TEXTURE3);

        for (int i=0; i<nvertex_attribs; i++) {
            if ( (initial_vertex_attrib_array_enabled[i] = boolval ) )
                glEnableVertexAttribArray(i);
            else
                glDisableVertexAttribArray(i);
            char buf[256];
            sprintf(buf, "vertex attrib array %d state", i);
            check_error(buf);
        }

        glUseProgram(initial_current_program = Program::handle());
        glViewport(initial_viewport[0] = 111, initial_viewport[1] = 222, initial_viewport[2] = 333, initial_viewport[3] = 444);
        gl_enable(GL_CULL_FACE, initial_cull_face = boolval);
        gl_enable(GL_DEPTH_TEST, initial_depth_test = boolval);
        glBindBuffer(GL_ARRAY_BUFFER, initial_array_buffer_binding = gl_gen(glGenBuffers));
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, initial_element_array_buffer_binding = gl_gen(glGenBuffers));
        glBindFramebuffer(GL_FRAMEBUFFER, initial_framebuffer_binding = gl_gen(glGenFramebuffers));

        // Vertex array objects are only used by Halide if the OpenGL version >=3
        if (gl_major_version >= 3) {
            glBindVertexArray(initial_vertex_array_binding = gl_gen(glGenVertexArrays));
        }

        check_error("known state");
    }

    void check(const char *operation)
    {
        check_value(operation, "ActiveTexture", GL_ACTIVE_TEXTURE, initial_active_texture);
        check_value(operation, "current program", GL_CURRENT_PROGRAM, initial_current_program);
        check_value(operation, "framebuffer binding", GL_FRAMEBUFFER_BINDING, initial_framebuffer_binding);
        check_value(operation, "array buffer binding", GL_ARRAY_BUFFER_BINDING, initial_array_buffer_binding);
        check_value(operation, "element array buffer binding", GL_ELEMENT_ARRAY_BUFFER_BINDING, initial_element_array_buffer_binding);
        check_value(operation, "viewport", GL_VIEWPORT, initial_viewport);
        check_value(operation, "GL_CULL_FACE", GL_CULL_FACE, initial_cull_face);
        check_value(operation, "GL_DEPTH_TEST", GL_DEPTH_TEST, initial_cull_face);

        // Vertex array objects are only used by Halide if the OpenGL version >=3
        if (gl_major_version >= 3) {
            check_value(operation, "vertex array binding", GL_VERTEX_ARRAY_BINDING, initial_vertex_array_binding);
        } else {
            fprintf(stderr, "Skipping vertex array binding tests because OpenGL version is %d.%d (<3.0)\n", gl_major_version, gl_minor_version);
        }

        for (int i=0; i<ntextures; i++) {
            char buf[100];
            sprintf(buf, "bound texture (unit %d)", i);
            glActiveTexture(GL_TEXTURE0 + i);
            check_value(operation, buf, GL_TEXTURE_BINDING_2D, initial_bound_textures[i]);
        }

        for (int i=0; i < nvertex_attribs; i++) {
            int initial = initial_vertex_attrib_array_enabled[i];
            GLint val;
            glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &val);
            if (val != initial) {
                fprintf(stderr, "%s did not restore boolean VertexAttributeArrayEnabled(%d): initial value was %s, current value is %s\n", operation, i, initial ? "true" : "false", val ? "true" : "false");
                errors = true;
            }
        }
    }
};

using namespace Halide;

int main() {
    // This test must be run with an OpenGL target.
    const Target target = get_jit_target_from_environment().with_feature(Target::OpenGL);

    KnownState known_state;

    Image<uint8_t> input(255, 10, 3);
    Image<uint8_t> out(UInt(8), 255, 10, 3);

    Var x, y, c;
    Func g;
    g(x, y, c) = input(x, y, c);
    g.bound(c, 0, 3);
    g.glsl(x, y, c);
    g.realize(out, target); // let Halide initialize OpenGL

    known_state.setup(true);
    g.realize(out, target);
    known_state.check("realize");

    known_state.setup(true);
    out.copy_to_host();
    known_state.check("copy_to_host");

    known_state.setup(false);
    g.realize(out, target);
    known_state.check("realize");

    known_state.setup(false);
    out.copy_to_host();
    known_state.check("copy_to_host");

    if (known_state.errors) {
	return 1;
    }

    printf("Success!\n");
    return 0;
}

#endif
<commit_msg>Initialize 'errors' field in save_state test<commit_after>// Test doesn't build on windows, because OpenGL on windows is a nightmare.
#ifdef _WIN32
#include <stdio.h>
int main() {
    printf("Skipping test on Windows\n");
    return 0;
}
#else

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <cstring>
#include "../src/runtime/mini_opengl.h"
#include "Halide.h"

extern "C" void glGenTextures(GLsizei, GLuint *);
extern "C" void glTexParameteri(GLenum, GLenum, GLint);
extern "C" void glBindTexture(GLenum, GLuint);
extern "C" void glTexImage2D(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
extern "C" GLuint glCreateProgram();
extern "C" void glAttachShader(GLuint, GLuint);
extern "C" void glLinkProgram(GLuint);
extern "C" void glGetProgramiv(GLuint, GLenum, GLint *);
extern "C" void glGetProgramInfoLog(GLuint, GLsizei, GLsizei *, GLchar *);
extern "C" GLuint glCreateShader(GLenum);
extern "C" void glShaderSource(GLuint, GLsizei, const GLchar **, const GLint *);
extern "C" void glCompileShader(GLuint);
extern "C" void glGetShaderiv(GLuint, GLenum, GLint *);
extern "C" void glGetShaderInfoLog(GLuint, GLsizei, GLsizei *, GLchar *);
extern "C" void glEnable(GLenum);
extern "C" void glDisable(GLenum);
extern "C" void glGetIntegerv(GLenum, GLint *);
extern "C" void glGetBooleanv(GLenum, GLboolean *);
extern "C" GLenum glGetError();
extern "C" void glActiveTexture(GLenum);
extern "C" void glEnableVertexAttribArray(GLuint);
extern "C" void glDisableVertexAttribArray(GLuint);
extern "C" void glUseProgram(GLuint);
extern "C" void glGenBuffers(GLsizei, GLuint *);
extern "C" void glViewport(GLint, GLint, GLsizei, GLsizei);
extern "C" void glGenFramebuffers(GLsizei, GLuint *);
extern "C" void glBindBuffer(GLenum, GLuint);
extern "C" void glBindFramebuffer(GLenum, GLuint);
extern "C" void glGenVertexArrays(GLsizei, GLuint *);
extern "C" void glBindVertexArray(GLuint);
extern "C" void glGetVertexAttribiv(GLuint, GLenum, GLint *);
extern "C" const GLubyte* glGetString(GLenum name);

// Generates an arbitrary program.
class Program
{
    public:

    static GLuint handle()
    {
        const char *vertexShader = " \
                                    attribute vec4 Position;  \
                                    attribute vec2 TexCoordIn; \
                                    varying vec2 TexCoordOut; \
                                    void main(void) {  \
                                        gl_Position = Position; \
                                        TexCoordOut = TexCoordIn; \
                                    }";

        const char *fragmentShader = " \
                                      varying vec2 TexCoordOut; \
                                      uniform sampler2D Texture; \
                                      void main(void) { \
                                          gl_FragColor = texture2D(Texture, TexCoordOut); \
                                      }";

        GLuint handle = glCreateProgram();
        glAttachShader(handle, compileShader("vertex", vertexShader, GL_VERTEX_SHADER));
        glAttachShader(handle, compileShader("fragment", fragmentShader, GL_FRAGMENT_SHADER));
        glLinkProgram(handle);

        GLint linkSuccess;
        glGetProgramiv(handle, GL_LINK_STATUS, &linkSuccess);
        if (linkSuccess == GL_FALSE) {
            GLchar messages[256];
            glGetProgramInfoLog(handle, sizeof(messages), 0, messages);
            fprintf(stderr, "Error linking program: %s\n", messages);
            exit(1);
        }

        return handle;
    }

    private:

    static GLuint compileShader(const char *label, const char *shaderString, GLenum shaderType)
    {
        const GLuint handle = glCreateShader(shaderType);
        const int len = strlen(shaderString);
        glShaderSource(handle, 1, &shaderString, &len);
        glCompileShader(handle);
        GLint compileSuccess;
        glGetShaderiv(handle, GL_COMPILE_STATUS, &compileSuccess);
        if (compileSuccess == GL_FALSE) {
            GLchar messages[256];
            glGetShaderInfoLog(handle, sizeof(messages), 0, messages);
            fprintf(stderr, "Error compiling %s shader: %s\n", label, messages);
            exit(1);
        }
        return handle;
    }
};

// Encapsulates setting OpenGL's state to arbitrary values, and checking
// whether the state matches those values.
class KnownState
{
    private:

    void gl_enable(GLenum cap, bool state)
    {
        (state ? glEnable : glDisable)(cap);
    }

    GLuint gl_gen(void (*fn)(GLsizei, GLuint *))
    {
        GLuint val;
        (*fn)(1, &val);
        return val;
    }

    void check_value(const char *operation, const char *label, GLenum pname, GLint initial)
    {
        GLint val;
        glGetIntegerv(pname, &val);
        if (val != initial) {
            fprintf(stderr, "%s did not restore %s: initial value was %d (%#x), current value is %d (%#x)\n", operation, label, initial, initial, val, val);
            errors = true;
        }
    }

    void check_value(const char *operation, const char *label, GLenum pname, GLenum initial)
    {
        check_value(operation, label, pname, (GLint) initial);
    }

    void check_value(const char *operation, const char *label, GLenum pname, GLint initial[], int n=4)
    {
        GLint val[2048];
        glGetIntegerv(pname, val);
        for (int i=0; i<n; i++) {
            if (val[i] != initial[i]) {
                fprintf(stderr, "%s did not restore %s: initial value was", operation, label);
                for (int j=0; j<n; j++) fprintf(stderr, " %d", initial[j]);
                fprintf(stderr, ", current value is");
                for (int j=0; j<n; j++) fprintf(stderr, " %d", val[j]);
                fprintf(stderr, "\n");
                errors = true;
                return;
            }
        }
    }

    void check_value(const char *operation, const char *label, GLenum pname, bool initial)
    {
        GLboolean val;
        glGetBooleanv(pname, &val);
        if (val != initial) {
            fprintf(stderr, "%s did not restore boolean %s: initial value was %s, current value is %s\n", operation, label, initial ? "true" : "false", val ? "true" : "false");
            errors = true;
        }
    }

    void check_error(const char *label)
    {
        GLenum err = glGetError();
        if (err != GL_NO_ERROR) {
            fprintf(stderr, "Error setting %s: OpenGL error %#x\n", label, err);
            errors = true;
        }
    }

    // version of OpenGL
    int gl_major_version;
    int gl_minor_version;

    GLenum initial_active_texture;
    GLint initial_viewport[4];
    GLuint initial_array_buffer_binding;
    GLuint initial_element_array_buffer_binding;
    GLuint initial_current_program;
    GLuint initial_framebuffer_binding;
    static const int ntextures = 10;
    GLuint initial_bound_textures[ntextures];
    bool initial_cull_face;
    bool initial_depth_test;

    static const int nvertex_attribs = 10;
    bool initial_vertex_attrib_array_enabled[nvertex_attribs];

    // The next two functions are stolen from opengl.cpp
    // and are used to parse the major/minor version of OpenGL
    // to see if vertex array objects are supported
    const char *parse_int(const char *str, int *val) {
        int v = 0;
        size_t i = 0;
        while (str[i] >= '0' && str[i] <= '9') {
            v = 10 * v + (str[i] - '0');
            i++;
        }
        if (i > 0) {
            *val = v;
            return &str[i];
        }
        return NULL;
    }

    const char *parse_opengl_version(const char *str, int *major, int *minor) {
        str = parse_int(str, major);
        if (str == NULL || *str != '.') {
            return NULL;
        }
        return parse_int(str + 1, minor);
    }

    GLuint initial_vertex_array_binding;

    public:

    bool errors{false};

    // This sets most values to generated or arbitrary values, which the
    // halide calls would be unlikely to accidentally use.  But for boolean
    // values, we want to be sure that halide is really restoring the
    // initial value, not just setting it to true or false.  So we need to
    // be able to try both.
    void setup(bool boolval)
    {
        // parse the OpenGL version
        const char *version = (const char *)glGetString(GL_VERSION);
        parse_opengl_version(version, &gl_major_version, &gl_minor_version);

        glGenTextures(ntextures, initial_bound_textures);
        for (int i=0; i<ntextures; i++) {
            glActiveTexture(GL_TEXTURE0 + i);
            glBindTexture(GL_TEXTURE_2D, initial_bound_textures[i]);
        }
        glActiveTexture(initial_active_texture = GL_TEXTURE3);

        for (int i=0; i<nvertex_attribs; i++) {
            if ( (initial_vertex_attrib_array_enabled[i] = boolval ) )
                glEnableVertexAttribArray(i);
            else
                glDisableVertexAttribArray(i);
            char buf[256];
            sprintf(buf, "vertex attrib array %d state", i);
            check_error(buf);
        }

        glUseProgram(initial_current_program = Program::handle());
        glViewport(initial_viewport[0] = 111, initial_viewport[1] = 222, initial_viewport[2] = 333, initial_viewport[3] = 444);
        gl_enable(GL_CULL_FACE, initial_cull_face = boolval);
        gl_enable(GL_DEPTH_TEST, initial_depth_test = boolval);
        glBindBuffer(GL_ARRAY_BUFFER, initial_array_buffer_binding = gl_gen(glGenBuffers));
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, initial_element_array_buffer_binding = gl_gen(glGenBuffers));
        glBindFramebuffer(GL_FRAMEBUFFER, initial_framebuffer_binding = gl_gen(glGenFramebuffers));

        // Vertex array objects are only used by Halide if the OpenGL version >=3
        if (gl_major_version >= 3) {
            glBindVertexArray(initial_vertex_array_binding = gl_gen(glGenVertexArrays));
        }

        check_error("known state");
    }

    void check(const char *operation)
    {
        check_value(operation, "ActiveTexture", GL_ACTIVE_TEXTURE, initial_active_texture);
        check_value(operation, "current program", GL_CURRENT_PROGRAM, initial_current_program);
        check_value(operation, "framebuffer binding", GL_FRAMEBUFFER_BINDING, initial_framebuffer_binding);
        check_value(operation, "array buffer binding", GL_ARRAY_BUFFER_BINDING, initial_array_buffer_binding);
        check_value(operation, "element array buffer binding", GL_ELEMENT_ARRAY_BUFFER_BINDING, initial_element_array_buffer_binding);
        check_value(operation, "viewport", GL_VIEWPORT, initial_viewport);
        check_value(operation, "GL_CULL_FACE", GL_CULL_FACE, initial_cull_face);
        check_value(operation, "GL_DEPTH_TEST", GL_DEPTH_TEST, initial_cull_face);

        // Vertex array objects are only used by Halide if the OpenGL version >=3
        if (gl_major_version >= 3) {
            check_value(operation, "vertex array binding", GL_VERTEX_ARRAY_BINDING, initial_vertex_array_binding);
        } else {
            fprintf(stderr, "Skipping vertex array binding tests because OpenGL version is %d.%d (<3.0)\n", gl_major_version, gl_minor_version);
        }

        for (int i=0; i<ntextures; i++) {
            char buf[100];
            sprintf(buf, "bound texture (unit %d)", i);
            glActiveTexture(GL_TEXTURE0 + i);
            check_value(operation, buf, GL_TEXTURE_BINDING_2D, initial_bound_textures[i]);
        }

        for (int i=0; i < nvertex_attribs; i++) {
            int initial = initial_vertex_attrib_array_enabled[i];
            GLint val;
            glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &val);
            if (val != initial) {
                fprintf(stderr, "%s did not restore boolean VertexAttributeArrayEnabled(%d): initial value was %s, current value is %s\n", operation, i, initial ? "true" : "false", val ? "true" : "false");
                errors = true;
            }
        }
    }
};

using namespace Halide;

int main() {
    // This test must be run with an OpenGL target.
    const Target target = get_jit_target_from_environment().with_feature(Target::OpenGL);

    KnownState known_state;

    Image<uint8_t> input(255, 10, 3);
    Image<uint8_t> out(UInt(8), 255, 10, 3);

    Var x, y, c;
    Func g;
    g(x, y, c) = input(x, y, c);
    g.bound(c, 0, 3);
    g.glsl(x, y, c);
    g.realize(out, target); // let Halide initialize OpenGL

    known_state.setup(true);
    g.realize(out, target);
    known_state.check("realize");

    known_state.setup(true);
    out.copy_to_host();
    known_state.check("copy_to_host");

    known_state.setup(false);
    g.realize(out, target);
    known_state.check("realize");

    known_state.setup(false);
    out.copy_to_host();
    known_state.check("copy_to_host");

    if (known_state.errors) {
	return 1;
    }

    printf("Success!\n");
    return 0;
}

#endif
<|endoftext|>