• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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