xref: /aosp_15_r20/external/virglrenderer/src/vrend_blitter.c (revision bbecb9d118dfdb95f99bd754f8fa9be01f189df3)
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 
25 /* gallium blitter implementation in GL */
26 /* for when we can't use glBlitFramebuffer */
27 
28 #include <stdio.h>
29 
30 #include "util/u_memory.h"
31 #include "util/u_format.h"
32 #include "util/u_hash_table.h"
33 #include "util/u_texture.h"
34 
35 #include "vrend_shader.h"
36 #include "vrend_renderer.h"
37 #include "vrend_blitter.h"
38 
39 #define XXH_INLINE_ALL
40 #include "util/xxhash.h"
41 
42 #define DEST_SWIZZLE_SNIPPET_SIZE 64
43 
44 #define BLIT_USE_GLES           (1 << 0)
45 #define BLIT_USE_MSAA           (1 << 1)
46 #define BLIT_USE_DEPTH          (1 << 2)
47 #define BLIT_MANUAL_SRGB_DECODE (1 << 3)
48 #define BLIT_MANUAL_SRGB_ENCODE (1 << 4)
49 
50 struct vec4 {
51    GLfloat x,y,z,w;
52 };
53 
54 struct blit_coord {
55   struct vec4 pos;
56   struct vec4 tex;
57 };
58 
59 struct vrend_blitter_ctx {
60    virgl_gl_context gl_context;
61    bool initialised;
62    bool use_gles;
63 
64    GLuint vaoid;
65 
66    struct util_hash_table *blit_programs;
67 
68    GLuint vs;
69    GLuint fb_id;
70 
71    unsigned dst_width;
72    unsigned dst_height;
73 
74    GLuint vbo_id;
75    struct blit_coord vertices[4];
76 };
77 
78 static struct vrend_blitter_ctx vrend_blit_ctx;
79 
80 struct blit_point {
81     int x;
82     int y;
83 };
84 
85 struct blit_swizzle_and_type {
86   char *swizzle;
87   char *type;
88   bool is_array;
89 };
90 
91 struct blit_prog_key {
92    bool is_color: 1;
93    bool is_msaa: 1;
94    bool manual_srgb_decode: 1;
95    bool manual_srgb_encode: 1;
96    uint8_t num_samples;
97    int pipe_tex_target;
98    struct {
99       bool has_swizzle;
100       enum virgl_formats src_format;
101       uint8_t swizzle[4];
102    } texcol;
103 };
104 
blit_shader_build_and_check(GLenum shader_type,const char * buf)105 static GLint blit_shader_build_and_check(GLenum shader_type, const char *buf)
106 {
107    GLint param;
108    GLint id = glCreateShader(shader_type);
109    glShaderSource(id, 1, (const char **)&buf, NULL);
110    glCompileShader(id);
111 
112    glGetShaderiv(id, GL_COMPILE_STATUS, &param);
113    if (param == GL_FALSE) {
114       char infolog[65536];
115       int len;
116       glGetShaderInfoLog(id, 65536, &len, infolog);
117       vrend_printf("shader failed to compile\n%s\n", infolog);
118       vrend_printf("GLSL:\n%s\n", buf);
119       glDeleteShader(id);
120       return 0;
121    }
122    return id;
123 }
124 
blit_shader_link_and_check(GLuint prog_id)125 static bool blit_shader_link_and_check(GLuint prog_id)
126 {
127    GLint lret;
128 
129    glLinkProgram(prog_id);
130    glGetProgramiv(prog_id, GL_LINK_STATUS, &lret);
131    if (lret == GL_FALSE) {
132       char infolog[65536];
133       int len;
134       glGetProgramInfoLog(prog_id, 65536, &len, infolog);
135       vrend_printf("got error linking\n%s\n", infolog);
136       /* dump shaders */
137       glDeleteProgram(prog_id);
138       return false;
139    }
140    return true;
141 }
142 
create_dest_swizzle_snippet(const uint8_t swizzle[4],char snippet[DEST_SWIZZLE_SNIPPET_SIZE])143 static void create_dest_swizzle_snippet(const uint8_t swizzle[4],
144                                         char snippet[DEST_SWIZZLE_SNIPPET_SIZE])
145 {
146    static const uint8_t invalid_swizzle = 0xff;
147    ssize_t si = 0;
148    uint8_t inverse[4] = {invalid_swizzle, invalid_swizzle,
149                          invalid_swizzle, invalid_swizzle};
150 
151    for (int i = 0; i < 4; ++i) {
152       if (swizzle[i] > 3)
153          continue;
154 
155       if (inverse[swizzle[i]] == invalid_swizzle)
156          inverse[swizzle[i]] = i;
157    }
158 
159    for (int i = 0; i < 4; ++i) {
160       int res = -1;
161       if (inverse[i] > 3) {
162           /* Use 0.0f for unused color values, 1.0f for an unused alpha value */
163          res = snprintf(&snippet[si], DEST_SWIZZLE_SNIPPET_SIZE - si,
164                         i < 3 ? "0.0f, " : "1.0f");
165       } else {
166          res = snprintf(&snippet[si], DEST_SWIZZLE_SNIPPET_SIZE - si,
167                         "texel.%c%s", "rgba"[inverse[i]], i < 3 ? ", " : "");
168       }
169       si += res > 0 ? res : 0;
170    }
171 }
172 
vec4_type_for_tgsi_ret(enum tgsi_return_type tgsi_ret)173 static const char *vec4_type_for_tgsi_ret(enum tgsi_return_type tgsi_ret)
174 {
175    switch (tgsi_ret) {
176    case TGSI_RETURN_TYPE_SINT: return "ivec4";
177    case TGSI_RETURN_TYPE_UINT: return "uvec4";
178    default: return "vec4";
179    }
180 }
181 
tgsi_ret_for_format(enum virgl_formats format)182 static enum tgsi_return_type tgsi_ret_for_format(enum virgl_formats format)
183 {
184    if (util_format_is_pure_uint(format))
185       return TGSI_RETURN_TYPE_UINT;
186    else if (util_format_is_pure_sint(format))
187       return TGSI_RETURN_TYPE_SINT;
188 
189    return TGSI_RETURN_TYPE_UNORM;
190 }
191 
blit_get_swizzle(int tgsi_tex_target,unsigned flags,struct blit_swizzle_and_type * retval)192 static void blit_get_swizzle(int tgsi_tex_target, unsigned flags,
193                              struct blit_swizzle_and_type *retval)
194 {
195    retval->swizzle = "";
196    retval->type = "";
197    retval->is_array = false;
198    switch (tgsi_tex_target) {
199    case TGSI_TEXTURE_1D:
200       if ((flags & (BLIT_USE_GLES | BLIT_USE_DEPTH)) == (BLIT_USE_GLES | BLIT_USE_DEPTH)) {
201          retval->swizzle = ".xy";
202          break;
203       }
204       /* fallthrough */
205    case TGSI_TEXTURE_BUFFER:
206       retval->swizzle = ".x";
207       break;
208    case TGSI_TEXTURE_2D_MSAA:
209       if (flags & BLIT_USE_MSAA) {
210          retval->type = "ivec2";
211       }
212       retval->swizzle = ".xy";
213       break;
214    case TGSI_TEXTURE_1D_ARRAY:
215       if (flags & (BLIT_USE_GLES)) {
216          retval->swizzle = ".xyz";
217          break;
218       }
219       /* fallthrough */
220    case TGSI_TEXTURE_2D:
221    case TGSI_TEXTURE_RECT:
222       retval->swizzle = ".xy";
223       break;
224    case TGSI_TEXTURE_2D_ARRAY_MSAA:
225       if (flags & BLIT_USE_MSAA) {
226          retval->type = "ivec3";
227          retval->is_array = true;
228       }
229       /* fallthrough */
230    case TGSI_TEXTURE_SHADOW1D:
231    case TGSI_TEXTURE_SHADOW2D:
232    case TGSI_TEXTURE_SHADOW1D_ARRAY:
233    case TGSI_TEXTURE_SHADOWRECT:
234    case TGSI_TEXTURE_3D:
235    case TGSI_TEXTURE_CUBE:
236    case TGSI_TEXTURE_2D_ARRAY:
237       retval->swizzle = ".xyz";
238       break;
239    case TGSI_TEXTURE_SHADOWCUBE:
240    case TGSI_TEXTURE_SHADOW2D_ARRAY:
241    case TGSI_TEXTURE_SHADOWCUBE_ARRAY:
242    case TGSI_TEXTURE_CUBE_ARRAY:
243       retval->swizzle = "";
244       break;
245    default:
246       if (flags & BLIT_USE_MSAA) {
247          break;
248       }
249       retval->swizzle = ".xy";
250       break;
251    }
252 }
253 
blit_build_frag_tex_col(struct vrend_blitter_ctx * blit_ctx,int tgsi_tex_target,enum tgsi_return_type tgsi_ret,const uint8_t swizzle[4],int nr_samples,uint32_t flags)254 static GLuint blit_build_frag_tex_col(struct vrend_blitter_ctx *blit_ctx,
255                                       int tgsi_tex_target,
256                                       enum tgsi_return_type tgsi_ret,
257                                       const uint8_t swizzle[4],
258                                       int nr_samples,
259                                       uint32_t flags)
260 {
261    char shader_buf[4096];
262    struct blit_swizzle_and_type swizzle_and_type;
263    unsigned swizzle_flags = 0;
264    char dest_swizzle_snippet[DEST_SWIZZLE_SNIPPET_SIZE] = "texel";
265    const char *ext_str = "";
266    bool msaa = nr_samples > 0;
267 
268    if (msaa && !blit_ctx->use_gles)
269       ext_str = "#extension GL_ARB_texture_multisample : enable\n";
270    else if (tgsi_tex_target == TGSI_TEXTURE_CUBE_ARRAY ||
271             tgsi_tex_target == TGSI_TEXTURE_SHADOWCUBE_ARRAY) {
272       if (blit_ctx->use_gles)
273          ext_str = "#extension GL_EXT_texture_cube_map_array : require\n";
274       else
275          ext_str = "#extension GL_ARB_texture_cube_map_array : require\n";
276    }
277 
278    if (blit_ctx->use_gles)
279       swizzle_flags |= BLIT_USE_GLES;
280    if (msaa)
281       swizzle_flags |= BLIT_USE_MSAA;
282    blit_get_swizzle(tgsi_tex_target, swizzle_flags, &swizzle_and_type);
283 
284    if (swizzle)
285       create_dest_swizzle_snippet(swizzle, dest_swizzle_snippet);
286 
287    bool needs_manual_srgb_decode = has_bit(flags, BLIT_MANUAL_SRGB_DECODE);
288    bool needs_manual_srgb_encode = has_bit(flags, BLIT_MANUAL_SRGB_ENCODE);
289 
290    if (msaa)
291       snprintf(shader_buf, 4096, blit_ctx->use_gles ?
292                                  (swizzle_and_type.is_array ? FS_TEXFETCH_COL_MSAA_ARRAY_GLES
293                                                    : FS_TEXFETCH_COL_MSAA_GLES)
294                                  : FS_TEXFETCH_COL_MSAA_GL,
295          ext_str, vec4_type_for_tgsi_ret(tgsi_ret),
296          needs_manual_srgb_decode ? FS_FUNC_COL_SRGB_DECODE : "",
297          needs_manual_srgb_encode ? FS_FUNC_COL_SRGB_ENCODE : "",
298          needs_manual_srgb_decode ? "srgb_decode" : "",
299          needs_manual_srgb_encode ? "srgb_encode" : "",
300          vrend_shader_samplerreturnconv(tgsi_ret),
301          vrend_shader_samplertypeconv(blit_ctx->use_gles, tgsi_tex_target),
302          nr_samples, swizzle_and_type.type, swizzle_and_type.swizzle, dest_swizzle_snippet);
303    else
304       snprintf(shader_buf, 4096, blit_ctx->use_gles ?
305                                  (tgsi_tex_target == TGSI_TEXTURE_1D ?
306                                     FS_TEXFETCH_COL_GLES_1D : FS_TEXFETCH_COL_GLES)
307                                  : FS_TEXFETCH_COL_GL,
308          ext_str, vec4_type_for_tgsi_ret(tgsi_ret),
309          needs_manual_srgb_decode ? FS_FUNC_COL_SRGB_DECODE : "",
310          needs_manual_srgb_encode ? FS_FUNC_COL_SRGB_ENCODE : "",
311          needs_manual_srgb_decode ? "srgb_decode" : "",
312          needs_manual_srgb_encode ? "srgb_encode" : "",
313          vrend_shader_samplerreturnconv(tgsi_ret),
314          vrend_shader_samplertypeconv(blit_ctx->use_gles, tgsi_tex_target),
315          swizzle_and_type.swizzle, dest_swizzle_snippet);
316 
317    VREND_DEBUG(dbg_blit, NULL, "-- Blit FS color shader MSAA: %d -----------------\n"
318                "%s\n---------------------------------------\n", msaa, shader_buf);
319 
320    return blit_shader_build_and_check(GL_FRAGMENT_SHADER, shader_buf);
321 }
322 
blit_build_frag_depth(struct vrend_blitter_ctx * blit_ctx,int tgsi_tex_target,bool msaa)323 static GLuint blit_build_frag_depth(struct vrend_blitter_ctx *blit_ctx, int tgsi_tex_target, bool msaa)
324 {
325    char shader_buf[4096];
326    struct blit_swizzle_and_type swizzle_and_type;
327    unsigned flags = BLIT_USE_DEPTH;
328 
329    if (msaa)
330       flags |= BLIT_USE_MSAA;
331 
332    blit_get_swizzle(tgsi_tex_target, flags, &swizzle_and_type);
333 
334    if (msaa)
335       snprintf(shader_buf, 4096, blit_ctx->use_gles ?
336                                  (swizzle_and_type.is_array ?  FS_TEXFETCH_DS_MSAA_ARRAY_GLES :  FS_TEXFETCH_DS_MSAA_GLES)
337                                  : FS_TEXFETCH_DS_MSAA_GL,
338          vrend_shader_samplertypeconv(blit_ctx->use_gles, tgsi_tex_target), swizzle_and_type.type, swizzle_and_type.swizzle);
339    else
340       snprintf(shader_buf, 4096, blit_ctx->use_gles ? FS_TEXFETCH_DS_GLES : FS_TEXFETCH_DS_GL,
341          vrend_shader_samplertypeconv(blit_ctx->use_gles, tgsi_tex_target), swizzle_and_type.swizzle);
342 
343    VREND_DEBUG(dbg_blit, NULL, "-- Blit FS depth shader MSAA: %d -----------------\n"
344                "%s\n---------------------------------------\n", msaa, shader_buf);
345 
346    return blit_shader_build_and_check(GL_FRAGMENT_SHADER, shader_buf);
347 }
348 
blit_get_frag_tex_writedepth(struct vrend_blitter_ctx * blit_ctx,int pipe_tex_target,unsigned nr_samples)349 static GLuint blit_get_frag_tex_writedepth(struct vrend_blitter_ctx *blit_ctx, int pipe_tex_target, unsigned nr_samples)
350 {
351    struct blit_prog_key key = {
352          .is_color = false,
353          .is_msaa = nr_samples > 0,
354          .num_samples = nr_samples,
355          .pipe_tex_target = pipe_tex_target,
356       };
357 
358       void *shader = util_hash_table_get(blit_ctx->blit_programs, &key);
359       GLuint prog_id;
360       if (shader) {
361          prog_id = (GLuint)((size_t)(shader) & 0xffffffff);
362       } else {
363          prog_id = glCreateProgram();
364          glAttachShader(prog_id, blit_ctx->vs);
365          unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(pipe_tex_target, key.num_samples);
366          GLuint fs_id = blit_build_frag_depth(blit_ctx, tgsi_tex, key.is_msaa);
367          glAttachShader(prog_id, fs_id);
368          if(!blit_shader_link_and_check(prog_id))
369             return 0;
370 
371          glDeleteShader(fs_id);
372          util_hash_table_set(blit_ctx->blit_programs, &key, (void *)(uintptr_t)prog_id);
373       }
374       return prog_id;
375 }
376 
blit_get_frag_tex_col(struct vrend_blitter_ctx * blit_ctx,int pipe_tex_target,unsigned nr_samples,const struct vrend_format_table * src_entry,const uint8_t swizzle[static4],uint32_t flags)377 static GLuint blit_get_frag_tex_col(struct vrend_blitter_ctx *blit_ctx,
378                                        int pipe_tex_target,
379                                        unsigned nr_samples,
380                                        const struct vrend_format_table *src_entry,
381                                        const uint8_t swizzle[static 4],
382                                        uint32_t flags)
383 {
384    bool needs_swizzle = false;
385    for (uint i = 0; i < 4; ++i) {
386       if (swizzle[i] != i) {
387          needs_swizzle = true;
388          break;
389       }
390    }
391 
392    struct blit_prog_key key = {
393       .is_color = true,
394       .is_msaa = nr_samples > 0,
395       .manual_srgb_decode = has_bit(flags, BLIT_MANUAL_SRGB_DECODE),
396       .manual_srgb_encode = has_bit(flags, BLIT_MANUAL_SRGB_ENCODE),
397       .num_samples = nr_samples,
398       .pipe_tex_target  = pipe_tex_target
399    };
400 
401    key.texcol.src_format = src_entry->format;
402    key.texcol.has_swizzle = needs_swizzle;
403    if (key.texcol.has_swizzle)
404       memcpy(key.texcol.swizzle, swizzle, 4);
405 
406    GLuint prog_id = 0;
407    void *shader = util_hash_table_get(blit_ctx->blit_programs, &key);
408 
409    if (shader) {
410       prog_id = (GLuint)((size_t)(shader) & 0xffffffff);
411    } else {
412       prog_id = glCreateProgram();
413       glAttachShader(prog_id, blit_ctx->vs);
414       unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(pipe_tex_target, key.num_samples);
415       enum tgsi_return_type tgsi_ret = tgsi_ret_for_format(src_entry->format);
416       int msaa_samples = nr_samples > 0 ? (tgsi_ret == TGSI_RETURN_TYPE_UNORM ? nr_samples : 1) : 0;
417 
418       GLuint fs_id = blit_build_frag_tex_col(blit_ctx, tgsi_tex, tgsi_ret,
419                                              swizzle, msaa_samples, flags);
420       glAttachShader(prog_id, fs_id);
421       if(!blit_shader_link_and_check(prog_id))
422          return 0;
423 
424       glDeleteShader(fs_id);
425       util_hash_table_set(blit_ctx->blit_programs, &key, (void *)(uintptr_t)prog_id);
426    }
427 
428    return prog_id;
429 }
430 
program_hash_func(const void * key)431 static uint32_t program_hash_func(const void *key)
432 {
433    return XXH32(key, sizeof(struct blit_prog_key), 0);
434 }
435 
program_equal_func(const void * key1,const void * key2)436 static bool program_equal_func(const void *key1, const void *key2)
437 {
438    return memcmp(key1, key2, sizeof(struct blit_prog_key)) == 0;
439 }
440 
program_destroy_func(void * shader_id)441 static void program_destroy_func(void *shader_id)
442 {
443    GLuint id;
444 #if __SIZEOF_POINTER__  == 8
445    id = ((uint64_t)(shader_id)) & 0xffffffff;
446 #else
447    id = (GLuint)(shader_id);
448 #endif
449    glDeleteProgram(id);
450 }
451 
452 
vrend_renderer_init_blit_ctx(struct vrend_blitter_ctx * blit_ctx)453 static void vrend_renderer_init_blit_ctx(struct vrend_blitter_ctx *blit_ctx)
454 {
455    struct virgl_gl_ctx_param ctx_params;
456    int i;
457    if (blit_ctx->initialised) {
458       vrend_sync_make_current(blit_ctx->gl_context);
459       return;
460    }
461 
462    vrend_blit_ctx.blit_programs = util_hash_table_create(program_hash_func,
463                                                          program_equal_func,
464                                                          program_destroy_func);
465 
466    blit_ctx->use_gles = epoxy_is_desktop_gl() == 0;
467    ctx_params.shared = true;
468    for (uint32_t i = 0; i < ARRAY_SIZE(gl_versions); i++) {
469       ctx_params.major_ver = gl_versions[i].major;
470       ctx_params.minor_ver = gl_versions[i].minor;
471 
472       blit_ctx->gl_context = vrend_clicbs->create_gl_context(0, &ctx_params);
473       if (blit_ctx->gl_context)
474          break;
475    }
476 
477    if (!blit_ctx->gl_context) {
478       vrend_printf("virglrenderer: Unable to create blit context");
479       abort();
480    }
481 
482    vrend_sync_make_current(blit_ctx->gl_context);
483    glGenVertexArrays(1, &blit_ctx->vaoid);
484    glGenFramebuffers(1, &blit_ctx->fb_id);
485 
486    glGenBuffers(1, &blit_ctx->vbo_id);
487    blit_ctx->vs = blit_shader_build_and_check(GL_VERTEX_SHADER,
488         blit_ctx->use_gles ? VS_PASSTHROUGH_GLES : VS_PASSTHROUGH_GL);
489 
490    for (i = 0; i < 4; i++) {
491       blit_ctx->vertices[i].pos.z = 0;
492       blit_ctx->vertices[i].pos.w = 1;
493    }
494 
495    glBindVertexArray(blit_ctx->vaoid);
496    glBindBuffer(GL_ARRAY_BUFFER, blit_ctx->vbo_id);
497 
498    if (!blit_ctx->use_gles)
499       glEnable(GL_FRAMEBUFFER_SRGB);
500 
501    blit_ctx->initialised = true;
502 }
503 
blitter_set_rectangle(struct vrend_blitter_ctx * blit_ctx,int x1,int y1,int x2,int y2)504 static void blitter_set_rectangle(struct vrend_blitter_ctx *blit_ctx,
505                                   int x1, int y1, int x2, int y2)
506 {
507    /* set vertex positions */
508    blit_ctx->vertices[0].pos.x = (float)x1 / blit_ctx->dst_width * 2.0f - 1.0f; /*v0.x*/
509    blit_ctx->vertices[0].pos.y = (float)y1 / blit_ctx->dst_height * 2.0f - 1.0f; /*v0.y*/
510 
511    blit_ctx->vertices[1].pos.x = (float)x2 / blit_ctx->dst_width * 2.0f - 1.0f; /*v1.x*/
512    blit_ctx->vertices[1].pos.y = (float)y1 / blit_ctx->dst_height * 2.0f - 1.0f; /*v1.y*/
513 
514    blit_ctx->vertices[2].pos.x = (float)x2 / blit_ctx->dst_width * 2.0f - 1.0f; /*v2.x*/
515    blit_ctx->vertices[2].pos.y = (float)y2 / blit_ctx->dst_height * 2.0f - 1.0f; /*v2.y*/
516 
517    blit_ctx->vertices[3].pos.x = (float)x1 / blit_ctx->dst_width * 2.0f - 1.0f; /*v3.x*/
518    blit_ctx->vertices[3].pos.y = (float)y2 / blit_ctx->dst_height * 2.0f - 1.0f; /*v3.y*/
519 
520    glViewport(0, 0, blit_ctx->dst_width, blit_ctx->dst_height);
521 }
522 
get_texcoords(struct vrend_blitter_ctx * blit_ctx,struct vrend_resource * src_res,int src_level,int x1,int y1,int x2,int y2,float out[4])523 static void get_texcoords(struct vrend_blitter_ctx *blit_ctx,
524                           struct vrend_resource *src_res,
525                           int src_level,
526                           int x1, int y1, int x2, int y2,
527                           float out[4])
528 {
529    bool normalized = (src_res->base.target != PIPE_TEXTURE_RECT || blit_ctx->use_gles) &&
530                      src_res->base.nr_samples < 1;
531 
532    if (normalized) {
533       out[0] = x1 / (float)u_minify(src_res->base.width0,  src_level);
534       out[1] = y1 / (float)u_minify(src_res->base.height0, src_level);
535       out[2] = x2 / (float)u_minify(src_res->base.width0,  src_level);
536       out[3] = y2 / (float)u_minify(src_res->base.height0, src_level);
537    } else {
538       out[0] = (float) x1;
539       out[1] = (float) y1;
540       out[2] = (float) x2;
541       out[3] = (float) y2;
542    }
543 }
544 
set_texcoords_in_vertices(const float coord[4],float * out,unsigned stride)545 static void set_texcoords_in_vertices(const float coord[4],
546                                       float *out, unsigned stride)
547 {
548    out[0] = coord[0]; /*t0.s*/
549    out[1] = coord[1]; /*t0.t*/
550    out += stride;
551    out[0] = coord[2]; /*t1.s*/
552    out[1] = coord[1]; /*t1.t*/
553    out += stride;
554    out[0] = coord[2]; /*t2.s*/
555    out[1] = coord[3]; /*t2.t*/
556    out += stride;
557    out[0] = coord[0]; /*t3.s*/
558    out[1] = coord[3]; /*t3.t*/
559 }
560 
blitter_set_texcoords(struct vrend_blitter_ctx * blit_ctx,struct vrend_resource * src_res,int level,float layer,unsigned sample,int x1,int y1,int x2,int y2)561 static void blitter_set_texcoords(struct vrend_blitter_ctx *blit_ctx,
562                                   struct vrend_resource *src_res,
563                                   int level,
564                                   float layer, unsigned sample,
565                                   int x1, int y1, int x2, int y2)
566 {
567    float coord[4];
568    float face_coord[4][2];
569    int i;
570    get_texcoords(blit_ctx, src_res, level, x1, y1, x2, y2, coord);
571 
572    if (src_res->base.target == PIPE_TEXTURE_CUBE ||
573        src_res->base.target == PIPE_TEXTURE_CUBE_ARRAY) {
574       set_texcoords_in_vertices(coord, &face_coord[0][0], 2);
575       util_map_texcoords2d_onto_cubemap((unsigned)layer % 6,
576                                         /* pointer, stride in floats */
577                                         &face_coord[0][0], 2,
578                                         &blit_ctx->vertices[0].tex.x, 8,
579                                         FALSE);
580    } else {
581       set_texcoords_in_vertices(coord, &blit_ctx->vertices[0].tex.x, 8);
582    }
583 
584    switch (src_res->base.target) {
585    case PIPE_TEXTURE_3D:
586    {
587       float r = layer / (float)u_minify(src_res->base.depth0,
588                                         level);
589       for (i = 0; i < 4; i++)
590          blit_ctx->vertices[i].tex.z = r; /*r*/
591    }
592    break;
593 
594    case PIPE_TEXTURE_1D_ARRAY:
595       for (i = 0; i < 4; i++)
596          blit_ctx->vertices[i].tex.y = (float) layer; /*t*/
597       break;
598 
599    case PIPE_TEXTURE_2D_ARRAY:
600       for (i = 0; i < 4; i++) {
601          blit_ctx->vertices[i].tex.z = (float) layer;  /*r*/
602          blit_ctx->vertices[i].tex.w = (float) sample; /*q*/
603       }
604       break;
605    case PIPE_TEXTURE_CUBE_ARRAY:
606       for (i = 0; i < 4; i++)
607          blit_ctx->vertices[i].tex.w = (float) ((unsigned)layer / 6); /*w*/
608       break;
609    case PIPE_TEXTURE_2D:
610       for (i = 0; i < 4; i++) {
611          blit_ctx->vertices[i].tex.w = (float) sample; /*r*/
612       }
613       break;
614    default:;
615    }
616 }
617 
set_dsa_write_depth_keep_stencil(void)618 static void set_dsa_write_depth_keep_stencil(void)
619 {
620    glDisable(GL_STENCIL_TEST);
621    glEnable(GL_DEPTH_TEST);
622    glDepthFunc(GL_ALWAYS);
623    glDepthMask(GL_TRUE);
624 }
625 
to_gl_swizzle(int swizzle)626 static inline GLenum to_gl_swizzle(int swizzle)
627 {
628    switch (swizzle) {
629    case PIPE_SWIZZLE_RED: return GL_RED;
630    case PIPE_SWIZZLE_GREEN: return GL_GREEN;
631    case PIPE_SWIZZLE_BLUE: return GL_BLUE;
632    case PIPE_SWIZZLE_ALPHA: return GL_ALPHA;
633    case PIPE_SWIZZLE_ZERO: return GL_ZERO;
634    case PIPE_SWIZZLE_ONE: return GL_ONE;
635    default:
636       assert(0);
637       return 0;
638    }
639 }
640 
641 /* Calculate the delta required to keep 'v' within [0, max] */
calc_delta_for_bound(int v,int max)642 static int calc_delta_for_bound(int v, int max)
643 {
644     int delta = 0;
645 
646     if (v < 0)
647         delta = -v;
648     else if (v > max)
649         delta = - (v - max);
650 
651     return delta;
652 }
653 
654 /* Calculate the deltas for the source blit region points in order to bound
655  * them within the source resource extents */
calc_src_deltas_for_bounds(struct vrend_resource * src_res,const struct pipe_blit_info * info,struct blit_point * src0_delta,struct blit_point * src1_delta)656 static void calc_src_deltas_for_bounds(struct vrend_resource *src_res,
657                                        const struct pipe_blit_info *info,
658                                        struct blit_point *src0_delta,
659                                        struct blit_point *src1_delta)
660 {
661    int max_x = u_minify(src_res->base.width0, info->src.level) - 1;
662    int max_y = u_minify(src_res->base.height0, info->src.level) - 1;
663 
664    /* Whether the bounds for the coordinates of a point are inclusive or
665     * exclusive depends on the direction of the blit read. Adjust the max
666     * bounds accordingly, with an adjustment of 0 for inclusive, and 1 for
667     * exclusive. */
668    int src0_x_excl = info->src.box.width < 0;
669    int src0_y_excl = info->src.box.height < 0;
670 
671    src0_delta->x = calc_delta_for_bound(info->src.box.x, max_x + src0_x_excl);
672    src0_delta->y = calc_delta_for_bound(info->src.box.y, max_y + src0_y_excl);
673 
674    src1_delta->x = calc_delta_for_bound(info->src.box.x + info->src.box.width,
675                                          max_x + !src0_x_excl);
676    src1_delta->y = calc_delta_for_bound(info->src.box.y + info->src.box.height,
677                                          max_y + !src0_y_excl);
678 }
679 
680 /* Calculate dst delta values to adjust the dst points for any changes in the
681  * src points */
calc_dst_deltas_from_src(const struct pipe_blit_info * info,const struct blit_point * src0_delta,const struct blit_point * src1_delta,struct blit_point * dst0_delta,struct blit_point * dst1_delta)682 static void calc_dst_deltas_from_src(const struct pipe_blit_info *info,
683                                      const struct blit_point *src0_delta,
684                                      const struct blit_point *src1_delta,
685                                      struct blit_point *dst0_delta,
686                                      struct blit_point *dst1_delta)
687 {
688    float scale_x = (float)info->dst.box.width / (float)info->src.box.width;
689    float scale_y = (float)info->dst.box.height / (float)info->src.box.height;
690 
691    dst0_delta->x = src0_delta->x * scale_x;
692    dst0_delta->y = src0_delta->y * scale_y;
693 
694    dst1_delta->x = src1_delta->x * scale_x;
695    dst1_delta->y = src1_delta->y * scale_y;
696 }
697 
blitter_set_points(struct vrend_blitter_ctx * blit_ctx,const struct pipe_blit_info * info,struct vrend_resource * src_res,struct vrend_resource * dst_res,struct blit_point * src0,struct blit_point * src1)698 static void blitter_set_points(struct vrend_blitter_ctx *blit_ctx,
699                                const struct pipe_blit_info *info,
700                                struct vrend_resource *src_res,
701                                struct vrend_resource *dst_res,
702                                struct blit_point *src0,
703                                struct blit_point *src1)
704 {
705    struct blit_point dst0, dst1;
706    struct blit_point src0_delta, src1_delta, dst0_delta, dst1_delta;
707 
708    blit_ctx->dst_width = u_minify(dst_res->base.width0, info->dst.level);
709    blit_ctx->dst_height = u_minify(dst_res->base.height0, info->dst.level);
710 
711    /* Calculate src and dst points taking deltas into account */
712    calc_src_deltas_for_bounds(src_res, info, &src0_delta, &src1_delta);
713    calc_dst_deltas_from_src(info, &src0_delta, &src1_delta, &dst0_delta, &dst1_delta);
714 
715    src0->x = info->src.box.x + src0_delta.x;
716    src0->y = info->src.box.y + src0_delta.y;
717    src1->x = info->src.box.x + info->src.box.width + src1_delta.x;
718    src1->y = info->src.box.y + info->src.box.height + src1_delta.y;
719 
720    dst0.x = info->dst.box.x + dst0_delta.x;
721    dst0.y = info->dst.box.y + dst0_delta.y;
722    dst1.x = info->dst.box.x + info->dst.box.width + dst1_delta.x;
723    dst1.y = info->dst.box.y + info->dst.box.height + dst1_delta.y;
724 
725    VREND_DEBUG(dbg_blit, NULL, "Blitter src:[%3d, %3d] - [%3d, %3d] to dst:[%3d, %3d] - [%3d, %3d]\n",
726                src0->x, src0->y, src1->x, src1->y,
727                dst0.x, dst0.y, dst1.x, dst1.y);
728 
729    blitter_set_rectangle(blit_ctx, dst0.x, dst0.y, dst1.x, dst1.y);
730 }
731 
vrend_set_tex_param(struct vrend_resource * src_res,const struct pipe_blit_info * info,bool has_texture_srgb_decode)732 static void vrend_set_tex_param(struct vrend_resource *src_res,
733                                 const struct pipe_blit_info *info,
734                                 bool has_texture_srgb_decode)
735 {
736    const struct vrend_format_table *src_entry =
737       vrend_get_format_table_entry(info->src.format);
738 
739    if (src_entry->flags & VIRGL_TEXTURE_NEED_SWIZZLE) {
740       glTexParameteri(src_res->target, GL_TEXTURE_SWIZZLE_R,
741                       to_gl_swizzle(src_entry->swizzle[0]));
742       glTexParameteri(src_res->target, GL_TEXTURE_SWIZZLE_G,
743                       to_gl_swizzle(src_entry->swizzle[1]));
744       glTexParameteri(src_res->target, GL_TEXTURE_SWIZZLE_B,
745                       to_gl_swizzle(src_entry->swizzle[2]));
746       glTexParameteri(src_res->target, GL_TEXTURE_SWIZZLE_A,
747                       to_gl_swizzle(src_entry->swizzle[3]));
748    }
749 
750    /* Just make sure that no stale state disabled decoding */
751    if (has_texture_srgb_decode && util_format_is_srgb(info->src.format) &&
752        src_res->base.nr_samples < 1)
753       glTexParameteri(src_res->target, GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
754 
755    if (src_res->base.nr_samples < 1) {
756       glTexParameteri(src_res->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
757       glTexParameteri(src_res->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
758       glTexParameteri(src_res->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
759    }
760 
761    glTexParameteri(src_res->target, GL_TEXTURE_BASE_LEVEL, info->src.level);
762    glTexParameteri(src_res->target, GL_TEXTURE_MAX_LEVEL, info->src.level);
763 
764    if (src_res->base.nr_samples < 1) {
765       GLenum filter = info->filter == PIPE_TEX_FILTER_NEAREST ?
766                                        GL_NEAREST : GL_LINEAR;
767       glTexParameteri(src_res->target, GL_TEXTURE_MAG_FILTER, filter);
768       glTexParameteri(src_res->target, GL_TEXTURE_MIN_FILTER, filter);
769    }
770 }
771 
vrend_set_vertex_param(GLuint prog_id)772 static void vrend_set_vertex_param(GLuint prog_id)
773 {
774    GLuint pos_loc, tc_loc;
775 
776    pos_loc = glGetAttribLocation(prog_id, "arg0");
777    tc_loc = glGetAttribLocation(prog_id, "arg1");
778 
779    glVertexAttribPointer(pos_loc, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)0);
780    glVertexAttribPointer(tc_loc, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(4 * sizeof(float)));
781 
782    glEnableVertexAttribArray(pos_loc);
783    glEnableVertexAttribArray(tc_loc);
784 }
785 
786 /* implement blitting using OpenGL. */
vrend_renderer_blit_gl(ASSERTED struct vrend_context * ctx,struct vrend_resource * src_res,struct vrend_resource * dst_res,const struct vrend_blit_info * info)787 void vrend_renderer_blit_gl(ASSERTED struct vrend_context *ctx,
788                             struct vrend_resource *src_res,
789                             struct vrend_resource *dst_res,
790                             const struct vrend_blit_info *info)
791 {
792    struct vrend_blitter_ctx *blit_ctx = &vrend_blit_ctx;
793 
794    int dst_z;
795    struct blit_point src0, src1;
796    const struct util_format_description *src_desc =
797       util_format_description(src_res->base.format);
798    const struct util_format_description *dst_desc =
799       util_format_description(dst_res->base.format);
800    const struct vrend_format_table *orig_src_entry = vrend_get_format_table_entry(info->b.src.format);
801 
802    bool blit_depth = util_format_has_depth(src_desc) &&
803          util_format_has_depth(dst_desc) &&
804          (info->b.mask & PIPE_MASK_Z);
805 
806    vrend_renderer_init_blit_ctx(blit_ctx);
807    blitter_set_points(blit_ctx, &info->b, src_res, dst_res, &src0, &src1);
808 
809    GLuint prog_id;
810 
811    if (blit_depth) {
812       prog_id = blit_get_frag_tex_writedepth(blit_ctx, src_res->base.target,
813                                              src_res->base.nr_samples);
814    } else {
815       VREND_DEBUG(dbg_blit, ctx, "BLIT: applying swizzle during blit: (%d %d %d %d)\n",
816                   info->swizzle[0], info->swizzle[1], info->swizzle[2], info->swizzle[3]);
817 
818       if (info->needs_manual_srgb_decode)
819          VREND_DEBUG(dbg_blit, ctx,
820                      "BLIT: applying manual srgb->linear conversion for src %s(%s)\n",
821                      util_format_name(src_res->base.format),
822                      util_format_name(info->b.src.format));
823 
824       if (info->needs_manual_srgb_encode)
825          VREND_DEBUG(dbg_blit, ctx,
826                      "BLIT: applying manual linear->srgb conversion for dst %s(%s)\n",
827                      util_format_name(dst_res->base.format),
828                      util_format_name(info->b.dst.format));
829 
830       uint32_t flags = 0;
831       flags |= info->needs_manual_srgb_decode ? BLIT_MANUAL_SRGB_DECODE : 0;
832       flags |= info->needs_manual_srgb_encode ? BLIT_MANUAL_SRGB_ENCODE : 0;
833       prog_id = blit_get_frag_tex_col(blit_ctx, src_res->base.target,
834                                       src_res->base.nr_samples,
835                                       orig_src_entry,
836                                       info->swizzle,
837                                       flags);
838    }
839    if (!prog_id) {
840       vrend_printf("Blitter: unable to create or find shader program\n");
841       return;
842    }
843 
844    glUseProgram(prog_id);
845 
846    glBindFramebuffer(GL_FRAMEBUFFER, blit_ctx->fb_id);
847    vrend_fb_bind_texture_id(dst_res, info->dst_view, 0, info->b.dst.level, info->b.dst.box.z, 0);
848 
849    GLuint buffers = GL_COLOR_ATTACHMENT0;
850    glDrawBuffers(1, &buffers);
851 
852    glBindTexture(src_res->target, info->src_view);
853    vrend_set_tex_param(src_res, &info->b,
854                        info->has_texture_srgb_decode &&
855                        !info->needs_manual_srgb_decode);
856    vrend_set_vertex_param(prog_id);
857 
858    set_dsa_write_depth_keep_stencil();
859 
860    if (info->b.scissor_enable) {
861       glScissor(info->b.scissor.minx, info->b.scissor.miny,
862                 info->b.scissor.maxx - info->b.scissor.minx,
863                 info->b.scissor.maxy - info->b.scissor.miny);
864       glEnable(GL_SCISSOR_TEST);
865    } else
866       glDisable(GL_SCISSOR_TEST);
867 
868    if (info->has_srgb_write_control) {
869       if (!info->needs_manual_srgb_encode &&
870           (util_format_is_srgb(info->b.dst.format) || util_format_is_srgb(info->b.src.format))) {
871          VREND_DEBUG(dbg_blit, ctx, "%s: Enable GL_FRAMEBUFFER_SRGB\n", __func__);
872          glEnable(GL_FRAMEBUFFER_SRGB);
873       } else {
874          VREND_DEBUG(dbg_blit, ctx, "%s: Disable GL_FRAMEBUFFER_SRGB\n", __func__);
875          glDisable(GL_FRAMEBUFFER_SRGB);
876       }
877    }
878 
879    for (dst_z = 0; dst_z < info->b.dst.box.depth; dst_z++) {
880       float dst2src_scale = info->b.src.box.depth / (float)info->b.dst.box.depth;
881       float dst_offset = ((info->b.src.box.depth - 1) -
882                           (info->b.dst.box.depth - 1) * dst2src_scale) * 0.5;
883       float src_z = (dst_z + dst_offset) * dst2src_scale;
884 
885       uint32_t layer = (dst_res->target == GL_TEXTURE_CUBE_MAP ||
886                         dst_res->target == GL_TEXTURE_1D_ARRAY ||
887                         dst_res->target == GL_TEXTURE_2D_ARRAY) ? info->b.dst.box.z : dst_z;
888 
889       vrend_fb_bind_texture_id(dst_res, info->dst_view, 0, info->b.dst.level, layer, 0);
890 
891       blitter_set_texcoords(blit_ctx, src_res, info->b.src.level,
892                             info->b.src.box.z + src_z, 0,
893                             src0.x, src0.y, src1.x, src1.y);
894 
895       glBufferData(GL_ARRAY_BUFFER, sizeof(blit_ctx->vertices), blit_ctx->vertices, GL_STATIC_DRAW);
896       glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
897    }
898 
899    glUseProgram(0);
900    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
901                              GL_TEXTURE_2D, 0, 0);
902    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
903                              GL_TEXTURE_2D, 0, 0);
904    glBindTexture(src_res->target, 0);
905 }
906 
vrend_blitter_fini(void)907 void vrend_blitter_fini(void)
908 {
909    vrend_blit_ctx.initialised = false;
910    vrend_clicbs->destroy_gl_context(vrend_blit_ctx.gl_context);
911    if (vrend_blit_ctx.blit_programs)
912       util_hash_table_destroy(vrend_blit_ctx.blit_programs);
913    memset(&vrend_blit_ctx, 0, sizeof(vrend_blit_ctx));
914 }
915