1 /* 2 * Copyright 2016 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: AMD 23 * 24 */ 25 26 #include "dm_services.h" 27 #include "dc.h" 28 #include "mod_freesync.h" 29 #include "core_types.h" 30 #include "core_dc.h" 31 32 #define MOD_FREESYNC_MAX_CONCURRENT_STREAMS 32 33 34 /* Refresh rate ramp at a fixed rate of 65 Hz/second */ 35 #define STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME ((1000 / 60) * 65) 36 /* Number of elements in the render times cache array */ 37 #define RENDER_TIMES_MAX_COUNT 20 38 /* Threshold to exit BTR (to avoid frequent enter-exits at the lower limit) */ 39 #define BTR_EXIT_MARGIN 2000 40 41 #define FREESYNC_REGISTRY_NAME "freesync_v1" 42 43 struct gradual_static_ramp { 44 bool ramp_is_active; 45 bool ramp_direction_is_up; 46 unsigned int ramp_current_frame_duration_in_ns; 47 }; 48 49 struct time_cache { 50 /* video (48Hz feature) related */ 51 unsigned int update_duration_in_ns; 52 53 /* BTR/fixed refresh related */ 54 unsigned int prev_time_stamp_in_us; 55 56 unsigned int min_render_time_in_us; 57 unsigned int max_render_time_in_us; 58 59 unsigned int render_times_index; 60 unsigned int render_times[RENDER_TIMES_MAX_COUNT]; 61 }; 62 63 struct below_the_range { 64 bool btr_active; 65 bool program_btr; 66 67 unsigned int mid_point_in_us; 68 69 unsigned int inserted_frame_duration_in_us; 70 unsigned int frames_to_insert; 71 unsigned int frame_counter; 72 }; 73 74 struct fixed_refresh { 75 bool fixed_refresh_active; 76 bool program_fixed_refresh; 77 }; 78 79 struct freesync_range { 80 unsigned int min_refresh; 81 unsigned int max_frame_duration; 82 unsigned int vmax; 83 84 unsigned int max_refresh; 85 unsigned int min_frame_duration; 86 unsigned int vmin; 87 }; 88 89 struct freesync_state { 90 bool fullscreen; 91 bool static_screen; 92 bool video; 93 94 unsigned int nominal_refresh_rate_in_micro_hz; 95 bool windowed_fullscreen; 96 97 struct time_cache time; 98 99 struct gradual_static_ramp static_ramp; 100 struct below_the_range btr; 101 struct fixed_refresh fixed_refresh; 102 struct freesync_range freesync_range; 103 }; 104 105 struct freesync_entity { 106 const struct dc_stream *stream; 107 struct mod_freesync_caps *caps; 108 struct freesync_state state; 109 struct mod_freesync_user_enable user_enable; 110 }; 111 112 struct freesync_registry_options { 113 unsigned int min_refresh_from_edid; 114 }; 115 116 struct core_freesync { 117 struct mod_freesync public; 118 struct dc *dc; 119 struct freesync_entity *map; 120 int num_entities; 121 struct freesync_registry_options opts; 122 }; 123 124 #define MOD_FREESYNC_TO_CORE(mod_freesync)\ 125 container_of(mod_freesync, struct core_freesync, public) 126 127 static bool check_dc_support(const struct dc *dc) 128 { 129 if (dc->stream_funcs.adjust_vmin_vmax == NULL) 130 return false; 131 132 return true; 133 } 134 135 struct mod_freesync *mod_freesync_create(struct dc *dc) 136 { 137 struct core_freesync *core_freesync = 138 dm_alloc(sizeof(struct core_freesync)); 139 140 struct core_dc *core_dc = DC_TO_CORE(dc); 141 142 struct persistent_data_flag flag; 143 144 int i, data = 0; 145 146 if (core_freesync == NULL) 147 goto fail_alloc_context; 148 149 core_freesync->map = dm_alloc(sizeof(struct freesync_entity) * 150 MOD_FREESYNC_MAX_CONCURRENT_STREAMS); 151 152 if (core_freesync->map == NULL) 153 goto fail_alloc_map; 154 155 for (i = 0; i < MOD_FREESYNC_MAX_CONCURRENT_STREAMS; i++) 156 core_freesync->map[i].stream = NULL; 157 158 core_freesync->num_entities = 0; 159 160 if (dc == NULL) 161 goto fail_construct; 162 163 core_freesync->dc = dc; 164 165 if (!check_dc_support(dc)) 166 goto fail_construct; 167 168 /* Create initial module folder in registry for freesync enable data */ 169 flag.save_per_edid = true; 170 flag.save_per_link = false; 171 dm_write_persistent_data(core_dc->ctx, NULL, FREESYNC_REGISTRY_NAME, NULL, NULL, 172 0, &flag); 173 flag.save_per_edid = false; 174 flag.save_per_link = false; 175 if (dm_read_persistent_data(core_dc->ctx, NULL, NULL, 176 "DalDrrSupport", &data, sizeof(data), &flag)) { 177 core_freesync->opts.min_refresh_from_edid = data; 178 } 179 180 return &core_freesync->public; 181 182 fail_construct: 183 dm_free(core_freesync->map); 184 185 fail_alloc_map: 186 dm_free(core_freesync); 187 188 fail_alloc_context: 189 return NULL; 190 } 191 192 void mod_freesync_destroy(struct mod_freesync *mod_freesync) 193 { 194 if (mod_freesync != NULL) { 195 int i; 196 struct core_freesync *core_freesync = 197 MOD_FREESYNC_TO_CORE(mod_freesync); 198 199 for (i = 0; i < core_freesync->num_entities; i++) 200 if (core_freesync->map[i].stream) 201 dc_stream_release(core_freesync->map[i].stream); 202 203 dm_free(core_freesync->map); 204 205 dm_free(core_freesync); 206 } 207 } 208 209 /* Given a specific dc_stream* this function finds its equivalent 210 * on the core_freesync->map and returns the corresponding index 211 */ 212 static unsigned int map_index_from_stream(struct core_freesync *core_freesync, 213 const struct dc_stream *stream) 214 { 215 unsigned int index = 0; 216 217 for (index = 0; index < core_freesync->num_entities; index++) { 218 if (core_freesync->map[index].stream == stream) { 219 return index; 220 } 221 } 222 /* Could not find stream requested */ 223 ASSERT(false); 224 return index; 225 } 226 227 bool mod_freesync_add_stream(struct mod_freesync *mod_freesync, 228 const struct dc_stream *stream, struct mod_freesync_caps *caps) 229 { 230 struct core_stream *core_stream = NULL; 231 struct core_dc *core_dc = NULL; 232 struct core_freesync *core_freesync = NULL; 233 int persistent_freesync_enable = 0; 234 struct persistent_data_flag flag; 235 unsigned int nom_refresh_rate_micro_hz; 236 unsigned long long temp; 237 238 if (mod_freesync == NULL) 239 return false; 240 241 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 242 core_stream = DC_STREAM_TO_CORE(stream); 243 core_dc = DC_TO_CORE(core_freesync->dc); 244 245 flag.save_per_edid = true; 246 flag.save_per_link = false; 247 248 if (core_freesync->num_entities < MOD_FREESYNC_MAX_CONCURRENT_STREAMS) { 249 250 dc_stream_retain(stream); 251 252 temp = stream->timing.pix_clk_khz; 253 temp *= 1000ULL * 1000ULL * 1000ULL; 254 temp = div_u64(temp, stream->timing.h_total); 255 temp = div_u64(temp, stream->timing.v_total); 256 257 nom_refresh_rate_micro_hz = (unsigned int) temp; 258 259 if (core_freesync->opts.min_refresh_from_edid != 0 && 260 dc_is_embedded_signal( 261 stream->sink->sink_signal)) { 262 caps->supported = true; 263 caps->min_refresh_in_micro_hz = 264 core_freesync->opts.min_refresh_from_edid * 265 1000000; 266 caps->max_refresh_in_micro_hz = 267 nom_refresh_rate_micro_hz; 268 } 269 270 core_freesync->map[core_freesync->num_entities].stream = stream; 271 core_freesync->map[core_freesync->num_entities].caps = caps; 272 273 core_freesync->map[core_freesync->num_entities].state. 274 fullscreen = false; 275 core_freesync->map[core_freesync->num_entities].state. 276 static_screen = false; 277 core_freesync->map[core_freesync->num_entities].state. 278 video = false; 279 core_freesync->map[core_freesync->num_entities].state.time. 280 update_duration_in_ns = 0; 281 core_freesync->map[core_freesync->num_entities].state. 282 static_ramp.ramp_is_active = false; 283 284 /* get persistent data from registry */ 285 if (dm_read_persistent_data(core_dc->ctx, stream->sink, 286 FREESYNC_REGISTRY_NAME, 287 "userenable", &persistent_freesync_enable, 288 sizeof(int), &flag)) { 289 core_freesync->map[core_freesync->num_entities].user_enable. 290 enable_for_gaming = 291 (persistent_freesync_enable & 1) ? true : false; 292 core_freesync->map[core_freesync->num_entities].user_enable. 293 enable_for_static = 294 (persistent_freesync_enable & 2) ? true : false; 295 core_freesync->map[core_freesync->num_entities].user_enable. 296 enable_for_video = 297 (persistent_freesync_enable & 4) ? true : false; 298 } else { 299 core_freesync->map[core_freesync->num_entities].user_enable. 300 enable_for_gaming = false; 301 core_freesync->map[core_freesync->num_entities].user_enable. 302 enable_for_static = false; 303 core_freesync->map[core_freesync->num_entities].user_enable. 304 enable_for_video = false; 305 } 306 307 if (caps->supported && 308 nom_refresh_rate_micro_hz >= caps->min_refresh_in_micro_hz && 309 nom_refresh_rate_micro_hz <= caps->max_refresh_in_micro_hz) 310 core_stream->public.ignore_msa_timing_param = 1; 311 312 core_freesync->num_entities++; 313 return true; 314 } 315 return false; 316 } 317 318 bool mod_freesync_remove_stream(struct mod_freesync *mod_freesync, 319 const struct dc_stream *stream) 320 { 321 int i = 0; 322 struct core_freesync *core_freesync = NULL; 323 unsigned int index = 0; 324 325 if (mod_freesync == NULL) 326 return false; 327 328 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 329 index = map_index_from_stream(core_freesync, stream); 330 331 dc_stream_release(core_freesync->map[index].stream); 332 core_freesync->map[index].stream = NULL; 333 /* To remove this entity, shift everything after down */ 334 for (i = index; i < core_freesync->num_entities - 1; i++) 335 core_freesync->map[i] = core_freesync->map[i + 1]; 336 core_freesync->num_entities--; 337 return true; 338 } 339 340 static void update_stream_freesync_context(struct core_freesync *core_freesync, 341 const struct dc_stream *stream) 342 { 343 unsigned int index; 344 struct freesync_context *ctx; 345 struct core_stream *core_stream; 346 347 core_stream = DC_STREAM_TO_CORE(stream); 348 ctx = &core_stream->public.freesync_ctx; 349 350 index = map_index_from_stream(core_freesync, stream); 351 352 ctx->supported = core_freesync->map[index].caps->supported; 353 ctx->enabled = (core_freesync->map[index].user_enable.enable_for_gaming || 354 core_freesync->map[index].user_enable.enable_for_video || 355 core_freesync->map[index].user_enable.enable_for_static); 356 ctx->active = (core_freesync->map[index].state.fullscreen || 357 core_freesync->map[index].state.video || 358 core_freesync->map[index].state.static_ramp.ramp_is_active); 359 ctx->min_refresh_in_micro_hz = 360 core_freesync->map[index].caps->min_refresh_in_micro_hz; 361 ctx->nominal_refresh_in_micro_hz = core_freesync-> 362 map[index].state.nominal_refresh_rate_in_micro_hz; 363 364 } 365 366 static void update_stream(struct core_freesync *core_freesync, 367 const struct dc_stream *stream) 368 { 369 struct core_stream *core_stream = DC_STREAM_TO_CORE(stream); 370 371 unsigned int index = map_index_from_stream(core_freesync, stream); 372 if (core_freesync->map[index].caps->supported) { 373 core_stream->public.ignore_msa_timing_param = 1; 374 update_stream_freesync_context(core_freesync, stream); 375 } 376 } 377 378 static void calc_freesync_range(struct core_freesync *core_freesync, 379 const struct dc_stream *stream, 380 struct freesync_state *state, 381 unsigned int min_refresh_in_uhz, 382 unsigned int max_refresh_in_uhz) 383 { 384 unsigned int min_frame_duration_in_ns = 0, max_frame_duration_in_ns = 0; 385 unsigned int index = map_index_from_stream(core_freesync, stream); 386 uint32_t vtotal = stream->timing.v_total; 387 388 if ((min_refresh_in_uhz == 0) || (max_refresh_in_uhz == 0)) { 389 state->freesync_range.min_refresh = 390 state->nominal_refresh_rate_in_micro_hz; 391 state->freesync_range.max_refresh = 392 state->nominal_refresh_rate_in_micro_hz; 393 394 state->freesync_range.max_frame_duration = 0; 395 state->freesync_range.min_frame_duration = 0; 396 397 state->freesync_range.vmax = vtotal; 398 state->freesync_range.vmin = vtotal; 399 400 return; 401 } 402 403 min_frame_duration_in_ns = ((unsigned int) (div64_u64( 404 (1000000000ULL * 1000000), 405 max_refresh_in_uhz))); 406 max_frame_duration_in_ns = ((unsigned int) (div64_u64( 407 (1000000000ULL * 1000000), 408 min_refresh_in_uhz))); 409 410 state->freesync_range.min_refresh = min_refresh_in_uhz; 411 state->freesync_range.max_refresh = max_refresh_in_uhz; 412 413 state->freesync_range.max_frame_duration = max_frame_duration_in_ns; 414 state->freesync_range.min_frame_duration = min_frame_duration_in_ns; 415 416 state->freesync_range.vmax = div64_u64(div64_u64(((unsigned long long)( 417 max_frame_duration_in_ns) * stream->timing.pix_clk_khz), 418 stream->timing.h_total), 1000000); 419 state->freesync_range.vmin = div64_u64(div64_u64(((unsigned long long)( 420 min_frame_duration_in_ns) * stream->timing.pix_clk_khz), 421 stream->timing.h_total), 1000000); 422 423 /* In case of 4k free sync monitor, vmin or vmax cannot be less than vtotal */ 424 if (state->freesync_range.vmin < vtotal) { 425 ASSERT(false); 426 state->freesync_range.vmin = vtotal; 427 } 428 429 if (state->freesync_range.vmax < vtotal) { 430 ASSERT(false); 431 state->freesync_range.vmax = vtotal; 432 } 433 434 /* Determine whether BTR can be supported */ 435 if (max_frame_duration_in_ns >= 436 2 * min_frame_duration_in_ns) 437 core_freesync->map[index].caps->btr_supported = true; 438 else 439 core_freesync->map[index].caps->btr_supported = false; 440 441 /* Cache the time variables */ 442 state->time.max_render_time_in_us = 443 max_frame_duration_in_ns / 1000; 444 state->time.min_render_time_in_us = 445 min_frame_duration_in_ns / 1000; 446 state->btr.mid_point_in_us = 447 (max_frame_duration_in_ns + 448 min_frame_duration_in_ns) / 2000; 449 } 450 451 static void calc_v_total_from_duration(const struct dc_stream *stream, 452 unsigned int duration_in_ns, int *v_total_nominal) 453 { 454 *v_total_nominal = div64_u64(div64_u64(((unsigned long long)( 455 duration_in_ns) * stream->timing.pix_clk_khz), 456 stream->timing.h_total), 1000000); 457 } 458 459 static void calc_v_total_for_static_ramp(struct core_freesync *core_freesync, 460 const struct dc_stream *stream, 461 unsigned int index, int *v_total) 462 { 463 unsigned int frame_duration = 0; 464 465 struct gradual_static_ramp *static_ramp_variables = 466 &core_freesync->map[index].state.static_ramp; 467 468 /* Calc ratio between new and current frame duration with 3 digit */ 469 unsigned int frame_duration_ratio = div64_u64(1000000, 470 (1000 + div64_u64(((unsigned long long)( 471 STATIC_SCREEN_RAMP_DELTA_REFRESH_RATE_PER_FRAME) * 472 static_ramp_variables->ramp_current_frame_duration_in_ns), 473 1000000000))); 474 475 /* Calculate delta between new and current frame duration in ns */ 476 unsigned int frame_duration_delta = div64_u64(((unsigned long long)( 477 static_ramp_variables->ramp_current_frame_duration_in_ns) * 478 (1000 - frame_duration_ratio)), 1000); 479 480 /* Adjust frame duration delta based on ratio between current and 481 * standard frame duration (frame duration at 60 Hz refresh rate). 482 */ 483 unsigned int ramp_rate_interpolated = div64_u64(((unsigned long long)( 484 frame_duration_delta) * static_ramp_variables-> 485 ramp_current_frame_duration_in_ns), 16666666); 486 487 /* Going to a higher refresh rate (lower frame duration) */ 488 if (static_ramp_variables->ramp_direction_is_up) { 489 /* reduce frame duration */ 490 static_ramp_variables->ramp_current_frame_duration_in_ns -= 491 ramp_rate_interpolated; 492 493 /* min frame duration */ 494 frame_duration = ((unsigned int) (div64_u64( 495 (1000000000ULL * 1000000), 496 core_freesync->map[index].state. 497 nominal_refresh_rate_in_micro_hz))); 498 499 /* adjust for frame duration below min */ 500 if (static_ramp_variables->ramp_current_frame_duration_in_ns <= 501 frame_duration) { 502 503 static_ramp_variables->ramp_is_active = false; 504 static_ramp_variables-> 505 ramp_current_frame_duration_in_ns = 506 frame_duration; 507 } 508 /* Going to a lower refresh rate (larger frame duration) */ 509 } else { 510 /* increase frame duration */ 511 static_ramp_variables->ramp_current_frame_duration_in_ns += 512 ramp_rate_interpolated; 513 514 /* max frame duration */ 515 frame_duration = ((unsigned int) (div64_u64( 516 (1000000000ULL * 1000000), 517 core_freesync->map[index].caps->min_refresh_in_micro_hz))); 518 519 /* adjust for frame duration above max */ 520 if (static_ramp_variables->ramp_current_frame_duration_in_ns >= 521 frame_duration) { 522 523 static_ramp_variables->ramp_is_active = false; 524 static_ramp_variables-> 525 ramp_current_frame_duration_in_ns = 526 frame_duration; 527 } 528 } 529 530 calc_v_total_from_duration(stream, static_ramp_variables-> 531 ramp_current_frame_duration_in_ns, v_total); 532 } 533 534 static void reset_freesync_state_variables(struct freesync_state* state) 535 { 536 state->static_ramp.ramp_is_active = false; 537 if (state->nominal_refresh_rate_in_micro_hz) 538 state->static_ramp.ramp_current_frame_duration_in_ns = 539 ((unsigned int) (div64_u64( 540 (1000000000ULL * 1000000), 541 state->nominal_refresh_rate_in_micro_hz))); 542 543 state->btr.btr_active = false; 544 state->btr.frame_counter = 0; 545 state->btr.frames_to_insert = 0; 546 state->btr.inserted_frame_duration_in_us = 0; 547 state->btr.program_btr = false; 548 549 state->fixed_refresh.fixed_refresh_active = false; 550 state->fixed_refresh.program_fixed_refresh = false; 551 } 552 /* 553 * Sets freesync mode on a stream depending on current freesync state. 554 */ 555 static bool set_freesync_on_streams(struct core_freesync *core_freesync, 556 const struct dc_stream **streams, int num_streams) 557 { 558 int v_total_nominal = 0, v_total_min = 0, v_total_max = 0; 559 unsigned int stream_idx, map_index = 0; 560 struct freesync_state *state; 561 562 if (num_streams == 0 || streams == NULL || num_streams > 1) 563 return false; 564 565 for (stream_idx = 0; stream_idx < num_streams; stream_idx++) { 566 567 map_index = map_index_from_stream(core_freesync, 568 streams[stream_idx]); 569 570 state = &core_freesync->map[map_index].state; 571 572 if (core_freesync->map[map_index].caps->supported) { 573 574 /* Fullscreen has the topmost priority. If the 575 * fullscreen bit is set, we are in a fullscreen 576 * application where it should not matter if it is 577 * static screen. We should not check the static_screen 578 * or video bit. 579 * 580 * Special cases of fullscreen include btr and fixed 581 * refresh. We program btr on every flip and involves 582 * programming full range right before the last inserted frame. 583 * However, we do not want to program the full freesync range 584 * when fixed refresh is active, because we only program 585 * that logic once and this will override it. 586 */ 587 if (core_freesync->map[map_index].user_enable. 588 enable_for_gaming == true && 589 state->fullscreen == true && 590 state->fixed_refresh.fixed_refresh_active == false) { 591 /* Enable freesync */ 592 593 v_total_min = state->freesync_range.vmin; 594 v_total_max = state->freesync_range.vmax; 595 596 /* Update the freesync context for the stream */ 597 update_stream_freesync_context(core_freesync, 598 streams[stream_idx]); 599 600 core_freesync->dc->stream_funcs. 601 adjust_vmin_vmax(core_freesync->dc, streams, 602 num_streams, v_total_min, 603 v_total_max); 604 605 return true; 606 607 } else if (core_freesync->map[map_index].user_enable. 608 enable_for_video && state->video == true) { 609 /* Enable 48Hz feature */ 610 611 calc_v_total_from_duration(streams[stream_idx], 612 state->time.update_duration_in_ns, 613 &v_total_nominal); 614 615 /* Program only if v_total_nominal is in range*/ 616 if (v_total_nominal >= 617 streams[stream_idx]->timing.v_total) { 618 619 /* Update the freesync context for 620 * the stream 621 */ 622 update_stream_freesync_context( 623 core_freesync, 624 streams[stream_idx]); 625 626 core_freesync->dc->stream_funcs. 627 adjust_vmin_vmax( 628 core_freesync->dc, streams, 629 num_streams, v_total_nominal, 630 v_total_nominal); 631 } 632 return true; 633 634 } else { 635 /* Disable freesync */ 636 v_total_nominal = streams[stream_idx]-> 637 timing.v_total; 638 639 /* Update the freesync context for 640 * the stream 641 */ 642 update_stream_freesync_context( 643 core_freesync, 644 streams[stream_idx]); 645 646 core_freesync->dc->stream_funcs. 647 adjust_vmin_vmax( 648 core_freesync->dc, streams, 649 num_streams, v_total_nominal, 650 v_total_nominal); 651 652 /* Reset the cached variables */ 653 reset_freesync_state_variables(state); 654 655 return true; 656 } 657 } else { 658 /* Disable freesync */ 659 v_total_nominal = streams[stream_idx]-> 660 timing.v_total; 661 /* 662 * we have to reset drr always even sink does 663 * not support freesync because a former stream has 664 * be programmed 665 */ 666 core_freesync->dc->stream_funcs. 667 adjust_vmin_vmax( 668 core_freesync->dc, streams, 669 num_streams, v_total_nominal, 670 v_total_nominal); 671 /* Reset the cached variables */ 672 reset_freesync_state_variables(state); 673 } 674 675 } 676 677 return false; 678 } 679 680 static void set_static_ramp_variables(struct core_freesync *core_freesync, 681 unsigned int index, bool enable_static_screen) 682 { 683 unsigned int frame_duration = 0; 684 685 struct gradual_static_ramp *static_ramp_variables = 686 &core_freesync->map[index].state.static_ramp; 687 688 /* If ramp is not active, set initial frame duration depending on 689 * whether we are enabling/disabling static screen mode. If the ramp is 690 * already active, ramp should continue in the opposite direction 691 * starting with the current frame duration 692 */ 693 if (!static_ramp_variables->ramp_is_active) { 694 695 static_ramp_variables->ramp_is_active = true; 696 697 if (enable_static_screen == true) { 698 /* Going to lower refresh rate, so start from max 699 * refresh rate (min frame duration) 700 */ 701 frame_duration = ((unsigned int) (div64_u64( 702 (1000000000ULL * 1000000), 703 core_freesync->map[index].state. 704 nominal_refresh_rate_in_micro_hz))); 705 } else { 706 /* Going to higher refresh rate, so start from min 707 * refresh rate (max frame duration) 708 */ 709 frame_duration = ((unsigned int) (div64_u64( 710 (1000000000ULL * 1000000), 711 core_freesync->map[index].caps->min_refresh_in_micro_hz))); 712 } 713 714 static_ramp_variables-> 715 ramp_current_frame_duration_in_ns = frame_duration; 716 } 717 718 /* If we are ENABLING static screen, refresh rate should go DOWN. 719 * If we are DISABLING static screen, refresh rate should go UP. 720 */ 721 static_ramp_variables->ramp_direction_is_up = !enable_static_screen; 722 } 723 724 void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync, 725 const struct dc_stream **streams, int num_streams) 726 { 727 unsigned int index, v_total, inserted_frame_v_total = 0; 728 unsigned int min_frame_duration_in_ns, vmax, vmin = 0; 729 struct freesync_state *state; 730 struct core_freesync *core_freesync = NULL; 731 struct dc_static_screen_events triggers = {0}; 732 733 if (mod_freesync == NULL) 734 return; 735 736 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 737 738 if (core_freesync->num_entities == 0) 739 return; 740 741 index = map_index_from_stream(core_freesync, 742 streams[0]); 743 744 if (core_freesync->map[index].caps->supported == false) 745 return; 746 747 state = &core_freesync->map[index].state; 748 749 /* Below the Range Logic */ 750 751 /* Only execute if in fullscreen mode */ 752 if (state->fullscreen == true && 753 core_freesync->map[index].user_enable.enable_for_gaming && 754 core_freesync->map[index].caps->btr_supported && 755 state->btr.btr_active) { 756 757 /* TODO: pass in flag for Pre-DCE12 ASIC 758 * in order for frame variable duration to take affect, 759 * it needs to be done one VSYNC early, which is at 760 * frameCounter == 1. 761 * For DCE12 and newer updates to V_TOTAL_MIN/MAX 762 * will take affect on current frame 763 */ 764 if (state->btr.frames_to_insert == state->btr.frame_counter) { 765 766 min_frame_duration_in_ns = ((unsigned int) (div64_u64( 767 (1000000000ULL * 1000000), 768 state->nominal_refresh_rate_in_micro_hz))); 769 770 vmin = state->freesync_range.vmin; 771 772 inserted_frame_v_total = vmin; 773 774 if (min_frame_duration_in_ns / 1000) 775 inserted_frame_v_total = 776 state->btr.inserted_frame_duration_in_us * 777 vmin / (min_frame_duration_in_ns / 1000); 778 779 /* Set length of inserted frames as v_total_max*/ 780 vmax = inserted_frame_v_total; 781 vmin = inserted_frame_v_total; 782 783 /* Program V_TOTAL */ 784 core_freesync->dc->stream_funcs.adjust_vmin_vmax( 785 core_freesync->dc, streams, 786 num_streams, vmin, vmax); 787 } 788 789 if (state->btr.frame_counter > 0) 790 state->btr.frame_counter--; 791 792 /* Restore FreeSync */ 793 if (state->btr.frame_counter == 0) 794 set_freesync_on_streams(core_freesync, streams, num_streams); 795 } 796 797 /* If in fullscreen freesync mode or in video, do not program 798 * static screen ramp values 799 */ 800 if (state->fullscreen == true || state->video == true) { 801 802 state->static_ramp.ramp_is_active = false; 803 804 return; 805 } 806 807 /* Gradual Static Screen Ramping Logic */ 808 809 /* Execute if ramp is active and user enabled freesync static screen*/ 810 if (state->static_ramp.ramp_is_active && 811 core_freesync->map[index].user_enable.enable_for_static) { 812 813 calc_v_total_for_static_ramp(core_freesync, streams[0], 814 index, &v_total); 815 816 /* Update the freesync context for the stream */ 817 update_stream_freesync_context(core_freesync, streams[0]); 818 819 /* Program static screen ramp values */ 820 core_freesync->dc->stream_funcs.adjust_vmin_vmax( 821 core_freesync->dc, streams, 822 num_streams, v_total, 823 v_total); 824 825 triggers.overlay_update = true; 826 triggers.surface_update = true; 827 828 core_freesync->dc->stream_funcs.set_static_screen_events( 829 core_freesync->dc, streams, num_streams, 830 &triggers); 831 } 832 } 833 834 void mod_freesync_update_state(struct mod_freesync *mod_freesync, 835 const struct dc_stream **streams, int num_streams, 836 struct mod_freesync_params *freesync_params) 837 { 838 bool freesync_program_required = false; 839 unsigned int stream_index; 840 struct freesync_state *state; 841 struct core_freesync *core_freesync = NULL; 842 843 if (mod_freesync == NULL) 844 return; 845 846 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 847 848 if (core_freesync->num_entities == 0) 849 return; 850 851 for(stream_index = 0; stream_index < num_streams; stream_index++) { 852 853 unsigned int map_index = map_index_from_stream(core_freesync, 854 streams[stream_index]); 855 856 state = &core_freesync->map[map_index].state; 857 858 switch (freesync_params->state){ 859 case FREESYNC_STATE_FULLSCREEN: 860 state->fullscreen = freesync_params->enable; 861 freesync_program_required = true; 862 state->windowed_fullscreen = 863 freesync_params->windowed_fullscreen; 864 break; 865 case FREESYNC_STATE_STATIC_SCREEN: 866 /* Static screen ramp is only enabled for embedded 867 * panels. Also change core variables only if there 868 * is a change. 869 */ 870 if (dc_is_embedded_signal( 871 streams[stream_index]->sink->sink_signal) && 872 state->static_screen != 873 freesync_params->enable) { 874 875 /* Change the state flag */ 876 state->static_screen = freesync_params->enable; 877 878 /* Change static screen ramp variables */ 879 set_static_ramp_variables(core_freesync, 880 map_index, 881 freesync_params->enable); 882 } 883 /* We program the ramp starting next VUpdate */ 884 break; 885 case FREESYNC_STATE_VIDEO: 886 /* Change core variables only if there is a change*/ 887 if(freesync_params->update_duration_in_ns != 888 state->time.update_duration_in_ns) { 889 890 state->video = freesync_params->enable; 891 state->time.update_duration_in_ns = 892 freesync_params->update_duration_in_ns; 893 894 freesync_program_required = true; 895 } 896 break; 897 case FREESYNC_STATE_NONE: 898 /* handle here to avoid warning */ 899 break; 900 } 901 } 902 903 if (freesync_program_required) 904 /* Program freesync according to current state*/ 905 set_freesync_on_streams(core_freesync, streams, num_streams); 906 } 907 908 909 bool mod_freesync_get_state(struct mod_freesync *mod_freesync, 910 const struct dc_stream *stream, 911 struct mod_freesync_params *freesync_params) 912 { 913 unsigned int index = 0; 914 struct core_freesync *core_freesync = NULL; 915 916 if (mod_freesync == NULL) 917 return false; 918 919 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 920 index = map_index_from_stream(core_freesync, stream); 921 922 if (core_freesync->map[index].state.fullscreen) { 923 freesync_params->state = FREESYNC_STATE_FULLSCREEN; 924 freesync_params->enable = true; 925 } else if (core_freesync->map[index].state.static_screen) { 926 freesync_params->state = FREESYNC_STATE_STATIC_SCREEN; 927 freesync_params->enable = true; 928 } else if (core_freesync->map[index].state.video) { 929 freesync_params->state = FREESYNC_STATE_VIDEO; 930 freesync_params->enable = true; 931 } else { 932 freesync_params->state = FREESYNC_STATE_NONE; 933 freesync_params->enable = false; 934 } 935 936 freesync_params->update_duration_in_ns = 937 core_freesync->map[index].state.time.update_duration_in_ns; 938 939 freesync_params->windowed_fullscreen = 940 core_freesync->map[index].state.windowed_fullscreen; 941 942 return true; 943 } 944 945 bool mod_freesync_set_user_enable(struct mod_freesync *mod_freesync, 946 const struct dc_stream **streams, int num_streams, 947 struct mod_freesync_user_enable *user_enable) 948 { 949 unsigned int stream_index, map_index; 950 int persistent_data = 0; 951 struct persistent_data_flag flag; 952 struct core_dc *core_dc = NULL; 953 struct core_freesync *core_freesync = NULL; 954 955 if (mod_freesync == NULL) 956 return false; 957 958 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 959 core_dc = DC_TO_CORE(core_freesync->dc); 960 961 flag.save_per_edid = true; 962 flag.save_per_link = false; 963 964 for(stream_index = 0; stream_index < num_streams; 965 stream_index++){ 966 967 map_index = map_index_from_stream(core_freesync, 968 streams[stream_index]); 969 970 core_freesync->map[map_index].user_enable = *user_enable; 971 972 /* Write persistent data in registry*/ 973 if (core_freesync->map[map_index].user_enable. 974 enable_for_gaming) 975 persistent_data = persistent_data | 1; 976 if (core_freesync->map[map_index].user_enable. 977 enable_for_static) 978 persistent_data = persistent_data | 2; 979 if (core_freesync->map[map_index].user_enable. 980 enable_for_video) 981 persistent_data = persistent_data | 4; 982 983 dm_write_persistent_data(core_dc->ctx, 984 streams[stream_index]->sink, 985 FREESYNC_REGISTRY_NAME, 986 "userenable", 987 &persistent_data, 988 sizeof(int), 989 &flag); 990 } 991 992 set_freesync_on_streams(core_freesync, streams, num_streams); 993 994 return true; 995 } 996 997 bool mod_freesync_get_user_enable(struct mod_freesync *mod_freesync, 998 const struct dc_stream *stream, 999 struct mod_freesync_user_enable *user_enable) 1000 { 1001 unsigned int index = 0; 1002 struct core_freesync *core_freesync = NULL; 1003 1004 if (mod_freesync == NULL) 1005 return false; 1006 1007 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1008 index = map_index_from_stream(core_freesync, stream); 1009 1010 *user_enable = core_freesync->map[index].user_enable; 1011 1012 return true; 1013 } 1014 1015 bool mod_freesync_override_min_max(struct mod_freesync *mod_freesync, 1016 const struct dc_stream *streams, 1017 unsigned int min_refresh, 1018 unsigned int max_refresh) 1019 { 1020 unsigned int index = 0; 1021 struct core_freesync *core_freesync; 1022 struct freesync_state *state; 1023 1024 if (mod_freesync == NULL) 1025 return false; 1026 1027 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1028 index = map_index_from_stream(core_freesync, streams); 1029 state = &core_freesync->map[index].state; 1030 1031 if (min_refresh == 0 || max_refresh == 0) { 1032 /* Restore defaults */ 1033 calc_freesync_range(core_freesync, streams, state, 1034 core_freesync->map[index].caps-> 1035 min_refresh_in_micro_hz, 1036 state->nominal_refresh_rate_in_micro_hz); 1037 } else { 1038 calc_freesync_range(core_freesync, streams, 1039 state, 1040 min_refresh, 1041 max_refresh); 1042 1043 /* Program vtotal min/max */ 1044 core_freesync->dc->stream_funcs.adjust_vmin_vmax( 1045 core_freesync->dc, &streams, 1, 1046 state->freesync_range.vmin, 1047 state->freesync_range.vmax); 1048 } 1049 1050 return true; 1051 } 1052 1053 bool mod_freesync_get_min_max(struct mod_freesync *mod_freesync, 1054 const struct dc_stream *stream, 1055 unsigned int *min_refresh, 1056 unsigned int *max_refresh) 1057 { 1058 unsigned int index = 0; 1059 struct core_freesync *core_freesync = NULL; 1060 1061 if (mod_freesync == NULL) 1062 return false; 1063 1064 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1065 index = map_index_from_stream(core_freesync, stream); 1066 1067 *min_refresh = 1068 core_freesync->map[index].state.freesync_range.min_refresh; 1069 *max_refresh = 1070 core_freesync->map[index].state.freesync_range.max_refresh; 1071 1072 return true; 1073 } 1074 1075 bool mod_freesync_get_vmin_vmax(struct mod_freesync *mod_freesync, 1076 const struct dc_stream *stream, 1077 unsigned int *vmin, 1078 unsigned int *vmax) 1079 { 1080 unsigned int index = 0; 1081 struct core_freesync *core_freesync = NULL; 1082 1083 if (mod_freesync == NULL) 1084 return false; 1085 1086 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1087 index = map_index_from_stream(core_freesync, stream); 1088 1089 *vmin = 1090 core_freesync->map[index].state.freesync_range.vmin; 1091 *vmax = 1092 core_freesync->map[index].state.freesync_range.vmax; 1093 1094 return true; 1095 } 1096 1097 bool mod_freesync_get_v_position(struct mod_freesync *mod_freesync, 1098 const struct dc_stream *stream, 1099 unsigned int *nom_v_pos, 1100 unsigned int *v_pos) 1101 { 1102 unsigned int index = 0; 1103 struct core_freesync *core_freesync = NULL; 1104 struct crtc_position position; 1105 1106 if (mod_freesync == NULL) 1107 return false; 1108 1109 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1110 index = map_index_from_stream(core_freesync, stream); 1111 1112 if (core_freesync->dc->stream_funcs.get_crtc_position( 1113 core_freesync->dc, &stream, 1, 1114 &position.vertical_count, &position.nominal_vcount)) { 1115 1116 *nom_v_pos = position.vertical_count; 1117 *v_pos = position.nominal_vcount; 1118 1119 return true; 1120 } 1121 1122 return false; 1123 } 1124 1125 void mod_freesync_notify_mode_change(struct mod_freesync *mod_freesync, 1126 const struct dc_stream **streams, int num_streams) 1127 { 1128 unsigned int stream_index, map_index; 1129 struct freesync_state *state; 1130 struct core_freesync *core_freesync = NULL; 1131 1132 if (mod_freesync == NULL) 1133 return; 1134 1135 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1136 1137 for (stream_index = 0; stream_index < num_streams; stream_index++) { 1138 map_index = map_index_from_stream(core_freesync, 1139 streams[stream_index]); 1140 1141 state = &core_freesync->map[map_index].state; 1142 1143 if (core_freesync->map[map_index].caps->supported) { 1144 /* Update the field rate for new timing */ 1145 unsigned long long temp; 1146 temp = streams[stream_index]->timing.pix_clk_khz; 1147 temp *= 1000ULL * 1000ULL * 1000ULL; 1148 temp = div_u64(temp, 1149 streams[stream_index]->timing.h_total); 1150 temp = div_u64(temp, 1151 streams[stream_index]->timing.v_total); 1152 state->nominal_refresh_rate_in_micro_hz = 1153 (unsigned int) temp; 1154 1155 /* Update the stream */ 1156 update_stream(core_freesync, streams[stream_index]); 1157 1158 /* Calculate vmin/vmax and refresh rate for 1159 * current mode 1160 */ 1161 calc_freesync_range(core_freesync, *streams, state, 1162 core_freesync->map[map_index].caps-> 1163 min_refresh_in_micro_hz, 1164 state->nominal_refresh_rate_in_micro_hz); 1165 } 1166 } 1167 1168 /* Program freesync according to current state*/ 1169 set_freesync_on_streams(core_freesync, streams, num_streams); 1170 } 1171 1172 /* Add the timestamps to the cache and determine whether BTR programming 1173 * is required, depending on the times calculated 1174 */ 1175 static void update_timestamps(struct core_freesync *core_freesync, 1176 const struct dc_stream *stream, unsigned int map_index, 1177 unsigned int last_render_time_in_us) 1178 { 1179 struct freesync_state *state = &core_freesync->map[map_index].state; 1180 1181 state->time.render_times[state->time.render_times_index] = 1182 last_render_time_in_us; 1183 state->time.render_times_index++; 1184 1185 if (state->time.render_times_index >= RENDER_TIMES_MAX_COUNT) 1186 state->time.render_times_index = 0; 1187 1188 if (last_render_time_in_us + BTR_EXIT_MARGIN < 1189 state->time.max_render_time_in_us) { 1190 1191 /* Exit Below the Range */ 1192 if (state->btr.btr_active) { 1193 1194 state->btr.program_btr = true; 1195 state->btr.btr_active = false; 1196 state->btr.frame_counter = 0; 1197 1198 /* Exit Fixed Refresh mode */ 1199 } else if (state->fixed_refresh.fixed_refresh_active) { 1200 1201 state->fixed_refresh.program_fixed_refresh = true; 1202 state->fixed_refresh.fixed_refresh_active = false; 1203 1204 } 1205 1206 } else if (last_render_time_in_us > state->time.max_render_time_in_us) { 1207 1208 /* Enter Below the Range */ 1209 if (!state->btr.btr_active && 1210 core_freesync->map[map_index].caps->btr_supported) { 1211 1212 state->btr.program_btr = true; 1213 state->btr.btr_active = true; 1214 1215 /* Enter Fixed Refresh mode */ 1216 } else if (!state->fixed_refresh.fixed_refresh_active && 1217 !core_freesync->map[map_index].caps->btr_supported) { 1218 1219 state->fixed_refresh.program_fixed_refresh = true; 1220 state->fixed_refresh.fixed_refresh_active = true; 1221 1222 } 1223 } 1224 1225 /* When Below the Range is active, must react on every frame */ 1226 if (state->btr.btr_active) 1227 state->btr.program_btr = true; 1228 } 1229 1230 static void apply_below_the_range(struct core_freesync *core_freesync, 1231 const struct dc_stream *stream, unsigned int map_index, 1232 unsigned int last_render_time_in_us) 1233 { 1234 unsigned int inserted_frame_duration_in_us = 0; 1235 unsigned int mid_point_frames_ceil = 0; 1236 unsigned int mid_point_frames_floor = 0; 1237 unsigned int frame_time_in_us = 0; 1238 unsigned int delta_from_mid_point_in_us_1 = 0xFFFFFFFF; 1239 unsigned int delta_from_mid_point_in_us_2 = 0xFFFFFFFF; 1240 unsigned int frames_to_insert = 0; 1241 unsigned int min_frame_duration_in_ns = 0; 1242 struct freesync_state *state = &core_freesync->map[map_index].state; 1243 1244 if (!state->btr.program_btr) 1245 return; 1246 1247 state->btr.program_btr = false; 1248 1249 min_frame_duration_in_ns = ((unsigned int) (div64_u64( 1250 (1000000000ULL * 1000000), 1251 state->nominal_refresh_rate_in_micro_hz))); 1252 1253 /* Program BTR */ 1254 1255 /* BTR set to "not active" so disengage */ 1256 if (!state->btr.btr_active) 1257 1258 /* Restore FreeSync */ 1259 set_freesync_on_streams(core_freesync, &stream, 1); 1260 1261 /* BTR set to "active" so engage */ 1262 else { 1263 1264 /* Calculate number of midPoint frames that could fit within 1265 * the render time interval- take ceil of this value 1266 */ 1267 mid_point_frames_ceil = (last_render_time_in_us + 1268 state->btr.mid_point_in_us- 1) / 1269 state->btr.mid_point_in_us; 1270 1271 if (mid_point_frames_ceil > 0) { 1272 1273 frame_time_in_us = last_render_time_in_us / 1274 mid_point_frames_ceil; 1275 delta_from_mid_point_in_us_1 = (state->btr.mid_point_in_us > 1276 frame_time_in_us) ? 1277 (state->btr.mid_point_in_us - frame_time_in_us): 1278 (frame_time_in_us - state->btr.mid_point_in_us); 1279 } 1280 1281 /* Calculate number of midPoint frames that could fit within 1282 * the render time interval- take floor of this value 1283 */ 1284 mid_point_frames_floor = last_render_time_in_us / 1285 state->btr.mid_point_in_us; 1286 1287 if (mid_point_frames_floor > 0) { 1288 1289 frame_time_in_us = last_render_time_in_us / 1290 mid_point_frames_floor; 1291 delta_from_mid_point_in_us_2 = (state->btr.mid_point_in_us > 1292 frame_time_in_us) ? 1293 (state->btr.mid_point_in_us - frame_time_in_us): 1294 (frame_time_in_us - state->btr.mid_point_in_us); 1295 } 1296 1297 /* Choose number of frames to insert based on how close it 1298 * can get to the mid point of the variable range. 1299 */ 1300 if (delta_from_mid_point_in_us_1 < delta_from_mid_point_in_us_2) 1301 frames_to_insert = mid_point_frames_ceil; 1302 else 1303 frames_to_insert = mid_point_frames_floor; 1304 1305 /* Either we've calculated the number of frames to insert, 1306 * or we need to insert min duration frames 1307 */ 1308 if (frames_to_insert > 0) 1309 inserted_frame_duration_in_us = last_render_time_in_us / 1310 frames_to_insert; 1311 1312 if (inserted_frame_duration_in_us < 1313 state->time.min_render_time_in_us) 1314 1315 inserted_frame_duration_in_us = 1316 state->time.min_render_time_in_us; 1317 1318 /* Cache the calculated variables */ 1319 state->btr.inserted_frame_duration_in_us = 1320 inserted_frame_duration_in_us; 1321 state->btr.frames_to_insert = frames_to_insert; 1322 state->btr.frame_counter = frames_to_insert; 1323 1324 } 1325 } 1326 1327 static void apply_fixed_refresh(struct core_freesync *core_freesync, 1328 const struct dc_stream *stream, unsigned int map_index) 1329 { 1330 unsigned int vmin = 0, vmax = 0; 1331 struct freesync_state *state = &core_freesync->map[map_index].state; 1332 1333 if (!state->fixed_refresh.program_fixed_refresh) 1334 return; 1335 1336 state->fixed_refresh.program_fixed_refresh = false; 1337 1338 /* Program Fixed Refresh */ 1339 1340 /* Fixed Refresh set to "not active" so disengage */ 1341 if (!state->fixed_refresh.fixed_refresh_active) { 1342 set_freesync_on_streams(core_freesync, &stream, 1); 1343 1344 /* Fixed Refresh set to "active" so engage (fix to max) */ 1345 } else { 1346 1347 vmin = state->freesync_range.vmin; 1348 1349 vmax = vmin; 1350 1351 core_freesync->dc->stream_funcs.adjust_vmin_vmax( 1352 core_freesync->dc, &stream, 1353 1, vmin, 1354 vmax); 1355 } 1356 } 1357 1358 void mod_freesync_pre_update_plane_addresses(struct mod_freesync *mod_freesync, 1359 const struct dc_stream **streams, int num_streams, 1360 unsigned int curr_time_stamp_in_us) 1361 { 1362 unsigned int stream_index, map_index, last_render_time_in_us = 0; 1363 struct core_freesync *core_freesync = NULL; 1364 1365 if (mod_freesync == NULL) 1366 return; 1367 1368 core_freesync = MOD_FREESYNC_TO_CORE(mod_freesync); 1369 1370 for (stream_index = 0; stream_index < num_streams; stream_index++) { 1371 1372 map_index = map_index_from_stream(core_freesync, 1373 streams[stream_index]); 1374 1375 if (core_freesync->map[map_index].caps->supported) { 1376 1377 last_render_time_in_us = curr_time_stamp_in_us - 1378 core_freesync->map[map_index].state.time. 1379 prev_time_stamp_in_us; 1380 1381 /* Add the timestamps to the cache and determine 1382 * whether BTR program is required 1383 */ 1384 update_timestamps(core_freesync, streams[stream_index], 1385 map_index, last_render_time_in_us); 1386 1387 if (core_freesync->map[map_index].state.fullscreen && 1388 core_freesync->map[map_index].user_enable. 1389 enable_for_gaming) { 1390 1391 if (core_freesync->map[map_index].caps->btr_supported) { 1392 1393 apply_below_the_range(core_freesync, 1394 streams[stream_index], map_index, 1395 last_render_time_in_us); 1396 } else { 1397 apply_fixed_refresh(core_freesync, 1398 streams[stream_index], map_index); 1399 } 1400 } 1401 1402 core_freesync->map[map_index].state.time. 1403 prev_time_stamp_in_us = curr_time_stamp_in_us; 1404 } 1405 1406 } 1407 } 1408