1 /**************************************************************************
2 *
3 * Copyright (C) 2014 Red Hat Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR 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
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
22 *
23 **************************************************************************/
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <unistd.h>
29 #include <stdio.h>
30 #include <errno.h>
31 #include "pipe/p_shader_tokens.h"
32
33 #include "pipe/p_context.h"
34 #include "pipe/p_defines.h"
35 #include "pipe/p_screen.h"
36 #include "pipe/p_state.h"
37 #include "util/u_inlines.h"
38 #include "util/u_memory.h"
39 #include "util/u_dual_blend.h"
40
41 #include "os/os_thread.h"
42 #include "util/u_format.h"
43 #include "tgsi/tgsi_parse.h"
44
45 #include "vrend_object.h"
46 #include "vrend_shader.h"
47
48 #include "vrend_renderer.h"
49 #include "vrend_debug.h"
50 #include "vrend_winsys.h"
51
52 #include "virgl_util.h"
53
54 #include "virgl_hw.h"
55 #include "virgl_resource.h"
56 #include "virglrenderer.h"
57 #include "virglrenderer_hw.h"
58 #include "virgl_protocol.h"
59
60 #include "tgsi/tgsi_text.h"
61
62 #ifdef HAVE_EPOXY_GLX_H
63 #include <epoxy/glx.h>
64 #endif
65
66 /*
67 * VIRGL_RENDERER_CAPSET_VIRGL has version 0 and 1, but they are both
68 * virgl_caps_v1 and are exactly the same.
69 *
70 * VIRGL_RENDERER_CAPSET_VIRGL2 has version 0, 1, and 2, but they are
71 * all virgl_caps_v2 and are exactly the same.
72 *
73 * Since virgl_caps_v2 is growable and no backward-incompatible change is
74 * expected, we don't bump up these versions anymore.
75 */
76 #define VREND_CAPSET_VIRGL_MAX_VERSION 1
77 #define VREND_CAPSET_VIRGL2_MAX_VERSION 2
78
79 static const uint32_t fake_occlusion_query_samples_passed_default = 1024;
80
81 const struct vrend_if_cbs *vrend_clicbs;
82
83 struct vrend_fence {
84 /* When the sync thread is waiting on the fence and the main thread
85 * destroys the context, ctx is set to NULL. Otherwise, ctx is always
86 * valid.
87 */
88 struct vrend_context *ctx;
89 uint32_t flags;
90 void *fence_cookie;
91
92 union {
93 GLsync glsyncobj;
94 #ifdef HAVE_EPOXY_EGL_H
95 EGLSyncKHR eglsyncobj;
96 #endif
97 };
98 struct list_head fences;
99 };
100
101 struct vrend_query {
102 struct list_head waiting_queries;
103
104 GLuint id;
105 GLuint type;
106 GLuint index;
107 GLuint gltype;
108 struct vrend_context *ctx;
109 struct vrend_resource *res;
110 uint64_t current_total;
111 bool fake_samples_passed;
112 };
113
114 struct global_error_state {
115 enum virgl_errors last_error;
116 };
117
118 enum features_id
119 {
120 feat_arb_or_gles_ext_texture_buffer,
121 feat_arb_robustness,
122 feat_arb_buffer_storage,
123 feat_arrays_of_arrays,
124 feat_ati_meminfo,
125 feat_atomic_counters,
126 feat_base_instance,
127 feat_barrier,
128 feat_bind_vertex_buffers,
129 feat_bit_encoding,
130 feat_blend_equation_advanced,
131 feat_clear_texture,
132 feat_clip_control,
133 feat_compute_shader,
134 feat_copy_image,
135 feat_conditional_render_inverted,
136 feat_conservative_depth,
137 feat_cube_map_array,
138 feat_cull_distance,
139 feat_debug_cb,
140 feat_depth_clamp,
141 feat_draw_instance,
142 feat_dual_src_blend,
143 feat_egl_image_external,
144 feat_egl_image_storage,
145 feat_enhanced_layouts,
146 feat_fb_no_attach,
147 feat_framebuffer_fetch,
148 feat_framebuffer_fetch_non_coherent,
149 feat_geometry_shader,
150 feat_gl_conditional_render,
151 feat_gl_prim_restart,
152 feat_gles_khr_robustness,
153 feat_gles31_compatibility,
154 feat_gles31_vertex_attrib_binding,
155 feat_gpu_shader5,
156 feat_images,
157 feat_indep_blend,
158 feat_indep_blend_func,
159 feat_indirect_draw,
160 feat_indirect_params,
161 feat_khr_debug,
162 feat_memory_object,
163 feat_memory_object_fd,
164 feat_mesa_invert,
165 feat_ms_scaled_blit,
166 feat_multisample,
167 feat_multi_draw_indirect,
168 feat_nv_conditional_render,
169 feat_nv_prim_restart,
170 feat_nvx_gpu_memory_info,
171 feat_polygon_offset_clamp,
172 feat_occlusion_query,
173 feat_occlusion_query_boolean,
174 feat_qbo,
175 feat_robust_buffer_access,
176 feat_sample_mask,
177 feat_sample_shading,
178 feat_samplers,
179 feat_sampler_border_colors,
180 feat_shader_clock,
181 feat_separate_shader_objects,
182 feat_ssbo,
183 feat_ssbo_barrier,
184 feat_srgb_write_control,
185 feat_stencil_texturing,
186 feat_storage_multisample,
187 feat_tessellation,
188 feat_texture_array,
189 feat_texture_barrier,
190 feat_texture_buffer_range,
191 feat_texture_gather,
192 feat_texture_multisample,
193 feat_texture_query_lod,
194 feat_texture_srgb_decode,
195 feat_texture_storage,
196 feat_texture_view,
197 feat_timer_query,
198 feat_transform_feedback,
199 feat_transform_feedback2,
200 feat_transform_feedback3,
201 feat_transform_feedback_overflow_query,
202 feat_txqs,
203 feat_ubo,
204 feat_viewport_array,
205 feat_implicit_msaa,
206 feat_anisotropic_filter,
207 feat_last,
208 };
209
210 #define FEAT_MAX_EXTS 4
211 #define UNAVAIL INT_MAX
212
213 #define FEAT(NAME, GLVER, GLESVER, ...) \
214 [feat_ ## NAME ] = {GLVER, GLESVER, { __VA_ARGS__ }, #NAME}
215
216 static const struct {
217 int gl_ver;
218 int gles_ver;
219 const char *gl_ext[FEAT_MAX_EXTS];
220 const char *log_name;
221 } feature_list[] = {
222 FEAT(arb_or_gles_ext_texture_buffer, 31, UNAVAIL, "GL_ARB_texture_buffer_object", "GL_EXT_texture_buffer", NULL),
223 FEAT(arb_robustness, UNAVAIL, UNAVAIL, "GL_ARB_robustness" ),
224 FEAT(arb_buffer_storage, 44, UNAVAIL, "GL_ARB_buffer_storage", "GL_EXT_buffer_storage"),
225 FEAT(arrays_of_arrays, 43, 31, "GL_ARB_arrays_of_arrays"),
226 FEAT(ati_meminfo, UNAVAIL, UNAVAIL, "GL_ATI_meminfo" ),
227 FEAT(atomic_counters, 42, 31, "GL_ARB_shader_atomic_counters" ),
228 FEAT(base_instance, 42, UNAVAIL, "GL_ARB_base_instance", "GL_EXT_base_instance" ),
229 FEAT(barrier, 42, 31, "GL_ARB_shader_image_load_store"),
230 FEAT(bind_vertex_buffers, 44, UNAVAIL, NULL),
231 FEAT(bit_encoding, 33, UNAVAIL, "GL_ARB_shader_bit_encoding" ),
232 FEAT(blend_equation_advanced, UNAVAIL, 32, "GL_KHR_blend_equation_advanced" ),
233 FEAT(clear_texture, 44, UNAVAIL, "GL_ARB_clear_texture", "GL_EXT_clear_texture"),
234 FEAT(clip_control, 45, UNAVAIL, "GL_ARB_clip_control", "GL_EXT_clip_control"),
235 FEAT(compute_shader, 43, 31, "GL_ARB_compute_shader" ),
236 FEAT(copy_image, 43, 32, "GL_ARB_copy_image", "GL_EXT_copy_image", "GL_OES_copy_image" ),
237 FEAT(conditional_render_inverted, 45, UNAVAIL, "GL_ARB_conditional_render_inverted" ),
238 FEAT(conservative_depth, 42, UNAVAIL, "GL_ARB_conservative_depth", "GL_EXT_conservative_depth" ),
239 FEAT(cube_map_array, 40, 32, "GL_ARB_texture_cube_map_array", "GL_EXT_texture_cube_map_array", "GL_OES_texture_cube_map_array" ),
240 FEAT(cull_distance, 45, UNAVAIL, "GL_ARB_cull_distance", "GL_EXT_clip_cull_distance" ),
241 FEAT(debug_cb, UNAVAIL, UNAVAIL, NULL), /* special case */
242 FEAT(draw_instance, 31, 30, "GL_ARB_draw_instanced" ),
243 FEAT(dual_src_blend, 33, UNAVAIL, "GL_ARB_blend_func_extended", "GL_EXT_blend_func_extended" ),
244 FEAT(depth_clamp, 32, UNAVAIL, "GL_ARB_depth_clamp", "GL_EXT_depth_clamp", "GL_NV_depth_clamp"),
245 FEAT(enhanced_layouts, 44, UNAVAIL, "GL_ARB_enhanced_layouts"),
246 FEAT(egl_image_external, UNAVAIL, UNAVAIL, "GL_OES_EGL_image_external"),
247 FEAT(egl_image_storage, UNAVAIL, UNAVAIL, "GL_EXT_EGL_image_storage"),
248 FEAT(fb_no_attach, 43, 31, "GL_ARB_framebuffer_no_attachments" ),
249 FEAT(framebuffer_fetch, UNAVAIL, UNAVAIL, "GL_EXT_shader_framebuffer_fetch" ),
250 FEAT(framebuffer_fetch_non_coherent, UNAVAIL, UNAVAIL, "GL_EXT_shader_framebuffer_fetch_non_coherent" ),
251 FEAT(geometry_shader, 32, 32, "GL_EXT_geometry_shader", "GL_OES_geometry_shader"),
252 FEAT(gl_conditional_render, 30, UNAVAIL, NULL),
253 FEAT(gl_prim_restart, 31, 30, NULL),
254 FEAT(gles_khr_robustness, UNAVAIL, UNAVAIL, "GL_KHR_robustness" ),
255 FEAT(gles31_compatibility, 45, 31, "ARB_ES3_1_compatibility" ),
256 FEAT(gles31_vertex_attrib_binding, 43, 31, "GL_ARB_vertex_attrib_binding" ),
257 FEAT(gpu_shader5, 40, 32, "GL_ARB_gpu_shader5", "GL_EXT_gpu_shader5", "GL_OES_gpu_shader5" ),
258 FEAT(images, 42, 31, "GL_ARB_shader_image_load_store" ),
259 FEAT(indep_blend, 30, 32, "GL_EXT_draw_buffers2", "GL_OES_draw_buffers_indexed" ),
260 FEAT(indep_blend_func, 40, 32, "GL_ARB_draw_buffers_blend", "GL_OES_draw_buffers_indexed"),
261 FEAT(indirect_draw, 40, 31, "GL_ARB_draw_indirect" ),
262 FEAT(indirect_params, 46, UNAVAIL, "GL_ARB_indirect_parameters" ),
263 FEAT(khr_debug, 43, 32, "GL_KHR_debug" ),
264 FEAT(memory_object, UNAVAIL, UNAVAIL, "GL_EXT_memory_object"),
265 FEAT(memory_object_fd, UNAVAIL, UNAVAIL, "GL_EXT_memory_object_fd"),
266 FEAT(mesa_invert, UNAVAIL, UNAVAIL, "GL_MESA_pack_invert" ),
267 FEAT(ms_scaled_blit, UNAVAIL, UNAVAIL, "GL_EXT_framebuffer_multisample_blit_scaled" ),
268 FEAT(multisample, 32, 30, "GL_ARB_texture_multisample" ),
269 FEAT(multi_draw_indirect, 43, UNAVAIL, "GL_ARB_multi_draw_indirect", "GL_EXT_multi_draw_indirect" ),
270 FEAT(nv_conditional_render, UNAVAIL, UNAVAIL, "GL_NV_conditional_render" ),
271 FEAT(nv_prim_restart, UNAVAIL, UNAVAIL, "GL_NV_primitive_restart" ),
272 FEAT(nvx_gpu_memory_info, UNAVAIL, UNAVAIL, "GL_NVX_gpu_memory_info" ),
273 FEAT(polygon_offset_clamp, 46, UNAVAIL, "GL_ARB_polygon_offset_clamp", "GL_EXT_polygon_offset_clamp"),
274 FEAT(occlusion_query, 15, UNAVAIL, "GL_ARB_occlusion_query"),
275 FEAT(occlusion_query_boolean, 33, 30, "GL_EXT_occlusion_query_boolean", "GL_ARB_occlusion_query2"),
276 FEAT(qbo, 44, UNAVAIL, "GL_ARB_query_buffer_object" ),
277 FEAT(robust_buffer_access, 43, UNAVAIL, "GL_ARB_robust_buffer_access_behavior", "GL_KHR_robust_buffer_access_behavior" ),
278 FEAT(sample_mask, 32, 31, "GL_ARB_texture_multisample" ),
279 FEAT(sample_shading, 40, 32, "GL_ARB_sample_shading", "GL_OES_sample_shading" ),
280 FEAT(samplers, 33, 30, "GL_ARB_sampler_objects" ),
281 FEAT(sampler_border_colors, 33, 32, "GL_ARB_sampler_objects", "GL_EXT_texture_border_clamp", "GL_OES_texture_border_clamp" ),
282 FEAT(separate_shader_objects, 41, 31, "GL_ARB_seperate_shader_objects"),
283 FEAT(shader_clock, UNAVAIL, UNAVAIL, "GL_ARB_shader_clock" ),
284 FEAT(ssbo, 43, 31, "GL_ARB_shader_storage_buffer_object" ),
285 FEAT(ssbo_barrier, 43, 31, "GL_ARB_shader_storage_buffer_object"),
286 FEAT(srgb_write_control, 30, UNAVAIL, "GL_EXT_sRGB_write_control"),
287 FEAT(stencil_texturing, 43, 31, "GL_ARB_stencil_texturing" ),
288 FEAT(storage_multisample, 43, 31, "GL_ARB_texture_storage_multisample" ),
289 FEAT(tessellation, 40, 32, "GL_ARB_tessellation_shader", "GL_OES_tessellation_shader", "GL_EXT_tessellation_shader" ),
290 FEAT(texture_array, 30, 30, "GL_EXT_texture_array" ),
291 FEAT(texture_barrier, 45, UNAVAIL, "GL_ARB_texture_barrier" ),
292 FEAT(texture_buffer_range, 43, 32, "GL_ARB_texture_buffer_range" ),
293 FEAT(texture_gather, 40, 31, "GL_ARB_texture_gather" ),
294 FEAT(texture_multisample, 32, 31, "GL_ARB_texture_multisample" ),
295 FEAT(texture_query_lod, 40, UNAVAIL, "GL_ARB_texture_query_lod", "GL_EXT_texture_query_lod"),
296 FEAT(texture_srgb_decode, UNAVAIL, UNAVAIL, "GL_EXT_texture_sRGB_decode" ),
297 FEAT(texture_storage, 42, 30, "GL_ARB_texture_storage" ),
298 FEAT(texture_view, 43, UNAVAIL, "GL_ARB_texture_view", "GL_OES_texture_view", "GL_EXT_texture_view" ),
299 FEAT(timer_query, 33, UNAVAIL, "GL_ARB_timer_query", "GL_EXT_disjoint_timer_query"),
300 FEAT(transform_feedback, 30, 30, "GL_EXT_transform_feedback" ),
301 FEAT(transform_feedback2, 40, 30, "GL_ARB_transform_feedback2" ),
302 FEAT(transform_feedback3, 40, UNAVAIL, "GL_ARB_transform_feedback3" ),
303 FEAT(transform_feedback_overflow_query, 46, UNAVAIL, "GL_ARB_transform_feedback_overflow_query" ),
304 FEAT(txqs, 45, UNAVAIL, "GL_ARB_shader_texture_image_samples" ),
305 FEAT(ubo, 31, 30, "GL_ARB_uniform_buffer_object" ),
306 FEAT(viewport_array, 41, UNAVAIL, "GL_ARB_viewport_array", "GL_OES_viewport_array"),
307 FEAT(implicit_msaa, UNAVAIL, UNAVAIL, "GL_EXT_multisampled_render_to_texture"),
308 FEAT(anisotropic_filter, 46, UNAVAIL, "GL_EXT_texture_filter_anisotropic", "GL_ARB_texture_filter_anisotropic"),
309 };
310
311 struct global_renderer_state {
312 struct vrend_context *ctx0;
313 struct vrend_context *current_ctx;
314 struct vrend_context *current_hw_ctx;
315
316 /* fence_mutex should be locked before using the query list
317 * if async fence callback are enabled
318 */
319 struct list_head waiting_query_list;
320 struct list_head fence_list;
321 struct list_head fence_wait_list;
322 struct vrend_fence *fence_waiting;
323 struct vrend_context *current_sync_thread_ctx;
324
325 int gl_major_ver;
326 int gl_minor_ver;
327
328 pipe_mutex fence_mutex;
329 pipe_thread sync_thread;
330 virgl_gl_context sync_context;
331
332 pipe_condvar fence_cond;
333
334 float tess_factors[6];
335 int eventfd;
336
337 uint32_t max_draw_buffers;
338 uint32_t max_texture_2d_size;
339 uint32_t max_texture_3d_size;
340 uint32_t max_texture_cube_size;
341
342 /* inferred GL caching type */
343 uint32_t inferred_gl_caching_type;
344
345 uint64_t features[feat_last / 64 + 1];
346
347 uint32_t finishing : 1;
348 uint32_t use_gles : 1;
349 uint32_t use_core_profile : 1;
350 uint32_t use_external_blob : 1;
351 uint32_t use_integer : 1;
352 /* these appeared broken on at least one driver */
353 uint32_t use_explicit_locations : 1;
354 /* threaded sync */
355 uint32_t stop_sync_thread : 1;
356 /* async fence callback */
357 bool use_async_fence_cb : 1;
358 /* Needed on GLES to inject a TCS */
359 uint32_t bgra_srgb_emulation_loaded : 1;
360
361 #ifdef HAVE_EPOXY_EGL_H
362 uint32_t use_egl_fence : 1;
363 #endif
364 };
365
366 static struct global_renderer_state vrend_state;
367
has_feature(enum features_id feature_id)368 static inline bool has_feature(enum features_id feature_id)
369 {
370 int slot = feature_id / 64;
371 uint64_t mask = 1ull << (feature_id & 63);
372 bool retval = vrend_state.features[slot] & mask ? true : false;
373 VREND_DEBUG(dbg_feature_use, NULL, "Try using feature %s:%d\n",
374 feature_list[feature_id].log_name,
375 retval);
376 return retval;
377 }
378
379
set_feature(enum features_id feature_id)380 static inline void set_feature(enum features_id feature_id)
381 {
382 int slot = feature_id / 64;
383 uint64_t mask = 1ull << (feature_id & 63);
384 vrend_state.features[slot] |= mask;
385 }
386
clear_feature(enum features_id feature_id)387 static inline void clear_feature(enum features_id feature_id)
388 {
389 int slot = feature_id / 64;
390 uint64_t mask = 1ull << (feature_id & 63);
391 vrend_state.features[slot] &= ~mask;
392 }
393
394
395 struct vrend_linked_shader_program {
396 struct list_head head;
397 struct list_head sl[PIPE_SHADER_TYPES];
398 GLuint id;
399
400 bool dual_src_linked;
401 struct vrend_shader *ss[PIPE_SHADER_TYPES];
402 uint64_t vs_fs_key;
403
404 uint32_t ubo_used_mask[PIPE_SHADER_TYPES];
405 uint32_t samplers_used_mask[PIPE_SHADER_TYPES];
406
407 GLuint *shadow_samp_mask_locs[PIPE_SHADER_TYPES];
408 GLuint *shadow_samp_add_locs[PIPE_SHADER_TYPES];
409
410 GLint const_location[PIPE_SHADER_TYPES];
411
412 GLuint *attrib_locs;
413 uint32_t shadow_samp_mask[PIPE_SHADER_TYPES];
414
415 GLuint vs_ws_adjust_loc;
416 float viewport_neg_val;
417
418 GLint fs_stipple_loc;
419
420 GLint fs_alpha_ref_val_loc;
421
422 GLuint clip_locs[8];
423
424 uint32_t images_used_mask[PIPE_SHADER_TYPES];
425 GLint *img_locs[PIPE_SHADER_TYPES];
426
427 uint32_t ssbo_used_mask[PIPE_SHADER_TYPES];
428
429 int32_t tex_levels_uniform_id[PIPE_SHADER_TYPES];
430
431 struct vrend_sub_context *ref_context;
432
433 uint32_t gles_use_query_texturelevel_mask;
434 };
435
436 struct vrend_shader {
437 struct vrend_shader *next_variant;
438 struct vrend_shader_selector *sel;
439
440 struct vrend_variable_shader_info var_sinfo;
441
442 struct vrend_strarray glsl_strings;
443 GLuint id;
444 uint32_t uid;
445 bool is_compiled;
446 struct vrend_shader_key key;
447 struct list_head programs;
448 };
449
450 struct vrend_shader_selector {
451 struct pipe_reference reference;
452
453 unsigned num_shaders;
454 unsigned type;
455 struct vrend_shader_info sinfo;
456
457 struct vrend_shader *current;
458 struct tgsi_token *tokens;
459
460 uint32_t req_local_mem;
461 char *tmp_buf;
462 uint32_t buf_len;
463 uint32_t buf_offset;
464 };
465
466 struct vrend_texture {
467 struct vrend_resource base;
468 struct pipe_sampler_state state;
469 GLint cur_swizzle[4];
470 GLuint cur_srgb_decode;
471 GLuint cur_base, cur_max;
472 };
473
474 struct vrend_surface {
475 struct pipe_reference reference;
476 GLuint id;
477 GLuint res_handle;
478 GLuint format;
479 GLuint val0, val1;
480 GLuint nr_samples;
481 struct vrend_resource *texture;
482 };
483
484 struct vrend_sampler_state {
485 struct pipe_sampler_state base;
486 GLuint ids[2];
487 };
488
489 struct vrend_so_target {
490 struct pipe_reference reference;
491 GLuint res_handle;
492 unsigned buffer_offset;
493 unsigned buffer_size;
494 struct vrend_resource *buffer;
495 struct vrend_sub_context *sub_ctx;
496 };
497
498 struct vrend_sampler_view {
499 struct pipe_reference reference;
500 GLuint id;
501 enum virgl_formats format;
502 GLenum target;
503 GLuint val0, val1;
504 GLint gl_swizzle[4];
505 GLenum depth_texture_mode;
506 GLuint srgb_decode;
507 GLuint levels;
508 struct vrend_resource *texture;
509 };
510
511 struct vrend_image_view {
512 GLuint id;
513 GLenum access;
514 GLenum format;
515 union {
516 struct {
517 unsigned first_layer:16; /**< first layer to use for array textures */
518 unsigned last_layer:16; /**< last layer to use for array textures */
519 unsigned level:8; /**< mipmap level to use */
520 } tex;
521 struct {
522 unsigned offset; /**< offset in bytes */
523 unsigned size; /**< size of the accessible sub-range in bytes */
524 } buf;
525 } u;
526 struct vrend_resource *texture;
527 };
528
529 struct vrend_ssbo {
530 struct vrend_resource *res;
531 unsigned buffer_size;
532 unsigned buffer_offset;
533 };
534
535 struct vrend_abo {
536 struct vrend_resource *res;
537 unsigned buffer_size;
538 unsigned buffer_offset;
539 };
540
541 struct vrend_vertex_element {
542 struct pipe_vertex_element base;
543 GLenum type;
544 GLboolean norm;
545 GLuint nr_chan;
546 };
547
548 struct vrend_vertex_element_array {
549 unsigned count;
550 struct vrend_vertex_element elements[PIPE_MAX_ATTRIBS];
551 GLuint id;
552 uint32_t signed_int_bitmask;
553 uint32_t unsigned_int_bitmask;
554 };
555
556 struct vrend_constants {
557 unsigned int *consts;
558 uint32_t num_consts;
559 uint32_t num_allocated_consts;
560 };
561
562 struct vrend_shader_view {
563 int num_views;
564 struct vrend_sampler_view *views[PIPE_MAX_SHADER_SAMPLER_VIEWS];
565 uint32_t res_id[PIPE_MAX_SHADER_SAMPLER_VIEWS];
566 uint32_t old_ids[PIPE_MAX_SHADER_SAMPLER_VIEWS];
567 };
568
569 struct vrend_viewport {
570 GLint cur_x, cur_y;
571 GLsizei width, height;
572 GLclampd near_val, far_val;
573 };
574
575 /* create a streamout object to support pause/resume */
576 struct vrend_streamout_object {
577 GLuint id;
578 uint32_t num_targets;
579 uint32_t handles[16];
580 struct list_head head;
581 int xfb_state;
582 struct vrend_so_target *so_targets[16];
583 };
584
585 #define XFB_STATE_OFF 0
586 #define XFB_STATE_STARTED_NEED_BEGIN 1
587 #define XFB_STATE_STARTED 2
588 #define XFB_STATE_PAUSED 3
589
590 struct vrend_vertex_buffer {
591 struct pipe_vertex_buffer base;
592 uint32_t res_id;
593 };
594
595 #define VREND_PROGRAM_NQUEUES (1 << 8)
596 #define VREND_PROGRAM_NQUEUE_MASK (VREND_PROGRAM_NQUEUES - 1)
597
598 struct vrend_sub_context {
599 struct list_head head;
600
601 virgl_gl_context gl_context;
602
603 int sub_ctx_id;
604
605 GLuint vaoid;
606 uint32_t enabled_attribs_bitmask;
607
608 /* Using an array of lists only adds VREND_PROGRAM_NQUEUES - 1 list_head
609 * structures to the consumed memory, but looking up the program can
610 * be spead up by the factor VREND_PROGRAM_NQUEUES which makes this
611 * worthwile. */
612 struct list_head gl_programs[VREND_PROGRAM_NQUEUES];
613 struct list_head cs_programs;
614 struct util_hash_table *object_hash;
615
616 struct vrend_vertex_element_array *ve;
617 int num_vbos;
618 int old_num_vbos; /* for cleaning up */
619 struct vrend_vertex_buffer vbo[PIPE_MAX_ATTRIBS];
620
621 struct pipe_index_buffer ib;
622 uint32_t index_buffer_res_id;
623
624 bool vbo_dirty;
625 bool shader_dirty;
626 bool cs_shader_dirty;
627 bool stencil_state_dirty;
628 bool image_state_dirty;
629 bool blend_state_dirty;
630
631 uint32_t long_shader_in_progress_handle[PIPE_SHADER_TYPES];
632 struct vrend_shader_selector *shaders[PIPE_SHADER_TYPES];
633 struct vrend_linked_shader_program *prog;
634
635 GLuint prog_ids[PIPE_SHADER_TYPES];
636 struct vrend_shader_view views[PIPE_SHADER_TYPES];
637
638 struct vrend_constants consts[PIPE_SHADER_TYPES];
639 bool const_dirty[PIPE_SHADER_TYPES];
640 struct vrend_sampler_state *sampler_state[PIPE_SHADER_TYPES][PIPE_MAX_SAMPLERS];
641
642 struct pipe_constant_buffer cbs[PIPE_SHADER_TYPES][PIPE_MAX_CONSTANT_BUFFERS];
643 uint32_t const_bufs_used_mask[PIPE_SHADER_TYPES];
644 uint32_t const_bufs_dirty[PIPE_SHADER_TYPES];
645
646 int num_sampler_states[PIPE_SHADER_TYPES];
647
648 uint32_t sampler_views_dirty[PIPE_SHADER_TYPES];
649 int32_t texture_levels[PIPE_SHADER_TYPES][PIPE_MAX_SAMPLERS];
650 int32_t n_samplers[PIPE_SHADER_TYPES];
651
652 uint32_t fb_id;
653 int nr_cbufs, old_nr_cbufs;
654 struct vrend_surface *zsurf;
655 struct vrend_surface *surf[PIPE_MAX_COLOR_BUFS];
656
657 struct vrend_viewport vps[PIPE_MAX_VIEWPORTS];
658 /* viewport is negative */
659 uint32_t scissor_state_dirty;
660 uint32_t viewport_state_dirty;
661 uint32_t viewport_state_initialized;
662
663 uint32_t fb_height;
664
665 struct pipe_scissor_state ss[PIPE_MAX_VIEWPORTS];
666
667 struct pipe_blend_state blend_state;
668 struct pipe_depth_stencil_alpha_state dsa_state;
669 struct pipe_rasterizer_state rs_state;
670
671 uint8_t stencil_refs[2];
672 bool viewport_is_negative;
673 /* this is set if the contents of the FBO look upside down when viewed
674 with 0,0 as the bottom corner */
675 bool inverted_fbo_content;
676
677 GLuint blit_fb_ids[2];
678
679 struct pipe_depth_stencil_alpha_state *dsa;
680
681 struct pipe_clip_state ucp_state;
682
683 bool depth_test_enabled;
684 bool alpha_test_enabled;
685 bool stencil_test_enabled;
686 bool framebuffer_srgb_enabled;
687
688 GLuint program_id;
689 int last_shader_idx;
690
691 GLint draw_indirect_buffer;
692
693 GLint draw_indirect_params_buffer;
694
695 struct pipe_rasterizer_state hw_rs_state;
696 struct pipe_blend_state hw_blend_state;
697
698 struct list_head streamout_list;
699 struct vrend_streamout_object *current_so;
700
701 struct pipe_blend_color blend_color;
702
703 uint32_t cond_render_q_id;
704 GLenum cond_render_gl_mode;
705
706 struct vrend_image_view image_views[PIPE_SHADER_TYPES][PIPE_MAX_SHADER_IMAGES];
707 uint32_t images_used_mask[PIPE_SHADER_TYPES];
708
709 struct vrend_ssbo ssbo[PIPE_SHADER_TYPES][PIPE_MAX_SHADER_BUFFERS];
710 uint32_t ssbo_used_mask[PIPE_SHADER_TYPES];
711
712 struct vrend_abo abo[PIPE_MAX_HW_ATOMIC_BUFFERS];
713 uint32_t abo_used_mask;
714 struct vrend_context_tweaks tweaks;
715 uint8_t swizzle_output_rgb_to_bgr;
716 uint8_t convert_linear_to_srgb_on_write;
717 int fake_occlusion_query_samples_passed_multiplier;
718
719 int prim_mode;
720 bool drawing;
721 struct vrend_context *parent;
722 };
723
724 struct vrend_untyped_resource {
725 struct virgl_resource *resource;
726 struct list_head head;
727 };
728
729 struct vrend_context {
730 char debug_name[64];
731
732 struct list_head sub_ctxs;
733 struct list_head vrend_resources;
734
735 struct vrend_sub_context *sub;
736 struct vrend_sub_context *sub0;
737
738 int ctx_id;
739 /* has this ctx gotten an error? */
740 bool in_error;
741 bool ctx_switch_pending;
742 bool pstip_inited;
743
744 GLuint pstipple_tex_id;
745
746 enum virgl_ctx_errors last_error;
747
748 /* resource bounds to this context */
749 struct util_hash_table *res_hash;
750
751 /*
752 * vrend_context only works with typed virgl_resources. More specifically,
753 * it works with vrend_resources that are inherited from pipe_resources
754 * wrapped in virgl_resources.
755 *
756 * Normally, a vrend_resource is created first by
757 * vrend_renderer_resource_create. It is then wrapped in a virgl_resource
758 * by virgl_resource_create_from_pipe. Depending on whether it is a blob
759 * resource or not, the two functions can be called from different paths.
760 * But we always get both a virgl_resource and a vrend_resource as a
761 * result.
762 *
763 * It is however possible that we encounter untyped virgl_resources that
764 * have no pipe_resources. To work with untyped virgl_resources, we park
765 * them in untyped_resources first when they are attached. We move them
766 * into res_hash only after we get the type information and create the
767 * vrend_resources in vrend_decode_pipe_resource_set_type.
768 */
769 struct list_head untyped_resources;
770 struct virgl_resource *untyped_resource_cache;
771
772 struct list_head active_nontimer_query_list;
773
774 struct vrend_shader_cfg shader_cfg;
775
776 unsigned debug_flags;
777
778 vrend_context_fence_retire fence_retire;
779 void *fence_retire_data;
780 };
781
782 static struct vrend_resource *vrend_renderer_ctx_res_lookup(struct vrend_context *ctx, int res_handle);
783 static void vrend_pause_render_condition(struct vrend_context *ctx, bool pause);
784 static void vrend_update_viewport_state(struct vrend_sub_context *sub_ctx);
785 static void vrend_update_scissor_state(struct vrend_sub_context *sub_ctx);
786 static void vrend_destroy_query_object(void *obj_ptr);
787 static void vrend_finish_context_switch(struct vrend_context *ctx);
788 static void vrend_patch_blend_state(struct vrend_sub_context *sub_ctx);
789 static void vrend_update_frontface_state(struct vrend_sub_context *ctx);
790 static int vrender_get_glsl_version(void);
791 static void vrend_destroy_program(struct vrend_linked_shader_program *ent);
792 static void vrend_apply_sampler_state(struct vrend_sub_context *sub_ctx,
793 struct vrend_resource *res,
794 uint32_t shader_type,
795 int id, int sampler_id,
796 struct vrend_sampler_view *tview);
797 static GLenum tgsitargettogltarget(const enum pipe_texture_target target, int nr_samples);
798
799 void vrend_update_stencil_state(struct vrend_sub_context *sub_ctx);
800
801 static struct vrend_format_table tex_conv_table[VIRGL_FORMAT_MAX_EXTENDED];
802
803 static uint32_t vrend_renderer_get_video_memory(void);
804
vrend_format_can_sample(enum virgl_formats format)805 static inline bool vrend_format_can_sample(enum virgl_formats format)
806 {
807 if (tex_conv_table[format].bindings & VIRGL_BIND_SAMPLER_VIEW)
808 return true;
809
810 #ifdef ENABLE_MINIGBM_ALLOCATION
811 uint32_t gbm_format = 0;
812 if (virgl_gbm_convert_format(&format, &gbm_format))
813 return false;
814
815 if (!gbm || !gbm->device || !gbm_format)
816 return false;
817
818 uint32_t gbm_usage = GBM_BO_USE_TEXTURING;
819 return gbm_device_is_format_supported(gbm->device, gbm_format, gbm_usage);
820 #else
821 return false;
822 #endif
823 }
824
vrend_format_can_readback(enum virgl_formats format)825 static inline bool vrend_format_can_readback(enum virgl_formats format)
826 {
827 return tex_conv_table[format].flags & VIRGL_TEXTURE_CAN_READBACK;
828 }
829
vrend_format_can_render(enum virgl_formats format)830 static inline bool vrend_format_can_render(enum virgl_formats format)
831 {
832 return tex_conv_table[format].bindings & VIRGL_BIND_RENDER_TARGET;
833 }
834
vrend_format_is_ds(enum virgl_formats format)835 static inline bool vrend_format_is_ds(enum virgl_formats format)
836 {
837 return tex_conv_table[format].bindings & VIRGL_BIND_DEPTH_STENCIL;
838 }
839
vrend_format_can_scanout(enum virgl_formats format)840 static inline bool vrend_format_can_scanout(enum virgl_formats format)
841 {
842 #ifdef ENABLE_MINIGBM_ALLOCATION
843 uint32_t gbm_format = 0;
844 if (virgl_gbm_convert_format(&format, &gbm_format))
845 return false;
846
847 if (!gbm || !gbm->device || !gbm_format)
848 return false;
849
850 return gbm_device_is_format_supported(gbm->device, gbm_format, GBM_BO_USE_SCANOUT);
851 #else
852 (void)format;
853 return true;
854 #endif
855 }
856
857 #ifdef ENABLE_MINIGBM_ALLOCATION
vrend_format_can_texture_view(enum virgl_formats format)858 static inline bool vrend_format_can_texture_view(enum virgl_formats format)
859 {
860 return has_feature(feat_texture_view) &&
861 tex_conv_table[format].flags & VIRGL_TEXTURE_CAN_TEXTURE_STORAGE;
862 }
863 #endif
864
vrend_get_context_tweaks(struct vrend_context * ctx)865 struct vrend_context_tweaks *vrend_get_context_tweaks(struct vrend_context *ctx)
866 {
867 return &ctx->sub->tweaks;
868 }
869
vrend_format_is_emulated_alpha(enum virgl_formats format)870 bool vrend_format_is_emulated_alpha(enum virgl_formats format)
871 {
872 if (vrend_state.use_gles || !vrend_state.use_core_profile)
873 return false;
874 return (format == VIRGL_FORMAT_A8_UNORM ||
875 format == VIRGL_FORMAT_A16_UNORM);
876 }
877
vrend_format_is_bgra(enum virgl_formats format)878 bool vrend_format_is_bgra(enum virgl_formats format) {
879 return (format == VIRGL_FORMAT_B8G8R8X8_UNORM ||
880 format == VIRGL_FORMAT_B8G8R8A8_UNORM ||
881 format == VIRGL_FORMAT_B8G8R8X8_SRGB ||
882 format == VIRGL_FORMAT_B8G8R8A8_SRGB);
883 }
884
vrend_resource_is_emulated_bgra(struct vrend_resource * res)885 static bool vrend_resource_is_emulated_bgra(struct vrend_resource *res)
886 {
887 /* On all hosts, BGR* resources are swizzled on upload and stored with RGB*
888 * internal format. On GLES hosts, we must perform that swizzle ourselves.
889 * However, for externally-stored resources such as EGL images and
890 * GBM-allocated dma-bufs, the pixel data is expected to be stored with BGR*
891 * byte-ordering. Emulation is added during texture sampling, blitting, and
892 * rendering to correct the red/blue color inversion caused by the mismatch
893 * between storage expectation and the RGB* internal format given to the host
894 * GL[ES] API.
895 */
896 if (vrend_format_is_bgra(res->base.format) &&
897 (has_bit(res->storage_bits, VREND_STORAGE_EGL_IMAGE) || res->egl_image ||
898 has_bit(res->storage_bits, VREND_STORAGE_GBM_BUFFER) || res->gbm_bo))
899 return true;
900 return false;
901 }
902
vrend_resource_has_24bpp_internal_format(struct vrend_resource * res)903 static bool vrend_resource_has_24bpp_internal_format(struct vrend_resource *res)
904 {
905 /* Some shared resources imported to guest mesa as EGL images occupy 24bpp instead of more common 32bpp. */
906 return (has_bit(res->storage_bits, VREND_STORAGE_EGL_IMAGE) &&
907 (res->base.format == VIRGL_FORMAT_B8G8R8X8_UNORM ||
908 res->base.format == VIRGL_FORMAT_R8G8B8X8_UNORM));
909 }
910
vrend_blit_needs_swizzle(enum virgl_formats src,enum virgl_formats dst)911 static bool vrend_blit_needs_swizzle(enum virgl_formats src,
912 enum virgl_formats dst)
913 {
914 for (int i = 0; i < 4; ++i) {
915 if (tex_conv_table[src].swizzle[i] != tex_conv_table[dst].swizzle[i])
916 return true;
917 }
918 return false;
919 }
920
pipe_shader_to_prefix(int shader_type)921 static inline const char *pipe_shader_to_prefix(int shader_type)
922 {
923 switch (shader_type) {
924 case PIPE_SHADER_VERTEX: return "vs";
925 case PIPE_SHADER_FRAGMENT: return "fs";
926 case PIPE_SHADER_GEOMETRY: return "gs";
927 case PIPE_SHADER_TESS_CTRL: return "tc";
928 case PIPE_SHADER_TESS_EVAL: return "te";
929 case PIPE_SHADER_COMPUTE: return "cs";
930 default:
931 return NULL;
932 };
933 }
934
translate_blend_func_advanced(enum gl_advanced_blend_mode blend)935 static GLenum translate_blend_func_advanced(enum gl_advanced_blend_mode blend)
936 {
937 switch(blend){
938 case BLEND_MULTIPLY: return GL_MULTIPLY_KHR;
939 case BLEND_SCREEN: return GL_SCREEN_KHR;
940 case BLEND_OVERLAY: return GL_OVERLAY_KHR;
941 case BLEND_DARKEN: return GL_DARKEN_KHR;
942 case BLEND_LIGHTEN: return GL_LIGHTEN_KHR;
943 case BLEND_COLORDODGE: return GL_COLORDODGE_KHR;
944 case BLEND_COLORBURN: return GL_COLORBURN_KHR;
945 case BLEND_HARDLIGHT: return GL_HARDLIGHT_KHR;
946 case BLEND_SOFTLIGHT: return GL_SOFTLIGHT_KHR;
947 case BLEND_DIFFERENCE: return GL_DIFFERENCE_KHR;
948 case BLEND_EXCLUSION: return GL_EXCLUSION_KHR;
949 case BLEND_HSL_HUE: return GL_HSL_HUE_KHR;
950 case BLEND_HSL_SATURATION: return GL_HSL_SATURATION_KHR;
951 case BLEND_HSL_COLOR: return GL_HSL_COLOR_KHR;
952 case BLEND_HSL_LUMINOSITY: return GL_HSL_LUMINOSITY_KHR;
953 default:
954 assert("invalid blend token()" == NULL);
955 return 0;
956 }
957 }
958
959 static const char *vrend_ctx_error_strings[] = {
960 [VIRGL_ERROR_CTX_NONE] = "None",
961 [VIRGL_ERROR_CTX_UNKNOWN] = "Unknown",
962 [VIRGL_ERROR_CTX_ILLEGAL_SHADER] = "Illegal shader",
963 [VIRGL_ERROR_CTX_ILLEGAL_HANDLE] = "Illegal handle",
964 [VIRGL_ERROR_CTX_ILLEGAL_RESOURCE] = "Illegal resource",
965 [VIRGL_ERROR_CTX_ILLEGAL_SURFACE] = "Illegal surface",
966 [VIRGL_ERROR_CTX_ILLEGAL_VERTEX_FORMAT] = "Illegal vertex format",
967 [VIRGL_ERROR_CTX_ILLEGAL_CMD_BUFFER] = "Illegal command buffer",
968 [VIRGL_ERROR_CTX_GLES_HAVE_TES_BUT_MISS_TCS] = "On GLES context and shader program has tesselation evaluation shader but no tesselation control shader",
969 [VIRGL_ERROR_GL_ANY_SAMPLES_PASSED] = "Query for ANY_SAMPLES_PASSED not supported",
970 [VIRGL_ERROR_CTX_ILLEGAL_FORMAT] = "Illegal format ID",
971 [VIRGL_ERROR_CTX_ILLEGAL_SAMPLER_VIEW_TARGET] = "Illegat target for sampler view",
972 [VIRGL_ERROR_CTX_TRANSFER_IOV_BOUNDS] = "IOV data size exceeds resource capacity",
973 };
974
vrend_report_context_error_internal(const char * fname,struct vrend_context * ctx,enum virgl_ctx_errors error,uint32_t value)975 void vrend_report_context_error_internal(const char *fname, struct vrend_context *ctx,
976 enum virgl_ctx_errors error, uint32_t value)
977 {
978 ctx->in_error = true;
979 ctx->last_error = error;
980 vrend_printf("%s: context error reported %d \"%s\" %s %d\n", fname,
981 ctx->ctx_id, ctx->debug_name, vrend_ctx_error_strings[error],
982 value);
983 }
984
985 #define CORE_PROFILE_WARN_NONE 0
986 #define CORE_PROFILE_WARN_STIPPLE 1
987 #define CORE_PROFILE_WARN_POLYGON_MODE 2
988 #define CORE_PROFILE_WARN_TWO_SIDE 3
989 #define CORE_PROFILE_WARN_CLAMP 4
990 #define CORE_PROFILE_WARN_SHADE_MODEL 5
991
992 static const char *vrend_core_profile_warn_strings[] = {
993 [CORE_PROFILE_WARN_NONE] = "None",
994 [CORE_PROFILE_WARN_STIPPLE] = "Stipple",
995 [CORE_PROFILE_WARN_POLYGON_MODE] = "Polygon Mode",
996 [CORE_PROFILE_WARN_TWO_SIDE] = "Two Side",
997 [CORE_PROFILE_WARN_CLAMP] = "Clamping",
998 [CORE_PROFILE_WARN_SHADE_MODEL] = "Shade Model",
999 };
1000
__report_core_warn(const char * fname,struct vrend_context * ctx,enum virgl_ctx_errors error)1001 static void __report_core_warn(const char *fname, struct vrend_context *ctx,
1002 enum virgl_ctx_errors error)
1003 {
1004 vrend_printf("%s: core profile violation reported %d \"%s\" %s\n", fname,
1005 ctx->ctx_id, ctx->debug_name,
1006 vrend_core_profile_warn_strings[error]);
1007 }
1008 #define report_core_warn(ctx, error) __report_core_warn(__func__, ctx, error)
1009
1010
1011 #define GLES_WARN_NONE 0
1012 #define GLES_WARN_STIPPLE 1
1013 #define GLES_WARN_POLYGON_MODE 2
1014 #define GLES_WARN_DEPTH_RANGE 3
1015 #define GLES_WARN_POINT_SIZE 4
1016 #define GLES_WARN_SEAMLESS_CUBE_MAP 5
1017 #define GLES_WARN_LOD_BIAS 6
1018 #define GLES_WARN_TEXTURE_RECT 7
1019 #define GLES_WARN_OFFSET_LINE 8
1020 #define GLES_WARN_OFFSET_POINT 9
1021 //#define GLES_WARN_ free slot 10
1022 #define GLES_WARN_FLATSHADE_FIRST 11
1023 #define GLES_WARN_LINE_SMOOTH 12
1024 #define GLES_WARN_POLY_SMOOTH 13
1025 #define GLES_WARN_DEPTH_CLEAR 14
1026 #define GLES_WARN_LOGIC_OP 15
1027 #define GLES_WARN_TIMESTAMP 16
1028 #define GLES_WARN_IMPLICIT_MSAA_SURFACE 17
1029
1030 MAYBE_UNUSED
1031 static const char *vrend_gles_warn_strings[] = {
1032 [GLES_WARN_NONE] = "None",
1033 [GLES_WARN_STIPPLE] = "Stipple",
1034 [GLES_WARN_POLYGON_MODE] = "Polygon Mode",
1035 [GLES_WARN_DEPTH_RANGE] = "Depth Range",
1036 [GLES_WARN_POINT_SIZE] = "Point Size",
1037 [GLES_WARN_SEAMLESS_CUBE_MAP] = "Seamless Cube Map",
1038 [GLES_WARN_LOD_BIAS] = "Lod Bias",
1039 [GLES_WARN_TEXTURE_RECT] = "Texture Rect",
1040 [GLES_WARN_OFFSET_LINE] = "Offset Line",
1041 [GLES_WARN_OFFSET_POINT] = "Offset Point",
1042 [GLES_WARN_FLATSHADE_FIRST] = "Flatshade First",
1043 [GLES_WARN_LINE_SMOOTH] = "Line Smooth",
1044 [GLES_WARN_POLY_SMOOTH] = "Poly Smooth",
1045 [GLES_WARN_DEPTH_CLEAR] = "Depth Clear",
1046 [GLES_WARN_LOGIC_OP] = "LogicOp",
1047 [GLES_WARN_TIMESTAMP] = "GL_TIMESTAMP",
1048 [GLES_WARN_IMPLICIT_MSAA_SURFACE] = "Implicit MSAA Surface",
1049 };
1050
__report_gles_warn(MAYBE_UNUSED const char * fname,MAYBE_UNUSED struct vrend_context * ctx,MAYBE_UNUSED enum virgl_ctx_errors error)1051 static void __report_gles_warn(MAYBE_UNUSED const char *fname,
1052 MAYBE_UNUSED struct vrend_context *ctx,
1053 MAYBE_UNUSED enum virgl_ctx_errors error)
1054 {
1055 VREND_DEBUG(dbg_gles, ctx, "%s: GLES violation - %s\n", fname, vrend_gles_warn_strings[error]);
1056 }
1057 #define report_gles_warn(ctx, error) __report_gles_warn(__func__, ctx, error)
1058
__report_gles_missing_func(MAYBE_UNUSED const char * fname,MAYBE_UNUSED struct vrend_context * ctx,MAYBE_UNUSED const char * missf)1059 static void __report_gles_missing_func(MAYBE_UNUSED const char *fname,
1060 MAYBE_UNUSED struct vrend_context *ctx,
1061 MAYBE_UNUSED const char *missf)
1062 {
1063 VREND_DEBUG(dbg_gles, ctx, "%s: GLES function %s is missing\n", fname, missf);
1064 }
1065
1066 #define report_gles_missing_func(ctx, missf) __report_gles_missing_func(__func__, ctx, missf)
1067
init_features(int gl_ver,int gles_ver)1068 static void init_features(int gl_ver, int gles_ver)
1069 {
1070 for (enum features_id id = 0; id < feat_last; id++) {
1071 if (gl_ver >= feature_list[id].gl_ver ||
1072 gles_ver >= feature_list[id].gles_ver) {
1073 set_feature(id);
1074 VREND_DEBUG(dbg_features, NULL, "Host feature %s provided by %s %3.1f\n",
1075 feature_list[id].log_name, (gl_ver > 0 ? "GL" : "GLES"),
1076 0.1f * (gl_ver > 0 ? gl_ver : gles_ver));
1077 } else {
1078 for (uint32_t i = 0; i < FEAT_MAX_EXTS; i++) {
1079 if (!feature_list[id].gl_ext[i])
1080 break;
1081 if (epoxy_has_gl_extension(feature_list[id].gl_ext[i])) {
1082 set_feature(id);
1083 VREND_DEBUG(dbg_features, NULL,
1084 "Host feature %s provide by %s\n", feature_list[id].log_name,
1085 feature_list[id].gl_ext[i]);
1086 break;
1087 }
1088 }
1089 }
1090 }
1091 }
1092
vrend_destroy_surface(struct vrend_surface * surf)1093 static void vrend_destroy_surface(struct vrend_surface *surf)
1094 {
1095 if (surf->id != surf->texture->id)
1096 glDeleteTextures(1, &surf->id);
1097 vrend_resource_reference(&surf->texture, NULL);
1098 free(surf);
1099 }
1100
1101 static inline void
vrend_surface_reference(struct vrend_surface ** ptr,struct vrend_surface * surf)1102 vrend_surface_reference(struct vrend_surface **ptr, struct vrend_surface *surf)
1103 {
1104 struct vrend_surface *old_surf = *ptr;
1105
1106 if (pipe_reference(&(*ptr)->reference, &surf->reference))
1107 vrend_destroy_surface(old_surf);
1108 *ptr = surf;
1109 }
1110
vrend_destroy_sampler_view(struct vrend_sampler_view * samp)1111 static void vrend_destroy_sampler_view(struct vrend_sampler_view *samp)
1112 {
1113 if (samp->texture->id != samp->id)
1114 glDeleteTextures(1, &samp->id);
1115 vrend_resource_reference(&samp->texture, NULL);
1116 free(samp);
1117 }
1118
1119 static inline void
vrend_sampler_view_reference(struct vrend_sampler_view ** ptr,struct vrend_sampler_view * view)1120 vrend_sampler_view_reference(struct vrend_sampler_view **ptr, struct vrend_sampler_view *view)
1121 {
1122 struct vrend_sampler_view *old_view = *ptr;
1123
1124 if (pipe_reference(&(*ptr)->reference, &view->reference))
1125 vrend_destroy_sampler_view(old_view);
1126 *ptr = view;
1127 }
1128
vrend_destroy_so_target(struct vrend_so_target * target)1129 static void vrend_destroy_so_target(struct vrend_so_target *target)
1130 {
1131 vrend_resource_reference(&target->buffer, NULL);
1132 free(target);
1133 }
1134
1135 static inline void
vrend_so_target_reference(struct vrend_so_target ** ptr,struct vrend_so_target * target)1136 vrend_so_target_reference(struct vrend_so_target **ptr, struct vrend_so_target *target)
1137 {
1138 struct vrend_so_target *old_target = *ptr;
1139
1140 if (pipe_reference(&(*ptr)->reference, &target->reference))
1141 vrend_destroy_so_target(old_target);
1142 *ptr = target;
1143 }
1144
vrend_shader_dump(struct vrend_shader * shader)1145 static void vrend_shader_dump(struct vrend_shader *shader)
1146 {
1147 const char *prefix = pipe_shader_to_prefix(shader->sel->type);
1148 vrend_printf("%s: %d GLSL:\n", prefix, shader->id);
1149 strarray_dump_with_line_numbers(&shader->glsl_strings);
1150 vrend_printf("\n");
1151 }
1152
vrend_shader_destroy(struct vrend_shader * shader)1153 static void vrend_shader_destroy(struct vrend_shader *shader)
1154 {
1155 struct vrend_linked_shader_program *ent, *tmp;
1156
1157 LIST_FOR_EACH_ENTRY_SAFE(ent, tmp, &shader->programs, sl[shader->sel->type]) {
1158 vrend_destroy_program(ent);
1159 }
1160
1161 glDeleteShader(shader->id);
1162 strarray_free(&shader->glsl_strings, true);
1163 free(shader);
1164 }
1165
vrend_destroy_shader_selector(struct vrend_shader_selector * sel)1166 static void vrend_destroy_shader_selector(struct vrend_shader_selector *sel)
1167 {
1168 struct vrend_shader *p = sel->current, *c;
1169 unsigned i;
1170 while (p) {
1171 c = p->next_variant;
1172 vrend_shader_destroy(p);
1173 p = c;
1174 }
1175 if (sel->sinfo.so_names)
1176 for (i = 0; i < sel->sinfo.so_info.num_outputs; i++)
1177 free(sel->sinfo.so_names[i]);
1178 free(sel->tmp_buf);
1179 free(sel->sinfo.so_names);
1180 free(sel->sinfo.sampler_arrays);
1181 free(sel->sinfo.image_arrays);
1182 free(sel->tokens);
1183 free(sel);
1184 }
1185
conv_shader_type(int type)1186 static inline int conv_shader_type(int type)
1187 {
1188 switch (type) {
1189 case PIPE_SHADER_VERTEX: return GL_VERTEX_SHADER;
1190 case PIPE_SHADER_FRAGMENT: return GL_FRAGMENT_SHADER;
1191 case PIPE_SHADER_GEOMETRY: return GL_GEOMETRY_SHADER;
1192 case PIPE_SHADER_TESS_CTRL: return GL_TESS_CONTROL_SHADER;
1193 case PIPE_SHADER_TESS_EVAL: return GL_TESS_EVALUATION_SHADER;
1194 case PIPE_SHADER_COMPUTE: return GL_COMPUTE_SHADER;
1195 default:
1196 return 0;
1197 };
1198 }
1199
vrend_compile_shader(struct vrend_sub_context * sub_ctx,struct vrend_shader * shader)1200 static bool vrend_compile_shader(struct vrend_sub_context *sub_ctx,
1201 struct vrend_shader *shader)
1202 {
1203 GLint param;
1204 const char *shader_parts[SHADER_MAX_STRINGS];
1205
1206 for (int i = 0; i < shader->glsl_strings.num_strings; i++)
1207 shader_parts[i] = shader->glsl_strings.strings[i].buf;
1208
1209 shader->id = glCreateShader(conv_shader_type(shader->sel->type));
1210 glShaderSource(shader->id, shader->glsl_strings.num_strings, shader_parts, NULL);
1211 glCompileShader(shader->id);
1212 glGetShaderiv(shader->id, GL_COMPILE_STATUS, ¶m);
1213 if (param == GL_FALSE) {
1214 char infolog[65536];
1215 int len;
1216 glGetShaderInfoLog(shader->id, 65536, &len, infolog);
1217 vrend_report_context_error(sub_ctx->parent, VIRGL_ERROR_CTX_ILLEGAL_SHADER, 0);
1218 vrend_printf("shader failed to compile\n%s\n", infolog);
1219 vrend_shader_dump(shader);
1220 return false;
1221 }
1222 shader->is_compiled = true;
1223 return true;
1224 }
1225
1226 static inline void
vrend_shader_state_reference(struct vrend_shader_selector ** ptr,struct vrend_shader_selector * shader)1227 vrend_shader_state_reference(struct vrend_shader_selector **ptr, struct vrend_shader_selector *shader)
1228 {
1229 struct vrend_shader_selector *old_shader = *ptr;
1230
1231 if (pipe_reference(&(*ptr)->reference, &shader->reference))
1232 vrend_destroy_shader_selector(old_shader);
1233 *ptr = shader;
1234 }
1235
1236 void
vrend_insert_format(struct vrend_format_table * entry,uint32_t bindings,uint32_t flags)1237 vrend_insert_format(struct vrend_format_table *entry, uint32_t bindings, uint32_t flags)
1238 {
1239 tex_conv_table[entry->format] = *entry;
1240 tex_conv_table[entry->format].bindings = bindings;
1241 tex_conv_table[entry->format].flags = flags;
1242 }
1243
1244 void
vrend_insert_format_swizzle(int override_format,struct vrend_format_table * entry,uint32_t bindings,uint8_t swizzle[4],uint32_t flags)1245 vrend_insert_format_swizzle(int override_format, struct vrend_format_table *entry,
1246 uint32_t bindings, uint8_t swizzle[4], uint32_t flags)
1247 {
1248 int i;
1249 tex_conv_table[override_format] = *entry;
1250 tex_conv_table[override_format].bindings = bindings;
1251 tex_conv_table[override_format].flags = flags | VIRGL_TEXTURE_NEED_SWIZZLE;
1252 for (i = 0; i < 4; i++)
1253 tex_conv_table[override_format].swizzle[i] = swizzle[i];
1254 }
1255
1256 const struct vrend_format_table *
vrend_get_format_table_entry(enum virgl_formats format)1257 vrend_get_format_table_entry(enum virgl_formats format)
1258 {
1259 return &tex_conv_table[format];
1260 }
1261
vrend_is_timer_query(GLenum gltype)1262 static bool vrend_is_timer_query(GLenum gltype)
1263 {
1264 return gltype == GL_TIMESTAMP ||
1265 gltype == GL_TIME_ELAPSED;
1266 }
1267
vrend_use_program(struct vrend_sub_context * sub_ctx,GLuint program_id)1268 static void vrend_use_program(struct vrend_sub_context *sub_ctx, GLuint program_id)
1269 {
1270 if (sub_ctx->program_id != program_id) {
1271 glUseProgram(program_id);
1272 sub_ctx->program_id = program_id;
1273 }
1274 }
1275
vrend_init_pstipple_texture(struct vrend_context * ctx)1276 static void vrend_init_pstipple_texture(struct vrend_context *ctx)
1277 {
1278 glGenTextures(1, &ctx->pstipple_tex_id);
1279 glBindTexture(GL_TEXTURE_2D, ctx->pstipple_tex_id);
1280 glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 32, 32, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
1281 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1282 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1283 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1284 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1285
1286 ctx->pstip_inited = true;
1287 }
1288
vrend_depth_test_enable(struct vrend_context * ctx,bool depth_test_enable)1289 static void vrend_depth_test_enable(struct vrend_context *ctx, bool depth_test_enable)
1290 {
1291 if (ctx->sub->depth_test_enabled != depth_test_enable) {
1292 ctx->sub->depth_test_enabled = depth_test_enable;
1293 if (depth_test_enable)
1294 glEnable(GL_DEPTH_TEST);
1295 else
1296 glDisable(GL_DEPTH_TEST);
1297 }
1298 }
1299
vrend_alpha_test_enable(struct vrend_context * ctx,bool alpha_test_enable)1300 static void vrend_alpha_test_enable(struct vrend_context *ctx, bool alpha_test_enable)
1301 {
1302 if (vrend_state.use_core_profile) {
1303 /* handled in shaders */
1304 return;
1305 }
1306 if (ctx->sub->alpha_test_enabled != alpha_test_enable) {
1307 ctx->sub->alpha_test_enabled = alpha_test_enable;
1308 if (alpha_test_enable)
1309 glEnable(GL_ALPHA_TEST);
1310 else
1311 glDisable(GL_ALPHA_TEST);
1312 }
1313 }
1314
vrend_stencil_test_enable(struct vrend_sub_context * sub_ctx,bool stencil_test_enable)1315 static void vrend_stencil_test_enable(struct vrend_sub_context *sub_ctx, bool stencil_test_enable)
1316 {
1317 if (sub_ctx->stencil_test_enabled != stencil_test_enable) {
1318 sub_ctx->stencil_test_enabled = stencil_test_enable;
1319 if (stencil_test_enable)
1320 glEnable(GL_STENCIL_TEST);
1321 else
1322 glDisable(GL_STENCIL_TEST);
1323 }
1324 }
1325
1326 MAYBE_UNUSED
dump_stream_out(struct pipe_stream_output_info * so)1327 static void dump_stream_out(struct pipe_stream_output_info *so)
1328 {
1329 unsigned i;
1330 if (!so)
1331 return;
1332 vrend_printf("streamout: %d\n", so->num_outputs);
1333 vrend_printf("strides: ");
1334 for (i = 0; i < 4; i++)
1335 vrend_printf("%d ", so->stride[i]);
1336 vrend_printf("\n");
1337 vrend_printf("outputs:\n");
1338 for (i = 0; i < so->num_outputs; i++) {
1339 vrend_printf("\t%d: reg: %d sc: %d, nc: %d ob: %d do: %d st: %d\n",
1340 i,
1341 so->output[i].register_index,
1342 so->output[i].start_component,
1343 so->output[i].num_components,
1344 so->output[i].output_buffer,
1345 so->output[i].dst_offset,
1346 so->output[i].stream);
1347 }
1348 }
1349
get_skip_str(int * skip_val)1350 static char *get_skip_str(int *skip_val)
1351 {
1352 char *start_skip = NULL;
1353 if (*skip_val < 0) {
1354 *skip_val = 0;
1355 return NULL;
1356 }
1357
1358 if (*skip_val == 1) {
1359 start_skip = strdup("gl_SkipComponents1");
1360 *skip_val -= 1;
1361 } else if (*skip_val == 2) {
1362 start_skip = strdup("gl_SkipComponents2");
1363 *skip_val -= 2;
1364 } else if (*skip_val == 3) {
1365 start_skip = strdup("gl_SkipComponents3");
1366 *skip_val -= 3;
1367 } else if (*skip_val >= 4) {
1368 start_skip = strdup("gl_SkipComponents4");
1369 *skip_val -= 4;
1370 }
1371 return start_skip;
1372 }
1373
set_stream_out_varyings(MAYBE_UNUSED struct vrend_sub_context * sub_ctx,int prog_id,struct vrend_shader_info * sinfo)1374 static void set_stream_out_varyings(MAYBE_UNUSED struct vrend_sub_context *sub_ctx,
1375 int prog_id,
1376 struct vrend_shader_info *sinfo)
1377 {
1378 struct pipe_stream_output_info *so = &sinfo->so_info;
1379 char *varyings[PIPE_MAX_SHADER_OUTPUTS*2];
1380 int j;
1381 uint i, n_outputs = 0;
1382 int last_buffer = 0;
1383 char *start_skip;
1384 int buf_offset = 0;
1385 int skip;
1386 if (!so->num_outputs)
1387 return;
1388
1389 VREND_DEBUG_EXT(dbg_shader_streamout, sub_ctx->parent, dump_stream_out(so));
1390
1391 for (i = 0; i < so->num_outputs; i++) {
1392 if (last_buffer != so->output[i].output_buffer) {
1393
1394 skip = so->stride[last_buffer] - buf_offset;
1395 while (skip) {
1396 start_skip = get_skip_str(&skip);
1397 if (start_skip)
1398 varyings[n_outputs++] = start_skip;
1399 }
1400 for (j = last_buffer; j < so->output[i].output_buffer; j++)
1401 varyings[n_outputs++] = strdup("gl_NextBuffer");
1402 last_buffer = so->output[i].output_buffer;
1403 buf_offset = 0;
1404 }
1405
1406 skip = so->output[i].dst_offset - buf_offset;
1407 while (skip) {
1408 start_skip = get_skip_str(&skip);
1409 if (start_skip)
1410 varyings[n_outputs++] = start_skip;
1411 }
1412 buf_offset = so->output[i].dst_offset;
1413
1414 buf_offset += so->output[i].num_components;
1415 if (sinfo->so_names[i])
1416 varyings[n_outputs++] = strdup(sinfo->so_names[i]);
1417 }
1418
1419 skip = so->stride[last_buffer] - buf_offset;
1420 while (skip) {
1421 start_skip = get_skip_str(&skip);
1422 if (start_skip)
1423 varyings[n_outputs++] = start_skip;
1424 }
1425
1426 glTransformFeedbackVaryings(prog_id, n_outputs,
1427 (const GLchar **)varyings, GL_INTERLEAVED_ATTRIBS_EXT);
1428
1429 for (i = 0; i < n_outputs; i++)
1430 if (varyings[i])
1431 free(varyings[i]);
1432 }
1433
bind_sampler_locs(struct vrend_linked_shader_program * sprog,int shader_type,int next_sampler_id)1434 static int bind_sampler_locs(struct vrend_linked_shader_program *sprog,
1435 int shader_type, int next_sampler_id)
1436 {
1437 const struct vrend_shader_info *sinfo = &sprog->ss[shader_type]->sel->sinfo;
1438
1439 if (sinfo->samplers_used_mask) {
1440 uint32_t mask = sinfo->samplers_used_mask;
1441 sprog->shadow_samp_mask[shader_type] = sinfo->shadow_samp_mask;
1442 if (sinfo->shadow_samp_mask) {
1443 unsigned nsamp = util_bitcount(sinfo->samplers_used_mask);
1444 sprog->shadow_samp_mask_locs[shader_type] = calloc(nsamp, sizeof(uint32_t));
1445 sprog->shadow_samp_add_locs[shader_type] = calloc(nsamp, sizeof(uint32_t));
1446 } else {
1447 sprog->shadow_samp_mask_locs[shader_type] = sprog->shadow_samp_add_locs[shader_type] = NULL;
1448 }
1449 const char *prefix = pipe_shader_to_prefix(shader_type);
1450 int sampler_index = 0;
1451 while(mask) {
1452 uint32_t i = u_bit_scan(&mask);
1453 char name[64];
1454 if (sinfo->num_sampler_arrays) {
1455 int arr_idx = vrend_shader_lookup_sampler_array(sinfo, i);
1456 snprintf(name, 32, "%ssamp%d[%d]", prefix, arr_idx, i - arr_idx);
1457 } else
1458 snprintf(name, 32, "%ssamp%d", prefix, i);
1459
1460 glUniform1i(glGetUniformLocation(sprog->id, name), next_sampler_id++);
1461
1462 if (sinfo->shadow_samp_mask & (1 << i)) {
1463 snprintf(name, 32, "%sshadmask%d", prefix, i);
1464 sprog->shadow_samp_mask_locs[shader_type][sampler_index] = glGetUniformLocation(sprog->id, name);
1465 snprintf(name, 32, "%sshadadd%d", prefix, i);
1466 sprog->shadow_samp_add_locs[shader_type][sampler_index] = glGetUniformLocation(sprog->id, name);
1467 }
1468 sampler_index++;
1469 }
1470 } else {
1471 sprog->shadow_samp_mask_locs[shader_type] = NULL;
1472 sprog->shadow_samp_add_locs[shader_type] = NULL;
1473 sprog->shadow_samp_mask[shader_type] = 0;
1474 }
1475 sprog->samplers_used_mask[shader_type] = sinfo->samplers_used_mask;
1476
1477 return next_sampler_id;
1478 }
1479
bind_const_locs(struct vrend_linked_shader_program * sprog,int shader_type)1480 static void bind_const_locs(struct vrend_linked_shader_program *sprog,
1481 int shader_type)
1482 {
1483 if (sprog->ss[shader_type]->sel->sinfo.num_consts) {
1484 char name[32];
1485 snprintf(name, 32, "%sconst0", pipe_shader_to_prefix(shader_type));
1486 sprog->const_location[shader_type] = glGetUniformLocation(sprog->id, name);
1487 } else
1488 sprog->const_location[shader_type] = -1;
1489 }
1490
bind_ubo_locs(struct vrend_linked_shader_program * sprog,int shader_type,int next_ubo_id)1491 static int bind_ubo_locs(struct vrend_linked_shader_program *sprog,
1492 int shader_type, int next_ubo_id)
1493 {
1494 if (!has_feature(feat_ubo))
1495 return next_ubo_id;
1496
1497 const struct vrend_shader_info *sinfo = &sprog->ss[shader_type]->sel->sinfo;
1498 if (sinfo->ubo_used_mask) {
1499 const char *prefix = pipe_shader_to_prefix(shader_type);
1500
1501 unsigned mask = sinfo->ubo_used_mask;
1502 while (mask) {
1503 uint32_t ubo_idx = u_bit_scan(&mask);
1504 char name[32];
1505 if (sinfo->ubo_indirect)
1506 snprintf(name, 32, "%subo[%d]", prefix, ubo_idx - 1);
1507 else
1508 snprintf(name, 32, "%subo%d", prefix, ubo_idx);
1509
1510 GLuint loc = glGetUniformBlockIndex(sprog->id, name);
1511 glUniformBlockBinding(sprog->id, loc, next_ubo_id++);
1512 }
1513 }
1514
1515 sprog->ubo_used_mask[shader_type] = sinfo->ubo_used_mask;
1516
1517 return next_ubo_id;
1518 }
1519
bind_ssbo_locs(struct vrend_linked_shader_program * sprog,int shader_type)1520 static void bind_ssbo_locs(struct vrend_linked_shader_program *sprog,
1521 int shader_type)
1522 {
1523 if (!has_feature(feat_ssbo))
1524 return;
1525 sprog->ssbo_used_mask[shader_type] = sprog->ss[shader_type]->sel->sinfo.ssbo_used_mask;
1526 }
1527
bind_image_locs(struct vrend_linked_shader_program * sprog,int shader_type)1528 static void bind_image_locs(struct vrend_linked_shader_program *sprog,
1529 int shader_type)
1530 {
1531 int i;
1532 char name[32];
1533 const char *prefix = pipe_shader_to_prefix(shader_type);
1534 const struct vrend_shader_info *sinfo = &sprog->ss[shader_type]->sel->sinfo;
1535
1536 uint32_t mask = sinfo->images_used_mask;
1537 if (!mask && !sinfo->num_image_arrays)
1538 return;
1539
1540 if (!has_feature(feat_images))
1541 return;
1542
1543 int nsamp = util_last_bit(mask);
1544 if (nsamp) {
1545 sprog->img_locs[shader_type] = calloc(nsamp, sizeof(GLint));
1546 if (!sprog->img_locs[shader_type])
1547 return;
1548 } else
1549 sprog->img_locs[shader_type] = NULL;
1550
1551 if (sinfo->num_image_arrays) {
1552 for (i = 0; i < sinfo->num_image_arrays; i++) {
1553 struct vrend_array *img_array = &sinfo->image_arrays[i];
1554 for (int j = 0; j < img_array->array_size; j++) {
1555 snprintf(name, 32, "%simg%d[%d]", prefix, img_array->first, j);
1556 sprog->img_locs[shader_type][img_array->first + j] = glGetUniformLocation(sprog->id, name);
1557 if (sprog->img_locs[shader_type][img_array->first + j] == -1)
1558 vrend_printf( "failed to get uniform loc for image %s\n", name);
1559 }
1560 }
1561 } else if (mask) {
1562 for (i = 0; i < nsamp; i++) {
1563 if (mask & (1 << i)) {
1564 snprintf(name, 32, "%simg%d", prefix, i);
1565 sprog->img_locs[shader_type][i] = glGetUniformLocation(sprog->id, name);
1566 if (sprog->img_locs[shader_type][i] == -1)
1567 vrend_printf( "failed to get uniform loc for image %s\n", name);
1568 } else {
1569 sprog->img_locs[shader_type][i] = -1;
1570 }
1571 }
1572 }
1573 sprog->images_used_mask[shader_type] = mask;
1574 }
1575
add_cs_shader_program(struct vrend_context * ctx,struct vrend_shader * cs)1576 static struct vrend_linked_shader_program *add_cs_shader_program(struct vrend_context *ctx,
1577 struct vrend_shader *cs)
1578 {
1579 struct vrend_linked_shader_program *sprog = CALLOC_STRUCT(vrend_linked_shader_program);
1580 GLuint prog_id;
1581 GLint lret;
1582 prog_id = glCreateProgram();
1583 glAttachShader(prog_id, cs->id);
1584 glLinkProgram(prog_id);
1585
1586 glGetProgramiv(prog_id, GL_LINK_STATUS, &lret);
1587 if (lret == GL_FALSE) {
1588 char infolog[65536];
1589 int len;
1590 glGetProgramInfoLog(prog_id, 65536, &len, infolog);
1591 vrend_printf("got error linking\n%s\n", infolog);
1592 /* dump shaders */
1593 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_SHADER, 0);
1594 vrend_shader_dump(cs);
1595 glDeleteProgram(prog_id);
1596 free(sprog);
1597 return NULL;
1598 }
1599 sprog->ss[PIPE_SHADER_COMPUTE] = cs;
1600
1601 list_add(&sprog->sl[PIPE_SHADER_COMPUTE], &cs->programs);
1602 sprog->id = prog_id;
1603 list_addtail(&sprog->head, &ctx->sub->cs_programs);
1604
1605 vrend_use_program(ctx->sub, prog_id);
1606
1607 bind_sampler_locs(sprog, PIPE_SHADER_COMPUTE, 0);
1608 bind_ubo_locs(sprog, PIPE_SHADER_COMPUTE, 0);
1609 bind_ssbo_locs(sprog, PIPE_SHADER_COMPUTE);
1610 bind_const_locs(sprog, PIPE_SHADER_COMPUTE);
1611 bind_image_locs(sprog, PIPE_SHADER_COMPUTE);
1612 return sprog;
1613 }
1614
add_shader_program(struct vrend_sub_context * sub_ctx,struct vrend_shader * vs,struct vrend_shader * fs,struct vrend_shader * gs,struct vrend_shader * tcs,struct vrend_shader * tes)1615 static struct vrend_linked_shader_program *add_shader_program(struct vrend_sub_context *sub_ctx,
1616 struct vrend_shader *vs,
1617 struct vrend_shader *fs,
1618 struct vrend_shader *gs,
1619 struct vrend_shader *tcs,
1620 struct vrend_shader *tes)
1621 {
1622 struct vrend_linked_shader_program *sprog = CALLOC_STRUCT(vrend_linked_shader_program);
1623 char name[64];
1624 int i;
1625 GLuint prog_id;
1626 GLint lret;
1627 int last_shader;
1628 if (!sprog)
1629 return NULL;
1630
1631 prog_id = glCreateProgram();
1632 glAttachShader(prog_id, vs->id);
1633 if (tcs && tcs->id > 0)
1634 glAttachShader(prog_id, tcs->id);
1635 if (tes && tes->id > 0)
1636 glAttachShader(prog_id, tes->id);
1637
1638 if (gs) {
1639 if (gs->id > 0)
1640 glAttachShader(prog_id, gs->id);
1641 set_stream_out_varyings(sub_ctx, prog_id, &gs->sel->sinfo);
1642 } else if (tes)
1643 set_stream_out_varyings(sub_ctx, prog_id, &tes->sel->sinfo);
1644 else
1645 set_stream_out_varyings(sub_ctx, prog_id, &vs->sel->sinfo);
1646 glAttachShader(prog_id, fs->id);
1647
1648 if (fs->sel->sinfo.num_outputs > 1) {
1649 if (util_blend_state_is_dual(&sub_ctx->blend_state, 0)) {
1650 if (has_feature(feat_dual_src_blend)) {
1651 glBindFragDataLocationIndexed(prog_id, 0, 0, "fsout_c0");
1652 glBindFragDataLocationIndexed(prog_id, 0, 1, "fsout_c1");
1653 } else {
1654 vrend_report_context_error(sub_ctx->parent, VIRGL_ERROR_CTX_ILLEGAL_DUAL_SRC_BLEND, 0);
1655 }
1656 sprog->dual_src_linked = true;
1657 } else {
1658 if (has_feature(feat_dual_src_blend)) {
1659 glBindFragDataLocationIndexed(prog_id, 0, 0, "fsout_c0");
1660 glBindFragDataLocationIndexed(prog_id, 1, 0, "fsout_c1");
1661 }
1662 sprog->dual_src_linked = false;
1663 }
1664 } else
1665 sprog->dual_src_linked = false;
1666
1667 if (has_feature(feat_gles31_vertex_attrib_binding)) {
1668 uint32_t mask = vs->sel->sinfo.attrib_input_mask;
1669 while (mask) {
1670 i = u_bit_scan(&mask);
1671 snprintf(name, 32, "in_%d", i);
1672 glBindAttribLocation(prog_id, i, name);
1673 }
1674 }
1675
1676 glLinkProgram(prog_id);
1677
1678 glGetProgramiv(prog_id, GL_LINK_STATUS, &lret);
1679 if (lret == GL_FALSE) {
1680 char infolog[65536];
1681 int len;
1682 glGetProgramInfoLog(prog_id, 65536, &len, infolog);
1683 vrend_printf("got error linking\n%s\n", infolog);
1684 /* dump shaders */
1685 vrend_report_context_error(sub_ctx->parent, VIRGL_ERROR_CTX_ILLEGAL_SHADER, 0);
1686 vrend_shader_dump(vs);
1687 if (gs)
1688 vrend_shader_dump(gs);
1689 vrend_shader_dump(fs);
1690 glDeleteProgram(prog_id);
1691 free(sprog);
1692 return NULL;
1693 }
1694
1695 sprog->ss[PIPE_SHADER_VERTEX] = vs;
1696 sprog->ss[PIPE_SHADER_FRAGMENT] = fs;
1697 sprog->vs_fs_key = (((uint64_t)fs->id) << 32) | (vs->id & ~VREND_PROGRAM_NQUEUE_MASK) |
1698 (sprog->dual_src_linked ? 1 : 0);
1699
1700 sprog->ss[PIPE_SHADER_GEOMETRY] = gs;
1701 sprog->ss[PIPE_SHADER_TESS_CTRL] = tcs;
1702 sprog->ss[PIPE_SHADER_TESS_EVAL] = tes;
1703
1704 list_add(&sprog->sl[PIPE_SHADER_VERTEX], &vs->programs);
1705 list_add(&sprog->sl[PIPE_SHADER_FRAGMENT], &fs->programs);
1706 if (gs)
1707 list_add(&sprog->sl[PIPE_SHADER_GEOMETRY], &gs->programs);
1708 if (tcs)
1709 list_add(&sprog->sl[PIPE_SHADER_TESS_CTRL], &tcs->programs);
1710 if (tes)
1711 list_add(&sprog->sl[PIPE_SHADER_TESS_EVAL], &tes->programs);
1712
1713 last_shader = tes ? PIPE_SHADER_TESS_EVAL : (gs ? PIPE_SHADER_GEOMETRY : PIPE_SHADER_FRAGMENT);
1714 sprog->id = prog_id;
1715
1716 list_addtail(&sprog->head, &sub_ctx->gl_programs[vs->id & VREND_PROGRAM_NQUEUE_MASK]);
1717
1718 if (fs->key.pstipple_tex)
1719 sprog->fs_stipple_loc = glGetUniformLocation(prog_id, "pstipple_sampler");
1720 else
1721 sprog->fs_stipple_loc = -1;
1722 if (vrend_shader_needs_alpha_func(&fs->key))
1723 sprog->fs_alpha_ref_val_loc = glGetUniformLocation(prog_id, "alpha_ref_val");
1724 else
1725 sprog->fs_alpha_ref_val_loc = -1;
1726 sprog->vs_ws_adjust_loc = glGetUniformLocation(prog_id, "winsys_adjust_y");
1727
1728 vrend_use_program(sub_ctx, prog_id);
1729
1730 int next_ubo_id = 0, next_sampler_id = 0;
1731 for (int shader_type = PIPE_SHADER_VERTEX; shader_type <= last_shader; shader_type++) {
1732 if (!sprog->ss[shader_type])
1733 continue;
1734
1735 next_sampler_id = bind_sampler_locs(sprog, shader_type, next_sampler_id);
1736 bind_const_locs(sprog, shader_type);
1737 next_ubo_id = bind_ubo_locs(sprog, shader_type, next_ubo_id);
1738 bind_image_locs(sprog, shader_type);
1739 bind_ssbo_locs(sprog, shader_type);
1740 }
1741
1742 if (!has_feature(feat_gles31_vertex_attrib_binding)) {
1743 if (vs->sel->sinfo.num_inputs) {
1744 sprog->attrib_locs = calloc(vs->sel->sinfo.num_inputs, sizeof(uint32_t));
1745 if (sprog->attrib_locs) {
1746 for (i = 0; i < vs->sel->sinfo.num_inputs; i++) {
1747 snprintf(name, 32, "in_%d", i);
1748 sprog->attrib_locs[i] = glGetAttribLocation(prog_id, name);
1749 }
1750 }
1751 } else
1752 sprog->attrib_locs = NULL;
1753 }
1754
1755 if (vs->var_sinfo.num_ucp) {
1756 for (i = 0; i < vs->var_sinfo.num_ucp; i++) {
1757 snprintf(name, 32, "clipp[%d]", i);
1758 sprog->clip_locs[i] = glGetUniformLocation(prog_id, name);
1759 }
1760 }
1761 return sprog;
1762 }
1763
lookup_cs_shader_program(struct vrend_context * ctx,GLuint cs_id)1764 static struct vrend_linked_shader_program *lookup_cs_shader_program(struct vrend_context *ctx,
1765 GLuint cs_id)
1766 {
1767 struct vrend_linked_shader_program *ent;
1768 LIST_FOR_EACH_ENTRY(ent, &ctx->sub->cs_programs, head) {
1769 if (ent->ss[PIPE_SHADER_COMPUTE]->id == cs_id) {
1770 list_del(&ent->head);
1771 list_add(&ent->head, &ctx->sub->cs_programs);
1772 return ent;
1773 }
1774 }
1775 return NULL;
1776 }
1777
lookup_shader_program(struct vrend_sub_context * sub_ctx,GLuint vs_id,GLuint fs_id,GLuint gs_id,GLuint tcs_id,GLuint tes_id,bool dual_src)1778 static struct vrend_linked_shader_program *lookup_shader_program(struct vrend_sub_context *sub_ctx,
1779 GLuint vs_id,
1780 GLuint fs_id,
1781 GLuint gs_id,
1782 GLuint tcs_id,
1783 GLuint tes_id,
1784 bool dual_src)
1785 {
1786 uint64_t vs_fs_key = (((uint64_t)fs_id) << 32) | (vs_id & ~VREND_PROGRAM_NQUEUE_MASK) |
1787 (dual_src ? 1 : 0);
1788
1789 struct vrend_linked_shader_program *ent;
1790
1791 struct list_head *programs = &sub_ctx->gl_programs[vs_id & VREND_PROGRAM_NQUEUE_MASK];
1792 LIST_FOR_EACH_ENTRY(ent, programs, head) {
1793 if (likely(ent->vs_fs_key != vs_fs_key))
1794 continue;
1795 if (ent->ss[PIPE_SHADER_GEOMETRY] &&
1796 ent->ss[PIPE_SHADER_GEOMETRY]->id != gs_id)
1797 continue;
1798 if (ent->ss[PIPE_SHADER_TESS_CTRL] &&
1799 ent->ss[PIPE_SHADER_TESS_CTRL]->id != tcs_id)
1800 continue;
1801 if (ent->ss[PIPE_SHADER_TESS_EVAL] &&
1802 ent->ss[PIPE_SHADER_TESS_EVAL]->id != tes_id)
1803 continue;
1804 /* put the entry in front */
1805 if (programs->next != &ent->head) {
1806 list_del(&ent->head);
1807 list_add(&ent->head, programs);
1808 }
1809 return ent;
1810 }
1811
1812 return NULL;
1813 }
1814
vrend_destroy_program(struct vrend_linked_shader_program * ent)1815 static void vrend_destroy_program(struct vrend_linked_shader_program *ent)
1816 {
1817 int i;
1818 if (ent->ref_context && ent->ref_context->prog == ent)
1819 ent->ref_context->prog = NULL;
1820
1821 glDeleteProgram(ent->id);
1822 list_del(&ent->head);
1823
1824 for (i = PIPE_SHADER_VERTEX; i <= PIPE_SHADER_COMPUTE; i++) {
1825 if (ent->ss[i])
1826 list_del(&ent->sl[i]);
1827 free(ent->shadow_samp_mask_locs[i]);
1828 free(ent->shadow_samp_add_locs[i]);
1829 free(ent->img_locs[i]);
1830 }
1831 free(ent->attrib_locs);
1832 free(ent);
1833 }
1834
vrend_free_programs(struct vrend_sub_context * sub)1835 static void vrend_free_programs(struct vrend_sub_context *sub)
1836 {
1837 struct vrend_linked_shader_program *ent, *tmp;
1838
1839 if (!LIST_IS_EMPTY(&sub->cs_programs)) {
1840 LIST_FOR_EACH_ENTRY_SAFE(ent, tmp, &sub->cs_programs, head)
1841 vrend_destroy_program(ent);
1842 }
1843
1844 for (unsigned i = 0; i < VREND_PROGRAM_NQUEUES; ++i) {
1845 if (!LIST_IS_EMPTY(&sub->gl_programs[i])) {
1846 LIST_FOR_EACH_ENTRY_SAFE(ent, tmp, &sub->gl_programs[i], head)
1847 vrend_destroy_program(ent);
1848 }
1849 }
1850 }
1851
vrend_destroy_streamout_object(struct vrend_streamout_object * obj)1852 static void vrend_destroy_streamout_object(struct vrend_streamout_object *obj)
1853 {
1854 unsigned i;
1855 list_del(&obj->head);
1856 for (i = 0; i < obj->num_targets; i++)
1857 vrend_so_target_reference(&obj->so_targets[i], NULL);
1858 if (has_feature(feat_transform_feedback2))
1859 glDeleteTransformFeedbacks(1, &obj->id);
1860 FREE(obj);
1861 }
1862
vrend_sync_make_current(virgl_gl_context gl_cxt)1863 void vrend_sync_make_current(virgl_gl_context gl_cxt) {
1864 GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
1865 vrend_clicbs->make_current(gl_cxt);
1866 glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
1867 glDeleteSync(sync);
1868 }
1869
vrend_create_surface(struct vrend_context * ctx,uint32_t handle,uint32_t res_handle,uint32_t format,uint32_t val0,uint32_t val1,uint32_t nr_samples)1870 int vrend_create_surface(struct vrend_context *ctx,
1871 uint32_t handle,
1872 uint32_t res_handle, uint32_t format,
1873 uint32_t val0, uint32_t val1,
1874 uint32_t nr_samples)
1875 {
1876 struct vrend_surface *surf;
1877 struct vrend_resource *res;
1878 uint32_t ret_handle;
1879
1880 if (format >= PIPE_FORMAT_COUNT) {
1881 return EINVAL;
1882 }
1883
1884 res = vrend_renderer_ctx_res_lookup(ctx, res_handle);
1885 if (!res) {
1886 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle);
1887 return EINVAL;
1888 }
1889
1890 surf = CALLOC_STRUCT(vrend_surface);
1891 if (!surf)
1892 return ENOMEM;
1893
1894 surf->res_handle = res_handle;
1895 surf->format = format;
1896
1897 surf->val0 = val0;
1898 surf->val1 = val1;
1899 surf->id = res->id;
1900 surf->nr_samples = nr_samples;
1901
1902 if (!has_bit(res->storage_bits, VREND_STORAGE_GL_BUFFER) &&
1903 has_bit(res->storage_bits, VREND_STORAGE_GL_IMMUTABLE) &&
1904 has_feature(feat_texture_view)) {
1905 /* We don't need texture views for buffer objects.
1906 * Otherwise we only need a texture view if the
1907 * a) formats differ between the surface and base texture
1908 * b) we need to map a sub range > 1 layer to a surface,
1909 * GL can make a single layer fine without a view, and it
1910 * can map the whole texure fine. In those cases we don't
1911 * create a texture view.
1912 */
1913 int first_layer = surf->val1 & 0xffff;
1914 int last_layer = (surf->val1 >> 16) & 0xffff;
1915
1916 if ((first_layer != last_layer &&
1917 (first_layer != 0 || (last_layer != (int)util_max_layer(&res->base, surf->val0)))) ||
1918 surf->format != res->base.format) {
1919 GLenum target = res->target;
1920 GLenum internalformat = tex_conv_table[format].internalformat;
1921
1922 if (vrend_resource_has_24bpp_internal_format(res))
1923 internalformat = GL_RGB8;
1924
1925 VREND_DEBUG(dbg_tex, ctx, "Create texture view from %s for %s\n",
1926 util_format_name(res->base.format),
1927 util_format_name(surf->format));
1928
1929 glGenTextures(1, &surf->id);
1930 if (vrend_state.use_gles) {
1931 if (target == GL_TEXTURE_RECTANGLE_NV ||
1932 target == GL_TEXTURE_1D)
1933 target = GL_TEXTURE_2D;
1934 else if (target == GL_TEXTURE_1D_ARRAY)
1935 target = GL_TEXTURE_2D_ARRAY;
1936 }
1937
1938 glTextureView(surf->id, target, res->id, internalformat,
1939 0, res->base.last_level + 1,
1940 first_layer, last_layer - first_layer + 1);
1941 }
1942 }
1943
1944 pipe_reference_init(&surf->reference, 1);
1945
1946 vrend_resource_reference(&surf->texture, res);
1947
1948 ret_handle = vrend_renderer_object_insert(ctx, surf, handle, VIRGL_OBJECT_SURFACE);
1949 if (ret_handle == 0) {
1950 FREE(surf);
1951 return ENOMEM;
1952 }
1953 return 0;
1954 }
1955
vrend_destroy_surface_object(void * obj_ptr)1956 static void vrend_destroy_surface_object(void *obj_ptr)
1957 {
1958 struct vrend_surface *surface = obj_ptr;
1959
1960 vrend_surface_reference(&surface, NULL);
1961 }
1962
vrend_destroy_sampler_view_object(void * obj_ptr)1963 static void vrend_destroy_sampler_view_object(void *obj_ptr)
1964 {
1965 struct vrend_sampler_view *samp = obj_ptr;
1966
1967 vrend_sampler_view_reference(&samp, NULL);
1968 }
1969
vrend_destroy_so_target_object(void * obj_ptr)1970 static void vrend_destroy_so_target_object(void *obj_ptr)
1971 {
1972 struct vrend_so_target *target = obj_ptr;
1973 struct vrend_sub_context *sub_ctx = target->sub_ctx;
1974 struct vrend_streamout_object *obj, *tmp;
1975 bool found;
1976 unsigned i;
1977
1978 LIST_FOR_EACH_ENTRY_SAFE(obj, tmp, &sub_ctx->streamout_list, head) {
1979 found = false;
1980 for (i = 0; i < obj->num_targets; i++) {
1981 if (obj->so_targets[i] == target) {
1982 found = true;
1983 break;
1984 }
1985 }
1986 if (found) {
1987 if (obj == sub_ctx->current_so)
1988 sub_ctx->current_so = NULL;
1989 if (obj->xfb_state == XFB_STATE_PAUSED) {
1990 if (has_feature(feat_transform_feedback2))
1991 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, obj->id);
1992 glEndTransformFeedback();
1993 if (sub_ctx->current_so && has_feature(feat_transform_feedback2))
1994 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, sub_ctx->current_so->id);
1995 }
1996 vrend_destroy_streamout_object(obj);
1997 }
1998 }
1999
2000 vrend_so_target_reference(&target, NULL);
2001 }
2002
vrend_destroy_vertex_elements_object(void * obj_ptr)2003 static void vrend_destroy_vertex_elements_object(void *obj_ptr)
2004 {
2005 struct vrend_vertex_element_array *v = obj_ptr;
2006
2007 if (has_feature(feat_gles31_vertex_attrib_binding)) {
2008 glDeleteVertexArrays(1, &v->id);
2009 }
2010 FREE(v);
2011 }
2012
vrend_destroy_sampler_state_object(void * obj_ptr)2013 static void vrend_destroy_sampler_state_object(void *obj_ptr)
2014 {
2015 struct vrend_sampler_state *state = obj_ptr;
2016
2017 if (has_feature(feat_samplers))
2018 glDeleteSamplers(2, state->ids);
2019 FREE(state);
2020 }
2021
convert_wrap(int wrap)2022 static GLuint convert_wrap(int wrap)
2023 {
2024 switch(wrap){
2025 case PIPE_TEX_WRAP_REPEAT: return GL_REPEAT;
2026 case PIPE_TEX_WRAP_CLAMP: if (vrend_state.use_core_profile == false) return GL_CLAMP; else return GL_CLAMP_TO_EDGE;
2027
2028 case PIPE_TEX_WRAP_CLAMP_TO_EDGE: return GL_CLAMP_TO_EDGE;
2029 case PIPE_TEX_WRAP_CLAMP_TO_BORDER: return GL_CLAMP_TO_BORDER;
2030
2031 case PIPE_TEX_WRAP_MIRROR_REPEAT: return GL_MIRRORED_REPEAT;
2032 case PIPE_TEX_WRAP_MIRROR_CLAMP: return GL_MIRROR_CLAMP_EXT;
2033 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: return GL_MIRROR_CLAMP_TO_EDGE_EXT;
2034 case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: return GL_MIRROR_CLAMP_TO_BORDER_EXT;
2035 default:
2036 assert(0);
2037 return -1;
2038 }
2039 }
2040
convert_mag_filter(unsigned int filter)2041 static inline GLenum convert_mag_filter(unsigned int filter)
2042 {
2043 if (filter == PIPE_TEX_FILTER_NEAREST)
2044 return GL_NEAREST;
2045 return GL_LINEAR;
2046 }
2047
convert_min_filter(unsigned int filter,unsigned int mip_filter)2048 static inline GLenum convert_min_filter(unsigned int filter, unsigned int mip_filter)
2049 {
2050 if (mip_filter == PIPE_TEX_MIPFILTER_NONE)
2051 return convert_mag_filter(filter);
2052 else if (mip_filter == PIPE_TEX_MIPFILTER_LINEAR) {
2053 if (filter == PIPE_TEX_FILTER_NEAREST)
2054 return GL_NEAREST_MIPMAP_LINEAR;
2055 else
2056 return GL_LINEAR_MIPMAP_LINEAR;
2057 } else if (mip_filter == PIPE_TEX_MIPFILTER_NEAREST) {
2058 if (filter == PIPE_TEX_FILTER_NEAREST)
2059 return GL_NEAREST_MIPMAP_NEAREST;
2060 else
2061 return GL_LINEAR_MIPMAP_NEAREST;
2062 }
2063 assert(0);
2064 return 0;
2065 }
2066
apply_sampler_border_color(GLuint sampler,const GLuint colors[static4])2067 static void apply_sampler_border_color(GLuint sampler,
2068 const GLuint colors[static 4])
2069 {
2070 if (has_feature(feat_sampler_border_colors)) {
2071 glSamplerParameterIuiv(sampler, GL_TEXTURE_BORDER_COLOR, colors);
2072 } else if (colors[0] || colors[1] || colors[2] || colors[3]) {
2073 vrend_printf("sampler border color setting requested but not supported\n");
2074 }
2075 }
2076
vrend_create_sampler_state(struct vrend_context * ctx,uint32_t handle,struct pipe_sampler_state * templ)2077 int vrend_create_sampler_state(struct vrend_context *ctx,
2078 uint32_t handle,
2079 struct pipe_sampler_state *templ)
2080 {
2081 struct vrend_sampler_state *state = CALLOC_STRUCT(vrend_sampler_state);
2082 int ret_handle;
2083
2084 if (!state)
2085 return ENOMEM;
2086
2087 state->base = *templ;
2088
2089 if (has_feature(feat_samplers)) {
2090 glGenSamplers(2, state->ids);
2091
2092 for (int i = 0; i < 2; ++i) {
2093 glSamplerParameteri(state->ids[i], GL_TEXTURE_WRAP_S, convert_wrap(templ->wrap_s));
2094 glSamplerParameteri(state->ids[i], GL_TEXTURE_WRAP_T, convert_wrap(templ->wrap_t));
2095 glSamplerParameteri(state->ids[i], GL_TEXTURE_WRAP_R, convert_wrap(templ->wrap_r));
2096 glSamplerParameterf(state->ids[i], GL_TEXTURE_MIN_FILTER, convert_min_filter(templ->min_img_filter, templ->min_mip_filter));
2097 glSamplerParameterf(state->ids[i], GL_TEXTURE_MAG_FILTER, convert_mag_filter(templ->mag_img_filter));
2098 glSamplerParameterf(state->ids[i], GL_TEXTURE_MIN_LOD, templ->min_lod);
2099 glSamplerParameterf(state->ids[i], GL_TEXTURE_MAX_LOD, templ->max_lod);
2100 glSamplerParameteri(state->ids[i], GL_TEXTURE_COMPARE_MODE, templ->compare_mode ? GL_COMPARE_R_TO_TEXTURE : GL_NONE);
2101 glSamplerParameteri(state->ids[i], GL_TEXTURE_COMPARE_FUNC, GL_NEVER + templ->compare_func);
2102 if (vrend_state.use_gles) {
2103 if (templ->lod_bias)
2104 report_gles_warn(ctx, GLES_WARN_LOD_BIAS);
2105 } else
2106 glSamplerParameterf(state->ids[i], GL_TEXTURE_LOD_BIAS, templ->lod_bias);
2107
2108 if (vrend_state.use_gles) {
2109 if (templ->seamless_cube_map != 0) {
2110 report_gles_warn(ctx, GLES_WARN_SEAMLESS_CUBE_MAP);
2111 }
2112 } else {
2113 glSamplerParameteri(state->ids[i], GL_TEXTURE_CUBE_MAP_SEAMLESS, templ->seamless_cube_map);
2114
2115 }
2116
2117 apply_sampler_border_color(state->ids[i], templ->border_color.ui);
2118 glSamplerParameteri(state->ids[i], GL_TEXTURE_SRGB_DECODE_EXT, i == 0 ? GL_SKIP_DECODE_EXT : GL_DECODE_EXT);
2119 }
2120 }
2121 ret_handle = vrend_renderer_object_insert(ctx, state, handle,
2122 VIRGL_OBJECT_SAMPLER_STATE);
2123 if (!ret_handle) {
2124 if (has_feature(feat_samplers))
2125 glDeleteSamplers(2, state->ids);
2126 FREE(state);
2127 return ENOMEM;
2128 }
2129 return 0;
2130 }
2131
to_gl_swizzle(int swizzle)2132 static inline GLenum to_gl_swizzle(int swizzle)
2133 {
2134 switch (swizzle) {
2135 case PIPE_SWIZZLE_RED: return GL_RED;
2136 case PIPE_SWIZZLE_GREEN: return GL_GREEN;
2137 case PIPE_SWIZZLE_BLUE: return GL_BLUE;
2138 case PIPE_SWIZZLE_ALPHA: return GL_ALPHA;
2139 case PIPE_SWIZZLE_ZERO: return GL_ZERO;
2140 case PIPE_SWIZZLE_ONE: return GL_ONE;
2141 default:
2142 assert(0);
2143 return 0;
2144 }
2145 }
2146
vrend_create_sampler_view(struct vrend_context * ctx,uint32_t handle,uint32_t res_handle,uint32_t format,uint32_t val0,uint32_t val1,uint32_t swizzle_packed)2147 int vrend_create_sampler_view(struct vrend_context *ctx,
2148 uint32_t handle,
2149 uint32_t res_handle, uint32_t format,
2150 uint32_t val0, uint32_t val1, uint32_t swizzle_packed)
2151 {
2152 struct vrend_sampler_view *view;
2153 struct vrend_resource *res;
2154 int ret_handle;
2155 uint8_t swizzle[4];
2156
2157 res = vrend_renderer_ctx_res_lookup(ctx, res_handle);
2158 if (!res) {
2159 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle);
2160 return EINVAL;
2161 }
2162
2163 view = CALLOC_STRUCT(vrend_sampler_view);
2164 if (!view)
2165 return ENOMEM;
2166
2167 pipe_reference_init(&view->reference, 1);
2168 view->format = format & 0xffffff;
2169
2170 if (!view->format || view->format >= VIRGL_FORMAT_MAX) {
2171 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_FORMAT, view->format);
2172 FREE(view);
2173 return EINVAL;
2174 }
2175
2176 uint32_t pipe_target = (format >> 24) & 0xff;
2177 if (pipe_target >= PIPE_MAX_TEXTURE_TYPES) {
2178 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_SAMPLER_VIEW_TARGET,
2179 view->format);
2180 FREE(view);
2181 return EINVAL;
2182 }
2183
2184 view->target = tgsitargettogltarget(pipe_target, res->base.nr_samples);
2185
2186 /* Work around TEXTURE_RECTANGLE and TEXTURE_1D missing on GLES */
2187 if (vrend_state.use_gles) {
2188 if (view->target == GL_TEXTURE_RECTANGLE_NV ||
2189 view->target == GL_TEXTURE_1D)
2190 view->target = GL_TEXTURE_2D;
2191 else if (view->target == GL_TEXTURE_1D_ARRAY)
2192 view->target = GL_TEXTURE_2D_ARRAY;
2193 }
2194
2195 view->val0 = val0;
2196 view->val1 = val1;
2197
2198 swizzle[0] = swizzle_packed & 0x7;
2199 swizzle[1] = (swizzle_packed >> 3) & 0x7;
2200 swizzle[2] = (swizzle_packed >> 6) & 0x7;
2201 swizzle[3] = (swizzle_packed >> 9) & 0x7;
2202
2203 vrend_resource_reference(&view->texture, res);
2204
2205 view->id = view->texture->id;
2206 if (view->target == PIPE_BUFFER)
2207 view->target = view->texture->target;
2208
2209 view->srgb_decode = GL_DECODE_EXT;
2210 if (view->format != view->texture->base.format) {
2211 if (util_format_is_srgb(view->texture->base.format) &&
2212 !util_format_is_srgb(view->format))
2213 view->srgb_decode = GL_SKIP_DECODE_EXT;
2214 }
2215
2216 if (!(util_format_has_alpha(view->format) || util_format_is_depth_or_stencil(view->format))) {
2217 if (swizzle[0] == PIPE_SWIZZLE_ALPHA)
2218 swizzle[0] = PIPE_SWIZZLE_ONE;
2219 if (swizzle[1] == PIPE_SWIZZLE_ALPHA)
2220 swizzle[1] = PIPE_SWIZZLE_ONE;
2221 if (swizzle[2] == PIPE_SWIZZLE_ALPHA)
2222 swizzle[2] = PIPE_SWIZZLE_ONE;
2223 if (swizzle[3] == PIPE_SWIZZLE_ALPHA)
2224 swizzle[3] = PIPE_SWIZZLE_ONE;
2225 }
2226
2227 if (tex_conv_table[view->format].flags & VIRGL_TEXTURE_NEED_SWIZZLE) {
2228 if (swizzle[0] <= PIPE_SWIZZLE_ALPHA)
2229 swizzle[0] = tex_conv_table[view->format].swizzle[swizzle[0]];
2230 if (swizzle[1] <= PIPE_SWIZZLE_ALPHA)
2231 swizzle[1] = tex_conv_table[view->format].swizzle[swizzle[1]];
2232 if (swizzle[2] <= PIPE_SWIZZLE_ALPHA)
2233 swizzle[2] = tex_conv_table[view->format].swizzle[swizzle[2]];
2234 if (swizzle[3] <= PIPE_SWIZZLE_ALPHA)
2235 swizzle[3] = tex_conv_table[view->format].swizzle[swizzle[3]];
2236 }
2237
2238 if (vrend_resource_is_emulated_bgra(view->texture)) {
2239 uint8_t temp = swizzle[0];
2240 swizzle[0] = swizzle[2];
2241 swizzle[2] = temp;
2242 VREND_DEBUG(dbg_bgra, ctx, "swizzling sampler channels on %s resource: (%d %d %d %d)\n",
2243 util_format_name(view->texture->base.format),
2244 swizzle[0], swizzle[1], swizzle[2], swizzle[3]);
2245 }
2246 for (unsigned i = 0; i < 4; ++i)
2247 view->gl_swizzle[i] = to_gl_swizzle(swizzle[i]);
2248
2249 if (!has_bit(view->texture->storage_bits, VREND_STORAGE_GL_BUFFER)) {
2250 enum virgl_formats format;
2251 bool needs_view = false;
2252
2253 /*
2254 * Need to use a texture view if the gallium
2255 * view target is different than the underlying
2256 * texture target.
2257 */
2258 if (view->target != view->texture->target)
2259 needs_view = true;
2260
2261 /*
2262 * If the formats are different and this isn't
2263 * a DS texture a view is required.
2264 * DS are special as they use different gallium
2265 * formats for DS views into a combined resource.
2266 * GL texture views can't be use for this, stencil
2267 * texturing is used instead. For DS formats
2268 * aways program the underlying DS format as a
2269 * view could be required for layers.
2270 */
2271 format = view->format;
2272 if (util_format_is_depth_or_stencil(view->texture->base.format))
2273 format = view->texture->base.format;
2274 else if (view->format != view->texture->base.format)
2275 needs_view = true;
2276
2277 if (needs_view &&
2278 has_bit(view->texture->storage_bits, VREND_STORAGE_GL_IMMUTABLE) &&
2279 has_feature(feat_texture_view)) {
2280 glGenTextures(1, &view->id);
2281 GLenum internalformat = tex_conv_table[format].internalformat;
2282 unsigned base_layer = view->val0 & 0xffff;
2283 unsigned max_layer = (view->val0 >> 16) & 0xffff;
2284 int base_level = view->val1 & 0xff;
2285 int max_level = (view->val1 >> 8) & 0xff;
2286 view->levels = (max_level - base_level) + 1;
2287
2288 glTextureView(view->id, view->target, view->texture->id, internalformat,
2289 base_level, view->levels,
2290 base_layer, max_layer - base_layer + 1);
2291
2292 glBindTexture(view->target, view->id);
2293
2294 if (util_format_is_depth_or_stencil(view->format)) {
2295 if (vrend_state.use_core_profile == false) {
2296 /* setting depth texture mode is deprecated in core profile */
2297 if (view->depth_texture_mode != GL_RED) {
2298 glTexParameteri(view->target, GL_DEPTH_TEXTURE_MODE, GL_RED);
2299 view->depth_texture_mode = GL_RED;
2300 }
2301 }
2302 if (has_feature(feat_stencil_texturing)) {
2303 const struct util_format_description *desc = util_format_description(view->format);
2304 if (!util_format_has_depth(desc)) {
2305 glTexParameteri(view->target, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
2306 } else {
2307 glTexParameteri(view->target, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_DEPTH_COMPONENT);
2308 }
2309 }
2310 }
2311
2312 glTexParameteri(view->target, GL_TEXTURE_BASE_LEVEL, base_level);
2313 glTexParameteri(view->target, GL_TEXTURE_MAX_LEVEL, max_level);
2314 if (vrend_state.use_gles) {
2315 for (unsigned int i = 0; i < 4; ++i) {
2316 glTexParameteri(view->target, GL_TEXTURE_SWIZZLE_R + i, view->gl_swizzle[i]);
2317 }
2318 } else
2319 glTexParameteriv(view->target, GL_TEXTURE_SWIZZLE_RGBA, view->gl_swizzle);
2320 if (util_format_is_srgb(view->format) &&
2321 has_feature(feat_texture_srgb_decode)) {
2322 glTexParameteri(view->target, GL_TEXTURE_SRGB_DECODE_EXT,
2323 view->srgb_decode);
2324 }
2325 glBindTexture(view->target, 0);
2326 } else if (needs_view && view->val0 < ARRAY_SIZE(res->aux_plane_egl_image) &&
2327 res->aux_plane_egl_image[view->val0]) {
2328 void *image = res->aux_plane_egl_image[view->val0];
2329 glGenTextures(1, &view->id);
2330 glBindTexture(view->target, view->id);
2331 glEGLImageTargetTexture2DOES(view->target, (GLeglImageOES) image);
2332 glBindTexture(view->target, 0);
2333 }
2334 }
2335
2336 ret_handle = vrend_renderer_object_insert(ctx, view, handle, VIRGL_OBJECT_SAMPLER_VIEW);
2337 if (ret_handle == 0) {
2338 FREE(view);
2339 return ENOMEM;
2340 }
2341 return 0;
2342 }
2343
vrend_framebuffer_texture_2d(struct vrend_resource * res,GLenum target,GLenum attachment,GLenum textarget,uint32_t texture,int32_t level,uint32_t samples)2344 static void vrend_framebuffer_texture_2d(struct vrend_resource *res,
2345 GLenum target, GLenum attachment,
2346 GLenum textarget, uint32_t texture,
2347 int32_t level, uint32_t samples)
2348 {
2349 if (samples == 0) {
2350 glFramebufferTexture2D(target, attachment, textarget, texture, level);
2351 } else if (!has_feature(feat_implicit_msaa)) {
2352 /* fallback to non-msaa */
2353 report_gles_warn(vrend_state.current_ctx, GLES_WARN_IMPLICIT_MSAA_SURFACE);
2354 glFramebufferTexture2D(target, attachment, textarget, texture, level);
2355 } else if (attachment == GL_COLOR_ATTACHMENT0){
2356 glFramebufferTexture2DMultisampleEXT(target, attachment, textarget,
2357 texture, level, samples);
2358 } else if (attachment == GL_STENCIL_ATTACHMENT || attachment == GL_DEPTH_ATTACHMENT) {
2359 GLenum internalformat =
2360 attachment == GL_STENCIL_ATTACHMENT ? GL_STENCIL_INDEX8 : GL_DEPTH_COMPONENT16;
2361
2362 glGenRenderbuffers(1, &res->rbo_id);
2363 glBindRenderbuffer(GL_RENDERBUFFER, res->rbo_id);
2364 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples,
2365 internalformat, res->base.width0,
2366 res->base.height0);
2367 glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment,
2368 GL_RENDERBUFFER, res->rbo_id);
2369 glBindRenderbuffer(GL_RENDERBUFFER, 0);
2370 } else {
2371 /* unsupported attachment for EXT_multisampled_render_to_texture, fallback to non-msaa */
2372 report_gles_warn(vrend_state.current_ctx, GLES_WARN_IMPLICIT_MSAA_SURFACE);
2373 glFramebufferTexture2D(target, attachment, textarget, texture, level);
2374 }
2375 }
2376
2377 static
debug_texture(MAYBE_UNUSED const char * f,const struct vrend_resource * gt)2378 void debug_texture(MAYBE_UNUSED const char *f, const struct vrend_resource *gt)
2379 {
2380 MAYBE_UNUSED const struct pipe_resource *pr = >->base;
2381 #define PRINT_TARGET(X) case X: vrend_printf( #X); break
2382 VREND_DEBUG_EXT(dbg_tex, NULL,
2383 vrend_printf("%s: ", f);
2384 switch (tgsitargettogltarget(pr->target, pr->nr_samples)) {
2385 PRINT_TARGET(GL_TEXTURE_RECTANGLE_NV);
2386 PRINT_TARGET(GL_TEXTURE_1D);
2387 PRINT_TARGET(GL_TEXTURE_2D);
2388 PRINT_TARGET(GL_TEXTURE_3D);
2389 PRINT_TARGET(GL_TEXTURE_1D_ARRAY);
2390 PRINT_TARGET(GL_TEXTURE_2D_ARRAY);
2391 PRINT_TARGET(GL_TEXTURE_2D_MULTISAMPLE);
2392 PRINT_TARGET(GL_TEXTURE_CUBE_MAP);
2393 PRINT_TARGET(GL_TEXTURE_CUBE_MAP_ARRAY);
2394 default:
2395 vrend_printf("UNKNOWN");
2396 }
2397 vrend_printf(" id:%d pipe_type:%d ms:%d format:%s size: %dx%dx%d mip:%d\n",
2398 gt->id, pr->target, pr->nr_samples, util_format_name(pr->format),
2399 pr->width0, pr->height0, pr->depth0, pr->last_level);
2400 );
2401 #undef PRINT_TARGET
2402 }
2403
vrend_fb_bind_texture_id(struct vrend_resource * res,int id,int idx,uint32_t level,uint32_t layer,uint32_t samples)2404 void vrend_fb_bind_texture_id(struct vrend_resource *res,
2405 int id, int idx, uint32_t level,
2406 uint32_t layer, uint32_t samples)
2407 {
2408 const struct util_format_description *desc = util_format_description(res->base.format);
2409 GLenum attachment = GL_COLOR_ATTACHMENT0 + idx;
2410
2411 debug_texture(__func__, res);
2412
2413 if (vrend_format_is_ds(res->base.format)) {
2414 if (util_format_has_stencil(desc)) {
2415 if (util_format_has_depth(desc))
2416 attachment = GL_DEPTH_STENCIL_ATTACHMENT;
2417 else
2418 attachment = GL_STENCIL_ATTACHMENT;
2419 } else
2420 attachment = GL_DEPTH_ATTACHMENT;
2421 }
2422
2423 switch (res->target) {
2424 case GL_TEXTURE_1D_ARRAY:
2425 case GL_TEXTURE_2D_ARRAY:
2426 case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
2427 case GL_TEXTURE_CUBE_MAP_ARRAY:
2428 if (layer == 0xffffffff)
2429 glFramebufferTexture(GL_FRAMEBUFFER, attachment,
2430 id, level);
2431 else
2432 glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment,
2433 id, level, layer);
2434 break;
2435 case GL_TEXTURE_3D:
2436 if (layer == 0xffffffff)
2437 glFramebufferTexture(GL_FRAMEBUFFER, attachment,
2438 id, level);
2439 else if (vrend_state.use_gles)
2440 glFramebufferTexture3DOES(GL_FRAMEBUFFER, attachment,
2441 res->target, id, level, layer);
2442 else
2443 glFramebufferTexture3D(GL_FRAMEBUFFER, attachment,
2444 res->target, id, level, layer);
2445 break;
2446 case GL_TEXTURE_CUBE_MAP:
2447 if (layer == 0xffffffff)
2448 glFramebufferTexture(GL_FRAMEBUFFER, attachment,
2449 id, level);
2450 else
2451 vrend_framebuffer_texture_2d(res, GL_FRAMEBUFFER, attachment,
2452 GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer,
2453 id, level, samples);
2454 break;
2455 case GL_TEXTURE_1D:
2456 glFramebufferTexture1D(GL_FRAMEBUFFER, attachment,
2457 res->target, id, level);
2458 break;
2459 case GL_TEXTURE_2D:
2460 default:
2461 vrend_framebuffer_texture_2d(res, GL_FRAMEBUFFER, attachment,
2462 res->target, id, level, samples);
2463 break;
2464 }
2465
2466 if (attachment == GL_DEPTH_ATTACHMENT) {
2467 switch (res->target) {
2468 case GL_TEXTURE_1D:
2469 glFramebufferTexture1D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
2470 GL_TEXTURE_1D, 0, 0);
2471 break;
2472 case GL_TEXTURE_2D:
2473 default:
2474 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
2475 GL_TEXTURE_2D, 0, 0);
2476 break;
2477 }
2478 }
2479 }
2480
vrend_fb_bind_texture(struct vrend_resource * res,int idx,uint32_t level,uint32_t layer)2481 void vrend_fb_bind_texture(struct vrend_resource *res,
2482 int idx,
2483 uint32_t level, uint32_t layer)
2484 {
2485 vrend_fb_bind_texture_id(res, res->id, idx, level, layer, 0);
2486 }
2487
vrend_hw_set_zsurf_texture(struct vrend_context * ctx)2488 static void vrend_hw_set_zsurf_texture(struct vrend_context *ctx)
2489 {
2490 struct vrend_surface *surf = ctx->sub->zsurf;
2491
2492 if (!surf) {
2493 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
2494 GL_TEXTURE_2D, 0, 0);
2495 } else {
2496 uint32_t first_layer = surf->val1 & 0xffff;
2497 uint32_t last_layer = (surf->val1 >> 16) & 0xffff;
2498
2499 if (!surf->texture)
2500 return;
2501
2502 vrend_fb_bind_texture_id(surf->texture, surf->id, 0, surf->val0,
2503 first_layer != last_layer ? 0xffffffff : first_layer,
2504 surf->nr_samples);
2505 }
2506 }
2507
vrend_hw_set_color_surface(struct vrend_sub_context * sub_ctx,int index)2508 static void vrend_hw_set_color_surface(struct vrend_sub_context *sub_ctx, int index)
2509 {
2510 struct vrend_surface *surf = sub_ctx->surf[index];
2511
2512 if (!surf) {
2513 GLenum attachment = GL_COLOR_ATTACHMENT0 + index;
2514
2515 glFramebufferTexture2D(GL_FRAMEBUFFER, attachment,
2516 GL_TEXTURE_2D, 0, 0);
2517 } else {
2518 uint32_t first_layer = sub_ctx->surf[index]->val1 & 0xffff;
2519 uint32_t last_layer = (sub_ctx->surf[index]->val1 >> 16) & 0xffff;
2520
2521 vrend_fb_bind_texture_id(surf->texture, surf->id, index, surf->val0,
2522 first_layer != last_layer ? 0xffffffff : first_layer,
2523 surf->nr_samples);
2524 }
2525 }
2526
vrend_hw_emit_framebuffer_state(struct vrend_sub_context * sub_ctx)2527 static void vrend_hw_emit_framebuffer_state(struct vrend_sub_context *sub_ctx)
2528 {
2529 static const GLenum buffers[8] = {
2530 GL_COLOR_ATTACHMENT0,
2531 GL_COLOR_ATTACHMENT1,
2532 GL_COLOR_ATTACHMENT2,
2533 GL_COLOR_ATTACHMENT3,
2534 GL_COLOR_ATTACHMENT4,
2535 GL_COLOR_ATTACHMENT5,
2536 GL_COLOR_ATTACHMENT6,
2537 GL_COLOR_ATTACHMENT7,
2538 };
2539
2540 if (sub_ctx->nr_cbufs == 0) {
2541 glReadBuffer(GL_NONE);
2542 if (has_feature(feat_srgb_write_control)) {
2543 glDisable(GL_FRAMEBUFFER_SRGB_EXT);
2544 sub_ctx->framebuffer_srgb_enabled = false;
2545 }
2546 } else if (has_feature(feat_srgb_write_control)) {
2547 struct vrend_surface *surf = NULL;
2548 bool use_srgb = false;
2549 int i;
2550 for (i = 0; i < sub_ctx->nr_cbufs; i++) {
2551 if (sub_ctx->surf[i]) {
2552 surf = sub_ctx->surf[i];
2553 if (util_format_is_srgb(surf->format)) {
2554 use_srgb = true;
2555 break;
2556 }
2557 }
2558 }
2559 if (use_srgb) {
2560 glEnable(GL_FRAMEBUFFER_SRGB_EXT);
2561 } else {
2562 glDisable(GL_FRAMEBUFFER_SRGB_EXT);
2563 }
2564 sub_ctx->framebuffer_srgb_enabled = use_srgb;
2565 }
2566
2567 sub_ctx->swizzle_output_rgb_to_bgr = 0;
2568 sub_ctx->convert_linear_to_srgb_on_write = 0;
2569 for (int i = 0; i < sub_ctx->nr_cbufs; i++) {
2570 if (sub_ctx->surf[i]) {
2571 struct vrend_surface *surf = sub_ctx->surf[i];
2572 if (vrend_resource_is_emulated_bgra(surf->texture)) {
2573 VREND_DEBUG(dbg_bgra, sub_ctx->parent, "swizzling output for 0x%x (surface format is %s; resource format is %s)\n",
2574 i, util_format_name(surf->format), util_format_name(surf->texture->base.format));
2575 sub_ctx->swizzle_output_rgb_to_bgr |= 1 << i;
2576 }
2577
2578 /* [R8G8B8|B8G8R8]X8_UNORM formatted resources imported to mesa as EGL images occupy 24bpp instead of
2579 * more common 32bpp (with an ignored alpha channel). GL_RGB8 internal format must be specified when
2580 * interacting with these textures in the host driver. Unfortunately, GL_SRGB8 is not guaranteed to
2581 * be color-renderable on either GL or GLES, and is typically not supported. Thus, rendering to such
2582 * surfaces by using an SRGB texture view will have no colorspace conversion effects.
2583 * To work around this, manual colorspace conversion is used instead in the fragment shader and
2584 * during glClearColor() setting.
2585 */
2586 if (vrend_resource_has_24bpp_internal_format(surf->texture) && util_format_is_srgb(surf->format)) {
2587 VREND_DEBUG(dbg_tex, sub_ctx->parent,
2588 "manually converting linear->srgb for EGL-backed framebuffer color attachment 0x%x"
2589 " (surface format is %s; resource format is %s)\n",
2590 i, util_format_name(surf->format), util_format_name(surf->texture->base.format));
2591 sub_ctx->convert_linear_to_srgb_on_write |= 1 << i;
2592 }
2593 }
2594 }
2595
2596 glDrawBuffers(sub_ctx->nr_cbufs, buffers);
2597 }
2598
vrend_set_framebuffer_state(struct vrend_context * ctx,uint32_t nr_cbufs,uint32_t surf_handle[PIPE_MAX_COLOR_BUFS],uint32_t zsurf_handle)2599 void vrend_set_framebuffer_state(struct vrend_context *ctx,
2600 uint32_t nr_cbufs, uint32_t surf_handle[PIPE_MAX_COLOR_BUFS],
2601 uint32_t zsurf_handle)
2602 {
2603 struct vrend_surface *surf, *zsurf;
2604 int i;
2605 int old_num;
2606 GLenum status;
2607 GLint new_height = -1;
2608 bool new_ibf = false;
2609
2610 struct vrend_sub_context *sub_ctx = ctx->sub;
2611
2612 glBindFramebuffer(GL_FRAMEBUFFER, sub_ctx->fb_id);
2613
2614 if (zsurf_handle) {
2615 zsurf = vrend_object_lookup(sub_ctx->object_hash, zsurf_handle, VIRGL_OBJECT_SURFACE);
2616 if (!zsurf) {
2617 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_SURFACE, zsurf_handle);
2618 return;
2619 }
2620 } else
2621 zsurf = NULL;
2622
2623 if (sub_ctx->zsurf != zsurf) {
2624 vrend_surface_reference(&sub_ctx->zsurf, zsurf);
2625 vrend_hw_set_zsurf_texture(ctx);
2626 }
2627
2628 old_num = sub_ctx->nr_cbufs;
2629 sub_ctx->nr_cbufs = nr_cbufs;
2630 sub_ctx->old_nr_cbufs = old_num;
2631
2632 for (i = 0; i < (int)nr_cbufs; i++) {
2633 if (surf_handle[i] != 0) {
2634 surf = vrend_object_lookup(sub_ctx->object_hash, surf_handle[i], VIRGL_OBJECT_SURFACE);
2635 if (!surf) {
2636 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_SURFACE, surf_handle[i]);
2637 return;
2638 }
2639 } else
2640 surf = NULL;
2641
2642 if (sub_ctx->surf[i] != surf) {
2643 vrend_surface_reference(&sub_ctx->surf[i], surf);
2644 vrend_hw_set_color_surface(sub_ctx, i);
2645 }
2646 }
2647
2648 if (old_num > sub_ctx->nr_cbufs) {
2649 for (i = sub_ctx->nr_cbufs; i < old_num; i++) {
2650 vrend_surface_reference(&sub_ctx->surf[i], NULL);
2651 vrend_hw_set_color_surface(sub_ctx, i);
2652 }
2653 }
2654
2655 /* find a buffer to set fb_height from */
2656 if (sub_ctx->nr_cbufs == 0 && !sub_ctx->zsurf) {
2657 new_height = 0;
2658 new_ibf = false;
2659 } else if (sub_ctx->nr_cbufs == 0) {
2660 new_height = u_minify(sub_ctx->zsurf->texture->base.height0, sub_ctx->zsurf->val0);
2661 new_ibf = sub_ctx->zsurf->texture->y_0_top ? true : false;
2662 }
2663 else {
2664 surf = NULL;
2665 for (i = 0; i < sub_ctx->nr_cbufs; i++) {
2666 if (sub_ctx->surf[i]) {
2667 surf = sub_ctx->surf[i];
2668 break;
2669 }
2670 }
2671 if (surf == NULL) {
2672 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_SURFACE, i);
2673 return;
2674 }
2675 new_height = u_minify(surf->texture->base.height0, surf->val0);
2676 new_ibf = surf->texture->y_0_top ? true : false;
2677 }
2678
2679 if (new_height != -1) {
2680 if (sub_ctx->fb_height != (uint32_t)new_height || sub_ctx->inverted_fbo_content != new_ibf) {
2681 sub_ctx->fb_height = new_height;
2682 sub_ctx->inverted_fbo_content = new_ibf;
2683 sub_ctx->viewport_state_dirty = (1 << 0);
2684 }
2685 }
2686
2687 vrend_hw_emit_framebuffer_state(sub_ctx);
2688
2689 if (sub_ctx->nr_cbufs > 0 || sub_ctx->zsurf) {
2690 status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
2691 if (status != GL_FRAMEBUFFER_COMPLETE)
2692 vrend_printf("failed to complete framebuffer 0x%x %s\n", status, ctx->debug_name);
2693 }
2694
2695 sub_ctx->shader_dirty = true;
2696 sub_ctx->blend_state_dirty = true;
2697 }
2698
vrend_set_framebuffer_state_no_attach(UNUSED struct vrend_context * ctx,uint32_t width,uint32_t height,uint32_t layers,uint32_t samples)2699 void vrend_set_framebuffer_state_no_attach(UNUSED struct vrend_context *ctx,
2700 uint32_t width, uint32_t height,
2701 uint32_t layers, uint32_t samples)
2702 {
2703 int gl_ver = vrend_state.gl_major_ver * 10 + vrend_state.gl_minor_ver;
2704
2705 if (has_feature(feat_fb_no_attach)) {
2706 glFramebufferParameteri(GL_FRAMEBUFFER,
2707 GL_FRAMEBUFFER_DEFAULT_WIDTH, width);
2708 glFramebufferParameteri(GL_FRAMEBUFFER,
2709 GL_FRAMEBUFFER_DEFAULT_HEIGHT, height);
2710 if (!(vrend_state.use_gles && gl_ver <= 31))
2711 glFramebufferParameteri(GL_FRAMEBUFFER,
2712 GL_FRAMEBUFFER_DEFAULT_LAYERS, layers);
2713 glFramebufferParameteri(GL_FRAMEBUFFER,
2714 GL_FRAMEBUFFER_DEFAULT_SAMPLES, samples);
2715 }
2716 }
2717
2718 /*
2719 * if the viewport Y scale factor is > 0 then we are rendering to
2720 * an FBO already so don't need to invert rendering?
2721 */
vrend_set_viewport_states(struct vrend_context * ctx,uint32_t start_slot,uint32_t num_viewports,const struct pipe_viewport_state * state)2722 void vrend_set_viewport_states(struct vrend_context *ctx,
2723 uint32_t start_slot,
2724 uint32_t num_viewports,
2725 const struct pipe_viewport_state *state)
2726 {
2727 /* convert back to glViewport */
2728 GLint x, y;
2729 GLsizei width, height;
2730 GLclampd near_val, far_val;
2731 bool viewport_is_negative = (state[0].scale[1] < 0) ? true : false;
2732 uint i, idx;
2733
2734 if (num_viewports > PIPE_MAX_VIEWPORTS ||
2735 start_slot > (PIPE_MAX_VIEWPORTS - num_viewports)) {
2736 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_CMD_BUFFER, num_viewports);
2737 return;
2738 }
2739
2740 for (i = 0; i < num_viewports; i++) {
2741 GLfloat abs_s1 = fabsf(state[i].scale[1]);
2742
2743 idx = start_slot + i;
2744 width = state[i].scale[0] * 2.0f;
2745 height = abs_s1 * 2.0f;
2746 x = state[i].translate[0] - state[i].scale[0];
2747 y = state[i].translate[1] - state[i].scale[1];
2748
2749 if (!ctx->sub->rs_state.clip_halfz) {
2750 near_val = state[i].translate[2] - state[i].scale[2];
2751 far_val = near_val + (state[i].scale[2] * 2.0);
2752 } else {
2753 near_val = state[i].translate[2];
2754 far_val = state[i].scale[2] + state[i].translate[2];
2755 }
2756
2757 if (ctx->sub->vps[idx].cur_x != x ||
2758 ctx->sub->vps[idx].cur_y != y ||
2759 ctx->sub->vps[idx].width != width ||
2760 ctx->sub->vps[idx].height != height ||
2761 ctx->sub->vps[idx].near_val != near_val ||
2762 ctx->sub->vps[idx].far_val != far_val ||
2763 (!(ctx->sub->viewport_state_initialized &= (1 << idx)))) {
2764 ctx->sub->vps[idx].cur_x = x;
2765 ctx->sub->vps[idx].cur_y = y;
2766 ctx->sub->vps[idx].width = width;
2767 ctx->sub->vps[idx].height = height;
2768 ctx->sub->vps[idx].near_val = near_val;
2769 ctx->sub->vps[idx].far_val = far_val;
2770 ctx->sub->viewport_state_dirty |= (1 << idx);
2771 }
2772
2773 if (idx == 0) {
2774 if (ctx->sub->viewport_is_negative != viewport_is_negative)
2775 ctx->sub->viewport_is_negative = viewport_is_negative;
2776 }
2777 }
2778 }
2779
2780 #define UPDATE_INT_SIGN_MASK(fmt, i, signed_mask, unsigned_mask) \
2781 if (vrend_state.use_integer && \
2782 util_format_is_pure_integer(fmt)) { \
2783 if (util_format_is_pure_uint(fmt)) \
2784 unsigned_mask |= (1 << i); \
2785 else \
2786 signed_mask |= (1 << i); \
2787 }
2788
vrend_create_vertex_elements_state(struct vrend_context * ctx,uint32_t handle,unsigned num_elements,const struct pipe_vertex_element * elements)2789 int vrend_create_vertex_elements_state(struct vrend_context *ctx,
2790 uint32_t handle,
2791 unsigned num_elements,
2792 const struct pipe_vertex_element *elements)
2793 {
2794 struct vrend_vertex_element_array *v;
2795 const struct util_format_description *desc;
2796 GLenum type;
2797 uint i;
2798 uint32_t ret_handle;
2799
2800 if (num_elements > PIPE_MAX_ATTRIBS)
2801 return EINVAL;
2802
2803 v = CALLOC_STRUCT(vrend_vertex_element_array);
2804 if (!v)
2805 return ENOMEM;
2806
2807 v->count = num_elements;
2808 for (i = 0; i < num_elements; i++) {
2809 memcpy(&v->elements[i].base, &elements[i], sizeof(struct pipe_vertex_element));
2810
2811 desc = util_format_description(elements[i].src_format);
2812 if (!desc) {
2813 FREE(v);
2814 return EINVAL;
2815 }
2816
2817 type = GL_FALSE;
2818 switch (desc->channel[0].type) {
2819 case UTIL_FORMAT_TYPE_FLOAT:
2820 switch (desc->channel[0].size) {
2821 case 16: type = GL_HALF_FLOAT; break;
2822 case 32: type = GL_FLOAT; break;
2823 case 64: type = GL_DOUBLE; break;
2824 }
2825 break;
2826 case UTIL_FORMAT_TYPE_UNSIGNED:
2827 switch (desc->channel[0].size) {
2828 case 8: type = GL_UNSIGNED_BYTE; break;
2829 case 16: type = GL_UNSIGNED_SHORT; break;
2830 case 32: type = GL_UNSIGNED_INT; break;
2831 }
2832 break;
2833 case UTIL_FORMAT_TYPE_SIGNED:
2834 switch (desc->channel[0].size) {
2835 case 8: type = GL_BYTE; break;
2836 case 16: type = GL_SHORT; break;
2837 case 32: type = GL_INT; break;
2838 }
2839 break;
2840 }
2841 if (type == GL_FALSE) {
2842 switch (elements[i].src_format) {
2843 case PIPE_FORMAT_R10G10B10A2_SSCALED:
2844 case PIPE_FORMAT_R10G10B10A2_SNORM:
2845 case PIPE_FORMAT_B10G10R10A2_SNORM:
2846 type = GL_INT_2_10_10_10_REV;
2847 break;
2848 case PIPE_FORMAT_R10G10B10A2_USCALED:
2849 case PIPE_FORMAT_R10G10B10A2_UNORM:
2850 case PIPE_FORMAT_B10G10R10A2_UNORM:
2851 type = GL_UNSIGNED_INT_2_10_10_10_REV;
2852 break;
2853 case PIPE_FORMAT_R11G11B10_FLOAT:
2854 type = GL_UNSIGNED_INT_10F_11F_11F_REV;
2855 break;
2856 default:
2857 ;
2858 }
2859 }
2860
2861 if (type == GL_FALSE) {
2862 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_VERTEX_FORMAT, elements[i].src_format);
2863 FREE(v);
2864 return EINVAL;
2865 }
2866
2867 v->elements[i].type = type;
2868 if (desc->channel[0].normalized)
2869 v->elements[i].norm = GL_TRUE;
2870 if (desc->nr_channels == 4 && desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_Z)
2871 v->elements[i].nr_chan = GL_BGRA;
2872 else if (elements[i].src_format == PIPE_FORMAT_R11G11B10_FLOAT)
2873 v->elements[i].nr_chan = 3;
2874 else
2875 v->elements[i].nr_chan = desc->nr_channels;
2876 }
2877
2878 if (has_feature(feat_gles31_vertex_attrib_binding)) {
2879 glGenVertexArrays(1, &v->id);
2880 glBindVertexArray(v->id);
2881 for (i = 0; i < num_elements; i++) {
2882 struct vrend_vertex_element *ve = &v->elements[i];
2883
2884 if (util_format_is_pure_integer(ve->base.src_format)) {
2885 UPDATE_INT_SIGN_MASK(ve->base.src_format, i,
2886 v->signed_int_bitmask,
2887 v->unsigned_int_bitmask);
2888 glVertexAttribIFormat(i, ve->nr_chan, ve->type, ve->base.src_offset);
2889 }
2890 else
2891 glVertexAttribFormat(i, ve->nr_chan, ve->type, ve->norm, ve->base.src_offset);
2892 glVertexAttribBinding(i, ve->base.vertex_buffer_index);
2893 glVertexBindingDivisor(i, ve->base.instance_divisor);
2894 glEnableVertexAttribArray(i);
2895 }
2896 }
2897 ret_handle = vrend_renderer_object_insert(ctx, v, handle,
2898 VIRGL_OBJECT_VERTEX_ELEMENTS);
2899 if (!ret_handle) {
2900 FREE(v);
2901 return ENOMEM;
2902 }
2903 return 0;
2904 }
2905
vrend_bind_vertex_elements_state(struct vrend_context * ctx,uint32_t handle)2906 void vrend_bind_vertex_elements_state(struct vrend_context *ctx,
2907 uint32_t handle)
2908 {
2909 struct vrend_vertex_element_array *v;
2910
2911 if (!handle) {
2912 ctx->sub->ve = NULL;
2913 return;
2914 }
2915 v = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_VERTEX_ELEMENTS);
2916 if (!v) {
2917 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_HANDLE, handle);
2918 return;
2919 }
2920
2921 if (ctx->sub->ve != v)
2922 ctx->sub->vbo_dirty = true;
2923 ctx->sub->ve = v;
2924 }
2925
vrend_set_constants(struct vrend_context * ctx,uint32_t shader,uint32_t num_constant,const float * data)2926 void vrend_set_constants(struct vrend_context *ctx,
2927 uint32_t shader,
2928 uint32_t num_constant,
2929 const float *data)
2930 {
2931 struct vrend_constants *consts;
2932
2933 consts = &ctx->sub->consts[shader];
2934 ctx->sub->const_dirty[shader] = true;
2935
2936 /* avoid reallocations by only growing the buffer */
2937 if (consts->num_allocated_consts < num_constant) {
2938 free(consts->consts);
2939 consts->consts = malloc(num_constant * sizeof(float));
2940 if (!consts->consts)
2941 return;
2942 consts->num_allocated_consts = num_constant;
2943 }
2944
2945 memcpy(consts->consts, data, num_constant * sizeof(unsigned int));
2946 consts->num_consts = num_constant;
2947 }
2948
vrend_set_uniform_buffer(struct vrend_context * ctx,uint32_t shader,uint32_t index,uint32_t offset,uint32_t length,uint32_t res_handle)2949 void vrend_set_uniform_buffer(struct vrend_context *ctx,
2950 uint32_t shader,
2951 uint32_t index,
2952 uint32_t offset,
2953 uint32_t length,
2954 uint32_t res_handle)
2955 {
2956 struct vrend_resource *res;
2957
2958 if (!has_feature(feat_ubo))
2959 return;
2960
2961 struct pipe_constant_buffer *cbs = &ctx->sub->cbs[shader][index];
2962 const uint32_t mask = 1u << index;
2963
2964 if (res_handle) {
2965 res = vrend_renderer_ctx_res_lookup(ctx, res_handle);
2966
2967 if (!res) {
2968 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle);
2969 return;
2970 }
2971 cbs->buffer = (struct pipe_resource *)res;
2972 cbs->buffer_offset = offset;
2973 cbs->buffer_size = length;
2974 ctx->sub->const_bufs_used_mask[shader] |= mask;
2975 } else {
2976 cbs->buffer = NULL;
2977 cbs->buffer_offset = 0;
2978 cbs->buffer_size = 0;
2979 ctx->sub->const_bufs_used_mask[shader] &= ~mask;
2980 }
2981 ctx->sub->const_bufs_dirty[shader] |= mask;
2982 }
2983
vrend_set_index_buffer(struct vrend_context * ctx,uint32_t res_handle,uint32_t index_size,uint32_t offset)2984 void vrend_set_index_buffer(struct vrend_context *ctx,
2985 uint32_t res_handle,
2986 uint32_t index_size,
2987 uint32_t offset)
2988 {
2989 struct vrend_resource *res;
2990
2991 ctx->sub->ib.index_size = index_size;
2992 ctx->sub->ib.offset = offset;
2993 if (res_handle) {
2994 if (ctx->sub->index_buffer_res_id != res_handle) {
2995 res = vrend_renderer_ctx_res_lookup(ctx, res_handle);
2996 if (!res) {
2997 vrend_resource_reference((struct vrend_resource **)&ctx->sub->ib.buffer, NULL);
2998 ctx->sub->index_buffer_res_id = 0;
2999 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle);
3000 return;
3001 }
3002 vrend_resource_reference((struct vrend_resource **)&ctx->sub->ib.buffer, res);
3003 ctx->sub->index_buffer_res_id = res_handle;
3004 }
3005 } else {
3006 vrend_resource_reference((struct vrend_resource **)&ctx->sub->ib.buffer, NULL);
3007 ctx->sub->index_buffer_res_id = 0;
3008 }
3009 }
3010
vrend_set_single_vbo(struct vrend_context * ctx,uint32_t index,uint32_t stride,uint32_t buffer_offset,uint32_t res_handle)3011 void vrend_set_single_vbo(struct vrend_context *ctx,
3012 uint32_t index,
3013 uint32_t stride,
3014 uint32_t buffer_offset,
3015 uint32_t res_handle)
3016 {
3017 struct vrend_resource *res;
3018 struct vrend_vertex_buffer *vbo = &ctx->sub->vbo[index];
3019
3020 if (vbo->base.stride != stride ||
3021 vbo->base.buffer_offset != buffer_offset ||
3022 vbo->res_id != res_handle)
3023 ctx->sub->vbo_dirty = true;
3024
3025 vbo->base.stride = stride;
3026 vbo->base.buffer_offset = buffer_offset;
3027
3028 if (res_handle == 0) {
3029 vrend_resource_reference((struct vrend_resource **)&vbo->base.buffer, NULL);
3030 vbo->res_id = 0;
3031 } else if (vbo->res_id != res_handle) {
3032 res = vrend_renderer_ctx_res_lookup(ctx, res_handle);
3033 if (!res) {
3034 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle);
3035 vbo->res_id = 0;
3036 return;
3037 }
3038 vrend_resource_reference((struct vrend_resource **)&vbo->base.buffer, res);
3039 vbo->res_id = res_handle;
3040 }
3041 }
3042
vrend_set_num_vbo_sub(struct vrend_sub_context * sub,int num_vbo)3043 static void vrend_set_num_vbo_sub(struct vrend_sub_context *sub,
3044 int num_vbo)
3045 {
3046 int old_num = sub->num_vbos;
3047 int i;
3048
3049 sub->num_vbos = num_vbo;
3050 sub->old_num_vbos = old_num;
3051
3052 if (old_num != num_vbo)
3053 sub->vbo_dirty = true;
3054
3055 for (i = num_vbo; i < old_num; i++) {
3056 vrend_resource_reference((struct vrend_resource **)&sub->vbo[i].base.buffer, NULL);
3057 sub->vbo[i].res_id = 0;
3058 }
3059
3060 }
3061
vrend_set_num_vbo(struct vrend_context * ctx,int num_vbo)3062 void vrend_set_num_vbo(struct vrend_context *ctx,
3063 int num_vbo)
3064 {
3065 vrend_set_num_vbo_sub(ctx->sub, num_vbo);
3066 }
3067
vrend_set_single_sampler_view(struct vrend_context * ctx,uint32_t shader_type,uint32_t index,uint32_t handle)3068 void vrend_set_single_sampler_view(struct vrend_context *ctx,
3069 uint32_t shader_type,
3070 uint32_t index,
3071 uint32_t handle)
3072 {
3073 struct vrend_sampler_view *view = NULL;
3074 struct vrend_texture *tex;
3075
3076 if (handle) {
3077 view = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_SAMPLER_VIEW);
3078 if (!view) {
3079 ctx->sub->views[shader_type].views[index] = NULL;
3080 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_HANDLE, handle);
3081 return;
3082 }
3083 if (ctx->sub->views[shader_type].views[index] == view) {
3084 return;
3085 }
3086 /* we should have a reference to this texture taken at create time */
3087 tex = (struct vrend_texture *)view->texture;
3088 if (!tex) {
3089 return;
3090 }
3091
3092 ctx->sub->sampler_views_dirty[shader_type] |= 1u << index;
3093
3094 if (!has_bit(view->texture->storage_bits, VREND_STORAGE_GL_BUFFER)) {
3095 if (view->texture->id == view->id) {
3096 glBindTexture(view->target, view->id);
3097
3098 if (util_format_is_depth_or_stencil(view->format)) {
3099 if (vrend_state.use_core_profile == false) {
3100 /* setting depth texture mode is deprecated in core profile */
3101 if (view->depth_texture_mode != GL_RED) {
3102 glTexParameteri(view->texture->target, GL_DEPTH_TEXTURE_MODE, GL_RED);
3103 view->depth_texture_mode = GL_RED;
3104 }
3105 }
3106 if (has_feature(feat_stencil_texturing)) {
3107 const struct util_format_description *desc = util_format_description(view->format);
3108 if (!util_format_has_depth(desc)) {
3109 glTexParameteri(view->texture->target, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
3110 } else {
3111 glTexParameteri(view->texture->target, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_DEPTH_COMPONENT);
3112 }
3113 }
3114 }
3115
3116 GLuint base_level = view->val1 & 0xff;
3117 GLuint max_level = (view->val1 >> 8) & 0xff;
3118 view->levels = max_level - base_level + 1;
3119
3120 if (tex->cur_base != base_level) {
3121 glTexParameteri(view->texture->target, GL_TEXTURE_BASE_LEVEL, base_level);
3122 tex->cur_base = base_level;
3123 }
3124 if (tex->cur_max != max_level) {
3125 glTexParameteri(view->texture->target, GL_TEXTURE_MAX_LEVEL, max_level);
3126 tex->cur_max = max_level;
3127 }
3128 if (memcmp(tex->cur_swizzle, view->gl_swizzle, 4 * sizeof(GLint))) {
3129 if (vrend_state.use_gles) {
3130 for (unsigned int i = 0; i < 4; ++i) {
3131 if (tex->cur_swizzle[i] != view->gl_swizzle[i]) {
3132 glTexParameteri(view->texture->target, GL_TEXTURE_SWIZZLE_R + i, view->gl_swizzle[i]);
3133 }
3134 }
3135 } else
3136 glTexParameteriv(view->texture->target, GL_TEXTURE_SWIZZLE_RGBA, view->gl_swizzle);
3137 memcpy(tex->cur_swizzle, view->gl_swizzle, 4 * sizeof(GLint));
3138 }
3139
3140 if (tex->cur_srgb_decode != view->srgb_decode && util_format_is_srgb(tex->base.base.format)) {
3141 if (has_feature(feat_samplers))
3142 ctx->sub->sampler_views_dirty[shader_type] |= (1u << index);
3143 else if (has_feature(feat_texture_srgb_decode)) {
3144 glTexParameteri(view->texture->target, GL_TEXTURE_SRGB_DECODE_EXT,
3145 view->srgb_decode);
3146 tex->cur_srgb_decode = view->srgb_decode;
3147 }
3148 }
3149 }
3150 } else {
3151 GLenum internalformat;
3152
3153 if (!view->texture->tbo_tex_id)
3154 glGenTextures(1, &view->texture->tbo_tex_id);
3155
3156 glBindTexture(GL_TEXTURE_BUFFER, view->texture->tbo_tex_id);
3157 internalformat = tex_conv_table[view->format].internalformat;
3158 if (has_feature(feat_texture_buffer_range)) {
3159 unsigned offset = view->val0;
3160 unsigned size = view->val1 - view->val0 + 1;
3161 int blsize = util_format_get_blocksize(view->format);
3162
3163 offset *= blsize;
3164 size *= blsize;
3165 glTexBufferRange(GL_TEXTURE_BUFFER, internalformat, view->texture->id, offset, size);
3166 } else
3167 glTexBuffer(GL_TEXTURE_BUFFER, internalformat, view->texture->id);
3168 }
3169 }
3170
3171 vrend_sampler_view_reference(&ctx->sub->views[shader_type].views[index], view);
3172 }
3173
vrend_set_num_sampler_views(struct vrend_context * ctx,uint32_t shader_type,uint32_t start_slot,uint32_t num_sampler_views)3174 void vrend_set_num_sampler_views(struct vrend_context *ctx,
3175 uint32_t shader_type,
3176 uint32_t start_slot,
3177 uint32_t num_sampler_views)
3178 {
3179 int last_slot = start_slot + num_sampler_views;
3180 int i;
3181
3182 for (i = last_slot; i < ctx->sub->views[shader_type].num_views; i++)
3183 vrend_sampler_view_reference(&ctx->sub->views[shader_type].views[i], NULL);
3184
3185 ctx->sub->views[shader_type].num_views = last_slot;
3186 }
3187
vrend_set_single_image_view(struct vrend_context * ctx,uint32_t shader_type,uint32_t index,uint32_t format,uint32_t access,uint32_t layer_offset,uint32_t level_size,uint32_t handle)3188 void vrend_set_single_image_view(struct vrend_context *ctx,
3189 uint32_t shader_type,
3190 uint32_t index,
3191 uint32_t format, uint32_t access,
3192 uint32_t layer_offset, uint32_t level_size,
3193 uint32_t handle)
3194 {
3195 struct vrend_image_view *iview = &ctx->sub->image_views[shader_type][index];
3196 struct vrend_resource *res;
3197
3198 if (handle) {
3199 if (!has_feature(feat_images))
3200 return;
3201
3202 res = vrend_renderer_ctx_res_lookup(ctx, handle);
3203 if (!res) {
3204 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, handle);
3205 return;
3206 }
3207 iview->texture = res;
3208 iview->format = tex_conv_table[format].internalformat;
3209 iview->access = access;
3210 iview->u.buf.offset = layer_offset;
3211 iview->u.buf.size = level_size;
3212 ctx->sub->images_used_mask[shader_type] |= (1u << index);
3213 } else {
3214 iview->texture = NULL;
3215 iview->format = 0;
3216 ctx->sub->images_used_mask[shader_type] &= ~(1u << index);
3217 }
3218 }
3219
vrend_set_single_ssbo(struct vrend_context * ctx,uint32_t shader_type,uint32_t index,uint32_t offset,uint32_t length,uint32_t handle)3220 void vrend_set_single_ssbo(struct vrend_context *ctx,
3221 uint32_t shader_type,
3222 uint32_t index,
3223 uint32_t offset, uint32_t length,
3224 uint32_t handle)
3225 {
3226 struct vrend_ssbo *ssbo = &ctx->sub->ssbo[shader_type][index];
3227 struct vrend_resource *res;
3228
3229 if (!has_feature(feat_ssbo))
3230 return;
3231
3232 if (handle) {
3233 res = vrend_renderer_ctx_res_lookup(ctx, handle);
3234 if (!res) {
3235 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, handle);
3236 return;
3237 }
3238 ssbo->res = res;
3239 ssbo->buffer_offset = offset;
3240 ssbo->buffer_size = length;
3241 ctx->sub->ssbo_used_mask[shader_type] |= (1u << index);
3242 } else {
3243 ssbo->res = 0;
3244 ssbo->buffer_offset = 0;
3245 ssbo->buffer_size = 0;
3246 ctx->sub->ssbo_used_mask[shader_type] &= ~(1u << index);
3247 }
3248 }
3249
vrend_set_single_abo(struct vrend_context * ctx,uint32_t index,uint32_t offset,uint32_t length,uint32_t handle)3250 void vrend_set_single_abo(struct vrend_context *ctx,
3251 uint32_t index,
3252 uint32_t offset, uint32_t length,
3253 uint32_t handle)
3254 {
3255 struct vrend_abo *abo = &ctx->sub->abo[index];
3256 struct vrend_resource *res;
3257
3258 if (!has_feature(feat_atomic_counters))
3259 return;
3260
3261 if (handle) {
3262 res = vrend_renderer_ctx_res_lookup(ctx, handle);
3263 if (!res) {
3264 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, handle);
3265 return;
3266 }
3267 abo->res = res;
3268 abo->buffer_offset = offset;
3269 abo->buffer_size = length;
3270 ctx->sub->abo_used_mask |= (1u << index);
3271 } else {
3272 abo->res = 0;
3273 abo->buffer_offset = 0;
3274 abo->buffer_size = 0;
3275 ctx->sub->abo_used_mask &= ~(1u << index);
3276 }
3277 }
3278
vrend_memory_barrier(UNUSED struct vrend_context * ctx,unsigned flags)3279 void vrend_memory_barrier(UNUSED struct vrend_context *ctx,
3280 unsigned flags)
3281 {
3282 GLbitfield gl_barrier = 0;
3283
3284 if (!has_feature(feat_barrier))
3285 return;
3286
3287 if ((flags & PIPE_BARRIER_ALL) == PIPE_BARRIER_ALL)
3288 gl_barrier = GL_ALL_BARRIER_BITS;
3289 else {
3290 if (flags & PIPE_BARRIER_VERTEX_BUFFER)
3291 gl_barrier |= GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT;
3292 if (flags & PIPE_BARRIER_INDEX_BUFFER)
3293 gl_barrier |= GL_ELEMENT_ARRAY_BARRIER_BIT;
3294 if (flags & PIPE_BARRIER_CONSTANT_BUFFER)
3295 gl_barrier |= GL_UNIFORM_BARRIER_BIT;
3296 if (flags & PIPE_BARRIER_TEXTURE)
3297 gl_barrier |= GL_TEXTURE_FETCH_BARRIER_BIT | GL_PIXEL_BUFFER_BARRIER_BIT;
3298 if (flags & PIPE_BARRIER_IMAGE)
3299 gl_barrier |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT;
3300 if (flags & PIPE_BARRIER_INDIRECT_BUFFER)
3301 gl_barrier |= GL_COMMAND_BARRIER_BIT;
3302 if (flags & PIPE_BARRIER_MAPPED_BUFFER)
3303 gl_barrier |= GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT;
3304 if (flags & PIPE_BARRIER_FRAMEBUFFER)
3305 gl_barrier |= GL_FRAMEBUFFER_BARRIER_BIT;
3306 if (flags & PIPE_BARRIER_STREAMOUT_BUFFER)
3307 gl_barrier |= GL_TRANSFORM_FEEDBACK_BARRIER_BIT;
3308 if (flags & PIPE_BARRIER_SHADER_BUFFER) {
3309 gl_barrier |= GL_ATOMIC_COUNTER_BARRIER_BIT;
3310 if (has_feature(feat_ssbo_barrier))
3311 gl_barrier |= GL_SHADER_STORAGE_BARRIER_BIT;
3312 }
3313 if (has_feature(feat_qbo) && (flags & PIPE_BARRIER_QUERY_BUFFER))
3314 gl_barrier |= GL_QUERY_BUFFER_BARRIER_BIT;
3315 }
3316 glMemoryBarrier(gl_barrier);
3317 }
3318
vrend_texture_barrier(UNUSED struct vrend_context * ctx,unsigned flags)3319 void vrend_texture_barrier(UNUSED struct vrend_context *ctx,
3320 unsigned flags)
3321 {
3322 if (has_feature(feat_texture_barrier) && (flags & PIPE_TEXTURE_BARRIER_SAMPLER))
3323 glTextureBarrier();
3324 if (has_feature(feat_blend_equation_advanced) && (flags & PIPE_TEXTURE_BARRIER_FRAMEBUFFER))
3325 glBlendBarrierKHR();
3326 }
3327
vrend_destroy_shader_object(void * obj_ptr)3328 static void vrend_destroy_shader_object(void *obj_ptr)
3329 {
3330 struct vrend_shader_selector *state = obj_ptr;
3331
3332 vrend_shader_state_reference(&state, NULL);
3333 }
3334
can_emulate_logicop(enum pipe_logicop op)3335 static inline bool can_emulate_logicop(enum pipe_logicop op)
3336 {
3337 if (has_feature(feat_framebuffer_fetch_non_coherent) ||
3338 has_feature(feat_framebuffer_fetch))
3339 return true;
3340
3341 /* These ops don't need to read back from the framebuffer */
3342 switch (op) {
3343 case PIPE_LOGICOP_CLEAR:
3344 case PIPE_LOGICOP_COPY:
3345 case PIPE_LOGICOP_SET:
3346 case PIPE_LOGICOP_COPY_INVERTED:
3347 return true;
3348 default:
3349 return false;
3350 }
3351 }
3352
vrend_sync_shader_io(struct vrend_sub_context * sub_ctx,struct vrend_shader_selector * sel,struct vrend_shader_key * key)3353 static inline void vrend_sync_shader_io(struct vrend_sub_context *sub_ctx,
3354 struct vrend_shader_selector *sel,
3355 struct vrend_shader_key *key)
3356 {
3357 unsigned type = sel->type;
3358
3359 int prev_type = (type != PIPE_SHADER_VERTEX) ?
3360 PIPE_SHADER_VERTEX : -1;
3361
3362 /* Gallium sends and binds the shaders in the reverse order, so if an
3363 * old shader is still bound we should ignore the "previous" (as in
3364 * execution order) shader when the key is evaluated, unless the currently
3365 * bound shader selector is actually refers to the current shader. */
3366 if (sub_ctx->shaders[type] == sel) {
3367 switch (type) {
3368 case PIPE_SHADER_GEOMETRY:
3369 if (key->tcs_present || key->tes_present)
3370 prev_type = PIPE_SHADER_TESS_EVAL;
3371 break;
3372 case PIPE_SHADER_FRAGMENT:
3373 if (key->gs_present)
3374 prev_type = PIPE_SHADER_GEOMETRY;
3375 else if (key->tcs_present || key->tes_present)
3376 prev_type = PIPE_SHADER_TESS_EVAL;
3377 break;
3378 case PIPE_SHADER_TESS_EVAL:
3379 if (key->tcs_present)
3380 prev_type = PIPE_SHADER_TESS_CTRL;
3381 break;
3382 default:
3383 break;
3384 }
3385 }
3386
3387 struct vrend_shader_selector *prev = sub_ctx->shaders[prev_type];
3388 if (prev_type != -1 && prev) {
3389 key->input = prev->sinfo.out;
3390 key->force_invariant_inputs = prev->sinfo.invariant_outputs;
3391
3392 memcpy(key->prev_stage_generic_and_patch_outputs_layout,
3393 prev->sinfo.generic_outputs_layout,
3394 prev->sinfo.out.num_generic_and_patch * sizeof (struct vrend_layout_info));
3395 }
3396
3397 int next_type = -1;
3398
3399 if (type == PIPE_SHADER_FRAGMENT) {
3400 key->fs.invert_origin = !sub_ctx->inverted_fbo_content;
3401 key->fs.swizzle_output_rgb_to_bgr = sub_ctx->swizzle_output_rgb_to_bgr;
3402 key->fs.convert_linear_to_srgb_on_write = sub_ctx->convert_linear_to_srgb_on_write;
3403 if (vrend_state.use_gles && can_emulate_logicop(sub_ctx->blend_state.logicop_func)) {
3404 key->fs.logicop_enabled = sub_ctx->blend_state.logicop_enable;
3405 key->fs.logicop_func = sub_ctx->blend_state.logicop_func;
3406 }
3407 int fs_prim_mode = sub_ctx->prim_mode; // inherit draw-call's mode
3408
3409 // Only use coord_replace if frag shader receives GL_POINTS
3410 switch (prev_type) {
3411 case PIPE_SHADER_TESS_EVAL:
3412 if (sub_ctx->shaders[PIPE_SHADER_TESS_EVAL]->sinfo.tes_point_mode)
3413 fs_prim_mode = PIPE_PRIM_POINTS;
3414 break;
3415 case PIPE_SHADER_GEOMETRY:
3416 fs_prim_mode = sub_ctx->shaders[PIPE_SHADER_GEOMETRY]->sinfo.gs_out_prim;
3417 break;
3418 }
3419 key->fs.prim_is_points = (fs_prim_mode == PIPE_PRIM_POINTS);
3420 key->fs.coord_replace = sub_ctx->rs_state.point_quad_rasterization
3421 && key->fs.prim_is_points
3422 ? sub_ctx->rs_state.sprite_coord_enable
3423 : 0x0;
3424
3425 if (prev_type != -1 && sub_ctx->shaders[prev_type]) {
3426 key->num_clip = sub_ctx->shaders[prev_type]->current->var_sinfo.num_clip;
3427 key->num_cull = sub_ctx->shaders[prev_type]->current->var_sinfo.num_cull;
3428 }
3429
3430 } else {
3431 if (sub_ctx->shaders[PIPE_SHADER_FRAGMENT]) {
3432 struct vrend_shader *fs =
3433 sub_ctx->shaders[PIPE_SHADER_FRAGMENT]->current;
3434 key->compiled_fs_uid = fs->uid;
3435 key->fs_info = &fs->var_sinfo.fs_info;
3436 next_type = PIPE_SHADER_FRAGMENT;
3437 }
3438 }
3439
3440 switch (type) {
3441 case PIPE_SHADER_VERTEX:
3442 if (key->tcs_present)
3443 next_type = PIPE_SHADER_TESS_CTRL;
3444 else if (key->gs_present)
3445 next_type = PIPE_SHADER_GEOMETRY;
3446 else if (key->tes_present) {
3447 if (!vrend_state.use_gles)
3448 next_type = PIPE_SHADER_TESS_EVAL;
3449 else
3450 next_type = PIPE_SHADER_TESS_CTRL;
3451 }
3452 break;
3453 case PIPE_SHADER_TESS_CTRL:
3454 next_type = PIPE_SHADER_TESS_EVAL;
3455 break;
3456 case PIPE_SHADER_TESS_EVAL:
3457 if (key->gs_present)
3458 next_type = PIPE_SHADER_GEOMETRY;
3459 default:
3460 break;
3461 }
3462
3463 if (next_type != -1 && sub_ctx->shaders[next_type]) {
3464 key->output = sub_ctx->shaders[next_type]->sinfo.in;
3465
3466 /* FS gets the clip/cull info in the key from this shader, so
3467 * we can avoid re-translating this shader by not updating the
3468 * info in the key */
3469 if (next_type != PIPE_SHADER_FRAGMENT) {
3470 key->num_clip = sub_ctx->shaders[next_type]->current->var_sinfo.num_clip;
3471 key->num_cull = sub_ctx->shaders[next_type]->current->var_sinfo.num_cull;
3472 }
3473
3474 if (type == PIPE_SHADER_VERTEX && next_type == PIPE_SHADER_FRAGMENT) {
3475 if (sub_ctx->shaders[type]) {
3476 uint32_t fog_input = sub_ctx->shaders[next_type]->sinfo.fog_input_mask;
3477 uint32_t fog_output = sub_ctx->shaders[type]->sinfo.fog_output_mask;
3478
3479 //We only want to issue the fixup for inputs not fed by the outputs of the
3480 //previous stage
3481 key->vs.fog_fixup_mask = (fog_input ^ fog_output) & fog_input;
3482 }
3483 }
3484 }
3485 }
3486
vrend_fill_shader_key(struct vrend_sub_context * sub_ctx,struct vrend_shader_selector * sel,struct vrend_shader_key * key)3487 static inline void vrend_fill_shader_key(struct vrend_sub_context *sub_ctx,
3488 struct vrend_shader_selector *sel,
3489 struct vrend_shader_key *key)
3490 {
3491 unsigned type = sel->type;
3492
3493 if (vrend_state.use_core_profile) {
3494 int i;
3495 bool add_alpha_test = true;
3496
3497 // Only use integer info when drawing to avoid stale info.
3498 if (vrend_state.use_integer && sub_ctx->drawing &&
3499 type == PIPE_SHADER_VERTEX) {
3500 key->vs.attrib_signed_int_bitmask = sub_ctx->ve->signed_int_bitmask;
3501 key->vs.attrib_unsigned_int_bitmask = sub_ctx->ve->unsigned_int_bitmask;
3502 }
3503 if (type == PIPE_SHADER_FRAGMENT) {
3504 for (i = 0; i < sub_ctx->nr_cbufs; i++) {
3505 if (!sub_ctx->surf[i])
3506 continue;
3507 if (vrend_format_is_emulated_alpha(sub_ctx->surf[i]->format))
3508 key->fs.cbufs_are_a8_bitmask |= (1 << i);
3509 if (util_format_is_pure_integer(sub_ctx->surf[i]->format)) {
3510 add_alpha_test = false;
3511 UPDATE_INT_SIGN_MASK(sub_ctx->surf[i]->format, i,
3512 key->fs.cbufs_signed_int_bitmask,
3513 key->fs.cbufs_unsigned_int_bitmask);
3514 }
3515 key->fs.surface_component_bits[i] = util_format_get_component_bits(sub_ctx->surf[i]->format, UTIL_FORMAT_COLORSPACE_RGB, 0);
3516 }
3517 if (add_alpha_test) {
3518 key->add_alpha_test = sub_ctx->dsa_state.alpha.enabled;
3519 key->alpha_test = sub_ctx->dsa_state.alpha.func;
3520 }
3521 }
3522
3523 key->pstipple_tex = sub_ctx->rs_state.poly_stipple_enable;
3524 key->color_two_side = sub_ctx->rs_state.light_twoside;
3525
3526 key->clip_plane_enable = sub_ctx->rs_state.clip_plane_enable;
3527 key->flatshade = sub_ctx->rs_state.flatshade ? true : false;
3528 }
3529
3530 key->gs_present = !!sub_ctx->shaders[PIPE_SHADER_GEOMETRY];
3531 key->tcs_present = !!sub_ctx->shaders[PIPE_SHADER_TESS_CTRL];
3532 key->tes_present = !!sub_ctx->shaders[PIPE_SHADER_TESS_EVAL];
3533
3534 if (type != PIPE_SHADER_COMPUTE)
3535 vrend_sync_shader_io(sub_ctx, sel, key);
3536 }
3537
vrend_shader_create(struct vrend_context * ctx,struct vrend_shader * shader,struct vrend_shader_key * key)3538 static int vrend_shader_create(struct vrend_context *ctx,
3539 struct vrend_shader *shader,
3540 struct vrend_shader_key *key)
3541 {
3542 static uint32_t uid;
3543
3544 shader->uid = ++uid;
3545
3546 if (shader->sel->tokens) {
3547
3548 VREND_DEBUG(dbg_shader_tgsi, ctx, "shader\n%s\n", shader->sel->tmp_buf);
3549
3550 bool ret = vrend_convert_shader(ctx, &ctx->shader_cfg, shader->sel->tokens,
3551 shader->sel->req_local_mem, key, &shader->sel->sinfo,
3552 &shader->var_sinfo, &shader->glsl_strings);
3553 if (!ret) {
3554 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_SHADER, shader->sel->type);
3555 return -1;
3556 }
3557 } else if (!ctx->shader_cfg.use_gles && shader->sel->type != TGSI_PROCESSOR_TESS_CTRL) {
3558 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_SHADER, shader->sel->type);
3559 return -1;
3560 }
3561
3562 shader->key = *key;
3563 return 0;
3564 }
3565
vrend_shader_select(struct vrend_sub_context * sub_ctx,struct vrend_shader_selector * sel,bool * dirty)3566 static int vrend_shader_select(struct vrend_sub_context *sub_ctx,
3567 struct vrend_shader_selector *sel,
3568 bool *dirty)
3569 {
3570 struct vrend_shader_key key;
3571 struct vrend_shader *shader = NULL;
3572 int r;
3573
3574 memset(&key, 0, sizeof(key));
3575 vrend_fill_shader_key(sub_ctx, sel, &key);
3576
3577 if (sel->current && !memcmp(&sel->current->key, &key, sizeof(key)))
3578 return 0;
3579
3580 if (sel->num_shaders > 1) {
3581 struct vrend_shader *p = sel->current;
3582 struct vrend_shader *c = p->next_variant;
3583 while (c && memcmp(&c->key, &key, sizeof(key)) != 0) {
3584 p = c;
3585 c = c->next_variant;
3586 }
3587 if (c) {
3588 p->next_variant = c->next_variant;
3589 shader = c;
3590 }
3591 }
3592
3593 if (!shader) {
3594 shader = CALLOC_STRUCT(vrend_shader);
3595 shader->sel = sel;
3596 list_inithead(&shader->programs);
3597 strarray_alloc(&shader->glsl_strings, SHADER_MAX_STRINGS);
3598
3599 r = vrend_shader_create(sub_ctx->parent, shader, &key);
3600 if (r) {
3601 sel->current = NULL;
3602 FREE(shader);
3603 return r;
3604 }
3605 sel->num_shaders++;
3606 }
3607 if (dirty)
3608 *dirty = true;
3609
3610 shader->next_variant = sel->current;
3611 sel->current = shader;
3612 return 0;
3613 }
3614
vrend_create_shader_state(const struct pipe_stream_output_info * so_info,uint32_t req_local_mem,unsigned pipe_shader_type)3615 static void *vrend_create_shader_state(const struct pipe_stream_output_info *so_info,
3616 uint32_t req_local_mem,
3617 unsigned pipe_shader_type)
3618 {
3619 struct vrend_shader_selector *sel = CALLOC_STRUCT(vrend_shader_selector);
3620
3621 if (!sel)
3622 return NULL;
3623
3624 sel->req_local_mem = req_local_mem;
3625 sel->type = pipe_shader_type;
3626 sel->sinfo.so_info = *so_info;
3627 pipe_reference_init(&sel->reference, 1);
3628
3629 return sel;
3630 }
3631
vrend_finish_shader(struct vrend_context * ctx,struct vrend_shader_selector * sel,const struct tgsi_token * tokens)3632 static int vrend_finish_shader(struct vrend_context *ctx,
3633 struct vrend_shader_selector *sel,
3634 const struct tgsi_token *tokens)
3635 {
3636 int r;
3637
3638 sel->tokens = tgsi_dup_tokens(tokens);
3639
3640 r = vrend_shader_select(ctx->sub, sel, NULL);
3641 if (r) {
3642 return EINVAL;
3643 }
3644 return 0;
3645 }
3646
vrend_create_shader(struct vrend_context * ctx,uint32_t handle,const struct pipe_stream_output_info * so_info,uint32_t req_local_mem,const char * shd_text,uint32_t offlen,uint32_t num_tokens,uint32_t type,uint32_t pkt_length)3647 int vrend_create_shader(struct vrend_context *ctx,
3648 uint32_t handle,
3649 const struct pipe_stream_output_info *so_info,
3650 uint32_t req_local_mem,
3651 const char *shd_text, uint32_t offlen, uint32_t num_tokens,
3652 uint32_t type, uint32_t pkt_length)
3653 {
3654 struct vrend_shader_selector *sel = NULL;
3655 int ret_handle;
3656 bool new_shader = true, long_shader = false;
3657 bool finished = false;
3658 int ret;
3659
3660 if (type > PIPE_SHADER_COMPUTE)
3661 return EINVAL;
3662
3663 if (type == PIPE_SHADER_GEOMETRY &&
3664 !has_feature(feat_geometry_shader))
3665 return EINVAL;
3666
3667 if ((type == PIPE_SHADER_TESS_CTRL ||
3668 type == PIPE_SHADER_TESS_EVAL) &&
3669 !has_feature(feat_tessellation))
3670 return EINVAL;
3671
3672 if (type == PIPE_SHADER_COMPUTE &&
3673 !has_feature(feat_compute_shader))
3674 return EINVAL;
3675
3676 if (offlen & VIRGL_OBJ_SHADER_OFFSET_CONT)
3677 new_shader = false;
3678 else if (((offlen + 3) / 4) > pkt_length)
3679 long_shader = true;
3680
3681 struct vrend_sub_context *sub_ctx = ctx->sub;
3682
3683 /* if we have an in progress one - don't allow a new shader
3684 of that type or a different handle. */
3685 if (sub_ctx->long_shader_in_progress_handle[type]) {
3686 if (new_shader == true)
3687 return EINVAL;
3688 if (handle != sub_ctx->long_shader_in_progress_handle[type])
3689 return EINVAL;
3690 }
3691
3692 if (new_shader) {
3693 sel = vrend_create_shader_state(so_info, req_local_mem, type);
3694 if (sel == NULL)
3695 return ENOMEM;
3696
3697 sel->buf_len = ((offlen + 3) / 4) * 4; /* round up buffer size */
3698 sel->tmp_buf = malloc(sel->buf_len);
3699 if (!sel->tmp_buf) {
3700 ret = ENOMEM;
3701 goto error;
3702 }
3703
3704 memcpy(sel->tmp_buf, shd_text, pkt_length * 4);
3705 if (long_shader) {
3706 sel->buf_offset = pkt_length * 4;
3707 sub_ctx->long_shader_in_progress_handle[type] = handle;
3708 } else
3709 finished = true;
3710 } else {
3711 sel = vrend_object_lookup(sub_ctx->object_hash, handle, VIRGL_OBJECT_SHADER);
3712 if (!sel) {
3713 vrend_printf( "got continuation without original shader %d\n", handle);
3714 ret = EINVAL;
3715 goto error;
3716 }
3717
3718 offlen &= ~VIRGL_OBJ_SHADER_OFFSET_CONT;
3719 if (offlen != sel->buf_offset) {
3720 vrend_printf( "Got mismatched shader continuation %d vs %d\n",
3721 offlen, sel->buf_offset);
3722 ret = EINVAL;
3723 goto error;
3724 }
3725
3726 /*make sure no overflow */
3727 if (pkt_length * 4 < pkt_length ||
3728 pkt_length * 4 + sel->buf_offset < pkt_length * 4 ||
3729 pkt_length * 4 + sel->buf_offset < sel->buf_offset) {
3730 ret = EINVAL;
3731 goto error;
3732 }
3733
3734 if ((pkt_length * 4 + sel->buf_offset) > sel->buf_len) {
3735 vrend_printf( "Got too large shader continuation %d vs %d\n",
3736 pkt_length * 4 + sel->buf_offset, sel->buf_len);
3737 ret = EINVAL;
3738 goto error;
3739 }
3740
3741 memcpy(sel->tmp_buf + sel->buf_offset, shd_text, pkt_length * 4);
3742
3743 sel->buf_offset += pkt_length * 4;
3744 if (sel->buf_offset >= sel->buf_len) {
3745 finished = true;
3746 shd_text = sel->tmp_buf;
3747 }
3748 }
3749
3750 if (finished) {
3751 struct tgsi_token *tokens;
3752
3753 /* check for null termination */
3754 uint32_t last_chunk_offset = sel->buf_offset ? sel->buf_offset : pkt_length * 4;
3755 if (last_chunk_offset < 4 || !memchr(shd_text + last_chunk_offset - 4, '\0', 4)) {
3756 ret = EINVAL;
3757 goto error;
3758 }
3759
3760 tokens = calloc(num_tokens + 10, sizeof(struct tgsi_token));
3761 if (!tokens) {
3762 ret = ENOMEM;
3763 goto error;
3764 }
3765
3766 if (!tgsi_text_translate((const char *)shd_text, tokens, num_tokens + 10)) {
3767 free(tokens);
3768 ret = EINVAL;
3769 goto error;
3770 }
3771
3772 if (vrend_finish_shader(ctx, sel, tokens)) {
3773 free(tokens);
3774 ret = EINVAL;
3775 goto error;
3776 } else {
3777 if (!vrend_debug(ctx, dbg_shader_tgsi)) {
3778 free(sel->tmp_buf);
3779 sel->tmp_buf = NULL;
3780 }
3781 }
3782 free(tokens);
3783 sub_ctx->long_shader_in_progress_handle[type] = 0;
3784 }
3785
3786 if (new_shader) {
3787 ret_handle = vrend_renderer_object_insert(ctx, sel, handle, VIRGL_OBJECT_SHADER);
3788 if (ret_handle == 0) {
3789 ret = ENOMEM;
3790 goto error;
3791 }
3792 }
3793
3794 return 0;
3795
3796 error:
3797 if (new_shader)
3798 vrend_destroy_shader_selector(sel);
3799 else
3800 vrend_renderer_object_destroy(ctx, handle);
3801
3802 return ret;
3803 }
3804
vrend_bind_shader(struct vrend_context * ctx,uint32_t handle,uint32_t type)3805 void vrend_bind_shader(struct vrend_context *ctx,
3806 uint32_t handle, uint32_t type)
3807 {
3808 struct vrend_shader_selector *sel;
3809
3810 if (type > PIPE_SHADER_COMPUTE)
3811 return;
3812
3813 struct vrend_sub_context *sub_ctx = ctx->sub;
3814
3815 if (handle == 0) {
3816 if (type == PIPE_SHADER_COMPUTE)
3817 sub_ctx->cs_shader_dirty = true;
3818 else
3819 sub_ctx->shader_dirty = true;
3820 vrend_shader_state_reference(&sub_ctx->shaders[type], NULL);
3821 return;
3822 }
3823
3824 sel = vrend_object_lookup(sub_ctx->object_hash, handle, VIRGL_OBJECT_SHADER);
3825 if (!sel)
3826 return;
3827
3828 if (sel->type != type)
3829 return;
3830
3831 if (sub_ctx->shaders[sel->type] != sel) {
3832 if (type == PIPE_SHADER_COMPUTE)
3833 sub_ctx->cs_shader_dirty = true;
3834 else
3835 sub_ctx->shader_dirty = true;
3836 sub_ctx->prog_ids[sel->type] = 0;
3837 }
3838
3839 vrend_shader_state_reference(&sub_ctx->shaders[sel->type], sel);
3840 }
3841
3842 static float
vrend_color_convert_linear_to_srgb(float color)3843 vrend_color_convert_linear_to_srgb(float color) {
3844 return color <= 0.0031308f
3845 ? 12.92f * color
3846 : 1.055f * powf(color, (1.f / 2.4f)) - 0.055f;
3847 }
3848
vrend_clear(struct vrend_context * ctx,unsigned buffers,const union pipe_color_union * color,double depth,unsigned stencil)3849 void vrend_clear(struct vrend_context *ctx,
3850 unsigned buffers,
3851 const union pipe_color_union *color,
3852 double depth, unsigned stencil)
3853 {
3854 GLbitfield bits = 0;
3855 struct vrend_sub_context *sub_ctx = ctx->sub;
3856
3857 if (ctx->in_error)
3858 return;
3859
3860 if (ctx->ctx_switch_pending)
3861 vrend_finish_context_switch(ctx);
3862
3863 vrend_update_frontface_state(sub_ctx);
3864 if (sub_ctx->stencil_state_dirty)
3865 vrend_update_stencil_state(sub_ctx);
3866 if (sub_ctx->scissor_state_dirty)
3867 vrend_update_scissor_state(sub_ctx);
3868 if (sub_ctx->viewport_state_dirty)
3869 vrend_update_viewport_state(sub_ctx);
3870
3871 vrend_use_program(sub_ctx, 0);
3872
3873 glDisable(GL_SCISSOR_TEST);
3874
3875 float colorf[4];
3876 memcpy(colorf, color->f, sizeof(colorf));
3877
3878 if (sub_ctx->nr_cbufs && sub_ctx->surf[0] &&
3879 vrend_resource_has_24bpp_internal_format(sub_ctx->surf[0]->texture) &&
3880 util_format_is_srgb(sub_ctx->surf[0]->format)) {
3881 VREND_DEBUG(dbg_tex, ctx,
3882 "manually converting glClearColor from linear->srgb colorspace for EGL-backed framebuffer color attachment"
3883 " (surface format is %s; resource format is %s)\n",
3884 util_format_name(sub_ctx->surf[0]->format),
3885 util_format_name(sub_ctx->surf[0]->texture->base.format));
3886 for (int i = 0; i < 3; ++i) // i < 3: don't convert alpha channel
3887 colorf[i] = vrend_color_convert_linear_to_srgb(colorf[i]);
3888 }
3889
3890 if (buffers & PIPE_CLEAR_COLOR) {
3891 if (sub_ctx->nr_cbufs && sub_ctx->surf[0] && vrend_format_is_emulated_alpha(sub_ctx->surf[0]->format)) {
3892 glClearColor(colorf[3], 0.0, 0.0, 0.0);
3893 } else if (sub_ctx->nr_cbufs && sub_ctx->surf[0] && vrend_resource_is_emulated_bgra(sub_ctx->surf[0]->texture)) {
3894 VREND_DEBUG(dbg_bgra, ctx, "swizzling glClearColor() since rendering surface is an externally-stored BGR* resource\n");
3895 glClearColor(colorf[2], colorf[1], colorf[0], colorf[3]);
3896 } else {
3897 glClearColor(colorf[0], colorf[1], colorf[2], colorf[3]);
3898 }
3899
3900 /* This function implements Gallium's full clear callback (st->pipe->clear) on the host. This
3901 callback requires no color component be masked. We must unmask all components before
3902 calling glClear* and restore the previous colormask afterwards, as Gallium expects. */
3903 if (sub_ctx->hw_blend_state.independent_blend_enable &&
3904 has_feature(feat_indep_blend)) {
3905 int i;
3906 for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++)
3907 glColorMaskIndexedEXT(i, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
3908 } else
3909 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
3910 }
3911
3912 if (buffers & PIPE_CLEAR_DEPTH) {
3913 /* gallium clears don't respect depth mask */
3914 glDepthMask(GL_TRUE);
3915 if (vrend_state.use_gles) {
3916 if (0.0f < depth && depth > 1.0f) {
3917 // Only warn, it is clamped by the function.
3918 report_gles_warn(ctx, GLES_WARN_DEPTH_CLEAR);
3919 }
3920 glClearDepthf(depth);
3921 } else {
3922 glClearDepth(depth);
3923 }
3924 }
3925
3926 if (buffers & PIPE_CLEAR_STENCIL) {
3927 glStencilMask(~0u);
3928 glClearStencil(stencil);
3929 }
3930
3931 if (sub_ctx->hw_rs_state.rasterizer_discard)
3932 glDisable(GL_RASTERIZER_DISCARD);
3933
3934 if (buffers & PIPE_CLEAR_COLOR) {
3935 uint32_t mask = 0;
3936 int i;
3937 for (i = 0; i < sub_ctx->nr_cbufs; i++) {
3938 if (sub_ctx->surf[i])
3939 mask |= (1 << i);
3940 }
3941 if (mask != (buffers >> 2)) {
3942 mask = buffers >> 2;
3943 while (mask) {
3944 i = u_bit_scan(&mask);
3945 if (i < PIPE_MAX_COLOR_BUFS && sub_ctx->surf[i] && util_format_is_pure_uint(sub_ctx->surf[i] && sub_ctx->surf[i]->format))
3946 glClearBufferuiv(GL_COLOR,
3947 i, (GLuint *)colorf);
3948 else if (i < PIPE_MAX_COLOR_BUFS && sub_ctx->surf[i] && util_format_is_pure_sint(sub_ctx->surf[i] && sub_ctx->surf[i]->format))
3949 glClearBufferiv(GL_COLOR,
3950 i, (GLint *)colorf);
3951 else
3952 glClearBufferfv(GL_COLOR,
3953 i, (GLfloat *)colorf);
3954 }
3955 }
3956 else
3957 bits |= GL_COLOR_BUFFER_BIT;
3958 }
3959 if (buffers & PIPE_CLEAR_DEPTH)
3960 bits |= GL_DEPTH_BUFFER_BIT;
3961 if (buffers & PIPE_CLEAR_STENCIL)
3962 bits |= GL_STENCIL_BUFFER_BIT;
3963
3964 if (bits)
3965 glClear(bits);
3966
3967 /* Is it really necessary to restore the old states? The only reason we
3968 * get here is because the guest cleared all those states but gallium
3969 * didn't forward them before calling the clear command
3970 */
3971 if (sub_ctx->hw_rs_state.rasterizer_discard)
3972 glEnable(GL_RASTERIZER_DISCARD);
3973
3974 if (buffers & PIPE_CLEAR_DEPTH) {
3975 if (!sub_ctx->dsa_state.depth.writemask)
3976 glDepthMask(GL_FALSE);
3977 }
3978
3979 /* Restore previous stencil buffer write masks for both front and back faces */
3980 if (buffers & PIPE_CLEAR_STENCIL) {
3981 glStencilMaskSeparate(GL_FRONT, sub_ctx->dsa_state.stencil[0].writemask);
3982 glStencilMaskSeparate(GL_BACK, sub_ctx->dsa_state.stencil[1].writemask);
3983 }
3984
3985 /* Restore previous colormask */
3986 if (buffers & PIPE_CLEAR_COLOR) {
3987 if (sub_ctx->hw_blend_state.independent_blend_enable &&
3988 has_feature(feat_indep_blend)) {
3989 int i;
3990 for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
3991 struct pipe_blend_state *blend = &sub_ctx->hw_blend_state;
3992 glColorMaskIndexedEXT(i, blend->rt[i].colormask & PIPE_MASK_R ? GL_TRUE : GL_FALSE,
3993 blend->rt[i].colormask & PIPE_MASK_G ? GL_TRUE : GL_FALSE,
3994 blend->rt[i].colormask & PIPE_MASK_B ? GL_TRUE : GL_FALSE,
3995 blend->rt[i].colormask & PIPE_MASK_A ? GL_TRUE : GL_FALSE);
3996 }
3997 } else {
3998 glColorMask(sub_ctx->hw_blend_state.rt[0].colormask & PIPE_MASK_R ? GL_TRUE : GL_FALSE,
3999 sub_ctx->hw_blend_state.rt[0].colormask & PIPE_MASK_G ? GL_TRUE : GL_FALSE,
4000 sub_ctx->hw_blend_state.rt[0].colormask & PIPE_MASK_B ? GL_TRUE : GL_FALSE,
4001 sub_ctx->hw_blend_state.rt[0].colormask & PIPE_MASK_A ? GL_TRUE : GL_FALSE);
4002 }
4003 }
4004 if (sub_ctx->hw_rs_state.scissor)
4005 glEnable(GL_SCISSOR_TEST);
4006 else
4007 glDisable(GL_SCISSOR_TEST);
4008 }
4009
vrend_clear_texture(struct vrend_context * ctx,uint32_t handle,uint32_t level,const struct pipe_box * box,const void * data)4010 void vrend_clear_texture(struct vrend_context* ctx,
4011 uint32_t handle, uint32_t level,
4012 const struct pipe_box *box,
4013 const void * data)
4014 {
4015 GLenum format, type;
4016 struct vrend_resource *res;
4017
4018 if (handle)
4019 res = vrend_renderer_ctx_res_lookup(ctx, handle);
4020 else {
4021 vrend_printf( "cannot find resource for handle %d\n", handle);
4022 return;
4023 }
4024
4025 enum virgl_formats fmt = res->base.format;
4026 format = tex_conv_table[fmt].glformat;
4027 type = tex_conv_table[fmt].gltype;
4028
4029 if (vrend_state.use_gles) {
4030 glClearTexSubImageEXT(res->id, level,
4031 box->x, box->y, box->z,
4032 box->width, box->height, box->depth,
4033 format, type, data);
4034 } else {
4035 glClearTexSubImage(res->id, level,
4036 box->x, box->y, box->z,
4037 box->width, box->height, box->depth,
4038 format, type, data);
4039 }
4040 }
4041
vrend_update_scissor_state(struct vrend_sub_context * sub_ctx)4042 static void vrend_update_scissor_state(struct vrend_sub_context *sub_ctx)
4043 {
4044 struct pipe_scissor_state *ss;
4045 GLint y;
4046 GLuint idx;
4047 unsigned mask = sub_ctx->scissor_state_dirty;
4048
4049 while (mask) {
4050 idx = u_bit_scan(&mask);
4051 if (idx >= PIPE_MAX_VIEWPORTS) {
4052 vrend_report_buffer_error(sub_ctx->parent, 0);
4053 break;
4054 }
4055 ss = &sub_ctx->ss[idx];
4056 y = ss->miny;
4057
4058 if (idx > 0 && has_feature(feat_viewport_array))
4059 glScissorIndexed(idx, ss->minx, y, ss->maxx - ss->minx, ss->maxy - ss->miny);
4060 else
4061 glScissor(ss->minx, y, ss->maxx - ss->minx, ss->maxy - ss->miny);
4062 }
4063 sub_ctx->scissor_state_dirty = 0;
4064 }
4065
vrend_update_viewport_state(struct vrend_sub_context * sub_ctx)4066 static void vrend_update_viewport_state(struct vrend_sub_context *sub_ctx)
4067 {
4068 GLint cy;
4069 unsigned mask = sub_ctx->viewport_state_dirty;
4070 int idx;
4071 while (mask) {
4072 idx = u_bit_scan(&mask);
4073
4074 if (sub_ctx->viewport_is_negative)
4075 cy = sub_ctx->vps[idx].cur_y - sub_ctx->vps[idx].height;
4076 else
4077 cy = sub_ctx->vps[idx].cur_y;
4078 if (idx > 0 && has_feature(feat_viewport_array))
4079 glViewportIndexedf(idx, sub_ctx->vps[idx].cur_x, cy, sub_ctx->vps[idx].width, sub_ctx->vps[idx].height);
4080 else
4081 glViewport(sub_ctx->vps[idx].cur_x, cy, sub_ctx->vps[idx].width, sub_ctx->vps[idx].height);
4082
4083 if (idx && has_feature(feat_viewport_array))
4084 if (vrend_state.use_gles) {
4085 glDepthRangeIndexedfOES(idx, sub_ctx->vps[idx].near_val, sub_ctx->vps[idx].far_val);
4086 } else
4087 glDepthRangeIndexed(idx, sub_ctx->vps[idx].near_val, sub_ctx->vps[idx].far_val);
4088 else
4089 if (vrend_state.use_gles)
4090 glDepthRangefOES(sub_ctx->vps[idx].near_val, sub_ctx->vps[idx].far_val);
4091 else
4092 glDepthRange(sub_ctx->vps[idx].near_val, sub_ctx->vps[idx].far_val);
4093 }
4094
4095 sub_ctx->viewport_state_dirty = 0;
4096 }
4097
get_gs_xfb_mode(GLenum mode)4098 static GLenum get_gs_xfb_mode(GLenum mode)
4099 {
4100 switch (mode) {
4101 case GL_POINTS:
4102 return GL_POINTS;
4103 case GL_LINE_STRIP:
4104 return GL_LINES;
4105 case GL_TRIANGLE_STRIP:
4106 return GL_TRIANGLES;
4107 default:
4108 vrend_printf( "illegal gs transform feedback mode %d\n", mode);
4109 return GL_POINTS;
4110 }
4111 }
4112
get_tess_xfb_mode(int mode,bool is_point_mode)4113 static GLenum get_tess_xfb_mode(int mode, bool is_point_mode)
4114 {
4115 if (is_point_mode)
4116 return GL_POINTS;
4117 switch (mode) {
4118 case GL_QUADS:
4119 case GL_TRIANGLES:
4120 return GL_TRIANGLES;
4121 case GL_LINES:
4122 return GL_LINES;
4123 default:
4124 vrend_printf( "illegal gs transform feedback mode %d\n", mode);
4125 return GL_POINTS;
4126 }
4127 }
4128
get_xfb_mode(GLenum mode)4129 static GLenum get_xfb_mode(GLenum mode)
4130 {
4131 switch (mode) {
4132 case GL_POINTS:
4133 return GL_POINTS;
4134 case GL_TRIANGLES:
4135 case GL_TRIANGLE_STRIP:
4136 case GL_TRIANGLE_FAN:
4137 case GL_QUADS:
4138 case GL_QUAD_STRIP:
4139 case GL_POLYGON:
4140 return GL_TRIANGLES;
4141 case GL_LINES:
4142 case GL_LINE_LOOP:
4143 case GL_LINE_STRIP:
4144 return GL_LINES;
4145 default:
4146 vrend_printf( "failed to translate TFB %d\n", mode);
4147 return GL_POINTS;
4148 }
4149 }
4150
vrend_draw_bind_vertex_legacy(struct vrend_context * ctx,struct vrend_vertex_element_array * va)4151 static void vrend_draw_bind_vertex_legacy(struct vrend_context *ctx,
4152 struct vrend_vertex_element_array *va)
4153 {
4154 uint32_t enable_bitmask;
4155 uint32_t disable_bitmask;
4156 int i;
4157
4158 enable_bitmask = 0;
4159 disable_bitmask = ~((1ull << va->count) - 1);
4160 for (i = 0; i < (int)va->count; i++) {
4161 struct vrend_vertex_element *ve = &va->elements[i];
4162 int vbo_index = ve->base.vertex_buffer_index;
4163 struct vrend_resource *res;
4164 GLint loc;
4165
4166 if (i >= ctx->sub->prog->ss[PIPE_SHADER_VERTEX]->sel->sinfo.num_inputs) {
4167 /* XYZZY: debug this? */
4168 break;
4169 }
4170 res = (struct vrend_resource *)ctx->sub->vbo[vbo_index].base.buffer;
4171
4172 if (!res) {
4173 vrend_printf("cannot find vbo buf %d %d %d\n", i, va->count, ctx->sub->prog->ss[PIPE_SHADER_VERTEX]->sel->sinfo.num_inputs);
4174 continue;
4175 }
4176
4177 if (vrend_state.use_explicit_locations || has_feature(feat_gles31_vertex_attrib_binding)) {
4178 loc = i;
4179 } else {
4180 if (ctx->sub->prog->attrib_locs) {
4181 loc = ctx->sub->prog->attrib_locs[i];
4182 } else loc = -1;
4183
4184 if (loc == -1) {
4185 vrend_printf("%s: cannot find loc %d %d %d\n", ctx->debug_name, i, va->count, ctx->sub->prog->ss[PIPE_SHADER_VERTEX]->sel->sinfo.num_inputs);
4186 if (i == 0) {
4187 vrend_printf("%s: shader probably didn't compile - skipping rendering\n", ctx->debug_name);
4188 return;
4189 }
4190 continue;
4191 }
4192 }
4193
4194 if (ve->type == GL_FALSE) {
4195 vrend_printf("failed to translate vertex type - skipping render\n");
4196 return;
4197 }
4198
4199 glBindBuffer(GL_ARRAY_BUFFER, res->id);
4200
4201 struct vrend_vertex_buffer *vbo = &ctx->sub->vbo[vbo_index];
4202
4203 if (vbo->base.stride == 0) {
4204 void *data;
4205 /* for 0 stride we are kinda screwed */
4206 data = glMapBufferRange(GL_ARRAY_BUFFER, vbo->base.buffer_offset, ve->nr_chan * sizeof(GLfloat), GL_MAP_READ_BIT);
4207
4208 switch (ve->nr_chan) {
4209 case 1:
4210 glVertexAttrib1fv(loc, data);
4211 break;
4212 case 2:
4213 glVertexAttrib2fv(loc, data);
4214 break;
4215 case 3:
4216 glVertexAttrib3fv(loc, data);
4217 break;
4218 case 4:
4219 default:
4220 glVertexAttrib4fv(loc, data);
4221 break;
4222 }
4223 glUnmapBuffer(GL_ARRAY_BUFFER);
4224 disable_bitmask |= (1 << loc);
4225 } else {
4226 enable_bitmask |= (1 << loc);
4227 if (util_format_is_pure_integer(ve->base.src_format)) {
4228 glVertexAttribIPointer(loc, ve->nr_chan, ve->type, vbo->base.stride, (void *)(unsigned long)(ve->base.src_offset + vbo->base.buffer_offset));
4229 } else {
4230 glVertexAttribPointer(loc, ve->nr_chan, ve->type, ve->norm, vbo->base.stride, (void *)(unsigned long)(ve->base.src_offset + vbo->base.buffer_offset));
4231 }
4232 glVertexAttribDivisorARB(loc, ve->base.instance_divisor);
4233 }
4234 }
4235 if (ctx->sub->enabled_attribs_bitmask != enable_bitmask) {
4236 uint32_t mask = ctx->sub->enabled_attribs_bitmask & disable_bitmask;
4237
4238 while (mask) {
4239 i = u_bit_scan(&mask);
4240 glDisableVertexAttribArray(i);
4241 }
4242 ctx->sub->enabled_attribs_bitmask &= ~disable_bitmask;
4243
4244 mask = ctx->sub->enabled_attribs_bitmask ^ enable_bitmask;
4245 while (mask) {
4246 i = u_bit_scan(&mask);
4247 glEnableVertexAttribArray(i);
4248 }
4249
4250 ctx->sub->enabled_attribs_bitmask = enable_bitmask;
4251 }
4252 }
4253
vrend_draw_bind_vertex_binding(struct vrend_context * ctx,struct vrend_vertex_element_array * va)4254 static void vrend_draw_bind_vertex_binding(struct vrend_context *ctx,
4255 struct vrend_vertex_element_array *va)
4256 {
4257 int i;
4258
4259 glBindVertexArray(va->id);
4260
4261 if (ctx->sub->vbo_dirty) {
4262 struct vrend_vertex_buffer *vbo = &ctx->sub->vbo[0];
4263
4264 if (has_feature(feat_bind_vertex_buffers)) {
4265 GLsizei count = MAX2(ctx->sub->num_vbos, ctx->sub->old_num_vbos);
4266
4267 GLuint buffers[PIPE_MAX_ATTRIBS];
4268 GLintptr offsets[PIPE_MAX_ATTRIBS];
4269 GLsizei strides[PIPE_MAX_ATTRIBS];
4270
4271 for (i = 0; i < ctx->sub->num_vbos; i++) {
4272 struct vrend_resource *res = (struct vrend_resource *)vbo[i].base.buffer;
4273 if (res) {
4274 buffers[i] = res->id;
4275 offsets[i] = vbo[i].base.buffer_offset;
4276 strides[i] = vbo[i].base.stride;
4277 } else {
4278 buffers[i] = 0;
4279 offsets[i] = 0;
4280 strides[i] = 0;
4281 }
4282 }
4283
4284 for (i = ctx->sub->num_vbos; i < ctx->sub->old_num_vbos; i++) {
4285 buffers[i] = 0;
4286 offsets[i] = 0;
4287 strides[i] = 0;
4288 }
4289
4290 glBindVertexBuffers(0, count, buffers, offsets, strides);
4291 } else {
4292 for (i = 0; i < ctx->sub->num_vbos; i++) {
4293 struct vrend_resource *res = (struct vrend_resource *)vbo[i].base.buffer;
4294 if (res)
4295 glBindVertexBuffer(i, res->id, vbo[i].base.buffer_offset, vbo[i].base.stride);
4296 else
4297 glBindVertexBuffer(i, 0, 0, 0);
4298 }
4299 for (i = ctx->sub->num_vbos; i < ctx->sub->old_num_vbos; i++)
4300 glBindVertexBuffer(i, 0, 0, 0);
4301 }
4302
4303 ctx->sub->vbo_dirty = false;
4304 }
4305 }
4306
vrend_draw_bind_samplers_shader(struct vrend_sub_context * sub_ctx,int shader_type,int next_sampler_id)4307 static int vrend_draw_bind_samplers_shader(struct vrend_sub_context *sub_ctx,
4308 int shader_type,
4309 int next_sampler_id)
4310 {
4311 int sampler_index = 0;
4312 int n_samplers = 0;
4313 uint32_t dirty = sub_ctx->sampler_views_dirty[shader_type];
4314 uint32_t mask = sub_ctx->prog->samplers_used_mask[shader_type];
4315 struct vrend_shader_view *sviews = &sub_ctx->views[shader_type];
4316
4317 while (mask) {
4318 int i = u_bit_scan(&mask);
4319
4320 struct vrend_sampler_view *tview = sviews->views[i];
4321 if ((dirty & (1 << i)) && tview) {
4322 if (sub_ctx->prog->shadow_samp_mask[shader_type] & (1 << i)) {
4323 glUniform4f(sub_ctx->prog->shadow_samp_mask_locs[shader_type][sampler_index],
4324 (tview->gl_swizzle[0] == GL_ZERO || tview->gl_swizzle[0] == GL_ONE) ? 0.0 : 1.0,
4325 (tview->gl_swizzle[1] == GL_ZERO || tview->gl_swizzle[1] == GL_ONE) ? 0.0 : 1.0,
4326 (tview->gl_swizzle[2] == GL_ZERO || tview->gl_swizzle[2] == GL_ONE) ? 0.0 : 1.0,
4327 (tview->gl_swizzle[3] == GL_ZERO || tview->gl_swizzle[3] == GL_ONE) ? 0.0 : 1.0);
4328 glUniform4f(sub_ctx->prog->shadow_samp_add_locs[shader_type][sampler_index],
4329 tview->gl_swizzle[0] == GL_ONE ? 1.0 : 0.0,
4330 tview->gl_swizzle[1] == GL_ONE ? 1.0 : 0.0,
4331 tview->gl_swizzle[2] == GL_ONE ? 1.0 : 0.0,
4332 tview->gl_swizzle[3] == GL_ONE ? 1.0 : 0.0);
4333 }
4334
4335 if (tview->texture) {
4336 GLuint id = tview->id;
4337 struct vrend_resource *texture = tview->texture;
4338 GLenum target = tview->target;
4339
4340 debug_texture(__func__, tview->texture);
4341
4342 if (has_bit(tview->texture->storage_bits, VREND_STORAGE_GL_BUFFER)) {
4343 id = texture->tbo_tex_id;
4344 target = GL_TEXTURE_BUFFER;
4345 }
4346
4347 glActiveTexture(GL_TEXTURE0 + next_sampler_id);
4348 glBindTexture(target, id);
4349
4350 if (vrend_state.use_gles) {
4351 const unsigned levels = tview->levels ? tview->levels : tview->texture->base.last_level + 1u;
4352 sub_ctx->texture_levels[shader_type][n_samplers++] = levels;
4353 }
4354
4355 if (sub_ctx->views[shader_type].old_ids[i] != id ||
4356 sub_ctx->sampler_views_dirty[shader_type] & (1 << i)) {
4357 vrend_apply_sampler_state(sub_ctx, texture, shader_type, i,
4358 next_sampler_id, tview);
4359 sviews->old_ids[i] = id;
4360 }
4361 dirty &= ~(1 << i);
4362 }
4363 }
4364 sampler_index++;
4365 next_sampler_id++;
4366 }
4367
4368 sub_ctx->n_samplers[shader_type] = n_samplers;
4369 sub_ctx->sampler_views_dirty[shader_type] = dirty;
4370
4371 return next_sampler_id;
4372 }
4373
vrend_draw_bind_ubo_shader(struct vrend_sub_context * sub_ctx,int shader_type,int next_ubo_id)4374 static int vrend_draw_bind_ubo_shader(struct vrend_sub_context *sub_ctx,
4375 int shader_type, int next_ubo_id)
4376 {
4377 uint32_t mask, dirty, update;
4378 struct pipe_constant_buffer *cb;
4379 struct vrend_resource *res;
4380
4381 if (!has_feature(feat_ubo))
4382 return next_ubo_id;
4383
4384 mask = sub_ctx->prog->ubo_used_mask[shader_type];
4385 dirty = sub_ctx->const_bufs_dirty[shader_type];
4386 update = dirty & sub_ctx->const_bufs_used_mask[shader_type];
4387
4388 if (!update)
4389 return next_ubo_id + util_bitcount(mask);
4390
4391 while (mask) {
4392 /* The const_bufs_used_mask stores the gallium uniform buffer indices */
4393 int i = u_bit_scan(&mask);
4394
4395 if (update & (1 << i)) {
4396 /* The cbs array is indexed using the gallium uniform buffer index */
4397 cb = &sub_ctx->cbs[shader_type][i];
4398 res = (struct vrend_resource *)cb->buffer;
4399
4400 glBindBufferRange(GL_UNIFORM_BUFFER, next_ubo_id, res->id,
4401 cb->buffer_offset, cb->buffer_size);
4402 dirty &= ~(1 << i);
4403 }
4404 next_ubo_id++;
4405 }
4406 sub_ctx->const_bufs_dirty[shader_type] = dirty;
4407
4408 return next_ubo_id;
4409 }
4410
vrend_draw_bind_const_shader(struct vrend_sub_context * sub_ctx,int shader_type,bool new_program)4411 static void vrend_draw_bind_const_shader(struct vrend_sub_context *sub_ctx,
4412 int shader_type, bool new_program)
4413 {
4414 if (sub_ctx->consts[shader_type].consts &&
4415 sub_ctx->shaders[shader_type] &&
4416 (sub_ctx->prog->const_location[shader_type] != -1) &&
4417 (sub_ctx->const_dirty[shader_type] || new_program)) {
4418 glUniform4uiv(sub_ctx->prog->const_location[shader_type],
4419 sub_ctx->shaders[shader_type]->sinfo.num_consts,
4420 sub_ctx->consts[shader_type].consts);
4421 sub_ctx->const_dirty[shader_type] = false;
4422 }
4423 }
4424
vrend_draw_bind_ssbo_shader(struct vrend_sub_context * sub_ctx,int shader_type)4425 static void vrend_draw_bind_ssbo_shader(struct vrend_sub_context *sub_ctx,
4426 int shader_type)
4427 {
4428 uint32_t mask;
4429 struct vrend_ssbo *ssbo;
4430 struct vrend_resource *res;
4431 int i;
4432
4433 if (!has_feature(feat_ssbo))
4434 return;
4435
4436 if (!sub_ctx->prog->ssbo_used_mask[shader_type])
4437 return;
4438
4439 if (!sub_ctx->ssbo_used_mask[shader_type])
4440 return;
4441
4442 mask = sub_ctx->ssbo_used_mask[shader_type];
4443 while (mask) {
4444 i = u_bit_scan(&mask);
4445
4446 ssbo = &sub_ctx->ssbo[shader_type][i];
4447 res = (struct vrend_resource *)ssbo->res;
4448 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, i, res->id,
4449 ssbo->buffer_offset, ssbo->buffer_size);
4450 }
4451 }
4452
vrend_draw_bind_abo_shader(struct vrend_sub_context * sub_ctx)4453 static void vrend_draw_bind_abo_shader(struct vrend_sub_context *sub_ctx)
4454 {
4455 uint32_t mask;
4456 struct vrend_abo *abo;
4457 struct vrend_resource *res;
4458 int i;
4459
4460 if (!has_feature(feat_atomic_counters))
4461 return;
4462
4463 mask = sub_ctx->abo_used_mask;
4464 while (mask) {
4465 i = u_bit_scan(&mask);
4466
4467 abo = &sub_ctx->abo[i];
4468 res = (struct vrend_resource *)abo->res;
4469 glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, i, res->id,
4470 abo->buffer_offset, abo->buffer_size);
4471 }
4472 }
4473
vrend_draw_bind_images_shader(struct vrend_sub_context * sub_ctx,int shader_type)4474 static void vrend_draw_bind_images_shader(struct vrend_sub_context *sub_ctx, int shader_type)
4475 {
4476 GLenum access;
4477 GLboolean layered;
4478 struct vrend_image_view *iview;
4479 uint32_t mask, tex_id, level, first_layer;
4480
4481
4482 if (!sub_ctx->images_used_mask[shader_type])
4483 return;
4484
4485 if (!sub_ctx->prog->img_locs[shader_type])
4486 return;
4487
4488 if (!has_feature(feat_images))
4489 return;
4490
4491 mask = sub_ctx->images_used_mask[shader_type];
4492 while (mask) {
4493 unsigned i = u_bit_scan(&mask);
4494
4495 if (!(sub_ctx->prog->images_used_mask[shader_type] & (1 << i)))
4496 continue;
4497 iview = &sub_ctx->image_views[shader_type][i];
4498 tex_id = iview->texture->id;
4499 if (has_bit(iview->texture->storage_bits, VREND_STORAGE_GL_BUFFER)) {
4500 if (!iview->texture->tbo_tex_id)
4501 glGenTextures(1, &iview->texture->tbo_tex_id);
4502
4503 /* glTexBuffer doesn't accept GL_RGBA8_SNORM, find an appropriate replacement. */
4504 uint32_t format = (iview->format == GL_RGBA8_SNORM) ? GL_RGBA8UI : iview->format;
4505
4506 glBindBufferARB(GL_TEXTURE_BUFFER, iview->texture->id);
4507 glBindTexture(GL_TEXTURE_BUFFER, iview->texture->tbo_tex_id);
4508
4509 if (has_feature(feat_arb_or_gles_ext_texture_buffer))
4510 glTexBuffer(GL_TEXTURE_BUFFER, format, iview->texture->id);
4511
4512 tex_id = iview->texture->tbo_tex_id;
4513 level = first_layer = 0;
4514 layered = GL_TRUE;
4515 } else {
4516 level = iview->u.tex.level;
4517 first_layer = iview->u.tex.first_layer;
4518 layered = !((iview->texture->base.array_size > 1 ||
4519 iview->texture->base.depth0 > 1) && (iview->u.tex.first_layer == iview->u.tex.last_layer));
4520 }
4521
4522 if (!vrend_state.use_gles)
4523 glUniform1i(sub_ctx->prog->img_locs[shader_type][i], i);
4524
4525 switch (iview->access) {
4526 case PIPE_IMAGE_ACCESS_READ:
4527 access = GL_READ_ONLY;
4528 break;
4529 case PIPE_IMAGE_ACCESS_WRITE:
4530 access = GL_WRITE_ONLY;
4531 break;
4532 case PIPE_IMAGE_ACCESS_READ_WRITE:
4533 access = GL_READ_WRITE;
4534 break;
4535 default:
4536 vrend_printf( "Invalid access specified\n");
4537 return;
4538 }
4539
4540 glBindImageTexture(i, tex_id, level, layered, first_layer, access, iview->format);
4541 }
4542 }
4543
vrend_draw_bind_objects(struct vrend_sub_context * sub_ctx,bool new_program)4544 static void vrend_draw_bind_objects(struct vrend_sub_context *sub_ctx, bool new_program)
4545 {
4546 int next_ubo_id = 0, next_sampler_id = 0;
4547 for (int shader_type = PIPE_SHADER_VERTEX; shader_type <= sub_ctx->last_shader_idx; shader_type++) {
4548 next_ubo_id = vrend_draw_bind_ubo_shader(sub_ctx, shader_type, next_ubo_id);
4549 vrend_draw_bind_const_shader(sub_ctx, shader_type, new_program);
4550 next_sampler_id = vrend_draw_bind_samplers_shader(sub_ctx, shader_type,
4551 next_sampler_id);
4552
4553 vrend_draw_bind_images_shader(sub_ctx, shader_type);
4554 vrend_draw_bind_ssbo_shader(sub_ctx, shader_type);
4555
4556 if (vrend_state.use_gles) {
4557 if (sub_ctx->prog->tex_levels_uniform_id[shader_type] != -1) {
4558 glUniform1iv(sub_ctx->prog->tex_levels_uniform_id[shader_type],
4559 sub_ctx->n_samplers[shader_type],
4560 sub_ctx->texture_levels[shader_type]);
4561 }
4562 }
4563 }
4564
4565 vrend_draw_bind_abo_shader(sub_ctx);
4566
4567 if (vrend_state.use_core_profile && sub_ctx->prog->fs_stipple_loc != -1) {
4568 glActiveTexture(GL_TEXTURE0 + next_sampler_id);
4569 glBindTexture(GL_TEXTURE_2D, sub_ctx->parent->pstipple_tex_id);
4570 glUniform1i(sub_ctx->prog->fs_stipple_loc, next_sampler_id);
4571 }
4572
4573 if (vrend_state.use_core_profile && sub_ctx->prog->fs_alpha_ref_val_loc != -1) {
4574 glUniform1f(sub_ctx->prog->fs_alpha_ref_val_loc, sub_ctx->dsa_state.alpha.ref_value);
4575 }
4576 }
4577
4578 static
vrend_inject_tcs(struct vrend_sub_context * sub_ctx,int vertices_per_patch)4579 void vrend_inject_tcs(struct vrend_sub_context *sub_ctx, int vertices_per_patch)
4580 {
4581 struct pipe_stream_output_info so_info;
4582
4583 memset(&so_info, 0, sizeof(so_info));
4584 struct vrend_shader_selector *sel = vrend_create_shader_state(&so_info,
4585 false, PIPE_SHADER_TESS_CTRL);
4586 struct vrend_shader *shader;
4587 shader = CALLOC_STRUCT(vrend_shader);
4588 vrend_fill_shader_key(sub_ctx, sel, &shader->key);
4589
4590 shader->sel = sel;
4591 list_inithead(&shader->programs);
4592 strarray_alloc(&shader->glsl_strings, SHADER_MAX_STRINGS);
4593
4594 vrend_shader_create_passthrough_tcs(sub_ctx->parent, &sub_ctx->parent->shader_cfg,
4595 sub_ctx->shaders[PIPE_SHADER_VERTEX]->tokens,
4596 &shader->key, vrend_state.tess_factors, &sel->sinfo,
4597 &shader->glsl_strings, vertices_per_patch);
4598 // Need to add inject the selected shader to the shader selector and then the code below
4599 // can continue
4600 sel->tokens = NULL;
4601 sel->current = shader;
4602 sub_ctx->shaders[PIPE_SHADER_TESS_CTRL] = sel;
4603 sub_ctx->shaders[PIPE_SHADER_TESS_CTRL]->num_shaders = 1;
4604
4605 vrend_compile_shader(sub_ctx, shader);
4606 }
4607
4608
4609 static bool
vrend_select_program(struct vrend_sub_context * sub_ctx,const struct pipe_draw_info * info)4610 vrend_select_program(struct vrend_sub_context *sub_ctx, const struct pipe_draw_info *info)
4611 {
4612 struct vrend_linked_shader_program *prog;
4613 bool fs_dirty, vs_dirty, gs_dirty, tcs_dirty, tes_dirty;
4614 bool dual_src = util_blend_state_is_dual(&sub_ctx->blend_state, 0);
4615 bool new_program = false;
4616
4617 struct vrend_shader_selector **shaders = sub_ctx->shaders;
4618
4619 sub_ctx->shader_dirty = false;
4620
4621 if (!shaders[PIPE_SHADER_VERTEX] || !shaders[PIPE_SHADER_FRAGMENT]) {
4622 vrend_printf("dropping rendering due to missing shaders: %s\n", sub_ctx->parent->debug_name);
4623 return false;
4624 }
4625
4626 // For some GPU, we'd like to use integer variable in generated GLSL if
4627 // the input buffers are integer formats. But we actually don't know the
4628 // buffer formats when the shader is created, we only know it here.
4629 // Set it to true so the underlying code knows to use the buffer formats
4630 // now.
4631 sub_ctx->drawing = true;
4632 vrend_shader_select(sub_ctx, shaders[PIPE_SHADER_VERTEX], &vs_dirty);
4633 sub_ctx->drawing = false;
4634
4635 if (shaders[PIPE_SHADER_TESS_CTRL] && shaders[PIPE_SHADER_TESS_CTRL]->tokens)
4636 vrend_shader_select(sub_ctx, shaders[PIPE_SHADER_TESS_CTRL], &tcs_dirty);
4637 else if (vrend_state.use_gles && shaders[PIPE_SHADER_TESS_EVAL]) {
4638 VREND_DEBUG(dbg_shader, sub_ctx->parent, "Need to inject a TCS\n");
4639 vrend_inject_tcs(sub_ctx, info->vertices_per_patch);
4640
4641 vrend_shader_select(sub_ctx, shaders[PIPE_SHADER_VERTEX], &vs_dirty);
4642 }
4643
4644 if (shaders[PIPE_SHADER_TESS_EVAL])
4645 vrend_shader_select(sub_ctx, shaders[PIPE_SHADER_TESS_EVAL], &tes_dirty);
4646 if (shaders[PIPE_SHADER_GEOMETRY])
4647 vrend_shader_select(sub_ctx, shaders[PIPE_SHADER_GEOMETRY], &gs_dirty);
4648 vrend_shader_select(sub_ctx, shaders[PIPE_SHADER_FRAGMENT], &fs_dirty);
4649
4650 // NOTE: run shader selection again as a workaround to #180 - "duplicated shader compilation"
4651 if (shaders[PIPE_SHADER_GEOMETRY])
4652 vrend_shader_select(sub_ctx, shaders[PIPE_SHADER_GEOMETRY], &gs_dirty);
4653 if (shaders[PIPE_SHADER_TESS_EVAL])
4654 vrend_shader_select(sub_ctx, shaders[PIPE_SHADER_TESS_EVAL], &tes_dirty);
4655 if (shaders[PIPE_SHADER_TESS_CTRL] && shaders[PIPE_SHADER_TESS_CTRL]->tokens)
4656 vrend_shader_select(sub_ctx, shaders[PIPE_SHADER_TESS_CTRL], &tcs_dirty);
4657 else if (vrend_state.use_gles && shaders[PIPE_SHADER_TESS_EVAL]) {
4658 VREND_DEBUG(dbg_shader, sub_ctx->parent, "Need to inject a TCS\n");
4659 vrend_inject_tcs(sub_ctx, info->vertices_per_patch);
4660 }
4661 sub_ctx->drawing = true;
4662 vrend_shader_select(sub_ctx, shaders[PIPE_SHADER_VERTEX], &vs_dirty);
4663 sub_ctx->drawing = false;
4664
4665 uint8_t gles_emulate_query_texture_levels_mask = 0;
4666
4667 for (uint i = 0; i < PIPE_SHADER_TYPES; i++) {
4668 struct vrend_shader_selector *sel = shaders[i];
4669 if (!sel)
4670 continue;
4671
4672 struct vrend_shader *shader = sel->current;
4673 if (shader && !shader->is_compiled) {//shader->sel->type == PIPE_SHADER_FRAGMENT || shader->sel->type == PIPE_SHADER_GEOMETRY) {
4674 if (!vrend_compile_shader(sub_ctx, shader))
4675 return false;
4676 }
4677 if (vrend_state.use_gles && sel->sinfo.gles_use_tex_query_level)
4678 gles_emulate_query_texture_levels_mask |= 1 << i;
4679 }
4680
4681 if (!shaders[PIPE_SHADER_VERTEX]->current ||
4682 !shaders[PIPE_SHADER_FRAGMENT]->current ||
4683 (shaders[PIPE_SHADER_GEOMETRY] && !shaders[PIPE_SHADER_GEOMETRY]->current) ||
4684 (shaders[PIPE_SHADER_TESS_CTRL] && !shaders[PIPE_SHADER_TESS_CTRL]->current) ||
4685 (shaders[PIPE_SHADER_TESS_EVAL] && !shaders[PIPE_SHADER_TESS_EVAL]->current)) {
4686 vrend_printf( "failure to compile shader variants: %s\n", sub_ctx->parent->debug_name);
4687 return false;
4688 }
4689
4690 GLuint vs_id = shaders[PIPE_SHADER_VERTEX]->current->id;
4691 GLuint fs_id = shaders[PIPE_SHADER_FRAGMENT]->current->id;
4692 GLuint gs_id = shaders[PIPE_SHADER_GEOMETRY] ? shaders[PIPE_SHADER_GEOMETRY]->current->id : 0;
4693 GLuint tcs_id = shaders[PIPE_SHADER_TESS_CTRL] ? shaders[PIPE_SHADER_TESS_CTRL]->current->id : 0;
4694 GLuint tes_id = shaders[PIPE_SHADER_TESS_EVAL] ? shaders[PIPE_SHADER_TESS_EVAL]->current->id : 0;
4695
4696 bool same_prog = sub_ctx->prog &&
4697 vs_id == sub_ctx->prog_ids[PIPE_SHADER_VERTEX] &&
4698 fs_id == sub_ctx->prog_ids[PIPE_SHADER_FRAGMENT] &&
4699 gs_id == sub_ctx->prog_ids[PIPE_SHADER_GEOMETRY] &&
4700 tcs_id == sub_ctx->prog_ids[PIPE_SHADER_TESS_CTRL] &&
4701 tes_id == sub_ctx->prog_ids[PIPE_SHADER_TESS_EVAL] &&
4702 sub_ctx->prog->dual_src_linked == dual_src;
4703
4704 if (!same_prog) {
4705 prog = lookup_shader_program(sub_ctx, vs_id, fs_id, gs_id, tcs_id, tes_id, dual_src);
4706 if (!prog) {
4707 prog = add_shader_program(sub_ctx,
4708 sub_ctx->shaders[PIPE_SHADER_VERTEX]->current,
4709 sub_ctx->shaders[PIPE_SHADER_FRAGMENT]->current,
4710 gs_id ? sub_ctx->shaders[PIPE_SHADER_GEOMETRY]->current : NULL,
4711 tcs_id ? sub_ctx->shaders[PIPE_SHADER_TESS_CTRL]->current : NULL,
4712 tes_id ? sub_ctx->shaders[PIPE_SHADER_TESS_EVAL]->current : NULL);
4713 if (!prog)
4714 return false;
4715 prog->gles_use_query_texturelevel_mask = gles_emulate_query_texture_levels_mask;
4716 }
4717
4718 sub_ctx->last_shader_idx = sub_ctx->shaders[PIPE_SHADER_TESS_EVAL] ? PIPE_SHADER_TESS_EVAL : (sub_ctx->shaders[PIPE_SHADER_GEOMETRY] ? PIPE_SHADER_GEOMETRY : PIPE_SHADER_FRAGMENT);
4719 } else
4720 prog = sub_ctx->prog;
4721 if (sub_ctx->prog != prog) {
4722 new_program = true;
4723 sub_ctx->prog_ids[PIPE_SHADER_VERTEX] = vs_id;
4724 sub_ctx->prog_ids[PIPE_SHADER_FRAGMENT] = fs_id;
4725 sub_ctx->prog_ids[PIPE_SHADER_GEOMETRY] = gs_id;
4726 sub_ctx->prog_ids[PIPE_SHADER_TESS_CTRL] = tcs_id;
4727 sub_ctx->prog_ids[PIPE_SHADER_TESS_EVAL] = tes_id;
4728 sub_ctx->prog_ids[PIPE_SHADER_COMPUTE] = 0;
4729 sub_ctx->prog = prog;
4730
4731 /* mark all constbufs and sampler views as dirty */
4732 for (int stage = PIPE_SHADER_VERTEX; stage <= PIPE_SHADER_FRAGMENT; stage++) {
4733 sub_ctx->const_bufs_dirty[stage] = ~0;
4734 sub_ctx->sampler_views_dirty[stage] = ~0;
4735 }
4736
4737 prog->ref_context = sub_ctx;
4738 }
4739 sub_ctx->cs_shader_dirty = true;
4740 return new_program;
4741 }
4742
vrend_draw_vbo(struct vrend_context * ctx,const struct pipe_draw_info * info,uint32_t cso,uint32_t indirect_handle,uint32_t indirect_draw_count_handle)4743 int vrend_draw_vbo(struct vrend_context *ctx,
4744 const struct pipe_draw_info *info,
4745 uint32_t cso, uint32_t indirect_handle,
4746 uint32_t indirect_draw_count_handle)
4747 {
4748 int i;
4749 bool new_program = false;
4750 struct vrend_resource *indirect_res = NULL;
4751 struct vrend_resource *indirect_params_res = NULL;
4752 struct vrend_sub_context *sub_ctx = ctx->sub;
4753
4754 if (ctx->in_error)
4755 return 0;
4756
4757 if (info->instance_count && !has_feature(feat_draw_instance))
4758 return EINVAL;
4759
4760 if (info->start_instance && !has_feature(feat_base_instance))
4761 return EINVAL;
4762
4763 if (info->indirect.draw_count > 1 && !has_feature(feat_multi_draw_indirect))
4764 return EINVAL;
4765
4766 if (indirect_handle) {
4767 if (!has_feature(feat_indirect_draw))
4768 return EINVAL;
4769 indirect_res = vrend_renderer_ctx_res_lookup(ctx, indirect_handle);
4770 if (!indirect_res) {
4771 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, indirect_handle);
4772 return 0;
4773 }
4774 }
4775
4776 /* this must be zero until we support the feature */
4777 if (indirect_draw_count_handle) {
4778 if (!has_feature(feat_indirect_params))
4779 return EINVAL;
4780
4781 indirect_params_res = vrend_renderer_ctx_res_lookup(ctx, indirect_draw_count_handle);
4782 if (!indirect_params_res){
4783 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, indirect_draw_count_handle);
4784 return 0;
4785 }
4786 }
4787
4788 if (ctx->ctx_switch_pending)
4789 vrend_finish_context_switch(ctx);
4790
4791 vrend_update_frontface_state(sub_ctx);
4792 if (ctx->sub->stencil_state_dirty)
4793 vrend_update_stencil_state(sub_ctx);
4794 if (ctx->sub->scissor_state_dirty)
4795 vrend_update_scissor_state(sub_ctx);
4796
4797 if (ctx->sub->viewport_state_dirty)
4798 vrend_update_viewport_state(sub_ctx);
4799
4800 if (ctx->sub->blend_state_dirty)
4801 vrend_patch_blend_state(sub_ctx);
4802
4803 // enable primitive-mode-dependent shader variants
4804 if (sub_ctx->prim_mode != (int)info->mode) {
4805 // Only refresh shader program when switching in/out of GL_POINTS primitive mode
4806 if (sub_ctx->prim_mode == PIPE_PRIM_POINTS
4807 || (int)info->mode == PIPE_PRIM_POINTS)
4808 sub_ctx->shader_dirty = true;
4809
4810 sub_ctx->prim_mode = (int)info->mode;
4811 }
4812
4813 if (sub_ctx->shader_dirty || sub_ctx->swizzle_output_rgb_to_bgr ||
4814 sub_ctx->convert_linear_to_srgb_on_write)
4815 new_program = vrend_select_program(sub_ctx, info);
4816
4817 if (!sub_ctx->prog) {
4818 vrend_printf("dropping rendering due to missing shaders: %s\n", ctx->debug_name);
4819 return 0;
4820 }
4821
4822 vrend_use_program(sub_ctx, sub_ctx->prog->id);
4823
4824 if (vrend_state.use_gles) {
4825 /* PIPE_SHADER and TGSI_SHADER have different ordering, so use two
4826 * different prefix arrays */
4827 for (unsigned i = PIPE_SHADER_VERTEX; i < PIPE_SHADER_COMPUTE; ++i) {
4828 if (sub_ctx->prog->gles_use_query_texturelevel_mask & (1 << i)) {
4829 char loc_name[32];
4830 snprintf(loc_name, 32, "%s_texlod[0]", pipe_shader_to_prefix(i));
4831 sub_ctx->prog->tex_levels_uniform_id[i] = glGetUniformLocation(sub_ctx->prog->id, loc_name);
4832 } else {
4833 sub_ctx->prog->tex_levels_uniform_id[i] = -1;
4834 }
4835
4836 }
4837 }
4838
4839 vrend_draw_bind_objects(sub_ctx, new_program);
4840
4841
4842 if (!sub_ctx->ve) {
4843 vrend_printf("illegal VE setup - skipping renderering\n");
4844 return 0;
4845 }
4846 float viewport_neg_val = sub_ctx->viewport_is_negative ? -1.0 : 1.0;
4847 if (sub_ctx->prog->viewport_neg_val != viewport_neg_val) {
4848 glUniform1f(sub_ctx->prog->vs_ws_adjust_loc, viewport_neg_val);
4849 sub_ctx->prog->viewport_neg_val = viewport_neg_val;
4850 }
4851
4852 if (sub_ctx->rs_state.clip_plane_enable) {
4853 for (i = 0 ; i < 8; i++) {
4854 glUniform4fv(sub_ctx->prog->clip_locs[i], 1, (const GLfloat *)&sub_ctx->ucp_state.ucp[i]);
4855 }
4856 }
4857
4858 if (has_feature(feat_gles31_vertex_attrib_binding))
4859 vrend_draw_bind_vertex_binding(ctx, sub_ctx->ve);
4860 else
4861 vrend_draw_bind_vertex_legacy(ctx, sub_ctx->ve);
4862
4863 if (info->indexed) {
4864 struct vrend_resource *res = (struct vrend_resource *)sub_ctx->ib.buffer;
4865 if (!res) {
4866 vrend_printf( "VBO missing indexed array buffer\n");
4867 return 0;
4868 }
4869 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, res->id);
4870 } else
4871 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
4872
4873 if (sub_ctx->current_so) {
4874 if (sub_ctx->current_so->xfb_state == XFB_STATE_STARTED_NEED_BEGIN) {
4875 if (sub_ctx->shaders[PIPE_SHADER_GEOMETRY])
4876 glBeginTransformFeedback(get_gs_xfb_mode(sub_ctx->shaders[PIPE_SHADER_GEOMETRY]->sinfo.gs_out_prim));
4877 else if (sub_ctx->shaders[PIPE_SHADER_TESS_EVAL])
4878 glBeginTransformFeedback(get_tess_xfb_mode(sub_ctx->shaders[PIPE_SHADER_TESS_EVAL]->sinfo.tes_prim,
4879 sub_ctx->shaders[PIPE_SHADER_TESS_EVAL]->sinfo.tes_point_mode));
4880 else
4881 glBeginTransformFeedback(get_xfb_mode(info->mode));
4882 sub_ctx->current_so->xfb_state = XFB_STATE_STARTED;
4883 } else if (sub_ctx->current_so->xfb_state == XFB_STATE_PAUSED) {
4884 glResumeTransformFeedback();
4885 sub_ctx->current_so->xfb_state = XFB_STATE_STARTED;
4886 }
4887 }
4888
4889 if (info->primitive_restart) {
4890 if (vrend_state.use_gles) {
4891 glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
4892 } else if (has_feature(feat_nv_prim_restart)) {
4893 glEnableClientState(GL_PRIMITIVE_RESTART_NV);
4894 glPrimitiveRestartIndexNV(info->restart_index);
4895 } else if (has_feature(feat_gl_prim_restart)) {
4896 glEnable(GL_PRIMITIVE_RESTART);
4897 glPrimitiveRestartIndex(info->restart_index);
4898 }
4899 }
4900
4901 if (has_feature(feat_indirect_draw)) {
4902 GLint buf = indirect_res ? indirect_res->id : 0;
4903 if (sub_ctx->draw_indirect_buffer != buf) {
4904 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buf);
4905 sub_ctx->draw_indirect_buffer = buf;
4906 }
4907
4908 if (has_feature(feat_indirect_params)) {
4909 GLint buf = indirect_params_res ? indirect_params_res->id : 0;
4910 if (sub_ctx->draw_indirect_params_buffer != buf) {
4911 glBindBuffer(GL_PARAMETER_BUFFER_ARB, buf);
4912 sub_ctx->draw_indirect_params_buffer = buf;
4913 }
4914 }
4915 }
4916
4917 if (info->vertices_per_patch && has_feature(feat_tessellation))
4918 glPatchParameteri(GL_PATCH_VERTICES, info->vertices_per_patch);
4919
4920 /* If the host support blend_equation_advanced but not fbfetch,
4921 * the guest driver will not lower the equation to fbfetch so we need to set up the renderer to
4922 * accept those blend equations.
4923 * When we transmit the blend mode through alpha_src_factor, alpha_dst_factor is always 0.
4924 */
4925 uint32_t blend_mask_shader = sub_ctx->shaders[PIPE_SHADER_FRAGMENT]->sinfo.fs_blend_equation_advanced;
4926 uint32_t blend_mode = sub_ctx->blend_state.rt[0].alpha_src_factor;
4927 uint32_t alpha_dst_factor = sub_ctx->blend_state.rt[0].alpha_dst_factor;
4928 bool use_advanced_blending = !has_feature(feat_framebuffer_fetch) &&
4929 has_feature(feat_blend_equation_advanced) &&
4930 blend_mask_shader != 0 &&
4931 blend_mode != 0 &&
4932 alpha_dst_factor == 0;
4933 if(use_advanced_blending) {
4934 GLenum blend = translate_blend_func_advanced(blend_mode);
4935 glBlendEquation(blend);
4936 glEnable(GL_BLEND);
4937 }
4938
4939 /* set the vertex state up now on a delay */
4940 if (!info->indexed) {
4941 GLenum mode = info->mode;
4942 int count = cso ? cso : info->count;
4943 int start = cso ? 0 : info->start;
4944
4945 if (indirect_handle) {
4946 if (indirect_params_res)
4947 glMultiDrawArraysIndirectCountARB(mode, (GLvoid const *)(unsigned long)info->indirect.offset,
4948 info->indirect.indirect_draw_count_offset, info->indirect.draw_count, info->indirect.stride);
4949 else if (info->indirect.draw_count > 1)
4950 glMultiDrawArraysIndirect(mode, (GLvoid const *)(unsigned long)info->indirect.offset, info->indirect.draw_count, info->indirect.stride);
4951 else
4952 glDrawArraysIndirect(mode, (GLvoid const *)(unsigned long)info->indirect.offset);
4953 } else if (info->instance_count <= 1)
4954 glDrawArrays(mode, start, count);
4955 else if (info->start_instance)
4956 glDrawArraysInstancedBaseInstance(mode, start, count, info->instance_count, info->start_instance);
4957 else
4958 glDrawArraysInstancedARB(mode, start, count, info->instance_count);
4959 } else {
4960 GLenum elsz;
4961 GLenum mode = info->mode;
4962 switch (sub_ctx->ib.index_size) {
4963 case 1:
4964 elsz = GL_UNSIGNED_BYTE;
4965 break;
4966 case 2:
4967 elsz = GL_UNSIGNED_SHORT;
4968 break;
4969 case 4:
4970 default:
4971 elsz = GL_UNSIGNED_INT;
4972 break;
4973 }
4974
4975 if (indirect_handle) {
4976 if (indirect_params_res)
4977 glMultiDrawElementsIndirectCountARB(mode, elsz, (GLvoid const *)(unsigned long)info->indirect.offset,
4978 info->indirect.indirect_draw_count_offset, info->indirect.draw_count, info->indirect.stride);
4979 else if (info->indirect.draw_count > 1)
4980 glMultiDrawElementsIndirect(mode, elsz, (GLvoid const *)(unsigned long)info->indirect.offset, info->indirect.draw_count, info->indirect.stride);
4981 else
4982 glDrawElementsIndirect(mode, elsz, (GLvoid const *)(unsigned long)info->indirect.offset);
4983 } else if (info->index_bias) {
4984 if (info->instance_count > 1)
4985 glDrawElementsInstancedBaseVertex(mode, info->count, elsz, (void *)(unsigned long)sub_ctx->ib.offset, info->instance_count, info->index_bias);
4986 else if (info->min_index != 0 || info->max_index != (unsigned)-1)
4987 glDrawRangeElementsBaseVertex(mode, info->min_index, info->max_index, info->count, elsz, (void *)(unsigned long)sub_ctx->ib.offset, info->index_bias);
4988 else
4989 glDrawElementsBaseVertex(mode, info->count, elsz, (void *)(unsigned long)sub_ctx->ib.offset, info->index_bias);
4990 } else if (info->instance_count > 1) {
4991 glDrawElementsInstancedARB(mode, info->count, elsz, (void *)(unsigned long)sub_ctx->ib.offset, info->instance_count);
4992 } else if (info->min_index != 0 || info->max_index != (unsigned)-1)
4993 glDrawRangeElements(mode, info->min_index, info->max_index, info->count, elsz, (void *)(unsigned long)sub_ctx->ib.offset);
4994 else
4995 glDrawElements(mode, info->count, elsz, (void *)(unsigned long)sub_ctx->ib.offset);
4996 }
4997
4998 if (info->primitive_restart) {
4999 if (vrend_state.use_gles) {
5000 glDisable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
5001 } else if (has_feature(feat_nv_prim_restart)) {
5002 glDisableClientState(GL_PRIMITIVE_RESTART_NV);
5003 } else if (has_feature(feat_gl_prim_restart)) {
5004 glDisable(GL_PRIMITIVE_RESTART);
5005 }
5006 }
5007
5008 if (sub_ctx->current_so && has_feature(feat_transform_feedback2)) {
5009 if (sub_ctx->current_so->xfb_state == XFB_STATE_STARTED) {
5010 glPauseTransformFeedback();
5011 sub_ctx->current_so->xfb_state = XFB_STATE_PAUSED;
5012 }
5013 }
5014 return 0;
5015 }
5016
vrend_launch_grid(struct vrend_context * ctx,UNUSED uint32_t * block,uint32_t * grid,uint32_t indirect_handle,uint32_t indirect_offset)5017 void vrend_launch_grid(struct vrend_context *ctx,
5018 UNUSED uint32_t *block,
5019 uint32_t *grid,
5020 uint32_t indirect_handle,
5021 uint32_t indirect_offset)
5022 {
5023 bool new_program = false;
5024 struct vrend_resource *indirect_res = NULL;
5025
5026 if (!has_feature(feat_compute_shader))
5027 return;
5028
5029 struct vrend_sub_context *sub_ctx = ctx->sub;
5030
5031 if (sub_ctx->cs_shader_dirty) {
5032 struct vrend_linked_shader_program *prog;
5033 bool cs_dirty;
5034
5035 sub_ctx->cs_shader_dirty = false;
5036
5037 if (!sub_ctx->shaders[PIPE_SHADER_COMPUTE]) {
5038 vrend_printf("dropping rendering due to missing shaders: %s\n", ctx->debug_name);
5039 return;
5040 }
5041
5042 vrend_shader_select(sub_ctx, sub_ctx->shaders[PIPE_SHADER_COMPUTE], &cs_dirty);
5043 if (!sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current) {
5044 vrend_printf( "failure to select compute shader variant: %s\n", ctx->debug_name);
5045 return;
5046 }
5047 if (!sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current->is_compiled) {
5048 if(!vrend_compile_shader(sub_ctx, sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current)) {
5049 vrend_printf( "failure to compile compute shader variant: %s\n", ctx->debug_name);
5050 return;
5051 }
5052 }
5053 if (sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current->id != (GLuint)sub_ctx->prog_ids[PIPE_SHADER_COMPUTE]) {
5054 prog = lookup_cs_shader_program(ctx, sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current->id);
5055 if (!prog) {
5056 prog = add_cs_shader_program(ctx, sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current);
5057 if (!prog)
5058 return;
5059 }
5060 } else
5061 prog = sub_ctx->prog;
5062
5063 if (sub_ctx->prog != prog) {
5064 new_program = true;
5065 sub_ctx->prog_ids[PIPE_SHADER_VERTEX] = 0;
5066 sub_ctx->prog_ids[PIPE_SHADER_COMPUTE] = sub_ctx->shaders[PIPE_SHADER_COMPUTE]->current->id;
5067 sub_ctx->prog = prog;
5068 prog->ref_context = sub_ctx;
5069 }
5070 sub_ctx->shader_dirty = true;
5071 }
5072
5073 if (!sub_ctx->prog) {
5074 vrend_printf("%s: Skipping compute shader execution due to missing shaders: %s\n",
5075 __func__, ctx->debug_name);
5076 return;
5077 }
5078
5079 vrend_use_program(sub_ctx, sub_ctx->prog->id);
5080
5081 vrend_draw_bind_ubo_shader(sub_ctx, PIPE_SHADER_COMPUTE, 0);
5082 vrend_draw_bind_const_shader(sub_ctx, PIPE_SHADER_COMPUTE, new_program);
5083 vrend_draw_bind_samplers_shader(sub_ctx, PIPE_SHADER_COMPUTE, 0);
5084 vrend_draw_bind_images_shader(sub_ctx, PIPE_SHADER_COMPUTE);
5085 vrend_draw_bind_ssbo_shader(sub_ctx, PIPE_SHADER_COMPUTE);
5086 vrend_draw_bind_abo_shader(sub_ctx);
5087
5088 if (indirect_handle) {
5089 indirect_res = vrend_renderer_ctx_res_lookup(ctx, indirect_handle);
5090 if (!indirect_res) {
5091 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, indirect_handle);
5092 return;
5093 }
5094 }
5095
5096 if (indirect_res)
5097 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, indirect_res->id);
5098 else
5099 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0);
5100
5101 if (indirect_res) {
5102 glDispatchComputeIndirect(indirect_offset);
5103 } else {
5104 glDispatchCompute(grid[0], grid[1], grid[2]);
5105 }
5106 }
5107
translate_blend_func(uint32_t pipe_blend)5108 static GLenum translate_blend_func(uint32_t pipe_blend)
5109 {
5110 switch(pipe_blend){
5111 case PIPE_BLEND_ADD: return GL_FUNC_ADD;
5112 case PIPE_BLEND_SUBTRACT: return GL_FUNC_SUBTRACT;
5113 case PIPE_BLEND_REVERSE_SUBTRACT: return GL_FUNC_REVERSE_SUBTRACT;
5114 case PIPE_BLEND_MIN: return GL_MIN;
5115 case PIPE_BLEND_MAX: return GL_MAX;
5116 default:
5117 assert("invalid blend token()" == NULL);
5118 return 0;
5119 }
5120 }
5121
translate_blend_factor(uint32_t pipe_factor)5122 static GLenum translate_blend_factor(uint32_t pipe_factor)
5123 {
5124 switch (pipe_factor) {
5125 case PIPE_BLENDFACTOR_ONE: return GL_ONE;
5126 case PIPE_BLENDFACTOR_SRC_COLOR: return GL_SRC_COLOR;
5127 case PIPE_BLENDFACTOR_SRC_ALPHA: return GL_SRC_ALPHA;
5128
5129 case PIPE_BLENDFACTOR_DST_COLOR: return GL_DST_COLOR;
5130 case PIPE_BLENDFACTOR_DST_ALPHA: return GL_DST_ALPHA;
5131
5132 case PIPE_BLENDFACTOR_CONST_COLOR: return GL_CONSTANT_COLOR;
5133 case PIPE_BLENDFACTOR_CONST_ALPHA: return GL_CONSTANT_ALPHA;
5134
5135 case PIPE_BLENDFACTOR_SRC1_COLOR: return GL_SRC1_COLOR;
5136 case PIPE_BLENDFACTOR_SRC1_ALPHA: return GL_SRC1_ALPHA;
5137 case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: return GL_SRC_ALPHA_SATURATE;
5138 case PIPE_BLENDFACTOR_ZERO: return GL_ZERO;
5139
5140
5141 case PIPE_BLENDFACTOR_INV_SRC_COLOR: return GL_ONE_MINUS_SRC_COLOR;
5142 case PIPE_BLENDFACTOR_INV_SRC_ALPHA: return GL_ONE_MINUS_SRC_ALPHA;
5143
5144 case PIPE_BLENDFACTOR_INV_DST_COLOR: return GL_ONE_MINUS_DST_COLOR;
5145 case PIPE_BLENDFACTOR_INV_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA;
5146
5147 case PIPE_BLENDFACTOR_INV_CONST_COLOR: return GL_ONE_MINUS_CONSTANT_COLOR;
5148 case PIPE_BLENDFACTOR_INV_CONST_ALPHA: return GL_ONE_MINUS_CONSTANT_ALPHA;
5149
5150 case PIPE_BLENDFACTOR_INV_SRC1_COLOR: return GL_ONE_MINUS_SRC1_COLOR;
5151 case PIPE_BLENDFACTOR_INV_SRC1_ALPHA: return GL_ONE_MINUS_SRC1_ALPHA;
5152
5153 default:
5154 assert("invalid blend token()" == NULL);
5155 return 0;
5156 }
5157 }
5158
5159 static GLenum
translate_logicop(GLuint pipe_logicop)5160 translate_logicop(GLuint pipe_logicop)
5161 {
5162 switch (pipe_logicop) {
5163 #define CASE(x) case PIPE_LOGICOP_##x: return GL_##x
5164 CASE(CLEAR);
5165 CASE(NOR);
5166 CASE(AND_INVERTED);
5167 CASE(COPY_INVERTED);
5168 CASE(AND_REVERSE);
5169 CASE(INVERT);
5170 CASE(XOR);
5171 CASE(NAND);
5172 CASE(AND);
5173 CASE(EQUIV);
5174 CASE(NOOP);
5175 CASE(OR_INVERTED);
5176 CASE(COPY);
5177 CASE(OR_REVERSE);
5178 CASE(OR);
5179 CASE(SET);
5180 default:
5181 assert("invalid logicop token()" == NULL);
5182 return 0;
5183 }
5184 #undef CASE
5185 }
5186
5187 static GLenum
translate_stencil_op(GLuint op)5188 translate_stencil_op(GLuint op)
5189 {
5190 switch (op) {
5191 #define CASE(x) case PIPE_STENCIL_OP_##x: return GL_##x
5192 CASE(KEEP);
5193 CASE(ZERO);
5194 CASE(REPLACE);
5195 CASE(INCR);
5196 CASE(DECR);
5197 CASE(INCR_WRAP);
5198 CASE(DECR_WRAP);
5199 CASE(INVERT);
5200 default:
5201 assert("invalid stencilop token()" == NULL);
5202 return 0;
5203 }
5204 #undef CASE
5205 }
5206
is_dst_blend(int blend_factor)5207 static inline bool is_dst_blend(int blend_factor)
5208 {
5209 return (blend_factor == PIPE_BLENDFACTOR_DST_ALPHA ||
5210 blend_factor == PIPE_BLENDFACTOR_INV_DST_ALPHA);
5211 }
5212
conv_a8_blend(int blend_factor)5213 static inline int conv_a8_blend(int blend_factor)
5214 {
5215 if (blend_factor == PIPE_BLENDFACTOR_DST_ALPHA)
5216 return PIPE_BLENDFACTOR_DST_COLOR;
5217 if (blend_factor == PIPE_BLENDFACTOR_INV_DST_ALPHA)
5218 return PIPE_BLENDFACTOR_INV_DST_COLOR;
5219 return blend_factor;
5220 }
5221
conv_dst_blend(int blend_factor)5222 static inline int conv_dst_blend(int blend_factor)
5223 {
5224 if (blend_factor == PIPE_BLENDFACTOR_DST_ALPHA)
5225 return PIPE_BLENDFACTOR_ONE;
5226 if (blend_factor == PIPE_BLENDFACTOR_INV_DST_ALPHA)
5227 return PIPE_BLENDFACTOR_ZERO;
5228 return blend_factor;
5229 }
5230
is_const_blend(int blend_factor)5231 static inline bool is_const_blend(int blend_factor)
5232 {
5233 return (blend_factor == PIPE_BLENDFACTOR_CONST_COLOR ||
5234 blend_factor == PIPE_BLENDFACTOR_CONST_ALPHA ||
5235 blend_factor == PIPE_BLENDFACTOR_INV_CONST_COLOR ||
5236 blend_factor == PIPE_BLENDFACTOR_INV_CONST_ALPHA);
5237 }
5238
vrend_hw_emit_blend(struct vrend_sub_context * sub_ctx,struct pipe_blend_state * state)5239 static void vrend_hw_emit_blend(struct vrend_sub_context *sub_ctx, struct pipe_blend_state *state)
5240 {
5241 if (state->logicop_enable != sub_ctx->hw_blend_state.logicop_enable) {
5242 sub_ctx->hw_blend_state.logicop_enable = state->logicop_enable;
5243 if (vrend_state.use_gles) {
5244 if (can_emulate_logicop(state->logicop_func))
5245 sub_ctx->shader_dirty = true;
5246 else
5247 report_gles_warn(sub_ctx->parent, GLES_WARN_LOGIC_OP);
5248 } else if (state->logicop_enable) {
5249 glEnable(GL_COLOR_LOGIC_OP);
5250 glLogicOp(translate_logicop(state->logicop_func));
5251 } else {
5252 glDisable(GL_COLOR_LOGIC_OP);
5253 }
5254 }
5255
5256 if (state->independent_blend_enable &&
5257 has_feature(feat_indep_blend) &&
5258 has_feature(feat_indep_blend_func)) {
5259 /* ARB_draw_buffers_blend is required for this */
5260 int i;
5261
5262 for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
5263
5264 if (state->rt[i].blend_enable) {
5265 bool dual_src = util_blend_state_is_dual(&sub_ctx->blend_state, i);
5266 if (dual_src && !has_feature(feat_dual_src_blend)) {
5267 vrend_printf( "dual src blend requested but not supported for rt %d\n", i);
5268 continue;
5269 }
5270
5271 glBlendFuncSeparateiARB(i, translate_blend_factor(state->rt[i].rgb_src_factor),
5272 translate_blend_factor(state->rt[i].rgb_dst_factor),
5273 translate_blend_factor(state->rt[i].alpha_src_factor),
5274 translate_blend_factor(state->rt[i].alpha_dst_factor));
5275 glBlendEquationSeparateiARB(i, translate_blend_func(state->rt[i].rgb_func),
5276 translate_blend_func(state->rt[i].alpha_func));
5277 glEnableIndexedEXT(GL_BLEND, i);
5278 } else
5279 glDisableIndexedEXT(GL_BLEND, i);
5280
5281 if (state->rt[i].colormask != sub_ctx->hw_blend_state.rt[i].colormask) {
5282 sub_ctx->hw_blend_state.rt[i].colormask = state->rt[i].colormask;
5283 glColorMaskIndexedEXT(i, state->rt[i].colormask & PIPE_MASK_R ? GL_TRUE : GL_FALSE,
5284 state->rt[i].colormask & PIPE_MASK_G ? GL_TRUE : GL_FALSE,
5285 state->rt[i].colormask & PIPE_MASK_B ? GL_TRUE : GL_FALSE,
5286 state->rt[i].colormask & PIPE_MASK_A ? GL_TRUE : GL_FALSE);
5287 }
5288 }
5289 } else {
5290 if (state->rt[0].blend_enable) {
5291 bool dual_src = util_blend_state_is_dual(&sub_ctx->blend_state, 0);
5292 if (dual_src && !has_feature(feat_dual_src_blend)) {
5293 vrend_printf( "dual src blend requested but not supported for rt 0\n");
5294 }
5295 glBlendFuncSeparate(translate_blend_factor(state->rt[0].rgb_src_factor),
5296 translate_blend_factor(state->rt[0].rgb_dst_factor),
5297 translate_blend_factor(state->rt[0].alpha_src_factor),
5298 translate_blend_factor(state->rt[0].alpha_dst_factor));
5299 glBlendEquationSeparate(translate_blend_func(state->rt[0].rgb_func),
5300 translate_blend_func(state->rt[0].alpha_func));
5301 glEnable(GL_BLEND);
5302 }
5303 else
5304 glDisable(GL_BLEND);
5305
5306 if (state->rt[0].colormask != sub_ctx->hw_blend_state.rt[0].colormask ||
5307 (sub_ctx->hw_blend_state.independent_blend_enable &&
5308 !state->independent_blend_enable)) {
5309 int i;
5310 for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++)
5311 sub_ctx->hw_blend_state.rt[i].colormask = state->rt[i].colormask;
5312 glColorMask(state->rt[0].colormask & PIPE_MASK_R ? GL_TRUE : GL_FALSE,
5313 state->rt[0].colormask & PIPE_MASK_G ? GL_TRUE : GL_FALSE,
5314 state->rt[0].colormask & PIPE_MASK_B ? GL_TRUE : GL_FALSE,
5315 state->rt[0].colormask & PIPE_MASK_A ? GL_TRUE : GL_FALSE);
5316 }
5317 }
5318 sub_ctx->hw_blend_state.independent_blend_enable = state->independent_blend_enable;
5319
5320 if (has_feature(feat_multisample)) {
5321 if (state->alpha_to_coverage)
5322 glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
5323 else
5324 glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
5325
5326 if (!vrend_state.use_gles) {
5327 if (state->alpha_to_one)
5328 glEnable(GL_SAMPLE_ALPHA_TO_ONE);
5329 else
5330 glDisable(GL_SAMPLE_ALPHA_TO_ONE);
5331 }
5332 }
5333
5334 if (state->dither)
5335 glEnable(GL_DITHER);
5336 else
5337 glDisable(GL_DITHER);
5338 }
5339
5340 /* there are a few reasons we might need to patch the blend state.
5341 a) patching blend factors for dst with no alpha
5342 b) patching colormask/blendcolor/blendfactors for A8/A16 format
5343 emulation using GL_R8/GL_R16.
5344 */
vrend_patch_blend_state(struct vrend_sub_context * sub_ctx)5345 static void vrend_patch_blend_state(struct vrend_sub_context *sub_ctx)
5346 {
5347 struct pipe_blend_state new_state = sub_ctx->blend_state;
5348 struct pipe_blend_state *state = &sub_ctx->blend_state;
5349 bool swizzle_blend_color = false;
5350 struct pipe_blend_color blend_color = sub_ctx->blend_color;
5351 int i;
5352
5353 if (sub_ctx->nr_cbufs == 0) {
5354 sub_ctx->blend_state_dirty = false;
5355 return;
5356 }
5357
5358 for (i = 0; i < (state->independent_blend_enable ? PIPE_MAX_COLOR_BUFS : 1); i++) {
5359 if (i < sub_ctx->nr_cbufs && sub_ctx->surf[i]) {
5360 if (vrend_format_is_emulated_alpha(sub_ctx->surf[i]->format)) {
5361 if (state->rt[i].blend_enable) {
5362 new_state.rt[i].rgb_src_factor = conv_a8_blend(state->rt[i].alpha_src_factor);
5363 new_state.rt[i].rgb_dst_factor = conv_a8_blend(state->rt[i].alpha_dst_factor);
5364 new_state.rt[i].alpha_src_factor = PIPE_BLENDFACTOR_ZERO;
5365 new_state.rt[i].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
5366 }
5367 new_state.rt[i].colormask = 0;
5368 if (state->rt[i].colormask & PIPE_MASK_A)
5369 new_state.rt[i].colormask |= PIPE_MASK_R;
5370 if (is_const_blend(new_state.rt[i].rgb_src_factor) ||
5371 is_const_blend(new_state.rt[i].rgb_dst_factor)) {
5372 swizzle_blend_color = true;
5373 }
5374 } else if (!util_format_has_alpha(sub_ctx->surf[i]->format)) {
5375 if (!(is_dst_blend(state->rt[i].rgb_src_factor) ||
5376 is_dst_blend(state->rt[i].rgb_dst_factor) ||
5377 is_dst_blend(state->rt[i].alpha_src_factor) ||
5378 is_dst_blend(state->rt[i].alpha_dst_factor)))
5379 continue;
5380 new_state.rt[i].rgb_src_factor = conv_dst_blend(state->rt[i].rgb_src_factor);
5381 new_state.rt[i].rgb_dst_factor = conv_dst_blend(state->rt[i].rgb_dst_factor);
5382 new_state.rt[i].alpha_src_factor = conv_dst_blend(state->rt[i].alpha_src_factor);
5383 new_state.rt[i].alpha_dst_factor = conv_dst_blend(state->rt[i].alpha_dst_factor);
5384 }
5385 }
5386 }
5387
5388 vrend_hw_emit_blend(sub_ctx, &new_state);
5389
5390 if (swizzle_blend_color) {
5391 blend_color.color[0] = blend_color.color[3];
5392 blend_color.color[1] = 0.0f;
5393 blend_color.color[2] = 0.0f;
5394 blend_color.color[3] = 0.0f;
5395 }
5396
5397 glBlendColor(blend_color.color[0],
5398 blend_color.color[1],
5399 blend_color.color[2],
5400 blend_color.color[3]);
5401
5402 sub_ctx->blend_state_dirty = false;
5403 }
5404
vrend_object_bind_blend(struct vrend_context * ctx,uint32_t handle)5405 void vrend_object_bind_blend(struct vrend_context *ctx,
5406 uint32_t handle)
5407 {
5408 struct pipe_blend_state *state;
5409
5410 if (handle == 0) {
5411 memset(&ctx->sub->blend_state, 0, sizeof(ctx->sub->blend_state));
5412 glDisable(GL_BLEND);
5413 return;
5414 }
5415 state = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_BLEND);
5416 if (!state) {
5417 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_HANDLE, handle);
5418 return;
5419 }
5420
5421 ctx->sub->shader_dirty = true;
5422 ctx->sub->blend_state = *state;
5423
5424 ctx->sub->blend_state_dirty = true;
5425 }
5426
vrend_hw_emit_dsa(struct vrend_context * ctx)5427 static void vrend_hw_emit_dsa(struct vrend_context *ctx)
5428 {
5429 struct pipe_depth_stencil_alpha_state *state = &ctx->sub->dsa_state;
5430
5431 if (state->depth.enabled) {
5432 vrend_depth_test_enable(ctx, true);
5433 glDepthFunc(GL_NEVER + state->depth.func);
5434 if (state->depth.writemask)
5435 glDepthMask(GL_TRUE);
5436 else
5437 glDepthMask(GL_FALSE);
5438 } else
5439 vrend_depth_test_enable(ctx, false);
5440
5441 if (state->alpha.enabled) {
5442 vrend_alpha_test_enable(ctx, true);
5443 if (!vrend_state.use_core_profile)
5444 glAlphaFunc(GL_NEVER + state->alpha.func, state->alpha.ref_value);
5445 } else
5446 vrend_alpha_test_enable(ctx, false);
5447
5448
5449 }
vrend_object_bind_dsa(struct vrend_context * ctx,uint32_t handle)5450 void vrend_object_bind_dsa(struct vrend_context *ctx,
5451 uint32_t handle)
5452 {
5453 struct pipe_depth_stencil_alpha_state *state;
5454
5455 if (handle == 0) {
5456 memset(&ctx->sub->dsa_state, 0, sizeof(ctx->sub->dsa_state));
5457 ctx->sub->dsa = NULL;
5458 ctx->sub->stencil_state_dirty = true;
5459 ctx->sub->shader_dirty = true;
5460 vrend_hw_emit_dsa(ctx);
5461 return;
5462 }
5463
5464 state = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_DSA);
5465 if (!state) {
5466 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_HANDLE, handle);
5467 return;
5468 }
5469
5470 if (ctx->sub->dsa != state) {
5471 ctx->sub->stencil_state_dirty = true;
5472 ctx->sub->shader_dirty = true;
5473 }
5474 ctx->sub->dsa_state = *state;
5475 ctx->sub->dsa = state;
5476
5477 vrend_hw_emit_dsa(ctx);
5478 }
5479
vrend_update_frontface_state(struct vrend_sub_context * sub_ctx)5480 static void vrend_update_frontface_state(struct vrend_sub_context *sub_ctx)
5481 {
5482 struct pipe_rasterizer_state *state = &sub_ctx->rs_state;
5483 int front_ccw = state->front_ccw;
5484
5485 front_ccw ^= (sub_ctx->inverted_fbo_content ? 0 : 1);
5486 if (front_ccw)
5487 glFrontFace(GL_CCW);
5488 else
5489 glFrontFace(GL_CW);
5490 }
5491
vrend_update_stencil_state(struct vrend_sub_context * sub_ctx)5492 void vrend_update_stencil_state(struct vrend_sub_context *sub_ctx)
5493 {
5494 struct pipe_depth_stencil_alpha_state *state = sub_ctx->dsa;
5495 int i;
5496 if (!state)
5497 return;
5498
5499 if (!state->stencil[1].enabled) {
5500 if (state->stencil[0].enabled) {
5501 vrend_stencil_test_enable(sub_ctx, true);
5502
5503 glStencilOp(translate_stencil_op(state->stencil[0].fail_op),
5504 translate_stencil_op(state->stencil[0].zfail_op),
5505 translate_stencil_op(state->stencil[0].zpass_op));
5506
5507 glStencilFunc(GL_NEVER + state->stencil[0].func,
5508 sub_ctx->stencil_refs[0],
5509 state->stencil[0].valuemask);
5510 glStencilMask(state->stencil[0].writemask);
5511 } else
5512 vrend_stencil_test_enable(sub_ctx, false);
5513 } else {
5514 vrend_stencil_test_enable(sub_ctx, true);
5515
5516 for (i = 0; i < 2; i++) {
5517 GLenum face = (i == 1) ? GL_BACK : GL_FRONT;
5518 glStencilOpSeparate(face,
5519 translate_stencil_op(state->stencil[i].fail_op),
5520 translate_stencil_op(state->stencil[i].zfail_op),
5521 translate_stencil_op(state->stencil[i].zpass_op));
5522
5523 glStencilFuncSeparate(face, GL_NEVER + state->stencil[i].func,
5524 sub_ctx->stencil_refs[i],
5525 state->stencil[i].valuemask);
5526 glStencilMaskSeparate(face, state->stencil[i].writemask);
5527 }
5528 }
5529 sub_ctx->stencil_state_dirty = false;
5530 }
5531
translate_fill(uint32_t mode)5532 static inline GLenum translate_fill(uint32_t mode)
5533 {
5534 switch (mode) {
5535 case PIPE_POLYGON_MODE_POINT:
5536 return GL_POINT;
5537 case PIPE_POLYGON_MODE_LINE:
5538 return GL_LINE;
5539 case PIPE_POLYGON_MODE_FILL:
5540 return GL_FILL;
5541 default:
5542 assert(0);
5543 return 0;
5544 }
5545 }
5546
vrend_hw_emit_rs(struct vrend_context * ctx)5547 static void vrend_hw_emit_rs(struct vrend_context *ctx)
5548 {
5549 struct pipe_rasterizer_state *state = &ctx->sub->rs_state;
5550 int i;
5551
5552 if (has_feature(feat_depth_clamp)) {
5553 if (state->depth_clip)
5554 glDisable(GL_DEPTH_CLAMP);
5555 else
5556 glEnable(GL_DEPTH_CLAMP);
5557 }
5558
5559 if (vrend_state.use_gles) {
5560 /* guest send invalid glPointSize parameter */
5561 if (!state->point_size_per_vertex &&
5562 state->point_size != 1.0f &&
5563 state->point_size != 0.0f) {
5564 report_gles_warn(ctx, GLES_WARN_POINT_SIZE);
5565 }
5566 } else if (state->point_size_per_vertex) {
5567 glEnable(GL_PROGRAM_POINT_SIZE);
5568 } else {
5569 glDisable(GL_PROGRAM_POINT_SIZE);
5570 if (state->point_size) {
5571 glPointSize(state->point_size);
5572 }
5573 }
5574
5575 /* line_width < 0 is invalid, the guest sometimes forgot to set it. */
5576 glLineWidth(state->line_width <= 0 ? 1.0f : state->line_width);
5577
5578 if (state->rasterizer_discard != ctx->sub->hw_rs_state.rasterizer_discard) {
5579 ctx->sub->hw_rs_state.rasterizer_discard = state->rasterizer_discard;
5580 if (state->rasterizer_discard)
5581 glEnable(GL_RASTERIZER_DISCARD);
5582 else
5583 glDisable(GL_RASTERIZER_DISCARD);
5584 }
5585
5586 if (vrend_state.use_gles == true) {
5587 if (translate_fill(state->fill_front) != GL_FILL) {
5588 report_gles_warn(ctx, GLES_WARN_POLYGON_MODE);
5589 }
5590 if (translate_fill(state->fill_back) != GL_FILL) {
5591 report_gles_warn(ctx, GLES_WARN_POLYGON_MODE);
5592 }
5593 } else if (vrend_state.use_core_profile == false) {
5594 glPolygonMode(GL_FRONT, translate_fill(state->fill_front));
5595 glPolygonMode(GL_BACK, translate_fill(state->fill_back));
5596 } else if (state->fill_front == state->fill_back) {
5597 glPolygonMode(GL_FRONT_AND_BACK, translate_fill(state->fill_front));
5598 } else
5599 report_core_warn(ctx, CORE_PROFILE_WARN_POLYGON_MODE);
5600
5601 if (state->offset_tri) {
5602 glEnable(GL_POLYGON_OFFSET_FILL);
5603 } else {
5604 glDisable(GL_POLYGON_OFFSET_FILL);
5605 }
5606
5607 if (vrend_state.use_gles) {
5608 if (state->offset_line) {
5609 report_gles_warn(ctx, GLES_WARN_OFFSET_LINE);
5610 }
5611 } else if (state->offset_line) {
5612 glEnable(GL_POLYGON_OFFSET_LINE);
5613 } else {
5614 glDisable(GL_POLYGON_OFFSET_LINE);
5615 }
5616
5617 if (vrend_state.use_gles) {
5618 if (state->offset_point) {
5619 report_gles_warn(ctx, GLES_WARN_OFFSET_POINT);
5620 }
5621 } else if (state->offset_point) {
5622 glEnable(GL_POLYGON_OFFSET_POINT);
5623 } else {
5624 glDisable(GL_POLYGON_OFFSET_POINT);
5625 }
5626
5627
5628 if (state->flatshade != ctx->sub->hw_rs_state.flatshade) {
5629 ctx->sub->hw_rs_state.flatshade = state->flatshade;
5630 if (vrend_state.use_core_profile == false) {
5631 if (state->flatshade) {
5632 glShadeModel(GL_FLAT);
5633 } else {
5634 glShadeModel(GL_SMOOTH);
5635 }
5636 }
5637 }
5638
5639 if (state->clip_halfz != ctx->sub->hw_rs_state.clip_halfz) {
5640 if (has_feature(feat_clip_control)) {
5641 /* We only need to handle clip_halfz here, the bottom_edge_rule is
5642 * already handled via Gallium */
5643 GLenum depthrule = state->clip_halfz ? GL_ZERO_TO_ONE : GL_NEGATIVE_ONE_TO_ONE;
5644 glClipControl(GL_LOWER_LEFT, depthrule);
5645 ctx->sub->hw_rs_state.clip_halfz = state->clip_halfz;
5646 } else {
5647 vrend_printf("No clip control supported\n");
5648 }
5649 }
5650 if (state->flatshade_first != ctx->sub->hw_rs_state.flatshade_first) {
5651 ctx->sub->hw_rs_state.flatshade_first = state->flatshade_first;
5652 if (vrend_state.use_gles) {
5653 if (state->flatshade_first) {
5654 report_gles_warn(ctx, GLES_WARN_FLATSHADE_FIRST);
5655 }
5656 } else if (state->flatshade_first) {
5657 glProvokingVertexEXT(GL_FIRST_VERTEX_CONVENTION_EXT);
5658 } else {
5659 glProvokingVertexEXT(GL_LAST_VERTEX_CONVENTION_EXT);
5660 }
5661 }
5662
5663 if (!vrend_state.use_gles && has_feature(feat_polygon_offset_clamp))
5664 glPolygonOffsetClampEXT(state->offset_scale, state->offset_units, state->offset_clamp);
5665 else
5666 glPolygonOffset(state->offset_scale, state->offset_units);
5667
5668 if (vrend_state.use_core_profile == false) {
5669 if (state->poly_stipple_enable)
5670 glEnable(GL_POLYGON_STIPPLE);
5671 else
5672 glDisable(GL_POLYGON_STIPPLE);
5673 } else if (state->poly_stipple_enable) {
5674 if (!ctx->pstip_inited)
5675 vrend_init_pstipple_texture(ctx);
5676 }
5677
5678 if (state->point_quad_rasterization) {
5679 if (vrend_state.use_core_profile == false &&
5680 vrend_state.use_gles == false) {
5681 glEnable(GL_POINT_SPRITE);
5682 }
5683
5684 if (vrend_state.use_gles == false) {
5685 glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN, state->sprite_coord_mode ? GL_UPPER_LEFT : GL_LOWER_LEFT);
5686 }
5687 } else {
5688 if (vrend_state.use_core_profile == false &&
5689 vrend_state.use_gles == false) {
5690 glDisable(GL_POINT_SPRITE);
5691 }
5692 }
5693
5694 if (state->cull_face != PIPE_FACE_NONE) {
5695 switch (state->cull_face) {
5696 case PIPE_FACE_FRONT:
5697 glCullFace(GL_FRONT);
5698 break;
5699 case PIPE_FACE_BACK:
5700 glCullFace(GL_BACK);
5701 break;
5702 case PIPE_FACE_FRONT_AND_BACK:
5703 glCullFace(GL_FRONT_AND_BACK);
5704 break;
5705 default:
5706 vrend_printf( "unhandled cull-face: %x\n", state->cull_face);
5707 }
5708 glEnable(GL_CULL_FACE);
5709 } else
5710 glDisable(GL_CULL_FACE);
5711
5712 /* two sided lighting handled in shader for core profile */
5713 if (vrend_state.use_core_profile == false) {
5714 if (state->light_twoside)
5715 glEnable(GL_VERTEX_PROGRAM_TWO_SIDE);
5716 else
5717 glDisable(GL_VERTEX_PROGRAM_TWO_SIDE);
5718 }
5719
5720 if (state->clip_plane_enable != ctx->sub->hw_rs_state.clip_plane_enable) {
5721 ctx->sub->hw_rs_state.clip_plane_enable = state->clip_plane_enable;
5722 for (i = 0; i < 8; i++) {
5723 if (state->clip_plane_enable & (1 << i))
5724 glEnable(GL_CLIP_PLANE0 + i);
5725 else
5726 glDisable(GL_CLIP_PLANE0 + i);
5727 }
5728 }
5729 if (vrend_state.use_core_profile == false) {
5730 glLineStipple(state->line_stipple_factor, state->line_stipple_pattern);
5731 if (state->line_stipple_enable)
5732 glEnable(GL_LINE_STIPPLE);
5733 else
5734 glDisable(GL_LINE_STIPPLE);
5735 } else if (state->line_stipple_enable) {
5736 if (vrend_state.use_gles)
5737 report_core_warn(ctx, GLES_WARN_STIPPLE);
5738 else
5739 report_core_warn(ctx, CORE_PROFILE_WARN_STIPPLE);
5740 }
5741
5742
5743 if (vrend_state.use_gles) {
5744 if (state->line_smooth) {
5745 report_gles_warn(ctx, GLES_WARN_LINE_SMOOTH);
5746 }
5747 } else if (state->line_smooth) {
5748 glEnable(GL_LINE_SMOOTH);
5749 } else {
5750 glDisable(GL_LINE_SMOOTH);
5751 }
5752
5753 if (vrend_state.use_gles) {
5754 if (state->poly_smooth) {
5755 report_gles_warn(ctx, GLES_WARN_POLY_SMOOTH);
5756 }
5757 } else if (state->poly_smooth) {
5758 glEnable(GL_POLYGON_SMOOTH);
5759 } else {
5760 glDisable(GL_POLYGON_SMOOTH);
5761 }
5762
5763 if (vrend_state.use_core_profile == false) {
5764 if (state->clamp_vertex_color)
5765 glClampColor(GL_CLAMP_VERTEX_COLOR_ARB, GL_TRUE);
5766 else
5767 glClampColor(GL_CLAMP_VERTEX_COLOR_ARB, GL_FALSE);
5768
5769 if (state->clamp_fragment_color)
5770 glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB, GL_TRUE);
5771 else
5772 glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB, GL_FALSE);
5773 } else {
5774 if (state->clamp_vertex_color || state->clamp_fragment_color)
5775 report_core_warn(ctx, CORE_PROFILE_WARN_CLAMP);
5776 }
5777
5778 /* read-color-clamping is handled in the mesa frontend */
5779 if (!vrend_state.use_gles) {
5780 glClampColor(GL_CLAMP_READ_COLOR_ARB, GL_FALSE);
5781 }
5782
5783 if (has_feature(feat_multisample)) {
5784 if (has_feature(feat_sample_mask)) {
5785 if (state->multisample)
5786 glEnable(GL_SAMPLE_MASK);
5787 else
5788 glDisable(GL_SAMPLE_MASK);
5789 }
5790
5791 /* GLES doesn't have GL_MULTISAMPLE */
5792 if (!vrend_state.use_gles) {
5793 if (state->multisample)
5794 glEnable(GL_MULTISAMPLE);
5795 else
5796 glDisable(GL_MULTISAMPLE);
5797 }
5798
5799 if (has_feature(feat_sample_shading)) {
5800 if (state->force_persample_interp)
5801 glEnable(GL_SAMPLE_SHADING);
5802 else
5803 glDisable(GL_SAMPLE_SHADING);
5804 }
5805 }
5806
5807 if (state->scissor)
5808 glEnable(GL_SCISSOR_TEST);
5809 else
5810 glDisable(GL_SCISSOR_TEST);
5811 ctx->sub->hw_rs_state.scissor = state->scissor;
5812
5813 }
5814
vrend_object_bind_rasterizer(struct vrend_context * ctx,uint32_t handle)5815 void vrend_object_bind_rasterizer(struct vrend_context *ctx,
5816 uint32_t handle)
5817 {
5818 struct pipe_rasterizer_state *state;
5819
5820 if (handle == 0) {
5821 memset(&ctx->sub->rs_state, 0, sizeof(ctx->sub->rs_state));
5822 return;
5823 }
5824
5825 state = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_RASTERIZER);
5826
5827 if (!state) {
5828 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_HANDLE, handle);
5829 return;
5830 }
5831
5832 ctx->sub->rs_state = *state;
5833 ctx->sub->shader_dirty = true;
5834 vrend_hw_emit_rs(ctx);
5835 }
5836
vrend_bind_sampler_states(struct vrend_context * ctx,uint32_t shader_type,uint32_t start_slot,uint32_t num_states,const uint32_t * handles)5837 void vrend_bind_sampler_states(struct vrend_context *ctx,
5838 uint32_t shader_type,
5839 uint32_t start_slot,
5840 uint32_t num_states,
5841 const uint32_t *handles)
5842 {
5843 uint32_t i;
5844 struct vrend_sampler_state *state;
5845
5846 if (shader_type >= PIPE_SHADER_TYPES) {
5847 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_CMD_BUFFER, shader_type);
5848 return;
5849 }
5850
5851 if (num_states > PIPE_MAX_SAMPLERS ||
5852 start_slot > (PIPE_MAX_SAMPLERS - num_states)) {
5853 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_CMD_BUFFER, num_states);
5854 return;
5855 }
5856
5857 ctx->sub->num_sampler_states[shader_type] = num_states;
5858
5859 for (i = 0; i < num_states; i++) {
5860 if (handles[i] == 0)
5861 state = NULL;
5862 else
5863 state = vrend_object_lookup(ctx->sub->object_hash, handles[i], VIRGL_OBJECT_SAMPLER_STATE);
5864
5865 if (!state && handles[i])
5866 vrend_printf("Failed to bind sampler state (handle=%d)\n", handles[i]);
5867
5868 ctx->sub->sampler_state[shader_type][start_slot + i] = state;
5869 ctx->sub->sampler_views_dirty[shader_type] |= (1 << (start_slot + i));
5870 }
5871 }
5872
vrend_apply_sampler_state(struct vrend_sub_context * sub_ctx,struct vrend_resource * res,uint32_t shader_type,int id,int sampler_id,struct vrend_sampler_view * tview)5873 static void vrend_apply_sampler_state(struct vrend_sub_context *sub_ctx,
5874 struct vrend_resource *res,
5875 uint32_t shader_type,
5876 int id,
5877 int sampler_id,
5878 struct vrend_sampler_view *tview)
5879 {
5880 struct vrend_texture *tex = (struct vrend_texture *)res;
5881 struct vrend_sampler_state *vstate = sub_ctx->sampler_state[shader_type][id];
5882 struct pipe_sampler_state *state = &vstate->base;
5883 bool set_all = false;
5884 GLenum target = tex->base.target;
5885
5886 assert(offsetof(struct vrend_sampler_state, base) == 0);
5887 if (!state)
5888 return;
5889
5890 if (res->base.nr_samples > 0) {
5891 tex->state = *state;
5892 return;
5893 }
5894
5895 if (has_bit(tex->base.storage_bits, VREND_STORAGE_GL_BUFFER)) {
5896 tex->state = *state;
5897 return;
5898 }
5899
5900 /*
5901 * If we emulate alpha format with red, we need to tell
5902 * the sampler to use the red channel and not the alpha one
5903 * by swizzling the GL_TEXTURE_BORDER_COLOR parameter.
5904 */
5905 bool is_emulated_alpha = vrend_format_is_emulated_alpha(tview->format);
5906 if (has_feature(feat_samplers)) {
5907 int sampler = vstate->ids[tview->srgb_decode == GL_SKIP_DECODE_EXT ? 0 : 1];
5908 if (is_emulated_alpha) {
5909 union pipe_color_union border_color;
5910 border_color = state->border_color;
5911 border_color.ui[0] = border_color.ui[3];
5912 border_color.ui[3] = 0;
5913 apply_sampler_border_color(sampler, border_color.ui);
5914 }
5915
5916 glBindSampler(sampler_id, sampler);
5917 return;
5918 }
5919
5920 if (tex->state.max_lod == -1)
5921 set_all = true;
5922
5923 if (tex->state.wrap_s != state->wrap_s || set_all)
5924 glTexParameteri(target, GL_TEXTURE_WRAP_S, convert_wrap(state->wrap_s));
5925 if (tex->state.wrap_t != state->wrap_t || set_all)
5926 glTexParameteri(target, GL_TEXTURE_WRAP_T, convert_wrap(state->wrap_t));
5927 if (tex->state.wrap_r != state->wrap_r || set_all)
5928 glTexParameteri(target, GL_TEXTURE_WRAP_R, convert_wrap(state->wrap_r));
5929 if (tex->state.min_img_filter != state->min_img_filter ||
5930 tex->state.min_mip_filter != state->min_mip_filter || set_all)
5931 glTexParameterf(target, GL_TEXTURE_MIN_FILTER, convert_min_filter(state->min_img_filter, state->min_mip_filter));
5932 if (tex->state.mag_img_filter != state->mag_img_filter || set_all)
5933 glTexParameterf(target, GL_TEXTURE_MAG_FILTER, convert_mag_filter(state->mag_img_filter));
5934 if (res->target != GL_TEXTURE_RECTANGLE) {
5935 if (tex->state.min_lod != state->min_lod || set_all)
5936 glTexParameterf(target, GL_TEXTURE_MIN_LOD, state->min_lod);
5937 if (tex->state.max_lod != state->max_lod || set_all)
5938 glTexParameterf(target, GL_TEXTURE_MAX_LOD, state->max_lod);
5939 if (tex->state.lod_bias != state->lod_bias || set_all) {
5940 if (vrend_state.use_gles) {
5941 if (state->lod_bias)
5942 report_gles_warn(sub_ctx->parent, GLES_WARN_LOD_BIAS);
5943 } else {
5944 glTexParameterf(target, GL_TEXTURE_LOD_BIAS, state->lod_bias);
5945 }
5946 }
5947 }
5948
5949 if (tex->state.compare_mode != state->compare_mode || set_all)
5950 glTexParameteri(target, GL_TEXTURE_COMPARE_MODE, state->compare_mode ? GL_COMPARE_R_TO_TEXTURE : GL_NONE);
5951 if (tex->state.compare_func != state->compare_func || set_all)
5952 glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC, GL_NEVER + state->compare_func);
5953 if (has_feature(feat_anisotropic_filter) && (tex->state.max_anisotropy != state->max_anisotropy || set_all))
5954 glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY, state->max_anisotropy);
5955
5956 /*
5957 * Oh this is a fun one. On GLES 2.0 all cubemap MUST NOT be seamless.
5958 * But on GLES 3.0 all cubemaps MUST be seamless. Either way there is no
5959 * way to toggle between the behaviour when running on GLES. And adding
5960 * warnings will spew the logs quite bad. Ignore and hope for the best.
5961 */
5962 if (!vrend_state.use_gles) {
5963 if (state->seamless_cube_map) {
5964 glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
5965 } else {
5966 glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
5967 }
5968 }
5969
5970 if (memcmp(&tex->state.border_color, &state->border_color, 16) || set_all ||
5971 is_emulated_alpha) {
5972 if (is_emulated_alpha) {
5973 union pipe_color_union border_color;
5974 border_color = state->border_color;
5975 border_color.ui[0] = border_color.ui[3];
5976 border_color.ui[3] = 0;
5977 glTexParameterIuiv(target, GL_TEXTURE_BORDER_COLOR, border_color.ui);
5978 } else {
5979 glTexParameterIuiv(target, GL_TEXTURE_BORDER_COLOR, state->border_color.ui);
5980 }
5981
5982 }
5983 tex->state = *state;
5984 }
5985
tgsitargettogltarget(const enum pipe_texture_target target,int nr_samples)5986 static GLenum tgsitargettogltarget(const enum pipe_texture_target target, int nr_samples)
5987 {
5988 switch(target) {
5989 case PIPE_TEXTURE_1D:
5990 return GL_TEXTURE_1D;
5991 case PIPE_TEXTURE_2D:
5992 return (nr_samples > 0) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
5993 case PIPE_TEXTURE_3D:
5994 return GL_TEXTURE_3D;
5995 case PIPE_TEXTURE_RECT:
5996 return GL_TEXTURE_RECTANGLE_NV;
5997 case PIPE_TEXTURE_CUBE:
5998 return GL_TEXTURE_CUBE_MAP;
5999
6000 case PIPE_TEXTURE_1D_ARRAY:
6001 return GL_TEXTURE_1D_ARRAY;
6002 case PIPE_TEXTURE_2D_ARRAY:
6003 return (nr_samples > 0) ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY : GL_TEXTURE_2D_ARRAY;
6004 case PIPE_TEXTURE_CUBE_ARRAY:
6005 return GL_TEXTURE_CUBE_MAP_ARRAY;
6006 case PIPE_BUFFER:
6007 default:
6008 return PIPE_BUFFER;
6009 }
6010 return PIPE_BUFFER;
6011 }
6012
lock_sync(void)6013 static inline void lock_sync(void)
6014 {
6015 if (vrend_state.sync_thread && vrend_state.use_async_fence_cb)
6016 pipe_mutex_lock(vrend_state.fence_mutex);
6017 }
6018
unlock_sync(void)6019 static inline void unlock_sync(void)
6020 {
6021 if (vrend_state.sync_thread && vrend_state.use_async_fence_cb)
6022 pipe_mutex_unlock(vrend_state.fence_mutex);
6023 }
6024
vrend_free_sync_thread(void)6025 static void vrend_free_sync_thread(void)
6026 {
6027 if (!vrend_state.sync_thread)
6028 return;
6029
6030 pipe_mutex_lock(vrend_state.fence_mutex);
6031 vrend_state.stop_sync_thread = true;
6032 pipe_condvar_signal(vrend_state.fence_cond);
6033 pipe_mutex_unlock(vrend_state.fence_mutex);
6034
6035 pipe_thread_wait(vrend_state.sync_thread);
6036 vrend_state.sync_thread = 0;
6037
6038 pipe_condvar_destroy(vrend_state.fence_cond);
6039 pipe_mutex_destroy(vrend_state.fence_mutex);
6040 }
6041
free_fence_locked(struct vrend_fence * fence)6042 static void free_fence_locked(struct vrend_fence *fence)
6043 {
6044 list_del(&fence->fences);
6045 #ifdef HAVE_EPOXY_EGL_H
6046 if (vrend_state.use_egl_fence) {
6047 virgl_egl_fence_destroy(egl, fence->eglsyncobj);
6048 } else
6049 #endif
6050 {
6051 glDeleteSync(fence->glsyncobj);
6052 }
6053 free(fence);
6054 }
6055
vrend_free_fences(void)6056 static void vrend_free_fences(void)
6057 {
6058 struct vrend_fence *fence, *stor;
6059
6060 /* this is called after vrend_free_sync_thread */
6061 assert(!vrend_state.sync_thread);
6062
6063 LIST_FOR_EACH_ENTRY_SAFE(fence, stor, &vrend_state.fence_list, fences)
6064 free_fence_locked(fence);
6065 LIST_FOR_EACH_ENTRY_SAFE(fence, stor, &vrend_state.fence_wait_list, fences)
6066 free_fence_locked(fence);
6067 }
6068
vrend_free_fences_for_context(struct vrend_context * ctx)6069 static void vrend_free_fences_for_context(struct vrend_context *ctx)
6070 {
6071 struct vrend_fence *fence, *stor;
6072
6073 if (vrend_state.sync_thread) {
6074 pipe_mutex_lock(vrend_state.fence_mutex);
6075 LIST_FOR_EACH_ENTRY_SAFE(fence, stor, &vrend_state.fence_list, fences) {
6076 if (fence->ctx == ctx)
6077 free_fence_locked(fence);
6078 }
6079 LIST_FOR_EACH_ENTRY_SAFE(fence, stor, &vrend_state.fence_wait_list, fences) {
6080 if (fence->ctx == ctx)
6081 free_fence_locked(fence);
6082 }
6083 if (vrend_state.fence_waiting) {
6084 /* mark the fence invalid as the sync thread is still waiting on it */
6085 vrend_state.fence_waiting->ctx = NULL;
6086 }
6087 pipe_mutex_unlock(vrend_state.fence_mutex);
6088 } else {
6089 LIST_FOR_EACH_ENTRY_SAFE(fence, stor, &vrend_state.fence_list, fences) {
6090 if (fence->ctx == ctx)
6091 free_fence_locked(fence);
6092 }
6093 }
6094 }
6095
do_wait(struct vrend_fence * fence,bool can_block)6096 static bool do_wait(struct vrend_fence *fence, bool can_block)
6097 {
6098 bool done = false;
6099 int timeout = can_block ? 1000000000 : 0;
6100
6101 #ifdef HAVE_EPOXY_EGL_H
6102 if (vrend_state.use_egl_fence) {
6103 do {
6104 done = virgl_egl_client_wait_fence(egl, fence->eglsyncobj, timeout);
6105 } while (!done && can_block);
6106 return done;
6107 }
6108 #endif
6109
6110 do {
6111 GLenum glret = glClientWaitSync(fence->glsyncobj, 0, timeout);
6112 if (glret == GL_WAIT_FAILED) {
6113 vrend_printf( "wait sync failed: illegal fence object %p\n", fence->glsyncobj);
6114 }
6115 done = glret != GL_TIMEOUT_EXPIRED;
6116 } while (!done && can_block);
6117
6118 return done;
6119 }
6120
6121 static void vrend_renderer_check_queries_locked(void);
6122
wait_sync(struct vrend_fence * fence)6123 static void wait_sync(struct vrend_fence *fence)
6124 {
6125 struct vrend_context *ctx = fence->ctx;
6126
6127 do_wait(fence, /* can_block */ true);
6128
6129 pipe_mutex_lock(vrend_state.fence_mutex);
6130 if (vrend_state.use_async_fence_cb) {
6131 vrend_renderer_check_queries_locked();
6132 /* to be able to call free_fence_locked without locking */
6133 list_inithead(&fence->fences);
6134 } else {
6135 list_addtail(&fence->fences, &vrend_state.fence_list);
6136 }
6137 vrend_state.fence_waiting = NULL;
6138 pipe_mutex_unlock(vrend_state.fence_mutex);
6139
6140 if (vrend_state.use_async_fence_cb) {
6141 ctx->fence_retire(fence->fence_cookie, ctx->fence_retire_data);
6142 free_fence_locked(fence);
6143 return;
6144 }
6145
6146 if (write_eventfd(vrend_state.eventfd, 1)) {
6147 perror("failed to write to eventfd\n");
6148 }
6149 }
6150
thread_sync(UNUSED void * arg)6151 static int thread_sync(UNUSED void *arg)
6152 {
6153 virgl_gl_context gl_context = vrend_state.sync_context;
6154 struct vrend_fence *fence, *stor;
6155
6156 pipe_thread_setname("vrend-sync");
6157
6158 pipe_mutex_lock(vrend_state.fence_mutex);
6159 vrend_clicbs->make_current(gl_context);
6160
6161 while (!vrend_state.stop_sync_thread) {
6162 if (LIST_IS_EMPTY(&vrend_state.fence_wait_list) &&
6163 pipe_condvar_wait(vrend_state.fence_cond, vrend_state.fence_mutex) != 0) {
6164 vrend_printf( "error while waiting on condition\n");
6165 break;
6166 }
6167
6168 LIST_FOR_EACH_ENTRY_SAFE(fence, stor, &vrend_state.fence_wait_list, fences) {
6169 if (vrend_state.stop_sync_thread)
6170 break;
6171 list_del(&fence->fences);
6172 vrend_state.fence_waiting = fence;
6173 pipe_mutex_unlock(vrend_state.fence_mutex);
6174 wait_sync(fence);
6175 pipe_mutex_lock(vrend_state.fence_mutex);
6176 }
6177 }
6178
6179 vrend_clicbs->make_current(0);
6180 vrend_clicbs->destroy_gl_context(vrend_state.sync_context);
6181 pipe_mutex_unlock(vrend_state.fence_mutex);
6182 return 0;
6183 }
6184
vrend_renderer_use_threaded_sync(void)6185 static void vrend_renderer_use_threaded_sync(void)
6186 {
6187 struct virgl_gl_ctx_param ctx_params;
6188
6189 ctx_params.shared = true;
6190 ctx_params.major_ver = vrend_state.gl_major_ver;
6191 ctx_params.minor_ver = vrend_state.gl_minor_ver;
6192
6193 vrend_state.stop_sync_thread = false;
6194
6195 vrend_state.sync_context = vrend_clicbs->create_gl_context(0, &ctx_params);
6196 if (vrend_state.sync_context == NULL) {
6197 vrend_printf( "failed to create sync opengl context\n");
6198 return;
6199 }
6200
6201 if (!vrend_state.use_async_fence_cb) {
6202 vrend_state.eventfd = create_eventfd(0);
6203 if (vrend_state.eventfd == -1) {
6204 vrend_printf( "Failed to create eventfd\n");
6205 vrend_clicbs->destroy_gl_context(vrend_state.sync_context);
6206 return;
6207 }
6208 }
6209
6210 pipe_condvar_init(vrend_state.fence_cond);
6211 pipe_mutex_init(vrend_state.fence_mutex);
6212
6213 vrend_state.sync_thread = pipe_thread_create(thread_sync, NULL);
6214 if (!vrend_state.sync_thread) {
6215 if (vrend_state.eventfd != -1) {
6216 close(vrend_state.eventfd);
6217 vrend_state.eventfd = -1;
6218 }
6219 vrend_clicbs->destroy_gl_context(vrend_state.sync_context);
6220 pipe_condvar_destroy(vrend_state.fence_cond);
6221 pipe_mutex_destroy(vrend_state.fence_mutex);
6222 }
6223 }
6224
vrend_debug_cb(UNUSED GLenum source,GLenum type,UNUSED GLuint id,UNUSED GLenum severity,UNUSED GLsizei length,UNUSED const GLchar * message,UNUSED const void * userParam)6225 static void vrend_debug_cb(UNUSED GLenum source, GLenum type, UNUSED GLuint id,
6226 UNUSED GLenum severity, UNUSED GLsizei length,
6227 UNUSED const GLchar* message, UNUSED const void* userParam)
6228 {
6229 if (type != GL_DEBUG_TYPE_ERROR) {
6230 return;
6231 }
6232
6233 vrend_printf( "ERROR: %s\n", message);
6234 }
6235
vrend_pipe_resource_unref(struct pipe_resource * pres,UNUSED void * data)6236 static void vrend_pipe_resource_unref(struct pipe_resource *pres,
6237 UNUSED void *data)
6238 {
6239 struct vrend_resource *res = (struct vrend_resource *)pres;
6240
6241 if (vrend_state.finishing || pipe_reference(&res->base.reference, NULL))
6242 vrend_renderer_resource_destroy(res);
6243 }
6244
vrend_pipe_resource_attach_iov(struct pipe_resource * pres,const struct iovec * iov,int iov_count,UNUSED void * data)6245 static void vrend_pipe_resource_attach_iov(struct pipe_resource *pres,
6246 const struct iovec *iov,
6247 int iov_count,
6248 UNUSED void *data)
6249 {
6250 struct vrend_resource *res = (struct vrend_resource *)pres;
6251
6252 res->iov = iov;
6253 res->num_iovs = iov_count;
6254
6255 if (has_bit(res->storage_bits, VREND_STORAGE_HOST_SYSTEM_MEMORY)) {
6256 vrend_write_to_iovec(res->iov, res->num_iovs, 0,
6257 res->ptr, res->base.width0);
6258 }
6259 }
6260
vrend_pipe_resource_detach_iov(struct pipe_resource * pres,UNUSED void * data)6261 static void vrend_pipe_resource_detach_iov(struct pipe_resource *pres,
6262 UNUSED void *data)
6263 {
6264 struct vrend_resource *res = (struct vrend_resource *)pres;
6265
6266 if (has_bit(res->storage_bits, VREND_STORAGE_HOST_SYSTEM_MEMORY)) {
6267 vrend_read_from_iovec(res->iov, res->num_iovs, 0,
6268 res->ptr, res->base.width0);
6269 }
6270
6271 res->iov = NULL;
6272 res->num_iovs = 0;
6273 }
6274
vrend_pipe_resource_export_fd(UNUSED struct pipe_resource * pres,UNUSED int * fd,UNUSED void * data)6275 static enum virgl_resource_fd_type vrend_pipe_resource_export_fd(UNUSED struct pipe_resource *pres,
6276 UNUSED int *fd,
6277 UNUSED void *data)
6278 {
6279 #ifdef ENABLE_MINIGBM_ALLOCATION
6280 struct vrend_resource *res = (struct vrend_resource *)pres;
6281
6282 if (res->storage_bits & VREND_STORAGE_GBM_BUFFER) {
6283 int ret = virgl_gbm_export_fd(gbm->device,
6284 gbm_bo_get_handle(res->gbm_bo).u32, fd);
6285 if (!ret)
6286 return VIRGL_RESOURCE_FD_DMABUF;
6287 }
6288 #endif
6289
6290 return VIRGL_RESOURCE_FD_INVALID;
6291 }
6292
6293 const struct virgl_resource_pipe_callbacks *
vrend_renderer_get_pipe_callbacks(void)6294 vrend_renderer_get_pipe_callbacks(void)
6295 {
6296 static const struct virgl_resource_pipe_callbacks callbacks = {
6297 .unref = vrend_pipe_resource_unref,
6298 .attach_iov = vrend_pipe_resource_attach_iov,
6299 .detach_iov = vrend_pipe_resource_detach_iov,
6300 .export_fd = vrend_pipe_resource_export_fd,
6301 };
6302
6303 return &callbacks;
6304 }
6305
use_integer()6306 static bool use_integer() {
6307 if (getenv("VIRGL_USE_INTEGER"))
6308 return true;
6309
6310 const char * a = (const char *) glGetString(GL_VENDOR);
6311 if (!a)
6312 return false;
6313 if (strcmp(a, "ARM") == 0)
6314 return true;
6315 return false;
6316 }
6317
vrend_renderer_init(const struct vrend_if_cbs * cbs,uint32_t flags)6318 int vrend_renderer_init(const struct vrend_if_cbs *cbs, uint32_t flags)
6319 {
6320 bool gles;
6321 int gl_ver;
6322 virgl_gl_context gl_context;
6323 struct virgl_gl_ctx_param ctx_params;
6324
6325 vrend_clicbs = cbs;
6326
6327 /* Give some defaults to be able to run the tests */
6328 vrend_state.max_texture_2d_size =
6329 vrend_state.max_texture_3d_size =
6330 vrend_state.max_texture_cube_size = 16384;
6331
6332 #ifndef NDEBUG
6333 vrend_init_debug_flags();
6334 #endif
6335
6336 ctx_params.shared = false;
6337 for (uint32_t i = 0; i < ARRAY_SIZE(gl_versions); i++) {
6338 ctx_params.major_ver = gl_versions[i].major;
6339 ctx_params.minor_ver = gl_versions[i].minor;
6340
6341 gl_context = vrend_clicbs->create_gl_context(0, &ctx_params);
6342 if (gl_context)
6343 break;
6344 }
6345
6346 vrend_clicbs->make_current(gl_context);
6347 gl_ver = epoxy_gl_version();
6348
6349 /* enable error output as early as possible */
6350 if (vrend_debug(NULL, dbg_khr) && epoxy_has_gl_extension("GL_KHR_debug")) {
6351 glDebugMessageCallback(vrend_debug_cb, NULL);
6352 glEnable(GL_DEBUG_OUTPUT);
6353 glDisable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
6354 set_feature(feat_debug_cb);
6355 }
6356
6357 /* make sure you have the latest version of libepoxy */
6358 gles = epoxy_is_desktop_gl() == 0;
6359
6360 vrend_state.gl_major_ver = gl_ver / 10;
6361 vrend_state.gl_minor_ver = gl_ver % 10;
6362
6363 if (gles) {
6364 vrend_printf( "gl_version %d - es profile enabled\n", gl_ver);
6365 vrend_state.use_gles = true;
6366 /* for now, makes the rest of the code use the most GLES 3.x like path */
6367 vrend_state.use_core_profile = 1;
6368 } else if (gl_ver > 30 && !epoxy_has_gl_extension("GL_ARB_compatibility")) {
6369 vrend_printf( "gl_version %d - core profile enabled\n", gl_ver);
6370 vrend_state.use_core_profile = 1;
6371 } else {
6372 vrend_printf( "gl_version %d - compat profile\n", gl_ver);
6373 }
6374
6375 vrend_state.use_integer = use_integer();
6376
6377 init_features(gles ? 0 : gl_ver,
6378 gles ? gl_ver : 0);
6379
6380 if (!vrend_winsys_has_gl_colorspace())
6381 clear_feature(feat_srgb_write_control) ;
6382
6383 glGetIntegerv(GL_MAX_DRAW_BUFFERS, (GLint *) &vrend_state.max_draw_buffers);
6384
6385 /* Mesa clamps this value to 8 anyway, so just make sure that this side
6386 * doesn't exceed the number to be on the save side when using 8-bit masks
6387 * for the color buffers */
6388 if (vrend_state.max_draw_buffers > 8)
6389 vrend_state.max_draw_buffers = 8;
6390
6391 if (!has_feature(feat_arb_robustness) &&
6392 !has_feature(feat_gles_khr_robustness)) {
6393 vrend_printf("WARNING: running without ARB/KHR robustness in place may crash\n");
6394 }
6395
6396 /* callbacks for when we are cleaning up the object table */
6397 vrend_object_set_destroy_callback(VIRGL_OBJECT_QUERY, vrend_destroy_query_object);
6398 vrend_object_set_destroy_callback(VIRGL_OBJECT_SURFACE, vrend_destroy_surface_object);
6399 vrend_object_set_destroy_callback(VIRGL_OBJECT_SHADER, vrend_destroy_shader_object);
6400 vrend_object_set_destroy_callback(VIRGL_OBJECT_SAMPLER_VIEW, vrend_destroy_sampler_view_object);
6401 vrend_object_set_destroy_callback(VIRGL_OBJECT_STREAMOUT_TARGET, vrend_destroy_so_target_object);
6402 vrend_object_set_destroy_callback(VIRGL_OBJECT_SAMPLER_STATE, vrend_destroy_sampler_state_object);
6403 vrend_object_set_destroy_callback(VIRGL_OBJECT_VERTEX_ELEMENTS, vrend_destroy_vertex_elements_object);
6404
6405 /* disable for format testing, spews a lot of errors */
6406 if (has_feature(feat_debug_cb)) {
6407 glDisable(GL_DEBUG_OUTPUT);
6408 }
6409
6410 vrend_build_format_list_common();
6411
6412 if (vrend_state.use_gles) {
6413 vrend_build_format_list_gles();
6414 } else {
6415 vrend_build_format_list_gl();
6416 }
6417
6418 vrend_check_texture_storage(tex_conv_table);
6419
6420 /* disable for format testing */
6421 if (has_feature(feat_debug_cb)) {
6422 glDisable(GL_DEBUG_OUTPUT);
6423 }
6424
6425 vrend_clicbs->destroy_gl_context(gl_context);
6426 list_inithead(&vrend_state.fence_list);
6427 list_inithead(&vrend_state.fence_wait_list);
6428 list_inithead(&vrend_state.waiting_query_list);
6429 /* create 0 context */
6430 vrend_state.ctx0 = vrend_create_context(0, strlen("HOST"), "HOST");
6431
6432 vrend_state.eventfd = -1;
6433 if (flags & VREND_USE_THREAD_SYNC) {
6434 if (flags & VREND_USE_ASYNC_FENCE_CB)
6435 vrend_state.use_async_fence_cb = true;
6436 vrend_renderer_use_threaded_sync();
6437 }
6438 if (flags & VREND_USE_EXTERNAL_BLOB)
6439 vrend_state.use_external_blob = true;
6440
6441 #ifdef HAVE_EPOXY_EGL_H
6442 if (vrend_state.use_gles)
6443 vrend_state.use_egl_fence = virgl_egl_supports_fences(egl);
6444 #endif
6445
6446 return 0;
6447 }
6448
6449 void
vrend_renderer_fini(void)6450 vrend_renderer_fini(void)
6451 {
6452 vrend_state.finishing = true;
6453
6454 if (vrend_state.eventfd != -1) {
6455 close(vrend_state.eventfd);
6456 vrend_state.eventfd = -1;
6457 }
6458
6459 vrend_free_fences();
6460 vrend_blitter_fini();
6461
6462 vrend_destroy_context(vrend_state.ctx0);
6463
6464 vrend_state.current_ctx = NULL;
6465 vrend_state.current_hw_ctx = NULL;
6466
6467 vrend_state.finishing = false;
6468 }
6469
vrend_destroy_sub_context(struct vrend_sub_context * sub)6470 static void vrend_destroy_sub_context(struct vrend_sub_context *sub)
6471 {
6472 int i, j;
6473 struct vrend_streamout_object *obj, *tmp;
6474
6475 vrend_clicbs->make_current(sub->gl_context);
6476
6477 if (sub->fb_id)
6478 glDeleteFramebuffers(1, &sub->fb_id);
6479
6480 if (sub->blit_fb_ids[0])
6481 glDeleteFramebuffers(2, sub->blit_fb_ids);
6482
6483 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
6484
6485 if (!has_feature(feat_gles31_vertex_attrib_binding)) {
6486 while (sub->enabled_attribs_bitmask) {
6487 i = u_bit_scan(&sub->enabled_attribs_bitmask);
6488
6489 glDisableVertexAttribArray(i);
6490 }
6491 glDeleteVertexArrays(1, &sub->vaoid);
6492 }
6493
6494 glBindVertexArray(0);
6495
6496 if (sub->current_so)
6497 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
6498
6499 LIST_FOR_EACH_ENTRY_SAFE(obj, tmp, &sub->streamout_list, head) {
6500 vrend_destroy_streamout_object(obj);
6501 }
6502
6503 vrend_shader_state_reference(&sub->shaders[PIPE_SHADER_VERTEX], NULL);
6504 vrend_shader_state_reference(&sub->shaders[PIPE_SHADER_FRAGMENT], NULL);
6505 vrend_shader_state_reference(&sub->shaders[PIPE_SHADER_GEOMETRY], NULL);
6506 vrend_shader_state_reference(&sub->shaders[PIPE_SHADER_TESS_CTRL], NULL);
6507 vrend_shader_state_reference(&sub->shaders[PIPE_SHADER_TESS_EVAL], NULL);
6508 vrend_shader_state_reference(&sub->shaders[PIPE_SHADER_COMPUTE], NULL);
6509
6510 if (sub->prog)
6511 sub->prog->ref_context = NULL;
6512
6513 vrend_free_programs(sub);
6514 for (i = 0; i < PIPE_SHADER_TYPES; i++) {
6515 free(sub->consts[i].consts);
6516 sub->consts[i].consts = NULL;
6517
6518 for (j = 0; j < PIPE_MAX_SHADER_SAMPLER_VIEWS; j++) {
6519 vrend_sampler_view_reference(&sub->views[i].views[j], NULL);
6520 }
6521 }
6522
6523 if (sub->zsurf)
6524 vrend_surface_reference(&sub->zsurf, NULL);
6525
6526 for (i = 0; i < sub->nr_cbufs; i++) {
6527 if (!sub->surf[i])
6528 continue;
6529 vrend_surface_reference(&sub->surf[i], NULL);
6530 }
6531
6532 vrend_set_num_vbo_sub(sub, 0);
6533 vrend_resource_reference((struct vrend_resource **)&sub->ib.buffer, NULL);
6534
6535 /* need to lock mutex before destroying queries, we could
6536 * be checking these in the sync thread */
6537 lock_sync();
6538 vrend_object_fini_ctx_table(sub->object_hash);
6539 unlock_sync();
6540
6541 vrend_clicbs->destroy_gl_context(sub->gl_context);
6542
6543 list_del(&sub->head);
6544 FREE(sub);
6545
6546 }
6547
vrend_destroy_context(struct vrend_context * ctx)6548 void vrend_destroy_context(struct vrend_context *ctx)
6549 {
6550 bool switch_0 = (ctx == vrend_state.current_ctx);
6551 struct vrend_context *cur = vrend_state.current_ctx;
6552 struct vrend_sub_context *sub, *tmp;
6553 struct vrend_untyped_resource *untyped_res, *untyped_res_tmp;
6554 if (switch_0) {
6555 vrend_state.current_ctx = NULL;
6556 vrend_state.current_hw_ctx = NULL;
6557 }
6558
6559 if (vrend_state.use_core_profile) {
6560 if (ctx->pstip_inited)
6561 glDeleteTextures(1, &ctx->pstipple_tex_id);
6562 ctx->pstip_inited = false;
6563 }
6564 vrend_clicbs->make_current(ctx->sub->gl_context);
6565 /* reset references on framebuffers */
6566 vrend_set_framebuffer_state(ctx, 0, NULL, 0);
6567
6568 vrend_set_num_sampler_views(ctx, PIPE_SHADER_VERTEX, 0, 0);
6569 vrend_set_num_sampler_views(ctx, PIPE_SHADER_FRAGMENT, 0, 0);
6570 vrend_set_num_sampler_views(ctx, PIPE_SHADER_GEOMETRY, 0, 0);
6571 vrend_set_num_sampler_views(ctx, PIPE_SHADER_TESS_CTRL, 0, 0);
6572 vrend_set_num_sampler_views(ctx, PIPE_SHADER_TESS_EVAL, 0, 0);
6573 vrend_set_num_sampler_views(ctx, PIPE_SHADER_COMPUTE, 0, 0);
6574
6575 vrend_set_streamout_targets(ctx, 0, 0, NULL);
6576
6577 vrend_set_index_buffer(ctx, 0, 0, 0);
6578
6579 LIST_FOR_EACH_ENTRY_SAFE(sub, tmp, &ctx->sub_ctxs, head)
6580 vrend_destroy_sub_context(sub);
6581 if(ctx->ctx_id)
6582 vrend_renderer_force_ctx_0();
6583
6584 vrend_free_fences_for_context(ctx);
6585
6586 LIST_FOR_EACH_ENTRY_SAFE(untyped_res, untyped_res_tmp, &ctx->untyped_resources, head)
6587 free(untyped_res);
6588 vrend_ctx_resource_fini_table(ctx->res_hash);
6589
6590 FREE(ctx);
6591
6592 if (!switch_0 && cur)
6593 vrend_hw_switch_context(cur, true);
6594 }
6595
vrend_create_context(int id,uint32_t nlen,const char * debug_name)6596 struct vrend_context *vrend_create_context(int id, uint32_t nlen, const char *debug_name)
6597 {
6598 struct vrend_context *grctx = CALLOC_STRUCT(vrend_context);
6599
6600 if (!grctx)
6601 return NULL;
6602
6603 if (nlen && debug_name) {
6604 strncpy(grctx->debug_name, debug_name,
6605 nlen < sizeof(grctx->debug_name) - 1 ?
6606 nlen : sizeof(grctx->debug_name) - 1);
6607 grctx->debug_name[sizeof(grctx->debug_name) - 1] = 0;
6608 }
6609
6610 VREND_DEBUG(dbg_caller, grctx, "create context\n");
6611
6612 grctx->ctx_id = id;
6613
6614 list_inithead(&grctx->sub_ctxs);
6615 list_inithead(&grctx->vrend_resources);
6616 list_inithead(&grctx->active_nontimer_query_list);
6617
6618 grctx->res_hash = vrend_ctx_resource_init_table();
6619 list_inithead(&grctx->untyped_resources);
6620
6621 grctx->shader_cfg.use_gles = vrend_state.use_gles;
6622 grctx->shader_cfg.use_core_profile = vrend_state.use_core_profile;
6623 grctx->shader_cfg.use_explicit_locations = vrend_state.use_explicit_locations;
6624 grctx->shader_cfg.max_draw_buffers = vrend_state.max_draw_buffers;
6625 grctx->shader_cfg.has_arrays_of_arrays = has_feature(feat_arrays_of_arrays);
6626 grctx->shader_cfg.has_gpu_shader5 = has_feature(feat_gpu_shader5);
6627 grctx->shader_cfg.has_es31_compat = has_feature(feat_gles31_compatibility);
6628 grctx->shader_cfg.has_conservative_depth = has_feature(feat_conservative_depth);
6629 grctx->shader_cfg.use_integer = vrend_state.use_integer;
6630 grctx->shader_cfg.has_dual_src_blend = has_feature(feat_dual_src_blend);
6631 grctx->shader_cfg.has_fbfetch_coherent = has_feature(feat_framebuffer_fetch);
6632
6633 vrend_renderer_create_sub_ctx(grctx, 0);
6634 vrend_renderer_set_sub_ctx(grctx, 0);
6635
6636 grctx->shader_cfg.glsl_version = vrender_get_glsl_version();
6637
6638 if (!grctx->ctx_id)
6639 grctx->fence_retire = vrend_clicbs->ctx0_fence_retire;
6640
6641 return grctx;
6642 }
6643
check_resource_valid(const struct vrend_renderer_resource_create_args * args,char errmsg[256])6644 static int check_resource_valid(const struct vrend_renderer_resource_create_args *args,
6645 char errmsg[256])
6646 {
6647 /* limit the target */
6648 if (args->target >= PIPE_MAX_TEXTURE_TYPES) {
6649 snprintf(errmsg, 256, "Invalid texture target %d (>= %d)",
6650 args->target, PIPE_MAX_TEXTURE_TYPES);
6651 return -1;
6652 }
6653
6654 if (args->format >= VIRGL_FORMAT_MAX) {
6655 snprintf(errmsg, 256, "Invalid texture format %d (>=%d)",
6656 args->format, VIRGL_FORMAT_MAX);
6657 return -1;
6658 }
6659
6660 bool format_can_texture_storage = has_feature(feat_texture_storage) &&
6661 (tex_conv_table[args->format].flags & VIRGL_TEXTURE_CAN_TEXTURE_STORAGE);
6662
6663 /* only texture 2d and 2d array can have multiple samples */
6664 if (args->nr_samples > 0) {
6665 if (!has_feature(feat_texture_multisample)) {
6666 snprintf(errmsg, 256, "Multisample textures not supported");
6667 return -1;
6668 }
6669
6670 if (args->target != PIPE_TEXTURE_2D && args->target != PIPE_TEXTURE_2D_ARRAY) {
6671 snprintf(errmsg, 256, "Multisample textures not 2D (target:%d)", args->target);
6672 return -1;
6673 }
6674 /* multisample can't have miplevels */
6675 if (args->last_level > 0) {
6676 snprintf(errmsg, 256, "Multisample textures don't support mipmaps");
6677 return -1;
6678 }
6679 if (!format_can_texture_storage && vrend_state.use_gles) {
6680 snprintf(errmsg, 256, "Unsupported multisample texture format %d", args->format);
6681 return -1;
6682 }
6683 }
6684
6685 if (args->last_level > 0) {
6686 /* buffer and rect textures can't have mipmaps */
6687 if (args->target == PIPE_BUFFER) {
6688 snprintf(errmsg, 256, "Buffers don't support mipmaps");
6689 return -1;
6690 }
6691
6692 if (args->target == PIPE_TEXTURE_RECT) {
6693 snprintf(errmsg, 256, "RECT textures don't support mipmaps");
6694 return -1;
6695 }
6696
6697 if (args->last_level > (floor(log2(MAX2(args->width, args->height))) + 1)) {
6698 snprintf(errmsg, 256, "Mipmap levels %d too large for texture size (%d, %d)",
6699 args->last_level, args->width, args->height);
6700 return -1;
6701 }
6702 }
6703
6704 if (args->flags != 0) {
6705 uint32_t supported_mask = VIRGL_RESOURCE_Y_0_TOP | VIRGL_RESOURCE_FLAG_MAP_PERSISTENT
6706 | VIRGL_RESOURCE_FLAG_MAP_COHERENT;
6707
6708 if (args->flags & ~supported_mask) {
6709 snprintf(errmsg, 256, "Resource flags 0x%x not supported", args->flags);
6710 return -1;
6711 }
6712 }
6713
6714 if (args->flags & VIRGL_RESOURCE_Y_0_TOP) {
6715 if (args->target != PIPE_TEXTURE_2D && args->target != PIPE_TEXTURE_RECT) {
6716 snprintf(errmsg, 256, "VIRGL_RESOURCE_Y_0_TOP only supported for 2D or RECT textures");
6717 return -1;
6718 }
6719 }
6720
6721 /* array size for array textures only */
6722 if (args->target == PIPE_TEXTURE_CUBE) {
6723 if (args->array_size != 6) {
6724 snprintf(errmsg, 256, "Cube map: unexpected array size %d", args->array_size);
6725 return -1;
6726 }
6727 } else if (args->target == PIPE_TEXTURE_CUBE_ARRAY) {
6728 if (!has_feature(feat_cube_map_array)) {
6729 snprintf(errmsg, 256, "Cube map arrays not supported");
6730 return -1;
6731 }
6732 if (args->array_size % 6) {
6733 snprintf(errmsg, 256, "Cube map array: unexpected array size %d", args->array_size);
6734 return -1;
6735 }
6736 } else if (args->array_size > 1) {
6737 if (args->target != PIPE_TEXTURE_2D_ARRAY &&
6738 args->target != PIPE_TEXTURE_1D_ARRAY) {
6739 snprintf(errmsg, 256, "Texture target %d can't be an array ", args->target);
6740 return -1;
6741 }
6742
6743 if (!has_feature(feat_texture_array)) {
6744 snprintf(errmsg, 256, "Texture arrays are not supported");
6745 return -1;
6746 }
6747 }
6748
6749 if (args->target != PIPE_BUFFER && !args->width) {
6750 snprintf(errmsg, 256, "Texture width must be >0");
6751 return -1;
6752 }
6753
6754 if (args->bind == 0 ||
6755 args->bind == VIRGL_BIND_CUSTOM ||
6756 args->bind == VIRGL_BIND_STAGING ||
6757 args->bind == VIRGL_BIND_INDEX_BUFFER ||
6758 args->bind == VIRGL_BIND_STREAM_OUTPUT ||
6759 args->bind == VIRGL_BIND_VERTEX_BUFFER ||
6760 args->bind == VIRGL_BIND_CONSTANT_BUFFER ||
6761 args->bind == VIRGL_BIND_QUERY_BUFFER ||
6762 args->bind == VIRGL_BIND_COMMAND_ARGS ||
6763 args->bind == VIRGL_BIND_SHADER_BUFFER) {
6764 if (args->target != PIPE_BUFFER) {
6765 snprintf(errmsg, 256, "Buffer bind flags requre the buffer target but this is target %d", args->target);
6766 return -1;
6767 }
6768 if (args->height != 1 || args->depth != 1) {
6769 snprintf(errmsg, 256, "Buffer target: Got height=%u, depth=%u, expect (1,1)", args->height, args->depth);
6770 return -1;
6771 }
6772 if (args->bind == VIRGL_BIND_QUERY_BUFFER && !has_feature(feat_qbo)) {
6773 snprintf(errmsg, 256, "Query buffers are not supported");
6774 return -1;
6775 }
6776 if (args->bind == VIRGL_BIND_COMMAND_ARGS && !has_feature(feat_indirect_draw)) {
6777 snprintf(errmsg, 256, "Command args buffer requested but indirect draw is not supported");
6778 return -1;
6779 }
6780 } else {
6781 if (!((args->bind & VIRGL_BIND_SAMPLER_VIEW) ||
6782 (args->bind & VIRGL_BIND_DEPTH_STENCIL) ||
6783 (args->bind & VIRGL_BIND_RENDER_TARGET) ||
6784 (args->bind & VIRGL_BIND_CURSOR) ||
6785 (args->bind & VIRGL_BIND_SHARED) ||
6786 (args->bind & VIRGL_BIND_LINEAR))) {
6787 snprintf(errmsg, 256, "Invalid texture bind flags 0x%x", args->bind);
6788 return -1;
6789 }
6790
6791 #ifdef ENABLE_MINIGBM_ALLOCATION
6792 if (!virgl_gbm_gpu_import_required(args->bind)) {
6793 return 0;
6794 }
6795 #endif
6796
6797 if (args->target == PIPE_TEXTURE_2D ||
6798 args->target == PIPE_TEXTURE_RECT ||
6799 args->target == PIPE_TEXTURE_CUBE ||
6800 args->target == PIPE_TEXTURE_2D_ARRAY ||
6801 args->target == PIPE_TEXTURE_CUBE_ARRAY) {
6802 if (args->depth != 1) {
6803 snprintf(errmsg, 256, "2D texture target with depth=%u != 1", args->depth);
6804 return -1;
6805 }
6806 if (format_can_texture_storage && !args->height) {
6807 snprintf(errmsg, 256, "2D Texture storage requires non-zero height");
6808 return -1;
6809 }
6810 }
6811 if (args->target == PIPE_TEXTURE_1D ||
6812 args->target == PIPE_TEXTURE_1D_ARRAY) {
6813 if (args->height != 1 || args->depth != 1) {
6814 snprintf(errmsg, 256, "Got height=%u, depth=%u, expect (1,1)",
6815 args->height, args->depth);
6816 return -1;
6817 }
6818 if (args->width > vrend_state.max_texture_2d_size) {
6819 snprintf(errmsg, 256, "1D Texture width (%u) exceeds supported value (%u)",
6820 args->width, vrend_state.max_texture_2d_size);
6821 return -1;
6822 }
6823 }
6824
6825 if (args->target == PIPE_TEXTURE_2D ||
6826 args->target == PIPE_TEXTURE_RECT ||
6827 args->target == PIPE_TEXTURE_2D_ARRAY) {
6828 if (args->width > vrend_state.max_texture_2d_size ||
6829 args->height > vrend_state.max_texture_2d_size) {
6830 snprintf(errmsg, 256, "2D Texture size components (%u, %u) exceeds supported value (%u)",
6831 args->width, args->height, vrend_state.max_texture_2d_size);
6832 return -1;
6833 }
6834 }
6835
6836 if (args->target == PIPE_TEXTURE_3D) {
6837 if (format_can_texture_storage &&
6838 (!args->height || !args->depth)) {
6839 snprintf(errmsg, 256, "Texture storage expects non-zero height (%u) and depth (%u)",
6840 args->height, args->depth);
6841 return -1;
6842 }
6843 if (args->width > vrend_state.max_texture_3d_size ||
6844 args->height > vrend_state.max_texture_3d_size ||
6845 args->depth > vrend_state.max_texture_3d_size) {
6846 snprintf(errmsg, 256, "3D Texture sizes (%u, %u, %u) exceeds supported value (%u)",
6847 args->width, args->height, args->depth,
6848 vrend_state.max_texture_3d_size);
6849 return -1;
6850 }
6851 }
6852 if (args->target == PIPE_TEXTURE_2D_ARRAY ||
6853 args->target == PIPE_TEXTURE_CUBE_ARRAY ||
6854 args->target == PIPE_TEXTURE_1D_ARRAY) {
6855 if (format_can_texture_storage &&
6856 !args->array_size) {
6857 snprintf(errmsg, 256, "Texture arrays require a non-zero arrays size "
6858 "when allocated with glTexStorage");
6859 return -1;
6860 }
6861 }
6862 if (args->target == PIPE_TEXTURE_CUBE ||
6863 args->target == PIPE_TEXTURE_CUBE_ARRAY) {
6864 if (args->width != args->height) {
6865 snprintf(errmsg, 256, "Cube maps require width (%u) == height (%u)",
6866 args->width, args->height);
6867 return -1;
6868 }
6869 if (args->width > vrend_state.max_texture_cube_size) {
6870 snprintf(errmsg, 256, "Cube maps size (%u) exceeds supported value (%u)",
6871 args->width, vrend_state.max_texture_cube_size);
6872 return -1;
6873 }
6874 }
6875 }
6876 return 0;
6877 }
6878
vrend_create_buffer(struct vrend_resource * gr,uint32_t width,uint32_t flags)6879 static void vrend_create_buffer(struct vrend_resource *gr, uint32_t width, uint32_t flags)
6880 {
6881
6882 GLbitfield buffer_storage_flags = 0;
6883 if (flags & VIRGL_RESOURCE_FLAG_MAP_PERSISTENT) {
6884 buffer_storage_flags |= GL_MAP_PERSISTENT_BIT;
6885 /* Gallium's storage_flags_to_buffer_flags seems to drop some information, but we have to
6886 * satisfy the following:
6887 *
6888 * "If flags contains GL_MAP_PERSISTENT_BIT, it must also contain at least one of
6889 * GL_MAP_READ_BIT or GL_MAP_WRITE_BIT."
6890 */
6891 buffer_storage_flags |= GL_MAP_READ_BIT | GL_MAP_WRITE_BIT;
6892 }
6893 if (flags & VIRGL_RESOURCE_FLAG_MAP_COHERENT)
6894 buffer_storage_flags |= GL_MAP_COHERENT_BIT;
6895
6896 gr->storage_bits |= VREND_STORAGE_GL_BUFFER;
6897 glGenBuffersARB(1, &gr->id);
6898 glBindBufferARB(gr->target, gr->id);
6899
6900 if (buffer_storage_flags) {
6901 if (has_feature(feat_arb_buffer_storage) && !vrend_state.use_external_blob) {
6902 glBufferStorage(gr->target, width, NULL, buffer_storage_flags);
6903 gr->map_info = vrend_state.inferred_gl_caching_type;
6904 }
6905 #ifdef ENABLE_MINIGBM_ALLOCATION
6906 else if (has_feature(feat_memory_object_fd) && has_feature(feat_memory_object)) {
6907 GLuint memobj = 0;
6908 int fd = -1;
6909 int ret;
6910
6911 /* Could use VK too. */
6912 struct gbm_bo *bo = gbm_bo_create(gbm->device, width, 1,
6913 GBM_FORMAT_R8, GBM_BO_USE_LINEAR);
6914 if (!bo) {
6915 vrend_printf("Failed to allocate emulated GL buffer backing storage");
6916 return;
6917 }
6918
6919 ret = virgl_gbm_export_fd(gbm->device, gbm_bo_get_handle(bo).u32, &fd);
6920 if (ret || fd < 0) {
6921 vrend_printf("Failed to get file descriptor\n");
6922 return;
6923 }
6924
6925 glCreateMemoryObjectsEXT(1, &memobj);
6926 glImportMemoryFdEXT(memobj, width, GL_HANDLE_TYPE_OPAQUE_FD_EXT, fd);
6927 glBufferStorageMemEXT(gr->target, width, memobj, 0);
6928 gr->gbm_bo = bo;
6929 gr->memobj = memobj;
6930 gr->storage_bits |= VREND_STORAGE_GBM_BUFFER | VREND_STORAGE_GL_MEMOBJ;
6931
6932 if (!strcmp(gbm_device_get_backend_name(gbm->device), "i915"))
6933 gr->map_info = VIRGL_RENDERER_MAP_CACHE_CACHED;
6934 else
6935 gr->map_info = VIRGL_RENDERER_MAP_CACHE_WC;
6936 }
6937 #endif
6938 else {
6939 vrend_printf("Missing buffer storage and interop extensions\n");
6940 return;
6941 }
6942
6943 gr->storage_bits |= VREND_STORAGE_GL_IMMUTABLE;
6944 gr->buffer_storage_flags = buffer_storage_flags;
6945 gr->size = width;
6946 } else
6947 glBufferData(gr->target, width, NULL, GL_STREAM_DRAW);
6948
6949 glBindBufferARB(gr->target, 0);
6950 }
6951
6952 static int
vrend_resource_alloc_buffer(struct vrend_resource * gr,uint32_t flags)6953 vrend_resource_alloc_buffer(struct vrend_resource *gr, uint32_t flags)
6954 {
6955 const uint32_t bind = gr->base.bind;
6956 const uint32_t size = gr->base.width0;
6957
6958 if (bind == VIRGL_BIND_CUSTOM) {
6959 /* use iovec directly when attached */
6960 gr->storage_bits |= VREND_STORAGE_HOST_SYSTEM_MEMORY;
6961 gr->ptr = malloc(size);
6962 if (!gr->ptr)
6963 return -ENOMEM;
6964 } else if (bind == VIRGL_BIND_STAGING) {
6965 /* staging buffers only use guest memory -- nothing to do. */
6966 } else if (bind == VIRGL_BIND_INDEX_BUFFER) {
6967 gr->target = GL_ELEMENT_ARRAY_BUFFER_ARB;
6968 vrend_create_buffer(gr, size, flags);
6969 } else if (bind == VIRGL_BIND_STREAM_OUTPUT) {
6970 gr->target = GL_TRANSFORM_FEEDBACK_BUFFER;
6971 vrend_create_buffer(gr, size, flags);
6972 } else if (bind == VIRGL_BIND_VERTEX_BUFFER) {
6973 gr->target = GL_ARRAY_BUFFER_ARB;
6974 vrend_create_buffer(gr, size, flags);
6975 } else if (bind == VIRGL_BIND_CONSTANT_BUFFER) {
6976 gr->target = GL_UNIFORM_BUFFER;
6977 vrend_create_buffer(gr, size, flags);
6978 } else if (bind == VIRGL_BIND_QUERY_BUFFER) {
6979 gr->target = GL_QUERY_BUFFER;
6980 vrend_create_buffer(gr, size, flags);
6981 } else if (bind == VIRGL_BIND_COMMAND_ARGS) {
6982 gr->target = GL_DRAW_INDIRECT_BUFFER;
6983 vrend_create_buffer(gr, size, flags);
6984 } else if (bind == 0 || bind == VIRGL_BIND_SHADER_BUFFER) {
6985 gr->target = GL_ARRAY_BUFFER_ARB;
6986 vrend_create_buffer(gr, size, flags);
6987 } else if (bind & VIRGL_BIND_SAMPLER_VIEW) {
6988 /*
6989 * On Desktop we use GL_ARB_texture_buffer_object on GLES we use
6990 * GL_EXT_texture_buffer (it is in the ANDRIOD extension pack).
6991 */
6992 #if GL_TEXTURE_BUFFER != GL_TEXTURE_BUFFER_EXT
6993 #error "GL_TEXTURE_BUFFER enums differ, they shouldn't."
6994 #endif
6995
6996 /* need to check GL version here */
6997 if (has_feature(feat_arb_or_gles_ext_texture_buffer)) {
6998 gr->target = GL_TEXTURE_BUFFER;
6999 } else {
7000 gr->target = GL_PIXEL_PACK_BUFFER_ARB;
7001 }
7002 vrend_create_buffer(gr, size, flags);
7003 } else {
7004 vrend_printf("%s: Illegal buffer binding flags 0x%x\n", __func__, bind);
7005 return -EINVAL;
7006 }
7007
7008 return 0;
7009 }
7010
7011 static inline void
vrend_renderer_resource_copy_args(const struct vrend_renderer_resource_create_args * args,struct vrend_resource * gr)7012 vrend_renderer_resource_copy_args(const struct vrend_renderer_resource_create_args *args,
7013 struct vrend_resource *gr)
7014 {
7015 assert(gr);
7016 assert(args);
7017
7018 gr->base.bind = args->bind;
7019 gr->base.width0 = args->width;
7020 gr->base.height0 = args->height;
7021 gr->base.depth0 = args->depth;
7022 gr->base.format = args->format;
7023 gr->base.target = args->target;
7024 gr->base.last_level = args->last_level;
7025 gr->base.nr_samples = args->nr_samples;
7026 gr->base.array_size = args->array_size;
7027 }
7028
7029 /*
7030 * When GBM allocation is enabled, this function creates a GBM buffer and
7031 * EGL image given certain flags.
7032 */
vrend_resource_gbm_init(struct vrend_resource * gr,uint32_t format)7033 static void vrend_resource_gbm_init(struct vrend_resource *gr, uint32_t format)
7034 {
7035 #ifdef ENABLE_MINIGBM_ALLOCATION
7036 uint32_t gbm_flags = virgl_gbm_convert_flags(gr->base.bind);
7037 uint32_t gbm_format = 0;
7038 if (virgl_gbm_convert_format(&format, &gbm_format))
7039 return;
7040 if (vrend_winsys_different_gpu())
7041 gbm_flags |= GBM_BO_USE_LINEAR;
7042
7043 if (gr->base.depth0 != 1 || gr->base.last_level != 0 || gr->base.nr_samples != 0)
7044 return;
7045
7046 if (!gbm || !gbm->device || !gbm_format || !gbm_flags)
7047 return;
7048
7049 if (!virgl_gbm_external_allocation_preferred(gr->base.bind))
7050 return;
7051
7052 if (!gbm_device_is_format_supported(gbm->device, gbm_format, gbm_flags))
7053 return;
7054
7055 struct gbm_bo *bo = gbm_bo_create(gbm->device, gr->base.width0, gr->base.height0,
7056 gbm_format, gbm_flags);
7057 if (!bo)
7058 return;
7059
7060 gr->gbm_bo = bo;
7061 gr->storage_bits |= VREND_STORAGE_GBM_BUFFER;
7062 /* This is true so far, but maybe gbm_bo_get_caching_type is needed in the future. */
7063 if (!strcmp(gbm_device_get_backend_name(gbm->device), "i915"))
7064 gr->map_info = VIRGL_RENDERER_MAP_CACHE_CACHED;
7065 else
7066 gr->map_info = VIRGL_RENDERER_MAP_CACHE_WC;
7067
7068 if (!virgl_gbm_gpu_import_required(gr->base.bind))
7069 return;
7070
7071 gr->egl_image = virgl_egl_image_from_gbm_bo(egl, bo);
7072 if (!gr->egl_image) {
7073 gr->gbm_bo = NULL;
7074 gbm_bo_destroy(bo);
7075 }
7076
7077 gr->storage_bits |= VREND_STORAGE_EGL_IMAGE;
7078
7079 #else
7080 (void)format;
7081 (void)gr;
7082 #endif
7083 }
7084
vrend_resource_alloc_texture(struct vrend_resource * gr,enum virgl_formats format,void * image_oes)7085 static int vrend_resource_alloc_texture(struct vrend_resource *gr,
7086 enum virgl_formats format,
7087 void *image_oes)
7088 {
7089 uint level;
7090 GLenum internalformat, glformat, gltype;
7091 struct vrend_texture *gt = (struct vrend_texture *)gr;
7092 struct pipe_resource *pr = &gr->base;
7093
7094 const bool format_can_texture_storage = has_feature(feat_texture_storage) &&
7095 (tex_conv_table[format].flags & VIRGL_TEXTURE_CAN_TEXTURE_STORAGE);
7096
7097 if (format_can_texture_storage)
7098 gr->storage_bits |= VREND_STORAGE_GL_IMMUTABLE;
7099
7100 if (!image_oes) {
7101 vrend_resource_gbm_init(gr, format);
7102 if (gr->gbm_bo && !has_bit(gr->storage_bits, VREND_STORAGE_EGL_IMAGE))
7103 return 0;
7104
7105 image_oes = gr->egl_image;
7106 }
7107
7108 gr->target = tgsitargettogltarget(pr->target, pr->nr_samples);
7109 gr->storage_bits |= VREND_STORAGE_GL_TEXTURE;
7110
7111 /* ugly workaround for texture rectangle missing on GLES */
7112 if (vrend_state.use_gles && gr->target == GL_TEXTURE_RECTANGLE_NV) {
7113 /* for some guests this is the only usage of rect */
7114 if (pr->width0 != 1 || pr->height0 != 1) {
7115 report_gles_warn(NULL, GLES_WARN_TEXTURE_RECT);
7116 }
7117 gr->target = GL_TEXTURE_2D;
7118 }
7119
7120 /* fallback for 1D textures */
7121 if (vrend_state.use_gles && gr->target == GL_TEXTURE_1D) {
7122 gr->target = GL_TEXTURE_2D;
7123 }
7124
7125 /* fallback for 1D array textures */
7126 if (vrend_state.use_gles && gr->target == GL_TEXTURE_1D_ARRAY) {
7127 gr->target = GL_TEXTURE_2D_ARRAY;
7128 }
7129
7130 glGenTextures(1, &gr->id);
7131 glBindTexture(gr->target, gr->id);
7132
7133 debug_texture(__func__, gr);
7134
7135 if (image_oes) {
7136 if (has_bit(gr->storage_bits, VREND_STORAGE_GL_IMMUTABLE) &&
7137 has_feature(feat_egl_image_storage)) {
7138 glEGLImageTargetTexStorageEXT(gr->target, (GLeglImageOES) image_oes, NULL);
7139 } else if (has_feature(feat_egl_image_external)) {
7140 gr->storage_bits &= ~VREND_STORAGE_GL_IMMUTABLE;
7141 glEGLImageTargetTexture2DOES(gr->target, (GLeglImageOES) image_oes);
7142 } else {
7143 vrend_printf( "missing GL_OES_EGL_image_external extensions\n");
7144 glBindTexture(gr->target, 0);
7145 return EINVAL;
7146 }
7147 } else {
7148 internalformat = tex_conv_table[format].internalformat;
7149 glformat = tex_conv_table[format].glformat;
7150 gltype = tex_conv_table[format].gltype;
7151
7152 if (internalformat == 0) {
7153 vrend_printf("unknown format is %d\n", pr->format);
7154 glBindTexture(gr->target, 0);
7155 return EINVAL;
7156 }
7157
7158 if (pr->nr_samples > 0) {
7159 if (format_can_texture_storage) {
7160 if (gr->target == GL_TEXTURE_2D_MULTISAMPLE) {
7161 glTexStorage2DMultisample(gr->target, pr->nr_samples,
7162 internalformat, pr->width0, pr->height0,
7163 GL_TRUE);
7164 } else {
7165 glTexStorage3DMultisample(gr->target, pr->nr_samples,
7166 internalformat, pr->width0, pr->height0, pr->array_size,
7167 GL_TRUE);
7168 }
7169 } else {
7170 if (gr->target == GL_TEXTURE_2D_MULTISAMPLE) {
7171 glTexImage2DMultisample(gr->target, pr->nr_samples,
7172 internalformat, pr->width0, pr->height0,
7173 GL_TRUE);
7174 } else {
7175 glTexImage3DMultisample(gr->target, pr->nr_samples,
7176 internalformat, pr->width0, pr->height0, pr->array_size,
7177 GL_TRUE);
7178 }
7179 }
7180 } else if (gr->target == GL_TEXTURE_CUBE_MAP) {
7181 int i;
7182 if (format_can_texture_storage)
7183 glTexStorage2D(GL_TEXTURE_CUBE_MAP, pr->last_level + 1, internalformat, pr->width0, pr->height0);
7184 else {
7185 for (i = 0; i < 6; i++) {
7186 GLenum ctarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
7187 for (level = 0; level <= pr->last_level; level++) {
7188 unsigned mwidth = u_minify(pr->width0, level);
7189 unsigned mheight = u_minify(pr->height0, level);
7190
7191 glTexImage2D(ctarget, level, internalformat, mwidth, mheight, 0, glformat,
7192 gltype, NULL);
7193 }
7194 }
7195 }
7196 } else if (gr->target == GL_TEXTURE_3D ||
7197 gr->target == GL_TEXTURE_2D_ARRAY ||
7198 gr->target == GL_TEXTURE_CUBE_MAP_ARRAY) {
7199 if (format_can_texture_storage) {
7200 unsigned depth_param = (gr->target == GL_TEXTURE_2D_ARRAY || gr->target == GL_TEXTURE_CUBE_MAP_ARRAY) ?
7201 pr->array_size : pr->depth0;
7202 glTexStorage3D(gr->target, pr->last_level + 1, internalformat, pr->width0, pr->height0, depth_param);
7203 } else {
7204 for (level = 0; level <= pr->last_level; level++) {
7205 unsigned depth_param = (gr->target == GL_TEXTURE_2D_ARRAY || gr->target == GL_TEXTURE_CUBE_MAP_ARRAY) ?
7206 pr->array_size : u_minify(pr->depth0, level);
7207 unsigned mwidth = u_minify(pr->width0, level);
7208 unsigned mheight = u_minify(pr->height0, level);
7209 glTexImage3D(gr->target, level, internalformat, mwidth, mheight,
7210 depth_param, 0, glformat, gltype, NULL);
7211 }
7212 }
7213 } else if (gr->target == GL_TEXTURE_1D && vrend_state.use_gles) {
7214 report_gles_missing_func(NULL, "glTexImage1D");
7215 } else if (gr->target == GL_TEXTURE_1D) {
7216 if (format_can_texture_storage) {
7217 glTexStorage1D(gr->target, pr->last_level + 1, internalformat, pr->width0);
7218 } else {
7219 for (level = 0; level <= pr->last_level; level++) {
7220 unsigned mwidth = u_minify(pr->width0, level);
7221 glTexImage1D(gr->target, level, internalformat, mwidth, 0,
7222 glformat, gltype, NULL);
7223 }
7224 }
7225 } else {
7226 if (format_can_texture_storage)
7227 glTexStorage2D(gr->target, pr->last_level + 1, internalformat, pr->width0,
7228 gr->target == GL_TEXTURE_1D_ARRAY ? pr->array_size : pr->height0);
7229 else {
7230 for (level = 0; level <= pr->last_level; level++) {
7231 unsigned mwidth = u_minify(pr->width0, level);
7232 unsigned mheight = u_minify(pr->height0, level);
7233 glTexImage2D(gr->target, level, internalformat, mwidth,
7234 gr->target == GL_TEXTURE_1D_ARRAY ? pr->array_size : mheight,
7235 0, glformat, gltype, NULL);
7236 }
7237 }
7238 }
7239 }
7240
7241 if (!format_can_texture_storage) {
7242 glTexParameteri(gr->target, GL_TEXTURE_BASE_LEVEL, 0);
7243 glTexParameteri(gr->target, GL_TEXTURE_MAX_LEVEL, pr->last_level);
7244 }
7245
7246 glBindTexture(gr->target, 0);
7247
7248 if (image_oes && gr->gbm_bo) {
7249 #ifdef ENABLE_MINIGBM_ALLOCATION
7250 if (!has_bit(gr->storage_bits, VREND_STORAGE_GL_BUFFER) &&
7251 !vrend_format_can_texture_view(gr->base.format)) {
7252 for (int i = 0; i < gbm_bo_get_plane_count(gr->gbm_bo); i++) {
7253 gr->aux_plane_egl_image[i] =
7254 virgl_egl_aux_plane_image_from_gbm_bo(egl, gr->gbm_bo, i);
7255 }
7256 }
7257 #endif
7258 }
7259
7260 gt->state.max_lod = -1;
7261 gt->cur_swizzle[0] = gt->cur_swizzle[1] = gt->cur_swizzle[2] = gt->cur_swizzle[3] = -1;
7262 gt->cur_base = -1;
7263 gt->cur_max = 10000;
7264 return 0;
7265 }
7266
7267 static struct vrend_resource *
vrend_resource_create(const struct vrend_renderer_resource_create_args * args)7268 vrend_resource_create(const struct vrend_renderer_resource_create_args *args)
7269 {
7270 struct vrend_resource *gr;
7271 int ret;
7272 char error_string[256];
7273
7274 ret = check_resource_valid(args, error_string);
7275 if (ret) {
7276 vrend_printf("%s, Illegal resource parameters, error: %s\n", __func__, error_string);
7277 return NULL;
7278 }
7279
7280 gr = (struct vrend_resource *)CALLOC_STRUCT(vrend_texture);
7281 if (!gr)
7282 return NULL;
7283
7284 vrend_renderer_resource_copy_args(args, gr);
7285 gr->storage_bits = VREND_STORAGE_GUEST_MEMORY;
7286
7287 if (args->flags & VIRGL_RESOURCE_Y_0_TOP)
7288 gr->y_0_top = true;
7289
7290 pipe_reference_init(&gr->base.reference, 1);
7291
7292 return gr;
7293 }
7294
7295 struct pipe_resource *
vrend_renderer_resource_create(const struct vrend_renderer_resource_create_args * args,void * image_oes)7296 vrend_renderer_resource_create(const struct vrend_renderer_resource_create_args *args,
7297 void *image_oes)
7298 {
7299 struct vrend_resource *gr;
7300 int ret;
7301
7302 gr = vrend_resource_create(args);
7303 if (!gr)
7304 return NULL;
7305
7306 if (args->target == PIPE_BUFFER) {
7307 ret = vrend_resource_alloc_buffer(gr, args->flags);
7308 } else {
7309 const enum virgl_formats format = gr->base.format;
7310 ret = vrend_resource_alloc_texture(gr, format, image_oes);
7311 }
7312
7313 if (ret) {
7314 FREE(gr);
7315 return NULL;
7316 }
7317
7318 return &gr->base;
7319 }
7320
vrend_renderer_resource_destroy(struct vrend_resource * res)7321 void vrend_renderer_resource_destroy(struct vrend_resource *res)
7322 {
7323 if (has_bit(res->storage_bits, VREND_STORAGE_GL_TEXTURE)) {
7324 glDeleteTextures(1, &res->id);
7325 } else if (has_bit(res->storage_bits, VREND_STORAGE_GL_BUFFER)) {
7326 glDeleteBuffers(1, &res->id);
7327 if (res->tbo_tex_id)
7328 glDeleteTextures(1, &res->tbo_tex_id);
7329 } else if (has_bit(res->storage_bits, VREND_STORAGE_HOST_SYSTEM_MEMORY)) {
7330 free(res->ptr);
7331 }
7332
7333 if (res->rbo_id) {
7334 glDeleteRenderbuffers(1, &res->rbo_id);
7335 }
7336
7337 if (has_bit(res->storage_bits, VREND_STORAGE_GL_MEMOBJ)) {
7338 glDeleteMemoryObjectsEXT(1, &res->memobj);
7339 }
7340
7341 #if HAVE_EPOXY_EGL_H
7342 if (res->egl_image) {
7343 virgl_egl_image_destroy(egl, res->egl_image);
7344 for (unsigned i = 0; i < ARRAY_SIZE(res->aux_plane_egl_image); i++) {
7345 if (res->aux_plane_egl_image[i]) {
7346 virgl_egl_image_destroy(egl, res->aux_plane_egl_image[i]);
7347 }
7348 }
7349 }
7350 #endif
7351 #ifdef ENABLE_MINIGBM_ALLOCATION
7352 if (res->gbm_bo)
7353 gbm_bo_destroy(res->gbm_bo);
7354 #endif
7355
7356 free(res);
7357 }
7358
7359 struct virgl_sub_upload_data {
7360 GLenum target;
7361 struct pipe_box *box;
7362 };
7363
iov_buffer_upload(void * cookie,uint32_t doff,void * src,int len)7364 static void iov_buffer_upload(void *cookie, uint32_t doff, void *src, int len)
7365 {
7366 struct virgl_sub_upload_data *d = cookie;
7367 glBufferSubData(d->target, d->box->x + doff, len, src);
7368 }
7369
vrend_scale_depth(void * ptr,int size,float scale_val)7370 static void vrend_scale_depth(void *ptr, int size, float scale_val)
7371 {
7372 GLuint *ival = ptr;
7373 const GLfloat myscale = 1.0f / 0xffffff;
7374 int i;
7375 for (i = 0; i < size / 4; i++) {
7376 GLuint value = ival[i];
7377 GLfloat d = ((float)(value >> 8) * myscale) * scale_val;
7378 d = CLAMP(d, 0.0F, 1.0F);
7379 ival[i] = (int)(d / myscale) << 8;
7380 }
7381 }
7382
read_transfer_data(const struct iovec * iov,unsigned int num_iovs,char * data,enum virgl_formats format,uint64_t offset,uint32_t src_stride,uint32_t src_layer_stride,struct pipe_box * box,bool invert)7383 static void read_transfer_data(const struct iovec *iov,
7384 unsigned int num_iovs,
7385 char *data,
7386 enum virgl_formats format,
7387 uint64_t offset,
7388 uint32_t src_stride,
7389 uint32_t src_layer_stride,
7390 struct pipe_box *box,
7391 bool invert)
7392 {
7393 int blsize = util_format_get_blocksize(format);
7394 uint32_t size = vrend_get_iovec_size(iov, num_iovs);
7395 uint32_t send_size = util_format_get_nblocks(format, box->width,
7396 box->height) * blsize * box->depth;
7397 uint32_t bwx = util_format_get_nblocksx(format, box->width) * blsize;
7398 int32_t bh = util_format_get_nblocksy(format, box->height);
7399 int d, h;
7400
7401 if ((send_size == size || bh == 1) && !invert && box->depth == 1)
7402 vrend_read_from_iovec(iov, num_iovs, offset, data, send_size);
7403 else {
7404 if (invert) {
7405 for (d = 0; d < box->depth; d++) {
7406 uint32_t myoffset = offset + d * src_layer_stride;
7407 for (h = bh - 1; h >= 0; h--) {
7408 void *ptr = data + (h * bwx) + d * (bh * bwx);
7409 vrend_read_from_iovec(iov, num_iovs, myoffset, ptr, bwx);
7410 myoffset += src_stride;
7411 }
7412 }
7413 } else {
7414 for (d = 0; d < box->depth; d++) {
7415 uint32_t myoffset = offset + d * src_layer_stride;
7416 for (h = 0; h < bh; h++) {
7417 void *ptr = data + (h * bwx) + d * (bh * bwx);
7418 vrend_read_from_iovec(iov, num_iovs, myoffset, ptr, bwx);
7419 myoffset += src_stride;
7420 }
7421 }
7422 }
7423 }
7424 }
7425
write_transfer_data(struct pipe_resource * res,const struct iovec * iov,unsigned num_iovs,char * data,uint32_t dst_stride,struct pipe_box * box,uint32_t level,uint64_t offset,bool invert)7426 static void write_transfer_data(struct pipe_resource *res,
7427 const struct iovec *iov,
7428 unsigned num_iovs,
7429 char *data,
7430 uint32_t dst_stride,
7431 struct pipe_box *box,
7432 uint32_t level,
7433 uint64_t offset,
7434 bool invert)
7435 {
7436 int blsize = util_format_get_blocksize(res->format);
7437 uint32_t size = vrend_get_iovec_size(iov, num_iovs);
7438 uint32_t send_size = util_format_get_nblocks(res->format, box->width,
7439 box->height) * blsize * box->depth;
7440 uint32_t bwx = util_format_get_nblocksx(res->format, box->width) * blsize;
7441 int32_t bh = util_format_get_nblocksy(res->format, box->height);
7442 int d, h;
7443 uint32_t stride = dst_stride ? dst_stride : util_format_get_nblocksx(res->format, u_minify(res->width0, level)) * blsize;
7444
7445 if ((send_size == size || bh == 1) && !invert && box->depth == 1) {
7446 vrend_write_to_iovec(iov, num_iovs, offset, data, send_size);
7447 } else if (invert) {
7448 for (d = 0; d < box->depth; d++) {
7449 uint32_t myoffset = offset + d * stride * u_minify(res->height0, level);
7450 for (h = bh - 1; h >= 0; h--) {
7451 void *ptr = data + (h * bwx) + d * (bh * bwx);
7452 vrend_write_to_iovec(iov, num_iovs, myoffset, ptr, bwx);
7453 myoffset += stride;
7454 }
7455 }
7456 } else {
7457 for (d = 0; d < box->depth; d++) {
7458 uint32_t myoffset = offset + d * stride * u_minify(res->height0, level);
7459 for (h = 0; h < bh; h++) {
7460 void *ptr = data + (h * bwx) + d * (bh * bwx);
7461 vrend_write_to_iovec(iov, num_iovs, myoffset, ptr, bwx);
7462 myoffset += stride;
7463 }
7464 }
7465 }
7466 }
7467
check_transfer_iovec(struct vrend_resource * res,const struct vrend_transfer_info * info)7468 static bool check_transfer_iovec(struct vrend_resource *res,
7469 const struct vrend_transfer_info *info)
7470 {
7471 return (info->iovec && info->iovec_cnt) || res->iov;
7472 }
7473
check_transfer_bounds(struct vrend_resource * res,const struct vrend_transfer_info * info)7474 static bool check_transfer_bounds(struct vrend_resource *res,
7475 const struct vrend_transfer_info *info)
7476 {
7477 int lwidth, lheight;
7478
7479 /* check mipmap level is in bounds */
7480 if (info->level > res->base.last_level)
7481 return false;
7482 if (info->box->x < 0 || info->box->y < 0)
7483 return false;
7484 /* these will catch bad y/z/w/d with 1D textures etc */
7485 lwidth = u_minify(res->base.width0, info->level);
7486 if (info->box->width > lwidth || info->box->width < 0)
7487 return false;
7488 if (info->box->x > lwidth)
7489 return false;
7490 if (info->box->width + info->box->x > lwidth)
7491 return false;
7492
7493 lheight = u_minify(res->base.height0, info->level);
7494 if (info->box->height > lheight || info->box->height < 0)
7495 return false;
7496 if (info->box->y > lheight)
7497 return false;
7498 if (info->box->height + info->box->y > lheight)
7499 return false;
7500
7501 if (res->base.target == PIPE_TEXTURE_3D) {
7502 int ldepth = u_minify(res->base.depth0, info->level);
7503 if (info->box->depth > ldepth || info->box->depth < 0)
7504 return false;
7505 if (info->box->z > ldepth)
7506 return false;
7507 if (info->box->z + info->box->depth > ldepth)
7508 return false;
7509 } else {
7510 if (info->box->depth > (int)res->base.array_size)
7511 return false;
7512 if (info->box->z > (int)res->base.array_size)
7513 return false;
7514 if (info->box->z + info->box->depth > (int)res->base.array_size)
7515 return false;
7516 }
7517
7518 return true;
7519 }
7520
7521 /* Calculate the size of the memory needed to hold all the data of a
7522 * transfer for particular stride values.
7523 */
vrend_transfer_size(struct vrend_resource * vres,const struct vrend_transfer_info * info,uint32_t stride,uint32_t layer_stride)7524 static uint64_t vrend_transfer_size(struct vrend_resource *vres,
7525 const struct vrend_transfer_info *info,
7526 uint32_t stride, uint32_t layer_stride)
7527 {
7528 struct pipe_resource *pres = &vres->base;
7529 struct pipe_box *box = info->box;
7530 uint64_t size;
7531 /* For purposes of size calculation, assume that invalid dimension values
7532 * correspond to 1.
7533 */
7534 int w = box->width > 0 ? box->width : 1;
7535 int h = box->height > 0 ? box->height : 1;
7536 int d = box->depth > 0 ? box->depth : 1;
7537 int nblocksx = util_format_get_nblocksx(pres->format, w);
7538 int nblocksy = util_format_get_nblocksy(pres->format, h);
7539
7540 /* Calculate the box size, not including the last layer. The last layer
7541 * is the only one which may be incomplete, and is the only layer for
7542 * non 3d/2d-array formats.
7543 */
7544 size = (d - 1) * layer_stride;
7545 /* Calculate the size of the last (or only) layer, not including the last
7546 * block row. The last block row is the only one which may be incomplete and
7547 * is the only block row for non 2d/1d-array formats.
7548 */
7549 size += (nblocksy - 1) * stride;
7550 /* Calculate the size of the the last (or only) block row. */
7551 size += nblocksx * util_format_get_blocksize(pres->format);
7552
7553 return size;
7554 }
7555
check_iov_bounds(struct vrend_resource * res,const struct vrend_transfer_info * info,const struct iovec * iov,int num_iovs)7556 static bool check_iov_bounds(struct vrend_resource *res,
7557 const struct vrend_transfer_info *info,
7558 const struct iovec *iov, int num_iovs)
7559 {
7560 GLuint transfer_size;
7561 GLuint iovsize = vrend_get_iovec_size(iov, num_iovs);
7562 GLuint valid_stride, valid_layer_stride;
7563
7564 /* If the transfer specifies a stride, verify that it's at least as large as
7565 * the minimum required for the transfer. If no stride is specified use the
7566 * image stride for the specified level.
7567 */
7568 if (info->stride) {
7569 GLuint min_stride = util_format_get_stride(res->base.format, info->box->width);
7570 if (info->stride < min_stride)
7571 return false;
7572 valid_stride = info->stride;
7573 } else {
7574 valid_stride = util_format_get_stride(res->base.format,
7575 u_minify(res->base.width0, info->level));
7576 }
7577
7578 /* If the transfer specifies a layer_stride, verify that it's at least as
7579 * large as the minimum required for the transfer. If no layer_stride is
7580 * specified use the image layer_stride for the specified level.
7581 */
7582 if (info->layer_stride) {
7583 GLuint min_layer_stride = util_format_get_2d_size(res->base.format,
7584 valid_stride,
7585 info->box->height);
7586 if (info->layer_stride < min_layer_stride)
7587 return false;
7588 valid_layer_stride = info->layer_stride;
7589 } else {
7590 valid_layer_stride =
7591 util_format_get_2d_size(res->base.format, valid_stride,
7592 u_minify(res->base.height0, info->level));
7593 }
7594
7595 /* Calculate the size required for the transferred data, based on the
7596 * calculated or provided strides, and ensure that the iov, starting at the
7597 * specified offset, is able to hold at least that size.
7598 */
7599 transfer_size = vrend_transfer_size(res, info,
7600 valid_stride,
7601 valid_layer_stride);
7602 if (iovsize < info->offset)
7603 return false;
7604 if (iovsize < transfer_size)
7605 return false;
7606 if (iovsize < info->offset + transfer_size)
7607 return false;
7608
7609 return true;
7610 }
7611
get_current_texture(GLenum target,GLint * tex)7612 static void get_current_texture(GLenum target, GLint* tex) {
7613 switch (target) {
7614 #define GET_TEXTURE(a) \
7615 case GL_TEXTURE_ ## a: \
7616 glGetIntegerv(GL_TEXTURE_BINDING_ ## a, tex); return
7617 GET_TEXTURE(1D);
7618 GET_TEXTURE(2D);
7619 GET_TEXTURE(3D);
7620 GET_TEXTURE(1D_ARRAY);
7621 GET_TEXTURE(2D_ARRAY);
7622 GET_TEXTURE(RECTANGLE);
7623 GET_TEXTURE(CUBE_MAP);
7624 GET_TEXTURE(CUBE_MAP_ARRAY);
7625 GET_TEXTURE(BUFFER);
7626 GET_TEXTURE(2D_MULTISAMPLE);
7627 GET_TEXTURE(2D_MULTISAMPLE_ARRAY);
7628 #undef GET_TEXTURE
7629 default:
7630 vrend_printf("Unknown texture target %x\n", target);
7631 }
7632 }
7633
vrend_swizzle_data_bgra(uint64_t size,void * data)7634 static void vrend_swizzle_data_bgra(uint64_t size, void *data) {
7635 const size_t bpp = 4;
7636 const size_t num_pixels = size / bpp;
7637 for (size_t i = 0; i < num_pixels; ++i) {
7638 unsigned char *pixel = ((unsigned char*)data) + i * bpp;
7639 unsigned char first = *pixel;
7640 *pixel = *(pixel + 2);
7641 *(pixel + 2) = first;
7642 }
7643 }
7644
vrend_renderer_transfer_write_iov(struct vrend_context * ctx,struct vrend_resource * res,const struct iovec * iov,int num_iovs,const struct vrend_transfer_info * info)7645 static int vrend_renderer_transfer_write_iov(struct vrend_context *ctx,
7646 struct vrend_resource *res,
7647 const struct iovec *iov, int num_iovs,
7648 const struct vrend_transfer_info *info)
7649 {
7650 void *data;
7651
7652 if ((is_only_bit(res->storage_bits, VREND_STORAGE_GUEST_MEMORY) ||
7653 has_bit(res->storage_bits, VREND_STORAGE_HOST_SYSTEM_MEMORY)) && res->iov) {
7654 return vrend_copy_iovec(iov, num_iovs, info->offset,
7655 res->iov, res->num_iovs, info->box->x,
7656 info->box->width, res->ptr);
7657 }
7658
7659 if (has_bit(res->storage_bits, VREND_STORAGE_HOST_SYSTEM_MEMORY)) {
7660 assert(!res->iov);
7661 vrend_read_from_iovec(iov, num_iovs, info->offset,
7662 res->ptr + info->box->x, info->box->width);
7663 return 0;
7664 }
7665
7666 if (has_bit(res->storage_bits, VREND_STORAGE_GL_BUFFER)) {
7667 GLuint map_flags = GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_WRITE_BIT;
7668 struct virgl_sub_upload_data d;
7669 d.box = info->box;
7670 d.target = res->target;
7671
7672 if (!info->synchronized)
7673 map_flags |= GL_MAP_UNSYNCHRONIZED_BIT;
7674
7675 glBindBufferARB(res->target, res->id);
7676 data = glMapBufferRange(res->target, info->box->x, info->box->width, map_flags);
7677 if (data == NULL) {
7678 vrend_printf("map failed for element buffer\n");
7679 vrend_read_from_iovec_cb(iov, num_iovs, info->offset, info->box->width, &iov_buffer_upload, &d);
7680 } else {
7681 vrend_read_from_iovec(iov, num_iovs, info->offset, data, info->box->width);
7682 glUnmapBuffer(res->target);
7683 }
7684 glBindBufferARB(res->target, 0);
7685 } else {
7686 GLenum glformat;
7687 GLenum gltype;
7688 int need_temp = 0;
7689 int elsize = util_format_get_blocksize(res->base.format);
7690 int x = 0, y = 0;
7691 bool compressed;
7692 bool invert = false;
7693 float depth_scale;
7694 GLuint send_size = 0;
7695 uint32_t stride = info->stride;
7696 uint32_t layer_stride = info->layer_stride;
7697
7698 if (ctx)
7699 vrend_use_program(ctx->sub, 0);
7700 else
7701 glUseProgram(0);
7702
7703 if (!stride)
7704 stride = util_format_get_nblocksx(res->base.format, u_minify(res->base.width0, info->level)) * elsize;
7705
7706 if (!layer_stride)
7707 layer_stride = util_format_get_2d_size(res->base.format, stride,
7708 u_minify(res->base.height0, info->level));
7709
7710 compressed = util_format_is_compressed(res->base.format);
7711 if (num_iovs > 1 || compressed) {
7712 need_temp = true;
7713 }
7714
7715 if (vrend_state.use_gles && vrend_format_is_bgra(res->base.format) &&
7716 !vrend_resource_is_emulated_bgra(res))
7717 need_temp = true;
7718
7719 if (vrend_state.use_core_profile == true &&
7720 (res->y_0_top || (res->base.format == VIRGL_FORMAT_Z24X8_UNORM))) {
7721 need_temp = true;
7722 if (res->y_0_top)
7723 invert = true;
7724 }
7725
7726 send_size = util_format_get_nblocks(res->base.format, info->box->width,
7727 info->box->height) * elsize;
7728 if (res->target == GL_TEXTURE_3D ||
7729 res->target == GL_TEXTURE_2D_ARRAY ||
7730 res->target == GL_TEXTURE_CUBE_MAP_ARRAY)
7731 send_size *= info->box->depth;
7732
7733 if (need_temp) {
7734 data = malloc(send_size);
7735 if (!data)
7736 return ENOMEM;
7737 read_transfer_data(iov, num_iovs, data, res->base.format, info->offset,
7738 stride, layer_stride, info->box, invert);
7739 } else {
7740 if (send_size > iov[0].iov_len - info->offset)
7741 return EINVAL;
7742 data = (char*)iov[0].iov_base + info->offset;
7743 }
7744
7745 if (!need_temp) {
7746 assert(stride);
7747 glPixelStorei(GL_UNPACK_ROW_LENGTH, stride / elsize);
7748 glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, layer_stride / stride);
7749 } else
7750 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
7751
7752 switch (elsize) {
7753 case 1:
7754 case 3:
7755 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
7756 break;
7757 case 2:
7758 case 6:
7759 glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
7760 break;
7761 case 4:
7762 default:
7763 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
7764 break;
7765 case 8:
7766 glPixelStorei(GL_UNPACK_ALIGNMENT, 8);
7767 break;
7768 }
7769
7770 glformat = tex_conv_table[res->base.format].glformat;
7771 gltype = tex_conv_table[res->base.format].gltype;
7772
7773 if ((!vrend_state.use_core_profile) && (res->y_0_top)) {
7774 GLuint buffers;
7775 GLuint fb_id;
7776
7777 glGenFramebuffers(1, &fb_id);
7778 glBindFramebuffer(GL_FRAMEBUFFER, fb_id);
7779 vrend_fb_bind_texture(res, 0, info->level, 0);
7780
7781 buffers = GL_COLOR_ATTACHMENT0;
7782 glDrawBuffers(1, &buffers);
7783 glDisable(GL_BLEND);
7784 if (ctx) {
7785 vrend_depth_test_enable(ctx, false);
7786 vrend_alpha_test_enable(ctx, false);
7787 vrend_stencil_test_enable(ctx->sub, false);
7788 } else {
7789 glDisable(GL_DEPTH_TEST);
7790 glDisable(GL_ALPHA_TEST);
7791 glDisable(GL_STENCIL_TEST);
7792 }
7793 glPixelZoom(1.0f, res->y_0_top ? -1.0f : 1.0f);
7794 glWindowPos2i(info->box->x, res->y_0_top ? (int)res->base.height0 - info->box->y : info->box->y);
7795 glDrawPixels(info->box->width, info->box->height, glformat, gltype,
7796 data);
7797 glDeleteFramebuffers(1, &fb_id);
7798 } else {
7799 uint32_t comp_size;
7800 GLint old_tex = 0;
7801 get_current_texture(res->target, &old_tex);
7802 glBindTexture(res->target, res->id);
7803
7804 if (compressed) {
7805 glformat = tex_conv_table[res->base.format].internalformat;
7806 comp_size = util_format_get_nblocks(res->base.format, info->box->width,
7807 info->box->height) * util_format_get_blocksize(res->base.format);
7808 }
7809
7810 if (glformat == 0) {
7811 glformat = GL_BGRA;
7812 gltype = GL_UNSIGNED_BYTE;
7813 }
7814
7815 x = info->box->x;
7816 y = invert ? (int)res->base.height0 - info->box->y - info->box->height : info->box->y;
7817
7818 /* GLES doesn't allow format conversions, which we need for BGRA resources with RGBA
7819 * internal format. So we fallback to performing a CPU swizzle before uploading. */
7820 if (vrend_state.use_gles && vrend_format_is_bgra(res->base.format) &&
7821 !vrend_resource_is_emulated_bgra(res)) {
7822 VREND_DEBUG(dbg_bgra, ctx, "manually swizzling bgra->rgba on upload since gles+bgra\n");
7823 vrend_swizzle_data_bgra(send_size, data);
7824 }
7825
7826 /* mipmaps are usually passed in one iov, and we need to keep the offset
7827 * into the data in case we want to read back the data of a surface
7828 * that can not be rendered. Since we can not assume that the whole texture
7829 * is filled, we evaluate the offset for origin (0,0,0). Since it is also
7830 * possible that a resource is reused and resized update the offset every time.
7831 */
7832 if (info->level < VR_MAX_TEXTURE_2D_LEVELS) {
7833 int64_t level_height = u_minify(res->base.height0, info->level);
7834 res->mipmap_offsets[info->level] = info->offset -
7835 ((info->box->z * level_height + y) * stride + x * elsize);
7836 }
7837
7838 if (res->base.format == VIRGL_FORMAT_Z24X8_UNORM) {
7839 /* we get values from the guest as 24-bit scaled integers
7840 but we give them to the host GL and it interprets them
7841 as 32-bit scaled integers, so we need to scale them here */
7842 depth_scale = 256.0;
7843 if (!vrend_state.use_core_profile)
7844 glPixelTransferf(GL_DEPTH_SCALE, depth_scale);
7845 else
7846 vrend_scale_depth(data, send_size, depth_scale);
7847 }
7848 if (res->target == GL_TEXTURE_CUBE_MAP) {
7849 GLenum ctarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + info->box->z;
7850 if (compressed) {
7851 glCompressedTexSubImage2D(ctarget, info->level, x, y,
7852 info->box->width, info->box->height,
7853 glformat, comp_size, data);
7854 } else {
7855 glTexSubImage2D(ctarget, info->level, x, y, info->box->width, info->box->height,
7856 glformat, gltype, data);
7857 }
7858 } else if (res->target == GL_TEXTURE_3D || res->target == GL_TEXTURE_2D_ARRAY || res->target == GL_TEXTURE_CUBE_MAP_ARRAY) {
7859 if (compressed) {
7860 glCompressedTexSubImage3D(res->target, info->level, x, y, info->box->z,
7861 info->box->width, info->box->height, info->box->depth,
7862 glformat, comp_size, data);
7863 } else {
7864 glTexSubImage3D(res->target, info->level, x, y, info->box->z,
7865 info->box->width, info->box->height, info->box->depth,
7866 glformat, gltype, data);
7867 }
7868 } else if (res->target == GL_TEXTURE_1D) {
7869 if (vrend_state.use_gles) {
7870 /* Covers both compressed and none compressed. */
7871 report_gles_missing_func(ctx, "gl[Compressed]TexSubImage1D");
7872 } else if (compressed) {
7873 glCompressedTexSubImage1D(res->target, info->level, info->box->x,
7874 info->box->width,
7875 glformat, comp_size, data);
7876 } else {
7877 glTexSubImage1D(res->target, info->level, info->box->x, info->box->width,
7878 glformat, gltype, data);
7879 }
7880 } else {
7881 if (compressed) {
7882 glCompressedTexSubImage2D(res->target, info->level, x, res->target == GL_TEXTURE_1D_ARRAY ? info->box->z : y,
7883 info->box->width, info->box->height,
7884 glformat, comp_size, data);
7885 } else {
7886 glTexSubImage2D(res->target, info->level, x, res->target == GL_TEXTURE_1D_ARRAY ? info->box->z : y,
7887 info->box->width,
7888 res->target == GL_TEXTURE_1D_ARRAY ? info->box->depth : info->box->height,
7889 glformat, gltype, data);
7890 }
7891 }
7892 if (res->base.format == VIRGL_FORMAT_Z24X8_UNORM) {
7893 if (!vrend_state.use_core_profile)
7894 glPixelTransferf(GL_DEPTH_SCALE, 1.0);
7895 }
7896 glBindTexture(res->target, old_tex);
7897 }
7898
7899 if (stride && !need_temp) {
7900 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
7901 glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
7902 }
7903
7904 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
7905
7906 if (need_temp)
7907 free(data);
7908 }
7909 return 0;
7910 }
7911
vrend_get_texture_depth(struct vrend_resource * res,uint32_t level)7912 static uint32_t vrend_get_texture_depth(struct vrend_resource *res, uint32_t level)
7913 {
7914 uint32_t depth = 1;
7915 if (res->target == GL_TEXTURE_3D)
7916 depth = u_minify(res->base.depth0, level);
7917 else if (res->target == GL_TEXTURE_1D_ARRAY || res->target == GL_TEXTURE_2D_ARRAY ||
7918 res->target == GL_TEXTURE_CUBE_MAP || res->target == GL_TEXTURE_CUBE_MAP_ARRAY)
7919 depth = res->base.array_size;
7920
7921 return depth;
7922 }
7923
vrend_transfer_send_getteximage(struct vrend_resource * res,const struct iovec * iov,int num_iovs,const struct vrend_transfer_info * info)7924 static int vrend_transfer_send_getteximage(struct vrend_resource *res,
7925 const struct iovec *iov, int num_iovs,
7926 const struct vrend_transfer_info *info)
7927 {
7928 GLenum format, type;
7929 uint32_t tex_size;
7930 char *data;
7931 int elsize = util_format_get_blocksize(res->base.format);
7932 int compressed = util_format_is_compressed(res->base.format);
7933 GLenum target;
7934 uint32_t send_offset = 0;
7935 format = tex_conv_table[res->base.format].glformat;
7936 type = tex_conv_table[res->base.format].gltype;
7937
7938 if (compressed)
7939 format = tex_conv_table[res->base.format].internalformat;
7940
7941 tex_size = util_format_get_nblocks(res->base.format, u_minify(res->base.width0, info->level), u_minify(res->base.height0, info->level)) *
7942 util_format_get_blocksize(res->base.format) * vrend_get_texture_depth(res, info->level);
7943
7944 if (info->box->z && res->target != GL_TEXTURE_CUBE_MAP) {
7945 send_offset = util_format_get_nblocks(res->base.format, u_minify(res->base.width0, info->level), u_minify(res->base.height0, info->level)) * util_format_get_blocksize(res->base.format) * info->box->z;
7946 }
7947
7948 data = malloc(tex_size);
7949 if (!data)
7950 return ENOMEM;
7951
7952 switch (elsize) {
7953 case 1:
7954 glPixelStorei(GL_PACK_ALIGNMENT, 1);
7955 break;
7956 case 2:
7957 glPixelStorei(GL_PACK_ALIGNMENT, 2);
7958 break;
7959 case 4:
7960 default:
7961 glPixelStorei(GL_PACK_ALIGNMENT, 4);
7962 break;
7963 case 8:
7964 glPixelStorei(GL_PACK_ALIGNMENT, 8);
7965 break;
7966 }
7967
7968 GLint old_tex = 0;
7969 get_current_texture(res->target, &old_tex);
7970 glBindTexture(res->target, res->id);
7971 if (res->target == GL_TEXTURE_CUBE_MAP) {
7972 target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + info->box->z;
7973 } else
7974 target = res->target;
7975
7976 if (compressed) {
7977 if (has_feature(feat_arb_robustness)) {
7978 glGetnCompressedTexImageARB(target, info->level, tex_size, data);
7979 } else if (vrend_state.use_gles) {
7980 report_gles_missing_func(NULL, "glGetCompressedTexImage");
7981 } else {
7982 glGetCompressedTexImage(target, info->level, data);
7983 }
7984 } else {
7985 if (has_feature(feat_arb_robustness)) {
7986 glGetnTexImageARB(target, info->level, format, type, tex_size, data);
7987 } else if (vrend_state.use_gles) {
7988 report_gles_missing_func(NULL, "glGetTexImage");
7989 } else {
7990 glGetTexImage(target, info->level, format, type, data);
7991 }
7992 }
7993
7994 glPixelStorei(GL_PACK_ALIGNMENT, 4);
7995
7996 write_transfer_data(&res->base, iov, num_iovs, data + send_offset,
7997 info->stride, info->box, info->level, info->offset,
7998 false);
7999 free(data);
8000 glBindTexture(res->target, old_tex);
8001 return 0;
8002 }
8003
do_readpixels(struct vrend_resource * res,int idx,uint32_t level,uint32_t layer,GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,GLsizei bufSize,void * data)8004 static void do_readpixels(struct vrend_resource *res,
8005 int idx, uint32_t level, uint32_t layer,
8006 GLint x, GLint y,
8007 GLsizei width, GLsizei height,
8008 GLenum format, GLenum type,
8009 GLsizei bufSize, void *data)
8010 {
8011 GLuint fb_id;
8012
8013 glGenFramebuffers(1, &fb_id);
8014 glBindFramebuffer(GL_FRAMEBUFFER, fb_id);
8015
8016 vrend_fb_bind_texture(res, idx, level, layer);
8017
8018 /* Warn if the driver doesn't agree about the read format and type.
8019 On desktop GL we can use basically any format and type to glReadPixels,
8020 so we picked the format and type that matches the native format.
8021
8022 But on GLES we are limited to a very few set, luckily most GLES
8023 implementations should return type and format that match the native
8024 formats, and can be used for glReadPixels acording to the GLES spec.
8025
8026 But we have found that at least Mesa returned the wrong formats, again
8027 luckily we are able to change Mesa. But just in case there are more bad
8028 drivers out there, or we mess up the format somewhere, we warn here. */
8029 if (vrend_state.use_gles) {
8030 GLint imp;
8031 if (type != GL_UNSIGNED_BYTE && type != GL_UNSIGNED_INT &&
8032 type != GL_INT && type != GL_FLOAT) {
8033 glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &imp);
8034 if (imp != (GLint)type) {
8035 vrend_printf( "GL_IMPLEMENTATION_COLOR_READ_TYPE is not expected native type 0x%x != imp 0x%x\n", type, imp);
8036 }
8037 }
8038 if (format != GL_RGBA && format != GL_RGBA_INTEGER) {
8039 glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &imp);
8040 if (imp != (GLint)format) {
8041 vrend_printf( "GL_IMPLEMENTATION_COLOR_READ_FORMAT is not expected native format 0x%x != imp 0x%x\n", format, imp);
8042 }
8043 }
8044 }
8045
8046 if (has_feature(feat_arb_robustness))
8047 glReadnPixelsARB(x, y, width, height, format, type, bufSize, data);
8048 else if (has_feature(feat_gles_khr_robustness))
8049 glReadnPixelsKHR(x, y, width, height, format, type, bufSize, data);
8050 else
8051 glReadPixels(x, y, width, height, format, type, data);
8052
8053 glDeleteFramebuffers(1, &fb_id);
8054 }
8055
vrend_transfer_send_readpixels(struct vrend_context * ctx,struct vrend_resource * res,const struct iovec * iov,int num_iovs,const struct vrend_transfer_info * info)8056 static int vrend_transfer_send_readpixels(struct vrend_context *ctx,
8057 struct vrend_resource *res,
8058 const struct iovec *iov, int num_iovs,
8059 const struct vrend_transfer_info *info)
8060 {
8061 char *myptr = (char*)iov[0].iov_base + info->offset;
8062 int need_temp = 0;
8063 char *data;
8064 bool actually_invert, separate_invert = false;
8065 GLenum format, type;
8066 GLint y1;
8067 uint32_t send_size = 0;
8068 uint32_t h = u_minify(res->base.height0, info->level);
8069 int elsize = util_format_get_blocksize(res->base.format);
8070 float depth_scale;
8071 int row_stride = info->stride / elsize;
8072 GLint old_fbo;
8073
8074 if (ctx)
8075 vrend_use_program(ctx->sub, 0);
8076 else
8077 glUseProgram(0);
8078
8079 enum virgl_formats fmt = res->base.format;
8080
8081 format = tex_conv_table[fmt].glformat;
8082 type = tex_conv_table[fmt].gltype;
8083 /* if we are asked to invert and reading from a front then don't */
8084
8085 actually_invert = res->y_0_top;
8086
8087 if (actually_invert && !has_feature(feat_mesa_invert))
8088 separate_invert = true;
8089
8090 #ifdef PIPE_ARCH_BIG_ENDIAN
8091 glPixelStorei(GL_PACK_SWAP_BYTES, 1);
8092 #endif
8093
8094 if (num_iovs > 1 || separate_invert)
8095 need_temp = 1;
8096
8097 if (vrend_state.use_gles && vrend_format_is_bgra(res->base.format) &&
8098 !vrend_resource_is_emulated_bgra(res))
8099 need_temp = true;
8100
8101 if (need_temp) {
8102 send_size = util_format_get_nblocks(res->base.format, info->box->width, info->box->height) * info->box->depth * util_format_get_blocksize(res->base.format);
8103 data = malloc(send_size);
8104 if (!data) {
8105 vrend_printf("malloc failed %d\n", send_size);
8106 return ENOMEM;
8107 }
8108 } else {
8109 send_size = iov[0].iov_len - info->offset;
8110 data = myptr;
8111 if (!row_stride)
8112 row_stride = util_format_get_nblocksx(res->base.format, u_minify(res->base.width0, info->level));
8113 }
8114
8115 glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_fbo);
8116
8117 if (actually_invert)
8118 y1 = h - info->box->y - info->box->height;
8119 else
8120 y1 = info->box->y;
8121
8122 if (has_feature(feat_mesa_invert) && actually_invert)
8123 glPixelStorei(GL_PACK_INVERT_MESA, 1);
8124 if (!need_temp && row_stride)
8125 glPixelStorei(GL_PACK_ROW_LENGTH, row_stride);
8126
8127 switch (elsize) {
8128 case 1:
8129 glPixelStorei(GL_PACK_ALIGNMENT, 1);
8130 break;
8131 case 2:
8132 glPixelStorei(GL_PACK_ALIGNMENT, 2);
8133 break;
8134 case 4:
8135 default:
8136 glPixelStorei(GL_PACK_ALIGNMENT, 4);
8137 break;
8138 case 8:
8139 glPixelStorei(GL_PACK_ALIGNMENT, 8);
8140 break;
8141 }
8142
8143 if (res->base.format == VIRGL_FORMAT_Z24X8_UNORM) {
8144 /* we get values from the guest as 24-bit scaled integers
8145 but we give them to the host GL and it interprets them
8146 as 32-bit scaled integers, so we need to scale them here */
8147 depth_scale = 1.0 / 256.0;
8148 if (!vrend_state.use_core_profile) {
8149 glPixelTransferf(GL_DEPTH_SCALE, depth_scale);
8150 }
8151 }
8152
8153 do_readpixels(res, 0, info->level, info->box->z, info->box->x, y1,
8154 info->box->width, info->box->height, format, type, send_size, data);
8155
8156 /* on GLES, texture-backed BGR* resources are always stored with RGB* internal format, but
8157 * the guest will expect to readback the data in BGRA format.
8158 * Since the GLES API doesn't allow format conversions like GL, we CPU-swizzle the data
8159 * on upload and need to do the same on readback.
8160 * The notable exception is externally-stored (GBM/EGL) BGR* resources, for which BGR*
8161 * byte-ordering is used instead to match external access patterns. */
8162 if (vrend_state.use_gles && vrend_format_is_bgra(res->base.format) &&
8163 !vrend_resource_is_emulated_bgra(res)) {
8164 VREND_DEBUG(dbg_bgra, ctx, "manually swizzling rgba->bgra on readback since gles+bgra\n");
8165 vrend_swizzle_data_bgra(send_size, data);
8166 }
8167
8168 if (res->base.format == VIRGL_FORMAT_Z24X8_UNORM) {
8169 if (!vrend_state.use_core_profile)
8170 glPixelTransferf(GL_DEPTH_SCALE, 1.0);
8171 else
8172 vrend_scale_depth(data, send_size, depth_scale);
8173 }
8174 if (has_feature(feat_mesa_invert) && actually_invert)
8175 glPixelStorei(GL_PACK_INVERT_MESA, 0);
8176 if (!need_temp && row_stride)
8177 glPixelStorei(GL_PACK_ROW_LENGTH, 0);
8178 glPixelStorei(GL_PACK_ALIGNMENT, 4);
8179
8180 #ifdef PIPE_ARCH_BIG_ENDIAN
8181 glPixelStorei(GL_PACK_SWAP_BYTES, 0);
8182 #endif
8183
8184 if (need_temp) {
8185 write_transfer_data(&res->base, iov, num_iovs, data,
8186 info->stride, info->box, info->level, info->offset,
8187 separate_invert);
8188 free(data);
8189 }
8190
8191 glBindFramebuffer(GL_FRAMEBUFFER, old_fbo);
8192
8193 return 0;
8194 }
8195
vrend_transfer_send_readonly(struct vrend_resource * res,const struct iovec * iov,int num_iovs,UNUSED const struct vrend_transfer_info * info)8196 static int vrend_transfer_send_readonly(struct vrend_resource *res,
8197 const struct iovec *iov, int num_iovs,
8198 UNUSED const struct vrend_transfer_info *info)
8199 {
8200 bool same_iov = true;
8201 uint i;
8202
8203 if (res->num_iovs == (uint32_t)num_iovs) {
8204 for (i = 0; i < res->num_iovs; i++) {
8205 if (res->iov[i].iov_len != iov[i].iov_len ||
8206 res->iov[i].iov_base != iov[i].iov_base) {
8207 same_iov = false;
8208 }
8209 }
8210 } else {
8211 same_iov = false;
8212 }
8213
8214 /*
8215 * When we detect that we are reading back to the same iovs that are
8216 * attached to the resource and we know that the resource can not
8217 * be rendered to (as this function is only called then), we do not
8218 * need to do anything more.
8219 */
8220 if (same_iov) {
8221 return 0;
8222 }
8223
8224 return -1;
8225 }
8226
vrend_renderer_transfer_send_iov(struct vrend_context * ctx,struct vrend_resource * res,const struct iovec * iov,int num_iovs,const struct vrend_transfer_info * info)8227 static int vrend_renderer_transfer_send_iov(struct vrend_context *ctx,
8228 struct vrend_resource *res,
8229 const struct iovec *iov, int num_iovs,
8230 const struct vrend_transfer_info *info)
8231 {
8232 if (is_only_bit(res->storage_bits, VREND_STORAGE_GUEST_MEMORY) ||
8233 (has_bit(res->storage_bits, VREND_STORAGE_HOST_SYSTEM_MEMORY) && res->iov)) {
8234 return vrend_copy_iovec(res->iov, res->num_iovs, info->box->x,
8235 iov, num_iovs, info->offset,
8236 info->box->width, res->ptr);
8237 }
8238
8239 if (has_bit(res->storage_bits, VREND_STORAGE_HOST_SYSTEM_MEMORY)) {
8240 assert(!res->iov);
8241 vrend_write_to_iovec(iov, num_iovs, info->offset,
8242 res->ptr + info->box->x, info->box->width);
8243 return 0;
8244 }
8245
8246 if (has_bit(res->storage_bits, VREND_STORAGE_GL_BUFFER)) {
8247 uint32_t send_size = info->box->width * util_format_get_blocksize(res->base.format);
8248 void *data;
8249
8250 glBindBufferARB(res->target, res->id);
8251 data = glMapBufferRange(res->target, info->box->x, info->box->width, GL_MAP_READ_BIT);
8252 if (!data)
8253 vrend_printf("unable to open buffer for reading %d\n", res->target);
8254 else
8255 vrend_write_to_iovec(iov, num_iovs, info->offset, data, send_size);
8256 glUnmapBuffer(res->target);
8257 glBindBufferARB(res->target, 0);
8258 } else {
8259 int ret = -1;
8260 bool can_readpixels = true;
8261
8262 can_readpixels = vrend_format_can_render(res->base.format) || vrend_format_is_ds(res->base.format);
8263
8264 if (can_readpixels)
8265 ret = vrend_transfer_send_readpixels(ctx, res, iov, num_iovs, info);
8266
8267 /* Can hit this on a non-error path as well. */
8268 if (ret) {
8269 if (!vrend_state.use_gles)
8270 ret = vrend_transfer_send_getteximage(res, iov, num_iovs, info);
8271 else
8272 ret = vrend_transfer_send_readonly(res, iov, num_iovs, info);
8273 }
8274
8275 return ret;
8276 }
8277 return 0;
8278 }
8279
vrend_renderer_transfer_internal(struct vrend_context * ctx,struct vrend_resource * res,const struct vrend_transfer_info * info,int transfer_mode)8280 static int vrend_renderer_transfer_internal(struct vrend_context *ctx,
8281 struct vrend_resource *res,
8282 const struct vrend_transfer_info *info,
8283 int transfer_mode)
8284 {
8285 const struct iovec *iov;
8286 int num_iovs;
8287
8288 if (!info->box)
8289 return EINVAL;
8290
8291 vrend_hw_switch_context(ctx, true);
8292
8293 assert(check_transfer_iovec(res, info));
8294 if (info->iovec && info->iovec_cnt) {
8295 iov = info->iovec;
8296 num_iovs = info->iovec_cnt;
8297 } else {
8298 iov = res->iov;
8299 num_iovs = res->num_iovs;
8300 }
8301
8302 #ifdef ENABLE_MINIGBM_ALLOCATION
8303 if (res->gbm_bo && (transfer_mode == VIRGL_TRANSFER_TO_HOST ||
8304 !has_bit(res->storage_bits, VREND_STORAGE_EGL_IMAGE))) {
8305 assert(!info->synchronized);
8306 return virgl_gbm_transfer(res->gbm_bo, transfer_mode, iov, num_iovs, info);
8307 }
8308 #endif
8309
8310 if (!check_transfer_bounds(res, info)) {
8311 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_TRANSFER_IOV_BOUNDS, res->id);
8312 return EINVAL;
8313 }
8314
8315 if (!check_iov_bounds(res, info, iov, num_iovs)) {
8316 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_TRANSFER_IOV_BOUNDS, res->id);
8317 return EINVAL;
8318 }
8319
8320 switch (transfer_mode) {
8321 case VIRGL_TRANSFER_TO_HOST:
8322 return vrend_renderer_transfer_write_iov(ctx, res, iov, num_iovs, info);
8323 case VIRGL_TRANSFER_FROM_HOST:
8324 return vrend_renderer_transfer_send_iov(ctx, res, iov, num_iovs, info);
8325
8326 default:
8327 assert(0);
8328 }
8329 return 0;
8330 }
8331
vrend_renderer_transfer_iov(struct vrend_context * ctx,uint32_t dst_handle,const struct vrend_transfer_info * info,int transfer_mode)8332 int vrend_renderer_transfer_iov(struct vrend_context *ctx,
8333 uint32_t dst_handle,
8334 const struct vrend_transfer_info *info,
8335 int transfer_mode)
8336 {
8337 struct vrend_resource *res;
8338
8339 res = vrend_renderer_ctx_res_lookup(ctx, dst_handle);
8340 if (!res || !check_transfer_iovec(res, info)) {
8341 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, dst_handle);
8342 return EINVAL;
8343 }
8344
8345 return vrend_renderer_transfer_internal(ctx, res, info,
8346 transfer_mode);
8347 }
8348
vrend_renderer_transfer_pipe(struct pipe_resource * pres,const struct vrend_transfer_info * info,int transfer_mode)8349 int vrend_renderer_transfer_pipe(struct pipe_resource *pres,
8350 const struct vrend_transfer_info *info,
8351 int transfer_mode)
8352 {
8353 struct vrend_resource *res = (struct vrend_resource *)pres;
8354 if (!check_transfer_iovec(res, info))
8355 return EINVAL;
8356
8357 return vrend_renderer_transfer_internal(vrend_state.ctx0, res, info,
8358 transfer_mode);
8359 }
8360
vrend_transfer_inline_write(struct vrend_context * ctx,uint32_t dst_handle,const struct vrend_transfer_info * info)8361 int vrend_transfer_inline_write(struct vrend_context *ctx,
8362 uint32_t dst_handle,
8363 const struct vrend_transfer_info *info)
8364 {
8365 struct vrend_resource *res;
8366
8367 res = vrend_renderer_ctx_res_lookup(ctx, dst_handle);
8368 if (!res) {
8369 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, dst_handle);
8370 return EINVAL;
8371 }
8372
8373 if (!check_transfer_bounds(res, info)) {
8374 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_CMD_BUFFER, dst_handle);
8375 return EINVAL;
8376 }
8377
8378 if (!check_iov_bounds(res, info, info->iovec, info->iovec_cnt)) {
8379 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_CMD_BUFFER, dst_handle);
8380 return EINVAL;
8381 }
8382
8383 #ifdef ENABLE_MINIGBM_ALLOCATION
8384 if (res->gbm_bo) {
8385 assert(!info->synchronized);
8386 return virgl_gbm_transfer(res->gbm_bo,
8387 VIRGL_TRANSFER_TO_HOST,
8388 info->iovec,
8389 info->iovec_cnt,
8390 info);
8391 }
8392 #endif
8393
8394 return vrend_renderer_transfer_write_iov(ctx, res, info->iovec, info->iovec_cnt, info);
8395
8396 }
8397
vrend_renderer_copy_transfer3d(struct vrend_context * ctx,uint32_t dst_handle,uint32_t src_handle,const struct vrend_transfer_info * info)8398 int vrend_renderer_copy_transfer3d(struct vrend_context *ctx,
8399 uint32_t dst_handle,
8400 uint32_t src_handle,
8401 const struct vrend_transfer_info *info)
8402 {
8403 struct vrend_resource *src_res, *dst_res;
8404
8405 src_res = vrend_renderer_ctx_res_lookup(ctx, src_handle);
8406 dst_res = vrend_renderer_ctx_res_lookup(ctx, dst_handle);
8407
8408 if (!src_res) {
8409 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, src_handle);
8410 return EINVAL;
8411 }
8412
8413 if (!dst_res) {
8414 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, dst_handle);
8415 return EINVAL;
8416 }
8417
8418 if (!src_res->iov) {
8419 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, dst_handle);
8420 return EINVAL;
8421 }
8422
8423 if (!check_transfer_bounds(dst_res, info)) {
8424 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_CMD_BUFFER, dst_handle);
8425 return EINVAL;
8426 }
8427
8428 if (!check_iov_bounds(dst_res, info, src_res->iov, src_res->num_iovs)) {
8429 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_CMD_BUFFER, dst_handle);
8430 return EINVAL;
8431 }
8432
8433 #ifdef ENABLE_MINIGBM_ALLOCATION
8434 if (dst_res->gbm_bo) {
8435 bool use_gbm = true;
8436
8437 /* The guest uses copy transfers against busy resources to avoid
8438 * waiting. The host GL driver is usually smart enough to avoid
8439 * blocking by putting the data in a staging buffer and doing a
8440 * pipelined copy. But when there is a GBM bo, we can only do that when
8441 * VREND_STORAGE_GL_IMMUTABLE is set because it implies that the
8442 * internal format is known and is known to be compatible with the
8443 * subsequence glTexSubImage2D. Otherwise, we glFinish and use GBM.
8444 * Also, EGL images with BGRX format are not compatible with
8445 * glTexSubImage2D, since they are stored with only 3bpp, so gbm
8446 * transfer is required.
8447 */
8448 if (info->synchronized) {
8449 if (has_bit(dst_res->storage_bits, VREND_STORAGE_GL_IMMUTABLE) &&
8450 dst_res->base.format != VIRGL_FORMAT_B8G8R8X8_UNORM)
8451 use_gbm = false;
8452 else
8453 glFinish();
8454 }
8455
8456 if (use_gbm) {
8457 return virgl_gbm_transfer(dst_res->gbm_bo,
8458 VIRGL_TRANSFER_TO_HOST,
8459 src_res->iov,
8460 src_res->num_iovs,
8461 info);
8462 }
8463 }
8464 #endif
8465
8466 return vrend_renderer_transfer_write_iov(ctx, dst_res, src_res->iov,
8467 src_res->num_iovs, info);
8468 }
8469
vrend_set_stencil_ref(struct vrend_context * ctx,struct pipe_stencil_ref * ref)8470 void vrend_set_stencil_ref(struct vrend_context *ctx,
8471 struct pipe_stencil_ref *ref)
8472 {
8473 if (ctx->sub->stencil_refs[0] != ref->ref_value[0] ||
8474 ctx->sub->stencil_refs[1] != ref->ref_value[1]) {
8475 ctx->sub->stencil_refs[0] = ref->ref_value[0];
8476 ctx->sub->stencil_refs[1] = ref->ref_value[1];
8477 ctx->sub->stencil_state_dirty = true;
8478 }
8479 }
8480
vrend_set_blend_color(struct vrend_context * ctx,struct pipe_blend_color * color)8481 void vrend_set_blend_color(struct vrend_context *ctx,
8482 struct pipe_blend_color *color)
8483 {
8484 ctx->sub->blend_color = *color;
8485 glBlendColor(color->color[0], color->color[1], color->color[2],
8486 color->color[3]);
8487 }
8488
vrend_set_scissor_state(struct vrend_context * ctx,uint32_t start_slot,uint32_t num_scissor,struct pipe_scissor_state * ss)8489 void vrend_set_scissor_state(struct vrend_context *ctx,
8490 uint32_t start_slot,
8491 uint32_t num_scissor,
8492 struct pipe_scissor_state *ss)
8493 {
8494 uint i, idx;
8495
8496 if (start_slot > PIPE_MAX_VIEWPORTS ||
8497 num_scissor > (PIPE_MAX_VIEWPORTS - start_slot)) {
8498 vrend_report_buffer_error(ctx, 0);
8499 return;
8500 }
8501
8502 for (i = 0; i < num_scissor; i++) {
8503 idx = start_slot + i;
8504 ctx->sub->ss[idx] = ss[i];
8505 ctx->sub->scissor_state_dirty |= (1 << idx);
8506 }
8507 }
8508
vrend_set_polygon_stipple(struct vrend_context * ctx,struct pipe_poly_stipple * ps)8509 void vrend_set_polygon_stipple(struct vrend_context *ctx,
8510 struct pipe_poly_stipple *ps)
8511 {
8512 if (vrend_state.use_core_profile) {
8513 static const unsigned bit31 = 1u << 31;
8514 GLubyte *stip = calloc(1, 1024);
8515 int i, j;
8516
8517 if (!ctx->pstip_inited)
8518 vrend_init_pstipple_texture(ctx);
8519
8520 if (!stip)
8521 return;
8522
8523 for (i = 0; i < 32; i++) {
8524 for (j = 0; j < 32; j++) {
8525 if (ps->stipple[i] & (bit31 >> j))
8526 stip[i * 32 + j] = 0;
8527 else
8528 stip[i * 32 + j] = 255;
8529 }
8530 }
8531
8532 glBindTexture(GL_TEXTURE_2D, ctx->pstipple_tex_id);
8533 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 32, 32,
8534 GL_RED, GL_UNSIGNED_BYTE, stip);
8535 glBindTexture(GL_TEXTURE_2D, 0);
8536
8537 free(stip);
8538 return;
8539 }
8540 glPolygonStipple((const GLubyte *)ps->stipple);
8541 }
8542
vrend_set_clip_state(struct vrend_context * ctx,struct pipe_clip_state * ucp)8543 void vrend_set_clip_state(struct vrend_context *ctx, struct pipe_clip_state *ucp)
8544 {
8545 if (vrend_state.use_core_profile) {
8546 ctx->sub->ucp_state = *ucp;
8547 } else {
8548 int i, j;
8549 GLdouble val[4];
8550
8551 for (i = 0; i < 8; i++) {
8552 for (j = 0; j < 4; j++)
8553 val[j] = ucp->ucp[i][j];
8554 glClipPlane(GL_CLIP_PLANE0 + i, val);
8555 }
8556 }
8557 }
8558
vrend_set_sample_mask(UNUSED struct vrend_context * ctx,unsigned sample_mask)8559 void vrend_set_sample_mask(UNUSED struct vrend_context *ctx, unsigned sample_mask)
8560 {
8561 if (has_feature(feat_sample_mask))
8562 glSampleMaski(0, sample_mask);
8563 }
8564
vrend_set_min_samples(struct vrend_context * ctx,unsigned min_samples)8565 void vrend_set_min_samples(struct vrend_context *ctx, unsigned min_samples)
8566 {
8567 float min_sample_shading = (float)min_samples;
8568 if (ctx->sub->nr_cbufs > 0 && ctx->sub->surf[0]) {
8569 assert(ctx->sub->surf[0]->texture);
8570 min_sample_shading /= MAX2(1, ctx->sub->surf[0]->texture->base.nr_samples);
8571 }
8572
8573 if (has_feature(feat_sample_shading))
8574 glMinSampleShading(min_sample_shading);
8575 }
8576
vrend_set_tess_state(UNUSED struct vrend_context * ctx,const float tess_factors[6])8577 void vrend_set_tess_state(UNUSED struct vrend_context *ctx, const float tess_factors[6])
8578 {
8579 if (has_feature(feat_tessellation)) {
8580 if (!vrend_state.use_gles) {
8581 glPatchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, tess_factors);
8582 glPatchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, &tess_factors[4]);
8583 } else {
8584 memcpy(vrend_state.tess_factors, tess_factors, 6 * sizeof (float));
8585 }
8586 }
8587 }
8588
vrend_hw_emit_streamout_targets(UNUSED struct vrend_context * ctx,struct vrend_streamout_object * so_obj)8589 static void vrend_hw_emit_streamout_targets(UNUSED struct vrend_context *ctx, struct vrend_streamout_object *so_obj)
8590 {
8591 uint i;
8592
8593 for (i = 0; i < so_obj->num_targets; i++) {
8594 if (!so_obj->so_targets[i])
8595 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, i, 0);
8596 else if (so_obj->so_targets[i]->buffer_offset || so_obj->so_targets[i]->buffer_size < so_obj->so_targets[i]->buffer->base.width0)
8597 glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, i, so_obj->so_targets[i]->buffer->id, so_obj->so_targets[i]->buffer_offset, so_obj->so_targets[i]->buffer_size);
8598 else
8599 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, i, so_obj->so_targets[i]->buffer->id);
8600 }
8601 }
8602
vrend_set_streamout_targets(struct vrend_context * ctx,UNUSED uint32_t append_bitmask,uint32_t num_targets,uint32_t * handles)8603 void vrend_set_streamout_targets(struct vrend_context *ctx,
8604 UNUSED uint32_t append_bitmask,
8605 uint32_t num_targets,
8606 uint32_t *handles)
8607 {
8608 struct vrend_so_target *target;
8609 uint i;
8610
8611 if (!has_feature(feat_transform_feedback))
8612 return;
8613
8614 if (num_targets) {
8615 bool found = false;
8616 struct vrend_streamout_object *obj;
8617 LIST_FOR_EACH_ENTRY(obj, &ctx->sub->streamout_list, head) {
8618 if (obj->num_targets == num_targets) {
8619 if (!memcmp(handles, obj->handles, num_targets * 4)) {
8620 found = true;
8621 break;
8622 }
8623 }
8624 }
8625 if (found) {
8626 ctx->sub->current_so = obj;
8627 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, obj->id);
8628 return;
8629 }
8630
8631 obj = CALLOC_STRUCT(vrend_streamout_object);
8632 if (has_feature(feat_transform_feedback2)) {
8633 glGenTransformFeedbacks(1, &obj->id);
8634 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, obj->id);
8635 }
8636 obj->num_targets = num_targets;
8637 for (i = 0; i < num_targets; i++) {
8638 obj->handles[i] = handles[i];
8639 if (handles[i] == 0)
8640 continue;
8641 target = vrend_object_lookup(ctx->sub->object_hash, handles[i], VIRGL_OBJECT_STREAMOUT_TARGET);
8642 if (!target) {
8643 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_HANDLE, handles[i]);
8644 free(obj);
8645 return;
8646 }
8647 vrend_so_target_reference(&obj->so_targets[i], target);
8648 }
8649 vrend_hw_emit_streamout_targets(ctx, obj);
8650 list_addtail(&obj->head, &ctx->sub->streamout_list);
8651 ctx->sub->current_so = obj;
8652 obj->xfb_state = XFB_STATE_STARTED_NEED_BEGIN;
8653 } else {
8654 if (has_feature(feat_transform_feedback2))
8655 glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
8656 ctx->sub->current_so = NULL;
8657 }
8658 }
8659
vrend_resource_buffer_copy(UNUSED struct vrend_context * ctx,struct vrend_resource * src_res,struct vrend_resource * dst_res,uint32_t dstx,uint32_t srcx,uint32_t width)8660 static void vrend_resource_buffer_copy(UNUSED struct vrend_context *ctx,
8661 struct vrend_resource *src_res,
8662 struct vrend_resource *dst_res,
8663 uint32_t dstx, uint32_t srcx,
8664 uint32_t width)
8665 {
8666 glBindBuffer(GL_COPY_READ_BUFFER, src_res->id);
8667 glBindBuffer(GL_COPY_WRITE_BUFFER, dst_res->id);
8668
8669 glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, srcx, dstx, width);
8670 glBindBuffer(GL_COPY_READ_BUFFER, 0);
8671 glBindBuffer(GL_COPY_WRITE_BUFFER, 0);
8672 }
8673
vrend_resource_copy_fallback(struct vrend_resource * src_res,struct vrend_resource * dst_res,uint32_t dst_level,uint32_t dstx,uint32_t dsty,uint32_t dstz,uint32_t src_level,const struct pipe_box * src_box)8674 static void vrend_resource_copy_fallback(struct vrend_resource *src_res,
8675 struct vrend_resource *dst_res,
8676 uint32_t dst_level,
8677 uint32_t dstx, uint32_t dsty,
8678 uint32_t dstz, uint32_t src_level,
8679 const struct pipe_box *src_box)
8680 {
8681 char *tptr;
8682 uint32_t total_size, src_stride, dst_stride, src_layer_stride;
8683 GLenum glformat, gltype;
8684 int elsize = util_format_get_blocksize(dst_res->base.format);
8685 int compressed = util_format_is_compressed(dst_res->base.format);
8686 int cube_slice = 1;
8687 uint32_t slice_size, slice_offset;
8688 int i;
8689 struct pipe_box box;
8690
8691 if (src_res->target == GL_TEXTURE_CUBE_MAP)
8692 cube_slice = 6;
8693
8694 if (src_res->base.format != dst_res->base.format) {
8695 vrend_printf( "copy fallback failed due to mismatched formats %d %d\n", src_res->base.format, dst_res->base.format);
8696 return;
8697 }
8698
8699 box = *src_box;
8700 box.depth = vrend_get_texture_depth(src_res, src_level);
8701 dst_stride = util_format_get_stride(dst_res->base.format, dst_res->base.width0);
8702
8703 /* this is ugly need to do a full GetTexImage */
8704 slice_size = util_format_get_nblocks(src_res->base.format, u_minify(src_res->base.width0, src_level), u_minify(src_res->base.height0, src_level)) *
8705 util_format_get_blocksize(src_res->base.format);
8706 total_size = slice_size * vrend_get_texture_depth(src_res, src_level);
8707
8708 tptr = malloc(total_size);
8709 if (!tptr)
8710 return;
8711
8712 glformat = tex_conv_table[src_res->base.format].glformat;
8713 gltype = tex_conv_table[src_res->base.format].gltype;
8714
8715 if (compressed)
8716 glformat = tex_conv_table[src_res->base.format].internalformat;
8717
8718 /* If we are on gles we need to rely on the textures backing
8719 * iovec to have the data we need, otherwise we can use glGetTexture
8720 */
8721 if (vrend_state.use_gles) {
8722 uint64_t src_offset = 0;
8723 uint64_t dst_offset = 0;
8724 if (src_level < VR_MAX_TEXTURE_2D_LEVELS) {
8725 src_offset = src_res->mipmap_offsets[src_level];
8726 dst_offset = dst_res->mipmap_offsets[src_level];
8727 }
8728
8729 src_stride = util_format_get_nblocksx(src_res->base.format,
8730 u_minify(src_res->base.width0, src_level)) * elsize;
8731 src_layer_stride = util_format_get_2d_size(src_res->base.format,
8732 src_stride,
8733 u_minify(src_res->base.height0, src_level));
8734 read_transfer_data(src_res->iov, src_res->num_iovs, tptr,
8735 src_res->base.format, src_offset,
8736 src_stride, src_layer_stride, &box, false);
8737 /* When on GLES sync the iov that backs the dst resource because
8738 * we might need it in a chain copy A->B, B->C */
8739 write_transfer_data(&dst_res->base, dst_res->iov, dst_res->num_iovs, tptr,
8740 dst_stride, &box, src_level, dst_offset, false);
8741 /* we get values from the guest as 24-bit scaled integers
8742 but we give them to the host GL and it interprets them
8743 as 32-bit scaled integers, so we need to scale them here */
8744 if (dst_res->base.format == VIRGL_FORMAT_Z24X8_UNORM) {
8745 float depth_scale = 256.0;
8746 vrend_scale_depth(tptr, total_size, depth_scale);
8747 }
8748
8749 /* if this is a BGR* resource on GLES, the data needs to be manually swizzled to RGB* before
8750 * storing in a texture. Iovec data is assumed to have the original byte-order, namely BGR*,
8751 * and needs to be reordered when storing in the host's texture memory as RGB*.
8752 * On the contrary, externally-stored BGR* resources are assumed to remain in BGR* format at
8753 * all times.
8754 */
8755 if (vrend_format_is_bgra(dst_res->base.format) && !vrend_resource_is_emulated_bgra(dst_res))
8756 vrend_swizzle_data_bgra(total_size, tptr);
8757 } else {
8758 uint32_t read_chunk_size;
8759 switch (elsize) {
8760 case 1:
8761 case 3:
8762 glPixelStorei(GL_PACK_ALIGNMENT, 1);
8763 break;
8764 case 2:
8765 case 6:
8766 glPixelStorei(GL_PACK_ALIGNMENT, 2);
8767 break;
8768 case 4:
8769 default:
8770 glPixelStorei(GL_PACK_ALIGNMENT, 4);
8771 break;
8772 case 8:
8773 glPixelStorei(GL_PACK_ALIGNMENT, 8);
8774 break;
8775 }
8776 glBindTexture(src_res->target, src_res->id);
8777 slice_offset = 0;
8778 read_chunk_size = (src_res->target == GL_TEXTURE_CUBE_MAP) ? slice_size : total_size;
8779 for (i = 0; i < cube_slice; i++) {
8780 GLenum ctarget = src_res->target == GL_TEXTURE_CUBE_MAP ?
8781 (GLenum)(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i) : src_res->target;
8782 if (compressed) {
8783 if (has_feature(feat_arb_robustness))
8784 glGetnCompressedTexImageARB(ctarget, src_level, read_chunk_size, tptr + slice_offset);
8785 else
8786 glGetCompressedTexImage(ctarget, src_level, tptr + slice_offset);
8787 } else {
8788 if (has_feature(feat_arb_robustness))
8789 glGetnTexImageARB(ctarget, src_level, glformat, gltype, read_chunk_size, tptr + slice_offset);
8790 else
8791 glGetTexImage(ctarget, src_level, glformat, gltype, tptr + slice_offset);
8792 }
8793 slice_offset += slice_size;
8794 }
8795 }
8796
8797 glPixelStorei(GL_PACK_ALIGNMENT, 4);
8798 switch (elsize) {
8799 case 1:
8800 case 3:
8801 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
8802 break;
8803 case 2:
8804 case 6:
8805 glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
8806 break;
8807 case 4:
8808 default:
8809 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
8810 break;
8811 case 8:
8812 glPixelStorei(GL_UNPACK_ALIGNMENT, 8);
8813 break;
8814 }
8815
8816 glBindTexture(dst_res->target, dst_res->id);
8817 slice_offset = src_box->z * slice_size;
8818 cube_slice = (src_res->target == GL_TEXTURE_CUBE_MAP) ? src_box->z + src_box->depth : cube_slice;
8819 i = (src_res->target == GL_TEXTURE_CUBE_MAP) ? src_box->z : 0;
8820 for (; i < cube_slice; i++) {
8821 GLenum ctarget = dst_res->target == GL_TEXTURE_CUBE_MAP ?
8822 (GLenum)(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i) : dst_res->target;
8823 if (compressed) {
8824 if (ctarget == GL_TEXTURE_1D) {
8825 glCompressedTexSubImage1D(ctarget, dst_level, dstx,
8826 src_box->width,
8827 glformat, slice_size, tptr + slice_offset);
8828 } else {
8829 glCompressedTexSubImage2D(ctarget, dst_level, dstx, dsty,
8830 src_box->width, src_box->height,
8831 glformat, slice_size, tptr + slice_offset);
8832 }
8833 } else {
8834 if (ctarget == GL_TEXTURE_1D) {
8835 glTexSubImage1D(ctarget, dst_level, dstx, src_box->width, glformat, gltype, tptr + slice_offset);
8836 } else if (ctarget == GL_TEXTURE_3D ||
8837 ctarget == GL_TEXTURE_2D_ARRAY ||
8838 ctarget == GL_TEXTURE_CUBE_MAP_ARRAY) {
8839 glTexSubImage3D(ctarget, dst_level, dstx, dsty, dstz, src_box->width, src_box->height, src_box->depth, glformat, gltype, tptr + slice_offset);
8840 } else {
8841 glTexSubImage2D(ctarget, dst_level, dstx, dsty, src_box->width, src_box->height, glformat, gltype, tptr + slice_offset);
8842 }
8843 }
8844 slice_offset += slice_size;
8845 }
8846
8847 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
8848 free(tptr);
8849 glBindTexture(GL_TEXTURE_2D, 0);
8850 }
8851
8852 static inline
translate_gles_emulation_texture_target(GLenum target)8853 GLenum translate_gles_emulation_texture_target(GLenum target)
8854 {
8855 switch (target) {
8856 case GL_TEXTURE_1D:
8857 case GL_TEXTURE_RECTANGLE: return GL_TEXTURE_2D;
8858 case GL_TEXTURE_1D_ARRAY: return GL_TEXTURE_2D_ARRAY;
8859 default: return target;
8860 }
8861 }
8862
8863 static inline void
vrend_copy_sub_image(struct vrend_resource * src_res,struct vrend_resource * dst_res,uint32_t src_level,const struct pipe_box * src_box,uint32_t dst_level,uint32_t dstx,uint32_t dsty,uint32_t dstz)8864 vrend_copy_sub_image(struct vrend_resource* src_res, struct vrend_resource * dst_res,
8865 uint32_t src_level, const struct pipe_box *src_box,
8866 uint32_t dst_level, uint32_t dstx, uint32_t dsty, uint32_t dstz)
8867 {
8868
8869 GLenum src_target = tgsitargettogltarget(src_res->base.target, src_res->base.nr_samples);
8870 GLenum dst_target = tgsitargettogltarget(dst_res->base.target, dst_res->base.nr_samples);
8871
8872 if (vrend_state.use_gles) {
8873 src_target = translate_gles_emulation_texture_target(src_target);
8874 dst_target = translate_gles_emulation_texture_target(dst_target);
8875 }
8876
8877 glCopyImageSubData(src_res->id, src_target, src_level,
8878 src_box->x, src_box->y, src_box->z,
8879 dst_res->id, dst_target, dst_level,
8880 dstx, dsty, dstz,
8881 src_box->width, src_box->height,src_box->depth);
8882 }
8883
8884
vrend_renderer_resource_copy_region(struct vrend_context * ctx,uint32_t dst_handle,uint32_t dst_level,uint32_t dstx,uint32_t dsty,uint32_t dstz,uint32_t src_handle,uint32_t src_level,const struct pipe_box * src_box)8885 void vrend_renderer_resource_copy_region(struct vrend_context *ctx,
8886 uint32_t dst_handle, uint32_t dst_level,
8887 uint32_t dstx, uint32_t dsty, uint32_t dstz,
8888 uint32_t src_handle, uint32_t src_level,
8889 const struct pipe_box *src_box)
8890 {
8891 struct vrend_resource *src_res, *dst_res;
8892 GLbitfield glmask = 0;
8893 GLint sy1, sy2, dy1, dy2;
8894 unsigned int comp_flags;
8895
8896 if (ctx->in_error)
8897 return;
8898
8899 src_res = vrend_renderer_ctx_res_lookup(ctx, src_handle);
8900 dst_res = vrend_renderer_ctx_res_lookup(ctx, dst_handle);
8901
8902 if (!src_res) {
8903 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, src_handle);
8904 return;
8905 }
8906 if (!dst_res) {
8907 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, dst_handle);
8908 return;
8909 }
8910
8911 VREND_DEBUG(dbg_copy_resource, ctx, "COPY_REGION: From %s ms:%d [%d, %d, %d]+[%d, %d, %d] lvl:%d "
8912 "To %s ms:%d [%d, %d, %d]\n",
8913 util_format_name(src_res->base.format), src_res->base.nr_samples,
8914 src_box->x, src_box->y, src_box->z,
8915 src_box->width, src_box->height, src_box->depth,
8916 src_level,
8917 util_format_name(dst_res->base.format), dst_res->base.nr_samples,
8918 dstx, dsty, dstz);
8919
8920 if (src_res->base.target == PIPE_BUFFER && dst_res->base.target == PIPE_BUFFER) {
8921 /* do a buffer copy */
8922 VREND_DEBUG(dbg_copy_resource, ctx, "COPY_REGION: buffer copy %d+%d\n",
8923 src_box->x, src_box->width);
8924 vrend_resource_buffer_copy(ctx, src_res, dst_res, dstx,
8925 src_box->x, src_box->width);
8926 return;
8927 }
8928
8929 comp_flags = VREND_COPY_COMPAT_FLAG_ALLOW_COMPRESSED;
8930 if (src_res->egl_image)
8931 comp_flags |= VREND_COPY_COMPAT_FLAG_ONE_IS_EGL_IMAGE;
8932 if (dst_res->egl_image)
8933 comp_flags ^= VREND_COPY_COMPAT_FLAG_ONE_IS_EGL_IMAGE;
8934
8935 if (has_feature(feat_copy_image) &&
8936 format_is_copy_compatible(src_res->base.format,dst_res->base.format, comp_flags) &&
8937 src_res->base.nr_samples == dst_res->base.nr_samples) {
8938 VREND_DEBUG(dbg_copy_resource, ctx, "COPY_REGION: use glCopyImageSubData\n");
8939 vrend_copy_sub_image(src_res, dst_res, src_level, src_box,
8940 dst_level, dstx, dsty, dstz);
8941 return;
8942 }
8943
8944 if (!vrend_format_can_render(src_res->base.format) ||
8945 !vrend_format_can_render(dst_res->base.format)) {
8946 VREND_DEBUG(dbg_copy_resource, ctx, "COPY_REGION: use resource_copy_fallback\n");
8947 vrend_resource_copy_fallback(src_res, dst_res, dst_level, dstx,
8948 dsty, dstz, src_level, src_box);
8949 return;
8950 }
8951
8952 glBindFramebuffer(GL_FRAMEBUFFER, ctx->sub->blit_fb_ids[0]);
8953 VREND_DEBUG(dbg_copy_resource, ctx, "COPY_REGION: use glBlitFramebuffer\n");
8954
8955 /* clean out fb ids */
8956 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
8957 GL_TEXTURE_2D, 0, 0);
8958 vrend_fb_bind_texture(src_res, 0, src_level, src_box->z);
8959
8960 glBindFramebuffer(GL_FRAMEBUFFER, ctx->sub->blit_fb_ids[1]);
8961 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
8962 GL_TEXTURE_2D, 0, 0);
8963 vrend_fb_bind_texture(dst_res, 0, dst_level, dstz);
8964 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, ctx->sub->blit_fb_ids[1]);
8965
8966 glBindFramebuffer(GL_READ_FRAMEBUFFER, ctx->sub->blit_fb_ids[0]);
8967
8968 glmask = GL_COLOR_BUFFER_BIT;
8969 glDisable(GL_SCISSOR_TEST);
8970
8971 if (!src_res->y_0_top) {
8972 sy1 = src_box->y;
8973 sy2 = src_box->y + src_box->height;
8974 } else {
8975 sy1 = src_res->base.height0 - src_box->y - src_box->height;
8976 sy2 = src_res->base.height0 - src_box->y;
8977 }
8978
8979 if (!dst_res->y_0_top) {
8980 dy1 = dsty;
8981 dy2 = dsty + src_box->height;
8982 } else {
8983 dy1 = dst_res->base.height0 - dsty - src_box->height;
8984 dy2 = dst_res->base.height0 - dsty;
8985 }
8986
8987 glBlitFramebuffer(src_box->x, sy1,
8988 src_box->x + src_box->width,
8989 sy2,
8990 dstx, dy1,
8991 dstx + src_box->width,
8992 dy2,
8993 glmask, GL_NEAREST);
8994
8995 glBindFramebuffer(GL_READ_FRAMEBUFFER, ctx->sub->blit_fb_ids[0]);
8996 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
8997 GL_TEXTURE_2D, 0, 0);
8998 glBindFramebuffer(GL_READ_FRAMEBUFFER, ctx->sub->blit_fb_ids[1]);
8999 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
9000 GL_TEXTURE_2D, 0, 0);
9001
9002 glBindFramebuffer(GL_FRAMEBUFFER, ctx->sub->fb_id);
9003
9004 if (ctx->sub->rs_state.scissor)
9005 glEnable(GL_SCISSOR_TEST);
9006 }
9007
vrend_make_view(struct vrend_resource * res,enum virgl_formats format)9008 static GLuint vrend_make_view(struct vrend_resource *res, enum virgl_formats format)
9009 {
9010 GLuint view_id;
9011
9012 GLenum tex_ifmt = tex_conv_table[res->base.format].internalformat;
9013 GLenum view_ifmt = tex_conv_table[format].internalformat;
9014
9015 if (tex_ifmt == view_ifmt)
9016 return res->id;
9017
9018 /* If the format doesn't support TextureStorage it is not immutable, so no TextureView*/
9019 if (!has_bit(res->storage_bits, VREND_STORAGE_GL_IMMUTABLE))
9020 return res->id;
9021
9022 VREND_DEBUG(dbg_blit, NULL, "Create texture view from %s as %s\n",
9023 util_format_name(res->base.format),
9024 util_format_name(format));
9025
9026 if (vrend_state.use_gles) {
9027 assert(res->target != GL_TEXTURE_RECTANGLE_NV);
9028 assert(res->target != GL_TEXTURE_1D);
9029 assert(res->target != GL_TEXTURE_1D_ARRAY);
9030 }
9031
9032 glGenTextures(1, &view_id);
9033 glTextureView(view_id, res->target, res->id, view_ifmt, 0, res->base.last_level + 1,
9034 0, res->base.array_size);
9035 return view_id;
9036 }
9037
vrend_renderer_blit_int(struct vrend_context * ctx,struct vrend_resource * src_res,struct vrend_resource * dst_res,const struct pipe_blit_info * info)9038 static void vrend_renderer_blit_int(struct vrend_context *ctx,
9039 struct vrend_resource *src_res,
9040 struct vrend_resource *dst_res,
9041 const struct pipe_blit_info *info)
9042 {
9043 GLbitfield glmask = 0;
9044 int src_y1, src_y2, dst_y1, dst_y2;
9045 GLenum filter;
9046 int n_layers = 1, i;
9047 bool use_gl = false;
9048 bool needs_swizzle = false;
9049 bool make_intermediate_copy = false;
9050 GLuint intermediate_fbo = 0;
9051 struct vrend_resource *intermediate_copy = 0;
9052
9053 GLuint blitter_views[2] = {src_res->id, dst_res->id};
9054
9055 filter = convert_mag_filter(info->filter);
9056
9057 /* if we can't make FBO's use the fallback path */
9058 if (!vrend_format_can_render(src_res->base.format) &&
9059 !vrend_format_is_ds(src_res->base.format))
9060 use_gl = true;
9061 if (!vrend_format_can_render(dst_res->base.format) &&
9062 !vrend_format_is_ds(dst_res->base.format))
9063 use_gl = true;
9064
9065 /* different depth formats */
9066 if (vrend_format_is_ds(src_res->base.format) &&
9067 vrend_format_is_ds(dst_res->base.format)) {
9068 if (src_res->base.format != dst_res->base.format) {
9069 if (!(src_res->base.format == PIPE_FORMAT_S8_UINT_Z24_UNORM &&
9070 (dst_res->base.format == PIPE_FORMAT_Z24X8_UNORM))) {
9071 use_gl = true;
9072 }
9073 }
9074 }
9075 /* glBlitFramebuffer - can support depth stencil with NEAREST
9076 which we use for mipmaps */
9077 if ((info->mask & (PIPE_MASK_Z | PIPE_MASK_S)) && info->filter == PIPE_TEX_FILTER_LINEAR)
9078 use_gl = true;
9079
9080 /* for scaled MS blits we either need extensions or hand roll */
9081 if (info->mask & PIPE_MASK_RGBA &&
9082 src_res->base.nr_samples > 0 &&
9083 src_res->base.nr_samples != dst_res->base.nr_samples &&
9084 (info->src.box.width != info->dst.box.width ||
9085 info->src.box.height != info->dst.box.height)) {
9086 if (has_feature(feat_ms_scaled_blit))
9087 filter = GL_SCALED_RESOLVE_NICEST_EXT;
9088 else
9089 use_gl = true;
9090 }
9091
9092 if (!dst_res->y_0_top) {
9093 dst_y1 = info->dst.box.y + info->dst.box.height;
9094 dst_y2 = info->dst.box.y;
9095 } else {
9096 dst_y1 = dst_res->base.height0 - info->dst.box.y - info->dst.box.height;
9097 dst_y2 = dst_res->base.height0 - info->dst.box.y;
9098 }
9099
9100 if (!src_res->y_0_top) {
9101 src_y1 = info->src.box.y + info->src.box.height;
9102 src_y2 = info->src.box.y;
9103 } else {
9104 src_y1 = src_res->base.height0 - info->src.box.y - info->src.box.height;
9105 src_y2 = src_res->base.height0 - info->src.box.y;
9106 }
9107
9108 /* since upstream mesa change
9109 * https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5034
9110 * an imported RGBX texture uses GL_RGB8 as internal format while
9111 * in virgl_formats, we use GL_RGBA8 internal format for RGBX texutre.
9112 * on GLES host, glBlitFramebuffer doesn't work in such case. */
9113 if (vrend_state.use_gles && !use_gl &&
9114 info->mask & PIPE_MASK_RGBA &&
9115 src_res->base.format == VIRGL_FORMAT_R8G8B8X8_UNORM &&
9116 dst_res->base.format == VIRGL_FORMAT_R8G8B8X8_UNORM &&
9117 has_bit(src_res->storage_bits, VREND_STORAGE_EGL_IMAGE) !=
9118 has_bit(dst_res->storage_bits, VREND_STORAGE_EGL_IMAGE) &&
9119 (src_res->base.nr_samples || dst_res->base.nr_samples)) {
9120 use_gl = true;
9121 }
9122
9123 if (use_gl) {;}
9124 /* GLES generally doesn't support blitting to a multi-sample FB, and also not
9125 * from a multi-sample FB where the regions are not exatly the same or the
9126 * source and target format are different. For
9127 * downsampling DS blits to zero samples we solve this by doing two blits */
9128 else if (vrend_state.use_gles &&
9129 ((dst_res->base.nr_samples > 0) ||
9130 ((info->mask & PIPE_MASK_RGBA) &&
9131 (src_res->base.nr_samples > 0) &&
9132 (info->src.box.x != info->dst.box.x ||
9133 info->src.box.width != info->dst.box.width ||
9134 dst_y1 != src_y1 || dst_y2 != src_y2 ||
9135 info->src.format != info->dst.format))
9136 )
9137 ) {
9138 VREND_DEBUG(dbg_blit, ctx, "Use GL fallback because dst:ms:%d src:ms:%d (%d %d %d %d) -> (%d %d %d %d)\n",
9139 dst_res->base.nr_samples, src_res->base.nr_samples, info->src.box.x, info->src.box.x + info->src.box.width,
9140 src_y1, src_y2, info->dst.box.x, info->dst.box.x + info->dst.box.width, dst_y1, dst_y2);
9141 use_gl = true;
9142 }
9143 /* for 3D mipmapped blits - hand roll time */
9144 else if (info->src.box.depth != info->dst.box.depth)
9145 use_gl = true;
9146 else if (vrend_blit_needs_swizzle(info->dst.format, info->src.format)) {
9147 use_gl = true;
9148 needs_swizzle = true;
9149 }
9150
9151 if ((src_res->base.format != info->src.format) && has_feature(feat_texture_view))
9152 blitter_views[0] = vrend_make_view(src_res, info->src.format);
9153
9154 if ((dst_res->base.format != info->dst.format) && has_feature(feat_texture_view))
9155 blitter_views[1] = vrend_make_view(dst_res, info->dst.format);
9156
9157 /* Virgl's BGR* formats always use GL_RGBA8 internal format so texture views have no format
9158 * conversion effects. Swizzling during blits is required instead.
9159 * Also, GBM/EGL-backed (i.e. external) BGR* resources are always stored with BGR* internal
9160 * format, despite Virgl's use of the GL_RGBA8 internal format, so special care must be taken
9161 * when determining the swizzling.
9162 */
9163 bool needs_redblue_swizzle = false;
9164 if (vrend_resource_is_emulated_bgra(src_res) ^ vrend_resource_is_emulated_bgra(dst_res))
9165 needs_redblue_swizzle = !needs_redblue_swizzle;
9166
9167 /* Virgl blits support "views" on source/dest resources, allowing another level of format
9168 * conversion on top of the host's GL API. These views need to be reconciled manually when
9169 * any BGR* resources are involved, since they are internally stored with RGB* byte-ordering,
9170 * and externally stored with BGR* byte-ordering.
9171 */
9172 if (vrend_format_is_bgra(src_res->base.format) ^ vrend_format_is_bgra(info->src.format))
9173 needs_redblue_swizzle = !needs_redblue_swizzle;
9174 if (vrend_format_is_bgra(dst_res->base.format) ^ vrend_format_is_bgra(info->dst.format))
9175 needs_redblue_swizzle = !needs_redblue_swizzle;
9176
9177 uint8_t blit_swizzle[4] = {0, 1, 2, 3};
9178 if (needs_swizzle && vrend_get_format_table_entry(dst_res->base.format)->flags & VIRGL_TEXTURE_NEED_SWIZZLE)
9179 memcpy(blit_swizzle, tex_conv_table[dst_res->base.format].swizzle, sizeof(blit_swizzle));
9180
9181 if (needs_redblue_swizzle) {
9182 VREND_DEBUG(dbg_blit, ctx, "Applying red/blue swizzle during blit involving an external BGR* resource\n");
9183 use_gl = true;
9184 uint8_t temp = blit_swizzle[0];
9185 blit_swizzle[0] = blit_swizzle[2];
9186 blit_swizzle[2] = temp;
9187 }
9188
9189 if (use_gl) {
9190 VREND_DEBUG(dbg_blit, ctx, "BLIT_INT: use GL fallback\n");
9191 vrend_renderer_blit_gl(ctx, src_res, dst_res, blitter_views, info,
9192 has_feature(feat_texture_srgb_decode),
9193 has_feature(feat_srgb_write_control),
9194 blit_swizzle);
9195 vrend_sync_make_current(ctx->sub->gl_context);
9196 goto cleanup;
9197 }
9198
9199 if (info->mask & PIPE_MASK_Z)
9200 glmask |= GL_DEPTH_BUFFER_BIT;
9201 if (info->mask & PIPE_MASK_S)
9202 glmask |= GL_STENCIL_BUFFER_BIT;
9203 if (info->mask & PIPE_MASK_RGBA)
9204 glmask |= GL_COLOR_BUFFER_BIT;
9205
9206
9207 if (info->scissor_enable) {
9208 glScissor(info->scissor.minx, info->scissor.miny, info->scissor.maxx - info->scissor.minx, info->scissor.maxy - info->scissor.miny);
9209 ctx->sub->scissor_state_dirty = (1 << 0);
9210 glEnable(GL_SCISSOR_TEST);
9211 } else
9212 glDisable(GL_SCISSOR_TEST);
9213
9214 /* An GLES GL_INVALID_OPERATION is generated if one wants to blit from a
9215 * multi-sample fbo to a non multi-sample fbo and the source and destination
9216 * rectangles are not defined with the same (X0, Y0) and (X1, Y1) bounds.
9217 *
9218 * Since stencil data can only be written in a fragment shader when
9219 * ARB_shader_stencil_export is available, the workaround using GL as given
9220 * above is usually not available. Instead, to work around the blit
9221 * limitations on GLES first copy the full frame to a non-multisample
9222 * surface and then copy the according area to the final target surface.
9223 */
9224 if (vrend_state.use_gles &&
9225 (info->mask & PIPE_MASK_ZS) &&
9226 ((src_res->base.nr_samples > 0) &&
9227 (src_res->base.nr_samples != dst_res->base.nr_samples)) &&
9228 ((info->src.box.x != info->dst.box.x) ||
9229 (src_y1 != dst_y1) ||
9230 (info->src.box.width != info->dst.box.width) ||
9231 (src_y2 != dst_y2))) {
9232
9233 make_intermediate_copy = true;
9234
9235 /* Create a texture that is the same like the src_res texture, but
9236 * without multi-sample */
9237 struct vrend_renderer_resource_create_args args;
9238 memset(&args, 0, sizeof(struct vrend_renderer_resource_create_args));
9239 args.width = src_res->base.width0;
9240 args.height = src_res->base.height0;
9241 args.depth = src_res->base.depth0;
9242 args.format = info->src.format;
9243 args.target = src_res->base.target;
9244 args.last_level = src_res->base.last_level;
9245 args.array_size = src_res->base.array_size;
9246 intermediate_copy = (struct vrend_resource *)CALLOC_STRUCT(vrend_texture);
9247 vrend_renderer_resource_copy_args(&args, intermediate_copy);
9248 /* this is PIPE_MASK_ZS and bgra fixup is not needed */
9249 MAYBE_UNUSED int r = vrend_resource_alloc_texture(intermediate_copy, args.format, NULL);
9250 assert(!r);
9251
9252 glGenFramebuffers(1, &intermediate_fbo);
9253 } else {
9254 /* If no intermediate copy is needed make the variables point to the
9255 * original source to simplify the code below.
9256 */
9257 intermediate_fbo = ctx->sub->blit_fb_ids[0];
9258 intermediate_copy = src_res;
9259 }
9260
9261 glBindFramebuffer(GL_FRAMEBUFFER, ctx->sub->blit_fb_ids[0]);
9262 if (info->mask & PIPE_MASK_RGBA)
9263 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
9264 GL_TEXTURE_2D, 0, 0);
9265 else
9266 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
9267 GL_TEXTURE_2D, 0, 0);
9268 glBindFramebuffer(GL_FRAMEBUFFER, ctx->sub->blit_fb_ids[1]);
9269 if (info->mask & PIPE_MASK_RGBA)
9270 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
9271 GL_TEXTURE_2D, 0, 0);
9272 else if (info->mask & (PIPE_MASK_Z | PIPE_MASK_S))
9273 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
9274 GL_TEXTURE_2D, 0, 0);
9275 if (info->src.box.depth == info->dst.box.depth)
9276 n_layers = info->dst.box.depth;
9277 for (i = 0; i < n_layers; i++) {
9278 glBindFramebuffer(GL_FRAMEBUFFER, ctx->sub->blit_fb_ids[0]);
9279 vrend_fb_bind_texture_id(src_res, blitter_views[0], 0, info->src.level, info->src.box.z + i, 0);
9280
9281 if (make_intermediate_copy) {
9282 int level_width = u_minify(src_res->base.width0, info->src.level);
9283 int level_height = u_minify(src_res->base.width0, info->src.level);
9284 glBindFramebuffer(GL_FRAMEBUFFER, intermediate_fbo);
9285 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
9286 GL_TEXTURE_2D, 0, 0);
9287 vrend_fb_bind_texture(intermediate_copy, 0, info->src.level, info->src.box.z + i);
9288
9289 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediate_fbo);
9290 glBindFramebuffer(GL_READ_FRAMEBUFFER, ctx->sub->blit_fb_ids[0]);
9291 glBlitFramebuffer(0, 0, level_width, level_height,
9292 0, 0, level_width, level_height,
9293 glmask, filter);
9294 }
9295
9296 glBindFramebuffer(GL_FRAMEBUFFER, ctx->sub->blit_fb_ids[1]);
9297 vrend_fb_bind_texture_id(dst_res, blitter_views[1], 0, info->dst.level, info->dst.box.z + i, 0);
9298 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, ctx->sub->blit_fb_ids[1]);
9299
9300 if (has_feature(feat_srgb_write_control)) {
9301 if (util_format_is_srgb(info->dst.format) ||
9302 util_format_is_srgb(info->src.format))
9303 glEnable(GL_FRAMEBUFFER_SRGB);
9304 else
9305 glDisable(GL_FRAMEBUFFER_SRGB);
9306 }
9307
9308 glBindFramebuffer(GL_READ_FRAMEBUFFER, intermediate_fbo);
9309
9310 glBlitFramebuffer(info->src.box.x,
9311 src_y1,
9312 info->src.box.x + info->src.box.width,
9313 src_y2,
9314 info->dst.box.x,
9315 dst_y1,
9316 info->dst.box.x + info->dst.box.width,
9317 dst_y2,
9318 glmask, filter);
9319 }
9320
9321 glBindFramebuffer(GL_FRAMEBUFFER, ctx->sub->blit_fb_ids[1]);
9322 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
9323 GL_TEXTURE_2D, 0, 0);
9324 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
9325 GL_TEXTURE_2D, 0, 0);
9326
9327 glBindFramebuffer(GL_FRAMEBUFFER, ctx->sub->blit_fb_ids[0]);
9328 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
9329 GL_TEXTURE_2D, 0, 0);
9330 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
9331 GL_TEXTURE_2D, 0, 0);
9332
9333 glBindFramebuffer(GL_FRAMEBUFFER, ctx->sub->fb_id);
9334
9335 if (has_feature(feat_srgb_write_control)) {
9336 if (ctx->sub->framebuffer_srgb_enabled)
9337 glEnable(GL_FRAMEBUFFER_SRGB);
9338 else
9339 glDisable(GL_FRAMEBUFFER_SRGB);
9340 }
9341
9342 if (make_intermediate_copy) {
9343 vrend_renderer_resource_destroy(intermediate_copy);
9344 glDeleteFramebuffers(1, &intermediate_fbo);
9345 }
9346
9347 if (ctx->sub->rs_state.scissor)
9348 glEnable(GL_SCISSOR_TEST);
9349 else
9350 glDisable(GL_SCISSOR_TEST);
9351
9352 cleanup:
9353 if (blitter_views[0] != src_res->id)
9354 glDeleteTextures(1, &blitter_views[0]);
9355
9356 if (blitter_views[1] != dst_res->id)
9357 glDeleteTextures(1, &blitter_views[1]);
9358 }
9359
vrend_renderer_blit(struct vrend_context * ctx,uint32_t dst_handle,uint32_t src_handle,const struct pipe_blit_info * info)9360 void vrend_renderer_blit(struct vrend_context *ctx,
9361 uint32_t dst_handle, uint32_t src_handle,
9362 const struct pipe_blit_info *info)
9363 {
9364 unsigned int comp_flags = 0;
9365 struct vrend_resource *src_res, *dst_res;
9366 src_res = vrend_renderer_ctx_res_lookup(ctx, src_handle);
9367 dst_res = vrend_renderer_ctx_res_lookup(ctx, dst_handle);
9368
9369 if (!src_res) {
9370 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, src_handle);
9371 return;
9372 }
9373 if (!dst_res) {
9374 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, dst_handle);
9375 return;
9376 }
9377
9378 if (ctx->in_error)
9379 return;
9380
9381 if (!info->src.format || info->src.format >= VIRGL_FORMAT_MAX) {
9382 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_FORMAT, info->src.format);
9383 return;
9384 }
9385
9386 if (!info->dst.format || info->dst.format >= VIRGL_FORMAT_MAX) {
9387 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_FORMAT, info->dst.format);
9388 return;
9389 }
9390
9391 if (info->render_condition_enable == false)
9392 vrend_pause_render_condition(ctx, true);
9393
9394 VREND_DEBUG(dbg_blit, ctx, "BLIT: rc:%d scissor:%d filter:%d alpha:%d mask:0x%x\n"
9395 " From %s(%s) ms:%d egl:%d gbm:%d [%d, %d, %d]+[%d, %d, %d] lvl:%d\n"
9396 " To %s(%s) ms:%d egl:%d gbm:%d [%d, %d, %d]+[%d, %d, %d] lvl:%d\n",
9397 info->render_condition_enable, info->scissor_enable,
9398 info->filter, info->alpha_blend, info->mask,
9399 util_format_name(src_res->base.format),
9400 util_format_name(info->src.format),
9401 src_res->base.nr_samples,
9402 has_bit(src_res->storage_bits, VREND_STORAGE_EGL_IMAGE),
9403 has_bit(src_res->storage_bits, VREND_STORAGE_GBM_BUFFER),
9404 info->src.box.x, info->src.box.y, info->src.box.z,
9405 info->src.box.width, info->src.box.height, info->src.box.depth,
9406 info->src.level,
9407 util_format_name(dst_res->base.format),
9408 util_format_name(info->dst.format),
9409 dst_res->base.nr_samples,
9410 has_bit(dst_res->storage_bits, VREND_STORAGE_EGL_IMAGE),
9411 has_bit(dst_res->storage_bits, VREND_STORAGE_GBM_BUFFER),
9412 info->dst.box.x, info->dst.box.y, info->dst.box.z,
9413 info->dst.box.width, info->dst.box.height, info->dst.box.depth,
9414 info->dst.level);
9415
9416 if (src_res->egl_image)
9417 comp_flags |= VREND_COPY_COMPAT_FLAG_ONE_IS_EGL_IMAGE;
9418 if (dst_res->egl_image)
9419 comp_flags ^= VREND_COPY_COMPAT_FLAG_ONE_IS_EGL_IMAGE;
9420
9421 /* The Gallium blit function can be called for a general blit that may
9422 * scale, convert the data, and apply some rander states, or it is called via
9423 * glCopyImageSubData. If the src or the dst image are equal, or the two
9424 * images formats are the same, then Galliums such calles are redirected
9425 * to resource_copy_region, in this case and if no render states etx need
9426 * to be applied, forward the call to glCopyImageSubData, otherwise do a
9427 * normal blit. */
9428 if (has_feature(feat_copy_image) &&
9429 (!info->render_condition_enable || !ctx->sub->cond_render_gl_mode) &&
9430 format_is_copy_compatible(info->src.format,info->dst.format, comp_flags) &&
9431 !info->scissor_enable && (info->filter == PIPE_TEX_FILTER_NEAREST) &&
9432 !info->alpha_blend && (info->mask == PIPE_MASK_RGBA) &&
9433 src_res->base.nr_samples == dst_res->base.nr_samples &&
9434 info->src.box.width == info->dst.box.width &&
9435 info->src.box.height == info->dst.box.height &&
9436 info->src.box.depth == info->dst.box.depth) {
9437 VREND_DEBUG(dbg_blit, ctx, " Use glCopyImageSubData\n");
9438 vrend_copy_sub_image(src_res, dst_res, info->src.level, &info->src.box,
9439 info->dst.level, info->dst.box.x, info->dst.box.y,
9440 info->dst.box.z);
9441 } else {
9442 VREND_DEBUG(dbg_blit, ctx, " Use blit_int\n");
9443 vrend_renderer_blit_int(ctx, src_res, dst_res, info);
9444 }
9445
9446 if (info->render_condition_enable == false)
9447 vrend_pause_render_condition(ctx, false);
9448 }
9449
vrend_renderer_set_fence_retire(struct vrend_context * ctx,vrend_context_fence_retire retire,void * retire_data)9450 void vrend_renderer_set_fence_retire(struct vrend_context *ctx,
9451 vrend_context_fence_retire retire,
9452 void *retire_data)
9453 {
9454 assert(ctx->ctx_id);
9455 ctx->fence_retire = retire;
9456 ctx->fence_retire_data = retire_data;
9457 }
9458
vrend_renderer_create_fence(struct vrend_context * ctx,uint32_t flags,void * fence_cookie)9459 int vrend_renderer_create_fence(struct vrend_context *ctx,
9460 uint32_t flags,
9461 void *fence_cookie)
9462 {
9463 struct vrend_fence *fence;
9464
9465 if (!ctx)
9466 return EINVAL;
9467
9468 fence = malloc(sizeof(struct vrend_fence));
9469 if (!fence)
9470 return ENOMEM;
9471
9472 fence->ctx = ctx;
9473 fence->flags = flags;
9474 fence->fence_cookie = fence_cookie;
9475
9476 #ifdef HAVE_EPOXY_EGL_H
9477 if (vrend_state.use_egl_fence) {
9478 fence->eglsyncobj = virgl_egl_fence_create(egl);
9479 } else
9480 #endif
9481 {
9482 fence->glsyncobj = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
9483 }
9484 glFlush();
9485
9486 if (fence->glsyncobj == NULL)
9487 goto fail;
9488
9489 if (vrend_state.sync_thread) {
9490 pipe_mutex_lock(vrend_state.fence_mutex);
9491 list_addtail(&fence->fences, &vrend_state.fence_wait_list);
9492 pipe_condvar_signal(vrend_state.fence_cond);
9493 pipe_mutex_unlock(vrend_state.fence_mutex);
9494 } else
9495 list_addtail(&fence->fences, &vrend_state.fence_list);
9496 return 0;
9497
9498 fail:
9499 vrend_printf( "failed to create fence sync object\n");
9500 free(fence);
9501 return ENOMEM;
9502 }
9503
need_fence_retire_signal_locked(struct vrend_fence * fence,const struct list_head * signaled_list)9504 static bool need_fence_retire_signal_locked(struct vrend_fence *fence,
9505 const struct list_head *signaled_list)
9506 {
9507 struct vrend_fence *next;
9508
9509 /* last fence */
9510 if (fence->fences.next == signaled_list)
9511 return true;
9512
9513 /* next fence belongs to a different context */
9514 next = LIST_ENTRY(struct vrend_fence, fence->fences.next, fences);
9515 if (next->ctx != fence->ctx)
9516 return true;
9517
9518 /* not mergeable */
9519 if (!(fence->flags & VIRGL_RENDERER_FENCE_FLAG_MERGEABLE))
9520 return true;
9521
9522 return false;
9523 }
9524
vrend_renderer_check_fences(void)9525 void vrend_renderer_check_fences(void)
9526 {
9527 struct list_head retired_fences;
9528 struct vrend_fence *fence, *stor;
9529
9530 /* No need to check the fence list, fences are retired directly in
9531 * the polling thread in that case.
9532 */
9533 if (vrend_state.use_async_fence_cb)
9534 return;
9535
9536 list_inithead(&retired_fences);
9537
9538 if (vrend_state.sync_thread) {
9539 flush_eventfd(vrend_state.eventfd);
9540 pipe_mutex_lock(vrend_state.fence_mutex);
9541 LIST_FOR_EACH_ENTRY_SAFE(fence, stor, &vrend_state.fence_list, fences) {
9542 /* vrend_free_fences_for_context might have marked the fence invalid
9543 * by setting fence->ctx to NULL
9544 */
9545 if (!fence->ctx) {
9546 free_fence_locked(fence);
9547 continue;
9548 }
9549
9550 if (need_fence_retire_signal_locked(fence, &vrend_state.fence_list)) {
9551 list_del(&fence->fences);
9552 list_addtail(&fence->fences, &retired_fences);
9553 } else {
9554 free_fence_locked(fence);
9555 }
9556 }
9557 pipe_mutex_unlock(vrend_state.fence_mutex);
9558 } else {
9559 vrend_renderer_force_ctx_0();
9560
9561 LIST_FOR_EACH_ENTRY_SAFE(fence, stor, &vrend_state.fence_list, fences) {
9562 if (do_wait(fence, /* can_block */ false)) {
9563 list_del(&fence->fences);
9564 list_addtail(&fence->fences, &retired_fences);
9565 } else {
9566 /* don't bother checking any subsequent ones */
9567 break;
9568 }
9569 }
9570
9571 LIST_FOR_EACH_ENTRY_SAFE(fence, stor, &retired_fences, fences) {
9572 if (!need_fence_retire_signal_locked(fence, &retired_fences))
9573 free_fence_locked(fence);
9574 }
9575 }
9576
9577 if (LIST_IS_EMPTY(&retired_fences))
9578 return;
9579
9580 /* no need to lock when not using a sync thread */
9581 vrend_renderer_check_queries_locked();
9582
9583 LIST_FOR_EACH_ENTRY_SAFE(fence, stor, &retired_fences, fences) {
9584 struct vrend_context *ctx = fence->ctx;
9585 ctx->fence_retire(fence->fence_cookie, ctx->fence_retire_data);
9586
9587 free_fence_locked(fence);
9588 }
9589 }
9590
vrend_get_one_query_result(GLuint query_id,bool use_64,uint64_t * result)9591 static bool vrend_get_one_query_result(GLuint query_id, bool use_64, uint64_t *result)
9592 {
9593 GLuint ready;
9594 GLuint passed;
9595 GLuint64 pass64;
9596
9597 glGetQueryObjectuiv(query_id, GL_QUERY_RESULT_AVAILABLE_ARB, &ready);
9598
9599 if (!ready)
9600 return false;
9601
9602 if (use_64) {
9603 glGetQueryObjectui64v(query_id, GL_QUERY_RESULT_ARB, &pass64);
9604 *result = pass64;
9605 } else {
9606 glGetQueryObjectuiv(query_id, GL_QUERY_RESULT_ARB, &passed);
9607 *result = passed;
9608 }
9609 return true;
9610 }
9611
9612 static inline void
vrend_update_oq_samples_multiplier(struct vrend_context * ctx)9613 vrend_update_oq_samples_multiplier(struct vrend_context *ctx)
9614 {
9615 if (!vrend_state.current_ctx->sub->fake_occlusion_query_samples_passed_multiplier) {
9616 uint32_t multiplier = 0;
9617 bool tweaked = vrend_get_tweak_is_active_with_params(vrend_get_context_tweaks(ctx),
9618 virgl_tweak_gles_tf3_samples_passes_multiplier, &multiplier);
9619 vrend_state.current_ctx->sub->fake_occlusion_query_samples_passed_multiplier =
9620 tweaked ? multiplier: fake_occlusion_query_samples_passed_default;
9621 }
9622 }
9623
9624
vrend_check_query_locked(struct vrend_query * query)9625 static bool vrend_check_query_locked(struct vrend_query *query)
9626 {
9627 struct virgl_host_query_state state;
9628 bool ret;
9629
9630 state.result_size = vrend_is_timer_query(query->gltype) ? 8 : 4;
9631 ret = vrend_get_one_query_result(query->id, state.result_size == 8,
9632 &state.result);
9633 if (ret == false)
9634 return false;
9635
9636 /* We got a boolean, but the client wanted the actual number of samples
9637 * blow the number up so that the client doesn't think it was just one pixel
9638 * and discards an object that might be bigger */
9639 if (query->fake_samples_passed) {
9640 vrend_update_oq_samples_multiplier(vrend_state.current_ctx);
9641 state.result *= vrend_state.current_ctx->sub->fake_occlusion_query_samples_passed_multiplier;
9642 }
9643
9644 state.query_state = VIRGL_QUERY_STATE_DONE;
9645
9646 if (query->res->iov) {
9647 vrend_write_to_iovec(query->res->iov, query->res->num_iovs, 0,
9648 (const void *) &state, sizeof(state));
9649 } else {
9650 *((struct virgl_host_query_state *) query->res->ptr) = state;
9651 }
9652
9653 return true;
9654 }
9655
vrend_hw_switch_query_context(struct vrend_context * ctx)9656 static bool vrend_hw_switch_query_context(struct vrend_context *ctx)
9657 {
9658 if (vrend_state.use_async_fence_cb) {
9659 if (!ctx)
9660 return false;
9661
9662 if (ctx == vrend_state.current_sync_thread_ctx)
9663 return true;
9664
9665 if (ctx->ctx_id != 0 && ctx->in_error)
9666 return false;
9667
9668 vrend_clicbs->make_current(ctx->sub->gl_context);
9669 vrend_state.current_sync_thread_ctx = ctx;
9670 return true;
9671 } else {
9672 return vrend_hw_switch_context(ctx, true);
9673 }
9674 }
9675
vrend_renderer_check_queries_locked(void)9676 static void vrend_renderer_check_queries_locked(void)
9677 {
9678 struct vrend_query *query, *stor;
9679
9680 LIST_FOR_EACH_ENTRY_SAFE(query, stor, &vrend_state.waiting_query_list, waiting_queries) {
9681 if (!vrend_hw_switch_query_context(query->ctx) ||
9682 vrend_check_query_locked(query))
9683 list_delinit(&query->waiting_queries);
9684 }
9685 }
9686
vrend_hw_switch_context(struct vrend_context * ctx,bool now)9687 bool vrend_hw_switch_context(struct vrend_context *ctx, bool now)
9688 {
9689 if (!ctx)
9690 return false;
9691
9692 if (ctx == vrend_state.current_ctx && ctx->ctx_switch_pending == false)
9693 return true;
9694
9695 if (ctx->ctx_id != 0 && ctx->in_error) {
9696 return false;
9697 }
9698
9699 ctx->ctx_switch_pending = true;
9700 if (now == true) {
9701 vrend_finish_context_switch(ctx);
9702 }
9703 vrend_state.current_ctx = ctx;
9704 return true;
9705 }
9706
vrend_finish_context_switch(struct vrend_context * ctx)9707 static void vrend_finish_context_switch(struct vrend_context *ctx)
9708 {
9709 if (ctx->ctx_switch_pending == false)
9710 return;
9711 ctx->ctx_switch_pending = false;
9712
9713 if (vrend_state.current_hw_ctx == ctx)
9714 return;
9715
9716 vrend_state.current_hw_ctx = ctx;
9717
9718 vrend_clicbs->make_current(ctx->sub->gl_context);
9719 }
9720
9721 void
vrend_renderer_object_destroy(struct vrend_context * ctx,uint32_t handle)9722 vrend_renderer_object_destroy(struct vrend_context *ctx, uint32_t handle)
9723 {
9724 vrend_object_remove(ctx->sub->object_hash, handle, 0);
9725 }
9726
vrend_renderer_object_insert(struct vrend_context * ctx,void * data,uint32_t handle,enum virgl_object_type type)9727 uint32_t vrend_renderer_object_insert(struct vrend_context *ctx, void *data,
9728 uint32_t handle, enum virgl_object_type type)
9729 {
9730 return vrend_object_insert(ctx->sub->object_hash, data, handle, type);
9731 }
9732
vrend_create_query(struct vrend_context * ctx,uint32_t handle,uint32_t query_type,uint32_t query_index,uint32_t res_handle,UNUSED uint32_t offset)9733 int vrend_create_query(struct vrend_context *ctx, uint32_t handle,
9734 uint32_t query_type, uint32_t query_index,
9735 uint32_t res_handle, UNUSED uint32_t offset)
9736 {
9737 struct vrend_query *q;
9738 struct vrend_resource *res;
9739 uint32_t ret_handle;
9740 bool fake_samples_passed = false;
9741 res = vrend_renderer_ctx_res_lookup(ctx, res_handle);
9742 if (!res || !has_bit(res->storage_bits, VREND_STORAGE_HOST_SYSTEM_MEMORY)) {
9743 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle);
9744 return EINVAL;
9745 }
9746
9747 /* If we don't have ARB_occlusion_query, at least try to fake GL_SAMPLES_PASSED
9748 * by using GL_ANY_SAMPLES_PASSED (i.e. EXT_occlusion_query_boolean) */
9749 if (!has_feature(feat_occlusion_query) && query_type == PIPE_QUERY_OCCLUSION_COUNTER) {
9750 VREND_DEBUG(dbg_query, ctx, "GL_SAMPLES_PASSED not supported will try GL_ANY_SAMPLES_PASSED\n");
9751 query_type = PIPE_QUERY_OCCLUSION_PREDICATE;
9752 fake_samples_passed = true;
9753 }
9754
9755 if (query_type == PIPE_QUERY_OCCLUSION_PREDICATE &&
9756 !has_feature(feat_occlusion_query_boolean)) {
9757 vrend_report_context_error(ctx, VIRGL_ERROR_GL_ANY_SAMPLES_PASSED, res_handle);
9758 return EINVAL;
9759 }
9760
9761 q = CALLOC_STRUCT(vrend_query);
9762 if (!q)
9763 return ENOMEM;
9764
9765 list_inithead(&q->waiting_queries);
9766 q->type = query_type;
9767 q->index = query_index;
9768 q->ctx = ctx;
9769 q->fake_samples_passed = fake_samples_passed;
9770
9771 vrend_resource_reference(&q->res, res);
9772
9773 switch (q->type) {
9774 case PIPE_QUERY_OCCLUSION_COUNTER:
9775 q->gltype = GL_SAMPLES_PASSED_ARB;
9776 break;
9777 case PIPE_QUERY_OCCLUSION_PREDICATE:
9778 if (has_feature(feat_occlusion_query_boolean)) {
9779 q->gltype = GL_ANY_SAMPLES_PASSED;
9780 break;
9781 } else
9782 return EINVAL;
9783 case PIPE_QUERY_TIMESTAMP:
9784 if (!has_feature(feat_timer_query))
9785 return EINVAL;
9786 q->gltype = GL_TIMESTAMP;
9787 break;
9788 case PIPE_QUERY_TIME_ELAPSED:
9789 if (!has_feature(feat_timer_query))
9790 return EINVAL;
9791 q->gltype = GL_TIME_ELAPSED;
9792 break;
9793 case PIPE_QUERY_PRIMITIVES_GENERATED:
9794 q->gltype = GL_PRIMITIVES_GENERATED;
9795 break;
9796 case PIPE_QUERY_PRIMITIVES_EMITTED:
9797 q->gltype = GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN;
9798 break;
9799 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
9800 q->gltype = GL_ANY_SAMPLES_PASSED_CONSERVATIVE;
9801 break;
9802 case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
9803 if (!has_feature(feat_transform_feedback_overflow_query))
9804 return EINVAL;
9805 q->gltype = GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB;
9806 break;
9807 case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
9808 if (!has_feature(feat_transform_feedback_overflow_query))
9809 return EINVAL;
9810 q->gltype = GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB;
9811 break;
9812 default:
9813 vrend_printf("unknown query object received %d\n", q->type);
9814 break;
9815 }
9816
9817 glGenQueries(1, &q->id);
9818
9819 ret_handle = vrend_renderer_object_insert(ctx, q, handle,
9820 VIRGL_OBJECT_QUERY);
9821 if (!ret_handle) {
9822 FREE(q);
9823 return ENOMEM;
9824 }
9825 return 0;
9826 }
9827
vrend_destroy_query(struct vrend_query * query)9828 static void vrend_destroy_query(struct vrend_query *query)
9829 {
9830 vrend_resource_reference(&query->res, NULL);
9831 list_del(&query->waiting_queries);
9832 glDeleteQueries(1, &query->id);
9833 free(query);
9834 }
9835
vrend_destroy_query_object(void * obj_ptr)9836 static void vrend_destroy_query_object(void *obj_ptr)
9837 {
9838 struct vrend_query *query = obj_ptr;
9839 vrend_destroy_query(query);
9840 }
9841
vrend_begin_query(struct vrend_context * ctx,uint32_t handle)9842 int vrend_begin_query(struct vrend_context *ctx, uint32_t handle)
9843 {
9844 struct vrend_query *q;
9845
9846 q = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_QUERY);
9847 if (!q)
9848 return EINVAL;
9849
9850 if (q->index > 0 && !has_feature(feat_transform_feedback3))
9851 return EINVAL;
9852
9853 lock_sync();
9854 list_delinit(&q->waiting_queries);
9855 unlock_sync();
9856
9857 if (q->gltype == GL_TIMESTAMP)
9858 return 0;
9859
9860 if (q->index > 0)
9861 glBeginQueryIndexed(q->gltype, q->index, q->id);
9862 else
9863 glBeginQuery(q->gltype, q->id);
9864 return 0;
9865 }
9866
vrend_end_query(struct vrend_context * ctx,uint32_t handle)9867 int vrend_end_query(struct vrend_context *ctx, uint32_t handle)
9868 {
9869 struct vrend_query *q;
9870 q = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_QUERY);
9871 if (!q)
9872 return EINVAL;
9873
9874 if (q->index > 0 && !has_feature(feat_transform_feedback3))
9875 return EINVAL;
9876
9877 if (vrend_is_timer_query(q->gltype)) {
9878 if (q->gltype == GL_TIMESTAMP && !has_feature(feat_timer_query)) {
9879 report_gles_warn(ctx, GLES_WARN_TIMESTAMP);
9880 } else if (q->gltype == GL_TIMESTAMP) {
9881 glQueryCounter(q->id, q->gltype);
9882 } else {
9883 /* remove from active query list for this context */
9884 glEndQuery(q->gltype);
9885 }
9886 return 0;
9887 }
9888
9889 if (q->index > 0)
9890 glEndQueryIndexed(q->gltype, q->index);
9891 else
9892 glEndQuery(q->gltype);
9893 return 0;
9894 }
9895
vrend_get_query_result(struct vrend_context * ctx,uint32_t handle,UNUSED uint32_t wait)9896 void vrend_get_query_result(struct vrend_context *ctx, uint32_t handle,
9897 UNUSED uint32_t wait)
9898 {
9899 struct vrend_query *q;
9900 bool ret;
9901
9902 q = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_QUERY);
9903 if (!q)
9904 return;
9905
9906 lock_sync();
9907 ret = vrend_check_query_locked(q);
9908 if (ret) {
9909 list_delinit(&q->waiting_queries);
9910 } else if (LIST_IS_EMPTY(&q->waiting_queries)) {
9911 list_addtail(&q->waiting_queries, &vrend_state.waiting_query_list);
9912 }
9913 unlock_sync();
9914 }
9915
9916 #define COPY_QUERY_RESULT_TO_BUFFER(resid, offset, pvalue, size, multiplier) \
9917 glBindBuffer(GL_QUERY_BUFFER, resid); \
9918 value *= multiplier; \
9919 void* buf = glMapBufferRange(GL_QUERY_BUFFER, offset, size, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT); \
9920 if (buf) memcpy(buf, &value, size); \
9921 glUnmapBuffer(GL_QUERY_BUFFER);
9922
buffer_offset(intptr_t i)9923 static inline void *buffer_offset(intptr_t i)
9924 {
9925 return (void *)i;
9926 }
9927
vrend_get_query_result_qbo(struct vrend_context * ctx,uint32_t handle,uint32_t qbo_handle,uint32_t wait,uint32_t result_type,uint32_t offset,int32_t index)9928 void vrend_get_query_result_qbo(struct vrend_context *ctx, uint32_t handle,
9929 uint32_t qbo_handle,
9930 uint32_t wait, uint32_t result_type, uint32_t offset,
9931 int32_t index)
9932 {
9933 struct vrend_query *q;
9934 struct vrend_resource *res;
9935
9936 if (!has_feature(feat_qbo))
9937 return;
9938
9939 q = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_QUERY);
9940 if (!q)
9941 return;
9942
9943 res = vrend_renderer_ctx_res_lookup(ctx, qbo_handle);
9944 if (!res) {
9945 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, qbo_handle);
9946 return;
9947 }
9948
9949 VREND_DEBUG(dbg_query, ctx, "Get query result from Query:%d\n", q->id);
9950
9951 GLenum qtype;
9952
9953 if (index == -1)
9954 qtype = GL_QUERY_RESULT_AVAILABLE;
9955 else
9956 qtype = wait ? GL_QUERY_RESULT : GL_QUERY_RESULT_NO_WAIT;
9957
9958 if (!q->fake_samples_passed) {
9959 glBindBuffer(GL_QUERY_BUFFER, res->id);
9960 switch ((enum pipe_query_value_type)result_type) {
9961 case PIPE_QUERY_TYPE_I32:
9962 glGetQueryObjectiv(q->id, qtype, buffer_offset(offset));
9963 break;
9964 case PIPE_QUERY_TYPE_U32:
9965 glGetQueryObjectuiv(q->id, qtype, buffer_offset(offset));
9966 break;
9967 case PIPE_QUERY_TYPE_I64:
9968 glGetQueryObjecti64v(q->id, qtype, buffer_offset(offset));
9969 break;
9970 case PIPE_QUERY_TYPE_U64:
9971 glGetQueryObjectui64v(q->id, qtype, buffer_offset(offset));
9972 break;
9973 }
9974 } else {
9975 VREND_DEBUG(dbg_query, ctx, "Was emulating GL_PIXELS_PASSED by GL_ANY_PIXELS_PASSED, artifically upscaling the result\n");
9976 /* The application expects a sample count but we have only a boolean
9977 * so we blow the result up by 1/10 of the screen space to make sure the
9978 * app doesn't think only one sample passed. */
9979 vrend_update_oq_samples_multiplier(ctx);
9980 switch ((enum pipe_query_value_type)result_type) {
9981 case PIPE_QUERY_TYPE_I32: {
9982 GLint value;
9983 glGetQueryObjectiv(q->id, qtype, &value);
9984 COPY_QUERY_RESULT_TO_BUFFER(q->id, offset, value, 4, ctx->sub->fake_occlusion_query_samples_passed_multiplier);
9985 break;
9986 }
9987 case PIPE_QUERY_TYPE_U32: {
9988 GLuint value;
9989 glGetQueryObjectuiv(q->id, qtype, &value);
9990 COPY_QUERY_RESULT_TO_BUFFER(q->id, offset, value, 4, ctx->sub->fake_occlusion_query_samples_passed_multiplier);
9991 break;
9992 }
9993 case PIPE_QUERY_TYPE_I64: {
9994 GLint64 value;
9995 glGetQueryObjecti64v(q->id, qtype, &value);
9996 COPY_QUERY_RESULT_TO_BUFFER(q->id, offset, value, 8, ctx->sub->fake_occlusion_query_samples_passed_multiplier);
9997 break;
9998 }
9999 case PIPE_QUERY_TYPE_U64: {
10000 GLuint64 value;
10001 glGetQueryObjectui64v(q->id, qtype, &value);
10002 COPY_QUERY_RESULT_TO_BUFFER(q->id, offset, value, 8, ctx->sub->fake_occlusion_query_samples_passed_multiplier);
10003 break;
10004 }
10005 }
10006
10007
10008 }
10009
10010 glBindBuffer(GL_QUERY_BUFFER, 0);
10011 }
10012
vrend_pause_render_condition(struct vrend_context * ctx,bool pause)10013 static void vrend_pause_render_condition(struct vrend_context *ctx, bool pause)
10014 {
10015 if (pause) {
10016 if (ctx->sub->cond_render_q_id) {
10017 if (has_feature(feat_gl_conditional_render))
10018 glEndConditionalRender();
10019 else if (has_feature(feat_nv_conditional_render))
10020 glEndConditionalRenderNV();
10021 }
10022 } else {
10023 if (ctx->sub->cond_render_q_id) {
10024 if (has_feature(feat_gl_conditional_render))
10025 glBeginConditionalRender(ctx->sub->cond_render_q_id,
10026 ctx->sub->cond_render_gl_mode);
10027 else if (has_feature(feat_nv_conditional_render))
10028 glBeginConditionalRenderNV(ctx->sub->cond_render_q_id,
10029 ctx->sub->cond_render_gl_mode);
10030 }
10031 }
10032 }
10033
vrend_render_condition(struct vrend_context * ctx,uint32_t handle,bool condition,uint mode)10034 void vrend_render_condition(struct vrend_context *ctx,
10035 uint32_t handle,
10036 bool condition,
10037 uint mode)
10038 {
10039 struct vrend_query *q;
10040 GLenum glmode = 0;
10041
10042 if (handle == 0) {
10043 if (has_feature(feat_gl_conditional_render))
10044 glEndConditionalRender();
10045 else if (has_feature(feat_nv_conditional_render))
10046 glEndConditionalRenderNV();
10047 ctx->sub->cond_render_q_id = 0;
10048 ctx->sub->cond_render_gl_mode = 0;
10049 return;
10050 }
10051
10052 q = vrend_object_lookup(ctx->sub->object_hash, handle, VIRGL_OBJECT_QUERY);
10053 if (!q)
10054 return;
10055
10056 if (condition && !has_feature(feat_conditional_render_inverted))
10057 return;
10058 switch (mode) {
10059 case PIPE_RENDER_COND_WAIT:
10060 glmode = condition ? GL_QUERY_WAIT_INVERTED : GL_QUERY_WAIT;
10061 break;
10062 case PIPE_RENDER_COND_NO_WAIT:
10063 glmode = condition ? GL_QUERY_NO_WAIT_INVERTED : GL_QUERY_NO_WAIT;
10064 break;
10065 case PIPE_RENDER_COND_BY_REGION_WAIT:
10066 glmode = condition ? GL_QUERY_BY_REGION_WAIT_INVERTED : GL_QUERY_BY_REGION_WAIT;
10067 break;
10068 case PIPE_RENDER_COND_BY_REGION_NO_WAIT:
10069 glmode = condition ? GL_QUERY_BY_REGION_NO_WAIT_INVERTED : GL_QUERY_BY_REGION_NO_WAIT;
10070 break;
10071 default:
10072 vrend_printf( "unhandled condition %x\n", mode);
10073 }
10074
10075 ctx->sub->cond_render_q_id = q->id;
10076 ctx->sub->cond_render_gl_mode = glmode;
10077 if (has_feature(feat_gl_conditional_render))
10078 glBeginConditionalRender(q->id, glmode);
10079 if (has_feature(feat_nv_conditional_render))
10080 glBeginConditionalRenderNV(q->id, glmode);
10081 }
10082
vrend_create_so_target(struct vrend_context * ctx,uint32_t handle,uint32_t res_handle,uint32_t buffer_offset,uint32_t buffer_size)10083 int vrend_create_so_target(struct vrend_context *ctx,
10084 uint32_t handle,
10085 uint32_t res_handle,
10086 uint32_t buffer_offset,
10087 uint32_t buffer_size)
10088 {
10089 struct vrend_so_target *target;
10090 struct vrend_resource *res;
10091 int ret_handle;
10092 res = vrend_renderer_ctx_res_lookup(ctx, res_handle);
10093 if (!res) {
10094 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle);
10095 return EINVAL;
10096 }
10097
10098 target = CALLOC_STRUCT(vrend_so_target);
10099 if (!target)
10100 return ENOMEM;
10101
10102 pipe_reference_init(&target->reference, 1);
10103 target->res_handle = res_handle;
10104 target->buffer_offset = buffer_offset;
10105 target->buffer_size = buffer_size;
10106 target->sub_ctx = ctx->sub;
10107 vrend_resource_reference(&target->buffer, res);
10108
10109 ret_handle = vrend_renderer_object_insert(ctx, target, handle,
10110 VIRGL_OBJECT_STREAMOUT_TARGET);
10111 if (ret_handle == 0) {
10112 FREE(target);
10113 return ENOMEM;
10114 }
10115 return 0;
10116 }
10117
vrender_get_glsl_version(void)10118 static int vrender_get_glsl_version(void)
10119 {
10120 int major_local = 0, minor_local = 0;
10121 const GLubyte *version_str;
10122 MAYBE_UNUSED int c;
10123
10124 version_str = glGetString(GL_SHADING_LANGUAGE_VERSION);
10125 if (vrend_state.use_gles) {
10126 char tmp[20];
10127 c = sscanf((const char *)version_str, "%s %s %s %s %i.%i",
10128 tmp, tmp, tmp, tmp, &major_local, &minor_local);
10129 assert(c == 6);
10130 } else {
10131 c = sscanf((const char *)version_str, "%i.%i",
10132 &major_local, &minor_local);
10133 assert(c == 2);
10134 }
10135
10136 return (major_local * 100) + minor_local;
10137 }
10138
vrend_fill_caps_glsl_version(int gl_ver,int gles_ver,union virgl_caps * caps)10139 static void vrend_fill_caps_glsl_version(int gl_ver, int gles_ver,
10140 union virgl_caps *caps)
10141 {
10142 if (gles_ver > 0) {
10143 caps->v1.glsl_level = 120;
10144
10145 if (gles_ver >= 31)
10146 caps->v1.glsl_level = 310;
10147 else if (gles_ver >= 30)
10148 caps->v1.glsl_level = 130;
10149 }
10150
10151 if (gl_ver > 0) {
10152 caps->v1.glsl_level = 130;
10153
10154 if (gl_ver == 31)
10155 caps->v1.glsl_level = 140;
10156 else if (gl_ver == 32)
10157 caps->v1.glsl_level = 150;
10158 else if (gl_ver >= 33)
10159 caps->v1.glsl_level = 10 * gl_ver;
10160 }
10161
10162 if (caps->v1.glsl_level < 400) {
10163 if (has_feature(feat_tessellation) &&
10164 has_feature(feat_geometry_shader) &&
10165 has_feature(feat_gpu_shader5)) {
10166 /* This is probably a lie, but Gallium enables
10167 * OES_geometry_shader and ARB_gpu_shader5
10168 * based on this value, apart from that it doesn't
10169 * seem to be a crucial value */
10170 caps->v1.glsl_level = 400;
10171
10172 /* Let's lie a bit more */
10173 if (has_feature(feat_separate_shader_objects)) {
10174 caps->v1.glsl_level = 410;
10175
10176 /* Compute shaders require GLSL 4.30 unless the shader explicitely
10177 * specifies GL_ARB_compute_shader as required. However, on OpenGL ES
10178 * they are already supported with version 3.10, so if we already
10179 * advertise a feature level of 410, just lie a bit more to make
10180 * compute shaders available to GL programs that don't specify the
10181 * extension within the shaders. */
10182 if (has_feature(feat_compute_shader))
10183 caps->v1.glsl_level = 430;
10184 }
10185 }
10186 }
10187 vrend_printf("GLSL feature level %d\n", caps->v1.glsl_level);
10188 }
10189
set_format_bit(struct virgl_supported_format_mask * mask,enum virgl_formats fmt)10190 static void set_format_bit(struct virgl_supported_format_mask *mask, enum virgl_formats fmt)
10191 {
10192 assert(fmt < VIRGL_FORMAT_MAX);
10193 unsigned val = (unsigned)fmt;
10194 unsigned idx = val / 32;
10195 unsigned bit = val % 32;
10196 assert(idx < ARRAY_SIZE(mask->bitmask));
10197 mask->bitmask[idx] |= 1u << bit;
10198 }
10199
10200 /*
10201 * Does all of the common caps setting,
10202 * if it dedects a early out returns true.
10203 */
vrend_renderer_fill_caps_v1(int gl_ver,int gles_ver,union virgl_caps * caps)10204 static void vrend_renderer_fill_caps_v1(int gl_ver, int gles_ver, union virgl_caps *caps)
10205 {
10206 int i;
10207 GLint max;
10208
10209 /*
10210 * We can't fully support this feature on GLES,
10211 * but it is needed for OpenGL 2.1 so lie.
10212 */
10213 caps->v1.bset.occlusion_query = 1;
10214
10215 /* Set supported prims here as we now know what shaders we support. */
10216 caps->v1.prim_mask = (1 << PIPE_PRIM_POINTS) | (1 << PIPE_PRIM_LINES) |
10217 (1 << PIPE_PRIM_LINE_STRIP) | (1 << PIPE_PRIM_LINE_LOOP) |
10218 (1 << PIPE_PRIM_TRIANGLES) | (1 << PIPE_PRIM_TRIANGLE_STRIP) |
10219 (1 << PIPE_PRIM_TRIANGLE_FAN);
10220
10221 if (gl_ver > 0 && !vrend_state.use_core_profile) {
10222 caps->v1.bset.poly_stipple = 1;
10223 caps->v1.bset.color_clamping = 1;
10224 caps->v1.prim_mask |= (1 << PIPE_PRIM_QUADS) |
10225 (1 << PIPE_PRIM_QUAD_STRIP) |
10226 (1 << PIPE_PRIM_POLYGON);
10227 }
10228
10229 if (caps->v1.glsl_level >= 150) {
10230 caps->v1.prim_mask |= (1 << PIPE_PRIM_LINES_ADJACENCY) |
10231 (1 << PIPE_PRIM_LINE_STRIP_ADJACENCY) |
10232 (1 << PIPE_PRIM_TRIANGLES_ADJACENCY) |
10233 (1 << PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY);
10234 }
10235 if (caps->v1.glsl_level >= 400 || has_feature(feat_tessellation))
10236 caps->v1.prim_mask |= (1 << PIPE_PRIM_PATCHES);
10237
10238 if (epoxy_has_gl_extension("GL_ARB_vertex_type_10f_11f_11f_rev"))
10239 set_format_bit(&caps->v1.vertexbuffer, VIRGL_FORMAT_R11G11B10_FLOAT);
10240
10241 if (has_feature(feat_nv_conditional_render) ||
10242 has_feature(feat_gl_conditional_render))
10243 caps->v1.bset.conditional_render = 1;
10244
10245 if (has_feature(feat_indep_blend))
10246 caps->v1.bset.indep_blend_enable = 1;
10247
10248 if (has_feature(feat_draw_instance))
10249 caps->v1.bset.instanceid = 1;
10250
10251 if (has_feature(feat_ubo)) {
10252 glGetIntegerv(GL_MAX_VERTEX_UNIFORM_BLOCKS, &max);
10253 caps->v1.max_uniform_blocks = max + 1;
10254 }
10255
10256 if (has_feature(feat_depth_clamp))
10257 caps->v1.bset.depth_clip_disable = 1;
10258
10259 if (gl_ver >= 32) {
10260 caps->v1.bset.fragment_coord_conventions = 1;
10261 caps->v1.bset.seamless_cube_map = 1;
10262 } else {
10263 if (epoxy_has_gl_extension("GL_ARB_fragment_coord_conventions"))
10264 caps->v1.bset.fragment_coord_conventions = 1;
10265 if (epoxy_has_gl_extension("GL_ARB_seamless_cube_map") || gles_ver >= 30)
10266 caps->v1.bset.seamless_cube_map = 1;
10267 }
10268
10269 if (epoxy_has_gl_extension("GL_AMD_seamless_cube_map_per_texture")) {
10270 caps->v1.bset.seamless_cube_map_per_texture = 1;
10271 }
10272
10273 if (has_feature(feat_texture_multisample))
10274 caps->v1.bset.texture_multisample = 1;
10275
10276 if (has_feature(feat_tessellation))
10277 caps->v1.bset.has_tessellation_shaders = 1;
10278
10279 if (has_feature(feat_sample_shading))
10280 caps->v1.bset.has_sample_shading = 1;
10281
10282 if (has_feature(feat_indirect_draw))
10283 caps->v1.bset.has_indirect_draw = 1;
10284
10285 if (has_feature(feat_indep_blend_func))
10286 caps->v1.bset.indep_blend_func = 1;
10287
10288 if (has_feature(feat_cube_map_array))
10289 caps->v1.bset.cube_map_array = 1;
10290
10291 if (has_feature(feat_texture_query_lod))
10292 caps->v1.bset.texture_query_lod = 1;
10293
10294 if (gl_ver >= 40) {
10295 caps->v1.bset.has_fp64 = 1;
10296 } else {
10297 /* need gpu shader 5 for bitfield insert */
10298 if (epoxy_has_gl_extension("GL_ARB_gpu_shader_fp64") &&
10299 epoxy_has_gl_extension("GL_ARB_gpu_shader5"))
10300 caps->v1.bset.has_fp64 = 1;
10301 }
10302
10303 if (has_feature(feat_base_instance))
10304 caps->v1.bset.start_instance = 1;
10305
10306 if (epoxy_has_gl_extension("GL_ARB_shader_stencil_export")) {
10307 caps->v1.bset.shader_stencil_export = 1;
10308 }
10309
10310 if (has_feature(feat_conditional_render_inverted))
10311 caps->v1.bset.conditional_render_inverted = 1;
10312
10313 if (gl_ver >= 45) {
10314 caps->v1.bset.has_cull = 1;
10315 caps->v1.bset.derivative_control = 1;
10316 } else {
10317 if (has_feature(feat_cull_distance))
10318 caps->v1.bset.has_cull = 1;
10319 if (epoxy_has_gl_extension("GL_ARB_derivative_control"))
10320 caps->v1.bset.derivative_control = 1;
10321 }
10322
10323 if (has_feature(feat_polygon_offset_clamp))
10324 caps->v1.bset.polygon_offset_clamp = 1;
10325
10326 if (has_feature(feat_transform_feedback_overflow_query))
10327 caps->v1.bset.transform_feedback_overflow_query = 1;
10328
10329 if (epoxy_has_gl_extension("GL_EXT_texture_mirror_clamp") ||
10330 epoxy_has_gl_extension("GL_ARB_texture_mirror_clamp_to_edge") ||
10331 epoxy_has_gl_extension("GL_EXT_texture_mirror_clamp_to_edge")) {
10332 caps->v1.bset.mirror_clamp = true;
10333 }
10334
10335 if (has_feature(feat_texture_array)) {
10336 glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &max);
10337 caps->v1.max_texture_array_layers = max;
10338 }
10339
10340 /* we need tf3 so we can do gallium skip buffers */
10341 if (has_feature(feat_transform_feedback)) {
10342 if (has_feature(feat_transform_feedback2))
10343 caps->v1.bset.streamout_pause_resume = 1;
10344
10345 if (has_feature(feat_transform_feedback3)) {
10346 glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_BUFFERS, &max);
10347 caps->v1.max_streamout_buffers = max;
10348 } else if (gles_ver > 0) {
10349 glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &max);
10350 /* As with the earlier version of transform feedback this min 4. */
10351 if (max >= 4) {
10352 caps->v1.max_streamout_buffers = 4;
10353 }
10354 } else
10355 caps->v1.max_streamout_buffers = 4;
10356 }
10357
10358 if (has_feature(feat_dual_src_blend)) {
10359 glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS, &max);
10360 caps->v1.max_dual_source_render_targets = max;
10361 }
10362
10363 if (has_feature(feat_arb_or_gles_ext_texture_buffer)) {
10364 glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &max);
10365 caps->v1.max_tbo_size = max;
10366 }
10367
10368 if (has_feature(feat_texture_gather)) {
10369 if (gl_ver > 0) {
10370 glGetIntegerv(GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB, &max);
10371 caps->v1.max_texture_gather_components = max;
10372 } else {
10373 caps->v1.max_texture_gather_components = 4;
10374 }
10375 }
10376
10377 if (has_feature(feat_viewport_array)) {
10378 glGetIntegerv(GL_MAX_VIEWPORTS, &max);
10379 caps->v1.max_viewports = max;
10380 } else {
10381 caps->v1.max_viewports = 1;
10382 }
10383
10384 /* Common limits for all backends. */
10385 caps->v1.max_render_targets = vrend_state.max_draw_buffers;
10386
10387 glGetIntegerv(GL_MAX_SAMPLES, &max);
10388 caps->v1.max_samples = max;
10389
10390 /* All of the formats are common. */
10391 for (i = 0; i < VIRGL_FORMAT_MAX; i++) {
10392 enum virgl_formats fmt = (enum virgl_formats)i;
10393 if (tex_conv_table[i].internalformat != 0 || fmt == VIRGL_FORMAT_YV12 ||
10394 fmt == VIRGL_FORMAT_NV12) {
10395 if (vrend_format_can_sample(fmt)) {
10396 set_format_bit(&caps->v1.sampler, fmt);
10397 if (vrend_format_can_render(fmt))
10398 set_format_bit(&caps->v1.render, fmt);
10399 }
10400 }
10401 }
10402
10403 /* These are filled in by the init code, so are common. */
10404 if (has_feature(feat_nv_prim_restart) ||
10405 has_feature(feat_gl_prim_restart)) {
10406 caps->v1.bset.primitive_restart = 1;
10407 }
10408 }
10409
vrend_renderer_fill_caps_v2(int gl_ver,int gles_ver,union virgl_caps * caps)10410 static void vrend_renderer_fill_caps_v2(int gl_ver, int gles_ver, union virgl_caps *caps)
10411 {
10412 GLint max;
10413 GLfloat range[2];
10414 uint32_t video_memory;
10415 const char *renderer = (const char *)glGetString(GL_RENDERER);
10416
10417 /* Count this up when you add a feature flag that is used to set a CAP in
10418 * the guest that was set unconditionally before. Then check that flag and
10419 * this value to avoid regressions when a guest with a new mesa version is
10420 * run on an old virgl host. Use it also to indicate non-cap fixes on the
10421 * host that help enable features in the guest. */
10422 caps->v2.host_feature_check_version = 5;
10423
10424 /* Forward host GL_RENDERER to the guest. */
10425 strncpy(caps->v2.renderer, renderer, sizeof(caps->v2.renderer) - 1);
10426
10427 glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, range);
10428 caps->v2.min_aliased_point_size = range[0];
10429 caps->v2.max_aliased_point_size = range[1];
10430
10431 glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, range);
10432 caps->v2.min_aliased_line_width = range[0];
10433 caps->v2.max_aliased_line_width = range[1];
10434
10435 if (gl_ver > 0) {
10436 glGetFloatv(GL_SMOOTH_POINT_SIZE_RANGE, range);
10437 caps->v2.min_smooth_point_size = range[0];
10438 caps->v2.max_smooth_point_size = range[1];
10439
10440 glGetFloatv(GL_SMOOTH_LINE_WIDTH_RANGE, range);
10441 caps->v2.min_smooth_line_width = range[0];
10442 caps->v2.max_smooth_line_width = range[1];
10443 }
10444
10445 glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &caps->v2.max_texture_lod_bias);
10446 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, (GLint*)&caps->v2.max_vertex_attribs);
10447
10448 if (gl_ver >= 32 || (vrend_state.use_gles && gl_ver >= 30))
10449 glGetIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, &max);
10450 else
10451 max = 64; // minimum required value
10452
10453 caps->v2.max_vertex_outputs = max / 4;
10454
10455 glGetIntegerv(GL_MIN_PROGRAM_TEXEL_OFFSET, &caps->v2.min_texel_offset);
10456 glGetIntegerv(GL_MAX_PROGRAM_TEXEL_OFFSET, &caps->v2.max_texel_offset);
10457
10458 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, (GLint*)&caps->v2.uniform_buffer_offset_alignment);
10459
10460 glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint*)&caps->v2.max_texture_2d_size);
10461 glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, (GLint*)&caps->v2.max_texture_3d_size);
10462 glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, (GLint*)&caps->v2.max_texture_cube_size);
10463 vrend_state.max_texture_2d_size = caps->v2.max_texture_2d_size;
10464 vrend_state.max_texture_3d_size = caps->v2.max_texture_3d_size;
10465 vrend_state.max_texture_cube_size = caps->v2.max_texture_cube_size;
10466 VREND_DEBUG(dbg_features, NULL, "Texture limits: 2D:%u 3D:%u Cube:%u\n",
10467 vrend_state.max_texture_2d_size, vrend_state.max_texture_3d_size,
10468 vrend_state.max_texture_cube_size);
10469
10470 if (has_feature(feat_geometry_shader)) {
10471 glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, (GLint*)&caps->v2.max_geom_output_vertices);
10472 glGetIntegerv(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS, (GLint*)&caps->v2.max_geom_total_output_components);
10473 }
10474
10475 if (has_feature(feat_tessellation)) {
10476 glGetIntegerv(GL_MAX_TESS_PATCH_COMPONENTS, &max);
10477 caps->v2.max_shader_patch_varyings = max / 4;
10478 } else
10479 caps->v2.max_shader_patch_varyings = 0;
10480
10481 if (has_feature(feat_texture_gather)) {
10482 glGetIntegerv(GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET, &caps->v2.min_texture_gather_offset);
10483 glGetIntegerv(GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET, &caps->v2.max_texture_gather_offset);
10484 }
10485
10486 if (has_feature(feat_texture_buffer_range)) {
10487 glGetIntegerv(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT, (GLint*)&caps->v2.texture_buffer_offset_alignment);
10488 }
10489
10490 if (has_feature(feat_ssbo)) {
10491 glGetIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, (GLint*)&caps->v2.shader_buffer_offset_alignment);
10492
10493 glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &max);
10494 if (max > PIPE_MAX_SHADER_BUFFERS)
10495 max = PIPE_MAX_SHADER_BUFFERS;
10496 caps->v2.max_shader_buffer_other_stages = max;
10497 glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &max);
10498 if (max > PIPE_MAX_SHADER_BUFFERS)
10499 max = PIPE_MAX_SHADER_BUFFERS;
10500 caps->v2.max_shader_buffer_frag_compute = max;
10501 glGetIntegerv(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS,
10502 (GLint*)&caps->v2.max_combined_shader_buffers);
10503 }
10504
10505 if (has_feature(feat_images)) {
10506 glGetIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &max);
10507 if (max > PIPE_MAX_SHADER_IMAGES)
10508 max = PIPE_MAX_SHADER_IMAGES;
10509 caps->v2.max_shader_image_other_stages = max;
10510 glGetIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &max);
10511 if (max > PIPE_MAX_SHADER_IMAGES)
10512 max = PIPE_MAX_SHADER_IMAGES;
10513 caps->v2.max_shader_image_frag_compute = max;
10514
10515 if (gl_ver > 0) /* Seems GLES doesn't support multisample images */
10516 glGetIntegerv(GL_MAX_IMAGE_SAMPLES, (GLint*)&caps->v2.max_image_samples);
10517 }
10518
10519 if (has_feature(feat_storage_multisample))
10520 caps->v1.max_samples = vrend_renderer_query_multisample_caps(caps->v1.max_samples, &caps->v2);
10521
10522 caps->v2.capability_bits |= VIRGL_CAP_TGSI_INVARIANT | VIRGL_CAP_SET_MIN_SAMPLES |
10523 VIRGL_CAP_TGSI_PRECISE | VIRGL_CAP_APP_TWEAK_SUPPORT;
10524
10525 /* If attribute isn't supported, assume 2048 which is the minimum allowed
10526 by the specification. */
10527 if (gl_ver >= 44 || gles_ver >= 31)
10528 glGetIntegerv(GL_MAX_VERTEX_ATTRIB_STRIDE, (GLint*)&caps->v2.max_vertex_attrib_stride);
10529 else
10530 caps->v2.max_vertex_attrib_stride = 2048;
10531
10532 if (has_feature(feat_compute_shader) && (vrend_state.use_gles || gl_ver >= 33)) {
10533 glGetIntegerv(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, (GLint*)&caps->v2.max_compute_work_group_invocations);
10534 glGetIntegerv(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE, (GLint*)&caps->v2.max_compute_shared_memory_size);
10535 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, (GLint*)&caps->v2.max_compute_grid_size[0]);
10536 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, (GLint*)&caps->v2.max_compute_grid_size[1]);
10537 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, (GLint*)&caps->v2.max_compute_grid_size[2]);
10538 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, (GLint*)&caps->v2.max_compute_block_size[0]);
10539 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, (GLint*)&caps->v2.max_compute_block_size[1]);
10540 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, (GLint*)&caps->v2.max_compute_block_size[2]);
10541
10542 caps->v2.capability_bits |= VIRGL_CAP_COMPUTE_SHADER;
10543 }
10544
10545 if (has_feature(feat_atomic_counters)) {
10546 glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS,
10547 (GLint*)(caps->v2.max_atomic_counters + PIPE_SHADER_VERTEX));
10548 glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS,
10549 (GLint*)(caps->v2.max_atomic_counter_buffers + PIPE_SHADER_VERTEX));
10550 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS,
10551 (GLint*)(caps->v2.max_atomic_counters + PIPE_SHADER_FRAGMENT));
10552 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS,
10553 (GLint*)(caps->v2.max_atomic_counter_buffers + PIPE_SHADER_FRAGMENT));
10554
10555 if (has_feature(feat_geometry_shader)) {
10556 glGetIntegerv(GL_MAX_GEOMETRY_ATOMIC_COUNTERS,
10557 (GLint*)(caps->v2.max_atomic_counters + PIPE_SHADER_GEOMETRY));
10558 glGetIntegerv(GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS,
10559 (GLint*)(caps->v2.max_atomic_counter_buffers + PIPE_SHADER_GEOMETRY));
10560 }
10561
10562 if (has_feature(feat_tessellation)) {
10563 glGetIntegerv(GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS,
10564 (GLint*)(caps->v2.max_atomic_counters + PIPE_SHADER_TESS_CTRL));
10565 glGetIntegerv(GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS,
10566 (GLint*)(caps->v2.max_atomic_counter_buffers + PIPE_SHADER_TESS_CTRL));
10567 glGetIntegerv(GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS,
10568 (GLint*)(caps->v2.max_atomic_counters + PIPE_SHADER_TESS_EVAL));
10569 glGetIntegerv(GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS,
10570 (GLint*)(caps->v2.max_atomic_counter_buffers + PIPE_SHADER_TESS_EVAL));
10571 }
10572
10573 if (has_feature(feat_compute_shader)) {
10574 glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS,
10575 (GLint*)(caps->v2.max_atomic_counters + PIPE_SHADER_COMPUTE));
10576 glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS,
10577 (GLint*)(caps->v2.max_atomic_counter_buffers + PIPE_SHADER_COMPUTE));
10578 }
10579
10580 glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTERS,
10581 (GLint*)&caps->v2.max_combined_atomic_counters);
10582 glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS,
10583 (GLint*)&caps->v2.max_combined_atomic_counter_buffers);
10584 }
10585
10586 if (has_feature(feat_fb_no_attach))
10587 caps->v2.capability_bits |= VIRGL_CAP_FB_NO_ATTACH;
10588
10589 if (has_feature(feat_texture_view))
10590 caps->v2.capability_bits |= VIRGL_CAP_TEXTURE_VIEW;
10591
10592 if (has_feature(feat_txqs))
10593 caps->v2.capability_bits |= VIRGL_CAP_TXQS;
10594
10595 if (has_feature(feat_barrier))
10596 caps->v2.capability_bits |= VIRGL_CAP_MEMORY_BARRIER;
10597
10598 if (has_feature(feat_copy_image))
10599 caps->v2.capability_bits |= VIRGL_CAP_COPY_IMAGE;
10600
10601 if (has_feature(feat_robust_buffer_access))
10602 caps->v2.capability_bits |= VIRGL_CAP_ROBUST_BUFFER_ACCESS;
10603
10604 if (has_feature(feat_framebuffer_fetch))
10605 caps->v2.capability_bits |= VIRGL_CAP_TGSI_FBFETCH;
10606
10607 if (has_feature(feat_shader_clock))
10608 caps->v2.capability_bits |= VIRGL_CAP_SHADER_CLOCK;
10609
10610 if (has_feature(feat_texture_barrier))
10611 caps->v2.capability_bits |= VIRGL_CAP_TEXTURE_BARRIER;
10612
10613 /* If we enable input arrays and don't have enhanced layouts then we
10614 * can't support components. */
10615 if (has_feature(feat_enhanced_layouts))
10616 caps->v2.capability_bits |= VIRGL_CAP_TGSI_COMPONENTS;
10617
10618 if (has_feature(feat_srgb_write_control))
10619 caps->v2.capability_bits |= VIRGL_CAP_SRGB_WRITE_CONTROL;
10620
10621 if (has_feature(feat_transform_feedback3))
10622 caps->v2.capability_bits |= VIRGL_CAP_TRANSFORM_FEEDBACK3;
10623 /* Enable feature use just now otherwise we just get a lot noise because
10624 * of the caps setting */
10625 if (vrend_debug(NULL, dbg_features))
10626 vrend_debug_add_flag(dbg_feature_use);
10627
10628 /* always enable, only indicates that the CMD is supported */
10629 caps->v2.capability_bits |= VIRGL_CAP_GUEST_MAY_INIT_LOG;
10630
10631 if (has_feature(feat_qbo))
10632 caps->v2.capability_bits |= VIRGL_CAP_QBO;
10633
10634 caps->v2.capability_bits |= VIRGL_CAP_TRANSFER;
10635
10636 if (vrend_check_framebuffer_mixed_color_attachements())
10637 caps->v2.capability_bits |= VIRGL_CAP_FBO_MIXED_COLOR_FORMATS;
10638
10639 /* We want to expose ARB_gpu_shader_fp64 when running on top of ES */
10640 if (vrend_state.use_gles) {
10641 caps->v2.capability_bits |= VIRGL_CAP_FAKE_FP64;
10642 }
10643
10644 if (has_feature(feat_indirect_draw))
10645 caps->v2.capability_bits |= VIRGL_CAP_BIND_COMMAND_ARGS;
10646
10647 if (has_feature(feat_multi_draw_indirect))
10648 caps->v2.capability_bits |= VIRGL_CAP_MULTI_DRAW_INDIRECT;
10649
10650 if (has_feature(feat_indirect_params))
10651 caps->v2.capability_bits |= VIRGL_CAP_INDIRECT_PARAMS;
10652
10653 for (int i = 0; i < VIRGL_FORMAT_MAX; i++) {
10654 enum virgl_formats fmt = (enum virgl_formats)i;
10655 if (tex_conv_table[i].internalformat != 0) {
10656 if (vrend_format_can_readback(fmt)) {
10657 VREND_DEBUG(dbg_features, NULL, "Support readback of %s\n",
10658 util_format_name(fmt));
10659 set_format_bit(&caps->v2.supported_readback_formats, fmt);
10660 }
10661 }
10662
10663 if (vrend_format_can_scanout(fmt))
10664 set_format_bit(&caps->v2.scanout, fmt);
10665 }
10666
10667 if (has_feature(feat_clear_texture))
10668 caps->v2.capability_bits |= VIRGL_CAP_CLEAR_TEXTURE;
10669
10670 if (has_feature(feat_clip_control))
10671 caps->v2.capability_bits |= VIRGL_CAP_CLIP_HALFZ;
10672
10673 if (epoxy_has_gl_extension("GL_KHR_texture_compression_astc_sliced_3d"))
10674 caps->v2.capability_bits |= VIRGL_CAP_3D_ASTC;
10675
10676 caps->v2.capability_bits |= VIRGL_CAP_INDIRECT_INPUT_ADDR;
10677
10678 caps->v2.capability_bits |= VIRGL_CAP_COPY_TRANSFER;
10679
10680
10681 if (has_feature(feat_arb_buffer_storage) && !vrend_state.use_external_blob) {
10682 const char *vendor = (const char *)glGetString(GL_VENDOR);
10683 bool is_mesa = ((strstr(renderer, "Mesa") != NULL) || (strstr(renderer, "DRM") != NULL));
10684 /*
10685 * Intel GPUs (aside from Atom, which doesn't expose GL4.5) are cache-coherent.
10686 * Mesa AMDGPUs use write-combine mappings for coherent/persistent memory (see
10687 * RADEON_FLAG_GTT_WC in si_buffer.c/r600_buffer_common.c). For Nvidia, we can guess and
10688 * check. Long term, maybe a GL extension or using VK could replace these heuristics.
10689 *
10690 * Note Intel VMX ignores the caching type returned from virglrenderer, while AMD SVM and
10691 * ARM honor it.
10692 */
10693 if (is_mesa) {
10694 if (strstr(vendor, "Intel") != NULL)
10695 vrend_state.inferred_gl_caching_type = VIRGL_RENDERER_MAP_CACHE_CACHED;
10696 else if (strstr(vendor, "AMD") != NULL)
10697 vrend_state.inferred_gl_caching_type = VIRGL_RENDERER_MAP_CACHE_WC;
10698 } else {
10699 /* This is an educated guess since things don't explode with VMX + Nvidia. */
10700 if (strstr(renderer, "Quadro K2200") != NULL)
10701 vrend_state.inferred_gl_caching_type = VIRGL_RENDERER_MAP_CACHE_CACHED;
10702 }
10703
10704 if (vrend_state.inferred_gl_caching_type)
10705 caps->v2.capability_bits |= VIRGL_CAP_ARB_BUFFER_STORAGE;
10706 }
10707
10708 #ifdef ENABLE_MINIGBM_ALLOCATION
10709 if (has_feature(feat_memory_object) && has_feature(feat_memory_object_fd)) {
10710 if (!strcmp(gbm_device_get_backend_name(gbm->device), "i915") &&
10711 !vrend_winsys_different_gpu())
10712 caps->v2.capability_bits |= VIRGL_CAP_ARB_BUFFER_STORAGE;
10713 }
10714 #endif
10715
10716 if (has_feature(feat_blend_equation_advanced))
10717 caps->v2.capability_bits_v2 |= VIRGL_CAP_V2_BLEND_EQUATION;
10718
10719 #ifdef HAVE_EPOXY_EGL_H
10720 if (egl)
10721 caps->v2.capability_bits_v2 |= VIRGL_CAP_V2_UNTYPED_RESOURCE;
10722 #endif
10723
10724 video_memory = vrend_renderer_get_video_memory();
10725 if (video_memory) {
10726 caps->v2.capability_bits_v2 |= VIRGL_CAP_V2_VIDEO_MEMORY;
10727 caps->v2.max_video_memory = video_memory;
10728 }
10729
10730 if (has_feature(feat_ati_meminfo) || has_feature(feat_nvx_gpu_memory_info)) {
10731 caps->v2.capability_bits_v2 |= VIRGL_CAP_V2_MEMINFO;
10732 }
10733
10734 if (has_feature(feat_khr_debug))
10735 caps->v2.capability_bits_v2 |= VIRGL_CAP_V2_STRING_MARKER;
10736
10737 if (has_feature(feat_implicit_msaa))
10738 caps->v2.capability_bits_v2 |= VIRGL_CAP_V2_IMPLICIT_MSAA;
10739
10740 if (vrend_winsys_different_gpu())
10741 caps->v2.capability_bits_v2 |= VIRGL_CAP_V2_DIFFERENT_GPU;
10742
10743 if (has_feature(feat_anisotropic_filter)) {
10744 float max_aniso;
10745 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &max_aniso);
10746 caps->v2.max_anisotropy = MIN2(max_aniso, 16.0);
10747 }
10748
10749 }
10750
vrend_renderer_fill_caps(uint32_t set,uint32_t version,union virgl_caps * caps)10751 void vrend_renderer_fill_caps(uint32_t set, uint32_t version,
10752 union virgl_caps *caps)
10753 {
10754 int gl_ver, gles_ver;
10755 GLenum err;
10756 bool fill_capset2 = false;
10757
10758 if (!caps)
10759 return;
10760
10761 switch (set) {
10762 case VIRGL_RENDERER_CAPSET_VIRGL:
10763 if (version > VREND_CAPSET_VIRGL_MAX_VERSION)
10764 return;
10765 memset(caps, 0, sizeof(struct virgl_caps_v1));
10766 caps->max_version = VREND_CAPSET_VIRGL_MAX_VERSION;
10767 break;
10768 case VIRGL_RENDERER_CAPSET_VIRGL2:
10769 if (version > VREND_CAPSET_VIRGL2_MAX_VERSION)
10770 return;
10771 memset(caps, 0, sizeof(*caps));
10772 caps->max_version = VREND_CAPSET_VIRGL2_MAX_VERSION;
10773 fill_capset2 = true;
10774 break;
10775 default:
10776 return;
10777 }
10778
10779 /* We don't want to deal with stale error states that the caller might not
10780 * have cleaned up propperly, so read the error state until we are okay.
10781 */
10782 while ((err = glGetError()) != GL_NO_ERROR)
10783 vrend_printf("%s: Entering with stale GL error: %d\n", __func__, err);
10784
10785 if (vrend_state.use_gles) {
10786 gles_ver = epoxy_gl_version();
10787 gl_ver = 0;
10788 } else {
10789 gles_ver = 0;
10790 gl_ver = epoxy_gl_version();
10791 }
10792
10793 vrend_fill_caps_glsl_version(gl_ver, gles_ver, caps);
10794 VREND_DEBUG(dbg_features, NULL, "GLSL support level: %d", caps->v1.glsl_level);
10795
10796 vrend_renderer_fill_caps_v1(gl_ver, gles_ver, caps);
10797
10798 if (!fill_capset2)
10799 return;
10800
10801 vrend_renderer_fill_caps_v2(gl_ver, gles_ver, caps);
10802 }
10803
vrend_renderer_get_timestamp(void)10804 GLint64 vrend_renderer_get_timestamp(void)
10805 {
10806 GLint64 v;
10807 glGetInteger64v(GL_TIMESTAMP, &v);
10808 return v;
10809 }
10810
vrend_renderer_get_cursor_contents(struct pipe_resource * pres,uint32_t * width,uint32_t * height)10811 void *vrend_renderer_get_cursor_contents(struct pipe_resource *pres,
10812 uint32_t *width,
10813 uint32_t *height)
10814 {
10815 struct vrend_resource *res = (struct vrend_resource *)pres;
10816 GLenum format, type;
10817 int blsize;
10818 char *data, *data2;
10819 int size;
10820 uint h;
10821
10822 if (res->base.width0 > 128 || res->base.height0 > 128)
10823 return NULL;
10824
10825 if (res->target != GL_TEXTURE_2D)
10826 return NULL;
10827
10828 if (!width || !height)
10829 return NULL;
10830
10831 *width = res->base.width0;
10832 *height = res->base.height0;
10833
10834 format = tex_conv_table[res->base.format].glformat;
10835 type = tex_conv_table[res->base.format].gltype;
10836 blsize = util_format_get_blocksize(res->base.format);
10837 size = util_format_get_nblocks(res->base.format, res->base.width0, res->base.height0) * blsize;
10838 data = malloc(size);
10839 data2 = malloc(size);
10840
10841 if (!data || !data2) {
10842 free(data);
10843 free(data2);
10844 return NULL;
10845 }
10846
10847 if (has_feature(feat_arb_robustness)) {
10848 glBindTexture(res->target, res->id);
10849 glGetnTexImageARB(res->target, 0, format, type, size, data);
10850 } else if (vrend_state.use_gles) {
10851 do_readpixels(res, 0, 0, 0, 0, 0, *width, *height, format, type, size, data);
10852 } else {
10853 glBindTexture(res->target, res->id);
10854 glGetTexImage(res->target, 0, format, type, data);
10855 }
10856
10857 for (h = 0; h < res->base.height0; h++) {
10858 uint32_t doff = (res->base.height0 - h - 1) * res->base.width0 * blsize;
10859 uint32_t soff = h * res->base.width0 * blsize;
10860
10861 memcpy(data2 + doff, data + soff, res->base.width0 * blsize);
10862 }
10863 free(data);
10864 glBindTexture(res->target, 0);
10865 return data2;
10866 }
10867
10868
vrend_renderer_force_ctx_0(void)10869 void vrend_renderer_force_ctx_0(void)
10870 {
10871 vrend_state.current_ctx = NULL;
10872 vrend_state.current_hw_ctx = NULL;
10873 vrend_hw_switch_context(vrend_state.ctx0, true);
10874 }
10875
vrend_renderer_get_rect(struct pipe_resource * pres,const struct iovec * iov,unsigned int num_iovs,uint32_t offset,int x,int y,int width,int height)10876 void vrend_renderer_get_rect(struct pipe_resource *pres,
10877 const struct iovec *iov, unsigned int num_iovs,
10878 uint32_t offset,
10879 int x, int y, int width, int height)
10880 {
10881 struct vrend_resource *res = (struct vrend_resource *)pres;
10882 struct vrend_transfer_info transfer_info;
10883 struct pipe_box box;
10884 int elsize;
10885
10886 memset(&transfer_info, 0, sizeof(transfer_info));
10887
10888 elsize = util_format_get_blocksize(res->base.format);
10889 box.x = x;
10890 box.y = y;
10891 box.z = 0;
10892 box.width = width;
10893 box.height = height;
10894 box.depth = 1;
10895
10896 transfer_info.box = &box;
10897
10898 transfer_info.stride = util_format_get_nblocksx(res->base.format, res->base.width0) * elsize;
10899 transfer_info.offset = offset;
10900 transfer_info.iovec = iov;
10901 transfer_info.iovec_cnt = num_iovs;
10902
10903 vrend_renderer_transfer_pipe(pres, &transfer_info,
10904 VIRGL_TRANSFER_FROM_HOST);
10905 }
10906
vrend_renderer_attach_res_ctx(struct vrend_context * ctx,struct virgl_resource * res)10907 void vrend_renderer_attach_res_ctx(struct vrend_context *ctx,
10908 struct virgl_resource *res)
10909 {
10910 if (!res->pipe_resource) {
10911 /* move the last untyped resource from cache to list */
10912 if (unlikely(ctx->untyped_resource_cache)) {
10913 struct virgl_resource *last = ctx->untyped_resource_cache;
10914 struct vrend_untyped_resource *wrapper = malloc(sizeof(*wrapper));
10915 if (wrapper) {
10916 wrapper->resource = last;
10917 list_add(&wrapper->head, &ctx->untyped_resources);
10918 } else {
10919 vrend_printf("dropping attached resource %d due to OOM\n", last->res_id);
10920 }
10921 }
10922
10923 ctx->untyped_resource_cache = res;
10924 /* defer to vrend_renderer_pipe_resource_set_type */
10925 return;
10926 }
10927
10928 vrend_ctx_resource_insert(ctx->res_hash,
10929 res->res_id,
10930 (struct vrend_resource *)res->pipe_resource);
10931 }
10932
vrend_renderer_detach_res_ctx(struct vrend_context * ctx,struct virgl_resource * res)10933 void vrend_renderer_detach_res_ctx(struct vrend_context *ctx,
10934 struct virgl_resource *res)
10935 {
10936 if (!res->pipe_resource) {
10937 if (ctx->untyped_resource_cache == res) {
10938 ctx->untyped_resource_cache = NULL;
10939 } else {
10940 struct vrend_untyped_resource *iter;
10941 LIST_FOR_EACH_ENTRY(iter, &ctx->untyped_resources, head) {
10942 if (iter->resource == res) {
10943 list_del(&iter->head);
10944 free(iter);
10945 break;
10946 }
10947 }
10948 }
10949
10950 return;
10951 }
10952
10953 vrend_ctx_resource_remove(ctx->res_hash, res->res_id);
10954 }
10955
vrend_renderer_ctx_res_lookup(struct vrend_context * ctx,int res_handle)10956 static struct vrend_resource *vrend_renderer_ctx_res_lookup(struct vrend_context *ctx, int res_handle)
10957 {
10958 return vrend_ctx_resource_lookup(ctx->res_hash, res_handle);
10959 }
10960
vrend_context_set_debug_flags(struct vrend_context * ctx,const char * flagstring)10961 void vrend_context_set_debug_flags(struct vrend_context *ctx, const char *flagstring)
10962 {
10963 if (vrend_debug_can_override()) {
10964 ctx->debug_flags |= vrend_get_debug_flags(flagstring);
10965 if (ctx->debug_flags & dbg_features)
10966 vrend_debug_add_flag(dbg_feature_use);
10967 }
10968 }
10969
vrend_renderer_resource_get_info(struct pipe_resource * pres,struct vrend_renderer_resource_info * info)10970 void vrend_renderer_resource_get_info(struct pipe_resource *pres,
10971 struct vrend_renderer_resource_info *info)
10972 {
10973 struct vrend_resource *res = (struct vrend_resource *)pres;
10974 int elsize;
10975
10976 elsize = util_format_get_blocksize(res->base.format);
10977
10978 info->tex_id = res->id;
10979 info->width = res->base.width0;
10980 info->height = res->base.height0;
10981 info->depth = res->base.depth0;
10982 info->format = res->base.format;
10983 info->flags = res->y_0_top ? VIRGL_RESOURCE_Y_0_TOP : 0;
10984 info->stride = util_format_get_nblocksx(res->base.format, u_minify(res->base.width0, 0)) * elsize;
10985 }
10986
vrend_renderer_get_cap_set(uint32_t cap_set,uint32_t * max_ver,uint32_t * max_size)10987 void vrend_renderer_get_cap_set(uint32_t cap_set, uint32_t *max_ver,
10988 uint32_t *max_size)
10989 {
10990 switch (cap_set) {
10991 case VIRGL_RENDERER_CAPSET_VIRGL:
10992 *max_ver = VREND_CAPSET_VIRGL_MAX_VERSION;
10993 *max_size = sizeof(struct virgl_caps_v1);
10994 break;
10995 case VIRGL_RENDERER_CAPSET_VIRGL2:
10996 *max_ver = VREND_CAPSET_VIRGL2_MAX_VERSION;
10997 *max_size = sizeof(struct virgl_caps_v2);
10998 break;
10999 default:
11000 *max_ver = 0;
11001 *max_size = 0;
11002 break;
11003 }
11004 }
11005
vrend_renderer_create_sub_ctx(struct vrend_context * ctx,int sub_ctx_id)11006 void vrend_renderer_create_sub_ctx(struct vrend_context *ctx, int sub_ctx_id)
11007 {
11008 struct vrend_sub_context *sub;
11009 struct virgl_gl_ctx_param ctx_params;
11010 GLuint i;
11011
11012 LIST_FOR_EACH_ENTRY(sub, &ctx->sub_ctxs, head) {
11013 if (sub->sub_ctx_id == sub_ctx_id) {
11014 return;
11015 }
11016 }
11017
11018 sub = CALLOC_STRUCT(vrend_sub_context);
11019 if (!sub)
11020 return;
11021
11022 ctx_params.shared = (ctx->ctx_id == 0 && sub_ctx_id == 0) ? false : true;
11023 ctx_params.major_ver = vrend_state.gl_major_ver;
11024 ctx_params.minor_ver = vrend_state.gl_minor_ver;
11025 sub->gl_context = vrend_clicbs->create_gl_context(0, &ctx_params);
11026 sub->parent = ctx;
11027 vrend_clicbs->make_current(sub->gl_context);
11028
11029 /* enable if vrend_renderer_init function has done it as well */
11030 if (has_feature(feat_debug_cb)) {
11031 glDebugMessageCallback(vrend_debug_cb, NULL);
11032 glEnable(GL_DEBUG_OUTPUT);
11033 glDisable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
11034 }
11035
11036 sub->sub_ctx_id = sub_ctx_id;
11037
11038 /* initialize the depth far_val to 1 */
11039 for (i = 0; i < PIPE_MAX_VIEWPORTS; i++) {
11040 sub->vps[i].far_val = 1.0;
11041 }
11042
11043 if (!has_feature(feat_gles31_vertex_attrib_binding)) {
11044 glGenVertexArrays(1, &sub->vaoid);
11045 glBindVertexArray(sub->vaoid);
11046 }
11047
11048 glGenFramebuffers(1, &sub->fb_id);
11049 glBindFramebuffer(GL_FRAMEBUFFER, sub->fb_id);
11050 glGenFramebuffers(2, sub->blit_fb_ids);
11051
11052 for (int i = 0; i < VREND_PROGRAM_NQUEUES; ++i)
11053 list_inithead(&sub->gl_programs[i]);
11054 list_inithead(&sub->cs_programs);
11055 list_inithead(&sub->streamout_list);
11056
11057 sub->object_hash = vrend_object_init_ctx_table();
11058
11059 ctx->sub = sub;
11060 list_add(&sub->head, &ctx->sub_ctxs);
11061 if (sub_ctx_id == 0)
11062 ctx->sub0 = sub;
11063
11064 vrend_set_tweak_from_env(&ctx->sub->tweaks);
11065 }
11066
vrend_context_has_debug_flag(const struct vrend_context * ctx,enum virgl_debug_flags flag)11067 unsigned vrend_context_has_debug_flag(const struct vrend_context *ctx, enum virgl_debug_flags flag)
11068 {
11069 return ctx && (ctx->debug_flags & flag);
11070 }
11071
vrend_print_context_name(const struct vrend_context * ctx)11072 void vrend_print_context_name(const struct vrend_context *ctx)
11073 {
11074 if (ctx)
11075 vrend_printf("%s: ", ctx->debug_name);
11076 else
11077 vrend_printf("HOST: ");
11078 }
11079
11080
vrend_renderer_destroy_sub_ctx(struct vrend_context * ctx,int sub_ctx_id)11081 void vrend_renderer_destroy_sub_ctx(struct vrend_context *ctx, int sub_ctx_id)
11082 {
11083 struct vrend_sub_context *sub, *tofree = NULL;
11084
11085 /* never destroy sub context id 0 */
11086 if (sub_ctx_id == 0)
11087 return;
11088
11089 LIST_FOR_EACH_ENTRY(sub, &ctx->sub_ctxs, head) {
11090 if (sub->sub_ctx_id == sub_ctx_id) {
11091 tofree = sub;
11092 }
11093 }
11094
11095 if (tofree) {
11096 if (ctx->sub == tofree) {
11097 ctx->sub = ctx->sub0;
11098 }
11099 vrend_destroy_sub_context(tofree);
11100 vrend_clicbs->make_current(ctx->sub->gl_context);
11101 }
11102 }
11103
vrend_renderer_set_sub_ctx(struct vrend_context * ctx,int sub_ctx_id)11104 void vrend_renderer_set_sub_ctx(struct vrend_context *ctx, int sub_ctx_id)
11105 {
11106 struct vrend_sub_context *sub;
11107 /* find the sub ctx */
11108
11109 if (ctx->sub && ctx->sub->sub_ctx_id == sub_ctx_id)
11110 return;
11111
11112 LIST_FOR_EACH_ENTRY(sub, &ctx->sub_ctxs, head) {
11113 if (sub->sub_ctx_id == sub_ctx_id) {
11114 ctx->sub = sub;
11115 vrend_clicbs->make_current(sub->gl_context);
11116 break;
11117 }
11118 }
11119 }
11120
vrend_renderer_prepare_reset(void)11121 void vrend_renderer_prepare_reset(void)
11122 {
11123 /* make sure user contexts are no longer accessed */
11124 vrend_free_sync_thread();
11125 vrend_hw_switch_context(vrend_state.ctx0, true);
11126 }
11127
vrend_renderer_reset(void)11128 void vrend_renderer_reset(void)
11129 {
11130 vrend_free_fences();
11131 vrend_blitter_fini();
11132
11133 vrend_destroy_context(vrend_state.ctx0);
11134
11135 vrend_state.ctx0 = vrend_create_context(0, strlen("HOST"), "HOST");
11136 /* TODO respawn sync thread */
11137 }
11138
vrend_renderer_get_poll_fd(void)11139 int vrend_renderer_get_poll_fd(void)
11140 {
11141 return vrend_state.eventfd;
11142 }
11143
vrend_renderer_export_query(struct pipe_resource * pres,struct virgl_renderer_export_query * export_query)11144 int vrend_renderer_export_query(struct pipe_resource *pres,
11145 struct virgl_renderer_export_query *export_query)
11146 {
11147 struct vrend_resource *res = (struct vrend_resource *)pres;
11148
11149 #ifdef ENABLE_MINIGBM_ALLOCATION
11150 if (res->gbm_bo)
11151 return virgl_gbm_export_query(res->gbm_bo, export_query);
11152 #else
11153 (void)res;
11154 #endif
11155
11156 /*
11157 * Implementations that support eglExportDMABUFImageMESA can also export certain resources.
11158 * This is omitted currently since virgl_renderer_get_fd_for_texture supports that use case.
11159 */
11160 export_query->out_num_fds = 0;
11161 export_query->out_fourcc = 0;
11162 export_query->out_modifier = DRM_FORMAT_MOD_INVALID;
11163 if (export_query->in_export_fds)
11164 return -EINVAL;
11165
11166 return 0;
11167 }
11168
vrend_renderer_pipe_resource_create(struct vrend_context * ctx,uint32_t blob_id,const struct vrend_renderer_resource_create_args * args)11169 int vrend_renderer_pipe_resource_create(struct vrend_context *ctx, uint32_t blob_id,
11170 const struct vrend_renderer_resource_create_args *args)
11171 {
11172 struct vrend_resource *res;
11173 res = (struct vrend_resource *)vrend_renderer_resource_create(args, NULL);
11174 if (!res)
11175 return EINVAL;
11176
11177 res->blob_id = blob_id;
11178 list_addtail(&res->head, &ctx->vrend_resources);
11179 return 0;
11180 }
11181
vrend_get_blob_pipe(struct vrend_context * ctx,uint64_t blob_id)11182 struct pipe_resource *vrend_get_blob_pipe(struct vrend_context *ctx, uint64_t blob_id)
11183 {
11184 uint32_t id = (uint32_t)blob_id;
11185 struct vrend_resource *res, *stor;
11186
11187 LIST_FOR_EACH_ENTRY_SAFE(res, stor, &ctx->vrend_resources, head) {
11188 if (res->blob_id != id)
11189 continue;
11190
11191 list_del(&res->head);
11192 /* Set the blob id to zero, since it won't be used anymore */
11193 res->blob_id = 0;
11194 return &res->base;
11195 }
11196
11197 return NULL;
11198 }
11199
11200 int
vrend_renderer_pipe_resource_set_type(struct vrend_context * ctx,uint32_t res_id,const struct vrend_renderer_resource_set_type_args * args)11201 vrend_renderer_pipe_resource_set_type(struct vrend_context *ctx,
11202 uint32_t res_id,
11203 const struct vrend_renderer_resource_set_type_args *args)
11204 {
11205 struct virgl_resource *res = NULL;
11206
11207 /* look up the untyped resource */
11208 if (ctx->untyped_resource_cache &&
11209 ctx->untyped_resource_cache->res_id == res_id) {
11210 res = ctx->untyped_resource_cache;
11211 ctx->untyped_resource_cache = NULL;
11212 } else {
11213 /* cache miss */
11214 struct vrend_untyped_resource *iter;
11215 LIST_FOR_EACH_ENTRY(iter, &ctx->untyped_resources, head) {
11216 if (iter->resource->res_id == res_id) {
11217 res = iter->resource;
11218 list_del(&iter->head);
11219 free(iter);
11220 break;
11221 }
11222 }
11223 }
11224
11225 /* either a bad res_id or the resource is already typed */
11226 if (!res) {
11227 if (vrend_renderer_ctx_res_lookup(ctx, res_id))
11228 return 0;
11229
11230 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_id);
11231 return EINVAL;
11232 }
11233
11234 /* resource is still untyped */
11235 if (!res->pipe_resource) {
11236 #ifdef HAVE_EPOXY_EGL_H
11237 const struct vrend_renderer_resource_create_args create_args = {
11238 .target = PIPE_TEXTURE_2D,
11239 .format = args->format,
11240 .bind = args->bind,
11241 .width = args->width,
11242 .height = args->height,
11243 .depth = 1,
11244 .array_size = 1,
11245 .last_level = 0,
11246 .nr_samples = 0,
11247 .flags = 0,
11248 };
11249 int plane_fds[VIRGL_GBM_MAX_PLANES];
11250 struct vrend_resource *gr;
11251 uint32_t virgl_format;
11252 uint32_t drm_format;
11253 int ret;
11254
11255 if (res->fd_type != VIRGL_RESOURCE_FD_DMABUF)
11256 return EINVAL;
11257
11258 for (uint32_t i = 0; i < args->plane_count; i++)
11259 plane_fds[i] = res->fd;
11260
11261 gr = vrend_resource_create(&create_args);
11262 if (!gr)
11263 return ENOMEM;
11264
11265 virgl_format = gr->base.format;
11266 drm_format = 0;
11267 if (virgl_gbm_convert_format(&virgl_format, &drm_format)) {
11268 vrend_printf("%s: unsupported format %d\n", __func__, virgl_format);
11269 FREE(gr);
11270 return EINVAL;
11271 }
11272
11273 gr->egl_image = virgl_egl_image_from_dmabuf(egl,
11274 args->width,
11275 args->height,
11276 drm_format,
11277 args->modifier,
11278 args->plane_count,
11279 plane_fds,
11280 args->plane_strides,
11281 args->plane_offsets);
11282 if (!gr->egl_image) {
11283 vrend_printf("%s: failed to create egl image\n", __func__);
11284 FREE(gr);
11285 return EINVAL;
11286 }
11287
11288 gr->storage_bits |= VREND_STORAGE_EGL_IMAGE;
11289
11290 ret = vrend_resource_alloc_texture(gr, virgl_format, gr->egl_image);
11291 if (ret) {
11292 virgl_egl_image_destroy(egl, gr->egl_image);
11293 FREE(gr);
11294 return ret;
11295 }
11296
11297 /* "promote" the fd to pipe_resource */
11298 close(res->fd);
11299 res->fd = -1;
11300 res->fd_type = VIRGL_RESOURCE_FD_INVALID;
11301 res->pipe_resource = &gr->base;
11302 #else /* HAVE_EPOXY_EGL_H */
11303 (void)args;
11304 vrend_printf("%s: no EGL support \n", __func__);
11305 return EINVAL;
11306 #endif /* HAVE_EPOXY_EGL_H */
11307 }
11308
11309 vrend_ctx_resource_insert(ctx->res_hash,
11310 res->res_id,
11311 (struct vrend_resource *)res->pipe_resource);
11312
11313 return 0;
11314 }
11315
vrend_renderer_resource_get_map_info(struct pipe_resource * pres)11316 uint32_t vrend_renderer_resource_get_map_info(struct pipe_resource *pres)
11317 {
11318 struct vrend_resource *res = (struct vrend_resource *)pres;
11319 return res->map_info;
11320 }
11321
vrend_renderer_resource_map(struct pipe_resource * pres,void ** map,uint64_t * out_size)11322 int vrend_renderer_resource_map(struct pipe_resource *pres, void **map, uint64_t *out_size)
11323 {
11324 struct vrend_resource *res = (struct vrend_resource *)pres;
11325 if (!has_bits(res->storage_bits, VREND_STORAGE_GL_BUFFER | VREND_STORAGE_GL_IMMUTABLE))
11326 return -EINVAL;
11327
11328 glBindBufferARB(res->target, res->id);
11329 *map = glMapBufferRange(res->target, 0, res->size, res->buffer_storage_flags);
11330 if (!*map)
11331 return -EINVAL;
11332
11333 glBindBufferARB(res->target, 0);
11334 *out_size = res->size;
11335 return 0;
11336 }
11337
vrend_renderer_resource_unmap(struct pipe_resource * pres)11338 int vrend_renderer_resource_unmap(struct pipe_resource *pres)
11339 {
11340 struct vrend_resource *res = (struct vrend_resource *)pres;
11341 if (!has_bits(res->storage_bits, VREND_STORAGE_GL_BUFFER | VREND_STORAGE_GL_IMMUTABLE))
11342 return -EINVAL;
11343
11344 glBindBufferARB(res->target, res->id);
11345 glUnmapBuffer(res->target);
11346 glBindBufferARB(res->target, 0);
11347 return 0;
11348 }
11349
vrend_renderer_create_ctx0_fence(uint32_t fence_id)11350 int vrend_renderer_create_ctx0_fence(uint32_t fence_id)
11351 {
11352 void *fence_cookie = (void *)(uintptr_t)fence_id;
11353 return vrend_renderer_create_fence(vrend_state.ctx0,
11354 VIRGL_RENDERER_FENCE_FLAG_MERGEABLE, fence_cookie);
11355 }
11356
11357 #ifdef HAVE_EPOXY_EGL_H
find_ctx0_fence_locked(struct list_head * fence_list,void * fence_cookie,bool * seen_first,struct vrend_fence ** fence)11358 static bool find_ctx0_fence_locked(struct list_head *fence_list,
11359 void *fence_cookie,
11360 bool *seen_first,
11361 struct vrend_fence **fence)
11362 {
11363 struct vrend_fence *iter;
11364
11365 LIST_FOR_EACH_ENTRY(iter, fence_list, fences) {
11366 /* only consider ctx0 fences */
11367 if (iter->ctx != vrend_state.ctx0)
11368 continue;
11369
11370 if (iter->fence_cookie == fence_cookie) {
11371 *fence = iter;
11372 return true;
11373 }
11374
11375 if (!*seen_first) {
11376 if (fence_cookie < iter->fence_cookie)
11377 return true;
11378 *seen_first = true;
11379 }
11380 }
11381
11382 return false;
11383 }
11384 #endif
11385
vrend_renderer_export_ctx0_fence(uint32_t fence_id,int * out_fd)11386 int vrend_renderer_export_ctx0_fence(uint32_t fence_id, int* out_fd) {
11387 #ifdef HAVE_EPOXY_EGL_H
11388 if (!vrend_state.use_egl_fence) {
11389 return -EINVAL;
11390 }
11391
11392 if (vrend_state.sync_thread)
11393 pipe_mutex_lock(vrend_state.fence_mutex);
11394
11395 void *fence_cookie = (void *)(uintptr_t)fence_id;
11396 bool seen_first = false;
11397 struct vrend_fence *fence = NULL;
11398 bool found = find_ctx0_fence_locked(&vrend_state.fence_list,
11399 fence_cookie,
11400 &seen_first,
11401 &fence);
11402 if (!found) {
11403 found = find_ctx0_fence_locked(&vrend_state.fence_wait_list,
11404 fence_cookie,
11405 &seen_first,
11406 &fence);
11407 /* consider signaled when no active ctx0 fence at all */
11408 if (!found && !seen_first)
11409 found = true;
11410 }
11411
11412 if (vrend_state.sync_thread)
11413 pipe_mutex_unlock(vrend_state.fence_mutex);
11414
11415 if (found) {
11416 if (fence)
11417 return virgl_egl_export_fence(egl, fence->eglsyncobj, out_fd) ? 0 : -EINVAL;
11418 else
11419 return virgl_egl_export_signaled_fence(egl, out_fd) ? 0 : -EINVAL;
11420 }
11421 #else
11422 (void)fence_id;
11423 (void)out_fd;
11424 #endif
11425 return -EINVAL;
11426 }
11427
vrend_renderer_get_meminfo(struct vrend_context * ctx,uint32_t res_handle)11428 void vrend_renderer_get_meminfo(struct vrend_context *ctx, uint32_t res_handle)
11429 {
11430 struct vrend_resource *res;
11431 struct virgl_memory_info *info;
11432
11433 res = vrend_renderer_ctx_res_lookup(ctx, res_handle);
11434 if (!res) {
11435 vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle);
11436 return;
11437 }
11438
11439 info = (struct virgl_memory_info *)res->iov->iov_base;
11440
11441 if (has_feature(feat_nvx_gpu_memory_info)) {
11442 GLint i;
11443 glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &i);
11444 info->total_device_memory = i;
11445 glGetIntegerv(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &i);
11446 info->total_staging_memory = i - info->total_device_memory;
11447 glGetIntegerv(GL_GPU_MEMORY_INFO_EVICTION_COUNT_NVX, &i);
11448 info->nr_device_memory_evictions = i;
11449 glGetIntegerv(GL_GPU_MEMORY_INFO_EVICTED_MEMORY_NVX, &i);
11450 info->device_memory_evicted = i;
11451 }
11452
11453 if (has_feature(feat_ati_meminfo)) {
11454 GLint i[4];
11455 glGetIntegerv(GL_VBO_FREE_MEMORY_ATI, i);
11456 info->avail_device_memory = i[0];
11457 info->avail_staging_memory = i[2];
11458 }
11459 }
11460
vrend_renderer_get_video_memory(void)11461 static uint32_t vrend_renderer_get_video_memory(void)
11462 {
11463 GLint video_memory = vrend_winsys_query_video_memory();
11464
11465 if (!video_memory && has_feature(feat_nvx_gpu_memory_info))
11466 glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &video_memory);
11467
11468 return video_memory;
11469 }
11470
vrend_context_emit_string_marker(struct vrend_context * ctx,GLsizei length,const char * message)11471 void vrend_context_emit_string_marker(struct vrend_context *ctx, GLsizei length, const char * message)
11472 {
11473 VREND_DEBUG(dbg_khr, ctx, "MARKER: '%.*s'\n", length, message);
11474
11475 #ifdef ENABLE_TRACING
11476 char buf[256];
11477 if (length > 6 && !strncmp(message, "BEGIN:", 6)) {
11478 snprintf(buf, 256, "%.*s", length - 6, &message[6]);
11479 TRACE_SCOPE_BEGIN(buf);
11480 } else if (length > 4 && !strncmp(message, "END:", 4)) {
11481 snprintf(buf, 256, "%.*s", length - 4, &message[4]);
11482 const char *scope = buf;
11483 TRACE_SCOPE_END(scope);
11484 }
11485 #endif
11486
11487 if (has_feature(feat_khr_debug)) {
11488 if (vrend_state.use_gles)
11489 glDebugMessageInsertKHR(GL_DEBUG_SOURCE_APPLICATION_KHR,
11490 GL_DEBUG_TYPE_MARKER_KHR,
11491 0, GL_DEBUG_SEVERITY_NOTIFICATION,
11492 length, message);
11493 else
11494 glDebugMessageInsert(GL_DEBUG_SOURCE_APPLICATION,
11495 GL_DEBUG_TYPE_MARKER,
11496 0, GL_DEBUG_SEVERITY_NOTIFICATION_KHR,
11497 length, message);
11498 }
11499 }
11500