|
@@ -31,9 +31,10 @@
|
|
|
|
|
|
#import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
|
|
|
|
|
|
-static const PGDisplayCoord_t apple_gfx_modes[] = {
|
|
|
- { .x = 1440, .y = 1080 },
|
|
|
- { .x = 1280, .y = 1024 },
|
|
|
+static const AppleGFXDisplayMode apple_gfx_default_modes[] = {
|
|
|
+ { 1920, 1080, 60 },
|
|
|
+ { 1440, 1080, 60 },
|
|
|
+ { 1280, 1024, 60 },
|
|
|
};
|
|
|
|
|
|
static Error *apple_gfx_mig_blocker;
|
|
@@ -690,22 +691,23 @@ static void new_frame_handler_bh(void *opaque)
|
|
|
return disp_desc;
|
|
|
}
|
|
|
|
|
|
-static NSArray<PGDisplayMode*>* apple_gfx_prepare_display_mode_array(void)
|
|
|
+static NSArray<PGDisplayMode *> *apple_gfx_create_display_mode_array(
|
|
|
+ const AppleGFXDisplayMode display_modes[], uint32_t display_mode_count)
|
|
|
{
|
|
|
- PGDisplayMode *modes[ARRAY_SIZE(apple_gfx_modes)];
|
|
|
- NSArray<PGDisplayMode*>* mode_array;
|
|
|
- int i;
|
|
|
-
|
|
|
- for (i = 0; i < ARRAY_SIZE(apple_gfx_modes); i++) {
|
|
|
- modes[i] =
|
|
|
- [[PGDisplayMode alloc] initWithSizeInPixels:apple_gfx_modes[i] refreshRateInHz:60.];
|
|
|
- }
|
|
|
-
|
|
|
- mode_array = [NSArray arrayWithObjects:modes count:ARRAY_SIZE(apple_gfx_modes)];
|
|
|
-
|
|
|
- for (i = 0; i < ARRAY_SIZE(apple_gfx_modes); i++) {
|
|
|
- [modes[i] release];
|
|
|
- modes[i] = nil;
|
|
|
+ PGDisplayMode *mode_obj;
|
|
|
+ NSMutableArray<PGDisplayMode *> *mode_array =
|
|
|
+ [[NSMutableArray alloc] initWithCapacity:display_mode_count];
|
|
|
+
|
|
|
+ for (unsigned i = 0; i < display_mode_count; i++) {
|
|
|
+ const AppleGFXDisplayMode *mode = &display_modes[i];
|
|
|
+ trace_apple_gfx_display_mode(i, mode->width_px, mode->height_px);
|
|
|
+ PGDisplayCoord_t mode_size = { mode->width_px, mode->height_px };
|
|
|
+
|
|
|
+ mode_obj =
|
|
|
+ [[PGDisplayMode alloc] initWithSizeInPixels:mode_size
|
|
|
+ refreshRateInHz:mode->refresh_rate_hz];
|
|
|
+ [mode_array addObject:mode_obj];
|
|
|
+ [mode_obj release];
|
|
|
}
|
|
|
|
|
|
return mode_array;
|
|
@@ -741,6 +743,9 @@ bool apple_gfx_common_realize(AppleGFXState *s, DeviceState *dev,
|
|
|
PGDeviceDescriptor *desc, Error **errp)
|
|
|
{
|
|
|
PGDisplayDescriptor *disp_desc;
|
|
|
+ const AppleGFXDisplayMode *display_modes = apple_gfx_default_modes;
|
|
|
+ uint32_t num_display_modes = ARRAY_SIZE(apple_gfx_default_modes);
|
|
|
+ NSArray<PGDisplayMode *> *mode_array;
|
|
|
|
|
|
if (apple_gfx_mig_blocker == NULL) {
|
|
|
error_setg(&apple_gfx_mig_blocker,
|
|
@@ -776,8 +781,99 @@ bool apple_gfx_common_realize(AppleGFXState *s, DeviceState *dev,
|
|
|
port:0
|
|
|
serialNum:next_pgdisplay_serial_num++];
|
|
|
[disp_desc release];
|
|
|
- s->pgdisp.modeList = apple_gfx_prepare_display_mode_array();
|
|
|
+
|
|
|
+ if (s->display_modes != NULL && s->num_display_modes > 0) {
|
|
|
+ trace_apple_gfx_common_realize_modes_property(s->num_display_modes);
|
|
|
+ display_modes = s->display_modes;
|
|
|
+ num_display_modes = s->num_display_modes;
|
|
|
+ }
|
|
|
+ s->pgdisp.modeList = mode_array =
|
|
|
+ apple_gfx_create_display_mode_array(display_modes, num_display_modes);
|
|
|
+ [mode_array release];
|
|
|
|
|
|
s->con = graphic_console_init(dev, 0, &apple_gfx_fb_ops, s);
|
|
|
return true;
|
|
|
}
|
|
|
+
|
|
|
+/* ------ Display mode list device property ------ */
|
|
|
+
|
|
|
+static void apple_gfx_get_display_mode(Object *obj, Visitor *v,
|
|
|
+ const char *name, void *opaque,
|
|
|
+ Error **errp)
|
|
|
+{
|
|
|
+ Property *prop = opaque;
|
|
|
+ AppleGFXDisplayMode *mode = object_field_prop_ptr(obj, prop);
|
|
|
+ /* 3 uint16s (max 5 digits) + 2 separator characters + nul. */
|
|
|
+ char buffer[5 * 3 + 2 + 1];
|
|
|
+ char *pos = buffer;
|
|
|
+
|
|
|
+ int rc = snprintf(buffer, sizeof(buffer),
|
|
|
+ "%"PRIu16"x%"PRIu16"@%"PRIu16,
|
|
|
+ mode->width_px, mode->height_px,
|
|
|
+ mode->refresh_rate_hz);
|
|
|
+ assert(rc < sizeof(buffer));
|
|
|
+
|
|
|
+ visit_type_str(v, name, &pos, errp);
|
|
|
+}
|
|
|
+
|
|
|
+static void apple_gfx_set_display_mode(Object *obj, Visitor *v,
|
|
|
+ const char *name, void *opaque,
|
|
|
+ Error **errp)
|
|
|
+{
|
|
|
+ Property *prop = opaque;
|
|
|
+ AppleGFXDisplayMode *mode = object_field_prop_ptr(obj, prop);
|
|
|
+ const char *endptr;
|
|
|
+ g_autofree char *str = NULL;
|
|
|
+ int ret;
|
|
|
+ int val;
|
|
|
+
|
|
|
+ if (!visit_type_str(v, name, &str, errp)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ endptr = str;
|
|
|
+
|
|
|
+ ret = qemu_strtoi(endptr, &endptr, 10, &val);
|
|
|
+ if (ret || val > UINT16_MAX || val <= 0) {
|
|
|
+ error_setg(errp, "width in '%s' must be a decimal integer number"
|
|
|
+ " of pixels in the range 1..65535", name);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ mode->width_px = val;
|
|
|
+ if (*endptr != 'x') {
|
|
|
+ goto separator_error;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = qemu_strtoi(endptr + 1, &endptr, 10, &val);
|
|
|
+ if (ret || val > UINT16_MAX || val <= 0) {
|
|
|
+ error_setg(errp, "height in '%s' must be a decimal integer number"
|
|
|
+ " of pixels in the range 1..65535", name);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ mode->height_px = val;
|
|
|
+ if (*endptr != '@') {
|
|
|
+ goto separator_error;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = qemu_strtoi(endptr + 1, &endptr, 10, &val);
|
|
|
+ if (ret || val > UINT16_MAX || val <= 0) {
|
|
|
+ error_setg(errp, "refresh rate in '%s'"
|
|
|
+ " must be a positive decimal integer (Hertz)", name);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ mode->refresh_rate_hz = val;
|
|
|
+ return;
|
|
|
+
|
|
|
+separator_error:
|
|
|
+ error_setg(errp,
|
|
|
+ "Each display mode takes the format '<width>x<height>@<rate>'");
|
|
|
+}
|
|
|
+
|
|
|
+const PropertyInfo qdev_prop_apple_gfx_display_mode = {
|
|
|
+ .name = "display_mode",
|
|
|
+ .description =
|
|
|
+ "Display mode in pixels and Hertz, as <width>x<height>@<refresh-rate> "
|
|
|
+ "Example: 3840x2160@60",
|
|
|
+ .get = apple_gfx_get_display_mode,
|
|
|
+ .set = apple_gfx_set_display_mode,
|
|
|
+};
|