Skip to content

Commit bb43a23

Browse files
pmjphilmd
authored andcommitted
hw/display/apple-gfx: Adds configurable mode list
This change adds a property 'display_modes' on the graphics device which permits specifying a list of display modes. (screen resolution and refresh rate) The property is an array of a custom type to make the syntax slightly less awkward to use, for example: -device '{"driver":"apple-gfx-pci", "display-modes":["1920x1080@60", "3840x2160@60"]}' Signed-off-by: Phil Dennis-Jordan <[email protected]> Reviewed-by: Akihiko Odaki <[email protected]> Tested-by: Akihiko Odaki <[email protected]> Message-ID: <[email protected]> Signed-off-by: Philippe Mathieu-Daudé <[email protected]>
1 parent b21f17c commit bb43a23

File tree

5 files changed

+141
-20
lines changed

5 files changed

+141
-20
lines changed

hw/display/apple-gfx-mmio.m

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,11 @@ static void apple_gfx_mmio_reset(Object *obj, ResetType type)
255255
[s->common.pgdev reset];
256256
}
257257

258+
static const Property apple_gfx_mmio_properties[] = {
259+
DEFINE_PROP_ARRAY("display-modes", AppleGFXMMIOState,
260+
common.num_display_modes, common.display_modes,
261+
qdev_prop_apple_gfx_display_mode, AppleGFXDisplayMode),
262+
};
258263

259264
static void apple_gfx_mmio_class_init(ObjectClass *klass, void *data)
260265
{
@@ -264,6 +269,8 @@ static void apple_gfx_mmio_class_init(ObjectClass *klass, void *data)
264269
rc->phases.hold = apple_gfx_mmio_reset;
265270
dc->hotpluggable = false;
266271
dc->realize = apple_gfx_mmio_realize;
272+
273+
device_class_set_props(dc, apple_gfx_mmio_properties);
267274
}
268275

269276
static const TypeInfo apple_gfx_mmio_types[] = {

hw/display/apple-gfx-pci.m

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ static void apple_gfx_pci_reset(Object *obj, ResetType type)
115115
[s->common.pgdev reset];
116116
}
117117

118+
static const Property apple_gfx_pci_properties[] = {
119+
DEFINE_PROP_ARRAY("display-modes", AppleGFXPCIState,
120+
common.num_display_modes, common.display_modes,
121+
qdev_prop_apple_gfx_display_mode, AppleGFXDisplayMode),
122+
};
123+
118124
static void apple_gfx_pci_class_init(ObjectClass *klass, void *data)
119125
{
120126
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -131,7 +137,7 @@ static void apple_gfx_pci_class_init(ObjectClass *klass, void *data)
131137
pci->class_id = PCI_CLASS_DISPLAY_OTHER;
132138
pci->realize = apple_gfx_pci_realize;
133139

134-
/* TODO: Property for setting mode list */
140+
device_class_set_props(dc, apple_gfx_pci_properties);
135141
}
136142

137143
static const TypeInfo apple_gfx_pci_types[] = {

hw/display/apple-gfx.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@
2525

2626
typedef QTAILQ_HEAD(, PGTask_s) PGTaskList;
2727

28+
typedef struct AppleGFXDisplayMode {
29+
uint16_t width_px;
30+
uint16_t height_px;
31+
uint16_t refresh_rate_hz;
32+
} AppleGFXDisplayMode;
33+
2834
typedef struct AppleGFXState {
2935
/* Initialised on init/realize() */
3036
MemoryRegion iomem_gfx;
@@ -33,6 +39,8 @@ typedef struct AppleGFXState {
3339
QemuConsole *con;
3440
id<MTLDevice> mtl;
3541
id<MTLCommandQueue> mtl_queue;
42+
AppleGFXDisplayMode *display_modes;
43+
uint32_t num_display_modes;
3644

3745
/* List `tasks` is protected by task_mutex */
3846
QemuMutex task_mutex;
@@ -60,5 +68,7 @@ void *apple_gfx_host_ptr_for_gpa_range(uint64_t guest_physical,
6068
uint64_t length, bool read_only,
6169
MemoryRegion **mapping_in_region);
6270

71+
extern const PropertyInfo qdev_prop_apple_gfx_display_mode;
72+
6373
#endif
6474

hw/display/apple-gfx.m

Lines changed: 115 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@
3131

3232
#import <ParavirtualizedGraphics/ParavirtualizedGraphics.h>
3333

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 },
3738
};
3839

3940
static Error *apple_gfx_mig_blocker;
@@ -690,22 +691,23 @@ static void new_frame_handler_bh(void *opaque)
690691
return disp_desc;
691692
}
692693

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)
694696
{
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];
709711
}
710712

711713
return mode_array;
@@ -741,6 +743,9 @@ bool apple_gfx_common_realize(AppleGFXState *s, DeviceState *dev,
741743
PGDeviceDescriptor *desc, Error **errp)
742744
{
743745
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;
744749

745750
if (apple_gfx_mig_blocker == NULL) {
746751
error_setg(&apple_gfx_mig_blocker,
@@ -776,8 +781,99 @@ bool apple_gfx_common_realize(AppleGFXState *s, DeviceState *dev,
776781
port:0
777782
serialNum:next_pgdisplay_serial_num++];
778783
[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];
780793

781794
s->con = graphic_console_init(dev, 0, &apple_gfx_fb_ops, s);
782795
return true;
783796
}
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+
};

hw/display/trace-events

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,8 @@ apple_gfx_cursor_set(uint32_t bpp, uint64_t width, uint64_t height) "bpp=%d widt
212212
apple_gfx_cursor_show(uint32_t show) "show=%d"
213213
apple_gfx_cursor_move(void) ""
214214
apple_gfx_common_init(const char *device_name, size_t mmio_size) "device: %s; MMIO size: %zu bytes"
215+
apple_gfx_common_realize_modes_property(uint32_t num_modes) "using %u modes supplied by 'display-modes' device property"
216+
apple_gfx_display_mode(uint32_t mode_idx, uint16_t width_px, uint16_t height_px) "mode %2"PRIu32": %4"PRIu16"x%4"PRIu16
215217

216218
# apple-gfx-mmio.m
217219
apple_gfx_mmio_iosfc_read(uint64_t offset, uint64_t res) "offset=0x%"PRIx64" res=0x%"PRIx64

0 commit comments

Comments
 (0)