Home | History | Annotate | Download | only in src
      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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 }
    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 
    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 
    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 
    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] */
    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 */
    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 */
    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. */
    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 }