1 /*
2 * Copyright © 2018 Broadcom
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include <sys/stat.h>
25
26 #include "pipe/p_screen.h"
27 #include "util/u_screen.h"
28 #include "util/u_debug.h"
29 #include "util/os_file.h"
30 #include "util/os_time.h"
31 #include "util/simple_mtx.h"
32 #include "util/u_hash_table.h"
33 #include "util/u_pointer.h"
34 #include "util/macros.h"
35
36 #ifdef HAVE_LIBDRM
37 #include <xf86drm.h>
38 #endif
39
40 void
u_init_pipe_screen_caps(struct pipe_screen * pscreen,int accel)41 u_init_pipe_screen_caps(struct pipe_screen *pscreen, int accel)
42 {
43 struct pipe_caps *caps = (struct pipe_caps *)&pscreen->caps;
44
45 caps->accelerated = accel;
46 caps->graphics = true;
47 caps->gl_clamp = true;
48 caps->max_render_targets = true;
49 caps->mixed_colorbuffer_formats = true;
50 caps->dithering = true;
51
52 caps->supported_prim_modes_with_restart =
53 caps->supported_prim_modes = BITFIELD_MASK(MESA_PRIM_COUNT);
54
55 /* GL 3.x minimum value. */
56 caps->min_texel_offset = -8;
57 caps->max_texel_offset = 7;
58
59 /* GL_EXT_transform_feedback minimum value. */
60 caps->max_stream_output_separate_components = 4;
61 caps->max_stream_output_interleaved_components = 64;
62
63 /* Minimum GLSL level implemented by gallium drivers. */
64 caps->glsl_feature_level =
65 caps->glsl_feature_level_compatibility = 120;
66
67 caps->vertex_input_alignment = PIPE_VERTEX_INPUT_ALIGNMENT_NONE;
68
69 /* GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT default value. */
70 caps->constant_buffer_offset_alignment = 1;
71
72 /* GL_ARB_map_buffer_alignment minimum value. All drivers expose the extension. */
73 caps->min_map_buffer_alignment = 64;
74
75 /* GL_EXT_texture_buffer minimum value. */
76 caps->texture_buffer_offset_alignment = 256;
77
78 caps->texture_transfer_modes = PIPE_TEXTURE_TRANSFER_BLIT;
79
80 /* GL_EXT_texture_buffer minimum value. */
81 caps->max_texel_buffer_elements = 65536;
82
83 caps->max_viewports = 1;
84
85 caps->endianness = PIPE_ENDIAN_LITTLE;
86
87 /* All new drivers should support persistent/coherent mappings. This CAP
88 * should only be unset by layered drivers whose host drivers cannot support
89 * coherent mappings.
90 */
91 caps->buffer_map_persistent_coherent = true;
92
93 caps->min_texture_gather_offset = -8;
94 caps->max_texture_gather_offset = 7;
95
96 caps->vendor_id =
97 caps->device_id = 0xffffffff;
98
99 /* GL minimum value */
100 caps->max_vertex_attrib_stride = 2048;
101
102 /* All drivers should expose this cap, as it is required for applications to
103 * be able to efficiently compile GL shaders from multiple threads during
104 * load.
105 */
106 caps->shareable_shaders = true;
107
108 caps->multi_draw_indirect_partial_stride = true;
109
110 /* GLES 2.0 minimum value */
111 caps->rasterizer_subpixel_bits = 4;
112
113 caps->prefer_back_buffer_reuse = true;
114
115 /* Drivers generally support this, and it reduces GL overhead just to
116 * throw an error when buffers are mapped.
117 */
118 caps->allow_mapped_buffers_during_execution = true;
119
120 /* Don't unset this unless your driver can do better, like using nir_opt_large_constants() */
121 caps->prefer_imm_arrays_as_constbuf = true;
122
123 caps->max_gs_invocations = 32;
124
125 caps->max_shader_buffer_size = 1 << 27;
126
127 caps->max_vertex_element_src_offset = 2047;
128
129 caps->dest_surface_srgb_control = true;
130
131 caps->max_varyings = 8;
132
133 caps->throttle = true;
134
135 #if defined(HAVE_LIBDRM) && (DETECT_OS_LINUX || DETECT_OS_BSD || DETECT_OS_MANAGARM)
136 if (pscreen->get_screen_fd) {
137 uint64_t cap;
138 int fd = pscreen->get_screen_fd(pscreen);
139 if (fd != -1 && (drmGetCap(fd, DRM_CAP_PRIME, &cap) == 0))
140 caps->dmabuf = cap;
141 }
142 #endif
143
144 /* Enables ARB_shadow */
145 caps->texture_shadow_map = true;
146
147 caps->flatshade = true;
148 caps->alpha_test = true;
149 caps->point_size_fixed = true;
150 caps->two_sided_color = true;
151 caps->clip_planes = 1;
152
153 caps->max_vertex_buffers = 16;
154
155 caps->nir_images_as_deref = true;
156
157 caps->packed_stream_output = true;
158
159 caps->gl_begin_end_buffer_size = 512 * 1024;
160
161 caps->texrect = true;
162
163 caps->allow_dynamic_vao_fastpath = true;
164
165 caps->max_constant_buffer_size =
166 pscreen->get_shader_param(pscreen, PIPE_SHADER_FRAGMENT,
167 PIPE_SHADER_CAP_MAX_CONST_BUFFER0_SIZE);
168
169 /* accel=0: on CPU, always disabled
170 * accel>0: on GPU, enable by default, user can disable it manually
171 * accel<0: unknown, disable by default, user can enable it manually
172 */
173 caps->hardware_gl_select =
174 !!accel && debug_get_bool_option("MESA_HW_ACCEL_SELECT", accel > 0) &&
175 /* internal geometry shader need indirect array access */
176 pscreen->get_shader_param(pscreen, PIPE_SHADER_GEOMETRY,
177 PIPE_SHADER_CAP_INDIRECT_TEMP_ADDR) &&
178 /* internal geometry shader need SSBO support */
179 pscreen->get_shader_param(pscreen, PIPE_SHADER_GEOMETRY,
180 PIPE_SHADER_CAP_MAX_SHADER_BUFFERS);
181
182 caps->query_timestamp_bits = 64;
183
184 /* this is expected of gallium drivers, but some just don't support it */
185 caps->texture_sampler_independent = true;
186
187 caps->performance_monitor =
188 pscreen->get_driver_query_info && pscreen->get_driver_query_group_info &&
189 pscreen->get_driver_query_group_info(pscreen, 0, NULL) != 0;
190 }
191
u_default_get_timestamp(UNUSED struct pipe_screen * screen)192 uint64_t u_default_get_timestamp(UNUSED struct pipe_screen *screen)
193 {
194 return os_time_get_nano();
195 }
196
197 static uint32_t
hash_file_description(const void * key)198 hash_file_description(const void *key)
199 {
200 int fd = pointer_to_intptr(key);
201 struct stat stat;
202
203 // File descriptions can't be hashed, but it should be safe to assume
204 // that the same file description will always refer to he same file
205 if (fstat(fd, &stat) == -1)
206 return ~0; // Make sure fstat failing won't result in a random hash
207
208 return stat.st_dev ^ stat.st_ino ^ stat.st_rdev;
209 }
210
211
212 static bool
equal_file_description(const void * key1,const void * key2)213 equal_file_description(const void *key1, const void *key2)
214 {
215 int ret;
216 int fd1 = pointer_to_intptr(key1);
217 int fd2 = pointer_to_intptr(key2);
218 struct stat stat1, stat2;
219
220 // If the file descriptors are the same, the file description will be too
221 // This will also catch sentinels, such as -1
222 if (fd1 == fd2)
223 return true;
224
225 ret = os_same_file_description(fd1, fd2);
226 if (ret >= 0)
227 return (ret == 0);
228
229 {
230 static bool has_warned;
231 if (!has_warned)
232 fprintf(stderr, "os_same_file_description couldn't determine if "
233 "two DRM fds reference the same file description. (%s)\n"
234 "Let's just assume that file descriptors for the same file probably"
235 "share the file description instead. This may cause problems when"
236 "that isn't the case.\n", strerror(errno));
237 has_warned = true;
238 }
239
240 // Let's at least check that it's the same file, different files can't
241 // have the same file descriptions
242 fstat(fd1, &stat1);
243 fstat(fd2, &stat2);
244
245 return stat1.st_dev == stat2.st_dev &&
246 stat1.st_ino == stat2.st_ino &&
247 stat1.st_rdev == stat2.st_rdev;
248 }
249
250
251 static struct hash_table *
hash_table_create_file_description_keys(void)252 hash_table_create_file_description_keys(void)
253 {
254 return _mesa_hash_table_create(NULL, hash_file_description, equal_file_description);
255 }
256
257 static struct hash_table *fd_tab = NULL;
258
259 static simple_mtx_t screen_mutex = SIMPLE_MTX_INITIALIZER;
260
261 static void
drm_screen_destroy(struct pipe_screen * pscreen)262 drm_screen_destroy(struct pipe_screen *pscreen)
263 {
264 bool destroy;
265
266 simple_mtx_lock(&screen_mutex);
267 destroy = --pscreen->refcnt == 0;
268 if (destroy) {
269 int fd = pscreen->get_screen_fd(pscreen);
270 _mesa_hash_table_remove_key(fd_tab, intptr_to_pointer(fd));
271
272 if (!fd_tab->entries) {
273 _mesa_hash_table_destroy(fd_tab, NULL);
274 fd_tab = NULL;
275 }
276 }
277 simple_mtx_unlock(&screen_mutex);
278
279 if (destroy) {
280 pscreen->destroy = pscreen->winsys_priv;
281 pscreen->destroy(pscreen);
282 }
283 }
284
285 struct pipe_screen *
u_pipe_screen_lookup_or_create(int gpu_fd,const struct pipe_screen_config * config,struct renderonly * ro,pipe_screen_create_function screen_create)286 u_pipe_screen_lookup_or_create(int gpu_fd,
287 const struct pipe_screen_config *config,
288 struct renderonly *ro,
289 pipe_screen_create_function screen_create)
290 {
291 struct pipe_screen *pscreen = NULL;
292
293 simple_mtx_lock(&screen_mutex);
294 if (!fd_tab) {
295 fd_tab = hash_table_create_file_description_keys();
296 if (!fd_tab)
297 goto unlock;
298 }
299
300 pscreen = util_hash_table_get(fd_tab, intptr_to_pointer(gpu_fd));
301 if (pscreen) {
302 pscreen->refcnt++;
303 } else {
304 pscreen = screen_create(gpu_fd, config, ro);
305 if (pscreen) {
306 pscreen->refcnt = 1;
307 _mesa_hash_table_insert(fd_tab, intptr_to_pointer(gpu_fd), pscreen);
308
309 /* Bit of a hack, to avoid circular linkage dependency,
310 * ie. pipe driver having to call in to winsys, we
311 * override the pipe drivers screen->destroy() */
312 pscreen->winsys_priv = pscreen->destroy;
313 pscreen->destroy = drm_screen_destroy;
314 }
315 }
316
317 unlock:
318 simple_mtx_unlock(&screen_mutex);
319 return pscreen;
320 }
321