This document describes how to set annotations, fidelity parameters, and
settings in your project.

## Annotations and fidelity parameters

Annotations give contextual information about what your game is doing when a
tick is recorded. Fidelity parameters reflect the performance and graphical
settings of your game. You define these using protocol buffers, which are
Google's language-neutral, structured, data-interchange format. For more
information on using protocol buffers within your game, see
[About protocol buffers](https://developer.android.com/games/sdk/performance-tuner/custom-engine/define-parameters#about-protocol-buffers).

The possible annotations and fidelity parameters for your game are defined in a
file called `dev_tuningfork.proto`, which is located in the `assets/tuningfork`
directory of your project. The following is an example from the demo app:  

    syntax = "proto3";

    package com.google.tuningfork;

    enum InstrumentKey {
      CPU = 0;
      GPU = 1;
      SWAPPY_WAIT = 2;
      SWAPPY_SWAP = 3;
      CHOREOGRAPHER = 4;
    }

    enum Level {
      // 0 is not a valid value
      LEVEL_INVALID = 0;
      LEVEL_1 = 1;
      LEVEL_2 = 2;
      LEVEL_3 = 3;
    };

    message Annotation {
      Level level = 1;
    }

    message FidelityParams {
      int32 num_spheres = 1;
      float tesselation_percent = 2;
    }

Note the following:

- The package must be `com.google.tuningfork`.
- The message names must be exactly `Annotation` and `FidelityParams`.
- You can use only `enums` defined in this file as part of annotations.
- You can only use `enums`, `int32s` or `floats` in `FidelityParams` fields.
- The [validation tool](https://developer.android.com/games/sdk/performance-tuner/custom-engine/validate-and-package) enforces these conventions.

## Settings

The `Settings` message is defined by [`tuningfork.proto`](https://android.googlesource.com/platform/frameworks/opt/gamesdk/+/refs/heads/master/src/tuningfork/proto/tuningfork.proto). See a full example in the
following file:

`gamesdk/samples/tuningfork/insightsdemo/app/src/main/assets/tuningfork/tuningfork_settings.txt`

You must define the settings for your game in a file called
`tuningfork_settings.txt` located in the `assets/tuningfork` directory of your
project. You need to specify only the following fields:

- `aggregation_strategy`: A message containing the following:

  - `method`: `TIME_BASED` to upload every *n* milliseconds or `TICK_BASED` to upload every *n* ticks.
  - `intervalms_or_count`: *n* for the `method` field.
  - `max_instrumentation_keys`: Number of instrumentation keys to use. Set to `4` if using the Android Frame Pacing library.
  - `annotation_enum_size`: An optional field since the size is calculated at start-up from the descriptor.
- `api_key`: Your app's Cloud project API key, used to validate requests to
  the endpoint. To generate this key, see
  [Enable the API](https://developer.android.com/games/sdk/performance-tuner/custom-engine/enable-api). If
  you see connection errors in `logcat`, check that the API key is correct.

- `default_fidelity_parameters_filename`: The fidelity parameter set used at
  initialization (optional if you set the
  [`training_fidelity_params`](https://developer.android.com/games/sdk/reference/performance-tuner/custom-engine/struct/t-f-settings#struct_t_f_settings_1a3ab649a2ec035694d4b035b742d56dd9)
  in your code).

- `level_annotation_index`: (Optional) The index in your annotation fields of
  the level number.

The following is an example text representation:  

    aggregation_strategy: {method: TIME_BASED, intervalms_or_count: 10000,
      max_instrumentation_keys: 5, annotation_enum_size: [3,4]}
    api_key: <var translate="no">"API-KEY-FROM-GOOGLE-CLOUD-CONSOLE"</var>
    default_fidelity_parameters_filename: "dev_tuningfork_fidelityparams_3.bin"
    level_annotation_index: 1

### Setting annotations

You need to manually set annotations during your game. You can see an
example of this in the demo app as it cycles through all of the game levels
automatically. For more information, see the `SetAnnotations()` function in
[`insightsdemo.cpp`](https://android.googlesource.com/platform/frameworks/opt/gamesdk/+/refs/heads/master/samples/tuningfork/insightsdemo/app/src/main/cpp/insightsdemo.cpp).

In this case, the annotation only specifies the level number.  

    message Annotation {
      Level level = 1;
    }

## Define quality levels

Use quality levels to annotate sessions so that you can determine if devices are
running on a quality level that is too high (resulting in lower performance) or
too low (resulting in unnecessarily reduced fidelity).

You must define at least one, and preferably several, quality levels for your
game. A quality level corresponds to an instance of your `FidelityParams`
message. These levels must be given in *increasing* fidelity order with the
following filename format:  

```
dev_tuningfork_fidelityparams_i.txt
```

where <var translate="no">i</var> is an index starting at 1 with a maximum value
of 15. These files must be located in the `assets/tuningfork` directory of your
project. The sample project shows an example of this structure in the
`gamesdk/samples/tuningfork/insightsdemo/app/src/main/assets/tuningfork/`
directory.

## About protocol buffers

The Tuning Fork library uses Google's protocol buffer format for
settings, annotations, and fidelity parameters. This is a well-defined,
multi-language protocol for extensible, structured data. For more information,
see the
[Protocol Buffers documentation](https://developers.google.com/protocol-buffers/).

### Proto2 vs proto3

The version of the protocol buffer format is set in the first line of the file:  

    syntax="proto2";

Proto2 and proto3 are two commonly-used versions of protocol buffers. They both
use the same wire format but the definition files are not compatible. Key
differences between the two versions include the following:

- The `optional` and `required` keywords are no longer allowed in proto3.
- Everything is effectively `optional` in proto3.
- Extensions are not supported in proto3.

Use proto3 in your proto files since these can be compiled to C#. Proto2 works
as well with the limited feature set used in the Tuning Fork library.

### Text versus binary representations

The binary protobuf wire-format is well-defined and stable across different
protobuf versions (the generated code is not). There is also a text format that
the full version of the protobuf library can generate and read. This format is
not as well-defined, but it is stable for the limited set of features in the
Tuning Fork library. You can convert between binary and text formats
using the `protoc` compiler. The following command converts a text protobuf to
binary:  

    protoc --encode com.google.tuningfork.Settings tuningfork.proto < tuningfork_settings.txt > tuningfork_settings.bin

You must include binary files rather than text files in your APK because the
full protobuf library is several MB in size; making the Tuning Fork
library depend on it would increase the size of your game by a similar amount.

### Full versus Lite versus Nano

As well as the full protobuf library, there is a lite version that reduces code
footprint by removing some features such as reflection, `FileDescriptors`, and
streaming to and from text formats. This version still requires several MB of
extra code footprint and so, the Tuning Fork library internally uses the
[nanopb library](https://github.com/nanopb/nanopb). The source code
for this library is included in the [Android Open Source Project](https://android.googlesource.com/platform/frameworks/opt/gamesdk/) in `external/nanopb-c` and
it is part of the `gamesdk` branch. Use this library in your game if code size
is an issue.

There are CMake files in `gamesdk/src/protobuf` that can help you to integrate
all three versions of protobuf. The samples use a mix of both nanopb and full
protobuf.