Re: [Freedreno] [PATCH libdrm] drm: Remove create_handle() drm_framebuffer "virtual".
Den 09.08.2017 01.42, skrev Joe Kniss: Because all drivers currently use gem objects for framebuffer planes, the virtual create_handle() is not required. This change adds a struct drm_gem_object *gems[4] field to drm_framebuffer and removes create_handle() function pointer from drm_framebuffer_funcs. The corresponding *_create_handle() function is removed from each driver. In many cases this change eliminates a struct *_framebuffer object, as the only need for the derived struct is the addition of the gem object pointer. TESTED: compiled: allyesconfig ARCH=x86,arm platforms:i915, rockchip Signed-off-by: Joe Kniss --- Hi Joe, I'm also looking into adding gem objs to drm_framebuffer in this patch: [PATCH v2 01/22] drm: Add GEM backed framebuffer library https://lists.freedesktop.org/archives/dri-devel/2017-August/149782.html [...] diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index ade319d10e70..f5f011b910b1 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -31,14 +31,9 @@ #define DEFAULT_FBDEFIO_DELAY_MS 50 -struct drm_fb_cma { - struct drm_framebuffer fb; - struct drm_gem_cma_object *obj[4]; -}; - struct drm_fbdev_cma { struct drm_fb_helperfb_helper; - struct drm_fb_cma *fb; + struct drm_framebuffer *fb; This fb pointer isn't necessary, since fb_helper already has one. Noralf. const struct drm_framebuffer_funcs *fb_funcs; }; @@ -72,7 +67,6 @@ struct drm_fbdev_cma { * * static struct drm_framebuffer_funcs driver_fb_funcs = { * .destroy = drm_fb_cma_destroy, - * .create_handle = drm_fb_cma_create_handle, * .dirty = driver_fb_dirty, * }; * @@ -90,67 +84,50 @@ static inline struct drm_fbdev_cma *to_fbdev_cma(struct drm_fb_helper *helper) return container_of(helper, struct drm_fbdev_cma, fb_helper); } -static inline struct drm_fb_cma *to_fb_cma(struct drm_framebuffer *fb) -{ - return container_of(fb, struct drm_fb_cma, fb); -} - void drm_fb_cma_destroy(struct drm_framebuffer *fb) { - struct drm_fb_cma *fb_cma = to_fb_cma(fb); int i; for (i = 0; i < 4; i++) { - if (fb_cma->obj[i]) - drm_gem_object_put_unlocked(&fb_cma->obj[i]->base); + if (fb->gem_objs[i]) + drm_gem_object_put_unlocked(fb->gem_objs[i]); } drm_framebuffer_cleanup(fb); - kfree(fb_cma); + kfree(fb); } EXPORT_SYMBOL(drm_fb_cma_destroy); -int drm_fb_cma_create_handle(struct drm_framebuffer *fb, - struct drm_file *file_priv, unsigned int *handle) -{ - struct drm_fb_cma *fb_cma = to_fb_cma(fb); - - return drm_gem_handle_create(file_priv, - &fb_cma->obj[0]->base, handle); -} -EXPORT_SYMBOL(drm_fb_cma_create_handle); - static struct drm_framebuffer_funcs drm_fb_cma_funcs = { .destroy= drm_fb_cma_destroy, - .create_handle = drm_fb_cma_create_handle, }; -static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev, +static struct drm_framebuffer *drm_fb_cma_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_cma_object **obj, unsigned int num_planes, const struct drm_framebuffer_funcs *funcs) { - struct drm_fb_cma *fb_cma; + struct drm_framebuffer *fb; int ret; int i; - fb_cma = kzalloc(sizeof(*fb_cma), GFP_KERNEL); - if (!fb_cma) + fb = kzalloc(sizeof(*fb), GFP_KERNEL); + if (!fb) return ERR_PTR(-ENOMEM); - drm_helper_mode_fill_fb_struct(dev, &fb_cma->fb, mode_cmd); + drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd); for (i = 0; i < num_planes; i++) - fb_cma->obj[i] = obj[i]; + fb->gem_objs[i] = &obj[i]->base; - ret = drm_framebuffer_init(dev, &fb_cma->fb, funcs); + ret = drm_framebuffer_init(dev, fb, funcs); if (ret) { dev_err(dev->dev, "Failed to initialize framebuffer: %d\n", ret); - kfree(fb_cma); + kfree(fb); return ERR_PTR(ret); } - return fb_cma; + return fb; } /** @@ -171,7 +148,7 @@ struct drm_framebuffer *drm_fb_cma_create_with_funcs(struct drm_device *dev, const struct drm_framebuffer_funcs *funcs) { const struct drm_format_info *info; - struct drm_fb_cma *fb_cma; + struct drm_framebuffer *fb; struct drm_gem_cma_object *objs[4]; struct drm_gem_object *obj; int ret; @@ -205,13 +182,13 @@ struct drm_framebuffer *drm_fb_cma_create_with_funcs(struct drm_device *dev, objs[i] = to_drm_gem_cma_obj(obj); } - fb_cma = drm_fb_cma_alloc(dev, mode_cmd, objs, i, funcs); - if (IS_ERR(fb_cma)) { - ret = PTR_ERR(f
Re: [Freedreno] [PATCH 00/23] drm: Eliminate plane->fb/crtc usage for atomic drivers
Den 22.03.2018 16.22, skrev Ville Syrjala: From: Ville Syrjälä I really just wanted to fix i915 to re-enable its planes afer load detection (a two line patch). This is what I actually ended up with after I ran into a framebuffer refcount leak with said two line patch. I've tested this on a few i915 boxes and so far it's looking good. Everything else is just compile tested. Entire series available here: git://github.com/vsyrjala/linux.git plane_fb_crtc_nuke Cc: Alex Deucher Cc: amd-...@lists.freedesktop.org Cc: Benjamin Gaignard Cc: Boris Brezillon Cc: ch...@chris-wilson.co.uk Cc: "Christian König" Cc: Daniel Vetter Cc: Dave Airlie Cc: David Airlie Cc: "David (ChunMing) Zhou" Cc: Eric Anholt Cc: freedreno@lists.freedesktop.org Cc: Gerd Hoffmann Cc: Harry Wentland Cc: Inki Dae Cc: Joonyoung Shim Cc: Kyungmin Park Cc: linux-arm-...@vger.kernel.org Cc: Maarten Lankhorst Cc: martin.pe...@free.fr Cc: Rob Clark Cc: Seung-Woo Kim Cc: Shawn Guo Cc: Sinclair Yeh Cc: Thomas Hellstrom Cc: Vincent Abriou Cc: virtualizat...@lists.linux-foundation.org Cc: VMware Graphics Ville Syrjälä (23): Revert "drm/atomic-helper: Fix leak in disable_all" drm/atomic-helper: Make drm_atomic_helper_disable_all() update the plane->fb pointers drm: Clear crtc->primary->crtc when disabling the crtc via setcrtc() drm/atomic-helper: WARN if legacy plane fb pointers are bogus when committing duplicated state drm: Add local 'plane' variable for primary/cursor planes drm: Adjust whitespace for legibility drm: Make the fb refcount handover less magic drm: Use plane->state->fb over plane->fb drm/i915: Stop consulting plane->fb drm/msm: Stop consulting plane->fb drm/sti: Stop consulting plane->fb drm/vmwgfx: Stop consulting plane->fb drm/zte: Stop consulting plane->fb drm/atmel-hlcdc: Stop using plane->fb drm: Stop updating plane->crtc/fb/old_fb on atomic drivers drm/amdgpu/dc: Stop updating plane->fb drm/i915: Stop updating plane->fb/crtc drm/exynos: Stop updating plane->crtc drm/msm: Stop updating plane->fb/crtc drm/virtio: Stop updating plane->fb drm/vc4: Stop updating plane->fb/crtc drm/i915: Restore planes after load detection drm/i915: Make force_load_detect effective even w/ DMI quirks/hotplug tinydrm is also using plane->fb: $ grep -r "plane\.fb" drivers/gpu/drm/tinydrm/ drivers/gpu/drm/tinydrm/repaper.c: if (tdev->pipe.plane.fb != fb) drivers/gpu/drm/tinydrm/mipi-dbi.c: if (tdev->pipe.plane.fb != fb) drivers/gpu/drm/tinydrm/mipi-dbi.c: struct drm_framebuffer *fb = mipi->tinydrm.pipe.plane.fb; drivers/gpu/drm/tinydrm/core/tinydrm-pipe.c: pipe->plane.fb = fb; drivers/gpu/drm/tinydrm/ili9225.c: if (tdev->pipe.plane.fb != fb) drivers/gpu/drm/tinydrm/st7586.c: if (tdev->pipe.plane.fb != fb) Noralf. drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 2 - drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 12 +--- drivers/gpu/drm/drm_atomic.c | 55 ++-- drivers/gpu/drm/drm_atomic_helper.c | 79 ++- drivers/gpu/drm/drm_crtc.c| 51 ++- drivers/gpu/drm/drm_fb_helper.c | 7 -- drivers/gpu/drm/drm_framebuffer.c | 5 -- drivers/gpu/drm/drm_plane.c | 64 +++--- drivers/gpu/drm/drm_plane_helper.c| 4 +- drivers/gpu/drm/exynos/exynos_drm_plane.c | 2 - drivers/gpu/drm/i915/intel_crt.c | 6 ++ drivers/gpu/drm/i915/intel_display.c | 9 +-- drivers/gpu/drm/i915/intel_fbdev.c| 2 +- drivers/gpu/drm/msm/disp/mdp4/mdp4_crtc.c | 3 +- drivers/gpu/drm/msm/disp/mdp4/mdp4_plane.c| 2 - drivers/gpu/drm/msm/disp/mdp5/mdp5_plane.c| 2 - drivers/gpu/drm/sti/sti_plane.c | 9 +-- drivers/gpu/drm/vc4/vc4_crtc.c| 3 - drivers/gpu/drm/virtio/virtgpu_display.c | 2 - drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 6 +- drivers/gpu/drm/zte/zx_vou.c | 2 +- include/drm/drm_atomic.h | 3 - 22 files changed, 143 insertions(+), 187 deletions(-) ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 00/23] drm: Eliminate plane->fb/crtc usage for atomic drivers
Den 22.03.2018 19.49, skrev Ville Syrjälä: On Thu, Mar 22, 2018 at 05:51:35PM +0100, Noralf Trønnes wrote: tinydrm is also using plane->fb: $ grep -r "plane\.fb" drivers/gpu/drm/tinydrm/ drivers/gpu/drm/tinydrm/repaper.c: if (tdev->pipe.plane.fb != fb) drivers/gpu/drm/tinydrm/mipi-dbi.c: if (tdev->pipe.plane.fb != fb) drivers/gpu/drm/tinydrm/mipi-dbi.c: struct drm_framebuffer *fb = mipi->tinydrm.pipe.plane.fb; Oh dear, and naturally it's the most annoying one of the bunch. So we want to take the plane lock in the fb.dirty() hook to look at the fb, but mipi-dbi.c calls that directly from the bowels of its .atomic_enable() hook. So that would deadlock pretty neatly if the commit happens while already holding the lock. So we'd either need to plumb an acquire context into fb.dirty(), or maybe have tinydrm provide a lower level lockless dirty() hook that gets called by both (there are just too many layers in this particular cake to immediately see where such a hook would be best placed). Or maybe there's some other solution I didn't think of. Looking at this I'm also left wondering how this is supposed handle fb.dirty() getting called concurrently with a modeset. The dirty_mutex only seems to offer any protection for fb.dirty() against another fb.dirty()... I have been waiting for the 'page-flip with damage'[1] work to come to fruition so I could handle all flushing during atomic commit. The idea is to use the same damage rect for a generic dirtyfb callback. Maybe a temporary tinydrm specific solution is possible until that work lands, but I don't know enough about how to implement such a dirtyfb callback. I imagine it could look something like this: struct tinydrm_device { + struct drm_clip_rect dirtyfb_rect; }; static int tinydrm_fb_dirty(struct drm_framebuffer *fb, struct drm_file *file_priv, unsigned int flags, unsigned int color, struct drm_clip_rect *clips, unsigned int num_clips) { struct tinydrm_device *tdev = fb->dev->dev_private; struct drm_framebuffer *planefb; /* Grab whatever lock needed to check this */ planefb = tdev->pipe.plane.state->fb; /* fbdev can flush even when we're not interested */ if (fb != planefb) return 0; /* Protect dirtyfb_rect with a lock */ tinydrm_merge_clips(&tdev->dirty_rectfb, clips, num_clips, flags, fb->width, fb->height); /* * Somehow do an atomic commit that results in the atomic update * callback being called */ ret = drm_atomic_commit(state); ... } static void mipi_dbi_flush(struct drm_framebuffer *fb, struct drm_clip_rect *clip) { /* Flush out framebuffer */ } void mipi_dbi_pipe_update(struct drm_simple_display_pipe *pipe, struct drm_plane_state *old_state) { struct tinydrm_device *tdev = pipe_to_tinydrm(pipe); struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev); struct drm_framebuffer *fb = pipe->plane.state->fb; struct drm_crtc *crtc = &tdev->pipe.crtc; if (!fb || (fb == old_state->fb && !tdev->dirty_rect.x2)) goto out_vblank; /* Don't flush if the controller isn't initialized yet */ if (!mipi->enabled) goto out_vblank; if (fb != old_state->fb) { /* Page flip or new, flush all */ mipi_dbi_flush(fb, NULL); } else { /* dirtyfb ioctl */ mipi_dbi_flush(fb, &tdev->dirtyfb_rect); memset(&tdev->dirtyfb_rect, 0, sizeof(tdev->dirtyfb_rect)); } out_vblank: if (crtc->state->event) { spin_lock_irq(&crtc->dev->event_lock); drm_crtc_send_vblank_event(crtc, crtc->state->event); spin_unlock_irq(&crtc->dev->event_lock); crtc->state->event = NULL; } } This is called from the driver pipe enable callback after the controller has been initialized: void mipi_dbi_pipe_enable(struct drm_simple_display_pipe *pipe, struct drm_crtc_state *crtc_state) { struct tinydrm_device *tdev = pipe_to_tinydrm(pipe); struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev); - struct drm_framebuffer *fb = pipe->plane.fb; + struct drm_framebuffer *fb = pipe->plane.state->fb; DRM_DEBUG_KMS("\n"); mipi->enabled = true; - if (fb) - fb->funcs->dirty(fb, NULL, 0, 0, NULL, 0); + mipi_dbi_flush(fb, NULL); tinydrm_enable_backlight(mipi->backlight); } I can make patches if this makes any sense and you can help me with the dirtyfb implementation. Noralf. [1] https://lists.freedesktop.org/archives/dri-devel/2017-December/161003.html ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [RFC] drm/atomic+msm: add helper to implement legacy dirtyfb
Den 04.04.2018 00.42, skrev Rob Clark: Add an atomic helper to implement dirtyfb support. This is needed to support DSI command-mode panels with x11 userspace (ie. when we can't rely on pageflips to trigger a flush to the panel). To signal to the driver that the async atomic update needs to synchronize with fences, even though the fb didn't change, the drm_atomic_state::dirty flag is added. Signed-off-by: Rob Clark --- Background: there are a number of different folks working on getting upstream kernel working on various different phones/tablets with qcom SoC's.. many of them have command mode panels, so we kind of need a way to support the legacy dirtyfb ioctl for x11 support. I know there is work on a proprer non-legacy atomic property for userspace to communicate dirty-rect(s) to the kernel, so this can be improved from triggering a full-frame flush once that is in place. But we kinda needa a stop-gap solution. I had considered an in-driver solution for this, but things get a bit tricky if userspace ands up combining dirtyfb ioctls with page- flips, because we need to synchronize setting various CTL.FLUSH bits with setting the CTL.START bit. (ie. really all we need to do for cmd mode panels is bang CTL.START, but is this ends up racing with pageflips setting FLUSH bits, then bad things.) The easiest soln is to wrap this up as an atomic commit and rely on the worker to serialize things. Hence adding an atomic dirtyfb helper. I guess at least the helper, with some small addition to translate and pass-thru the dirty rect(s) is useful to the final atomic dirty- rect property solution. Depending on how far off that is, a stop- gap solution could be useful. I have been waiting for someone to address this since I'm not skilled enough myself to tackle the atomic machinery. It would be be nice to do all flushing during commit since that would mean that the tinydrm drivers could be driven solely through drm_simple_display_pipe_funcs. I wouldn't have to wire through the dirty callback like I do now. I see that you use a nonblocking commit. What happens if a new dirtyfb comes in before the previous is done? If we could save the dirty clips, then I could use this in tinydrm. A full flush over SPI takes ~50ms so I need to shave off where I can. This works for me in my tinydrm world: diff --git a/include/drm/drm_plane.h b/include/drm/drm_plane.h index c64225274807..218cb36757fa 100644 --- a/include/drm/drm_plane.h +++ b/include/drm/drm_plane.h @@ -28,6 +28,7 @@ #include #include +struct drm_clip_rect; struct drm_crtc; struct drm_printer; struct drm_modeset_acquire_ctx; @@ -85,6 +86,9 @@ struct drm_plane_state { */ bool dirty; + struct drm_clip_rect *dirty_clips; + unsigned int num_dirty_clips; + /** * @fence: * diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 8066c508ab50..e00b8247b7c5 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -3521,6 +3521,8 @@ void __drm_atomic_helper_plane_duplicate_state(struct drm_plane *plane, drm_framebuffer_get(state->fb); state->dirty = false; + state->dirty_clips = NULL; + state->num_dirty_clips = 0; state->fence = NULL; state->commit = NULL; } @@ -3567,6 +3569,8 @@ void __drm_atomic_helper_plane_destroy_state(struct drm_plane_state *state) if (state->commit) drm_crtc_commit_put(state->commit); + + kfree(state->dirty_clips); } EXPORT_SYMBOL(__drm_atomic_helper_plane_destroy_state); @@ -3877,8 +3881,20 @@ int drm_atomic_helper_dirtyfb(struct drm_framebuffer *fb, struct drm_modeset_acquire_ctx ctx; struct drm_atomic_state *state; struct drm_plane *plane; + bool fb_found = false; int ret = 0; + /* fbdev can flush even when we don't want it to */ + drm_for_each_plane(plane, fb->dev) { + if (plane->state->fb == fb) { + fb_found = true; + break; + } + } + + if (!fb_found) + return 0; + /* * When called from ioctl, we are interruptable, but not when * called internally (ie. defio worker) @@ -3907,6 +3923,25 @@ int drm_atomic_helper_dirtyfb(struct drm_framebuffer *fb, } plane_state->dirty = true; + if (clips && num_clips) + plane_state->dirty_clips = kmemdup(clips, num_clips * sizeof(*clips), + GFP_KERNEL); + else + plane_state->dirty_clips = kzalloc(sizeof(*clips), GFP_KERNEL); + + if (!plane_state->dirty_clips) { + ret = -ENOMEM; + goto out; + } + + if (clips && num_clips) { + plane_state->num_dirty_clips = num_clips; + } el
Re: [Freedreno] [RFC] drm/atomic+msm: add helper to implement legacy dirtyfb
Den 04.04.2018 19.56, skrev Daniel Vetter: On Wed, Apr 4, 2018 at 7:41 PM, Noralf Trønnes wrote: Den 04.04.2018 00.42, skrev Rob Clark: Add an atomic helper to implement dirtyfb support. This is needed to support DSI command-mode panels with x11 userspace (ie. when we can't rely on pageflips to trigger a flush to the panel). To signal to the driver that the async atomic update needs to synchronize with fences, even though the fb didn't change, the drm_atomic_state::dirty flag is added. Signed-off-by: Rob Clark --- Background: there are a number of different folks working on getting upstream kernel working on various different phones/tablets with qcom SoC's.. many of them have command mode panels, so we kind of need a way to support the legacy dirtyfb ioctl for x11 support. I know there is work on a proprer non-legacy atomic property for userspace to communicate dirty-rect(s) to the kernel, so this can be improved from triggering a full-frame flush once that is in place. But we kinda needa a stop-gap solution. I had considered an in-driver solution for this, but things get a bit tricky if userspace ands up combining dirtyfb ioctls with page- flips, because we need to synchronize setting various CTL.FLUSH bits with setting the CTL.START bit. (ie. really all we need to do for cmd mode panels is bang CTL.START, but is this ends up racing with pageflips setting FLUSH bits, then bad things.) The easiest soln is to wrap this up as an atomic commit and rely on the worker to serialize things. Hence adding an atomic dirtyfb helper. I guess at least the helper, with some small addition to translate and pass-thru the dirty rect(s) is useful to the final atomic dirty- rect property solution. Depending on how far off that is, a stop- gap solution could be useful. I have been waiting for someone to address this since I'm not skilled enough myself to tackle the atomic machinery. It would be be nice to do all flushing during commit since that would mean that the tinydrm drivers could be driven solely through drm_simple_display_pipe_funcs. I wouldn't have to wire through the dirty callback like I do now. I see that you use a nonblocking commit. What happens if a new dirtyfb comes in before the previous is done? We could reuse the same trick we're doing in the fbdev code, of pushing the commit to a worker and doing it in a blocking fashion. Or at least wait for it to finish (can be done with the crtc_state->event stuff). That way userspace can pile us up in dirtyfb calls, but we'd do at most one per frame. More isn't really useful anyway. If we could save the dirty clips, then I could use this in tinydrm. A full flush over SPI takes ~50ms so I need to shave off where I can. This works for me in my tinydrm world: One thing I thought you've had around somewhere is some additional tracking code, so we don't have to take all the plane mutexes in the ->dirtyfb callback. Does that exist, or was that just a figment of my imagination? I haven't looked at this at all since I know way too little about how atomic works and after the discussion started with damage on page flips, I knew I just had to wait for someone other than me to do this. And I hardly know anything about how the multitude of userspace operates. So I'm sorry, but I can't add much to this discussion, I fall off rather quickly when the details and corner cases are discussed. All I can do is state the needs of tinydrm :-) Noralf. ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 13/21] drm/bochs: Use drm_fb_helper_fill_info
Den 26.03.2019 15.42, skrev Noralf Trønnes: > > > Den 26.03.2019 14.20, skrev Daniel Vetter: >> This will change the fb name from "msm" to "msmdrmfb". >> >> v2: Rebase >> >> Signed-off-by: Daniel Vetter >> Cc: Rob Clark >> Cc: linux-arm-...@vger.kernel.org >> Cc: freedreno@lists.freedesktop.org >> --- > > Reviewed-by: Noralf Trønnes I missed out on one thing, the subject is wrong wrt to the driver: bochs -> msm. > ___ > dri-devel mailing list > dri-de...@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/dri-devel > ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno
Re: [Freedreno] [PATCH 13/21] drm/bochs: Use drm_fb_helper_fill_info
Den 26.03.2019 14.20, skrev Daniel Vetter: > This will change the fb name from "msm" to "msmdrmfb". > > v2: Rebase > > Signed-off-by: Daniel Vetter > Cc: Rob Clark > Cc: linux-arm-...@vger.kernel.org > Cc: freedreno@lists.freedesktop.org > --- Reviewed-by: Noralf Trønnes ___ Freedreno mailing list Freedreno@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/freedreno