Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2015 The Chromium OS Authors. All rights reserved. |
| 3 | * Use of this source code is governed by a BSD-style license that can be |
| 4 | * found in the LICENSE file. |
| 5 | */ |
| 6 | |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 7 | #include "bs_drm.h" |
| 8 | |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 9 | #include <getopt.h> |
| 10 | #include <math.h> |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 11 | |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 12 | #define TABLE_LINEAR 0 |
| 13 | #define TABLE_NEGATIVE 1 |
| 14 | #define TABLE_POW 2 |
| 15 | #define TABLE_STEP 3 |
Miguel Casas | a5d9ff2 | 2020-03-12 17:23:34 -0400 | [diff] [blame] | 16 | // TABLE_PIECEWISE_HDR mimics Chrome's PIECEWISE_HDR gfx::ColorSpace::TranferID, |
| 17 | // basically an sRGB up to a given elbow or joint, and linear after. |
| 18 | #define TABLE_PIECEWISE_HDR 4 |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 19 | |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 20 | #define FLAG_INTERNAL 'i' |
| 21 | #define FLAG_EXTERNAL 'e' |
| 22 | #define FLAG_GAMMA 'g' |
| 23 | #define FLAG_LINEAR 'l' |
| 24 | #define FLAG_NEGATIVE 'n' |
| 25 | #define FLAG_TIME 't' |
| 26 | #define FLAG_CRTCS 'c' |
| 27 | #define FLAG_PERSIST 'p' |
| 28 | #define FLAG_STEP 's' |
Miguel Casas | a5d9ff2 | 2020-03-12 17:23:34 -0400 | [diff] [blame] | 29 | #define FLAG_HDR 'x' |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 30 | #define FLAG_HELP 'h' |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 31 | |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 32 | static struct option command_options[] = { { "internal", no_argument, NULL, FLAG_INTERNAL }, |
| 33 | { "external", no_argument, NULL, FLAG_EXTERNAL }, |
| 34 | { "gamma", required_argument, NULL, FLAG_GAMMA }, |
| 35 | { "linear", no_argument, NULL, FLAG_LINEAR }, |
| 36 | { "negative", no_argument, NULL, FLAG_NEGATIVE }, |
| 37 | { "time", required_argument, NULL, FLAG_TIME }, |
| 38 | { "crtcs", required_argument, NULL, FLAG_CRTCS }, |
| 39 | { "persist", no_argument, NULL, FLAG_PERSIST }, |
| 40 | { "step", no_argument, NULL, FLAG_STEP }, |
Miguel Casas | a5d9ff2 | 2020-03-12 17:23:34 -0400 | [diff] [blame] | 41 | { "hdr", required_argument, NULL, FLAG_HDR }, |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 42 | { "help", no_argument, NULL, FLAG_HELP }, |
| 43 | { NULL, 0, NULL, 0 } }; |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 44 | |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 45 | static void gamma_linear(uint16_t *table, int size) |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 46 | { |
| 47 | int i; |
| 48 | for (i = 0; i < size; i++) { |
| 49 | float v = (float)(i) / (float)(size - 1); |
| 50 | v *= 65535.0f; |
| 51 | table[i] = (uint16_t)v; |
| 52 | } |
| 53 | } |
| 54 | |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 55 | static void gamma_inv(uint16_t *table, int size) |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 56 | { |
| 57 | int i; |
| 58 | for (i = 0; i < size; i++) { |
| 59 | float v = (float)(size - 1 - i) / (float)(size - 1); |
| 60 | v *= 65535.0f; |
| 61 | table[i] = (uint16_t)v; |
| 62 | } |
| 63 | } |
| 64 | |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 65 | static void gamma_pow(uint16_t *table, int size, float p) |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 66 | { |
| 67 | int i; |
| 68 | for (i = 0; i < size; i++) { |
| 69 | float v = (float)(i) / (float)(size - 1); |
| 70 | v = pow(v, p); |
| 71 | v *= 65535.0f; |
| 72 | table[i] = (uint16_t)v; |
| 73 | } |
| 74 | } |
| 75 | |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 76 | static void gamma_step(uint16_t *table, int size) |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 77 | { |
| 78 | int i; |
| 79 | for (i = 0; i < size; i++) { |
| 80 | table[i] = (i < size / 2) ? 0 : 65535; |
| 81 | } |
| 82 | } |
| 83 | |
Miguel Casas | a5d9ff2 | 2020-03-12 17:23:34 -0400 | [diff] [blame] | 84 | static void gamma_piecewise_linear(uint16_t *table, int size, float joint) |
| 85 | { |
| 86 | const float gamma = 1 / 2.2f; |
| 87 | // |joint_i| is the index in [0, size) where sRGB and linear curves meet. |
| 88 | const size_t joint_i = joint * size; |
| 89 | // |joint_v| is the gamma output value where sRGB and linear curves meet. |
| 90 | const float joint_v = pow(joint, gamma); |
| 91 | // |slope| is the slope of the linear part. |
| 92 | const float slope = (1 - joint_v) / (1 - joint); |
| 93 | int i; |
| 94 | for (i = 0; i < size; i++) { |
| 95 | float v = (float)(i) / (float)(size - 1); |
| 96 | |
| 97 | if (i < joint_i) |
| 98 | v = pow(v, gamma); |
| 99 | else |
| 100 | v = joint_v + slope * (v - joint); |
| 101 | |
| 102 | v *= 65535.0f; |
| 103 | table[i] = (uint16_t)v; |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | static const char* gamma_name(int gamma_table_id) |
| 108 | { |
| 109 | const char *table_names[] = { "TABLE_LINEAR", "TABLE_NEGATIVE", "TABLE_POW", "TABLE_STEP", |
| 110 | "TABLE_PIECEWISE_HDR" }; |
| 111 | const size_t max_gamma_table_id = sizeof(table_names)/sizeof(table_names[0]); |
| 112 | if (gamma_table_id >= max_gamma_table_id) |
| 113 | return NULL; |
| 114 | return table_names[gamma_table_id]; |
| 115 | } |
| 116 | |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 117 | static void fsleep(double secs) |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 118 | { |
| 119 | usleep((useconds_t)(1000000.0f * secs)); |
| 120 | } |
| 121 | |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 122 | static drmModeModeInfoPtr find_best_mode(int mode_count, drmModeModeInfoPtr modes) |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 123 | { |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 124 | assert(mode_count >= 0); |
| 125 | if (mode_count == 0) |
| 126 | return NULL; |
| 127 | |
| 128 | assert(modes); |
| 129 | |
| 130 | for (int m = 0; m < mode_count; m++) |
| 131 | if (modes[m].type & DRM_MODE_TYPE_PREFERRED) |
| 132 | return &modes[m]; |
| 133 | |
| 134 | return &modes[0]; |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 135 | } |
| 136 | |
Miguel Casas | a5d9ff2 | 2020-03-12 17:23:34 -0400 | [diff] [blame] | 137 | static bool draw_pattern(struct bs_mapper *mapper, struct gbm_bo *bo, int gbm_format) |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 138 | { |
Satyajit Sahu | b7e47dd | 2018-05-07 12:35:50 +0530 | [diff] [blame] | 139 | uint32_t stride; |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 140 | const uint32_t height = gbm_bo_get_height(bo); |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 141 | const uint32_t stripw = gbm_bo_get_width(bo) / 256; |
| 142 | const uint32_t striph = height / 4; |
| 143 | |
Miguel Casas | a5d9ff2 | 2020-03-12 17:23:34 -0400 | [diff] [blame] | 144 | if (gbm_format != GBM_FORMAT_XRGB8888 && gbm_format != GBM_FORMAT_XRGB2101010) |
| 145 | return false; |
| 146 | |
Dongseong Hwang | 9093afe | 2017-03-20 19:16:28 -0700 | [diff] [blame] | 147 | void *map_data; |
Satyajit Sahu | b7e47dd | 2018-05-07 12:35:50 +0530 | [diff] [blame] | 148 | uint8_t *bo_ptr = bs_mapper_map(mapper, bo, 0, &map_data, &stride); |
Dongseong Hwang | 9093afe | 2017-03-20 19:16:28 -0700 | [diff] [blame] | 149 | if (bo_ptr == MAP_FAILED) { |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 150 | bs_debug_error("failed to mmap buffer while drawing pattern"); |
| 151 | return false; |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 152 | } |
Satyajit Sahu | b7e47dd | 2018-05-07 12:35:50 +0530 | [diff] [blame] | 153 | const uint32_t bo_size = stride * height; |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 154 | |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 155 | bool success = true; |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 156 | |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 157 | memset(bo_ptr, 0, bo_size); |
| 158 | for (uint32_t s = 0; s < 4; s++) { |
| 159 | uint8_t r = 0, g = 0, b = 0; |
| 160 | switch (s) { |
| 161 | case 0: |
| 162 | r = g = b = 1; |
| 163 | break; |
| 164 | case 1: |
| 165 | r = 1; |
| 166 | break; |
| 167 | case 2: |
| 168 | g = 1; |
| 169 | break; |
| 170 | case 3: |
| 171 | b = 1; |
| 172 | break; |
| 173 | default: |
| 174 | assert("invalid strip" && false); |
| 175 | success = false; |
| 176 | goto out; |
| 177 | } |
| 178 | for (uint32_t y = s * striph; y < (s + 1) * striph; y++) { |
| 179 | uint8_t *row_ptr = &bo_ptr[y * stride]; |
| 180 | for (uint32_t i = 0; i < 256; i++) { |
| 181 | for (uint32_t x = i * stripw; x < (i + 1) * stripw; x++) { |
Miguel Casas | a5d9ff2 | 2020-03-12 17:23:34 -0400 | [diff] [blame] | 182 | if (gbm_format == GBM_FORMAT_XRGB8888) { |
| 183 | row_ptr[x * 4 + 0] = b * i; |
| 184 | row_ptr[x * 4 + 1] = g * i; |
| 185 | row_ptr[x * 4 + 2] = r * i; |
| 186 | row_ptr[x * 4 + 3] = 0; |
| 187 | } else { |
| 188 | *(uint32_t *)(&row_ptr[x * 4]) = |
| 189 | (((r * i) << 2) | ((r * i) >> 6)) << 20 | |
| 190 | (((g * i) << 2) | ((g * i) >> 6)) << 10 | |
| 191 | (((b * i) << 2) | ((b * i) >> 6)); |
| 192 | } |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 193 | } |
| 194 | } |
| 195 | } |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 196 | } |
| 197 | |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 198 | out: |
Dongseong Hwang | 9093afe | 2017-03-20 19:16:28 -0700 | [diff] [blame] | 199 | bs_mapper_unmap(mapper, bo, map_data); |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 200 | return success; |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 201 | } |
| 202 | |
Miguel Casas | a5d9ff2 | 2020-03-12 17:23:34 -0400 | [diff] [blame] | 203 | // |parameter| is passed to the appropriate |gamma_table| generation function. |
| 204 | static int set_gamma(int fd, uint32_t crtc_id, int gamma_size, int gamma_table, float parameter) |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 205 | { |
| 206 | int res; |
| 207 | uint16_t *r, *g, *b; |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 208 | r = calloc(gamma_size, sizeof(*r)); |
| 209 | g = calloc(gamma_size, sizeof(*g)); |
| 210 | b = calloc(gamma_size, sizeof(*b)); |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 211 | |
Miguel Casas | a5d9ff2 | 2020-03-12 17:23:34 -0400 | [diff] [blame] | 212 | printf("Setting gamma table index %d (%s)\n", gamma_table, gamma_name(gamma_table)); |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 213 | switch (gamma_table) { |
| 214 | case TABLE_LINEAR: |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 215 | gamma_linear(r, gamma_size); |
| 216 | gamma_linear(g, gamma_size); |
| 217 | gamma_linear(b, gamma_size); |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 218 | break; |
| 219 | case TABLE_NEGATIVE: |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 220 | gamma_inv(r, gamma_size); |
| 221 | gamma_inv(g, gamma_size); |
| 222 | gamma_inv(b, gamma_size); |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 223 | break; |
| 224 | case TABLE_POW: |
Miguel Casas | a5d9ff2 | 2020-03-12 17:23:34 -0400 | [diff] [blame] | 225 | gamma_pow(r, gamma_size, parameter); |
| 226 | gamma_pow(g, gamma_size, parameter); |
| 227 | gamma_pow(b, gamma_size, parameter); |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 228 | break; |
| 229 | case TABLE_STEP: |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 230 | gamma_step(r, gamma_size); |
| 231 | gamma_step(g, gamma_size); |
| 232 | gamma_step(b, gamma_size); |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 233 | break; |
Miguel Casas | a5d9ff2 | 2020-03-12 17:23:34 -0400 | [diff] [blame] | 234 | case TABLE_PIECEWISE_HDR: |
| 235 | gamma_piecewise_linear(r, gamma_size, parameter); |
| 236 | gamma_piecewise_linear(g, gamma_size, parameter); |
| 237 | gamma_piecewise_linear(b, gamma_size, parameter); |
| 238 | break; |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 239 | } |
| 240 | |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 241 | res = drmModeCrtcSetGamma(fd, crtc_id, gamma_size, r, g, b); |
| 242 | if (res) |
| 243 | bs_debug_error("drmModeCrtcSetGamma(%d) failed: %s", crtc_id, strerror(errno)); |
| 244 | free(r); |
| 245 | free(g); |
| 246 | free(b); |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 247 | return res; |
| 248 | } |
| 249 | |
| 250 | void help(void) |
| 251 | { |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 252 | printf( |
| 253 | "\ |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 254 | gamma test\n\ |
| 255 | command line options:\ |
| 256 | \n\ |
| 257 | --help - this\n\ |
| 258 | --linear - set linear gamma table\n\ |
| 259 | --negative - set negative linear gamma table\n\ |
| 260 | --step - set step gamma table\n\ |
| 261 | --gamma=f - set pow(gamma) gamma table with gamma=f\n\ |
| 262 | --time=f - set test time\n\ |
| 263 | --crtcs=n - set mask of crtcs to test\n\ |
| 264 | --persist - do not reset gamma table at the end of the test\n\ |
| 265 | --internal - display tests on internal display\n\ |
| 266 | --external - display tests on external display\n\ |
Miguel Casas | a5d9ff2 | 2020-03-12 17:23:34 -0400 | [diff] [blame] | 267 | --hdr=x - sets piecewise HDR gamma table with SDR-HDR joint at x (usually 0.5)\n\ |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 268 | "); |
| 269 | } |
| 270 | |
| 271 | int main(int argc, char **argv) |
| 272 | { |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 273 | int internal = 1; |
| 274 | int persist = 0; |
| 275 | float time = 5.0; |
| 276 | float gamma = 2.2f; |
Miguel Casas | a5d9ff2 | 2020-03-12 17:23:34 -0400 | [diff] [blame] | 277 | float srgb_joint = 0.0f; |
| 278 | int table = TABLE_LINEAR; |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 279 | uint32_t crtcs = 0xFFFF; |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 280 | |
| 281 | for (;;) { |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 282 | int c = getopt_long(argc, argv, "", command_options, NULL); |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 283 | |
| 284 | if (c == -1) |
| 285 | break; |
| 286 | |
| 287 | switch (c) { |
| 288 | case FLAG_HELP: |
| 289 | help(); |
| 290 | return 0; |
| 291 | |
| 292 | case FLAG_INTERNAL: |
| 293 | internal = 1; |
| 294 | break; |
| 295 | |
| 296 | case FLAG_EXTERNAL: |
| 297 | internal = 0; |
| 298 | break; |
| 299 | |
| 300 | case FLAG_GAMMA: |
| 301 | gamma = strtof(optarg, NULL); |
| 302 | table = TABLE_POW; |
| 303 | break; |
| 304 | |
| 305 | case FLAG_LINEAR: |
| 306 | table = TABLE_LINEAR; |
| 307 | break; |
| 308 | |
| 309 | case FLAG_NEGATIVE: |
| 310 | table = TABLE_NEGATIVE; |
| 311 | break; |
| 312 | |
| 313 | case FLAG_STEP: |
| 314 | table = TABLE_STEP; |
| 315 | break; |
| 316 | |
Miguel Casas | a5d9ff2 | 2020-03-12 17:23:34 -0400 | [diff] [blame] | 317 | case FLAG_HDR: |
| 318 | srgb_joint = strtof(optarg, NULL); |
| 319 | table = TABLE_PIECEWISE_HDR; |
| 320 | break; |
| 321 | |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 322 | case FLAG_TIME: |
| 323 | time = strtof(optarg, NULL); |
| 324 | break; |
| 325 | |
| 326 | case FLAG_CRTCS: |
| 327 | crtcs = strtoul(optarg, NULL, 0); |
| 328 | break; |
| 329 | |
| 330 | case FLAG_PERSIST: |
| 331 | persist = 1; |
| 332 | break; |
| 333 | } |
| 334 | } |
| 335 | |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 336 | drmModeConnector *connector = NULL; |
| 337 | struct bs_drm_pipe pipe = { 0 }; |
| 338 | struct bs_drm_pipe_plumber *plumber = bs_drm_pipe_plumber_new(); |
| 339 | bs_drm_pipe_plumber_connector_ptr(plumber, &connector); |
| 340 | bs_drm_pipe_plumber_crtc_mask(plumber, crtcs); |
| 341 | if (!internal) |
| 342 | bs_drm_pipe_plumber_connector_ranks(plumber, bs_drm_connectors_external_rank); |
| 343 | if (!bs_drm_pipe_plumber_make(plumber, &pipe)) { |
| 344 | bs_debug_error("failed to make pipe"); |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 345 | return 1; |
| 346 | } |
| 347 | |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 348 | int fd = pipe.fd; |
| 349 | bs_drm_pipe_plumber_fd(plumber, fd); |
| 350 | drmModeRes *resources = drmModeGetResources(fd); |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 351 | if (!resources) { |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 352 | bs_debug_error("failed to get drm resources"); |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 353 | return 1; |
| 354 | } |
| 355 | |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 356 | struct gbm_device *gbm = gbm_create_device(fd); |
| 357 | if (!gbm) { |
| 358 | bs_debug_error("failed to create gbm"); |
| 359 | return 1; |
| 360 | } |
| 361 | |
Shirish S | 99c916e | 2017-07-07 15:57:57 +0530 | [diff] [blame] | 362 | struct bs_mapper *mapper = bs_mapper_gem_new(); |
Dongseong Hwang | 9093afe | 2017-03-20 19:16:28 -0700 | [diff] [blame] | 363 | if (mapper == NULL) { |
| 364 | bs_debug_error("failed to create mapper object"); |
| 365 | return 1; |
| 366 | } |
| 367 | |
Gurchetan Singh | 5dd7b70 | 2017-02-24 17:56:33 -0800 | [diff] [blame] | 368 | uint32_t num_success = 0; |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 369 | for (int c = 0; c < resources->count_crtcs && (crtcs >> c); c++) { |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 370 | int ret; |
| 371 | drmModeCrtc *crtc; |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 372 | uint32_t crtc_mask = 1u << c; |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 373 | |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 374 | if (!(crtcs & crtc_mask)) |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 375 | continue; |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 376 | |
Miguel Casas | a5d9ff2 | 2020-03-12 17:23:34 -0400 | [diff] [blame] | 377 | if (c > 0) |
| 378 | printf("\n"); |
| 379 | |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 380 | if (connector != NULL) { |
| 381 | drmModeFreeConnector(connector); |
| 382 | connector = NULL; |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 383 | } |
| 384 | |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 385 | bs_drm_pipe_plumber_crtc_mask(plumber, crtc_mask); |
| 386 | if (!bs_drm_pipe_plumber_make(plumber, &pipe)) { |
Gurchetan Singh | 5dd7b70 | 2017-02-24 17:56:33 -0800 | [diff] [blame] | 387 | printf("unable to make pipe with crtc mask: %x\n", crtc_mask); |
| 388 | continue; |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 389 | } |
| 390 | |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 391 | crtc = drmModeGetCrtc(fd, pipe.crtc_id); |
| 392 | if (!crtc) { |
| 393 | bs_debug_error("drmModeGetCrtc(%d) failed: %s\n", pipe.crtc_id, |
| 394 | strerror(errno)); |
| 395 | return 1; |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 396 | } |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 397 | int gamma_size = crtc->gamma_size; |
| 398 | drmModeFreeCrtc(crtc); |
| 399 | |
| 400 | if (!gamma_size) { |
| 401 | bs_debug_error("CRTC %d has no gamma table", crtc->crtc_id); |
| 402 | continue; |
| 403 | } |
| 404 | |
Miguel Casas | a5d9ff2 | 2020-03-12 17:23:34 -0400 | [diff] [blame] | 405 | printf("CRTC:%d gamma table size:%d\n", pipe.crtc_id, gamma_size); |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 406 | |
| 407 | printf("Using CRTC:%u ENCODER:%u CONNECTOR:%u\n", pipe.crtc_id, pipe.encoder_id, |
| 408 | pipe.connector_id); |
| 409 | |
| 410 | drmModeModeInfoPtr mode = find_best_mode(connector->count_modes, connector->modes); |
| 411 | if (!mode) { |
| 412 | bs_debug_error("Could not find mode for CRTC %d", pipe.crtc_id); |
| 413 | continue; |
| 414 | } |
| 415 | |
| 416 | printf("Using mode %s\n", mode->name); |
| 417 | |
Miguel Casas | a5d9ff2 | 2020-03-12 17:23:34 -0400 | [diff] [blame] | 418 | const bool is_hdr = table == TABLE_PIECEWISE_HDR; |
| 419 | const int gbm_format = is_hdr ? GBM_FORMAT_XRGB2101010 : GBM_FORMAT_XRGB8888; |
| 420 | |
| 421 | printf("Creating buffer %ux%u (%s)\n", mode->hdisplay, mode->vdisplay, |
| 422 | (is_hdr ? "XR30" : "XR24")); |
| 423 | struct gbm_bo *bo = gbm_bo_create(gbm, mode->hdisplay, mode->vdisplay, gbm_format, |
| 424 | GBM_BO_USE_SCANOUT | GBM_BO_USE_SW_WRITE_RARELY); |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 425 | if (!bo) { |
| 426 | bs_debug_error("failed to create buffer object"); |
| 427 | return 1; |
| 428 | } |
| 429 | |
| 430 | uint32_t fb_id = bs_drm_fb_create_gbm(bo); |
| 431 | if (!fb_id) { |
| 432 | bs_debug_error("failed to create frame buffer for buffer object"); |
| 433 | return 1; |
| 434 | } |
| 435 | |
Miguel Casas | a5d9ff2 | 2020-03-12 17:23:34 -0400 | [diff] [blame] | 436 | if (!draw_pattern(mapper, bo, gbm_format)) { |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 437 | bs_debug_error("failed to draw pattern on buffer object"); |
| 438 | return 1; |
| 439 | } |
| 440 | |
| 441 | ret = drmModeSetCrtc(fd, pipe.crtc_id, fb_id, 0, 0, &pipe.connector_id, 1, mode); |
| 442 | if (ret < 0) { |
| 443 | bs_debug_error("Could not set mode on CRTC %d %s", pipe.crtc_id, |
| 444 | strerror(errno)); |
| 445 | return 1; |
| 446 | } |
| 447 | |
Miguel Casas | a5d9ff2 | 2020-03-12 17:23:34 -0400 | [diff] [blame] | 448 | ret = set_gamma(fd, pipe.crtc_id, gamma_size, table, is_hdr ? srgb_joint : gamma); |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 449 | if (ret) |
| 450 | return ret; |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 451 | |
| 452 | fsleep(time); |
| 453 | |
| 454 | if (!persist) { |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 455 | ret = set_gamma(fd, pipe.crtc_id, gamma_size, TABLE_LINEAR, 0.0f); |
| 456 | if (ret) |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 457 | return ret; |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 458 | } |
| 459 | |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 460 | ret = drmModeSetCrtc(fd, pipe.crtc_id, 0, 0, 0, NULL, 0, NULL); |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 461 | if (ret < 0) { |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 462 | bs_debug_error("Could disable CRTC %d %s\n", pipe.crtc_id, strerror(errno)); |
Gurchetan Singh | 5dd7b70 | 2017-02-24 17:56:33 -0800 | [diff] [blame] | 463 | return 1; |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 464 | } |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 465 | |
| 466 | drmModeRmFB(fd, fb_id); |
| 467 | gbm_bo_destroy(bo); |
Gurchetan Singh | 5dd7b70 | 2017-02-24 17:56:33 -0800 | [diff] [blame] | 468 | num_success++; |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 469 | } |
Dongseong Hwang | 9093afe | 2017-03-20 19:16:28 -0700 | [diff] [blame] | 470 | bs_mapper_destroy(mapper); |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 471 | |
| 472 | if (connector != NULL) { |
| 473 | drmModeFreeConnector(connector); |
| 474 | connector = NULL; |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 475 | } |
| 476 | |
| 477 | drmModeFreeResources(resources); |
Zach Reizner | 3415d06 | 2016-03-30 11:14:29 -0700 | [diff] [blame] | 478 | bs_drm_pipe_plumber_destroy(&plumber); |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 479 | |
Gurchetan Singh | 5dd7b70 | 2017-02-24 17:56:33 -0800 | [diff] [blame] | 480 | if (!num_success) { |
| 481 | bs_debug_error("unable to set gamma table on any CRTC"); |
| 482 | return 1; |
| 483 | } |
| 484 | |
Dominik Behr | e472630 | 2015-04-27 20:18:26 -0700 | [diff] [blame] | 485 | return 0; |
| 486 | } |