From 4fe3fcb0831dc87108a73e20e4d834500ec25f4f72e0afc9f8a9925c71f3c6ba Mon Sep 17 00:00:00 2001 From: Stefan Dirsch Date: Tue, 18 Mar 2014 11:29:12 +0000 Subject: [PATCH] Accepting request 225987 from home:tobijk:branches:X11:XOrg Fixes for BNC#866445 OBS-URL: https://build.opensuse.org/request/show/225987 OBS-URL: https://build.opensuse.org/package/show/X11:XOrg/Mesa?expand=0&rev=362 --- Mesa.changes | 10 + Mesa.spec | 10 + ...lium_util_add_missing_u_math_include.patch | 26 ++ U_nouveau_add_valid_range_tracking.patch | 200 +++++++++++++++ U_nouveau_create_only_one_shared_screen.patch | 231 ++++++++++++++++++ U_nouveau_fix_fence_waiting_logic.patch | 85 +++++++ 6 files changed, 562 insertions(+) create mode 100644 U_gallium_util_add_missing_u_math_include.patch create mode 100644 U_nouveau_add_valid_range_tracking.patch create mode 100644 U_nouveau_create_only_one_shared_screen.patch create mode 100644 U_nouveau_fix_fence_waiting_logic.patch diff --git a/Mesa.changes b/Mesa.changes index c7ed213..ceac7bc 100644 --- a/Mesa.changes +++ b/Mesa.changes @@ -1,3 +1,13 @@ +------------------------------------------------------------------- +Thu Mar 13 15:20:17 UTC 2014 - tobias.johannes.klausmann@mni.thm.de + +- Add U_gallium_util_add_missing_u_math_include.patch (patch27) +- Add U_nouveau_create_only_one_shared_screen.patch (patch28) +- Add U_nouveau_add_valid_range_tracking.patch (patch29) +- Add U_nouveau_fix_fence_waiting_logic.patch (patch30) + + https://bugzilla.novell.com/show_bug.cgi?id=866445 + + https://bugs.freedesktop.org/show_bug.cgi?id=75279 + ------------------------------------------------------------------- Wed Mar 5 16:17:42 UTC 2014 - tobias.johannes.klausmann@mni.thm.de diff --git a/Mesa.spec b/Mesa.spec index f9017a3..4c64832 100644 --- a/Mesa.spec +++ b/Mesa.spec @@ -118,6 +118,11 @@ Patch11: u_Fix-crash-in-swrast-when-setting-a-texture-for-a-pix.patch Patch13: u_mesa-8.0.1-fix-16bpp.patch # Patch from Fedora, use shmget when available, under llvmpipe Patch15: u_mesa-8.0-llvmpipe-shmget.patch +# BNC#866445 +Patch27: U_gallium_util_add_missing_u_math_include.patch +Patch28: U_nouveau_create_only_one_shared_screen.patch +Patch29: U_nouveau_add_valid_range_tracking.patch +Patch30: U_nouveau_fix_fence_waiting_logic.patch BuildRoot: %{_tmppath}/%{name}-%{version}-build @@ -482,6 +487,11 @@ rm -rf docs/README.{VMS,WIN32,OS2} #%patch11 -p1 #%patch15 -p1 #%patch13 -p1 +### +%patch27 -p1 +%patch28 -p1 +%patch29 -p1 +%patch30 -p1 %build rm -f src/mesa/depend diff --git a/U_gallium_util_add_missing_u_math_include.patch b/U_gallium_util_add_missing_u_math_include.patch new file mode 100644 index 0000000..e2830de --- /dev/null +++ b/U_gallium_util_add_missing_u_math_include.patch @@ -0,0 +1,26 @@ +From f19271c7bf73efe6d583e9dc5fc37329558a5cc3 Mon Sep 17 00:00:00 2001 +From: Ilia Mirkin +Date: Thu, 27 Feb 2014 06:07:30 +0000 +Subject: gallium/util: add missing u_math include + +This is needed for MIN2/MAX2 + +Signed-off-by: Ilia Mirkin +Reviewed-by: Marek Olšák +--- +diff --git a/src/gallium/auxiliary/util/u_range.h b/src/gallium/auxiliary/util/u_range.h +index 4b1d0d1..efe25ef 100644 +--- a/src/gallium/auxiliary/util/u_range.h ++++ b/src/gallium/auxiliary/util/u_range.h +@@ -36,6 +36,8 @@ + + #include "os/os_thread.h" + ++#include "util/u_math.h" ++ + struct util_range { + unsigned start; /* inclusive */ + unsigned end; /* exclusive */ +-- +cgit v0.9.0.2-2-gbebe + diff --git a/U_nouveau_add_valid_range_tracking.patch b/U_nouveau_add_valid_range_tracking.patch new file mode 100644 index 0000000..9cd28cb --- /dev/null +++ b/U_nouveau_add_valid_range_tracking.patch @@ -0,0 +1,200 @@ +From 5bf90cb521d1d6f26684b1ce9d0811c636b6abb1 Mon Sep 17 00:00:00 2001 +From: Ilia Mirkin +Date: Thu, 27 Feb 2014 06:07:51 +0000 +Subject: nouveau: add valid range tracking to nouveau_buffer + +This logic is borrowed from the radeon code. The transfer logic will +only get called for PIPE_BUFFER resources, so it shouldn't be necessary +to worry about them becoming render targets. + +Signed-off-by: Ilia Mirkin +Reviewed-by: Christoph Bumiller +--- +diff --git a/src/gallium/drivers/nouveau/nouveau_buffer.c b/src/gallium/drivers/nouveau/nouveau_buffer.c +index 5b0b93b..e308ff4 100644 +--- a/src/gallium/drivers/nouveau/nouveau_buffer.c ++++ b/src/gallium/drivers/nouveau/nouveau_buffer.c +@@ -69,6 +69,8 @@ nouveau_buffer_allocate(struct nouveau_screen *screen, + if (buf->bo) + buf->address = buf->bo->offset + buf->offset; + ++ util_range_set_empty(&buf->valid_buffer_range); ++ + return TRUE; + } + +@@ -124,6 +126,8 @@ nouveau_buffer_destroy(struct pipe_screen *pscreen, + nouveau_fence_ref(NULL, &res->fence); + nouveau_fence_ref(NULL, &res->fence_wr); + ++ util_range_destroy(&res->valid_buffer_range); ++ + FREE(res); + + NOUVEAU_DRV_STAT(nouveau_screen(pscreen), buf_obj_current_count, -1); +@@ -387,6 +391,17 @@ nouveau_buffer_transfer_map(struct pipe_context *pipe, + if (usage & PIPE_TRANSFER_WRITE) + NOUVEAU_DRV_STAT(nv->screen, buf_transfers_wr, 1); + ++ /* If we are trying to write to an uninitialized range, the user shouldn't ++ * care what was there before. So we can treat the write as if the target ++ * range were being discarded. Furthermore, since we know that even if this ++ * buffer is busy due to GPU activity, because the contents were ++ * uninitialized, the GPU can't care what was there, and so we can treat ++ * the write as being unsynchronized. ++ */ ++ if ((usage & PIPE_TRANSFER_WRITE) && ++ !util_ranges_intersect(&buf->valid_buffer_range, box->x, box->x + box->width)) ++ usage |= PIPE_TRANSFER_DISCARD_RANGE | PIPE_TRANSFER_UNSYNCHRONIZED; ++ + if (buf->domain == NOUVEAU_BO_VRAM) { + if (usage & NOUVEAU_TRANSFER_DISCARD) { + /* Set up a staging area for the user to write to. It will be copied +@@ -492,8 +507,14 @@ nouveau_buffer_transfer_flush_region(struct pipe_context *pipe, + const struct pipe_box *box) + { + struct nouveau_transfer *tx = nouveau_transfer(transfer); ++ struct nv04_resource *buf = nv04_resource(transfer->resource); ++ + if (tx->map) + nouveau_transfer_write(nouveau_context(pipe), tx, box->x, box->width); ++ ++ util_range_add(&buf->valid_buffer_range, ++ tx->base.box.x + box->x, ++ tx->base.box.x + box->x + box->width); + } + + /* Unmap stage of the transfer. If it was a WRITE transfer and the map that +@@ -522,6 +543,9 @@ nouveau_buffer_transfer_unmap(struct pipe_context *pipe, + if (bind & (PIPE_BIND_CONSTANT_BUFFER)) + nv->cb_dirty = TRUE; + } ++ ++ util_range_add(&buf->valid_buffer_range, ++ tx->base.box.x, tx->base.box.x + tx->base.box.width); + } + + if (!tx->bo && (tx->base.usage & PIPE_TRANSFER_WRITE)) +@@ -562,6 +586,8 @@ nouveau_copy_buffer(struct nouveau_context *nv, + &dst->base, 0, dstx, 0, 0, + &src->base, 0, &src_box); + } ++ ++ util_range_add(&dst->valid_buffer_range, dstx, dstx + size); + } + + +@@ -659,6 +685,8 @@ nouveau_buffer_create(struct pipe_screen *pscreen, + + NOUVEAU_DRV_STAT(screen, buf_obj_current_count, 1); + ++ util_range_init(&buffer->valid_buffer_range); ++ + return &buffer->base; + + fail: +@@ -690,6 +718,9 @@ nouveau_user_buffer_create(struct pipe_screen *pscreen, void *ptr, + buffer->data = ptr; + buffer->status = NOUVEAU_BUFFER_STATUS_USER_MEMORY; + ++ util_range_init(&buffer->valid_buffer_range); ++ util_range_add(&buffer->valid_buffer_range, 0, bytes); ++ + return &buffer->base; + } + +diff --git a/src/gallium/drivers/nouveau/nouveau_buffer.h b/src/gallium/drivers/nouveau/nouveau_buffer.h +index aeb9b17..f881adc 100644 +--- a/src/gallium/drivers/nouveau/nouveau_buffer.h ++++ b/src/gallium/drivers/nouveau/nouveau_buffer.h +@@ -1,6 +1,7 @@ + #ifndef __NOUVEAU_BUFFER_H__ + #define __NOUVEAU_BUFFER_H__ + ++#include "util/u_range.h" + #include "util/u_transfer.h" + #include "util/u_double_list.h" + +@@ -44,6 +45,9 @@ struct nv04_resource { + struct nouveau_fence *fence_wr; + + struct nouveau_mm_allocation *mm; ++ ++ /* buffer range that has been initialized */ ++ struct util_range valid_buffer_range; + }; + + void +diff --git a/src/gallium/drivers/nouveau/nv50/nv50_resource.c b/src/gallium/drivers/nouveau/nv50/nv50_resource.c +index 7fbb0a9..d289b4a 100644 +--- a/src/gallium/drivers/nouveau/nv50/nv50_resource.c ++++ b/src/gallium/drivers/nouveau/nv50/nv50_resource.c +@@ -68,6 +68,8 @@ nv50_surface_create(struct pipe_context *pipe, + struct pipe_resource *pres, + const struct pipe_surface *templ) + { ++ /* surfaces are assumed to be miptrees all over the place. */ ++ assert(pres->target != PIPE_BUFFER); + if (unlikely(pres->target == PIPE_BUFFER)) + return nv50_surface_from_buffer(pipe, pres, templ); + return nv50_miptree_surface_new(pipe, pres, templ); +diff --git a/src/gallium/drivers/nouveau/nv50/nv50_state.c b/src/gallium/drivers/nouveau/nv50/nv50_state.c +index 288ba46..c03d729 100644 +--- a/src/gallium/drivers/nouveau/nv50/nv50_state.c ++++ b/src/gallium/drivers/nouveau/nv50/nv50_state.c +@@ -1010,6 +1010,7 @@ nv50_so_target_create(struct pipe_context *pipe, + struct pipe_resource *res, + unsigned offset, unsigned size) + { ++ struct nv04_resource *buf = (struct nv04_resource *)res; + struct nv50_so_target *targ = MALLOC_STRUCT(nv50_so_target); + if (!targ) + return NULL; +@@ -1033,6 +1034,9 @@ nv50_so_target_create(struct pipe_context *pipe, + pipe_resource_reference(&targ->pipe.buffer, res); + pipe_reference_init(&targ->pipe.reference, 1); + ++ assert(buf->base.target == PIPE_BUFFER); ++ util_range_add(&buf->valid_buffer_range, offset, offset + size); ++ + return &targ->pipe; + } + +diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_resource.c b/src/gallium/drivers/nouveau/nvc0/nvc0_resource.c +index 4e70903..12b5a02 100644 +--- a/src/gallium/drivers/nouveau/nvc0/nvc0_resource.c ++++ b/src/gallium/drivers/nouveau/nvc0/nvc0_resource.c +@@ -36,6 +36,8 @@ nvc0_surface_create(struct pipe_context *pipe, + struct pipe_resource *pres, + const struct pipe_surface *templ) + { ++ /* surfaces are assumed to be miptrees all over the place. */ ++ assert(pres->target != PIPE_BUFFER); + if (unlikely(pres->target == PIPE_BUFFER)) + return nv50_surface_from_buffer(pipe, pres, templ); + return nvc0_miptree_surface_new(pipe, pres, templ); +diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_state.c b/src/gallium/drivers/nouveau/nvc0/nvc0_state.c +index 0213a8e..dec5355 100644 +--- a/src/gallium/drivers/nouveau/nvc0/nvc0_state.c ++++ b/src/gallium/drivers/nouveau/nvc0/nvc0_state.c +@@ -992,6 +992,7 @@ nvc0_so_target_create(struct pipe_context *pipe, + struct pipe_resource *res, + unsigned offset, unsigned size) + { ++ struct nv04_resource *buf = (struct nv04_resource *)res; + struct nvc0_so_target *targ = MALLOC_STRUCT(nvc0_so_target); + if (!targ) + return NULL; +@@ -1010,6 +1011,9 @@ nvc0_so_target_create(struct pipe_context *pipe, + pipe_resource_reference(&targ->pipe.buffer, res); + pipe_reference_init(&targ->pipe.reference, 1); + ++ assert(buf->base.target == PIPE_BUFFER); ++ util_range_add(&buf->valid_buffer_range, offset, offset + size); ++ + return &targ->pipe; + } + +-- +cgit v0.9.0.2-2-gbebe + diff --git a/U_nouveau_create_only_one_shared_screen.patch b/U_nouveau_create_only_one_shared_screen.patch new file mode 100644 index 0000000..ce6008a --- /dev/null +++ b/U_nouveau_create_only_one_shared_screen.patch @@ -0,0 +1,231 @@ +From fee0686c21c631d96d6042741267a3c218c23ffc Mon Sep 17 00:00:00 2001 +From: Maarten Lankhorst +Date: Wed, 12 Feb 2014 13:56:53 +0000 +Subject: nouveau: create only 1 shared screen between vdpau and opengl + +This fixes bug 73200 "vdpau-GL interop fails due to different screen +objects" in the same way radeon does. + +Signed-off-by: Maarten Lankhorst +Reviewed-by: Emil Velikov +--- +diff --git a/src/gallium/drivers/nouveau/nouveau_screen.c b/src/gallium/drivers/nouveau/nouveau_screen.c +index 21b31e0..f742a94 100644 +--- a/src/gallium/drivers/nouveau/nouveau_screen.c ++++ b/src/gallium/drivers/nouveau/nouveau_screen.c +@@ -144,6 +144,12 @@ nouveau_screen_init(struct nouveau_screen *screen, struct nouveau_device *dev) + if (nv_dbg) + nouveau_mesa_debug = atoi(nv_dbg); + ++ /* ++ * this is initialized to 1 in nouveau_drm_screen_create after screen ++ * is fully constructed and added to the global screen list. ++ */ ++ screen->refcount = -1; ++ + if (dev->chipset < 0xc0) { + data = &nv04_data; + size = sizeof(nv04_data); +diff --git a/src/gallium/drivers/nouveau/nouveau_screen.h b/src/gallium/drivers/nouveau/nouveau_screen.h +index 51e24fa..cf06f7e 100644 +--- a/src/gallium/drivers/nouveau/nouveau_screen.h ++++ b/src/gallium/drivers/nouveau/nouveau_screen.h +@@ -22,6 +22,8 @@ struct nouveau_screen { + struct nouveau_client *client; + struct nouveau_pushbuf *pushbuf; + ++ int refcount; ++ + unsigned vidmem_bindings; /* PIPE_BIND_* where VRAM placement is desired */ + unsigned sysmem_bindings; /* PIPE_BIND_* where GART placement is desired */ + unsigned lowmem_bindings; /* PIPE_BIND_* that require an address < 4 GiB */ +@@ -112,6 +114,8 @@ nouveau_screen(struct pipe_screen *pscreen) + return (struct nouveau_screen *)pscreen; + } + ++boolean nouveau_drm_screen_unref(struct nouveau_screen *screen); ++ + boolean + nouveau_screen_bo_get_handle(struct pipe_screen *pscreen, + struct nouveau_bo *bo, +diff --git a/src/gallium/drivers/nouveau/nv30/nv30_screen.c b/src/gallium/drivers/nouveau/nv30/nv30_screen.c +index c027a5f..9854708 100644 +--- a/src/gallium/drivers/nouveau/nv30/nv30_screen.c ++++ b/src/gallium/drivers/nouveau/nv30/nv30_screen.c +@@ -302,6 +302,9 @@ nv30_screen_destroy(struct pipe_screen *pscreen) + { + struct nv30_screen *screen = nv30_screen(pscreen); + ++ if (!nouveau_drm_screen_unref(&screen->base)) ++ return; ++ + if (screen->base.fence.current && + screen->base.fence.current->state >= NOUVEAU_FENCE_STATE_EMITTED) { + nouveau_fence_wait(screen->base.fence.current); +diff --git a/src/gallium/drivers/nouveau/nv50/nv50_screen.c b/src/gallium/drivers/nouveau/nv50/nv50_screen.c +index e636bf8..db3265f 100644 +--- a/src/gallium/drivers/nouveau/nv50/nv50_screen.c ++++ b/src/gallium/drivers/nouveau/nv50/nv50_screen.c +@@ -287,6 +287,9 @@ nv50_screen_destroy(struct pipe_screen *pscreen) + { + struct nv50_screen *screen = nv50_screen(pscreen); + ++ if (!nouveau_drm_screen_unref(&screen->base)) ++ return; ++ + if (screen->base.fence.current) { + nouveau_fence_wait(screen->base.fence.current); + nouveau_fence_ref (NULL, &screen->base.fence.current); +diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c b/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c +index 28d9be2..f04771d 100644 +--- a/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c ++++ b/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c +@@ -333,6 +333,9 @@ nvc0_screen_destroy(struct pipe_screen *pscreen) + { + struct nvc0_screen *screen = nvc0_screen(pscreen); + ++ if (!nouveau_drm_screen_unref(&screen->base)) ++ return; ++ + if (screen->base.fence.current) { + nouveau_fence_wait(screen->base.fence.current); + nouveau_fence_ref(NULL, &screen->base.fence.current); +diff --git a/src/gallium/targets/dri-nouveau/Makefile.am b/src/gallium/targets/dri-nouveau/Makefile.am +index 1988067..4bd4e21 100644 +--- a/src/gallium/targets/dri-nouveau/Makefile.am ++++ b/src/gallium/targets/dri-nouveau/Makefile.am +@@ -20,6 +20,7 @@ + # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + # DEALINGS IN THE SOFTWARE. + ++DRI_VERSION_SCRIPT = $(srcdir)/nouveau_dri.link + include $(top_srcdir)/src/gallium/Automake.inc + + AM_CFLAGS = \ +diff --git a/src/gallium/targets/dri-nouveau/nouveau_dri.link b/src/gallium/targets/dri-nouveau/nouveau_dri.link +new file mode 100644 +index 0000000..16015aa +--- a/dev/null ++++ b/src/gallium/targets/dri-nouveau/nouveau_dri.link +@@ -0,0 +1,6 @@ ++VERSION { ++ global: ++ __driDriverExtensions; ++ nouveau_drm_screen_create; ++ local: *; ++}; +diff --git a/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c b/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c +index e4f27f6..a077c48 100644 +--- a/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c ++++ b/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c +@@ -1,24 +1,83 @@ ++#include + #include "pipe/p_context.h" + #include "pipe/p_state.h" + #include "util/u_format.h" + #include "util/u_memory.h" + #include "util/u_inlines.h" ++#include "util/u_hash_table.h" ++#include "os/os_thread.h" + + #include "nouveau_drm_public.h" + + #include "nouveau/nouveau_winsys.h" + #include "nouveau/nouveau_screen.h" + +-struct pipe_screen * ++static struct util_hash_table *fd_tab = NULL; ++ ++pipe_static_mutex(nouveau_screen_mutex); ++ ++boolean nouveau_drm_screen_unref(struct nouveau_screen *screen) ++{ ++ int ret; ++ if (screen->refcount == -1) ++ return true; ++ ++ pipe_mutex_lock(nouveau_screen_mutex); ++ ret = --screen->refcount; ++ assert(ret >= 0); ++ if (ret == 0) ++ util_hash_table_remove(fd_tab, intptr_to_pointer(screen->device->fd)); ++ pipe_mutex_unlock(nouveau_screen_mutex); ++ return ret == 0; ++} ++ ++static unsigned hash_fd(void *key) ++{ ++ int fd = pointer_to_intptr(key); ++ struct stat stat; ++ fstat(fd, &stat); ++ ++ return stat.st_dev ^ stat.st_ino ^ stat.st_rdev; ++} ++ ++static int compare_fd(void *key1, void *key2) ++{ ++ int fd1 = pointer_to_intptr(key1); ++ int fd2 = pointer_to_intptr(key2); ++ struct stat stat1, stat2; ++ fstat(fd1, &stat1); ++ fstat(fd2, &stat2); ++ ++ return stat1.st_dev != stat2.st_dev || ++ stat1.st_ino != stat2.st_ino || ++ stat1.st_rdev != stat2.st_rdev; ++} ++ ++PUBLIC struct pipe_screen * + nouveau_drm_screen_create(int fd) + { + struct nouveau_device *dev = NULL; + struct pipe_screen *(*init)(struct nouveau_device *); ++ struct nouveau_screen *screen; + int ret; + ++ pipe_mutex_lock(nouveau_screen_mutex); ++ if (!fd_tab) { ++ fd_tab = util_hash_table_create(hash_fd, compare_fd); ++ if (!fd_tab) ++ goto err; ++ } ++ ++ screen = util_hash_table_get(fd_tab, intptr_to_pointer(fd)); ++ if (screen) { ++ screen->refcount++; ++ pipe_mutex_unlock(nouveau_screen_mutex); ++ return &screen->base; ++ } ++ + ret = nouveau_device_wrap(fd, 0, &dev); + if (ret) +- return NULL; ++ goto err; + + switch (dev->chipset & ~0xf) { + case 0x30: +@@ -42,8 +101,19 @@ nouveau_drm_screen_create(int fd) + default: + debug_printf("%s: unknown chipset nv%02x\n", __func__, + dev->chipset); +- return NULL; ++ goto err; + } + +- return init(dev); ++ screen = (struct nouveau_screen*)init(dev); ++ if (!screen) ++ goto err; ++ ++ util_hash_table_set(fd_tab, intptr_to_pointer(fd), screen); ++ screen->refcount = 1; ++ pipe_mutex_unlock(nouveau_screen_mutex); ++ return &screen->base; ++ ++err: ++ pipe_mutex_unlock(nouveau_screen_mutex); ++ return NULL; + } +-- +cgit v0.9.0.2-2-gbebe + diff --git a/U_nouveau_fix_fence_waiting_logic.patch b/U_nouveau_fix_fence_waiting_logic.patch new file mode 100644 index 0000000..99a86c2 --- /dev/null +++ b/U_nouveau_fix_fence_waiting_logic.patch @@ -0,0 +1,85 @@ +From 507f0230d4ca2238c818006499e21abb4c133203 Mon Sep 17 00:00:00 2001 +From: Ilia Mirkin +Date: Thu, 06 Mar 2014 03:25:55 +0000 +Subject: nouveau: fix fence waiting logic in screen destroy + +nouveau_fence_wait has the expectation that an external entity is +holding onto the fence being waited on, not that it is merely held onto +by the current pointer. Fixes a use-after-free in nouveau_fence_wait +when used on the screen's current fence. + +Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=75279 +Signed-off-by: Ilia Mirkin +Reviewed-by: Christoph Bumiller +Cc: "9.2 10.0 10.1" +--- +diff --git a/src/gallium/drivers/nouveau/nv30/nv30_screen.c b/src/gallium/drivers/nouveau/nv30/nv30_screen.c +index 82f2c06..5378913 100644 +--- a/src/gallium/drivers/nouveau/nv30/nv30_screen.c ++++ b/src/gallium/drivers/nouveau/nv30/nv30_screen.c +@@ -308,10 +308,16 @@ nv30_screen_destroy(struct pipe_screen *pscreen) + if (!nouveau_drm_screen_unref(&screen->base)) + return; + +- if (screen->base.fence.current && +- screen->base.fence.current->state >= NOUVEAU_FENCE_STATE_EMITTED) { +- nouveau_fence_wait(screen->base.fence.current); +- nouveau_fence_ref (NULL, &screen->base.fence.current); ++ if (screen->base.fence.current) { ++ struct nouveau_fence *current = NULL; ++ ++ /* nouveau_fence_wait will create a new current fence, so wait on the ++ * _current_ one, and remove both. ++ */ ++ nouveau_fence_ref(screen->base.fence.current, ¤t); ++ nouveau_fence_wait(current); ++ nouveau_fence_ref(NULL, ¤t); ++ nouveau_fence_ref(NULL, &screen->base.fence.current); + } + + nouveau_object_del(&screen->query); +diff --git a/src/gallium/drivers/nouveau/nv50/nv50_screen.c b/src/gallium/drivers/nouveau/nv50/nv50_screen.c +index ab0d63e..e8c7fe3 100644 +--- a/src/gallium/drivers/nouveau/nv50/nv50_screen.c ++++ b/src/gallium/drivers/nouveau/nv50/nv50_screen.c +@@ -294,8 +294,15 @@ nv50_screen_destroy(struct pipe_screen *pscreen) + return; + + if (screen->base.fence.current) { +- nouveau_fence_wait(screen->base.fence.current); +- nouveau_fence_ref (NULL, &screen->base.fence.current); ++ struct nouveau_fence *current = NULL; ++ ++ /* nouveau_fence_wait will create a new current fence, so wait on the ++ * _current_ one, and remove both. ++ */ ++ nouveau_fence_ref(screen->base.fence.current, ¤t); ++ nouveau_fence_wait(current); ++ nouveau_fence_ref(NULL, ¤t); ++ nouveau_fence_ref(NULL, &screen->base.fence.current); + } + if (screen->base.pushbuf) + screen->base.pushbuf->user_priv = NULL; +diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c b/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c +index 044847d..04f3088 100644 +--- a/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c ++++ b/src/gallium/drivers/nouveau/nvc0/nvc0_screen.c +@@ -340,7 +340,14 @@ nvc0_screen_destroy(struct pipe_screen *pscreen) + return; + + if (screen->base.fence.current) { +- nouveau_fence_wait(screen->base.fence.current); ++ struct nouveau_fence *current = NULL; ++ ++ /* nouveau_fence_wait will create a new current fence, so wait on the ++ * _current_ one, and remove both. ++ */ ++ nouveau_fence_ref(screen->base.fence.current, ¤t); ++ nouveau_fence_wait(current); ++ nouveau_fence_ref(NULL, ¤t); + nouveau_fence_ref(NULL, &screen->base.fence.current); + } + if (screen->base.pushbuf) +-- +cgit v0.9.0.2-2-gbebe +