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