summaryrefslogtreecommitdiff
path: root/chromium-119-nvidia-use-separate-bo-to-verify-modifier.patch
blob: 717d897446c7c43dc3f352715e7170ef963c124c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
commit bdcc23e0a5e7e220660d3f54c97262f9a4c31606
Author: Nick Diego Yamane <nickdiego@igalia.com>
Date:   Thu Nov 2 17:26:25 2023 +0000

    gbm: nvidia: use separate bo to verify modifiers
    
    Buggy Nvidia drivers fail to return FDs for planes of a BO which had
    already an imported BO destroyed before. This is a workaround for that
    issue, which consists of creating/destroying a separate 1x1 BO for
    validating the modifiers before actually creating the final requested
    BO, which for now is limited to IS_LINUX builds.
    
    The Nvidia driver bug is being tracked under internal bug 4315529. There
    seems to be other issues when running under Wayland with Nvidia, which
    will be tracked and addressed in separate patches.
    
    R=dcastagna, msisov@igalia.com
    
      with ozone/wayland backend and verify GPU acceleration is not broken.
    
    Test: In a single Nvidia GPU setup, with proprietary driver, run Chrome
    Bug: 1273758, 1478684, 1463851
    Change-Id: I9f322bcf40b460bcd4ead02f05dd2e9a8d271cea
    Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4989782
    Reviewed-by: Maksim Sisov <msisov@igalia.com>
    Commit-Queue: Nick Yamane <nickdiego@igalia.com>
    Cr-Commit-Position: refs/heads/main@{#1218924}

diff --git a/ui/gfx/linux/gbm_wrapper.cc b/ui/gfx/linux/gbm_wrapper.cc
index bf90b76605f68..14918c19c0ab0 100644
--- a/ui/gfx/linux/gbm_wrapper.cc
+++ b/ui/gfx/linux/gbm_wrapper.cc
@@ -11,6 +11,7 @@
 #include "base/logging.h"
 #include "base/memory/raw_ptr.h"
 #include "base/memory/raw_ptr_exclusion.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/posix/eintr_wrapper.h"
 #include "skia/ext/legacy_display_globals.h"
 #include "third_party/skia/include/core/SkSurface.h"
@@ -71,6 +72,7 @@ base::ScopedFD GetPlaneFdForBo(gbm_bo* bo, size_t plane) {
   int ret;
   // Use DRM_RDWR to allow the fd to be mappable in another process.
   ret = drmPrimeHandleToFD(dev_fd, plane_handle, DRM_CLOEXEC | DRM_RDWR, &fd);
+  PLOG_IF(ERROR, ret != 0) << "Failed to get fd for plane.";
 
   // Older DRM implementations blocked DRM_RDWR, but gave a read/write mapping
   // anyways
@@ -301,58 +303,82 @@ class Device final : public ui::GbmDevice {
 
   std::unique_ptr<ui::GbmBuffer> CreateBufferWithModifiers(
       uint32_t format,
-      const gfx::Size& size,
+      const gfx::Size& requested_size,
       uint32_t flags,
       const std::vector<uint64_t>& modifiers) override {
-    if (modifiers.empty())
-      return CreateBuffer(format, size, flags);
-
-    std::vector<uint64_t> filtered_modifiers =
-        GetFilteredModifiers(format, flags, modifiers);
-    struct gbm_bo* bo = nullptr;
-    while (filtered_modifiers.size() > 0) {
-      bo = gbm_bo_create_with_modifiers(device_, size.width(), size.height(),
-                                        format, filtered_modifiers.data(),
-                                        filtered_modifiers.size());
-      if (!bo) {
+    if (modifiers.empty()) {
+      return CreateBuffer(format, requested_size, flags);
+    }
+
+    // Buggy drivers prevent us from getting plane FDs from a BO which had its
+    // previously imported BO destroyed. E.g: Nvidia. Thus, on Linux Desktop, we
+    // do the create/import modifiers validation loop below using a separate set
+    // of 1x1 BOs which are destroyed before creating the final BO creation used
+    // to instantiate the returned GbmBuffer.
+    gfx::Size size =
+#if BUILDFLAG(IS_LINUX)
+        gfx::Size(1, 1);
+#else
+        requested_size;
+#endif
+    auto filtered_modifiers = GetFilteredModifiers(format, flags, modifiers);
+    struct gbm_bo* created_bo = nullptr;
+    bool valid_modifiers = false;
+
+    while (!valid_modifiers && !filtered_modifiers.empty()) {
+      created_bo = gbm_bo_create_with_modifiers(
+          device_, size.width(), size.height(), format,
+          filtered_modifiers.data(), filtered_modifiers.size());
+      if (!created_bo) {
         return nullptr;
       }
 
-      struct gbm_import_fd_modifier_data fd_data;
-      fd_data.width = size.width();
-      fd_data.height = size.height();
-      fd_data.format = format;
-      fd_data.num_fds = gbm_bo_get_plane_count(bo);
-      fd_data.modifier = gbm_bo_get_modifier(bo);
-
-      // Store fds in the vector of base::ScopedFDs. Will be released
-      // automatically.
+      const int planes_count = gbm_bo_get_plane_count(created_bo);
+      struct gbm_import_fd_modifier_data fd_data = {
+          .width = base::checked_cast<uint32_t>(size.width()),
+          .height = base::checked_cast<uint32_t>(size.height()),
+          .format = format,
+          .num_fds = base::checked_cast<uint32_t>(planes_count),
+          .modifier = gbm_bo_get_modifier(created_bo)};
+      // Store fds in a base::ScopedFDs vector. Will be released automatically.
       std::vector<base::ScopedFD> fds;
       for (size_t i = 0; i < static_cast<size_t>(fd_data.num_fds); ++i) {
-        fds.emplace_back(GetPlaneFdForBo(bo, i));
+        fds.emplace_back(GetPlaneFdForBo(created_bo, i));
         fd_data.fds[i] = fds.back().get();
-        fd_data.strides[i] = gbm_bo_get_stride_for_plane(bo, i);
-        fd_data.offsets[i] = gbm_bo_get_offset(bo, i);
+        fd_data.strides[i] = gbm_bo_get_stride_for_plane(created_bo, i);
+        fd_data.offsets[i] = gbm_bo_get_offset(created_bo, i);
       }
 
-      struct gbm_bo* bo_import =
+      struct gbm_bo* imported_bo =
           gbm_bo_import(device_, GBM_BO_IMPORT_FD_MODIFIER, &fd_data, flags);
-      if (bo_import) {
-        gbm_bo_destroy(bo_import);
-        break;
+
+      if (imported_bo) {
+        valid_modifiers = true;
+        gbm_bo_destroy(imported_bo);
       } else {
-        gbm_bo_destroy(bo);
-        bo = nullptr;
         AddModifierToBlocklist(format, flags, fd_data.modifier);
         filtered_modifiers =
             GetFilteredModifiers(format, flags, filtered_modifiers);
       }
+
+      if (!valid_modifiers || size != requested_size) {
+        gbm_bo_destroy(created_bo);
+        created_bo = nullptr;
+      }
     }
-    if (!bo) {
-      return nullptr;
+
+    // If modifiers were successfully verified though `created_bo` is null here,
+    // it it means that the buffer created for verification could not be reused,
+    // ie: different size, so create it now with the `requested_size`.
+    if (valid_modifiers && !created_bo) {
+      created_bo = gbm_bo_create_with_modifiers(
+          device_, requested_size.width(), requested_size.height(), format,
+          filtered_modifiers.data(), filtered_modifiers.size());
+      PLOG_IF(ERROR, !created_bo) << "Failed to create BO with modifiers.";
     }
 
-    return CreateBufferForBO(bo, format, size, flags);
+    return created_bo ? CreateBufferForBO(created_bo, format, size, flags)
+                      : nullptr;
   }
 
   std::unique_ptr<ui::GbmBuffer> CreateBufferFromHandle(