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