static void vrend_renderer_fill_caps_v1(int gl_ver, int gles_ver, union virgl_caps *caps)
{
   int i;
   GLint max;

   /*
    * We can't fully support this feature on GLES,
    * but it is needed for OpenGL 2.1 so lie.
    */
   caps->v1.bset.occlusion_query = 1;

   /* Set supported prims here as we now know what shaders we support. */
   caps->v1.prim_mask = (1 << PIPE_PRIM_POINTS) | (1 << PIPE_PRIM_LINES) |
                        (1 << PIPE_PRIM_LINE_STRIP) | (1 << PIPE_PRIM_LINE_LOOP) |
                        (1 << PIPE_PRIM_TRIANGLES) | (1 << PIPE_PRIM_TRIANGLE_STRIP) |
                        (1 << PIPE_PRIM_TRIANGLE_FAN);

   if (gl_ver > 0 && !vrend_state.use_core_profile) {
      caps->v1.bset.poly_stipple = 1;
      caps->v1.bset.color_clamping = 1;
      caps->v1.prim_mask |= (1 << PIPE_PRIM_QUADS) |
                            (1 << PIPE_PRIM_QUAD_STRIP) |
                            (1 << PIPE_PRIM_POLYGON);
   }

   if (caps->v1.glsl_level >= 150) {
      caps->v1.prim_mask |= (1 << PIPE_PRIM_LINES_ADJACENCY) |
                            (1 << PIPE_PRIM_LINE_STRIP_ADJACENCY) |
                            (1 << PIPE_PRIM_TRIANGLES_ADJACENCY) |
                            (1 << PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY);
   }
   if (caps->v1.glsl_level >= 400 || has_feature(feat_tessellation))
      caps->v1.prim_mask |= (1 << PIPE_PRIM_PATCHES);

   if (epoxy_has_gl_extension("GL_ARB_vertex_type_10f_11f_11f_rev"))
      set_format_bit(&caps->v1.vertexbuffer, VIRGL_FORMAT_R11G11B10_FLOAT);

   if (has_feature(feat_nv_conditional_render) ||
       has_feature(feat_gl_conditional_render))
      caps->v1.bset.conditional_render = 1;

   if (has_feature(feat_indep_blend))
      caps->v1.bset.indep_blend_enable = 1;

   if (has_feature(feat_draw_instance))
      caps->v1.bset.instanceid = 1;

   if (has_feature(feat_ubo)) {
      glGetIntegerv(GL_MAX_VERTEX_UNIFORM_BLOCKS, &max);
      caps->v1.max_uniform_blocks = max + 1;
   }

   if (has_feature(feat_depth_clamp))
      caps->v1.bset.depth_clip_disable = 1;

   if (gl_ver >= 32) {
      caps->v1.bset.fragment_coord_conventions = 1;
      caps->v1.bset.seamless_cube_map = 1;
   } else {
      if (epoxy_has_gl_extension("GL_ARB_fragment_coord_conventions"))
         caps->v1.bset.fragment_coord_conventions = 1;
      if (epoxy_has_gl_extension("GL_ARB_seamless_cube_map") || gles_ver >= 30)
         caps->v1.bset.seamless_cube_map = 1;
   }

   if (epoxy_has_gl_extension("GL_AMD_seamless_cube_map_per_texture")) {
      caps->v1.bset.seamless_cube_map_per_texture = 1;
   }

   if (has_feature(feat_texture_multisample))
      caps->v1.bset.texture_multisample = 1;

   if (has_feature(feat_tessellation))
      caps->v1.bset.has_tessellation_shaders = 1;

   if (has_feature(feat_sample_shading))
      caps->v1.bset.has_sample_shading = 1;

   if (has_feature(feat_indirect_draw))
      caps->v1.bset.has_indirect_draw = 1;

   if (has_feature(feat_indep_blend_func))
      caps->v1.bset.indep_blend_func = 1;

   if (has_feature(feat_cube_map_array))
      caps->v1.bset.cube_map_array = 1;

   if (has_feature(feat_texture_query_lod))
      caps->v1.bset.texture_query_lod = 1;

   if (gl_ver >= 40) {
      caps->v1.bset.has_fp64 = 1;
   } else {
      /* need gpu shader 5 for bitfield insert */
      if (epoxy_has_gl_extension("GL_ARB_gpu_shader_fp64") &&
          epoxy_has_gl_extension("GL_ARB_gpu_shader5"))
         caps->v1.bset.has_fp64 = 1;
   }

   if (has_feature(feat_base_instance))
      caps->v1.bset.start_instance = 1;

   if (epoxy_has_gl_extension("GL_ARB_shader_stencil_export")) {
      caps->v1.bset.shader_stencil_export = 1;
   }

   if (has_feature(feat_conditional_render_inverted))
      caps->v1.bset.conditional_render_inverted = 1;

   if (gl_ver >= 45) {
      caps->v1.bset.has_cull = 1;
      caps->v1.bset.derivative_control = 1;
   } else {
     if (has_feature(feat_cull_distance))
        caps->v1.bset.has_cull = 1;
     if (epoxy_has_gl_extension("GL_ARB_derivative_control"))
	caps->v1.bset.derivative_control = 1;
   }

   if (has_feature(feat_polygon_offset_clamp))
      caps->v1.bset.polygon_offset_clamp = 1;

   if (has_feature(feat_transform_feedback_overflow_query))
     caps->v1.bset.transform_feedback_overflow_query = 1;

   if (epoxy_has_gl_extension("GL_EXT_texture_mirror_clamp") ||
       epoxy_has_gl_extension("GL_ARB_texture_mirror_clamp_to_edge") ||
       epoxy_has_gl_extension("GL_EXT_texture_mirror_clamp_to_edge")) {
      caps->v1.bset.mirror_clamp = true;
   }

   if (has_feature(feat_texture_array)) {
      glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &max);
      caps->v1.max_texture_array_layers = max;
   }

   /* we need tf3 so we can do gallium skip buffers */
   if (has_feature(feat_transform_feedback)) {
      if (has_feature(feat_transform_feedback2))
         caps->v1.bset.streamout_pause_resume = 1;

      if (has_feature(feat_transform_feedback3)) {
         glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_BUFFERS, &max);
         caps->v1.max_streamout_buffers = max;
      } else if (gles_ver > 0) {
         glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &max);
         /* As with the earlier version of transform feedback this min 4. */
         if (max >= 4) {
            caps->v1.max_streamout_buffers = 4;
         }
      } else
         caps->v1.max_streamout_buffers = 4;
   }

   if (has_feature(feat_dual_src_blend)) {
      glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS, &max);
      caps->v1.max_dual_source_render_targets = max;
   }

   if (has_feature(feat_arb_or_gles_ext_texture_buffer)) {
      glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &max);
      caps->v1.max_tbo_size = max;
   }

   if (has_feature(feat_texture_gather)) {
      if (gl_ver > 0) {
         glGetIntegerv(GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB, &max);
         caps->v1.max_texture_gather_components = max;
      } else {
         caps->v1.max_texture_gather_components = 4;
      }
   }

   if (has_feature(feat_viewport_array)) {
      glGetIntegerv(GL_MAX_VIEWPORTS, &max);
      caps->v1.max_viewports = max;
   } else {
      caps->v1.max_viewports = 1;
   }

   /* Common limits for all backends. */
   caps->v1.max_render_targets = vrend_state.max_draw_buffers;

   glGetIntegerv(GL_MAX_SAMPLES, &max);
   caps->v1.max_samples = max;

   /* All of the formats are common. */
   for (i = 0; i < VIRGL_FORMAT_MAX; i++) {
      enum virgl_formats fmt = (enum virgl_formats)i;
      if (tex_conv_table[i].internalformat != 0 || fmt == VIRGL_FORMAT_YV12 ||
          fmt == VIRGL_FORMAT_NV12) {
         if (vrend_format_can_sample(fmt)) {
            set_format_bit(&caps->v1.sampler, fmt);
            if (vrend_format_can_render(fmt))
               set_format_bit(&caps->v1.render, fmt);
         }
      }
   }

   /* These are filled in by the init code, so are common. */
   if (has_feature(feat_nv_prim_restart) ||
       has_feature(feat_gl_prim_restart)) {
      caps->v1.bset.primitive_restart = 1;
   }
}
static void vrend_renderer_fill_caps_v1(int gl_ver, int gles_ver, union virgl_caps *caps)
{
   int i;
   GLint max;

    
   caps->v1.bset.occlusion_query = 1;

    
   caps->v1.prim_mask = (1 << PIPE_PRIM_POINTS) | (1 << PIPE_PRIM_LINES) |
                        (1 << PIPE_PRIM_LINE_STRIP) | (1 << PIPE_PRIM_LINE_LOOP) |
                        (1 << PIPE_PRIM_TRIANGLES) | (1 << PIPE_PRIM_TRIANGLE_STRIP) |
                        (1 << PIPE_PRIM_TRIANGLE_FAN);

   if (gl_ver > 0 && !vrend_state.use_core_profile) {
      caps->v1.bset.poly_stipple = 1;
      caps->v1.bset.color_clamping = 1;
      caps->v1.prim_mask |= (1 << PIPE_PRIM_QUADS) |
                            (1 << PIPE_PRIM_QUAD_STRIP) |
                            (1 << PIPE_PRIM_POLYGON);
   }

   if (caps->v1.glsl_level >= 150) {
      caps->v1.prim_mask |= (1 << PIPE_PRIM_LINES_ADJACENCY) |
                            (1 << PIPE_PRIM_LINE_STRIP_ADJACENCY) |
                            (1 << PIPE_PRIM_TRIANGLES_ADJACENCY) |
                            (1 << PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY);
   }
   if (caps->v1.glsl_level >= 400 || has_feature(feat_tessellation))
      caps->v1.prim_mask |= (1 << PIPE_PRIM_PATCHES);

   if (epoxy_has_gl_extension("GL_ARB_vertex_type_10f_11f_11f_rev"))
      set_format_bit(&caps->v1.vertexbuffer, VIRGL_FORMAT_R11G11B10_FLOAT);

   if (has_feature(feat_nv_conditional_render) ||
       has_feature(feat_gl_conditional_render))
      caps->v1.bset.conditional_render = 1;

   if (has_feature(feat_indep_blend))
      caps->v1.bset.indep_blend_enable = 1;

   if (has_feature(feat_draw_instance))
      caps->v1.bset.instanceid = 1;

   if (has_feature(feat_ubo)) {
      glGetIntegerv(GL_MAX_VERTEX_UNIFORM_BLOCKS, &max);
      caps->v1.max_uniform_blocks = max + 1;
   }

   if (has_feature(feat_depth_clamp))
      caps->v1.bset.depth_clip_disable = 1;

   if (gl_ver >= 32) {
      caps->v1.bset.fragment_coord_conventions = 1;
      caps->v1.bset.seamless_cube_map = 1;
   } else {
      if (epoxy_has_gl_extension("GL_ARB_fragment_coord_conventions"))
         caps->v1.bset.fragment_coord_conventions = 1;
      if (epoxy_has_gl_extension("GL_ARB_seamless_cube_map") || gles_ver >= 30)
         caps->v1.bset.seamless_cube_map = 1;
   }

   if (epoxy_has_gl_extension("GL_AMD_seamless_cube_map_per_texture")) {
      caps->v1.bset.seamless_cube_map_per_texture = 1;
   }

   if (has_feature(feat_texture_multisample))
      caps->v1.bset.texture_multisample = 1;

   if (has_feature(feat_tessellation))
      caps->v1.bset.has_tessellation_shaders = 1;

   if (has_feature(feat_sample_shading))
      caps->v1.bset.has_sample_shading = 1;

   if (has_feature(feat_indirect_draw))
      caps->v1.bset.has_indirect_draw = 1;

   if (has_feature(feat_indep_blend_func))
      caps->v1.bset.indep_blend_func = 1;

   if (has_feature(feat_cube_map_array))
      caps->v1.bset.cube_map_array = 1;

   if (has_feature(feat_texture_query_lod))
      caps->v1.bset.texture_query_lod = 1;

   if (gl_ver >= 40) {
      caps->v1.bset.has_fp64 = 1;
   } else {
       
      if (epoxy_has_gl_extension("GL_ARB_gpu_shader_fp64") &&
          epoxy_has_gl_extension("GL_ARB_gpu_shader5"))
         caps->v1.bset.has_fp64 = 1;
   }

   if (has_feature(feat_base_instance))
      caps->v1.bset.start_instance = 1;

   if (epoxy_has_gl_extension("GL_ARB_shader_stencil_export")) {
      caps->v1.bset.shader_stencil_export = 1;
   }

   if (has_feature(feat_conditional_render_inverted))
      caps->v1.bset.conditional_render_inverted = 1;

   if (gl_ver >= 45) {
      caps->v1.bset.has_cull = 1;
      caps->v1.bset.derivative_control = 1;
   } else {
     if (has_feature(feat_cull_distance))
        caps->v1.bset.has_cull = 1;
     if (epoxy_has_gl_extension("GL_ARB_derivative_control"))
	caps->v1.bset.derivative_control = 1;
   }

   if (has_feature(feat_polygon_offset_clamp))
      caps->v1.bset.polygon_offset_clamp = 1;

   if (has_feature(feat_transform_feedback_overflow_query))
     caps->v1.bset.transform_feedback_overflow_query = 1;

   if (epoxy_has_gl_extension("GL_EXT_texture_mirror_clamp") ||
       epoxy_has_gl_extension("GL_ARB_texture_mirror_clamp_to_edge") ||
       epoxy_has_gl_extension("GL_EXT_texture_mirror_clamp_to_edge")) {
      caps->v1.bset.mirror_clamp = true;
   }

   if (has_feature(feat_texture_array)) {
      glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &max);
      caps->v1.max_texture_array_layers = max;
   }

    
   if (has_feature(feat_transform_feedback)) {
      if (has_feature(feat_transform_feedback2))
         caps->v1.bset.streamout_pause_resume = 1;

      if (has_feature(feat_transform_feedback3)) {
         glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_BUFFERS, &max);
         caps->v1.max_streamout_buffers = max;
      } else if (gles_ver > 0) {
         glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &max);
          
         if (max >= 4) {
            caps->v1.max_streamout_buffers = 4;
         }
      } else
         caps->v1.max_streamout_buffers = 4;
   }

   if (has_feature(feat_dual_src_blend)) {
      glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS, &max);
      caps->v1.max_dual_source_render_targets = max;
   }

   if (has_feature(feat_arb_or_gles_ext_texture_buffer)) {
      glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &max);
      caps->v1.max_tbo_size = max;
   }

   if (has_feature(feat_texture_gather)) {
      if (gl_ver > 0) {
         glGetIntegerv(GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB, &max);
         caps->v1.max_texture_gather_components = max;
      } else {
         caps->v1.max_texture_gather_components = 4;
      }
   }

   if (has_feature(feat_viewport_array)) {
      glGetIntegerv(GL_MAX_VIEWPORTS, &max);
      caps->v1.max_viewports = max;
   } else {
      caps->v1.max_viewports = 1;
   }

    
   caps->v1.max_render_targets = vrend_state.max_draw_buffers;

   glGetIntegerv(GL_MAX_SAMPLES, &max);
   caps->v1.max_samples = max;

    
   for (i = 0; i < VIRGL_FORMAT_MAX; i++) {
      enum virgl_formats fmt = (enum virgl_formats)i;
      if (tex_conv_table[i].internalformat != 0 || fmt == VIRGL_FORMAT_YV12 ||
          fmt == VIRGL_FORMAT_NV12) {
         if (vrend_format_can_sample(fmt)) {
            set_format_bit(&caps->v1.sampler, fmt);
            if (vrend_format_can_render(fmt))
               set_format_bit(&caps->v1.render, fmt);
         }
      }
   }

    
   if (has_feature(feat_nv_prim_restart) ||
       has_feature(feat_gl_prim_restart)) {
      caps->v1.bset.primitive_restart = 1;
   }
}