Exemplo n.º 1
0
TEST(BytesTest, Comparison)
{
  EXPECT_GT(Terabytes(1), Gigabytes(1));
  EXPECT_GT(Gigabytes(1), Megabytes(1));
  EXPECT_GT(Megabytes(1), Kilobytes(1));
  EXPECT_GT(Kilobytes(1), Bytes(1));

  EXPECT_EQ(Bytes(1024), Kilobytes(1));
  EXPECT_LT(Bytes(1023), Kilobytes(1));
  EXPECT_GT(Bytes(1025), Kilobytes(1));
}
Exemplo n.º 2
0
TEST(BytesTest, Stringify)
{
  EXPECT_NE(Megabytes(1023), Gigabytes(1));

  EXPECT_EQ("0B", stringify(Bytes()));

  EXPECT_EQ("1KB", stringify(Kilobytes(1)));
  EXPECT_EQ("1MB", stringify(Megabytes(1)));
  EXPECT_EQ("1GB", stringify(Gigabytes(1)));
  EXPECT_EQ("1TB", stringify(Terabytes(1)));

  EXPECT_EQ("1023B", stringify(Bytes(1023)));
  EXPECT_EQ("1023KB", stringify(Kilobytes(1023)));
  EXPECT_EQ("1023MB", stringify(Megabytes(1023)));
  EXPECT_EQ("1023GB", stringify(Gigabytes(1023)));
}
Exemplo n.º 3
0
static Try<Nothing> increasePageCache(const vector<string>& tokens)
{
  const Bytes UNIT = Megabytes(1);

  if (tokens.size() < 2) {
    return Error("Expect at least one argument");
  }

  Try<Bytes> size = Bytes::parse(tokens[1]);
  if (size.isError()) {
    return Error("The first argument '" + tokens[1] + "' is not a byte size");
  }

  // TODO(chzhcn): Currently, we assume the current working directory
  // is a temporary directory and will be cleaned up when the test
  // finishes. Since the child process will inherit the current
  // working directory from the parent process, that means the test
  // that uses this helper probably needs to inherit from
  // TemporaryDirectoryTest. Consider relaxing this constraint.
  Try<string> path = os::mktemp(path::join(os::getcwd(), "XXXXXX"));
  if (path.isError()) {
    return Error("Failed to create a temporary file: " + path.error());
  }

  Try<int> fd = os::open(path.get(), O_WRONLY);
  if (fd.isError()) {
    return Error("Failed to open file: " + fd.error());
  }

  // NOTE: We are doing round-down here to calculate the number of
  // writes to do.
  for (uint64_t i = 0; i < size.get().bytes() / UNIT.bytes(); i++) {
    // Write UNIT size to disk at a time. The content isn't important.
    Try<Nothing> write = os::write(fd.get(), string(UNIT.bytes(), 'a'));
    if (write.isError()) {
      os::close(fd.get());
      return Error("Failed to write file: " + write.error());
    }

    // Use fsync to make sure data is written to disk.
    if (fsync(fd.get()) == -1) {
      // Save the error message because os::close below might
      // overwrite the errno.
      const string message = os::strerror(errno);

      os::close(fd.get());
      return Error("Failed to fsync: " + message);
    }
  }

  os::close(fd.get());
  return Nothing();
}
Exemplo n.º 4
0
// Add available ContainerLogger modules.
static void addContainerLoggerModules(Modules* modules)
{
  CHECK_NOTNULL(modules);

  const string libraryDirectory = path::join(
      tests::flags.build_dir,
      "src",
      ".libs");

  const string sandboxLoggerPath = path::join(
      libraryDirectory,
      os::libraries::expandName("testcontainer_logger"));

  // Add our test container logger module.
  Modules::Library* library = modules->add_libraries();
  library->set_file(sandboxLoggerPath);

  // To add a new module from this library, create a new ModuleID enum
  // and tie it with a module name.
  addModule(library,
            TestSandboxContainerLogger,
            "org_apache_mesos_TestSandboxContainerLogger");

  const string logrotateLoggerPath = path::join(
      libraryDirectory,
      os::libraries::expandName("logrotate_container_logger"));

  // Add the second container logger module.
  library = modules->add_libraries();
  library->set_file(logrotateLoggerPath);

  addModule(library,
            LogrotateContainerLogger,
            "org_apache_mesos_LogrotateContainerLogger");

  // Pass in the directory for the binary test sources.
  Modules::Library::Module* module = library->mutable_modules(0);
  mesos::Parameter* moduleParameter = module->add_parameters();
  moduleParameter->set_key("launcher_dir");
  moduleParameter->set_value(path::join(tests::flags.build_dir, "src"));

  // Set the size and number of log files to keep.
  moduleParameter = module->add_parameters();
  moduleParameter->set_key("max_stdout_size");
  moduleParameter->set_value(stringify(Megabytes(2)));

  // NOTE: This is a 'logrotate' configuration option.
  // It means to "rotate" a file 4 times before removal.
  moduleParameter = module->add_parameters();
  moduleParameter->set_key("logrotate_stdout_options");
  moduleParameter->set_value("rotate 4");
}
Exemplo n.º 5
0
void setupDebug(DebugState* dstate)
{
    dstate->lines = 0;
    dstate->lineMem = malloc(Megabytes(5));

    glGenBuffers(1, &dstate->lineBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, dstate->lineBuffer);
    glBufferData(GL_ARRAY_BUFFER, MAX_DEBUG_LINES*sizeof(Vec4), dstate->lineMem, GL_DYNAMIC_DRAW);
    glGenVertexArrays(1, &dstate->lineVAO);
    glBindVertexArray(dstate->lineVAO);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}
Exemplo n.º 6
0
namespace master {

const int MAX_OFFERS_PER_FRAMEWORK = 50;
const double MIN_CPUS = 0.01;
const Bytes MIN_MEM = Megabytes(32);
const Duration SLAVE_PING_TIMEOUT = Seconds(15);
const uint32_t MAX_SLAVE_PING_TIMEOUTS = 5;
const Duration MIN_SLAVE_REREGISTER_TIMEOUT = Minutes(10);
const double RECOVERY_SLAVE_REMOVAL_PERCENT_LIMIT = 1.0; // 100%.
const size_t MAX_REMOVED_SLAVES = 100000;
const uint32_t MAX_COMPLETED_FRAMEWORKS = 50;
const uint32_t MAX_COMPLETED_TASKS_PER_FRAMEWORK = 1000;
const Duration WHITELIST_WATCH_INTERVAL = Seconds(5);
const uint32_t TASK_LIMIT = 100;
const std::string MASTER_INFO_LABEL = "info";
const Duration ZOOKEEPER_SESSION_TIMEOUT = Seconds(10);
} // namespace master {
Exemplo n.º 7
0
TEST(BytesTest, Parse)
{
  EXPECT_SOME_EQ(Terabytes(1), Bytes::parse("1TB"));
  EXPECT_SOME_EQ(Gigabytes(1), Bytes::parse("1GB"));
  EXPECT_SOME_EQ(Megabytes(1), Bytes::parse("1MB"));
  EXPECT_SOME_EQ(Kilobytes(1), Bytes::parse("1KB"));
  EXPECT_SOME_EQ(Bytes(1), Bytes::parse("1B"));

  // Cannot have fractional bytes.
  EXPECT_ERROR(Bytes::parse("1.5B"));

  // Parsing fractions is unsupported.
  EXPECT_ERROR(Bytes::parse("1.5GB"));

  // Unknown unit.
  EXPECT_ERROR(Bytes::parse("1PB"));
}
Exemplo n.º 8
0
void ShowMemoryInfo() {
	auto localMemory = GetLocalMemoryInfo();
	auto nonLocalMemory = GetNonLocalMemoryInfo();

	ImGui::BulletText("Device memory");
	ImGui::Indent();
	ImGui::Text("Local memory");
	ImGui::Text("Budget:\nCurrent usage:"); ImGui::SameLine();
	ImGui::Text("%llu Mb\n%llu Mb", Megabytes(localMemory.Budget), Megabytes(localMemory.CurrentUsage));
	ImGui::Text("Non-Local memory");
	ImGui::Text("Budget:\nCurrent usage:"); ImGui::SameLine();
	ImGui::Text("%llu Mb\n%llu Mb", Megabytes(nonLocalMemory.Budget), Megabytes(nonLocalMemory.CurrentUsage));
	ImGui::Unindent();

	ImGui::Separator();

	ImGui::BulletText("Process memory");
	PROCESS_MEMORY_COUNTERS pmc;
	verify(GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)));
	ImGui::Indent();
	ImGui::Text("Working set:\nPagefile:"); ImGui::SameLine();
	ImGui::Text("%llu Mb\n%llu Mb", Megabytes(pmc.WorkingSetSize), Megabytes(pmc.PagefileUsage));
	ImGui::Unindent();

	ImGui::Separator();

	ImGui::BulletText("System memory");
	PERFORMANCE_INFORMATION perfInfo;
	verify(GetPerformanceInfo(&perfInfo, sizeof(perfInfo)));
	ImGui::Indent();
	ImGui::Text("Commited total:\nPhysical total:\nPhysical available:"); ImGui::SameLine();
	ImGui::Text("%llu Mb\n%llu Mb\n%llu Mb"
		, Megabytes(perfInfo.CommitTotal * perfInfo.PageSize)
		, Megabytes(perfInfo.PhysicalTotal * perfInfo.PageSize)
		, Megabytes(perfInfo.PhysicalAvailable * perfInfo.PageSize));
	ImGui::Unindent();
}
Exemplo n.º 9
0
//Program entry point
int main(int argc, char *argv[])
{
	UNUSED(argc);
	UNUSED(argv);

	//paths required by platform code
	platform::app_code.app_dll_path = "App.dll";
	platform::app_state.record_file = "input.smi";

	//Load the application dll
	platform_load_app_code(&platform::app_code);

	//initialize sdl
	if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
	{
		std::cerr << ERROR_LINE << "SDL Error: Unable to initialize SDL" << std::endl;
	}
	else
	{
		std::cout << "SDL initialized"<<std::endl;
	}

	//SDL version
	{
		SDL_version ver;
		SDL_VERSION(&ver);
		std::cout << "SDL version " << (int)ver.major << "." << (int)ver.minor << "." << (int)ver.patch << std::endl;
		SDL_GetVersion(&ver);
		std::cout << "Linked version " << (int)ver.major << "." << (int)ver.minor << "." << (int)ver.patch << std::endl;
	}

	//init time
	platform_update_time(platform::app_time);

	//call app config to get settings
	platform::app_code.config(&platform::services.config);

	//Set Opengl attributes
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, PLATFORM_GL_VERSION_MAJOR);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, PLATFORM_GL_VERSION_MINOR);

	//Set buffer attributes
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, PLATFORM_GL_DOUBLEBUFFER);
	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, PLATFORM_GL_DEPTHBUFFER);


	//Create a window
	platform_create_window();

	if (!platform::services.config.sdl_window)
	{
		std::cerr << ERROR_LINE << "Error: Unable to create window" << std::endl;
		return -1;
	}
	else
	{
		platform::services.config.quit = false;
		std::cout << "SDL window " << platform::services.config.width << "x" << platform::services.config.height << " opened" << std::endl;
	}

	//set OpenGL context
	auto sdl_context = SDL_GL_CreateContext(platform::services.config.sdl_window);

	// Initialise GLEW
	glewExperimental = GL_TRUE;
	GLenum glewError = glewInit();

	if (glewError != GLEW_OK)
	{
		std::cerr << ERROR_LINE << "GLEW Error: Unable to initialise glew";
		return -1;
	}
	else
	{
		std::cout<<"GLEW "<<glewGetString(GLEW_VERSION)<<" Initialised";
	}

	//Allocate memory for the app
	auto base_address = Gigabytes(1);
	platform::services.memory = {};
	platform::services.memory.permanent_memory_size = Megabytes(8);
	platform::services.memory.permanent_memory = platform::os::get_memory(base_address,platform::services.memory.permanent_memory_size);

	if (!platform::services.memory.permanent_memory)
	{
		std::cerr << "\nUnable to allocate enough memory";
		return -1;
	}

	//link memory to app state
	platform::app_state.memory = &platform::services.memory;

	//call the application startup
	platform::app_code.startup(&platform::services);

	//run application
	#ifdef __EMSCRIPTEN__
	emscripten_set_main_loop(platform_update, 0, true);
	#else
	//run as long as quit is not set to true
	while(!platform::services.config.quit)
	{
		platform_update();
	}
	#endif

	//free resources
	SDL_GL_DeleteContext(sdl_context);
	SDL_DestroyWindow(platform::services.config.sdl_window);

	//exit
	return 0;
}
Exemplo n.º 10
0
namespace slave {

// TODO(jieyu): Use static functions for all the constants. See more
// details in MESOS-1023.

constexpr Duration EXECUTOR_REGISTRATION_TIMEOUT = Minutes(1);
constexpr Duration EXECUTOR_REREGISTRATION_TIMEOUT = Seconds(2);

// The maximum timeout within which an executor can re-register.
// Note that this value has to be << 'MIN_AGENT_REREGISTER_TIMEOUT'
// declared in 'master/constants.hpp'; since agent recovery will only
// complete after this timeout has elapsed, this ensures that the
// agent can re-register with the master before it is marked
// unreachable and its tasks are transitioned to TASK_UNREACHABLE or
// TASK_LOST.
constexpr Duration MAX_EXECUTOR_REREGISTRATION_TIMEOUT = Seconds(15);

// The default amount of time to wait for the executor to
// shut down before destroying the container.
constexpr Duration DEFAULT_EXECUTOR_SHUTDOWN_GRACE_PERIOD = Seconds(5);

constexpr Duration RECOVERY_TIMEOUT = Minutes(15);

// TODO(gkleiman): Move this to a different file once `TaskStatusUpdateManager`
// uses `StatusUpdateManagerProcess`. See MESOS-8296.
constexpr Duration STATUS_UPDATE_RETRY_INTERVAL_MIN = Seconds(10);
constexpr Duration STATUS_UPDATE_RETRY_INTERVAL_MAX = Minutes(10);

// Default backoff interval used by the slave to wait before registration.
constexpr Duration DEFAULT_REGISTRATION_BACKOFF_FACTOR = Seconds(1);

// The maximum interval the slave waits before retrying registration.
// Note that this value has to be << 'MIN_SLAVE_REREGISTER_TIMEOUT'
// declared in 'master/constants.hpp'. This helps the slave to retry
// (re-)registration multiple times between when the master finishes
// recovery and when it times out slave re-registration.
constexpr Duration REGISTER_RETRY_INTERVAL_MAX = Minutes(1);

// The maximum interval the slave waits before retrying authentication.
constexpr Duration AUTHENTICATION_RETRY_INTERVAL_MAX = Minutes(1);

// Default backoff interval used by the slave to wait after failed
// authentication.
constexpr Duration DEFAULT_AUTHENTICATION_BACKOFF_FACTOR = Seconds(1);

constexpr Duration GC_DELAY = Weeks(1);
constexpr Duration DISK_WATCH_INTERVAL = Minutes(1);

// Minimum free disk capacity enforced by the garbage collector.
constexpr double GC_DISK_HEADROOM = 0.1;

// Maximum number of completed frameworks to store in memory.
constexpr size_t MAX_COMPLETED_FRAMEWORKS = 50;

// Default maximum number of completed executors per framework
// to store in memory.
constexpr size_t DEFAULT_MAX_COMPLETED_EXECUTORS_PER_FRAMEWORK = 150;

// Maximum number of completed tasks per executor to store in memory.
//
// NOTE: This should be greater than zero because the agent looks
// for completed tasks to determine (with false positives) whether
// an executor ever received tasks. See MESOS-8411.
//
// TODO(mzhu): Remove this note once we can determine whether an
// executor ever received tasks without looking through the
// completed tasks.
constexpr size_t MAX_COMPLETED_TASKS_PER_EXECUTOR = 200;

// Default cpus offered by the slave.
constexpr double DEFAULT_CPUS = 1;

// Default memory offered by the slave.
constexpr Bytes DEFAULT_MEM = Gigabytes(1);

// Default disk space offered by the slave.
constexpr Bytes DEFAULT_DISK = Gigabytes(10);

// Default ports range offered by the slave.
constexpr char DEFAULT_PORTS[] = "[31000-32000]";

// Default cpu resource given to a command executor.
constexpr double DEFAULT_EXECUTOR_CPUS = 0.1;

// Default memory resource given to a command executor.
constexpr Bytes DEFAULT_EXECUTOR_MEM = Megabytes(32);

#ifdef ENABLE_PORT_MAPPING_ISOLATOR
// Default number of ephemeral ports allocated to a container by the
// network isolator.
constexpr uint16_t DEFAULT_EPHEMERAL_PORTS_PER_CONTAINER = 1024;
#endif

// Default UNIX socket (Linux) or Named Pipe (Windows) resource that provides
// CLI access to the Docker daemon.
#ifdef __WINDOWS__
constexpr char DEFAULT_DOCKER_HOST_RESOURCE[] = "//./pipe/docker_engine";
#else
constexpr char DEFAULT_DOCKER_HOST_RESOURCE[] = "/var/run/docker.sock";
#endif // __WINDOWS__

// Default duration that docker containers will be removed after exit.
constexpr Duration DOCKER_REMOVE_DELAY = Hours(6);

// Default duration to wait before retry inspecting a docker
// container.
constexpr Duration DOCKER_INSPECT_DELAY = Seconds(1);

// Default maximum number of docker inspect calls docker ps will invoke
// in parallel to prevent hitting system's open file descriptor limit.
constexpr size_t DOCKER_PS_MAX_INSPECT_CALLS = 100;

// Default duration that docker containerizer will wait to check
// docker version.
// TODO(tnachen): Make this a flag.
constexpr Duration DOCKER_VERSION_WAIT_TIMEOUT = Seconds(5);

// Additional duration that docker containerizer will wait beyond the
// configured `docker_stop_timeout` for docker stop to succeed, before
// trying to kill the process by itself.
constexpr Duration DOCKER_FORCE_KILL_TIMEOUT = Seconds(1);

// Name of the default, CRAM-MD5 authenticatee.
constexpr char DEFAULT_AUTHENTICATEE[] = "crammd5";

// Name of the default, local authorizer.
constexpr char DEFAULT_AUTHORIZER[] = "local";

// Name of the agent HTTP authentication realm for read-only endpoints.
constexpr char READONLY_HTTP_AUTHENTICATION_REALM[] = "mesos-agent-readonly";

// Name of the agent HTTP authentication realm for read-write endpoints.
constexpr char READWRITE_HTTP_AUTHENTICATION_REALM[] = "mesos-agent-readwrite";

// Name of the agent HTTP authentication realm for HTTP executors.
constexpr char EXECUTOR_HTTP_AUTHENTICATION_REALM[] = "mesos-agent-executor";

// Default maximum storage space to be used by the fetcher cache.
constexpr Bytes DEFAULT_FETCHER_CACHE_SIZE = Gigabytes(2);

// If no pings received within this timeout, then the slave will
// trigger a re-detection of the master to cause a re-registration.
Duration DEFAULT_MASTER_PING_TIMEOUT();

// Name of the executable for default executor.
#ifdef __WINDOWS__
constexpr char MESOS_DEFAULT_EXECUTOR[] = "mesos-default-executor.exe";
#else
constexpr char MESOS_DEFAULT_EXECUTOR[] = "mesos-default-executor";
#endif // __WINDOWS__

// Virtual path on which agent logs are mounted in `/files/` endpoint.
constexpr char AGENT_LOG_VIRTUAL_PATH[] = "/slave/log";

std::vector<SlaveInfo::Capability> AGENT_CAPABILITIES();

} // namespace slave {
Exemplo n.º 11
0
namespace master {

// TODO(benh): Add units after constants.
// TODO(benh): Also make configuration options be constants.

// TODO(vinod): Move constants that are only used in flags to
// 'master/flags.hpp'.

// TODO(jieyu): Use static functions for all the constants. See more
// details in MESOS-1023.

// Maximum number of slot offers to have outstanding for each framework.
constexpr int MAX_OFFERS_PER_FRAMEWORK = 50;

// Minimum number of cpus per offer.
constexpr double MIN_CPUS = 0.01;

// Minimum amount of memory per offer.
constexpr Bytes MIN_MEM = Megabytes(32);

// Default interval the master uses to send heartbeats to an HTTP
// scheduler.
constexpr Duration DEFAULT_HEARTBEAT_INTERVAL = Seconds(15);

// Amount of time within which a slave PING should be received.
// NOTE: The slave uses these PING constants to determine when
// the master has stopped sending pings. If these are made
// configurable, then we'll need to rely on upper/lower bounds
// to ensure that the slave is not unnecessarily triggering
// re-registrations.
constexpr Duration DEFAULT_AGENT_PING_TIMEOUT = Seconds(15);

// Maximum number of ping timeouts until slave is considered failed.
constexpr size_t DEFAULT_MAX_AGENT_PING_TIMEOUTS = 5;

// The minimum timeout that can be used by a newly elected leader to
// allow re-registration of slaves. Any slaves that do not re-register
// within this timeout will be marked unreachable; if/when the agent
// re-registers, non-partition-aware tasks running on the agent will
// be terminated.
constexpr Duration MIN_AGENT_REREGISTER_TIMEOUT = Minutes(10);

// Default limit on the percentage of slaves that will be removed
// after recovering if no re-registration attempts were made.
// TODO(bmahler): There's no value here that works for all setups.
// Currently the default is 100% which is favorable to those running
// small clusters or experimenting with Mesos. However, it's important
// that we also prevent the catastrophic 100% removal case for
// production clusters. This TODO is to provide a --production flag
// which would allow flag defaults that are more appropriate for
// production use-cases.
constexpr double RECOVERY_AGENT_REMOVAL_PERCENT_LIMIT = 1.0; // 100%.

// Maximum number of removed slaves to store in the cache.
constexpr size_t MAX_REMOVED_SLAVES = 100000;

// Default maximum number of completed frameworks to store in the cache.
constexpr size_t DEFAULT_MAX_COMPLETED_FRAMEWORKS = 50;

// Default maximum number of completed tasks per framework
// to store in the cache.
constexpr size_t DEFAULT_MAX_COMPLETED_TASKS_PER_FRAMEWORK = 1000;

// Default maximum number of unreachable tasks per framework
// to store in the cache.
constexpr size_t DEFAULT_MAX_UNREACHABLE_TASKS_PER_FRAMEWORK = 1000;

// Time interval to check for updated watchers list.
constexpr Duration WHITELIST_WATCH_INTERVAL = Seconds(5);

// Default number of tasks (limit) for /master/tasks endpoint.
constexpr size_t TASK_LIMIT = 100;

constexpr Duration DEFAULT_REGISTRY_GC_INTERVAL = Minutes(15);

constexpr Duration DEFAULT_REGISTRY_MAX_AGENT_AGE = Weeks(2);

constexpr size_t DEFAULT_REGISTRY_MAX_AGENT_COUNT = 100 * 1024;

/**
 * Label used by the Leader Contender and Detector.
 *
 * \deprecated Will be deprecated as of Mesos 0.24: see MESOS-2340.
 */
constexpr char MASTER_INFO_LABEL[] = "info";

/**
 * Label used by the Leader Contender and Detector, for JSON content.
 *
 * \since Mesos 0.23 (see MESOS-2340).
 */
constexpr char MASTER_INFO_JSON_LABEL[] = "json.info";

// Timeout used for ZooKeeper related operations.
// TODO(vinod): Master detector/contender should use this timeout.
constexpr Duration ZOOKEEPER_SESSION_TIMEOUT = Seconds(10);

// Name of the default, CRAM-MD5 authenticator.
constexpr char DEFAULT_AUTHENTICATOR[] = "crammd5";

// Name of the default, HierarchicalDRF authenticator.
constexpr char DEFAULT_ALLOCATOR[] = "HierarchicalDRF";

// The default interval between allocations.
constexpr Duration DEFAULT_ALLOCATION_INTERVAL = Seconds(1);

// Name of the default, local authorizer.
constexpr char DEFAULT_AUTHORIZER[] = "local";

// Name of the master HTTP authentication realm for read-only endpoints.
constexpr char READONLY_HTTP_AUTHENTICATION_REALM[] =
  "mesos-master-readonly";

// Name of the master HTTP authentication realm for read-write endpoints.
constexpr char READWRITE_HTTP_AUTHENTICATION_REALM[] =
  "mesos-master-readwrite";

// Name of the default authentication realm for HTTP frameworks.
constexpr char DEFAULT_HTTP_FRAMEWORK_AUTHENTICATION_REALM[] =
  "mesos-master-scheduler";

// Agents older than this version are not allowed to register.
const Version MINIMUM_AGENT_VERSION = Version(1, 0, 0);

std::vector<MasterInfo::Capability> MASTER_CAPABILITIES();

} // namespace master {
Exemplo n.º 12
0
  Flags()
  {
    add(&Flags::environment_variable_prefix,
        "environment_variable_prefix",
        "Prefix for environment variables meant to modify the behavior of\n"
        "the container logger for the specific executor being launched.\n"
        "The logger will look for the prefixed environment variables in the\n"
        "'ExecutorInfo's 'CommandInfo's 'Environment':\n"
        "  * DESTINATION_TYPE\n"
        "  * LOGROTATE_MAX_STDOUT_SIZE\n"
        "  * LOGROTATE_STDOUT_OPTIONS\n"
        "  * LOGROTATE_MAX_STDERR_SIZE\n"
        "  * LOGROTATE_STDERR_OPTIONS\n"
        "If present, these variables will override the global values set\n"
        "via module parameters.",
        "CONTAINER_LOGGER_");

    add(&Flags::companion_dir,
        "companion_dir",
        None(),
        "Directory where this module's companion binary is located.\n"
        "The journald container logger will find the '" +
        mesos::journald::logger::NAME + "'\n"
        "binary file under this directory.",
        static_cast<const std::string*>(nullptr),
        [](const std::string& value) -> Option<Error> {
          std::string executablePath =
            path::join(value, mesos::journald::logger::NAME);

          if (!os::exists(executablePath)) {
            return Error("Cannot find: " + executablePath);
          }

          return None();
        });

    add(&Flags::logrotate_path,
        "logrotate_path",
        "If specified, the logrotate container logger will use the specified\n"
        "'logrotate' instead of the system's 'logrotate'.",
        "logrotate",
        [](const std::string& value) -> Option<Error> {
          // Check if `logrotate` exists via the help command.
          // TODO(josephw): Consider a more comprehensive check.
          Try<std::string> helpCommand =
            os::shell(value + " --help > /dev/null");

          if (helpCommand.isError()) {
            return Error(
                "Failed to check logrotate: " + helpCommand.error());
          }

          return None();
        });

    add(&Flags::max_label_payload_size,
        "max_label_payload_size",
        "Maximum size of the label data transferred to the\n"
        "logger companion binary. Can be at most one megabyte.",
        Kilobytes(10),
        [](const Bytes& value) -> Option<Error> {
          if (value > Megabytes(1)) {
            return Error(
                "Maximum --max_label_payload_size is one megabyte");
          }

          return None();
        });

    add(&Flags::libprocess_num_worker_threads,
        "libprocess_num_worker_threads",
        "Number of Libprocess worker threads.\n"
        "Defaults to 8.  Must be at least 1.",
        8u,
        [](const size_t& value) -> Option<Error> {
          if (value < 1u) {
            return Error(
                "Expected --libprocess_num_worker_threads of at least 1");
          }

          return None();
        });


    add(&Flags::fluentbit_ip,
        "fluentbit_ip",
        "IP of the Fluent Bit TCP listener.",
        [](const Option<net::IP>& value) -> Option<Error> {
          if (value.isNone()) {
            return Error("--fluentbit_ip is required");
          }

          return None();
        });

    add(&Flags::fluentbit_port,
        "fluentbit_port",
        "Port of the Fluent Bit TCP listener.");
  }
Exemplo n.º 13
0
  Flags()
  {
    add(&max_stdout_size,
        "max_stdout_size",
        "Maximum size, in bytes, of a single stdout log file.\n"
        "Defaults to 10 MB.  Must be at least 1 (memory) page.",
        Megabytes(10),
        &Flags::validateSize);

    add(&logrotate_stdout_options,
        "logrotate_stdout_options",
        "Additional config options to pass into 'logrotate' for stdout.\n"
        "This string will be inserted into a 'logrotate' configuration file.\n"
        "i.e.\n"
        "  /path/to/stdout {\n"
        "    <logrotate_stdout_options>\n"
        "    size <max_stdout_size>\n"
        "  }\n"
        "NOTE: The 'size' option will be overriden by this module.");

    add(&max_stderr_size,
        "max_stderr_size",
        "Maximum size, in bytes, of a single stderr log file.\n"
        "Defaults to 10 MB.  Must be at least 1 (memory) page.",
        Megabytes(10),
        &Flags::validateSize);

    add(&logrotate_stderr_options,
        "logrotate_stderr_options",
        "Additional config options to pass into 'logrotate' for stderr.\n"
        "This string will be inserted into a 'logrotate' configuration file.\n"
        "i.e.\n"
        "  /path/to/stderr {\n"
        "    <logrotate_stderr_options>\n"
        "    size <max_stderr_size>\n"
        "  }\n"
        "NOTE: The 'size' option will be overriden by this module.");

    add(&launcher_dir,
        "launcher_dir",
        "Directory path of Mesos binaries.  The logrotate container logger\n"
        "will find the '" + mesos::internal::logger::rotate::NAME + "'\n"
        "binary file under this directory.",
        PKGLIBEXECDIR,
        [](const std::string& value) -> Option<Error> {
          std::string executablePath =
            path::join(value, mesos::internal::logger::rotate::NAME);

          if (!os::exists(executablePath)) {
            return Error("Cannot find: " + executablePath);
          }

          return None();
        });

    add(&logrotate_path,
        "logrotate_path",
        "If specified, the logrotate container logger will use the specified\n"
        "'logrotate' instead of the system's 'logrotate'.",
        "logrotate",
        [](const std::string& value) -> Option<Error> {
          // Check if `logrotate` exists via the help command.
          // TODO(josephw): Consider a more comprehensive check.
          Try<std::string> helpCommand =
            os::shell(value + " --help > /dev/null");

          if (helpCommand.isError()) {
            return Error(
                "Failed to check logrotate: " + helpCommand.error());
          }

          return None();
        });

    add(&libprocess_num_worker_threads,
        "libprocess_num_worker_threads",
        "Number of Libprocess worker threads.\n"
        "Defaults to 8.  Must be at least 1.",
        8u,
        [](const size_t& value) -> Option<Error> {
          if (value < 1u) {
            return Error(
                "Expected --libprocess_num_worker_threads of at least 1");
          }

          return None();
        });
  }
Exemplo n.º 14
0
// This is an end-to-end test that verfies that the slave returns the
// correct ResourceUsage based on the currently running executors, and
// the values get from the statistics endpoint are as expected.
TEST_F(MonitorIntegrationTest, RunningExecutor)
{
  Try<PID<Master>> master = StartMaster();
  ASSERT_SOME(master);

  Try<PID<Slave>> slave = StartSlave();
  ASSERT_SOME(slave);

  MockScheduler sched;
  MesosSchedulerDriver driver(
      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);

  EXPECT_CALL(sched, registered(&driver, _, _));

  Future<vector<Offer>> offers;
  EXPECT_CALL(sched, resourceOffers(&driver, _))
    .WillOnce(FutureArg<1>(&offers))
    .WillRepeatedly(Return());        // Ignore subsequent offers.

  driver.start();

  AWAIT_READY(offers);
  EXPECT_FALSE(offers.get().empty());

  const Offer& offer = offers.get()[0];

  // Launch a task and wait until it is in RUNNING status.
  TaskInfo task = createTask(
      offer.slave_id(),
      Resources::parse("cpus:1;mem:32").get(),
      "sleep 1000");

  Future<TaskStatus> status;
  EXPECT_CALL(sched, statusUpdate(&driver, _))
    .WillOnce(FutureArg<1>(&status));

  driver.launchTasks(offer.id(), {task});

  AWAIT_READY(status);
  EXPECT_EQ(task.task_id(), status.get().task_id());
  EXPECT_EQ(TASK_RUNNING, status.get().state());

  // Hit the statistics endpoint and expect the response contains the
  // resource statistics for the running container.
  UPID upid("monitor", process::address());

  Future<http::Response> response = http::get(upid, "statistics");
  AWAIT_READY(response);

  AWAIT_EXPECT_RESPONSE_STATUS_EQ(http::OK().status, response);
  AWAIT_EXPECT_RESPONSE_HEADER_EQ(
      "application/json",
      "Content-Type",
      response);

  // Verify that the statistics in the response contains the proper
  // resource limits for the container.
  Try<JSON::Value> value = JSON::parse(response.get().body);
  ASSERT_SOME(value);

  Try<JSON::Value> expected = JSON::parse(strings::format(
      "[{"
          "\"statistics\":{"
              "\"cpus_limit\":%g,"
              "\"mem_limit_bytes\":%lu"
          "}"
      "}]",
      1 + slave::DEFAULT_EXECUTOR_CPUS,
      (Megabytes(32) + slave::DEFAULT_EXECUTOR_MEM).bytes()).get());

  ASSERT_SOME(expected);
  EXPECT_TRUE(value.get().contains(expected.get()));

  driver.stop();
  driver.join();

  Shutdown();
}
Exemplo n.º 15
0
  Flags()
  {
    // TODO(benh): Is there a way to specify units for the resources?
    add(&Flags::resources,
        "resources",
        "Total consumable resources per slave, in\n"
        "the form 'name(role):value;name(role):value...'.");

    add(&Flags::default_role,
        "default_role",
        "Any resources in the --resources flag that\n"
        "omit a role, as well as any resources that\n"
        "are not present in --resources but that are\n"
        "automatically detected, will be assigned to\n"
        "this role.",
        "*");

    add(&Flags::attributes,
      "attributes",
      "Attributes of machine");

    add(&Flags::work_dir,
        "work_dir",
        "Where to place framework work directories\n",
        "/tmp/mesos");

    add(&Flags::launcher_dir, // TODO(benh): This needs a better name.
        "launcher_dir",
        "Location of Mesos binaries",
        PKGLIBEXECDIR);

    add(&Flags::hadoop_home,
        "hadoop_home",
        "Where to find Hadoop installed (for\n"
        "fetching framework executors from HDFS)\n"
        "(no default, look for HADOOP_HOME in\n"
        "environment or find hadoop on PATH)",
        "");

    add(&Flags::switch_user,
        "switch_user",
        "Whether to run tasks as the user who\n"
        "submitted them rather than the user running\n"
        "the slave (requires setuid permission)",
        true);

    add(&Flags::frameworks_home,
        "frameworks_home",
        "Directory prepended to relative executor URIs",
        "");

    add(&Flags::executor_registration_timeout,
        "executor_registration_timeout",
        "Amount of time to wait for an executor\n"
        "to register with the slave before considering it hung and\n"
        "shutting it down (e.g., 60secs, 3mins, etc)",
        EXECUTOR_REGISTRATION_TIMEOUT);

    add(&Flags::executor_shutdown_grace_period,
        "executor_shutdown_grace_period",
        "Amount of time to wait for an executor\n"
        "to shut down (e.g., 60secs, 3mins, etc)",
        EXECUTOR_SHUTDOWN_GRACE_PERIOD);

    add(&Flags::gc_delay,
        "gc_delay",
        "Maximum amount of time to wait before cleaning up\n"
        "executor directories (e.g., 3days, 2weeks, etc).\n"
        "Note that this delay may be shorter depending on\n"
        "the available disk usage.",
        GC_DELAY);

    add(&Flags::disk_watch_interval,
        "disk_watch_interval",
        "Periodic time interval (e.g., 10secs, 2mins, etc)\n"
        "to check the disk usage",
        DISK_WATCH_INTERVAL);

    add(&Flags::resource_monitoring_interval,
        "resource_monitoring_interval",
        "Periodic time interval for monitoring executor\n"
        "resource usage (e.g., 10secs, 1min, etc)",
        RESOURCE_MONITORING_INTERVAL);

    // TODO(vinod): Consider killing this flag and always checkpoint.
    add(&Flags::checkpoint,
        "checkpoint",
        "Whether to checkpoint slave and frameworks information\n"
        "to disk. This enables a restarted slave to recover\n"
        "status updates and reconnect with (--recover=reconnect) or\n"
        "kill (--recover=kill) old executors",
        false);

    add(&Flags::recover,
        "recover",
        "Whether to recover status updates and reconnect with old executors.\n"
        "Valid values for 'recover' are\n"
        "reconnect: Reconnect with any old live executors.\n"
        "cleanup  : Kill any old live executors and exit.\n"
        "           Use this option when doing an incompatible slave\n"
        "           or executor upgrade!).\n"
        "NOTE: If checkpointed slave doesn't exist, no recovery is performed\n"
        "      and the slave registers with the master as a new slave.",
        "reconnect");

    add(&Flags::recovery_timeout,
        "recovery_timeout",
        "Amount of time alloted for the slave to recover. If the slave takes\n"
        "longer than recovery_timeout to recover, any executors that are\n"
        "waiting to reconnect to the slave will self-terminate.\n"
        "NOTE: This flag is only applicable when checkpoint is enabled.\n",
        RECOVERY_TIMEOUT);

    add(&Flags::strict,
        "strict",
        "If strict=true, any and all recovery errors are considered fatal.\n"
        "If strict=false, any expected errors (e.g., slave cannot recover\n"
        "information about an executor, because the slave died right before\n"
        "the executor registered.) during recovery are ignored and as much\n"
        "state as possible is recovered.\n",
        true);

#ifdef __linux__
    add(&Flags::cgroups_hierarchy,
        "cgroups_hierarchy",
        "The path to the cgroups hierarchy root\n",
        "/cgroup");

    add(&Flags::cgroups_root,
        "cgroups_root",
        "Name of the root cgroup\n",
        "mesos");

    add(&Flags::cgroups_subsystems,
        "cgroups_subsystems",
        "List of subsystems to enable (e.g., 'cpu,freezer')\n",
        "cpu,memory,freezer");

    add(&Flags::cgroups_enable_cfs,
        "cgroups_enable_cfs",
        "Cgroups feature flag to enable hard limits on CPU resources\n"
        "via the CFS bandwidth limiting subfeature.\n",
        false);

    add(&Flags::cgroups_oom_buffer,
        "cgroups_oom_buffer",
        "Additional memory alloted to executors in order to allow mesos\n"
        "to soft-kill the executor prior to the kernel placing it under OOM.\n"
        "(e.g. 128MB)\n"
        "NOTE: This was added to compensate for a bug in the Linux kernel\n"
        "      that causes the system to lock up when the oom_killer is\n"
        "      disabled.",
        Megabytes(128));
#endif
  }
Exemplo n.º 16
0
int main(int argc, char** argv)
{
	//stbi_set_flip_vertically_on_load(1);

	if(SDL_Init(SDL_INIT_EVERYTHING) != 0) {
		Log_Error("Could not init SDL"); 
		Log_Error(SDL_GetError());
		return 1;
	}

	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
	SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 1);
	SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
	

	int32 window_display_index = 0;
#if 1
	window_display_index = 1;
#endif
	SDL_Window* window = SDL_CreateWindow("Rituals", 
			SDL_WINDOWPOS_CENTERED_DISPLAY(window_display_index), 
			SDL_WINDOWPOS_CENTERED_DISPLAY(window_display_index),
			1280, 720, 
			SDL_WINDOW_OPENGL | 
			SDL_WINDOW_RESIZABLE |
			SDL_WINDOW_MOUSE_FOCUS |
			SDL_WINDOW_INPUT_FOCUS);

	if(window == NULL) {
		Log_Error("Could not create window");
		Log_Error(SDL_GetError());
		return 1;
	}

	printf("%s \n", SDL_GetError());
	SDL_GLContext glctx = SDL_GL_CreateContext(window);

	if(ogl_LoadFunctions() == ogl_LOAD_FAILED) {
		Log_Error("Could not load OpenGL 3.3 functions...");
		return 1;
	}

	int ret = SDL_GL_SetSwapInterval(-1);

	{
#define _check_gl_attribute(attr, val) int _##attr##_val; \
	int _##attr##_success = SDL_GL_GetAttribute(attr, &_##attr##_val); \
	gl_checks[gl_check_count++] = _##attr##_val == val; \
	gl_names[gl_check_count - 1] = #attr; \
	gl_vals[gl_check_count - 1] = _##attr##_val; \
	gl_exp_vals[gl_check_count - 1] = val; 
			 
		//check if we got everything
		bool gl_checks[64];
		char* gl_names[64];
		int gl_vals[64];
		int gl_exp_vals[64];
		isize gl_check_count = 0;

		_check_gl_attribute(SDL_GL_RED_SIZE, 8);
		_check_gl_attribute(SDL_GL_GREEN_SIZE, 8);
		_check_gl_attribute(SDL_GL_BLUE_SIZE, 8);
		_check_gl_attribute(SDL_GL_ALPHA_SIZE, 8);
		_check_gl_attribute(SDL_GL_DOUBLEBUFFER, 1);
		_check_gl_attribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
		_check_gl_attribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
		_check_gl_attribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 1);
		_check_gl_attribute(SDL_GL_ACCELERATED_VISUAL, 1);
		_check_gl_attribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

		for(isize i = 0; i < gl_check_count; ++i) {
			printf("%s %s: wanted %d, got %d \n", 
					gl_names[i], 
					gl_checks[i] ? "succeeeded" : "failed", 
					gl_exp_vals[i], 
					gl_vals[i]);
		}

	}	

	// Game initializiation
	game = Allocate(Game, 1);
	{
		game->window = window;
		game->state = Game_State_None;
		game->meta_arena = Allocate(Memory_Arena, 1);
		init_memory_arena(game->meta_arena, isz(Memory_Arena) * 10);
		game->game_arena = new_memory_arena(Kilobytes(64), game->meta_arena);
		game->asset_arena = new_memory_arena(Megabytes(512), game->meta_arena);
		game->temp_arena = new_memory_arena(Megabytes(64), game->meta_arena);
		game->play_arena = new_memory_arena(Megabytes(512), game->meta_arena);
		game->renderer_arena = new_memory_arena(Megabytes(32), game->meta_arena);

		game->base_path = SDL_GetBasePath();
		game->base_path_length = strlen(game->base_path);

		game->input = Arena_Push_Struct(game->game_arena, Game_Input);
		game->input->scancodes = Arena_Push_Array(game->game_arena, int8, SDL_NUM_SCANCODES);
		game->input->keycodes = Arena_Push_Array(game->game_arena, int8, SDL_NUM_SCANCODES);
		game->input->mouse = Arena_Push_Array(game->game_arena, int8, 16);

		init_random(&game->r, time(NULL));
		//TODO(will) load window settings from file
		game->window_size = v2i(1280, 720);
		game->scale = 1.0f;

		game->renderer = Arena_Push_Struct(game->game_arena, Renderer);
		renderer_init(game->renderer, game->renderer_arena);

		renderer = game->renderer;
		input = game->input;
	}

	load_assets();

	bool running = true;
	SDL_Event event;
	glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
	//glClearColor(1, 1, 1, 1);

	play_state->current_time = SDL_GetTicks();
	play_state->prev_time = play_state->current_time;
	while(running) {
		uint64 start_ticks = SDL_GetTicks();

		if(game->input->num_keys_down < 0) game->input->num_keys_down = 0;
		if(game->input->num_mouse_down < 0) game->input->num_mouse_down = 0;

		if(game->input->num_keys_down > 0)
		for(int64 i = 0; i < SDL_NUM_SCANCODES; ++i) {
			int8* t = game->input->scancodes + i;
			if(*t == State_Just_Released) {
				*t = State_Released;
			} else if(*t == State_Just_Pressed) {
				*t = State_Pressed;
			}
			t = game->input->keycodes + i;
			if(*t == State_Just_Released) {
				*t = State_Released;
			} else if(*t == State_Just_Pressed) {
				*t = State_Pressed;
			}
		}
		if(game->input->num_mouse_down > 0)
		for(int64 i = 0; i < 16; ++i) {
			int8* t = game->input->mouse + i;
			if(*t == State_Just_Released) {
				*t = State_Released;
			} else if(*t == State_Just_Pressed) {
				*t = State_Pressed;
			}
		}


		while(SDL_PollEvent(&event)) {
			//TODO(will) handle text input
			switch(event.type) {
				case SDL_QUIT:
					running = false;
					break;
				case SDL_WINDOWEVENT:
					update_screen();
					break;
				case SDL_KEYDOWN:
					game->input->num_keys_down++;
					if(!event.key.repeat) {
						game->input->scancodes[event.key.keysym.scancode] = State_Just_Pressed;
						if(event.key.keysym.sym < SDL_NUM_SCANCODES) {
							game->input->keycodes[event.key.keysym.sym] = State_Just_Pressed;
						}
					}
					break;
				case SDL_KEYUP:
					game->input->num_keys_down--;
					if(!event.key.repeat) {
						game->input->scancodes[event.key.keysym.scancode] = State_Just_Released;
						if(event.key.keysym.sym < SDL_NUM_SCANCODES) {
							game->input->keycodes[event.key.keysym.sym] = State_Just_Released;
						}
					}
					break;
				case SDL_MOUSEBUTTONDOWN:
					game->input->num_mouse_down++;
					game->input->mouse[event.button.button] = State_Just_Pressed;
					break;
				case SDL_MOUSEBUTTONUP:
					game->input->num_mouse_down--;
					game->input->mouse[event.button.button] = State_Just_Released;
					break;
			}
		}
	
		int mx, my;
		SDL_GetMouseState(&mx, &my);
		input->mouse_x = mx;
		input->mouse_y = my;

		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		update();

		SDL_GL_SwapWindow(window);
		uint64 frame_ticks = SDL_GetTicks() - start_ticks;
		//if(frame_ticks > 18) printf("Slow frame! %d\n", frame_ticks);
	}

	SDL_Quit();
	return 0;
}
Exemplo n.º 17
0
  Flags()
  {
    setUsageMessage(
      "Usage: " + NAME + " [options]\n"
      "\n"
      "This command pipes from STDIN to the given leading log file.\n"
      "When the leading log file reaches '--max_size', the command.\n"
      "uses 'logrotate' to rotate the logs.  All 'logrotate' options\n"
      "are supported.  See '--logrotate_options'.\n"
      "\n");

    add(&max_size,
        "max_size",
        "Maximum size, in bytes, of a single log file.\n"
        "Defaults to 10 MB.  Must be at least 1 (memory) page.",
        Megabytes(10),
        [](const Bytes& value) -> Option<Error> {
          if (value.bytes() < (size_t) sysconf(_SC_PAGE_SIZE)) {
            return Error(
                "Expected --max_size of at least " +
                stringify(sysconf(_SC_PAGE_SIZE)) + " bytes");
          }
          return None();
        });

    add(&logrotate_options,
        "logrotate_options",
        "Additional config options to pass into 'logrotate'.\n"
        "This string will be inserted into a 'logrotate' configuration file.\n"
        "i.e.\n"
        "  /path/to/<log_filename> {\n"
        "    <logrotate_options>\n"
        "    size <max_size>\n"
        "  }\n"
        "NOTE: The 'size' option will be overriden by this command.");

    add(&log_filename,
        "log_filename",
        "Absolute path to the leading log file.\n"
        "NOTE: This command will also create two files by appending\n"
        "'" + CONF_SUFFIX + "' and '" + STATE_SUFFIX + "' to the end of\n"
        "'--log_filename'.  These files are used by 'logrotate'.",
        [](const Option<std::string>& value) -> Option<Error> {
          if (value.isNone()) {
            return Error("Missing required option --log_filename");
          }

          if (!path::absolute(value.get())) {
            return Error("Expected --log_filename to be an absolute path");
          }

          return None();
        });

    add(&logrotate_path,
        "logrotate_path",
        "If specified, this command will use the specified\n"
        "'logrotate' instead of the system's 'logrotate'.",
        "logrotate",
        [](const std::string& value) -> Option<Error> {
          // Check if `logrotate` exists via the help command.
          // TODO(josephw): Consider a more comprehensive check.
          Try<std::string> helpCommand =
            os::shell(value + " --help > /dev/null");

          if (helpCommand.isError()) {
            return Error(
                "Failed to check logrotate: " + helpCommand.error());
          }

          return None();
        });
  }
Exemplo n.º 18
0
// WINDOWS MAIN FUNCTION
// hInst = current instance of the program
// hPrevInst = previous instance which is not used anymore.
// cmdLine = holds command line arguments to be passed in to the program
// cmdShow = holds an integer to specify if we want to show this window.
int CALLBACK WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdLine, int cmdShow)
{
    WNDCLASS wc = {0};
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.hInstance = hInst;
    wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
    wc.lpszClassName = wndClassName;
    wc.hCursor = 0; //TODO: Add cursors and icons to this program.
    wc.hIcon = 0;
    wc.lpfnWndProc = (WNDPROC)wndProc;

    RegisterClass(&wc);

    HWND window = CreateWindow(wndClassName, wndTitle,
                               WS_OVERLAPPEDWINDOW,
                               CW_USEDEFAULT, CW_USEDEFAULT,
                               wndWidth, wndHeight,
                               0, 0, hInst, 0);
    
    if(window)
    {
        ShowWindow(window, SW_SHOW);
        UpdateWindow(window);

        // NOTE: Initializing SDL
        if(SDL_Init(SDL_INIT_VIDEO) != 0 )
        {
            DestroyWindow(window);
            return -2;
        }

        IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG);
        
        sdlWindow = SDL_CreateWindowFrom((void*)window);

        char error[MAX_PATH];
        stringCopy(error, SDL_GetError());
        OutputDebugStringA(error);

        if(!sdlWindow)
        {
            SDL_Quit();
            DestroyWindow(window);
            return -3;
        }
        
        renderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

        if(!renderer)
        {
            SDL_DestroyWindow(sdlWindow);
            SDL_Quit();
            DestroyWindow(window);
            return -4;
        }

        i32 RefreshRate = 0;
        HDC dc = GetDC(window);
        i32 winRefreshRate = GetDeviceCaps(dc, VREFRESH);

        if( winRefreshRate > 1 )
        {
            RefreshRate = winRefreshRate / 2;
        }
        else
        {
            RefreshRate = 30;
        }

        r32 targetSecsPerFrame = 1.0f / RefreshRate;

        GameMemory memory = {};
        memory.permanentSize = Megabytes(64);
        memory.transientSize = Megabytes(64);
        memory.totalSize = memory.permanentSize + memory.transientSize;
        
        gameMemoryBlock = VirtualAlloc( 0, memory.totalSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

        if(!gameMemoryBlock)
        {
            SDL_DestroyRenderer(renderer);
            SDL_DestroyWindow(sdlWindow);
            SDL_Quit();
            DestroyWindow(window);
            return -5;
        }

        memory.permanentBlock = gameMemoryBlock;
        memory.transientBlock = (i8*)gameMemoryBlock + memory.permanentSize;
        memory.readEntireFile = ReadEntireFile;
        memory.freeFile = FreeFile;
        memory.writeEntireFile = WriteEntireFile;

        Win32Dims windowDims = GetWindowDimensions(window);
        
        Render render = {};
        render.renderer = renderer;
        render.screenW = windowDims.width;
        render.screenH = windowDims.height;
        
        GameController input = {0};
        input.dt = targetSecsPerFrame;
        
        Win32State state = {0};
        state.memoryBlock = gameMemoryBlock;
        state.memorySize = memory.totalSize;

        GameCodeDLL gameCode =  Win32LoadGameCode("Game.dll", "Game_temp.dll", "lock.tmp");
        
        isRunning = true;

        r32 sleepIsGranular = (timeBeginPeriod(1) == TIMERR_NOERROR);
        
        LARGE_INTEGER lastCounter = Win32GetClock();

        i64 lastCycles = __rdtsc();
        
        LARGE_INTEGER performanceFreqPerSecRes;
        QueryPerformanceFrequency(&performanceFreqPerSecRes);
        globalPerformanceCountFreq = performanceFreqPerSecRes.QuadPart;
        
        // NOTE: PROGRAM LOOP!!
        while(isRunning)
        {
            // NOTE: compare File times for us to be able to reload the new game code
            FILETIME currentFileTime = Win32GetLastWriteTime("Game.dll");
            if(CompareFileTime(&currentFileTime, &gameCode.lastWriteTime) != 0)
            {
                Win32UnloadGameCode(&gameCode);
                gameCode = Win32LoadGameCode("Game.dll", "Game_temp.dll", "lock.tmp");
            }
            
            MSG msg = {0};
            while(PeekMessage(&msg, window, 0, 0, PM_REMOVE))
            {
                switch(msg.message)
                {
                    case WM_CLOSE:
                    {
                        isRunning = false;
                    }break;

                    case WM_KEYUP:
                    case WM_KEYDOWN:
                    case WM_SYSKEYUP:
                    case WM_SYSKEYDOWN:
                    {
                        u32 vkCode = (u32)msg.wParam;   // This contains the keycode for the key that the user pressed.
                        bool isDown = ((msg.lParam & (1 << 31)) == 0);  // Check to see if the key is down now.
                        bool wasDown = ((msg.lParam & (1 << 30)) != 0); // Check to see if the key was down previously.

                        if(isDown != wasDown)
                        {
                            if(vkCode == 'W')
                            {
                                input.moveUp.isDown = isDown;
                            }
                            else if(vkCode == 'S')
                            {
                                input.moveDown.isDown = isDown;
                            }
                            else if(vkCode == 'A')
                            {
                                input.moveLeft.isDown = isDown;
                            }
                            else if(vkCode == 'D')
                            {
                                input.moveRight.isDown = isDown;
                            }
                            if(vkCode == VK_UP)
                            {
                                input.actionUp.isDown = isDown;
                            }
                            else if(vkCode == VK_DOWN)
                            {
                                input.actionDown.isDown = isDown;
                            }
                            else if(vkCode == VK_LEFT)
                            {
                                input.actionLeft.isDown = isDown;
                            }
                            else if(vkCode == VK_RIGHT)
                            {
                                input.actionRight.isDown = isDown;
                            }
                            else if(vkCode == VK_ESCAPE)
                            {
                                input.back.isDown = isDown;
                            }
                            else if(vkCode == 'O')
                            {
                                if(isDown)
                                {
                                    if(state.recordingIndex == 0)
                                    {
                                        BeginRecording(&state, 1);
                                    }
                                    else
                                    {
                                        EndRecording(&state);
                                        BeginPlayback(&state, 1);
                                    }
                                }
                            }
                            else if(vkCode == 'P')
                            {
                                if(isDown)
                                {
                                    if(state.playbackIndex > 0)
                                    {
                                        EndPlayback(&state);
                                        ZeroMemory(&input, sizeof(input));
                                    }
                                }
                            }
                        }

                        if(isDown)
                        {
                            bool AltKeyWasDown = ((msg.lParam & (1 << 29)) != 0);
                            if(vkCode == VK_RETURN && AltKeyWasDown)
                            {
                                if(msg.hwnd)
                                {
                                    isFullscreen = !isFullscreen;
                                    Win32FullscreenToggle(msg.hwnd);
                                }
                            }
                        }

                    }break;

                    default:
                    {
                        TranslateMessage(&msg);
                        DispatchMessage(&msg);
                    }
                }
            }

            if(input.back.isDown)
            {
                isRunning = false;
                PostQuitMessage(0);
            }

            if(state.recordingIndex > 0)
            {
                RecordingInput(&state, &input);
            }
            else if(state.playbackIndex > 0)
            {
                PlaybackInput(&state, &input);
            }

            Win32Dims windowDims = GetWindowDimensions(window);
            Win32UpdateWindow(windowDims, (i32*)&render.screenW, (i32*)&render.screenH);
            
            if(gameCode.UpdateRender)
            {
                gameCode.UpdateRender(&memory, &input, &render);
            }

            LARGE_INTEGER workCounter = Win32GetClock();
            r32 workSecsElapsed = Win32GetSecondsElapsed(lastCounter, workCounter);

            r32 secondsElapsed = workSecsElapsed;
            if(secondsElapsed < targetSecsPerFrame)
            {
                if(sleepIsGranular)
                {
                    DWORD sleepMS = (DWORD)(1000.0f * (targetSecsPerFrame - secondsElapsed));
                    if(sleepMS > 0)
                    {
                        Sleep(sleepMS);
                    }
                }

                r32 testSecsElapsed = Win32GetSecondsElapsed(lastCounter, Win32GetClock());
                if(testSecsElapsed < targetSecsPerFrame)
                {
                    //TODO: LOG MISSED SLEEP HERE!!
                }

                while(secondsElapsed < targetSecsPerFrame)
                {
                    secondsElapsed = Win32GetSecondsElapsed(lastCounter, Win32GetClock());
                }
            }
            else
            {
                //TODO: MISSED FRAME RATE!!
            }
            
            LARGE_INTEGER endCounter = Win32GetClock();

            i64 endCycles = __rdtsc();
            
            r64 elapsedCounts = (r64)(endCounter.QuadPart - lastCounter.QuadPart);
            r64 elapsedCycles = (r64)(endCycles - lastCycles);

            r32 MSperFrame = ((1000.0f * Win32GetSecondsElapsed(lastCounter, endCounter)));
            r32 FPS = (r32)(globalPerformanceCountFreq / elapsedCounts);
            r32 MegaCyclesPerFrame = (r32)(elapsedCycles / (1000.0f * 1000.0f));
            
            char buffer[256];
            sprintf_s(buffer, "%.02fms, %.02ffps, %.02fmcpf\n", MSperFrame, FPS, MegaCyclesPerFrame);            
            OutputDebugStringA(buffer);
            
            lastCounter = endCounter;
            lastCycles = endCycles;
            
        } // NOTE: END OF WHILE LOOP

        //IMPORTANT: Unload this when we exit the program.
        Win32UnloadGameCode(&gameCode);        
    }
    else
    {
        // TODO: Handle Error Loggin here!!
        return -1;
    }

    if(gameMemoryBlock)
    {
        VirtualFree(gameMemoryBlock, 0, MEM_RELEASE);
    }
    
    //Close
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(sdlWindow);
    IMG_Quit();
    SDL_Quit();
    DestroyWindow(window);

    return 0;
}
Exemplo n.º 19
0
  LoggerFlags()
  {
    add(&LoggerFlags::destination_type,
        "destination_type",
        "Determines where logs should be piped.\n"
        "Valid destinations include: 'journald', 'logrotate',\n"
        "'fluentbit', 'journald+logrotate', or 'fluentbit+logrotate'.",
        "journald",
        [](const std::string& value) -> Option<Error> {
          if (value != "journald" &&
              value != "logrotate" &&
              value != "fluentbit" &&
              value != "journald+logrotate" &&
              value != "fluentbit+logrotate") {
            return Error("Invalid destination type: " + value);
          }

          return None();
        });

    add(&LoggerFlags::logrotate_max_stdout_size,
        "logrotate_max_stdout_size",
        "Maximum size, in bytes, of a single stdout log file.\n"
        "Defaults to 10 MB.  Must be at least 1 (memory) page.",
        Megabytes(10),
        &LoggerFlags::validateSize);

    add(&LoggerFlags::logrotate_stdout_options,
        "logrotate_stdout_options",
        "Additional config options to pass into 'logrotate' for stdout.\n"
        "This string will be inserted into a 'logrotate' configuration file.\n"
        "i.e.\n"
        "  /path/to/stdout {\n"
        "    <logrotate_stdout_options>\n"
        "    size <logrotate_max_stdout_size>\n"
        "  }\n"
        "NOTE: The 'size' option will be overridden by this module.");

    add(&LoggerFlags::logrotate_max_stderr_size,
        "logrotate_max_stderr_size",
        "Maximum size, in bytes, of a single stderr log file.\n"
        "Defaults to 10 MB.  Must be at least 1 (memory) page.",
        Megabytes(10),
        &LoggerFlags::validateSize);

    add(&LoggerFlags::logrotate_stderr_options,
        "logrotate_stderr_options",
        "Additional config options to pass into 'logrotate' for stderr.\n"
        "This string will be inserted into a 'logrotate' configuration file.\n"
        "i.e.\n"
        "  /path/to/stderr {\n"
        "    <logrotate_stderr_options>\n"
        "    size <logrotate_max_stderr_size>\n"
        "  }\n"
        "NOTE: The 'size' option will be overridden by this module.");

    add(&LoggerFlags::extra_labels,
        "extra_labels",
        "Extra key value pairs (in JSON object format) that will be set\n"
        "for the journald entry. Both the keys and the values need to be\n"
        "strings. Note, this field is meant for cases where ExecutorInfo\n"
        "labels are not applicable (e.g., standalone containers).\n"
        "For example:\n"
        "  {\"key\":\"value\"}",
        JSON::Object());
  }
Exemplo n.º 20
0
int CALLBACK
WinMain(
    HINSTANCE Instance,
    HINSTANCE PrevInstance,
    LPSTR CommandLine,
    int ShowCode)
{
#if 1
    Win32EnableConsole();


    
#endif

#if TERRIFIC_INTERNAL
    LPVOID BaseAddress = 0;//(LPVOID)Terabytes(2);
#else
    LPVOID BaseAddress = 0;
#endif

    win32_state State = {};

    game_memory GameMemory = {};
    GameMemory.PermanentStorageSize = Megabytes(512);
    GameMemory.TransientStorageSize = Megabytes(512);

    State.TotalSize = GameMemory.PermanentStorageSize + GameMemory.TransientStorageSize;

    State.GameMemoryBlock = VirtualAlloc(BaseAddress, State.TotalSize,
       MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
    DWORD Error = GetLastError();
    GameMemory.PermanentStorage = State.GameMemoryBlock;

    GameMemory.TransientStorage = ((uint8 *)GameMemory.PermanentStorage +
     GameMemory.PermanentStorageSize);


    char *GameDLLFullPath = "J:/build/terrific.dll";
    char *TempDLLName = "J:/build/tmp.dll";
    char *LockFileName = "J:/build/lock.tmp";

    auto GameCodeDLL = Win32LoadGameCode(GameDLLFullPath, TempDLLName, LockFileName);
    //Game *game = GameCodeDLL.CreateGame();

    uint32 m_fps_counter = 0;
    ex::TimeDelta delta = 0;
    sf::Clock m_fps_clock;
    m_fps_clock.restart();

    sf::Clock clock;
    sf::Clock frame_time_clock;

    sf::Int64 frame_times[5000];
    std::size_t frame_times_index = 0;

    std::fill( std::begin( frame_times ), std::end( frame_times ), 0 );

    uint32 loadCounter = 0;
    bool32 running = true;
    if (GameMemory.PermanentStorage && GameMemory.TransientStorage)
    {
        game_state *GameState = (game_state *) GameMemory.PermanentStorage;

        while(running)
        {

            FILETIME NewDLLWriteTime = Win32GetLastWriteTime(GameDLLFullPath);
            auto t = CompareFileTime(&NewDLLWriteTime, &GameCodeDLL.LastWriteTime);
            if(t != 0)
            {
              GameCodeDLL.DestroyGame(&GameMemory);
	      Win32DEBUGDelay(0.1f, "Exiting Game");
                Win32UnloadGameCode(&GameCodeDLL);
                Win32DEBUGDelay(0.2f, "Unloading Game Code");
                if(!DeleteFile(TempDLLName))
                {
                    return 666;
                }
                //Win32DEBUGDelay(0.1f, "Deleting tmp.dll");
                GameCodeDLL = Win32LoadGameCode(GameDLLFullPath, TempDLLName, LockFileName);
                if(GameCodeDLL.IsValid) {
                    //game = GameCodeDLL.CreateGame();
                    GameMemory.IsInitialized = false;

                    GameState = (game_state *) GameMemory.PermanentStorage;
                    GameState->RenderWindow.close();
                    while(GameState->RenderWindow.isOpen())
                    {

                    }
                    //VirtualFree(State.GameMemoryBlock, State.TotalSize, MEM_RELEASE );
                    VirtualFree(State.GameMemoryBlock, 0, MEM_RELEASE);
                    Error = GetLastError();
                    State = {};
                    GameMemory = {};
                    GameState = NULL;
                    GameMemory.PermanentStorageSize = Megabytes(256);
                    GameMemory.TransientStorageSize = Megabytes(256);

                    State.TotalSize = GameMemory.PermanentStorageSize + GameMemory.TransientStorageSize;

                    State.GameMemoryBlock = VirtualAlloc(BaseAddress, State.TotalSize,
                       MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
                    Error = GetLastError();
                    GameMemory.PermanentStorage = State.GameMemoryBlock;

                    GameMemory.TransientStorage = ((uint8 *)GameMemory.PermanentStorage +
                     GameMemory.PermanentStorageSize);
                }
            }
            //running = !game->IsExiting();
            GameState = (game_state *) GameMemory.PermanentStorage;
            if(GameCodeDLL.IsValid && GameMemory.PermanentStorage && GameMemory.TransientStorage)
            {
                //delta = static_cast<float>( microseconds ) / 1000000.f;
                //delta = frame_time_clock.getElapsedTime().asSeconds();
                delta = 0.16f;
                //game->Run2(delta, &GameMemory);
                if(!GameCodeDLL.RunGame(delta, &GameMemory))
                {

                    GameState->RenderWindow.close();
                     GameCodeDLL.DestroyGame(&GameMemory);
		     Win32DEBUGDelay(0.1f, "Exiting Game");
		    VirtualFree(State.GameMemoryBlock, State.TotalSize, MEM_RELEASE );
		    
                    Win32DEBUGDelay(0.25f, "Closing Window");
                    Win32UnloadGameCode(&GameCodeDLL);
                    Win32DEBUGDelay(0.25f, "Unloading Game Code");
                    return(DeleteFile(TempDLLName));
                }
            } 
            else
            {
                running = false;
            }

            auto frame_time = frame_time_clock.getElapsedTime().asMicroseconds();
            frame_time_clock.restart();

            frame_times[ frame_times_index ] = frame_time;
            frame_times_index = ( frame_times_index + 1 ) % 5000;

            if( m_fps_clock.getElapsedTime().asMicroseconds() >= 1000000 ) {
                m_fps_clock.restart();

                sf::Int64 total_time = 0;

                for( std::size_t index = 0; index < 5000; ++index ) {
                    total_time += frame_times[index];
                }

                std::stringstream sstr;
                sstr << "SFGUI test -- FPS: " << m_fps_counter << " -- Frame Time (seconds): min: "
                << static_cast<float>(*std::min_element( frame_times, frame_times + 5000 ) / 1000000.f) << " max: "
                << static_cast<float>(*std::max_element( frame_times, frame_times + 5000 ) / 1000000.f) << " avg: "
                << static_cast<float>((( total_time ) / 5000.f) / 1000000.f);
                if(running)
                {
		  //game->SetTitle(sstr.str());
                }
                //renderWindow.setTitle( sstr.str() );
                GameState->DEBUGString = sstr.str();
                

                m_fps_counter = 0;
            }
            ++m_fps_counter;
        }
    }
    GameCodeDLL.DestroyGame(&GameMemory);
    Win32DEBUGDelay(0.1f, "Exiting Game");
    Win32UnloadGameCode(&GameCodeDLL);
    Win32DEBUGDelay(1.5f, "Unloading Game Code");
    return(DeleteFile(TempDLLName));
    //return 0;
}
Exemplo n.º 21
0
int
main(void) {
    uint64 PerfCountFrequency = SDL_GetPerformanceFrequency();
    SDL_Event Event;
    SDL_Window *Window;
    SDL_Renderer *Renderer;

    if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC) != 0) {
        fprintf(stderr, "Could not initialize SDL: %s\n", SDL_GetError());
        return -1;
    }

    atexit(SDL_Quit);

    int WindowWidth = 1300;
    int WindowHeight = 870;
    int BytesPerPixel = 4;

    Window = SDL_CreateWindow("Echelon",
                              0, 0,
                              WindowWidth, WindowHeight,
                              SDL_WINDOW_RESIZABLE);
    
    if(Window) {
        Renderer = SDL_CreateRenderer(Window, -1, 0);

        if(Renderer) {
            GlobalRunning = true;
            window_dimensions Dimensions = SDLGetWindowDimensions(Window);
            SDLCreateNewTexture(&GlobalBuffer,
                                Renderer,
                                Dimensions.Width, Dimensions.Height,
                                BytesPerPixel);

            uint64 LastCounter = SDL_GetPerformanceCounter();
            uint64 LastCycleCount = _rdtsc();

            real64 DebugTimer = 0;
            real64 FPSTimer = 0;
            real64 UpdateTimer = 0;

            uint32 FPS = 0;
            uint32 UPS = 0;
            
            keyboard_input KeyboardInput = {};
            gamepad_input GamePadInput = {};

            game_code Game = LoadGameCode();

            game_memory GameMemory = {};
            GameMemory.IsInitialized = false;
            GameMemory.PlayRumble = SDLPlayRumble;
            GameMemory.WindowDimensions = SDLGetWindowDimensions(Window);
            GameMemory.PlatformDrawRenderQueue = DrawRenderQueueStub;
            GameMemory.PermanentStorageSize = Megabytes(100);
            GameMemory.PermanentStorage = mmap(0,
                                               GameMemory.PermanentStorageSize,
                                               PROT_READ | PROT_WRITE,
                                               MAP_PRIVATE | MAP_ANONYMOUS,
                                               -1, 0);
            
            GameMemory.TransientStorageSize = Gigabytes(2);
            GameMemory.TransientStorage = mmap(0,
                                               GameMemory.TransientStorageSize,
                                               PROT_READ | PROT_WRITE,
                                               MAP_PRIVATE | MAP_ANONYMOUS,
                                               -1, 0);

            Game.GameInit(&GameMemory);
            
            while(GlobalRunning) {
                // NOTE(Redab): This needs to while loop because we need
                // to handle events as long as they are available.
                while(SDL_PollEvent(&Event)) {
                    SDLHandleEvent(&Event, &Dimensions);
                    SDLHandleUserInput(&Event, &Game, &GameMemory, &KeyboardInput, &GamePadInput);
                }

                uint64 EndCycleCount = _rdtsc();
                uint64 EndCounter = SDL_GetPerformanceCounter();
                uint64 CounterElapsed = EndCounter - LastCounter;
                uint64 CyclesElapsed = EndCycleCount - LastCycleCount;

                // NOTE(Redab): CounterElapsed Contains the number of
                // clock cycles since last check. So we need to divide
                // this by the number of cycles per second which we
                // have in PerCountFrequency. Multiplied by 1000 to
                // get milliseconds.

                real64 SecondsPerFrame = ((real64)CounterElapsed / (real64)PerfCountFrequency);
                real64 MSPerFrame = SecondsPerFrame * 1000.0f;
                
                real64 KCPF = ((real64)CyclesElapsed / (1000.0f));

                FPSTimer += MSPerFrame;
                UpdateTimer += MSPerFrame;
                DebugTimer += MSPerFrame;

                if(UpdateTimer >= (1000.0f / 60.0f)) {
                    GameMemory.WindowDimensions = Dimensions;                        
                    Game.GameUpdate(&GameMemory, &KeyboardInput, &GamePadInput, UpdateTimer / 1000.0f);

                    UPS++;
                    UpdateTimer = 0;
                }

                if(FPSTimer >= (1000.0f / 60.0f)) {
                    SDLGameRender(&GlobalBuffer, &Game, &GameMemory);
                    SDLBlitFrameToWindow(&GlobalBuffer, Renderer);
                    
                    FPS++;
                    FPSTimer = 0;
                }
                
                if(DebugTimer >= 1000.0f) {
                    printf("%.05fms/f, FPS: %d, UPS: %d, %.02fKc/f, Timer: %.02f\n",
                           MSPerFrame, FPS, UPS, KCPF, DebugTimer);

                    FPS = 0;
                    UPS = 0;
                    DebugTimer = 0;
                }

                LastCycleCount = EndCycleCount;
                LastCounter = EndCounter;
            }
        } else {
            printf("Failed to create SDL_Renderer: %s\n", SDL_GetError());
        }
    } else {
        printf("Failed to create SDL_Window: %s\n", SDL_GetError());
    }

    SDL_CloseAudio();
    SDL_Quit();
    return 0;
}
Exemplo n.º 22
0
int main()
{
    SDL_Init(SDL_INIT_VIDEO);
    
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);

    SDL_Window * window = SDL_CreateWindow("gamedev", SDL_WINDOWPOS_UNDEFINED,
            SDL_WINDOWPOS_UNDEFINED, 1024, 768,
            SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);

    if(window) {
        SDL_GLContext gl_context = SDL_GL_CreateContext(window);

        // Initialize GLEW so we can get 3.30 stuff
        // I copied this from my quaternion demo
        // TODO: Can I do this without glew?

        // This experimental flag seems to be necessary for GLEW to load entry points
        // for certain core profile functions, like glGenVertexArrays. Really 
        // looking forward to getting rid of GLEW
        glewExperimental = GL_TRUE;
        GLenum err = glewInit();
        if (err != GLEW_OK)
        {
            fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
            exit(1); // or handle the error in a nicer way
        }

        if (!GLEW_VERSION_3_3)  // 
        {
            printf("Missing OpenGL version 3.3\n");
            exit(1); // or handle the error in a nicer way
        }

        printf("GLSL version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));

        game_memory Memory = {};
        Memory.PermanentStoreSize = Megabytes(256);
        Memory.TransientStoreSize = Gigabytes(1);
        Memory.TotalSize = Memory.PermanentStoreSize + Memory.TransientStoreSize;
        void * AllocatedMemory = mmap(0, Memory.TotalSize, PROT_READ | PROT_WRITE,
                MAP_ANON | MAP_PRIVATE, 0, 0);

        if(AllocatedMemory != MAP_FAILED) {
            //TODO: zero out the memory?

            Memory.PermanentStore = (uint8*)AllocatedMemory;
            Memory.TransientStore = Memory.PermanentStore + Memory.PermanentStoreSize;

            Memory.PermanentArena.Base = Memory.PermanentStore;
            Memory.PermanentArena.Size = Memory.PermanentStoreSize;
            Memory.PermanentArena.Offset = 0;

            Memory.TransientArena.Base = Memory.TransientStore;
            Memory.TransientArena.Size = Memory.TransientStoreSize;
            Memory.TransientArena.Offset = 0;

            game_state * GameState = PushStruct(&Memory.PermanentArena, game_state);

            bool Quit = false;
            while(!Quit) {

                // Handle keyboard events
                SDL_Event Event;
                while(SDL_PollEvent(&Event)) {
                    // TODO: probably don't want to take all the events here
                    switch(Event.type) {
                        case SDL_KEYUP:
                        case SDL_KEYDOWN:
                            SDL_KeyboardEvent KB_Event = Event.key;
                            SDL_Keysym Keysym = KB_Event.keysym;
                            switch(Keysym.sym) {
                                case SDLK_q:
                                    Quit = true;
                                    break;
                            }
                            break;
                    }
                }

                // Update/draw
                UpdateAndRender(&Memory, GameState);
                SDL_GL_SwapWindow(window);
            }
        }

        SDL_GL_DeleteContext(gl_context);
    } else {
        printf("Could not initialize SDL window.");
        return 1;
    }
    return 0;
}
Exemplo n.º 23
0
int main(int argc, char *argv[]) {
    sdl_state SDLState = {};

    platform_work_queue HighPriorityQueue = {};
    SDLMakeQueue(&HighPriorityQueue, 6);

    platform_work_queue LowPriorityQueue = {};
    SDLMakeQueue(&LowPriorityQueue, 2);


    GlobalPerfCountFrequency = SDL_GetPerformanceFrequency();

    SDLGetEXEFileName(&SDLState);

    char SourceGameCodeDLLFullpath[SDL_STATE_FILE_NAME_COUNT];
    SDLBuildEXEPathFileName(&SDLState, "handmade.dylib",
                            sizeof(SourceGameCodeDLLFullpath), SourceGameCodeDLLFullpath);

    char TempGameCodeDLLFullpath[SDL_STATE_FILE_NAME_COUNT];
    SDLBuildEXEPathFileName(&SDLState, "handmade_temp.dylib",
                            sizeof(TempGameCodeDLLFullpath), TempGameCodeDLLFullpath);

    char GameCodeLockFullpath[SDL_STATE_FILE_NAME_COUNT];
    SDLBuildEXEPathFileName(&SDLState, "lock.tmp",
                            sizeof(GameCodeLockFullpath), GameCodeLockFullpath);

    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0) {
        printf("Failed to initialize SDL: %s\n", SDL_GetError());
        return -1;
    }

    SDL_Window *Window = SDL_CreateWindow("Handmade Hero",
                                          SDL_WINDOWPOS_CENTERED,
                                          SDL_WINDOWPOS_CENTERED,
                                          960, 540,
                                          SDL_WINDOW_OPENGL);
    if (!Window) {
        printf("Failed to create window: %s\n", SDL_GetError());
        return -1;
    }

    SDLResizeDIBSection(Window, &GlobalBackBuffer, 960, 540);

    // TODO: Set GameUpdateHz by monitor refresh HZ
    real32 GameUpdateHz = 60.0f;
    real32 TargetSecondsPerFrame = 1.0f / GameUpdateHz;

    sdl_sound_output SoundOutput = {};
    SoundOutput.SamplesPerSecond = 48000;
    SoundOutput.BytesPerSample = sizeof(int16) * 2;
    SoundOutput.BufferSize = SoundOutput.SamplesPerSecond * SoundOutput.BytesPerSample;

    SDL_AudioDeviceID Audio = SDLInitSound(SoundOutput.SamplesPerSecond);

    u32 MaxPossibleOverrun = 2 * 4 * sizeof(u16);
    int16 *Samples = (int16 *)mmap(0, (size_t)(SoundOutput.BufferSize + MaxPossibleOverrun),
                                   PROT_READ | PROT_WRITE,
                                   MAP_PRIVATE | MAP_ANON, -1, 0);

    GlobalRunning = true;

#if HANDMADE_INTERNAL
    void *BaseAddress = (void *)Terabytes(2);
#else
    void *BaseAddress = 0;
#endif

    game_memory GameMemory = {};
    GameMemory.PermanentStorageSize = Megabytes(64);
    GameMemory.TransientStorageSize = Gigabytes(256);
    GameMemory.HighPriorityQueue = &HighPriorityQueue;
    GameMemory.LowPriorityQueue = &LowPriorityQueue;

    GameMemory.PlatformAPI.AddEntry = SDLAddEntry;
    GameMemory.PlatformAPI.CompleteAllWork = SDLCompleteAllWork;

    GameMemory.PlatformAPI.GetAllFilesOfTypeBegin = SDLGetAllFilesOfTypeBegin;
    GameMemory.PlatformAPI.GetAllFilesOfTypeEnd = SDLGetAllFilesOfTypeEnd;
    GameMemory.PlatformAPI.OpenNextFile = SDLOpenNextFile;
    GameMemory.PlatformAPI.ReadDataFromFile = SDLReadDataFromFile;
    GameMemory.PlatformAPI.FileError = SDLFileError;

    GameMemory.PlatformAPI.AllocateMemory = SDLAllocateMemory;
    GameMemory.PlatformAPI.DeallocateMemory = SDLDeallocateMemory;

    GameMemory.PlatformAPI.DEBUGFreeFileMemory = DEBUGPlatformFreeFileMemory;
    GameMemory.PlatformAPI.DEBUGReadEntireFile = DEBUGPlatformReadEntireFile;
    GameMemory.PlatformAPI.DEBUGWriteEntireFile = DEBUGPlatformWriteEntireFile;

    SDLState.TotalSize = GameMemory.PermanentStorageSize + GameMemory.TransientStorageSize;

    SDLState.GameMemoryBlock = mmap(BaseAddress,
                                    (size_t) SDLState.TotalSize,
                                    PROT_READ | PROT_WRITE,
                                    MAP_PRIVATE | MAP_ANON, -1, 0);
    GameMemory.PermanentStorage = SDLState.GameMemoryBlock;
    GameMemory.TransientStorage = ((uint8 *) GameMemory.PermanentStorage + GameMemory.PermanentStorageSize);

    if (!(GameMemory.PermanentStorage && GameMemory.TransientStorage)) {
        printf("Failed to allocate game memory\n");
        return -1;
    }

    // TODO: Add game replay support here

    game_input Input[2] = {};
    game_input *NewInput = &Input[0];
    game_input *OldInput = &Input[1];

    uint64 LastCounter = SDL_GetPerformanceCounter();
    uint64 FlipWallClock = SDL_GetPerformanceCounter();

    sdl_game_code Game = SDLLoadGameCode(SourceGameCodeDLLFullpath,
                                         TempGameCodeDLLFullpath,
                                         GameCodeLockFullpath);

    uint64 LastCycleCount = _rdtsc();

    while (GlobalRunning) {
        NewInput->dtForFrame = TargetSecondsPerFrame;

        NewInput->ExecutableReloaded = false;
        time_t NewDLLWriteTime = SDLGetLastWriteTime(SourceGameCodeDLLFullpath);
        if (difftime(NewDLLWriteTime, Game.DLLLastWriteTime) > 0) {
            SDLCompleteAllWork(&HighPriorityQueue);
            SDLCompleteAllWork(&LowPriorityQueue);

            SDLUnloadGameCode(&Game);
            Game = SDLLoadGameCode(SourceGameCodeDLLFullpath,
                                   TempGameCodeDLLFullpath,
                                   GameCodeLockFullpath);
            NewInput->ExecutableReloaded = true;
        }

        game_controller_input *OldKeyboardController = GetController(OldInput, 0);
        game_controller_input *NewKeyboardController = GetController(NewInput, 0);
        *NewKeyboardController = {};
        NewKeyboardController->IsConnected = true;
        for (size_t ButtonIndex = 0; ButtonIndex < ArrayCount(NewKeyboardController->Buttons); ++ButtonIndex) {
            NewKeyboardController->Buttons[ButtonIndex].EndedDown = OldKeyboardController->Buttons[ButtonIndex].EndedDown;
        }

        SDLProcessPendingMessage(&SDLState, NewKeyboardController);

        if (!GlobalPause) {
            Uint32 MouseButtons = SDL_GetMouseState(&NewInput->MouseX, &NewInput->MouseY);
            NewInput->MouseZ = 0;
            SDLProcessKeyboardMessage(&NewInput->MouseButtons[0],
                                      SDL_BUTTON(SDL_BUTTON_LEFT));
            SDLProcessKeyboardMessage(&NewInput->MouseButtons[1],
                                      SDL_BUTTON(SDL_BUTTON_MIDDLE));
            SDLProcessKeyboardMessage(&NewInput->MouseButtons[2],
                                      SDL_BUTTON(SDL_BUTTON_RIGHT));
            SDLProcessKeyboardMessage(&NewInput->MouseButtons[3],
                                      SDL_BUTTON(SDL_BUTTON_X1));
            SDLProcessKeyboardMessage(&NewInput->MouseButtons[4],
                                      SDL_BUTTON(SDL_BUTTON_X2));

            // TODO: Handle Mouse button here

            // TODO: Game controller support here

            game_offscreen_buffer Buffer = {};
            Buffer.Memory = GlobalBackBuffer.Memory;
            Buffer.Width = GlobalBackBuffer.Width;
            Buffer.Height = GlobalBackBuffer.Height;
            Buffer.Pitch = GlobalBackBuffer.Pitch;

            if (Game.UpdateAndRender) {
                Game.UpdateAndRender(&GameMemory, NewInput, &Buffer);
                HandleDebugCycleCounters(&GameMemory);
            }

            // TODO: Game audio support here
            game_sound_output_buffer SoundBuffer = {};
            SoundBuffer.SamplesPerSecond = SoundOutput.SamplesPerSecond;
            SoundBuffer.SampleCount = Align8((u32)(SoundOutput.SamplesPerSecond * TargetSecondsPerFrame));
            SoundBuffer.Samples = Samples;
            if (Game.GetSoundSamples) {
                Game.GetSoundSamples(&GameMemory, &SoundBuffer);
                SDL_QueueAudio(Audio, SoundBuffer.Samples, SoundBuffer.SampleCount * SoundOutput.BytesPerSample);
            }

            SDLDisplayBufferInWindow(&GlobalBackBuffer);

            game_input *Temp = NewInput;
            NewInput = OldInput;
            OldInput = Temp;
        }
    }

    return 0;
}
Exemplo n.º 24
0
int main(int argc, char** argv){
	// Initialize compiler
	Compiler compiler;
	zeroMemory(&compiler, sizeof(compiler));
	compiler.pool =  AllocatorPool::createFromOS(Megabytes(24));
	compiler.poolTransient = compiler.pool->create(Megabytes(8));
	compiler.astFiles = Array<AST_File>::create(1024, compiler.pool);
	compiler.stack = Array<CompilerParameters*>::create(256, compiler.pool);
	compiler.componentsUsed = Array<AST_ComponentDefinition*>::create(256, compiler.pool);

	// Get all files in directory
	compiler.targetDirectory = String::create("C:\\wamp\\www\\nweb\\test\\wordpress\\wp-content\\themes\\twentysixteen\\fel\\");
	StringLinkedList files = Directory::getFilesRecursive(compiler.pool, compiler.targetDirectory);
	if (files.first == NULL)
	{
		compiler.targetDirectory = String::create("D:\\wamp\\www\\Nweb\\test\\wordpress\\wp-content\\themes\\twentysixteen\\fel\\");
		files = Directory::getFilesRecursive(compiler.pool, compiler.targetDirectory);
		if (files.first == NULL)
		{	
			compiler.targetDirectory = String::create("C:\\wamp\\www\\PersonalProjects\\fel\\test\\wordpress\\wp-content\\themes\\twentysixteen\\fel\\");
			files = Directory::getFilesRecursive(compiler.pool, compiler.targetDirectory);
			if (files.first == NULL)
			{	
				printf("Invalid directory supplied. Terminating program.\n");
				while(true) {}
				return -1;
			}
		}
	}

	if (compiler.targetDirectory.length == 0) 
	{
		printf("No directory supplied. Terminating program.\n");
		while(true) {}
		return -1;
	}

	// Setup default output directory
	if (compiler.outputDirectory.length == 0)
	{
		compiler.outputDirectory = compiler.targetDirectory.goUpDirectory();
	}
	assert(compiler.outputDirectory.length != 0);

	// Parse each file and add the AST to the compilers files
	for (StringLinkedListNode* node = files.first; node != NULL; node = node->next)
	{
		// Only parse files with the '.fel' extension
		if (node->string.fileExtension().cmp("fel"))
		{
			parse(&compiler, node->string);
		}
	}
	printf("Finished parsing.\n");

	// Run compile
	compile(&compiler);
	if (compiler.hasError)
	{
		printf("Fatal error compiling.\n");
	}
	else
	{
		print("Finished compiling successfully. Memory Used: %d, Transient Memory Used: %d (should be 0).\n", compiler.pool->used - compiler.poolTransient->size, compiler.poolTransient->used);
	}
	while(true) {}
	return 0;
}
Exemplo n.º 25
0
int main(int argc, char *args[])
{
#if _WIN32
	// NOTE(nathan): Set the windows schedular granularity to 1ms
	// so that our SDL_Delay() and be more granular

	// SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); 
	// NOTE(nathan): This seems to give a more consistant result than above
	timeBeginPeriod(1);
#if _DEBUG
	HWND console = GetConsoleWindow();
	if(console != 0)
	MoveWindow(console, -900, 100, 700, 800, TRUE);
#endif
#endif
	SDL_Init(SDL_INIT_EVERYTHING);

	// NOTE(nathan): This also initializes the window_with and window_height
	WindowData window_data = { };
	window_data.target_width = 1920;
	window_data.target_height = 1080;

	FixViewport(1280, 720, &window_data);

	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
	//SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
	//SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 4);

	SDL_Window *window = SDL_CreateWindow(
		"Banana",
		SDL_WINDOWPOS_CENTERED,
		SDL_WINDOWPOS_CENTERED,
		window_data.width, window_data.height,
		SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL);

	// ToggleFullScreen(window);
	SDL_ShowCursor(SDL_DISABLE);
	// OutputSystemInfo();
	SDL_GLContext glContext = SDL_GL_CreateContext(window);
	glewExperimental = GL_TRUE;
	if (glewInit() != GLEW_OK) Error("glewInit");

	// Goes stuttery if we turn on vsync
	SDL_GL_SetSwapInterval((int)window_data.vsync);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_CULL_FACE);
	glCullFace(GL_BACK);
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

	bool running = true;
	SDL_Event e;

	uint32 gameUpdateHz = 60;
	float32 targetSecondsPerFrame = 1.0f / (float32)gameUpdateHz;

	perfCountFreq = SDL_GetPerformanceFrequency();
	uint64 lastCounter = GetWallClock();

	GameMemory game_memory = { 0 };
	game_memory.size = Megabytes(64);
	game_memory.memory = SDL_malloc(game_memory.size);

	EditorMemory editor_memory = { 0 };
	editor_memory.size = Megabytes(64);
	editor_memory.memory = SDL_malloc(editor_memory.size);

	RenderContext render_context = {};
	render_context.diffuse = CreateShader("assets/shaders/diffuse.vert", "assets/shaders/diffuse.frag");
	InitializeContext(&render_context);

	VoxelRenderContext voxel_render_context = {};
	voxel_render_context.diffuse = CreateShader("assets/shaders/voxels.vert", "assets/shaders/voxels.frag");
	InitializeVoxelContext(&voxel_render_context);

	InputData input = { };
	input.window = window;

	UIContext ui_context = { 0 };
	ui_context.input = &input;
	ui_context.render_context = &render_context;

	Mode mode = MODE_GAME;

	bool game_paused = false;

	while (running)
	{
		while (SDL_PollEvent(&e))
		{
			if (e.type == SDL_QUIT)
				running = false;
			if (e.type == SDL_WINDOWEVENT)
			{
				if (e.window.event == SDL_WINDOWEVENT_RESIZED)
				{
					FixViewport((int)e.window.data1, (int)e.window.data2, &window_data);
				}
			}
			if (e.type == SDL_KEYDOWN)
			{
				SDL_Scancode key = e.key.keysym.scancode;
				input.keyboard_state[key] = true;
				if (key == SDL_SCANCODE_ESCAPE)
					running = false;
				if (key == SDL_SCANCODE_F12)
					window_data.vsync = !window_data.vsync;
				if (key == SDL_SCANCODE_F11)
					ToggleFullScreen(window, &window_data);
				if (key == SDL_SCANCODE_F10)
				{
					if (mode == MODE_GAME)
					{
						game_paused = true;
						mode = MODE_EDITOR;
					}
					else
					{
						mode = MODE_GAME;
						game_paused = false;
					}
				}
			}
			if (e.type == SDL_KEYUP)
			{
				SDL_Scancode key = e.key.keysym.scancode;
				input.keyboard_state[key] = false;
			}
			if (e.type == SDL_MOUSEMOTION)
			{
				input.mouse_pos.x = (((float)window_data.target_width / (float)window_data.vp_width) 
					* ((float)e.motion.x - window_data.vp_x));
				input.mouse_pos.y = (((float)window_data.target_height / (float)window_data.vp_height) 
					* ((float)e.motion.y - window_data.vp_y));
			}
			if (e.type == SDL_MOUSEBUTTONDOWN)
			{
				if (e.button.button == SDL_BUTTON_LEFT)
					input.mb_left = true;
				if (e.button.button == SDL_BUTTON_RIGHT)
					input.mb_right = true;
				if (e.button.button == SDL_BUTTON_MIDDLE)
					input.mb_middle = true;
			}
			if (e.type == SDL_MOUSEBUTTONUP)
			{
				if (e.button.button == SDL_BUTTON_LEFT)
					input.mb_left = false;
				if (e.button.button == SDL_BUTTON_RIGHT)
					input.mb_right = false;
				if (e.button.button == SDL_BUTTON_MIDDLE)
					input.mb_middle = false;
			}
		}

		float32 delta = 1.0f / (float32)gameUpdateHz;

		GameUpdateAndRender(&game_memory, &input, &render_context, &voxel_render_context, 
			&window_data, game_paused, delta);

		uint64 workCounter = GetWallClock();
		float32 workSecondsElapsed = GetSecondsElapsed(lastCounter, workCounter);
		// Dont include this in frametime
		if (mode == MODE_EDITOR)
			EditorUpdateAndRender(&editor_memory, &input, &render_context, &ui_context, delta);

		float32 secondsElapsedForFrame = workSecondsElapsed;
		if (secondsElapsedForFrame < targetSecondsPerFrame)
		{
			uint32 sleepMS = (uint32)((1000.0f * (targetSecondsPerFrame - secondsElapsedForFrame)) - 1);
			if (sleepMS > 0)
				SDL_Delay(sleepMS);
			while (secondsElapsedForFrame < targetSecondsPerFrame)
			{
				secondsElapsedForFrame = GetSecondsElapsed(lastCounter, GetWallClock());
			}
		}
		else
		{
			// Error("Missed Frame Rate");
		}

		uint64 endCounter = GetWallClock();
		float64 msPerFrame = 1000.0f * GetSecondsElapsed(lastCounter, endCounter);
		lastCounter = endCounter;

		// Debug Render
		BeginRenderer(&render_context);

		std::string s = "FRAMETIME " + std::to_string(msPerFrame) + " VSYNC " + std::to_string(window_data.vsync);
		RenderString(&render_context, 40.0f, 40.0f, s.c_str(), 0.0f);


		EndRenderer();

		SDL_GL_SwapWindow(window);
		input.prev_keyboard_state = input.keyboard_state;
		input.mb_left_prev = input.mb_left;
		input.mb_right_prev = input.mb_right;
		input.mb_middle_prev = input.mb_middle;
	}
	UnloadContext(&render_context);
	UnloadVoxelContext(&voxel_render_context);
	SDL_free(game_memory.memory);

	SDL_GL_DeleteContext(glContext);
	SDL_DestroyWindow(window);
	SDL_Quit();
	return(0);
}
Exemplo n.º 26
0
assets_s* AllocateAssets(memoryBlock_s* memoryBlock)
{
	assets_s* assets = PushStruct(memoryBlock, assets_s);
    assets->assetUseQueue = InitLinkedList(memoryBlock, Kilobytes(2));
    assets->dyMemoryBlock = InitDynamicMemoryBlock(memoryBlock, Megabytes(64), Kilobytes(10));
    assets->tagCount = 1;
    assets->assetCount = 1;

    platformFileGroup_s* fileGroup = Platform.getAllFilesOfTypeBegin("wa");
    assets->fileCount = fileGroup->fileCount;
    assets->files = PushArray(memoryBlock, assets->fileCount, assetFile_s);
    for(uint32_t index = 0; index < assets->fileCount; index++)
    {
        assetFile_s* file = assets->files + index;
        file->tagBase = assets->tagCount;
        file->handle = Platform.openNextFile(fileGroup);
        file->header = {};

        Platform.readDataFromFile(file->handle, 0, sizeof(file->header), &file->header);

        uint32_t assetTypeArraySize = file->header.assetTypesCount*sizeof(waAssetType_s);
        file->assetTypeArray = (waAssetType_s*) PushSize(memoryBlock, assetTypeArraySize);
        Platform.readDataFromFile(file->handle, file->header.assetTypes, assetTypeArraySize, 
            file->assetTypeArray);
        if(PlatformNoFileErrors(file->handle))
        {
            if(file->header.magicValue != MAGIC_VALUE)
            {
                Platform.fileError(file->handle, "wa file has an invalid magic value");
            }
            if(file->header.version > WALLACE_ASSET_VERSION)
            {
                Platform.fileError(file->handle, "wa file has a version which exceeds game version");
            } 

            if(PlatformNoFileErrors(file->handle))
            {
                // NOTE: The first asset and tag slot in every
                // .wa is a null (reserved) so we don't count it as
                // something we will need space for!
                assets->tagCount += (file->header.tagCount - 1);
                assets->assetCount += (file->header.assetCount - 1);
            }
        }
        else
        {
            InvalidCodePath;
        }
    }
    Platform.getAllFilesOfTypeEnd(fileGroup);
    assets->assets = PushArray(memoryBlock, assets->assetCount, assetFileData_s);
    assets->slots = PushArray(memoryBlock, assets->assetCount, assetData_s);
    assets->tags = PushArray(memoryBlock, assets->tagCount, waTag_s);

    assets->tags[0] = {};

    for(uint32_t fileIndex = 0; fileIndex < assets->fileCount; fileIndex++)
    {
        assetFile_s* file = assets->files + fileIndex;
        if(PlatformNoFileErrors(file->handle))
        {
            uint32_t tagArraySize = sizeof(waTag_s) * (file->header.tagCount - 1);
            Platform.readDataFromFile(file->handle, file->header.tags + sizeof(waTag_s), tagArraySize, 
                assets->tags + file->tagBase);
        }
    }

    // NOTE: Reserve one null asset at the beginning
    uint32_t assetCount = 0;
    assets->assets[assetCount] = {};
    assetCount++;
    for(uint32_t destTypeId = 0; destTypeId < assetType_last; destTypeId++)
    {
        waAssetType_s* destType = assets->assetTypes + destTypeId;
        destType->firstAssetIndex = assetCount;
        for(uint32_t fileIndex = 0; fileIndex < assets->fileCount; fileIndex++)
        {
            assetFile_s* file = assets->files + fileIndex;
            if(PlatformNoFileErrors(file->handle))
            {
                for(uint32_t sourceIndex = 0; sourceIndex < file->header.assetTypesCount; sourceIndex++)
                {
                    waAssetType_s* sourceType = file->assetTypeArray + sourceIndex;
                    if(sourceType->typeId == destTypeId)
                    {
                        uint32_t assetCountForType = sourceType->onePastLastAssetIndex - 
                            sourceType->firstAssetIndex;
                        temporaryMemory_s tempMem = BeginTemporaryMemory(memoryBlock);
                        waAssetFileData_s* waAssetArray = PushArray(memoryBlock, assetCountForType, waAssetFileData_s);
                        Platform.readDataFromFile(file->handle, file->header.assets +
                                                  sourceType->firstAssetIndex * sizeof(waAssetFileData_s),
                                                  assetCountForType * sizeof(waAssetFileData_s), waAssetArray);
                        for(uint32_t assetIndex = 0; assetIndex < assetCountForType; assetIndex++)
                        {
                            waAssetFileData_s* waAsset = waAssetArray + assetIndex;

                            // Assert(assetCount < assets->assetCount);
                            assetFileData_s* asset = assets->assets + assetCount++;
                            
                            asset->fileIndex = fileIndex;
                            asset->wa = *waAsset;
                            if(asset->wa.firstTagIndex == 0)
                            {
                                asset->wa.firstTagIndex = 0;
                                asset->wa.onePastLastTagIndex = 0;
                            }
                            else
                            {
                                asset->wa.firstTagIndex += (file->tagBase - 1);
                                asset->wa.onePastLastTagIndex += (file->tagBase - 1);
                            }
                        }

                        EndTemporaryMemory(tempMem);
                    }
                }
            }
        }
        destType->onePastLastAssetIndex = assetCount;
    }

    // Assert(assetCount == assets->assetCount);
	return assets;
}
Exemplo n.º 27
0
Win32_App::Win32_App()
{
	SourceDLLName = "Game.dll";
	//GameCode = Win32_LoadGameCode(SourceDLLName);

#ifdef _DEBUG
	// Дебажная консоль
	FileLogger flogger("debug.log");
	log_event("SYSTEM", "Logger initialized");
#endif

	try
	{
		// We support all display targets, in order listed here
#ifdef WIN32
		D3DTarget::enable();
#endif
		OpenGLTarget::enable();
	}
	catch (Exception exception)
	{
		// Create a console window for text-output if not available
		ConsoleWindow console("Console", 80, 160);
		Console::write_line("Exception caught: " + exception.get_message_and_stack_trace());
		console.display_close_message();

		quit = true;
	}

	// TODO: сохранять настройки графики
	fullscreen = 0;
	// TODO: Масштабировать окно
	InitScreenSize = Sizef(1024.0f, 768.0f);
	ScreenSize = InitScreenSize;
	DisplayWindowDescription window_description;
	window_description.set_title("Robot Game");
	window_description.set_size(ScreenSize, true);
	window_description.set_allow_resize(true);
	//window_description.set_type(WindowType::tool);
	window = DisplayWindow(window_description);

	canvas = Canvas(window);

	// Подключим коллбэки на слоты пользовательского ввода
	keyboard = window.get_ic().get_keyboard();
	sc.connect(window.sig_window_close(), bind_member(this, &Win32_App::Win32_OnWindowClose));
	sc.connect(window.get_ic().get_keyboard().sig_key_up(), bind_member(this, &Win32_App::Win32_OnKeyUp));
	sc.connect(window.get_ic().get_keyboard().sig_key_down(), bind_member(this, &Win32_App::Win32_OnKeyDown));
	sc.connect(window.get_ic().get_mouse().sig_key_down(), bind_member(this, &Win32_App::Win32_OnMouseDown));

	// Sound
	SoundOutput sound_output(48000);
/*
	SoundBuffer sbuffer("cheer1.ogg");
	sbuffer.play();
*/


	// Game memory
	LPVOID BaseAddress = 0;
	GameMemory.PermanentStorageSize = Megabytes(256);
	GameMemory.TransientStorageSize = Megabytes(256);
	size_t TotalStorageSize = (size_t)(GameMemory.PermanentStorageSize + GameMemory.TransientStorageSize);
	GameMemory.PermanentStorage = VirtualAlloc(BaseAddress, TotalStorageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
	GameMemory.TransientStorage = ((uint8*)GameMemory.PermanentStorage + GameMemory.PermanentStorageSize);

	// Game state
	GameState = (game_state*)GameMemory.PermanentStorage;
	*GameState = {};
	GameState->ScreenSize = ScreenSize;


	// Resources
	//OpenGLTarget::set_current();
	GameState->game_resources = clan::XMLResourceManager::create(clan::XMLResourceDocument("sprites.xml"));

	GameState->LoadGameSpriteFromImage = &LoadGameSpriteFromImage;
	GameState->LoadGameSpriteFromResource = &LoadGameSpriteFromResource;
	GameState->AddGameSpriteFrameFromImage = &AddGameSpriteFrameFromImage;

	// Main display buffers
	//GameState->MainDisplayBuffer = PixelBuffer(1024, 768, TextureFormat::tf_rgba8, GameMemory.TransientStorage);


	// Win32 Timings
	CanSleepSafe = (timeBeginPeriod(1) == TIMERR_NOERROR);
	QueryPerformanceFrequency(&PerfCounterFrequencyQ);
	PerfCounterFrequency = PerfCounterFrequencyQ.QuadPart;

	QueryPerformanceCounter(&LastCounter);

	LastCycleCount = __rdtsc();

	game_time.reset();

	//console.display_close_message();
	//timeEndPeriod(1);
}
Exemplo n.º 28
0
int CALLBACK WinMain(HINSTANCE Instance, HINSTANCE PrevInstance, LPSTR CommandLine, int ShowCode) {
	win32_state Win32State = {};

	LARGE_INTEGER PerfCounterFrequencyResult;
	QueryPerformanceFrequency(&PerfCounterFrequencyResult);
	GlobalPerfCounterFrequency = PerfCounterFrequencyResult.QuadPart;

	Win32GetEXEFileName(&Win32State);
	char SourceGameCodeDLLFullPath[WIN32_STATE_FILE_NAME_COUNT];
	Win32BuildEXEPathFileName(&Win32State, "handmade.dll", sizeof(SourceGameCodeDLLFullPath), SourceGameCodeDLLFullPath);
	char TempGameCodeDLLFullPath[WIN32_STATE_FILE_NAME_COUNT];
	Win32BuildEXEPathFileName(&Win32State, "handmade_temp.dll", sizeof(TempGameCodeDLLFullPath), TempGameCodeDLLFullPath);
	char GameCodeLockFullPath[WIN32_STATE_FILE_NAME_COUNT];
	Win32BuildEXEPathFileName(&Win32State, "lock.tmp", sizeof(GameCodeLockFullPath), GameCodeLockFullPath);

	// NOTE: setting windows scheduler granularity for our sleep() call
	UINT DesiredSchedulerMS = 1;
	bool32 SleepIsGranular = (timeBeginPeriod(DesiredSchedulerMS) == TIMERR_NOERROR);

	Win32LoadXInput();
	Win32ResizeDIBSection(&GlobalBackbuffer, 960, 540);

#if HANDMADE_INTERNAL
	DEBUGGlobalShowCursor = true;
#endif

	WNDCLASSEXA WindowClass = {};
	WindowClass.style = CS_VREDRAW | CS_HREDRAW;
	WindowClass.cbSize = sizeof(WNDCLASSEXA);
	WindowClass.lpfnWndProc = Win32MainWindowCallback;
	WindowClass.hInstance = Instance;
	WindowClass.hCursor = LoadCursor(0, IDC_ARROW);
	// WindowClass.hIcon;
	WindowClass.lpszClassName = "HandmadeHeroWindowClass";

	if (RegisterClassExA(&WindowClass)) {
		// WS_EX_TOPMOST|WS_EX_LAYERED
		HWND Window = CreateWindowExA(0, WindowClass.lpszClassName, "Handmade Hero", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 996, 600, 0, 0, Instance, 0);

		if (Window) {
			// TODO: reliably query this from windows
			int MonitorRefreshHz = 60;
			HDC RefreshDC = GetDC(Window);
			int Win32RefreshRate = GetDeviceCaps(RefreshDC, VREFRESH);
			ReleaseDC(Window, RefreshDC);
			if (Win32RefreshRate > 1) {
				MonitorRefreshHz = Win32RefreshRate;

				if (MonitorRefreshHz == 59) {
					MonitorRefreshHz = 60;
				}
			}
			real32 GameUpdateHz = MonitorRefreshHz / 2.0f;
			real32 TargetSecondsPerFrame = 1.0f / GameUpdateHz;

			// NOTE: sound test
			win32_sound_output SoundOutput = {};
			SoundOutput.SamplesPerSecond = 48000;
			SoundOutput.BytesPerSample = sizeof(int16) * 2;
			SoundOutput.SecondaryBufferSize = SoundOutput.SamplesPerSecond * SoundOutput.BytesPerSample;
			// TODO: compute this variance and see what the lowest reasonable value is
			SoundOutput.SafetyBytes = (int)((real32)SoundOutput.SamplesPerSecond * (real32)SoundOutput.BytesPerSample / GameUpdateHz / 3.0f);

			Win32InitDSound(Window, SoundOutput.SamplesPerSecond, SoundOutput.SecondaryBufferSize);
			Win32ClearSoundBuffer(&SoundOutput);
			GlobalSecondaryBuffer->Play(0, 0, DSBPLAY_LOOPING);

			GlobalRunning = true;

			// TODO: pool with bitmap virtualalloc
			int16 *Samples = (int16 *)VirtualAlloc(0, SoundOutput.SecondaryBufferSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

#if HANDMADE_INTERNAL
			LPVOID BaseAddress = (LPVOID)Terabytes(2);
#else
			LPVOID BaseAddress = 0;
#endif

			game_memory GameMemory = {};
			GameMemory.PermanentStorageSize = Megabytes(64);
			GameMemory.TransientStorageSize = Gigabytes(1);
			GameMemory.DEBUGPlatformFreeFileMemory = DEBUGPlatformFreeFileMemory;
			GameMemory.DEBUGPlatformReadEntireFile = DEBUGPlatformReadEntireFile;
			GameMemory.DEBUGPlatformWriteEntireFile = DEBUGPlatformWriteEntireFile;

			// TODO: handle various memory footprints using system metrics
			// TODO: use MEM_LARGE_PAGES
			Win32State.TotalSize = GameMemory.PermanentStorageSize + GameMemory.TransientStorageSize;
			Win32State.GameMemoryBlock = VirtualAlloc(BaseAddress, (size_t)Win32State.TotalSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
			GameMemory.PermanentStorage = Win32State.GameMemoryBlock;
			GameMemory.TransientStorage = (uint8 *)GameMemory.PermanentStorage + GameMemory.PermanentStorageSize;

			for (int ReplayIndex = 1; ReplayIndex < ArrayCount(Win32State.ReplayBuffers); ++ReplayIndex) {
				// TODO: recording system still takes too long on record start
				win32_replay_buffer *ReplayBuffer = &Win32State.ReplayBuffers[ReplayIndex];

				Win32GetInputFileLocation(&Win32State, false, ReplayIndex, sizeof(ReplayBuffer->FileName), ReplayBuffer->FileName);
				ReplayBuffer->FileHandle = CreateFileA(ReplayBuffer->FileName, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);

				LARGE_INTEGER MaxSize;
				MaxSize.QuadPart = Win32State.TotalSize;
				ReplayBuffer->MemoryMap = CreateFileMapping(ReplayBuffer->FileHandle, 0, PAGE_READWRITE, MaxSize.HighPart, MaxSize.LowPart, 0);
				ReplayBuffer->MemoryBlock = MapViewOfFile(ReplayBuffer->MemoryMap, FILE_MAP_ALL_ACCESS, 0, 0, (size_t)Win32State.TotalSize);

				if (!ReplayBuffer->MemoryBlock) {
					// TODO: diagnostic
				}
			}

			if (Samples && GameMemory.PermanentStorage && GameMemory.TransientStorage) {
				game_input Input[2] = {};
				game_input *NewInput = &Input[0];
				game_input *OldInput = &Input[1];

				LARGE_INTEGER LastCounter = Win32GetWallClock();
				LARGE_INTEGER FlipWallClock = Win32GetWallClock();

				int DebugTimeMarkerIndex = 0;
				win32_debug_time_marker DebugTimeMarkers[30] = { 0 };

				// TODO: handle startup specially
				bool32 SoundIsValid = false;
				DWORD AudioLatencyBytes = 0;
				real32 AudioLatencySeconds = 0;

				win32_game_code Game = Win32LoadGameCode(SourceGameCodeDLLFullPath, TempGameCodeDLLFullPath, GameCodeLockFullPath);

				uint64 LastCycleCount = __rdtsc();

				while (GlobalRunning) {
					NewInput->FrameTimeDelta = TargetSecondsPerFrame;

					FILETIME NewDLLWriteTime = Win32GetLastWriteTime(SourceGameCodeDLLFullPath);
					if (CompareFileTime(&NewDLLWriteTime, &Game.DLLLastWriteTime) != 0) {
						Win32UnloadGameCode(&Game);
						Game = Win32LoadGameCode(SourceGameCodeDLLFullPath, TempGameCodeDLLFullPath, GameCodeLockFullPath);
					}

					// TODO: zeroing macro
					// TODO: we cant zero everything as the up/down state will be wrong
					game_controller_input *OldKeyboardController = GetController(OldInput, 0);
					game_controller_input *NewKeyboardController = GetController(NewInput, 0);
					*NewKeyboardController = {};
					NewKeyboardController->IsConnected = true;

					for (int ButtonIndex = 0; ButtonIndex < ArrayCount(NewKeyboardController->Buttons); ++ButtonIndex) {
						NewKeyboardController->Buttons[ButtonIndex].EndedDown = OldKeyboardController->Buttons[ButtonIndex].EndedDown;
					}

					Win32ProcessPendingMessages(&Win32State, NewKeyboardController);

					if (!GlobalPause) {
						POINT MousePoint;
						GetCursorPos(&MousePoint);
						ScreenToClient(Window, &MousePoint);
						NewInput->MouseX = MousePoint.x;
						NewInput->MouseY = MousePoint.y;
						NewInput->MouseZ = 0; // TODO: support mousewheel?
						Win32ProcessKeyboardMessage(&NewInput->MouseButtons[0], GetKeyState(VK_LBUTTON) & (1 << 15));
						Win32ProcessKeyboardMessage(&NewInput->MouseButtons[1], GetKeyState(VK_MBUTTON) & (1 << 15));
						Win32ProcessKeyboardMessage(&NewInput->MouseButtons[2], GetKeyState(VK_RBUTTON) & (1 << 15));
						Win32ProcessKeyboardMessage(&NewInput->MouseButtons[3], GetKeyState(VK_XBUTTON1) & (1 << 15));
						Win32ProcessKeyboardMessage(&NewInput->MouseButtons[4], GetKeyState(VK_XBUTTON2) & (1 << 15));

						// TODO: should we poll this more frequently
						// TODO: dont poll disconnected controllers to prevent xinput frame rate impact
						DWORD MaxControllerCount = XUSER_MAX_COUNT;
						if (MaxControllerCount > (ArrayCount(NewInput->Controllers) - 1)) {
							MaxControllerCount = (ArrayCount(NewInput->Controllers) - 1);
						}

						for (DWORD ControllerIndex = 0; ControllerIndex < MaxControllerCount; ++ControllerIndex) {
							DWORD OurControllerIndex = ControllerIndex + 1;
							game_controller_input *OldController = GetController(OldInput, OurControllerIndex);
							game_controller_input *NewController = GetController(NewInput, OurControllerIndex);

							XINPUT_STATE ControllerState;

							if (XInputGetState(ControllerIndex, &ControllerState) == ERROR_SUCCESS) {
								NewController->IsConnected = true;
								NewController->IsAnalog = OldController->IsAnalog;
								// TODO: See if ControllerState.dwPacketNumber increments too rapidly
								XINPUT_GAMEPAD *Pad = &ControllerState.Gamepad;

								// TODO: currently handling a square deadzone, check if it is circular
								NewController->StickAverageX = Win32ProcessXInputStickValue(Pad->sThumbLX, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);
								NewController->StickAverageY = Win32ProcessXInputStickValue(Pad->sThumbLY, XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE);

								if ((NewController->StickAverageX != 0.0f) || (NewController->StickAverageY != 0.0f)) {
									NewController->IsAnalog = true;
								}

								if (Pad->wButtons & XINPUT_GAMEPAD_DPAD_UP) {
									NewController->StickAverageY = 1.0f;
									NewController->IsAnalog = false;
								}

								if (Pad->wButtons & XINPUT_GAMEPAD_DPAD_DOWN) {
									NewController->StickAverageY = -1.0f;
									NewController->IsAnalog = false;
								}

								if (Pad->wButtons & XINPUT_GAMEPAD_DPAD_LEFT) {
									NewController->StickAverageX = -1.0f;
									NewController->IsAnalog = false;
								}

								if (Pad->wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) {
									NewController->StickAverageX = 1.0f;
									NewController->IsAnalog = false;
								}

								real32 Threshold = 0.5f;
								Win32ProcessXInputDigitalButton((NewController->StickAverageX < -Threshold) ? 1 : 0, &OldController->MoveLeft, 1, &NewController->MoveLeft);
								Win32ProcessXInputDigitalButton((NewController->StickAverageX > Threshold) ? 1 : 0, &OldController->MoveRight, 1, &NewController->MoveRight);
								Win32ProcessXInputDigitalButton((NewController->StickAverageY < -Threshold) ? 1 : 0, &OldController->MoveDown, 1, &NewController->MoveDown);
								Win32ProcessXInputDigitalButton((NewController->StickAverageY > Threshold) ? 1 : 0, &OldController->MoveUp, 1, &NewController->MoveUp);

								Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->ActionDown, XINPUT_GAMEPAD_A, &NewController->ActionDown);
								Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->ActionRight, XINPUT_GAMEPAD_B, &NewController->ActionRight);
								Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->ActionLeft, XINPUT_GAMEPAD_X, &NewController->ActionLeft);
								Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->ActionUp, XINPUT_GAMEPAD_Y, &NewController->ActionUp);
								Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->LeftShoulder, XINPUT_GAMEPAD_LEFT_SHOULDER, &NewController->LeftShoulder);
								Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->RightShoulder, XINPUT_GAMEPAD_RIGHT_SHOULDER, &NewController->RightShoulder);

								Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->Start, XINPUT_GAMEPAD_START, &NewController->Start);
								Win32ProcessXInputDigitalButton(Pad->wButtons, &OldController->Back, XINPUT_GAMEPAD_BACK, &NewController->Back);
							}
							else {
								// NOTE: the controller is not available
								NewController->IsConnected = false;
							}
						}

						thread_context Thread = {};

						game_offscreen_buffer Buffer = {};
						Buffer.Memory = GlobalBackbuffer.Memory;
						Buffer.Width = GlobalBackbuffer.Width;
						Buffer.Height = GlobalBackbuffer.Height;
						Buffer.Pitch = GlobalBackbuffer.Pitch;
						Buffer.BytesPerPixel = GlobalBackbuffer.BytesPerPixel;

						if (Win32State.InputRecordingIndex) {
							Win32RecordInput(&Win32State, NewInput);
						}

						if (Win32State.InputPlaybackIndex) {
							Win32PlaybackInput(&Win32State, NewInput);
						}

						if (Game.UpdateAndRender) {
							Game.UpdateAndRender(&Thread, &GameMemory, NewInput, &Buffer);
						}

						LARGE_INTEGER AudioWallClock = Win32GetWallClock();
						real32 FromBeginToAudioSeconds = Win32GetSecondsElapsed(FlipWallClock, AudioWallClock);

						DWORD PlayCursor;
						DWORD WriteCursor;

						if (GlobalSecondaryBuffer->GetCurrentPosition(&PlayCursor, &WriteCursor) == DS_OK) {
							/* NOTE: Sound output explanation

							We define a safety value that is the number of samples we think our game update loop can vary by.
							When we wake up to write audio we look at the play cursor position and forecast where we think it will be on the next frame boundary.
							If the write cursor is before that by at least our safety value, the target fill position is the frame boundary plus one frame. This gives us perfect audio sync if the audio latency is low enough.
							If the write cursor is after that safety value then we assume we can't sync the audio so we write one frames worth of audio plus the safety values worth of samples.

							*/

							if (!SoundIsValid) {
								SoundOutput.RunningSampleIndex = WriteCursor / SoundOutput.BytesPerSample;
								SoundIsValid = true;
							}

							DWORD ByteToLock = (SoundOutput.RunningSampleIndex * SoundOutput.BytesPerSample) % SoundOutput.SecondaryBufferSize;
							DWORD ExpectedSoundBytesPerFrame = (int)((real32)(SoundOutput.SamplesPerSecond * SoundOutput.BytesPerSample) / GameUpdateHz);
							real32 SecondsLeftUntilFlip = TargetSecondsPerFrame - FromBeginToAudioSeconds;
							DWORD ExpectedBytesUntilFlip = (DWORD)((SecondsLeftUntilFlip / TargetSecondsPerFrame) * (real32)ExpectedSoundBytesPerFrame);
							DWORD ExpectedFrameBoundaryByte = PlayCursor + ExpectedBytesUntilFlip;
							DWORD SafeWriteCursor = WriteCursor;

							if (SafeWriteCursor < PlayCursor) {
								SafeWriteCursor += SoundOutput.SecondaryBufferSize;
							}

							Assert(SafeWriteCursor >= PlayCursor);
							SafeWriteCursor += SoundOutput.SafetyBytes;
							bool32 AudioCardIsLowLatency = (SafeWriteCursor < ExpectedFrameBoundaryByte);
							DWORD TargetCursor = 0;

							if (AudioCardIsLowLatency) {
								TargetCursor = ExpectedFrameBoundaryByte + ExpectedSoundBytesPerFrame;
							}
							else {
								TargetCursor = WriteCursor + ExpectedSoundBytesPerFrame + SoundOutput.SafetyBytes;
							}

							TargetCursor = TargetCursor % SoundOutput.SecondaryBufferSize;
							DWORD BytesToWrite = 0;

							if (ByteToLock > TargetCursor) {
								BytesToWrite = SoundOutput.SecondaryBufferSize - ByteToLock;
								BytesToWrite += TargetCursor;
							}
							else {
								BytesToWrite = TargetCursor - ByteToLock;
							}

							game_sound_output_buffer SoundBuffer = {};
							SoundBuffer.SamplesPerSecond = SoundOutput.SamplesPerSecond;
							SoundBuffer.SampleCount = BytesToWrite / SoundOutput.BytesPerSample;
							SoundBuffer.Samples = Samples;
							if (Game.GetSoundSamples) {
								Game.GetSoundSamples(&Thread, &GameMemory, &SoundBuffer);
							}

#if HANDMADE_INTERNAL
							win32_debug_time_marker *Marker = &DebugTimeMarkers[DebugTimeMarkerIndex];
							Marker->OutputPlayCursor = PlayCursor;
							Marker->OutputWriteCursor = WriteCursor;
							Marker->OutputLocation = ByteToLock;
							Marker->OutputByteCount = BytesToWrite;
							Marker->ExpectedFlipPlayCursor = ExpectedFrameBoundaryByte;
							DWORD UnwrappedWriteCursor = WriteCursor;

							if (UnwrappedWriteCursor < PlayCursor) {
								UnwrappedWriteCursor += SoundOutput.SecondaryBufferSize;
							}

							AudioLatencyBytes = UnwrappedWriteCursor - PlayCursor;
							AudioLatencySeconds = ((real32)AudioLatencyBytes / (real32)SoundOutput.BytesPerSample) / (real32)SoundOutput.SamplesPerSecond;

#if 0
							char DebugSoundBuffer[256];
							sprintf_s(DebugSoundBuffer, "BTL:%u TC:%u BTW:%u - PC:%u WC:%u DELTA:%u (%fs)\n", ByteToLock, TargetCursor, BytesToWrite, PlayCursor, WriteCursor, AudioLatencyBytes, AudioLatencySeconds);
							OutputDebugStringA(DebugSoundBuffer);
#endif
#endif
							Win32FillSoundBuffer(&SoundOutput, ByteToLock, BytesToWrite, &SoundBuffer);
						}
						else {
							SoundIsValid = false;
						}

						LARGE_INTEGER WorkCounter = Win32GetWallClock();
						real32 WorkSecondsElapsed = Win32GetSecondsElapsed(LastCounter, WorkCounter);
						// TODO: not tested yet!
						real32 SecondsElapsedForFrame = WorkSecondsElapsed;

						if (SecondsElapsedForFrame < TargetSecondsPerFrame) {
							if (SleepIsGranular) {
								DWORD SleepMS = (DWORD)(1000.0f * (TargetSecondsPerFrame - SecondsElapsedForFrame));
								if (SleepMS > 0) {
									Sleep(SleepMS);
								}
							}

							real32 TestSecondsElapsedForFrame = Win32GetSecondsElapsed(LastCounter, Win32GetWallClock());

							if (TestSecondsElapsedForFrame < TargetSecondsPerFrame) {
								// TODO: log missed sleep here
							}

							while (SecondsElapsedForFrame < TargetSecondsPerFrame) {
								SecondsElapsedForFrame = Win32GetSecondsElapsed(LastCounter, Win32GetWallClock());
							}
						}
						else {
							// TODO: missed frame rate
							// TODO: logging
						}

						LARGE_INTEGER EndCounter = Win32GetWallClock();
						real32 MSPerFrame = 1000.0f * Win32GetSecondsElapsed(LastCounter, EndCounter);
						LastCounter = EndCounter;

						win32_window_dimension Dimension = Win32GetWindowDimension(Window);
						HDC BufferDC = GetDC(Window);
						Win32DisplayBufferInWindow(&GlobalBackbuffer, BufferDC, Dimension.Width, Dimension.Height);
						ReleaseDC(Window, BufferDC);

						FlipWallClock = Win32GetWallClock();

#if HANDMADE_INTERNAL
						DWORD DebugPlayCursor;
						DWORD DebugWriteCursor;
						if (GlobalSecondaryBuffer->GetCurrentPosition(&DebugPlayCursor, &DebugWriteCursor) == DS_OK) {
							Assert(DebugTimeMarkerIndex < ArrayCount(DebugTimeMarkers));
							win32_debug_time_marker *Marker = &DebugTimeMarkers[DebugTimeMarkerIndex];
							Marker->FlipPlayCursor = DebugPlayCursor;
							Marker->FlipWriteCursor = DebugWriteCursor;
						}
#endif

						game_input *Temp = NewInput;
						NewInput = OldInput;
						OldInput = Temp;
						// TODO: should these be cleared?

#if 0
						uint64 EndCycleCount = __rdtsc();
						uint64 CyclesElapsed = EndCycleCount - LastCycleCount;
						LastCycleCount = EndCycleCount;

						// real32 FPS = (real32)GlobalPerfCounterFrequency / (real32)CounterElapsed;
						real32 FPS = 0.0f;
						real32 MCPF = (real32)CyclesElapsed / (1000.0f * 1000.0f);

						char DebugPerformanceBuffer[256];
						sprintf_s(DebugPerformanceBuffer, "%0.02fmspf, %0.02ffps, %0.02fmcpf\n", MSPerFrame, FPS, MCPF);
						OutputDebugStringA(DebugPerformanceBuffer);
#endif

#if HANDMADE_INTERNAL
						++DebugTimeMarkerIndex;
						if (DebugTimeMarkerIndex == ArrayCount(DebugTimeMarkers)) {
							DebugTimeMarkerIndex = 0;
						}
#endif
					}
				}
			}
			else {
				// TODO: logging
			}
		}
		else {
			// TODO: logging
		}
	}
	else {
		// TODO: logging
	}

	return(0);
}