|
31 | 31 |
|
32 | 32 | #import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
|
33 | 33 |
|
34 |
| -static const PGDisplayCoord_t apple_gfx_modes[] = { |
35 |
| - { .x = 1440, .y = 1080 }, |
36 |
| - { .x = 1280, .y = 1024 }, |
| 34 | +static const AppleGFXDisplayMode apple_gfx_default_modes[] = { |
| 35 | + { 1920, 1080, 60 }, |
| 36 | + { 1440, 1080, 60 }, |
| 37 | + { 1280, 1024, 60 }, |
37 | 38 | };
|
38 | 39 |
|
39 | 40 | static Error *apple_gfx_mig_blocker;
|
@@ -690,22 +691,23 @@ static void new_frame_handler_bh(void *opaque)
|
690 | 691 | return disp_desc;
|
691 | 692 | }
|
692 | 693 |
|
693 |
| -static NSArray<PGDisplayMode*>* apple_gfx_prepare_display_mode_array(void) |
| 694 | +static NSArray<PGDisplayMode *> *apple_gfx_create_display_mode_array( |
| 695 | + const AppleGFXDisplayMode display_modes[], uint32_t display_mode_count) |
694 | 696 | {
|
695 |
| - PGDisplayMode *modes[ARRAY_SIZE(apple_gfx_modes)]; |
696 |
| - NSArray<PGDisplayMode*>* mode_array; |
697 |
| - int i; |
698 |
| - |
699 |
| - for (i = 0; i < ARRAY_SIZE(apple_gfx_modes); i++) { |
700 |
| - modes[i] = |
701 |
| - [[PGDisplayMode alloc] initWithSizeInPixels:apple_gfx_modes[i] refreshRateInHz:60.]; |
702 |
| - } |
703 |
| - |
704 |
| - mode_array = [NSArray arrayWithObjects:modes count:ARRAY_SIZE(apple_gfx_modes)]; |
705 |
| - |
706 |
| - for (i = 0; i < ARRAY_SIZE(apple_gfx_modes); i++) { |
707 |
| - [modes[i] release]; |
708 |
| - modes[i] = nil; |
| 697 | + PGDisplayMode *mode_obj; |
| 698 | + NSMutableArray<PGDisplayMode *> *mode_array = |
| 699 | + [[NSMutableArray alloc] initWithCapacity:display_mode_count]; |
| 700 | + |
| 701 | + for (unsigned i = 0; i < display_mode_count; i++) { |
| 702 | + const AppleGFXDisplayMode *mode = &display_modes[i]; |
| 703 | + trace_apple_gfx_display_mode(i, mode->width_px, mode->height_px); |
| 704 | + PGDisplayCoord_t mode_size = { mode->width_px, mode->height_px }; |
| 705 | + |
| 706 | + mode_obj = |
| 707 | + [[PGDisplayMode alloc] initWithSizeInPixels:mode_size |
| 708 | + refreshRateInHz:mode->refresh_rate_hz]; |
| 709 | + [mode_array addObject:mode_obj]; |
| 710 | + [mode_obj release]; |
709 | 711 | }
|
710 | 712 |
|
711 | 713 | return mode_array;
|
@@ -741,6 +743,9 @@ bool apple_gfx_common_realize(AppleGFXState *s, DeviceState *dev,
|
741 | 743 | PGDeviceDescriptor *desc, Error **errp)
|
742 | 744 | {
|
743 | 745 | PGDisplayDescriptor *disp_desc;
|
| 746 | + const AppleGFXDisplayMode *display_modes = apple_gfx_default_modes; |
| 747 | + uint32_t num_display_modes = ARRAY_SIZE(apple_gfx_default_modes); |
| 748 | + NSArray<PGDisplayMode *> *mode_array; |
744 | 749 |
|
745 | 750 | if (apple_gfx_mig_blocker == NULL) {
|
746 | 751 | error_setg(&apple_gfx_mig_blocker,
|
@@ -776,8 +781,99 @@ bool apple_gfx_common_realize(AppleGFXState *s, DeviceState *dev,
|
776 | 781 | port:0
|
777 | 782 | serialNum:next_pgdisplay_serial_num++];
|
778 | 783 | [disp_desc release];
|
779 |
| - s->pgdisp.modeList = apple_gfx_prepare_display_mode_array(); |
| 784 | + |
| 785 | + if (s->display_modes != NULL && s->num_display_modes > 0) { |
| 786 | + trace_apple_gfx_common_realize_modes_property(s->num_display_modes); |
| 787 | + display_modes = s->display_modes; |
| 788 | + num_display_modes = s->num_display_modes; |
| 789 | + } |
| 790 | + s->pgdisp.modeList = mode_array = |
| 791 | + apple_gfx_create_display_mode_array(display_modes, num_display_modes); |
| 792 | + [mode_array release]; |
780 | 793 |
|
781 | 794 | s->con = graphic_console_init(dev, 0, &apple_gfx_fb_ops, s);
|
782 | 795 | return true;
|
783 | 796 | }
|
| 797 | + |
| 798 | +/* ------ Display mode list device property ------ */ |
| 799 | + |
| 800 | +static void apple_gfx_get_display_mode(Object *obj, Visitor *v, |
| 801 | + const char *name, void *opaque, |
| 802 | + Error **errp) |
| 803 | +{ |
| 804 | + Property *prop = opaque; |
| 805 | + AppleGFXDisplayMode *mode = object_field_prop_ptr(obj, prop); |
| 806 | + /* 3 uint16s (max 5 digits) + 2 separator characters + nul. */ |
| 807 | + char buffer[5 * 3 + 2 + 1]; |
| 808 | + char *pos = buffer; |
| 809 | + |
| 810 | + int rc = snprintf(buffer, sizeof(buffer), |
| 811 | + "%"PRIu16"x%"PRIu16"@%"PRIu16, |
| 812 | + mode->width_px, mode->height_px, |
| 813 | + mode->refresh_rate_hz); |
| 814 | + assert(rc < sizeof(buffer)); |
| 815 | + |
| 816 | + visit_type_str(v, name, &pos, errp); |
| 817 | +} |
| 818 | + |
| 819 | +static void apple_gfx_set_display_mode(Object *obj, Visitor *v, |
| 820 | + const char *name, void *opaque, |
| 821 | + Error **errp) |
| 822 | +{ |
| 823 | + Property *prop = opaque; |
| 824 | + AppleGFXDisplayMode *mode = object_field_prop_ptr(obj, prop); |
| 825 | + const char *endptr; |
| 826 | + g_autofree char *str = NULL; |
| 827 | + int ret; |
| 828 | + int val; |
| 829 | + |
| 830 | + if (!visit_type_str(v, name, &str, errp)) { |
| 831 | + return; |
| 832 | + } |
| 833 | + |
| 834 | + endptr = str; |
| 835 | + |
| 836 | + ret = qemu_strtoi(endptr, &endptr, 10, &val); |
| 837 | + if (ret || val > UINT16_MAX || val <= 0) { |
| 838 | + error_setg(errp, "width in '%s' must be a decimal integer number" |
| 839 | + " of pixels in the range 1..65535", name); |
| 840 | + return; |
| 841 | + } |
| 842 | + mode->width_px = val; |
| 843 | + if (*endptr != 'x') { |
| 844 | + goto separator_error; |
| 845 | + } |
| 846 | + |
| 847 | + ret = qemu_strtoi(endptr + 1, &endptr, 10, &val); |
| 848 | + if (ret || val > UINT16_MAX || val <= 0) { |
| 849 | + error_setg(errp, "height in '%s' must be a decimal integer number" |
| 850 | + " of pixels in the range 1..65535", name); |
| 851 | + return; |
| 852 | + } |
| 853 | + mode->height_px = val; |
| 854 | + if (*endptr != '@') { |
| 855 | + goto separator_error; |
| 856 | + } |
| 857 | + |
| 858 | + ret = qemu_strtoi(endptr + 1, &endptr, 10, &val); |
| 859 | + if (ret || val > UINT16_MAX || val <= 0) { |
| 860 | + error_setg(errp, "refresh rate in '%s'" |
| 861 | + " must be a positive decimal integer (Hertz)", name); |
| 862 | + return; |
| 863 | + } |
| 864 | + mode->refresh_rate_hz = val; |
| 865 | + return; |
| 866 | + |
| 867 | +separator_error: |
| 868 | + error_setg(errp, |
| 869 | + "Each display mode takes the format '<width>x<height>@<rate>'"); |
| 870 | +} |
| 871 | + |
| 872 | +const PropertyInfo qdev_prop_apple_gfx_display_mode = { |
| 873 | + .name = "display_mode", |
| 874 | + .description = |
| 875 | + "Display mode in pixels and Hertz, as <width>x<height>@<refresh-rate> " |
| 876 | + "Example: 3840x2160@60", |
| 877 | + .get = apple_gfx_get_display_mode, |
| 878 | + .set = apple_gfx_set_display_mode, |
| 879 | +}; |
0 commit comments