qemu-riscv
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v10 02/15] hw/display/apple-gfx: Introduce ParavirtualizedGra


From: Phil Dennis-Jordan
Subject: Re: [PATCH v10 02/15] hw/display/apple-gfx: Introduce ParavirtualizedGraphics.Framework support
Date: Wed, 27 Nov 2024 11:26:08 +0100



On Wed, 27 Nov 2024 at 07:18, Akihiko Odaki <akihiko.odaki@daynix.com> wrote:
On 2024/11/13 23:23, Phil Dennis-Jordan wrote:
[…]
> +static void apple_gfx_render_new_frame(AppleGFXState *s)
> +{
> +    bool managed_texture = s->using_managed_texture_storage;
> +    uint32_t width = surface_width(s->surface);
> +    uint32_t height = surface_height(s->surface);
> +    MTLRegion region = MTLRegionMake2D(0, 0, width, height);
> +    id<MTLCommandBuffer> command_buffer = [s->mtl_queue commandBuffer];

The documentation says:
 > Create a command encoder from an MTLCommandQueue instance by calling
 > its commandBuffer method. Typically, you create one or more command
 > queues when your app launches and then keep them throughout your app’s
 > lifetime.
https://developer.apple.com/documentation/metal/mtlcommandbuffer?language=objc

So let's do so.

This is already what we do - we have only one MTLCommandQueue, s->mtl_queue, which is long-lived and created during _realize().

The documentation phrasing is a little awkward because it inserts the bit about command encoders and commandBuffers in between the discussion of command queues. To be clear, it is only the command *queue* which can be long-lived. Command *buffers* are explicitly short-lived, once you call the commit method on them, you cannot use them again for anything else:

https://developer.apple.com/documentation/metal/mtlcommandbuffer/1443003-commit?language=objc

Similarly, the command *encoders* are even shorter-lived, because they are (a) tied to a particular command buffer instance, which is already short-lived in itself, and (b) you must call endEncoding on the current encoder (and thus make it unusable) before using another kind of command encoder on the same command buffer.

So I don't see any meaningful change we can make here.

> +    id<MTLTexture> texture = s->texture;
> +
> +    assert(bql_locked());
> +    [texture retain];
> +
> +    s->rendering_frame_width = width;
> +    s->rendering_frame_height = height;
> +
> +    dispatch_async(s->render_queue, ^{
> +        /*
> +         * This is not safe to call from the BQL due to PVG-internal locks
> +         * causing deadlocks.
> +         */
> +        bool r = [s->pgdisp encodeCurrentFrameToCommandBuffer:command_buffer
> +                                                 texture:texture
> +                                                  region:region];
> +        if (!r) {
> +            [texture release];
> +            bql_lock();
> +            --s->pending_frames;
> +            bql_unlock();
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "%s: encodeCurrentFrameToCommandBuffer:texture:region: "
> +                          "failed\n", __func__);
> +            return;
> +        }
> +
> +        if (managed_texture) {
> +            /* "Managed" textures exist in both VRAM and RAM and must be synced. */
> +            id<MTLBlitCommandEncoder> blit = [command_buffer blitCommandEncoder];
> +            [blit synchronizeResource:texture];
> +            [blit endEncoding];
> +        }
> +        [texture release];
> +        [command_buffer addCompletedHandler:
> +            ^(id<MTLCommandBuffer> cb)
> +            {
> +                aio_bh_schedule_oneshot(qemu_get_aio_context(),
> +                                        apple_gfx_render_frame_completed_bh, s);
> +
> +            }];
> +        [command_buffer commit];
> +    });
> +}
> +
> +static void copy_mtl_texture_to_surface_mem(id<MTLTexture> texture, void *vram)
> +{
> +    /*
> +     * TODO: Skip this entirely on a pure Metal or headless/guest-only
> +     * rendering path, else use a blit command encoder? Needs careful
> +     * (double?) buffering design.
> +     */
> +    size_t width = texture.width, height = texture.height;
> +    MTLRegion region = MTLRegionMake2D(0, 0, width, height);
> +    [texture getBytes:vram
> +          bytesPerRow:(width * 4)
> +        bytesPerImage:(width * height * 4)
> +           fromRegion:region
> +          mipmapLevel:0
> +                slice:0];
> +}
> +
> +static void apple_gfx_render_frame_completed_bh(void *opaque)
> +{
> +    AppleGFXState *s = opaque;
> +
> +    --s->pending_frames;
> +    assert(s->pending_frames >= 0);
> +
> +    /* Only update display if mode hasn't changed since we started rendering. */
> +    if (s->rendering_frame_width == surface_width(s->surface) &&
> +        s->rendering_frame_height == surface_height(s->surface)) {
> +        copy_mtl_texture_to_surface_mem(s->texture, surface_data(s->surface));
> +        if (s->gfx_update_requested) {
> +            s->gfx_update_requested = false;
> +            dpy_gfx_update_full(s->con);
> +            graphic_hw_update_done(s->con);
> +            s->new_frame_ready = false;
> +        } else {
> +            s->new_frame_ready = true;
> +        }
> +    }
> +    if (s->pending_frames > 0) {
> +        apple_gfx_render_new_frame(s);
> +    }
> +}
> +
> +static void apple_gfx_fb_update_display(void *opaque)
> +{
> +    AppleGFXState *s = opaque;
> +
> +    assert(bql_locked());
> +    if (s->new_frame_ready) {
> +        dpy_gfx_update_full(s->con);
> +        s->new_frame_ready = false;
> +        graphic_hw_update_done(s->con);
> +    } else if (s->pending_frames > 0) {
> +        s->gfx_update_requested = true;
> +    } else {
> +        graphic_hw_update_done(s->con);
> +    }
> +}
> +
> +static const GraphicHwOps apple_gfx_fb_ops = {
> +    .gfx_update = apple_gfx_fb_update_display,
> +    .gfx_update_async = true,
> +};
> +
> +/* ------ Mouse cursor and display mode setting ------ */
> +
> +static void set_mode(AppleGFXState *s, uint32_t width, uint32_t height)
> +{
> +    MTLTextureDescriptor *textureDescriptor;
> +
> +    if (s->surface &&
> +        width == surface_width(s->surface) &&
> +        height == surface_height(s->surface)) {
> +        return;
> +    }
> +
> +    [s->texture release];
> +
> +    s->surface = qemu_create_displaysurface(width, height);
> +
> +    @autoreleasepool {
> +        textureDescriptor =
> +            [MTLTextureDescriptor
> +                texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
> +                                             width:width
> +                                            height:height
> +                                         mipmapped:NO];
> +        textureDescriptor.usage = s->pgdisp.minimumTextureUsage;
> +        s->texture = [s->mtl newTextureWithDescriptor:textureDescriptor];
> +    }
> +
> +    s->using_managed_texture_storage =
> +        (s->texture.storageMode == MTLStorageModeManaged);
> +    dpy_gfx_replace_surface(s->con, s->surface);
> +}
> +
> +static void update_cursor(AppleGFXState *s)
> +{
> +    assert(bql_locked());
> +    dpy_mouse_set(s->con, s->pgdisp.cursorPosition.x,
> +                  s->pgdisp.cursorPosition.y, qatomic_read(&s->cursor_show));
> +}
> +
> +static void update_cursor_bh(void *opaque)
> +{
> +    AppleGFXState *s = opaque;
> +    update_cursor(s);
> +}
> +
> +typedef struct AppleGFXSetCursorGlyphJob {
> +    AppleGFXState *s;
> +    NSBitmapImageRep *glyph;
> +    PGDisplayCoord_t hotspot;
> +} AppleGFXSetCursorGlyphJob;
> +
> +static void set_cursor_glyph(void *opaque)
> +{
> +    AppleGFXSetCursorGlyphJob *job = opaque;
> +    AppleGFXState *s = job->s;
> +    NSBitmapImageRep *glyph = job->glyph;
> +    uint32_t bpp = glyph.bitsPerPixel;
> +    size_t width = glyph.pixelsWide;
> +    size_t height = glyph.pixelsHigh;
> +    size_t padding_bytes_per_row = glyph.bytesPerRow - width * 4;
> +    const uint8_t* px_data = glyph.bitmapData;
> +
> +    trace_apple_gfx_cursor_set(bpp, width, height);
> +
> +    if (s->cursor) {
> +        cursor_unref(s->cursor);
> +        s->cursor = NULL;
> +    }
> +
> +    if (bpp == 32) { /* Shouldn't be anything else, but just to be safe...*/
> +        s->cursor = cursor_alloc(width, height);
> +        s->cursor->hot_x = job->hotspot.x;
> +        s->cursor->hot_y = job->hotspot.y;
> +
> +        uint32_t *dest_px = s->cursor->data;
> +
> +        for (size_t y = 0; y < height; ++y) {
> +            for (size_t x = 0; x < width; ++x) {
> +                /*
> +                 * NSBitmapImageRep's red & blue channels are swapped
> +                 * compared to QEMUCursor's.
> +                 */
> +                *dest_px =
> +                    (px_data[0] << 16u) |
> +                    (px_data[1] <<  8u) |
> +                    (px_data[2] <<  0u) |
> +                    (px_data[3] << 24u);
> +                ++dest_px;
> +                px_data += 4;
> +            }
> +            px_data += padding_bytes_per_row;
> +        }
> +        dpy_cursor_define(s->con, s->cursor);
> +        update_cursor(s);
> +    }
> +    [glyph release];
> +
> +    g_free(job);
> +}
> +
> +/* ------ DMA (device reading system memory) ------ */
> +
> +typedef struct AppleGFXReadMemoryJob {
> +    QemuSemaphore sem;
> +    hwaddr physical_address;
> +    uint64_t length;
> +    void *dst;
> +    bool success;
> +} AppleGFXReadMemoryJob;
> +
> +static void apple_gfx_do_read_memory(void *opaque)
> +{
> +    AppleGFXReadMemoryJob *job = opaque;
> +    MemTxResult r;
> +
> +    r = dma_memory_read(&address_space_memory, job->physical_address,
> +                        job->dst, job->length, MEMTXATTRS_UNSPECIFIED);
> +    job->success = r == MEMTX_OK;
> +
> +    qemu_sem_post(&job->sem);
> +}
> +
> +static bool apple_gfx_read_memory(AppleGFXState *s, hwaddr physical_address,
> +                                  uint64_t length, void *dst)
> +{
> +    AppleGFXReadMemoryJob job = {
> +        .physical_address = physical_address, .length = length, .dst = dst
> +    };
> +
> +    trace_apple_gfx_read_memory(physical_address, length, dst);
> +
> +    /* Performing DMA requires BQL, so do it in a BH. */
> +    qemu_sem_init(&job.sem, 0);
> +    aio_bh_schedule_oneshot(qemu_get_aio_context(),
> +                            apple_gfx_do_read_memory, &job);
> +    qemu_sem_wait(&job.sem);
> +    qemu_sem_destroy(&job.sem);
> +    return job.success;
> +}
> +
> +/* ------ Memory-mapped device I/O operations ------ */
> +
> +static dispatch_queue_t get_background_queue(void)
> +{
> +    return dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
> +}
> +
> +typedef struct AppleGFXIOJob {
> +    AppleGFXState *state;
> +    uint64_t offset;
> +    uint64_t value;
> +    bool completed;
> +} AppleGFXIOJob;
> +
> +static void apple_gfx_do_read(void *opaque)
> +{
> +    AppleGFXIOJob *job = opaque;
> +    job->value = [job->state->pgdev mmioReadAtOffset:job->offset];
> +    qatomic_set(&job->completed, true);
> +    aio_wait_kick();
> +}
> +
> +static uint64_t apple_gfx_read(void *opaque, hwaddr offset, unsigned size)
> +{
> +    AppleGFXIOJob job = {
> +        .state = opaque,
> +        .offset = offset,
> +        .completed = false,
> +    };
> +    dispatch_queue_t queue = get_background_queue();
> +
> +    dispatch_async_f(queue, &job, apple_gfx_do_read);
> +    AIO_WAIT_WHILE(NULL, !qatomic_read(&job.completed));
> +
> +    trace_apple_gfx_read(offset, job.value);
> +    return job.value;
> +}
> +
> +static void apple_gfx_do_write(void *opaque)
> +{
> +    AppleGFXIOJob *job = opaque;
> +    [job->state->pgdev mmioWriteAtOffset:job->offset value:job->value];
> +    qatomic_set(&job->completed, true);
> +    aio_wait_kick();
> +}
> +
> +static void apple_gfx_write(void *opaque, hwaddr offset, uint64_t val,
> +                            unsigned size)
> +{
> +    /*
> +     * The methods mmioReadAtOffset: and especially mmioWriteAtOffset: can
> +     * trigger synchronous operations on other dispatch queues, which in turn
> +     * may call back out on one or more of the callback blocks. For this reason,
> +     * and as we are holding the BQL, we invoke the I/O methods on a pool
> +     * thread and handle AIO tasks while we wait. Any work in the callbacks
> +     * requiring the BQL will in turn schedule BHs which this thread will
> +     * process while waiting.
> +     */
> +    AppleGFXIOJob job = {
> +        .state = opaque,
> +        .offset = offset,
> +        .value = val,
> +        .completed = false,
> +    };
> +    dispatch_queue_t queue = get_background_queue();
> +
> +    dispatch_async_f(queue, &job, apple_gfx_do_write);
> +    AIO_WAIT_WHILE(NULL, !qatomic_read(&job.completed));
> +
> +    trace_apple_gfx_write(offset, val);
> +}
> +
> +static const MemoryRegionOps apple_gfx_ops = {
> +    .read = apple_gfx_read,
> +    .write = apple_gfx_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 4,
> +        .max_access_size = 8,
> +    },
> +    .impl = {
> +        .min_access_size = 4,
> +        .max_access_size = 4,
> +    },
> +};
> +
> +static size_t apple_gfx_get_default_mmio_range_size(void)
> +{
> +    size_t mmio_range_size;
> +    @autoreleasepool {
> +        PGDeviceDescriptor *desc = [PGDeviceDescriptor new];
> +        mmio_range_size = desc.mmioLength;
> +        [desc release];
> +    }
> +    return mmio_range_size;
> +}
> +
> +/* ------ Initialisation and startup ------ */
> +
> +void apple_gfx_common_init(Object *obj, AppleGFXState *s, const char* obj_name)
> +{
> +    size_t mmio_range_size = apple_gfx_get_default_mmio_range_size();
> +
> +    trace_apple_gfx_common_init(obj_name, mmio_range_size);
> +    memory_region_init_io(&s->iomem_gfx, obj, &apple_gfx_ops, s, obj_name,
> +                          mmio_range_size);
> +
> +    /* TODO: PVG framework supports serialising device state: integrate it! */
> +}
> +
> +static void apple_gfx_register_task_mapping_handlers(AppleGFXState *s,
> +                                                     PGDeviceDescriptor *desc)
> +{
> +    desc.createTask = ^(uint64_t vmSize, void * _Nullable * _Nonnull baseAddress) {
> +        PGTask_t *task = apple_gfx_new_task(s, vmSize);
> +        *baseAddress = (void *)task->address;
> +        trace_apple_gfx_create_task(vmSize, *baseAddress);
> +        return task;
> +    };
> +
> +    desc.destroyTask = ^(PGTask_t * _Nonnull task) {
> +        trace_apple_gfx_destroy_task(task, task->mapped_regions->len);
> +
> +        apple_gfx_destroy_task(s, task);
> +    };
> +
> +    desc.mapMemory = ^bool(PGTask_t * _Nonnull task, uint32_t range_count,
> +                           uint64_t virtual_offset, bool read_only,
> +                           PGPhysicalMemoryRange_t * _Nonnull ranges) {
> +        return apple_gfx_task_map_memory(s, task, virtual_offset,
> +                                         ranges, range_count, read_only);
> +    };
> +
> +    desc.unmapMemory = ^bool(PGTask_t * _Nonnull task, uint64_t virtual_offset,
> +                             uint64_t length) {
> +        apple_gfx_task_unmap_memory(s, task, virtual_offset, length);
> +        return true;
> +    };
> +
> +    desc.readMemory = ^bool(uint64_t physical_address, uint64_t length,
> +                            void * _Nonnull dst) {
> +        return apple_gfx_read_memory(s, physical_address, length, dst);
> +    };
> +}
> +
> +static void new_frame_handler_bh(void *opaque)
> +{
> +    AppleGFXState *s = opaque;
> +
> +    /* Drop frames if we get too far ahead. */
> +    if (s->pending_frames >= 2) {
> +        return;
> +    }
> +    ++s->pending_frames;
> +    if (s->pending_frames > 1) {
> +        return;
> +    }
> +    apple_gfx_render_new_frame(s);
> +}
> +
> +static PGDisplayDescriptor *apple_gfx_prepare_display_descriptor(AppleGFXState *s)
> +{
> +    PGDisplayDescriptor *disp_desc = [PGDisplayDescriptor new];
> +
> +    disp_desc.name = @"QEMU display";
> +    disp_desc.sizeInMillimeters = NSMakeSize(400., 300.); /* A 20" display */
> +    disp_desc.queue = dispatch_get_main_queue();
> +    disp_desc.newFrameEventHandler = ^(void) {
> +        trace_apple_gfx_new_frame();
> +        aio_bh_schedule_oneshot(qemu_get_aio_context(), new_frame_handler_bh, s);
> +    };
> +    disp_desc.modeChangeHandler = ^(PGDisplayCoord_t sizeInPixels,
> +                                    OSType pixelFormat) {
> +        trace_apple_gfx_mode_change(sizeInPixels.x, sizeInPixels.y);
> +
> +        BQL_LOCK_GUARD();
> +        set_mode(s, sizeInPixels.x, sizeInPixels.y);
> +    };
> +    disp_desc.cursorGlyphHandler = ^(NSBitmapImageRep *glyph,
> +                                     PGDisplayCoord_t hotspot) {
> +        AppleGFXSetCursorGlyphJob *job = g_malloc0(sizeof(*job));
> +        job->s = s;
> +        job->glyph = glyph;
> +        job->hotspot = hotspot;
> +        [glyph retain];
> +        aio_bh_schedule_oneshot(qemu_get_aio_context(),
> +                                set_cursor_glyph, job);
> +    };
> +    disp_desc.cursorShowHandler = ^(BOOL show) {
> +        trace_apple_gfx_cursor_show(show);
> +        qatomic_set(&s->cursor_show, show);
> +        aio_bh_schedule_oneshot(qemu_get_aio_context(),
> +                                update_cursor_bh, s);
> +    };
> +    disp_desc.cursorMoveHandler = ^(void) {
> +        trace_apple_gfx_cursor_move();
> +        aio_bh_schedule_oneshot(qemu_get_aio_context(),
> +                                update_cursor_bh, s);
> +    };
> +
> +    return disp_desc;
> +}
> +
> +static NSArray<PGDisplayMode*>* apple_gfx_prepare_display_mode_array(void)
> +{
> +    PGDisplayMode *modes[ARRAY_SIZE(apple_gfx_modes)];
> +    NSArray<PGDisplayMode*>* mode_array = nil;

Don't initialize mode_array here; it will suppress an uniniailized
variable warning in case you forget assigning a real value later.

OK
 
> +    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;
> +    }
> +
> +    return mode_array;
> +}
> +
> +static id<MTLDevice> copy_suitable_metal_device(void)
> +{
> +    id<MTLDevice> dev = nil;
> +    NSArray<id<MTLDevice>> *devs = MTLCopyAllDevices();
> +
> +    /* Prefer a unified memory GPU. Failing that, pick a non-removable GPU. */
> +    for (size_t i = 0; i < devs.count; ++i) {
> +        if (devs[i].hasUnifiedMemory) {
> +            dev = devs[i];
> +            break;
> +        }
> +        if (!devs[i].removable) {
> +            dev = devs[i];
> +        }
> +    }
> +
> +    if (dev != nil) {
> +        [dev retain];
> +    } else {
> +        dev = MTLCreateSystemDefaultDevice();
> +    }
> +    [devs release];
> +
> +    return dev;
> +}
> +
> +bool apple_gfx_common_realize(AppleGFXState *s, DeviceState *dev,
> +                              PGDeviceDescriptor *desc, Error **errp)
> +{
> +    PGDisplayDescriptor *disp_desc = nil;
> +
> +    if (apple_gfx_mig_blocker == NULL) {
> +        error_setg(&apple_gfx_mig_blocker,
> +                  "Migration state blocked by apple-gfx display device");
> +        if (migrate_add_blocker(&apple_gfx_mig_blocker, errp) < 0) {
> +            return false;
> +        }
> +    }
> +
> +    qemu_mutex_init(&s->task_mutex);
> +    QTAILQ_INIT(&s->tasks);
> +    s->render_queue = dispatch_queue_create("apple-gfx.render",
> +                                            DISPATCH_QUEUE_SERIAL);
> +    s->mtl = copy_suitable_metal_device();
> +    s->mtl_queue = [s->mtl newCommandQueue];
> +
> +    desc.device = s->mtl;
> +
> +    apple_gfx_register_task_mapping_handlers(s, desc);
> +
> +    s->cursor_show = true;
> +
> +    s->pgdev = PGNewDeviceWithDescriptor(desc);
> +
> +    disp_desc = apple_gfx_prepare_display_descriptor(s);
> +    s->pgdisp = [s->pgdev newDisplayWithDescriptor:disp_desc
> +                                              port:0 serialNum:1234];
> +    [disp_desc release];
> +    s->pgdisp.modeList = apple_gfx_prepare_display_mode_array();
> +
> +    s->con = graphic_console_init(dev, 0, &apple_gfx_fb_ops, s);
> +    return true;
> +}
> diff --git a/hw/display/meson.build b/hw/display/meson.build
> index 20a94973fa2..cf9e6dd35d2 100644
> --- a/hw/display/meson.build
> +++ b/hw/display/meson.build
> @@ -61,6 +61,12 @@ system_ss.add(when: 'CONFIG_ARTIST', if_true: files('artist.c'))
>   
>   system_ss.add(when: 'CONFIG_ATI_VGA', if_true: [files('ati.c', 'ati_2d.c', 'ati_dbg.c'), pixman])
>   
> +if host_os == 'darwin'
> +  system_ss.add(when: 'CONFIG_MAC_PVG',         if_true: [files('apple-gfx.m'), pvg, metal])
> +  if cpu == 'aarch64'
> +    system_ss.add(when: 'CONFIG_MAC_PVG_MMIO',  if_true: [files('apple-gfx-mmio.m'), pvg, metal])
> +  endif
> +endif
>   
>   if config_all_devices.has_key('CONFIG_VIRTIO_GPU')
>     virtio_gpu_ss = ss.source_set()
> diff --git a/hw/display/trace-events b/hw/display/trace-events
> index d26d663f963..a50e4eea0c0 100644
> --- a/hw/display/trace-events
> +++ b/hw/display/trace-events
> @@ -194,3 +194,31 @@ dm163_bits_ppi(unsigned dest_width) "dest_width : %u"
>   dm163_leds(int led, uint32_t value) "led %d: 0x%x"
>   dm163_channels(int channel, uint8_t value) "channel %d: 0x%x"
>   dm163_refresh_rate(uint32_t rr) "refresh rate %d"
> +
> +# apple-gfx.m
> +apple_gfx_read(uint64_t offset, uint64_t res) "offset=0x%"PRIx64" res=0x%"PRIx64
> +apple_gfx_write(uint64_t offset, uint64_t val) "offset=0x%"PRIx64" val=0x%"PRIx64
> +apple_gfx_create_task(uint32_t vm_size, void *va) "vm_size=0x%x base_addr=%p"
> +apple_gfx_destroy_task(void *task, unsigned int num_mapped_regions) "task=%p, task->mapped_regions->len=%u"
> +apple_gfx_map_memory(void *task, uint32_t range_count, uint64_t virtual_offset, uint32_t read_only) "task=%p range_count=0x%x virtual_offset=0x%"PRIx64" read_only=%d"
> +apple_gfx_map_memory_range(uint32_t i, uint64_t phys_addr, uint64_t phys_len) "[%d] phys_addr=0x%"PRIx64" phys_len=0x%"PRIx64
> +apple_gfx_remap(uint64_t retval, void *source_ptr, uint64_t target) "retval=%"PRId64" source=%p target=0x%"PRIx64
> +apple_gfx_unmap_memory(void *task, uint64_t virtual_offset, uint64_t length) "task=%p virtual_offset=0x%"PRIx64" length=0x%"PRIx64
> +apple_gfx_read_memory(uint64_t phys_address, uint64_t length, void *dst) "phys_addr=0x%"PRIx64" length=0x%"PRIx64" dest=%p"
> +apple_gfx_raise_irq(uint32_t vector) "vector=0x%x"
> +apple_gfx_new_frame(void) ""
> +apple_gfx_mode_change(uint64_t x, uint64_t y) "x=%"PRId64" y=%"PRId64
> +apple_gfx_cursor_set(uint32_t bpp, uint64_t width, uint64_t height) "bpp=%d width=%"PRId64" height=0x%"PRId64
> +apple_gfx_cursor_show(uint32_t show) "show=%d"
> +apple_gfx_cursor_move(void) ""
> +apple_gfx_common_init(const char *device_name, size_t mmio_size) "device: %s; MMIO size: %zu bytes"
> +
> +# apple-gfx-mmio.m
> +apple_gfx_mmio_iosfc_read(uint64_t offset, uint64_t res) "offset=0x%"PRIx64" res=0x%"PRIx64
> +apple_gfx_mmio_iosfc_write(uint64_t offset, uint64_t val) "offset=0x%"PRIx64" val=0x%"PRIx64
> +apple_gfx_iosfc_map_memory(uint64_t phys, uint64_t len, uint32_t ro, void *va, void *e, void *f, void* va_result) "phys=0x%"PRIx64" len=0x%"PRIx64" ro=%d va=%p e=%p f=%p -> *va=%p"
> +apple_gfx_iosfc_map_memory_new_region(size_t i, void *region, uint64_t start, uint64_t end) "index=%zu, region=%p, 0x%"PRIx64"-0x%"PRIx64
> +apple_gfx_iosfc_unmap_memory(void *a, void *b, void *c, void *d, void *e, void *f) "a=%p b=%p c=%p d=%p e=%p f=%p"
> +apple_gfx_iosfc_unmap_memory_region(void* mem, void *region) "unmapping @ %p from memory region %p"
> +apple_gfx_iosfc_raise_irq(uint32_t vector) "vector=0x%x"
> +
> diff --git a/meson.build b/meson.build
> index e0b880e4e13..3c61238bc77 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -794,6 +794,8 @@ socket = []
>   version_res = []
>   coref = []
>   iokit = []
> +pvg = not_found
> +metal = []
>   emulator_link_args = []
>   midl = not_found
>   widl = not_found
> @@ -815,6 +817,8 @@ elif host_os == 'darwin'
>     coref = dependency('appleframeworks', modules: 'CoreFoundation')
>     iokit = dependency('appleframeworks', modules: 'IOKit', required: false)
>     host_dsosuf = '.dylib'
> +  pvg = dependency('appleframeworks', modules: 'ParavirtualizedGraphics')
> +  metal = dependency('appleframeworks', modules: 'Metal')
>   elif host_os == 'sunos'
>     socket = [cc.find_library('socket'),
>               cc.find_library('nsl'),


reply via email to

[Prev in Thread] Current Thread [Next in Thread]