Upgrade virglrenderer to 0.10.4 am: 056b3873e4 am: 9b631e492a

Original change: https://android-review.googlesource.com/c/platform/external/virglrenderer/+/2393713

Change-Id: Ic7131f1a0fc632b38d8d6df121191f586f4e1e5d
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 9a27a93..3955e38 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,6 +1,6 @@
 variables:
   FDO_UPSTREAM_REPO: "virgl/virglrenderer"
-  MESA_TEMPLATES_COMMIT: &ci-templates-commit 290b79e0e78eab67a83766f4e9691be554fc4afd
+  MESA_TEMPLATES_COMMIT: &ci-templates-commit d5aa3941aa03c2f716595116354fb81eb8012acb
   MESA_BASE_TAG: ${DEBIAN_BASE_TAG}
   #
   # IMPORTANT!
@@ -11,12 +11,17 @@
   #
   # Pick a pipeline on https://gitlab.freedesktop.org/mesa/mesa/-/pipelines/
   #
-  MESA_PIPELINE_ID: 634658
+  MESA_PIPELINE_ID: 743439
   MESA_PROJECT_PATH: mesa/mesa
-  MINIO_HOST: minio-packet.freedesktop.org
-  # Per-pipeline artifact storage on MinIO
-  PIPELINE_ARTIFACTS_BASE: ${MINIO_HOST}/artifacts/${CI_PROJECT_PATH}/${CI_PIPELINE_ID}
+  STORAGE_HOST: s3.freedesktop.org
   CI_REGISTRY_IMAGE: "registry.freedesktop.org/${MESA_PROJECT_PATH}"
+  # per-pipeline artifact storage on MinIO
+  PIPELINE_ARTIFACTS_BASE: ${STORAGE_HOST}/artifacts/${CI_PROJECT_PATH}/${CI_PIPELINE_ID}
+  # per-job artifact storage on MinIO
+  JOB_ARTIFACTS_BASE: ${PIPELINE_ARTIFACTS_BASE}/${CI_JOB_ID}
+  # reference images stored for traces
+  PIGLIT_REPLAY_REFERENCE_IMAGES_BASE: "${STORAGE_HOST}/mesa-tracie-results/${FDO_UPSTREAM_REPO}"
+
 
 include:
   - project: 'freedesktop/ci-templates'
@@ -32,7 +37,7 @@
     # IMPORTANT: Use a recent Mesa Git revision
     # The commit ref must be in sync with the pipeline picked above
     # It can be found on the pipeline page below the commit message
-    ref: 27c57b86500ce48154533d78b74350c31152b2f3
+    ref: 1ec172646cd7f5b8c04173a6b45a871aa48aa12e
     file:
       - '/.gitlab-ci/image-tags.yml'
 
@@ -134,7 +139,6 @@
   extends: .make_check_base
   variables:
     TEST_SUITE: make-check-venus
-    EXTRA_OPTION: "-D venus-experimental=true"
 
 #
 # Piglit & dEQP test jobs
@@ -145,9 +149,12 @@
   extends:
     - .set-image-base-tag
   before_script:
+    - echo -n "${CI_JOB_JWT}" > "${CI_JOB_JWT_FILE}"
+    - unset CI_JOB_JWT
     - export CI_JOB_NAME_SANITIZED="$(echo $CI_JOB_NAME | tr ' /' '--')"
   variables:
-    MESA_IMAGE_PATH: ${DEBIAN_X86_TEST_IMAGE_PATH}
+    CI_JOB_JWT_FILE: /minio_jwt
+    MESA_IMAGE_PATH: ${DEBIAN_X86_TEST_IMAGE_GL_PATH}
     MESA_IMAGE_TAG: ${DEBIAN_X86_TEST_GL_TAG}
   script:
     - export DEQP_RESULTS_DIR="results/${CI_JOB_NAME_SANITIZED}"
@@ -168,6 +175,37 @@
       when: never
     - when: on_success
 
+.use-vk-test-image:
+  stage: test
+  extends:
+    - .set-image-base-tag
+  before_script:
+    - echo -n "${CI_JOB_JWT}" > "${CI_JOB_JWT_FILE}"
+    - unset CI_JOB_JWT
+    - export CI_JOB_NAME_SANITIZED="$(echo $CI_JOB_NAME | tr ' /' '--')"
+  variables:
+    CI_JOB_JWT_FILE: /minio_jwt
+    MESA_IMAGE_PATH: ${DEBIAN_X86_TEST_IMAGE_VK_PATH}
+    MESA_IMAGE_TAG: ${DEBIAN_X86_TEST_VK_TAG}
+  script:
+    - export DEQP_RESULTS_DIR="results/${CI_JOB_NAME_SANITIZED}"
+    - export PIGLIT_RESULTS_DIR="results/${CI_JOB_NAME_SANITIZED}"
+    - .gitlab-ci/container/debian/x86_test.sh
+  artifacts:
+    name: "venus-result"
+    when: always
+    paths:
+      - results/
+    reports:
+      junit: results/junit.xml
+  needs:
+    - job: debian/x86_build
+      artifacts: true
+  rules:
+    - if: *is-post-merge
+      when: never
+    - when: on_success
+
 .gl-host-test:
   extends:
     - .use-gl-test-image
@@ -276,3 +314,36 @@
     VIRGL_HOST_API: GLES
     GPU_VERSION: virgl-gles
     CROSVM_GPU_ARGS: *deqp-gles-crosvm-gpu-args
+
+virgl-traces:
+  extends:
+    - .piglit-virt
+  variables:
+    GPU_VERSION: virgl-gl
+    CROSVM_GPU_ARGS: *deqp-gl-crosvm-gpu-args
+    EGL_PLATFORM: "surfaceless"
+    PIGLIT_REPLAY_DESCRIPTION_FILE: "${CI_PROJECT_DIR}/install/traces-virgl.yml"
+    PIGLIT_REPLAY_DEVICE_NAME: "gl-virgl"
+    PIGLIT_RESULTS: "virgl-replay"
+
+.venus-lavapipe-test:
+  extends:
+    - .use-vk-test-image
+  variables:
+    VK_DRIVER: virtio
+    CROSVM_GALLIUM_DRIVER: "llvmpipe"
+    CROSVM_VK_DRIVER: "lvp"
+
+venus-lavapipe:
+  extends:
+    - .venus-lavapipe-test
+  variables:
+    DEQP_FRACTION: 15
+    DEQP_SUITE: venus
+    GPU_VERSION: venus
+    LP_NUM_THREADS: 1 # There will be FDO_CI_CONCURRENT Crosvm processes, so each should use a single thread
+    FDO_CI_CONCURRENT: 32 # Seems to be the fastest value, more gets actually slower
+    CROSVM_MEMORY: 3072
+    CROSVM_GPU_ARGS: "vulkan=true,gles=false,backend=virglrenderer,egl=true,surfaceless=true"
+  tags:
+    - mesa-swrast
diff --git a/.gitlab-ci/container/debian/x86_test.sh b/.gitlab-ci/container/debian/x86_test.sh
index 8450df1..01488b8 100755
--- a/.gitlab-ci/container/debian/x86_test.sh
+++ b/.gitlab-ci/container/debian/x86_test.sh
@@ -7,9 +7,9 @@
 cd ${MESA_CI_PROJECT_DIR}
 
 # Deploy Mesa CI artifacts
-MESA_CI_ARTIFACTS_URL="https://${MINIO_HOST}/artifacts/${MESA_PROJECT_PATH}/${MESA_PIPELINE_ID}/mesa-amd64.tar.gz"
+MESA_CI_ARTIFACTS_URL="https://${STORAGE_HOST}/artifacts/${MESA_PROJECT_PATH}/${MESA_PIPELINE_ID}/mesa-amd64.tar.zst"
 if wget -q --method=HEAD ${MESA_CI_ARTIFACTS_URL}; then
-    wget -S --progress=dot:giga -O- ${MESA_CI_ARTIFACTS_URL} | tar -xvz
+    wget -S --progress=dot:giga -O- ${MESA_CI_ARTIFACTS_URL} | tar -xv --zstd
 else
     echo -e "\e[31mThe Mesa artifacts has expired, please update to newer Mesa pipeline!\e[0m"
     apt-get update && apt-get -y install jq
@@ -38,7 +38,7 @@
 cp -a ${CI_PROJECT_DIR}/install/bin/virgl_test_server /usr/local/bin/
 cp -a ${CI_PROJECT_DIR}/install/lib/libvirglrenderer.so* /usr/local/lib/
 
-if [ "${GALLIUM_DRIVER}" = "virgl" ]; then
+if [ "${VK_DRIVER}" = "virtio" ] || [ "${GALLIUM_DRIVER}" = "virgl" ]; then
     #
     # Run the tests on virtual platform (virgl/crosvm)
     #
@@ -58,8 +58,13 @@
     set +e
 
     if [ -z "${DEQP_SUITE}" ]; then
-        FDO_CI_CONCURRENT=${FORCE_FDO_CI_CONCURRENT:-FDO_CI_CONCURRENT} \
-            install/crosvm-runner.sh install/piglit/piglit-runner.sh
+        if [ -z "${PIGLIT_REPLAY_DESCRIPTION_FILE}" ]; then
+            FDO_CI_CONCURRENT=${FORCE_FDO_CI_CONCURRENT:-FDO_CI_CONCURRENT} \
+                install/crosvm-runner.sh install/piglit/piglit-runner.sh
+        else
+            FDO_CI_CONCURRENT=${FORCE_FDO_CI_CONCURRENT:-FDO_CI_CONCURRENT} \
+                install/crosvm-runner.sh install/piglit/piglit-traces.sh
+        fi
     else
         install/deqp-runner.sh
     fi
diff --git a/.gitlab-ci/expectations/host/virgl-gl-fails.txt b/.gitlab-ci/expectations/host/virgl-gl-fails.txt
index dd3f30d..3cca206 100644
--- a/.gitlab-ci/expectations/host/virgl-gl-fails.txt
+++ b/.gitlab-ci/expectations/host/virgl-gl-fails.txt
@@ -27,8 +27,6 @@
 dEQP-GLES3.functional.clipping.point.wide_point_clip,Fail
 dEQP-GLES3.functional.clipping.point.wide_point_clip_viewport_center,Fail
 dEQP-GLES3.functional.clipping.point.wide_point_clip_viewport_corner,Fail
-dEQP-GLES3.functional.draw_buffers_indexed.random.max_implementation_draw_buffers.8,Fail
-dEQP-GLES3.functional.draw_buffers_indexed.random.max_required_draw_buffers.9,Fail
 dEQP-GLES3.functional.fbo.blit.rect.nearest_consistency_mag,Fail
 dEQP-GLES3.functional.fbo.blit.rect.nearest_consistency_mag_reverse_dst_x,Fail
 dEQP-GLES3.functional.fbo.blit.rect.nearest_consistency_mag_reverse_src_dst_x,Fail
@@ -107,95 +105,7 @@
 spec@arb_blend_func_extended@arb_blend_func_extended-fbo-extended-blend-pattern_gles2,Fail
 spec@arb_clear_texture@arb_clear_texture-depth,Fail
 spec@arb_copy_image@arb_copy_image-formats,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_RED_RGTC1/Destination: GL_COMPRESSED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_RGBA_BPTC_UNORM/Destination: GL_COMPRESSED_RGBA_BPTC_UNORM,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT/Destination: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_RGBA_S3TC_DXT3_EXT/Destination: GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_RGBA_S3TC_DXT5_EXT/Destination: GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT/Destination: GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT/Destination: GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_RGB_S3TC_DXT1_EXT/Destination: GL_COMPRESSED_RGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_RG_RGTC2/Destination: GL_COMPRESSED_RG_RGTC2,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_SIGNED_RED_RGTC1/Destination: GL_COMPRESSED_SIGNED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_SIGNED_RG_RGTC2/Destination: GL_COMPRESSED_SIGNED_RG_RGTC2,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM/Destination: GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT/Destination: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,Fail
 spec@arb_copy_image@arb_copy_image-formats@Source: GL_DEPTH_COMPONENT24/Destination: GL_DEPTH_COMPONENT24,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32F/Destination: GL_COMPRESSED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32F/Destination: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32F/Destination: GL_COMPRESSED_RGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32F/Destination: GL_COMPRESSED_SIGNED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32F/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32F/Destination: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32I/Destination: GL_COMPRESSED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32I/Destination: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32I/Destination: GL_COMPRESSED_RGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32I/Destination: GL_COMPRESSED_SIGNED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32I/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32I/Destination: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32UI/Destination: GL_COMPRESSED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32UI/Destination: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32UI/Destination: GL_COMPRESSED_RGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32UI/Destination: GL_COMPRESSED_SIGNED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32UI/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32UI/Destination: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16/Destination: GL_COMPRESSED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16/Destination: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16/Destination: GL_COMPRESSED_RGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16/Destination: GL_COMPRESSED_SIGNED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16/Destination: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16I/Destination: GL_COMPRESSED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16I/Destination: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16I/Destination: GL_COMPRESSED_RGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16I/Destination: GL_COMPRESSED_SIGNED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16I/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16I/Destination: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16_SNORM/Destination: GL_COMPRESSED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16_SNORM/Destination: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16_SNORM/Destination: GL_COMPRESSED_RGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16_SNORM/Destination: GL_COMPRESSED_SIGNED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16_SNORM/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16_SNORM/Destination: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16UI/Destination: GL_COMPRESSED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16UI/Destination: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16UI/Destination: GL_COMPRESSED_RGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16UI/Destination: GL_COMPRESSED_SIGNED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16UI/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16UI/Destination: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32F/Destination: GL_COMPRESSED_RGBA_BPTC_UNORM,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32F/Destination: GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32F/Destination: GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32F/Destination: GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32F/Destination: GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32F/Destination: GL_COMPRESSED_RG_RGTC2,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32F/Destination: GL_COMPRESSED_SIGNED_RG_RGTC2,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32F/Destination: GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32F/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32F/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32I/Destination: GL_COMPRESSED_RGBA_BPTC_UNORM,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32I/Destination: GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32I/Destination: GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32I/Destination: GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32I/Destination: GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32I/Destination: GL_COMPRESSED_RG_RGTC2,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32I/Destination: GL_COMPRESSED_SIGNED_RG_RGTC2,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32I/Destination: GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32I/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32I/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32UI/Destination: GL_COMPRESSED_RGBA_BPTC_UNORM,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32UI/Destination: GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32UI/Destination: GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32UI/Destination: GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32UI/Destination: GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32UI/Destination: GL_COMPRESSED_RG_RGTC2,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32UI/Destination: GL_COMPRESSED_SIGNED_RG_RGTC2,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32UI/Destination: GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32UI/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32UI/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,Fail
 spec@arb_depth_buffer_float@fbo-depthstencil-gl_depth32f_stencil8-copypixels,Fail
 spec@arb_depth_buffer_float@fbo-depthstencil-gl_depth32f_stencil8-drawpixels-24_8,Fail
 spec@arb_depth_buffer_float@fbo-depthstencil-gl_depth32f_stencil8-drawpixels-32f_24_8_rev,Fail
@@ -213,17 +123,14 @@
 spec@arb_depth_texture@texwrap formats bordercolor-swizzled@GL_DEPTH_COMPONENT16- swizzled- border color only,Fail
 spec@arb_depth_texture@texwrap formats bordercolor-swizzled@GL_DEPTH_COMPONENT24- swizzled- border color only,Fail
 spec@arb_depth_texture@texwrap formats bordercolor-swizzled@GL_DEPTH_COMPONENT32- swizzled- border color only,Fail
+spec@arb_enhanced_layouts@matching_fp64_types_1,Crash
+spec@arb_enhanced_layouts@matching_fp64_types_2,Crash
+spec@arb_enhanced_layouts@matching_fp64_types_3,Crash
 spec@arb_es2_compatibility@texwrap formats bordercolor,Fail
 spec@arb_es2_compatibility@texwrap formats bordercolor@GL_RGB565- border color only,Fail
 spec@arb_es2_compatibility@texwrap formats bordercolor-swizzled,Fail
 spec@arb_es2_compatibility@texwrap formats bordercolor-swizzled@GL_RGB565- swizzled- border color only,Fail
-spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@Basic,Fail
-spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic,Fail
-spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@glScissor,Fail
-spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@MS4,Fail
-spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@Per-sample,Fail
 spec@arb_get_texture_sub_image@arb_get_texture_sub_image-getcompressed,Crash
-spec@arb_get_texture_sub_image@arb_get_texture_sub_image-get,Fail
 spec@arb_occlusion_query@occlusion_query_conform,Fail
 spec@arb_occlusion_query@occlusion_query_conform@GetObjivAval_multi1,Fail
 spec@arb_occlusion_query@occlusion_query_meta_no_fragments,Fail
@@ -233,8 +140,6 @@
 spec@arb_program_interface_query@arb_program_interface_query-getprogramresourceindex@'vs_input2[1][0]' on GL_PROGRAM_INPUT,Fail
 spec@arb_sample_shading@builtin-gl-sample-position 2,Fail
 spec@arb_shader_atomic_counter_ops@execution@add,Fail
-spec@arb_shader_atomic_counters@fragment-discard,Fail
-spec@arb_shader_atomic_counters@function-argument,Fail
 spec@arb_shader_image_load_store@early-z,Fail
 spec@arb_shader_image_load_store@early-z@occlusion query test/early-z pass,Fail
 spec@arb_shader_image_load_store@layer,Fail
@@ -253,16 +158,8 @@
 spec@arb_shader_image_load_store@semantics@imageLoad/Vertex shader/rgba32f/image2DMS test,Fail
 spec@arb_shader_storage_buffer_object@execution@ssbo-atomiccompswap-int,Fail
 spec@arb_shader_storage_buffer_object@layout-std140-write-shader,Fail
-spec@arb_shader_storage_buffer_object@layout-std430-write-shader,Fail
 spec@arb_shader_storage_buffer_object@maxblocks,Fail
-spec@arb_shader_texture_lod@execution@arb_shader_texture_lod-texgradcube,Fail
 spec@arb_shader_texture_lod@execution@arb_shader_texture_lod-texgrad,Fail
-spec@arb_shader_texture_lod@execution@glsl-fs-shadow2dgradarb-07,Fail
-spec@arb_shader_texture_lod@execution@glsl-fs-shadow2dgradarb-08,Fail
-spec@arb_shader_texture_lod@execution@glsl-fs-shadow2dgradarb-cumulative,Fail
-spec@arb_texture_compression_bptc@compressedteximage gl_compressed_rgb_bptc_signed_float,Fail
-spec@arb_texture_compression_bptc@compressedteximage gl_compressed_rgb_bptc_unsigned_float,Fail
-spec@arb_texture_compression_bptc@compressedteximage gl_compressed_srgb_alpha_bptc_unorm,Fail
 spec@arb_texture_compression_bptc@texwrap formats bordercolor,Fail
 spec@arb_texture_compression_bptc@texwrap formats bordercolor@GL_COMPRESSED_RGBA_BPTC_UNORM- border color only,Fail
 spec@arb_texture_compression_bptc@texwrap formats bordercolor@GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT- border color only,Fail
@@ -291,8 +188,6 @@
 spec@arb_texture_float@fbo-blending-formats,Fail
 spec@arb_texture_float@fbo-blending-formats@GL_ALPHA16F_ARB,Fail
 spec@arb_texture_float@fbo-blending-formats@GL_ALPHA32F_ARB,Fail
-spec@arb_texture_float@fbo-blending-formats@GL_INTENSITY16F_ARB,Fail
-spec@arb_texture_float@fbo-blending-formats@GL_INTENSITY32F_ARB,Fail
 spec@arb_texture_float@fbo-blending-formats@GL_RGB32F,Fail
 spec@arb_texture_float@fbo-clear-formats,Fail
 spec@arb_texture_float@fbo-clear-formats@GL_ALPHA16F_ARB,Fail
@@ -333,8 +228,6 @@
 spec@arb_texture_rectangle@copyteximage rect,Fail
 spec@arb_texture_rectangle@copyteximage rect samples=2,Fail
 spec@arb_texture_rectangle@copyteximage rect samples=4,Fail
-spec@arb_texture_rectangle@glsl-fs-shadow2drect-07,Fail
-spec@arb_texture_rectangle@glsl-fs-shadow2drect-08,Fail
 spec@arb_texture_rectangle@texwrap rect bordercolor,Fail
 spec@arb_texture_rectangle@texwrap rect bordercolor@GL_RGBA8- border color only,Fail
 spec@arb_texture_rectangle@texwrap rect proj bordercolor,Fail
@@ -372,32 +265,6 @@
 spec@egl_ext_protected_content@conformance,Fail
 spec@egl_khr_gl_image@egl_khr_gl_renderbuffer_image-clear-shared-image gl_depth_component24,Fail
 spec@egl_khr_surfaceless_context@viewport,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage2DEXT + display list GL_COMPILE_AND_EXECUTE,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage2DEXT + display list GL_COMPILE,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage2DEXT,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage3DEXT + display list GL_COMPILE_AND_EXECUTE,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage3DEXT + display list GL_COMPILE,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage3DEXT,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage2DEXT + display list GL_COMPILE_AND_EXECUTE,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage2DEXT + display list GL_COMPILE,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage2DEXT,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage3DEXT + display list GL_COMPILE_AND_EXECUTE,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage3DEXT + display list GL_COMPILE,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage3DEXT,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage2DEXT + display list GL_COMPILE_AND_EXECUTE,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage2DEXT + display list GL_COMPILE,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage2DEXT,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage3DEXT + display list GL_COMPILE_AND_EXECUTE,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage3DEXT + display list GL_COMPILE,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage3DEXT,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage2DEXT + display list GL_COMPILE_AND_EXECUTE,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage2DEXT + display list GL_COMPILE,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage2DEXT,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage3DEXT + display list GL_COMPILE_AND_EXECUTE,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage3DEXT + display list GL_COMPILE,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage3DEXT,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float,Fail
 spec@ext_framebuffer_multisample@alpha-blending-after-rendering 2,Fail
 spec@ext_framebuffer_multisample@blit-mismatched-formats,Fail
 spec@ext_framebuffer_multisample@interpolation 2 centroid-edges,Fail
@@ -409,12 +276,6 @@
 spec@ext_framebuffer_multisample@sample-coverage 2 inverted,Fail
 spec@ext_framebuffer_multisample@sample-coverage 2 non-inverted,Fail
 spec@ext_framebuffer_object@fbo-blending-format-quirks,Fail
-spec@ext_framebuffer_object@fbo-blending-formats,Fail
-spec@ext_framebuffer_object@fbo-blending-formats@GL_INTENSITY12,Fail
-spec@ext_framebuffer_object@fbo-blending-formats@GL_INTENSITY16,Fail
-spec@ext_framebuffer_object@fbo-blending-formats@GL_INTENSITY4,Fail
-spec@ext_framebuffer_object@fbo-blending-formats@GL_INTENSITY8,Fail
-spec@ext_framebuffer_object@fbo-blending-formats@GL_INTENSITY,Fail
 spec@ext_framebuffer_object@fbo-readpixels-depth-formats,Fail
 spec@ext_framebuffer_object@fbo-readpixels-depth-formats@GL_DEPTH_COMPONENT24/GL_FLOAT,Fail
 spec@ext_framebuffer_object@fbo-readpixels-depth-formats@GL_DEPTH_COMPONENT/GL_FLOAT,Fail
@@ -434,10 +295,6 @@
 spec@ext_packed_float@texwrap formats bordercolor-swizzled@GL_R11F_G11F_B10F- swizzled- border color only,Fail
 spec@ext_texture_array@fbo-generatemipmap-array s3tc_dxt1,Fail
 spec@ext_texture_array@gen-mipmap,Fail
-spec@ext_texture_array@glsl-fs-shadow1darray-07,Fail
-spec@ext_texture_array@glsl-fs-shadow1darray-08,Fail
-spec@ext_texture_array@glsl-fs-shadow2darray-07,Fail
-spec@ext_texture_array@glsl-fs-shadow2darray-08,Fail
 spec@ext_texture_compression_rgtc@texwrap formats bordercolor,Fail
 spec@ext_texture_compression_rgtc@texwrap formats bordercolor@GL_COMPRESSED_RED_RGTC1- border color only,Fail
 spec@ext_texture_compression_rgtc@texwrap formats bordercolor@GL_COMPRESSED_RG_RGTC2- border color only,Fail
@@ -480,10 +337,6 @@
 spec@ext_texture_shared_exponent@texwrap formats bordercolor@GL_RGB9_E5- border color only,Fail
 spec@ext_texture_shared_exponent@texwrap formats bordercolor-swizzled,Fail
 spec@ext_texture_shared_exponent@texwrap formats bordercolor-swizzled@GL_RGB9_E5- swizzled- border color only,Fail
-spec@ext_texture_snorm@fbo-blending-formats,Fail
-spec@ext_texture_snorm@fbo-blending-formats@GL_INTENSITY16_SNORM,Fail
-spec@ext_texture_snorm@fbo-blending-formats@GL_INTENSITY8_SNORM,Fail
-spec@ext_texture_snorm@fbo-blending-formats@GL_INTENSITY_SNORM,Fail
 spec@ext_texture_snorm@texwrap formats bordercolor,Fail
 spec@ext_texture_snorm@texwrap formats bordercolor@GL_ALPHA16_SNORM- border color only,Fail
 spec@ext_texture_snorm@texwrap formats bordercolor@GL_ALPHA8_SNORM- border color only,Fail
@@ -546,80 +399,34 @@
 spec@ext_texture_srgb@texwrap formats-s3tc bordercolor-swizzled@GL_COMPRESSED_SRGB_ALPHA- swizzled- border color only,Fail
 spec@ext_texture_srgb@texwrap formats-s3tc bordercolor-swizzled@GL_COMPRESSED_SRGB_S3TC_DXT1_EXT- swizzled- border color only,Fail
 spec@ext_texture_srgb@texwrap formats-s3tc bordercolor-swizzled@GL_COMPRESSED_SRGB- swizzled- border color only,Fail
-spec@glsl-1.10@execution@samplers@glsl-fs-shadow1d-07,Fail
-spec@glsl-1.10@execution@samplers@glsl-fs-shadow1d-08,Fail
-spec@glsl-1.10@execution@samplers@glsl-fs-shadow2d-07,Fail
-spec@glsl-1.10@execution@samplers@glsl-fs-shadow2d-08,Fail
+spec@ext_transform_feedback@builtin-varyings gl_culldistance,Fail
 spec@glsl-1.10@execution@samplers@glsl-fs-shadow2d-clamp-z,Fail
 spec@glsl-1.50@execution@primitive-id-no-gs-quads,Fail
 spec@glsl-1.50@execution@primitive-id-no-gs-quad-strip,Fail
 spec@glsl-1.50@execution@variable-indexing@gs-input-array-float-index-rd,Fail
-spec@khr_texture_compression_astc@array-gl@12x12 Block Dim,Fail
-spec@khr_texture_compression_astc@array-gl@5x5 Block Dim,Fail
-spec@khr_texture_compression_astc@array-gles@12x12 Block Dim,Fail
-spec@khr_texture_compression_astc@array-gles@5x5 Block Dim,Fail
-spec@khr_texture_compression_astc@array-gles,Fail
-spec@khr_texture_compression_astc@array-gl,Fail
-spec@khr_texture_compression_astc@miptree-gles ldr,Fail
-spec@khr_texture_compression_astc@miptree-gles ldr@LDR Profile,Fail
-spec@khr_texture_compression_astc@miptree-gles srgb,Fail
 spec@khr_texture_compression_astc@miptree-gles srgb-fp,Fail
 spec@khr_texture_compression_astc@miptree-gles srgb-fp@sRGB decode full precision,Fail
-spec@khr_texture_compression_astc@miptree-gles srgb-sd,Fail
-spec@khr_texture_compression_astc@miptree-gles srgb-sd@sRGB skip decode,Fail
-spec@khr_texture_compression_astc@miptree-gles srgb@sRGB decode,Fail
-spec@khr_texture_compression_astc@miptree-gl ldr,Fail
-spec@khr_texture_compression_astc@miptree-gl ldr@LDR Profile,Fail
-spec@khr_texture_compression_astc@miptree-gl srgb,Fail
 spec@khr_texture_compression_astc@miptree-gl srgb-fp,Fail
 spec@khr_texture_compression_astc@miptree-gl srgb-fp@sRGB decode full precision,Fail
-spec@khr_texture_compression_astc@miptree-gl srgb-sd,Fail
-spec@khr_texture_compression_astc@miptree-gl srgb-sd@sRGB skip decode,Fail
-spec@khr_texture_compression_astc@miptree-gl srgb@sRGB decode,Fail
-spec@khr_texture_compression_astc@sliced-3d-miptree-gles ldr,Fail
-spec@khr_texture_compression_astc@sliced-3d-miptree-gles ldr@LDR Profile,Fail
-spec@khr_texture_compression_astc@sliced-3d-miptree-gles srgb,Fail
 spec@khr_texture_compression_astc@sliced-3d-miptree-gles srgb-fp,Fail
 spec@khr_texture_compression_astc@sliced-3d-miptree-gles srgb-fp@sRGB decode full precision,Fail
-spec@khr_texture_compression_astc@sliced-3d-miptree-gles srgb@sRGB decode,Fail
-spec@khr_texture_compression_astc@sliced-3d-miptree-gl ldr,Fail
-spec@khr_texture_compression_astc@sliced-3d-miptree-gl ldr@LDR Profile,Fail
-spec@khr_texture_compression_astc@sliced-3d-miptree-gl srgb,Fail
 spec@khr_texture_compression_astc@sliced-3d-miptree-gl srgb-fp,Fail
 spec@khr_texture_compression_astc@sliced-3d-miptree-gl srgb-fp@sRGB decode full precision,Fail
-spec@khr_texture_compression_astc@sliced-3d-miptree-gl srgb@sRGB decode,Fail
 spec@nv_copy_depth_to_color@nv_copy_depth_to_color 0 0x223344ff,Fail
 spec@nv_copy_depth_to_color@nv_copy_depth_to_color 0 0x76356278,Fail
 spec@nv_copy_depth_to_color@nv_copy_depth_to_color 1 0x223344ff,Fail
 spec@nv_copy_depth_to_color@nv_copy_depth_to_color 1 0x76356278,Fail
 spec@nv_copy_depth_to_color@nv_copy_depth_to_color,Fail
 spec@nv_copy_image@nv_copy_image-formats,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_RED_RGTC1/Destination: GL_COMPRESSED_RED_RGTC1,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_RGBA_BPTC_UNORM/Destination: GL_COMPRESSED_RGBA_BPTC_UNORM,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT/Destination: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_RGBA_S3TC_DXT3_EXT/Destination: GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_RGBA_S3TC_DXT5_EXT/Destination: GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT/Destination: GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT/Destination: GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_RGB_S3TC_DXT1_EXT/Destination: GL_COMPRESSED_RGB_S3TC_DXT1_EXT,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_RG_RGTC2/Destination: GL_COMPRESSED_RG_RGTC2,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_SIGNED_RED_RGTC1/Destination: GL_COMPRESSED_SIGNED_RED_RGTC1,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_SIGNED_RG_RGTC2/Destination: GL_COMPRESSED_SIGNED_RG_RGTC2,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM/Destination: GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT/Destination: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,Fail
 spec@nv_copy_image@nv_copy_image-formats@Source: GL_DEPTH_COMPONENT24/Destination: GL_DEPTH_COMPONENT24,Fail
 spec@nv_read_depth@read_depth_gles3,Fail
 spec@!opengl 1.0@depth-clear-precision-check@depth32,Fail
 spec@!opengl 1.0@depth-clear-precision-check,Fail
-spec@!opengl 1.0@gl-1.0-dlist-bitmap,Fail
 spec@!opengl 1.0@gl-1.0-drawbuffer-modes,Fail
 spec@!opengl 1.0@gl-1.0-edgeflag,Fail
 spec@!opengl 1.0@gl-1.0-edgeflag-quads,Fail
 spec@!opengl 1.0@gl-1.0-swapbuffers-behavior,Fail
-spec@!opengl 1.0@rasterpos,Crash
+spec@!opengl 1.0@rasterpos,Fail
 spec@!opengl 1.0@rasterpos@glsl_vs_gs_linked,Fail
 spec@!opengl 1.0@rasterpos@glsl_vs_tes_linked,Fail
 spec@!opengl 1.1@depthstencil-default_fb-copypixels,Fail
diff --git a/.gitlab-ci/expectations/host/virgl-gl-flakes.txt b/.gitlab-ci/expectations/host/virgl-gl-flakes.txt
index f07a498..5836e9f 100644
--- a/.gitlab-ci/expectations/host/virgl-gl-flakes.txt
+++ b/.gitlab-ci/expectations/host/virgl-gl-flakes.txt
@@ -351,6 +351,8 @@
 shaders@glsl-uniform-interstage-limits@subdivide 5- statechanges
 spec@arb_fragment_layer_viewport@layer-gs-writes-in-range
 spec@arb_fragment_layer_viewport@viewport-gs-writes-in-range
+spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@Basic
+spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic
 spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@MS4
 spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@Per-sample
 spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@glScissor
@@ -367,6 +369,7 @@
 spec@arb_shader_storage_buffer_object@layout-std140-write-shader
 spec@arb_timer_query@query gl_timestamp
 spec@arb_timer_query@timestamp-get
+spec@ext_timer_query@time-elapsed
 spec@ext_framebuffer_blit@fbo-blit-check-limits
 spec@ext_framebuffer_blit@fbo-sys-blit
 spec@ext_framebuffer_blit@fbo-sys-sub-blit
diff --git a/.gitlab-ci/expectations/host/virgl-gl-skips.txt b/.gitlab-ci/expectations/host/virgl-gl-skips.txt
index 494b552..6c282d1 100644
--- a/.gitlab-ci/expectations/host/virgl-gl-skips.txt
+++ b/.gitlab-ci/expectations/host/virgl-gl-skips.txt
@@ -21,9 +21,6 @@
 # Fails on iris too
 spec@arb_direct_state_access@gettextureimage-formats
 
-spec@arb_texture_buffer_object@formats (fs- arb)*
-spec@arb_texture_buffer_object@formats (vs- arb)*
-
 # Skip these as they get skipped with the Intel driver + vtest
 spec@arb_shader_texture_image_samples@builtin-image*
 
diff --git a/.gitlab-ci/expectations/host/virgl-gles-fails.txt b/.gitlab-ci/expectations/host/virgl-gles-fails.txt
index f99a222..e26206f 100644
--- a/.gitlab-ci/expectations/host/virgl-gles-fails.txt
+++ b/.gitlab-ci/expectations/host/virgl-gles-fails.txt
@@ -11,8 +11,6 @@
 dEQP-GLES31.functional.shaders.sample_variables.sample_mask_in.bit_count_per_two_samples.multisample_texture_2,Fail
 dEQP-GLES3.functional.clipping.line.wide_line_clip_viewport_center,Fail
 dEQP-GLES3.functional.clipping.line.wide_line_clip_viewport_corner,Fail
-dEQP-GLES3.functional.draw_buffers_indexed.random.max_implementation_draw_buffers.8,Fail
-dEQP-GLES3.functional.draw_buffers_indexed.random.max_required_draw_buffers.9,Fail
 dEQP-GLES3.functional.fbo.blit.rect.nearest_consistency_mag,Fail
 dEQP-GLES3.functional.fbo.blit.rect.nearest_consistency_mag_reverse_dst_x,Fail
 dEQP-GLES3.functional.fbo.blit.rect.nearest_consistency_mag_reverse_src_dst_x,Fail
@@ -195,14 +193,17 @@
 spec@arb_draw_indirect@arb_draw_indirect-draw-elements-prim-restart-ugly,Fail
 spec@arb_enhanced_layouts@linker@component-layout@intrastage-vs,Fail
 spec@arb_enhanced_layouts@linker@component-layout@vs-to-fs,Fail
+spec@arb_enhanced_layouts@matching_basic_types_3_loc_1,Fail
+spec@arb_enhanced_layouts@matching_fp64_types_1,Crash
+spec@arb_enhanced_layouts@matching_fp64_types_1_loc_1,Fail
+spec@arb_enhanced_layouts@matching_fp64_types_2,Crash
+spec@arb_enhanced_layouts@matching_fp64_types_2_loc_1,Fail
+spec@arb_enhanced_layouts@matching_fp64_types_3,Crash
+spec@arb_enhanced_layouts@matching_fp64_types_3_loc_1,Fail
 spec@arb_es2_compatibility@texwrap formats bordercolor,Fail
 spec@arb_es2_compatibility@texwrap formats bordercolor@GL_RGB565- border color only,Fail
 spec@arb_es2_compatibility@texwrap formats bordercolor-swizzled,Fail
 spec@arb_es2_compatibility@texwrap formats bordercolor-swizzled@GL_RGB565- swizzled- border color only,Fail
-spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@Basic,Fail
-spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic,Fail
-spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@MS4,Fail
-spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@Per-sample,Fail
 spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-query@Basic,Fail
 spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-query@discard,Fail
 spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-query,Fail
@@ -262,137 +263,10 @@
 spec@arb_sample_shading@samplemask 4@noms partition,Fail
 spec@arb_sample_shading@samplemask 4@sample mask_in_one,Fail
 spec@arb_seamless_cube_map@arb_seamless_cubemap,Fail
-spec@arb_shader_atomic_counters@fragment-discard,Fail
 spec@arb_shader_image_load_store@early-z,ExpectedFail
 spec@arb_shader_image_load_store@early-z@occlusion query test/early-z pass,ExpectedFail
 spec@arb_shader_image_load_store@early-z@occlusion query test/late-z pass,Fail
 spec@arb_shader_image_load_store@execution@disable_early_z,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@layer,Fail
-spec@arb_shader_image_load_store@layer@image1DArray/layered binding test,Fail
-spec@arb_shader_image_load_store@layer@image1DArray/non-layered binding test,Fail
-spec@arb_shader_image_load_store@layer@image1D/layered binding test,Fail
-spec@arb_shader_image_load_store@layer@image1D/non-layered binding test,Fail
-spec@arb_shader_image_load_store@layer@image2DArray/layered binding test,Fail
-spec@arb_shader_image_load_store@layer@image2DArray/non-layered binding test,Fail
-spec@arb_shader_image_load_store@layer@image2D/layered binding test,Fail
-spec@arb_shader_image_load_store@layer@image2D/non-layered binding test,Fail
-spec@arb_shader_image_load_store@layer@image2DRect/layered binding test,Fail
-spec@arb_shader_image_load_store@layer@image2DRect/non-layered binding test,Fail
-spec@arb_shader_image_load_store@layer@image3D/layered binding test,Fail
-spec@arb_shader_image_load_store@layer@image3D/non-layered binding test,Fail
-spec@arb_shader_image_load_store@layer@imageBuffer/layered binding test,Fail
-spec@arb_shader_image_load_store@layer@imageBuffer/non-layered binding test,Fail
-spec@arb_shader_image_load_store@layer@imageCubeArray/layered binding test,Fail
-spec@arb_shader_image_load_store@layer@imageCubeArray/non-layered binding test,Fail
-spec@arb_shader_image_load_store@layer@imageCube/layered binding test,Fail
-spec@arb_shader_image_load_store@layer@imageCube/non-layered binding test,Fail
-spec@arb_shader_image_load_store@level@1DArray level binding test,Fail
-spec@arb_shader_image_load_store@level@1D level binding test,Fail
-spec@arb_shader_image_load_store@level@2DArray level binding test,Fail
-spec@arb_shader_image_load_store@level@2D level binding test,Fail
-spec@arb_shader_image_load_store@level@3D level binding test,Fail
-spec@arb_shader_image_load_store@level@CubeArray level binding test,Fail
-spec@arb_shader_image_load_store@level@Cube level binding test,Fail
-spec@arb_shader_image_load_store@level,Fail
 spec@arb_shader_image_load_store@max-images@Combined max image uniforms test,Fail
 spec@arb_shader_image_load_store@max-images,Fail
 spec@arb_shader_image_load_store@max-size,Fail
@@ -408,12 +282,8 @@
 spec@arb_shader_storage_buffer_object@execution@ssbo-atomiccompswap-int,ExpectedFail
 spec@arb_shader_storage_buffer_object@layout-std140-write-shader,Fail
 spec@arb_shader_storage_buffer_object@maxblocks,Fail
-spec@arb_shader_storage_buffer_object@minmax,Fail
 spec@arb_shader_texture_lod@execution@arb_shader_texture_lod-texgradcube,ExpectedFail
 spec@arb_shader_texture_lod@execution@arb_shader_texture_lod-texgrad,ExpectedFail
-spec@arb_shader_texture_lod@execution@glsl-fs-shadow2dgradarb-07,Fail
-spec@arb_shader_texture_lod@execution@glsl-fs-shadow2dgradarb-08,Fail
-spec@arb_shader_texture_lod@execution@glsl-fs-shadow2dgradarb-cumulative,Fail
 spec@arb_shader_texture_lod@execution@tex-miplevel-selection *gradarb 1d,Fail
 spec@arb_shader_texture_lod@execution@tex-miplevel-selection *gradarb 1dshadow,Fail
 spec@arb_shader_texture_lod@execution@tex-miplevel-selection *gradarb 2d,Fail
@@ -472,8 +342,6 @@
 spec@arb_texture_float@fbo-blending-formats,Fail
 spec@arb_texture_float@fbo-blending-formats@GL_ALPHA16F_ARB,Fail
 spec@arb_texture_float@fbo-blending-formats@GL_ALPHA32F_ARB,Fail
-spec@arb_texture_float@fbo-blending-formats@GL_INTENSITY16F_ARB,Fail
-spec@arb_texture_float@fbo-blending-formats@GL_INTENSITY32F_ARB,Fail
 spec@arb_texture_float@fbo-blending-formats@GL_RGB32F,Fail
 spec@arb_texture_float@fbo-clear-formats,Fail
 spec@arb_texture_float@fbo-clear-formats@GL_ALPHA16F_ARB,Fail
@@ -514,8 +382,6 @@
 spec@arb_texture_multisample@arb_texture_multisample-dsa-texelfetch,Fail
 spec@arb_texture_multisample@arb_texture_multisample-dsa-texelfetch@Texture type: GL_RGB9_E5,Fail
 spec@arb_texture_query_lod@execution@fs-texturequerylod-nearest-biased,Fail
-spec@arb_texture_rectangle@glsl-fs-shadow2drect-07,Fail
-spec@arb_texture_rectangle@glsl-fs-shadow2drect-08,Fail
 spec@arb_texture_rectangle@texwrap rect bordercolor,Fail
 spec@arb_texture_rectangle@texwrap rect bordercolor@GL_RGBA8- border color only,Fail
 spec@arb_texture_rectangle@texwrap rect proj bordercolor,Fail
@@ -638,11 +504,6 @@
 spec@ext_framebuffer_object@fbo-blending-formats,Fail
 spec@ext_framebuffer_object@fbo-blending-formats@GL_ALPHA12,Fail
 spec@ext_framebuffer_object@fbo-blending-formats@GL_ALPHA16,Fail
-spec@ext_framebuffer_object@fbo-blending-formats@GL_INTENSITY12,Fail
-spec@ext_framebuffer_object@fbo-blending-formats@GL_INTENSITY16,Fail
-spec@ext_framebuffer_object@fbo-blending-formats@GL_INTENSITY4,Fail
-spec@ext_framebuffer_object@fbo-blending-formats@GL_INTENSITY8,Fail
-spec@ext_framebuffer_object@fbo-blending-formats@GL_INTENSITY,Fail
 spec@ext_framebuffer_object@fbo-blending-snorm,Fail
 spec@ext_framebuffer_object@fbo-clear-formats,Fail
 spec@ext_framebuffer_object@fbo-clear-formats@GL_ALPHA12,Fail
@@ -678,10 +539,6 @@
 spec@ext_texture_array@fbo-generatemipmap-array rgb9_e5,Fail
 spec@ext_texture_array@fbo-generatemipmap-array s3tc_dxt1,Fail
 spec@ext_texture_array@gen-mipmap,Fail
-spec@ext_texture_array@glsl-fs-shadow1darray-07,Fail
-spec@ext_texture_array@glsl-fs-shadow1darray-08,Fail
-spec@ext_texture_array@glsl-fs-shadow2darray-07,Fail
-spec@ext_texture_array@glsl-fs-shadow2darray-08,Fail
 spec@ext_texture_compression_rgtc@fbo-generatemipmap-formats-signed,Fail
 spec@ext_texture_compression_rgtc@fbo-generatemipmap-formats-signed@GL_COMPRESSED_SIGNED_RED_RGTC1,Fail
 spec@ext_texture_compression_rgtc@fbo-generatemipmap-formats-signed@GL_COMPRESSED_SIGNED_RED_RGTC1 NPOT,Fail
@@ -728,10 +585,6 @@
 spec@ext_texture_shared_exponent@texwrap formats bordercolor@GL_RGB9_E5- border color only,Fail
 spec@ext_texture_shared_exponent@texwrap formats bordercolor-swizzled,Fail
 spec@ext_texture_shared_exponent@texwrap formats bordercolor-swizzled@GL_RGB9_E5- swizzled- border color only,Fail
-spec@ext_texture_snorm@fbo-blending-formats,Fail
-spec@ext_texture_snorm@fbo-blending-formats@GL_INTENSITY16_SNORM,Fail
-spec@ext_texture_snorm@fbo-blending-formats@GL_INTENSITY8_SNORM,Fail
-spec@ext_texture_snorm@fbo-blending-formats@GL_INTENSITY_SNORM,Fail
 spec@ext_texture_snorm@multisample-formats 2 gl_ext_texture_snorm,Fail
 spec@ext_texture_snorm@multisample-formats 4 gl_ext_texture_snorm,Fail
 spec@ext_texture_snorm@texwrap formats bordercolor,Fail
@@ -796,12 +649,9 @@
 spec@ext_texture_srgb@texwrap formats-s3tc bordercolor-swizzled@GL_COMPRESSED_SRGB_ALPHA- swizzled- border color only,Fail
 spec@ext_texture_srgb@texwrap formats-s3tc bordercolor-swizzled@GL_COMPRESSED_SRGB_S3TC_DXT1_EXT- swizzled- border color only,Fail
 spec@ext_texture_srgb@texwrap formats-s3tc bordercolor-swizzled@GL_COMPRESSED_SRGB- swizzled- border color only,Fail
+spec@ext_transform_feedback@builtin-varyings gl_culldistance,Fail
 spec@ext_transform_feedback@immediate-reuse-index-buffer,Fail
 spec@ext_transform_feedback@immediate-reuse-uniform-buffer,Fail
-spec@glsl-1.10@execution@samplers@glsl-fs-shadow1d-07,Fail
-spec@glsl-1.10@execution@samplers@glsl-fs-shadow1d-08,Fail
-spec@glsl-1.10@execution@samplers@glsl-fs-shadow2d-07,Fail
-spec@glsl-1.10@execution@samplers@glsl-fs-shadow2d-08,Fail
 spec@glsl-1.10@execution@samplers@glsl-fs-shadow2d-clamp-z,Fail
 spec@glsl-1.20@execution@tex-miplevel-selection gl2:texture() 1d,Fail
 spec@glsl-1.20@execution@tex-miplevel-selection gl2:texture() 1dshadow,Fail
@@ -817,47 +667,6 @@
 spec@glsl-1.20@execution@tex-miplevel-selection gl2:textureproj 2dshadow,Fail
 spec@glsl-1.20@execution@tex-miplevel-selection gl2:textureproj 3d,Fail
 spec@glsl-1.30@execution@fs-texturelod-miplevels-biased,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-mixed,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backcolor-flat-distance,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backcolor-flat-fixed,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backcolor-flat-none,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backcolor-flat-vertex,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backcolor-smooth-distance,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backcolor-smooth-fixed,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backcolor-smooth-none,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backcolor-smooth-vertex,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backsecondarycolor-flat-distance,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backsecondarycolor-flat-fixed,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backsecondarycolor-flat-none,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backsecondarycolor-flat-vertex,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backsecondarycolor-smooth-distance,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backsecondarycolor-smooth-fixed,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backsecondarycolor-smooth-none,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backsecondarycolor-smooth-vertex,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontcolor-flat-distance,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontcolor-flat-fixed,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontcolor-flat-none,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontcolor-flat-vertex,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontcolor-smooth-distance,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontcolor-smooth-fixed,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontcolor-smooth-none,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontcolor-smooth-vertex,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontsecondarycolor-flat-distance,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontsecondarycolor-flat-fixed,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontsecondarycolor-flat-none,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontsecondarycolor-flat-vertex,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontsecondarycolor-smooth-distance,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontsecondarycolor-smooth-fixed,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontsecondarycolor-smooth-none,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontsecondarycolor-smooth-vertex,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-other-flat-distance,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-other-flat-fixed,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-other-flat-none,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-other-flat-vertex,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-other-smooth-distance,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-other-smooth-fixed,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-other-smooth-none,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-other-smooth-vertex,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection texture() 1darray,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection texture() 1darrayshadow,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection texture() 1d,Fail
@@ -867,7 +676,6 @@
 spec@glsl-1.30@execution@tex-miplevel-selection texture() 2d,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection texture() 2dshadow,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection texture() 3d,Fail
-spec@glsl-1.30@execution@tex-miplevel-selection texture(bias) 1darrayshadow,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection texture() cubearray,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection texture() cubearrayshadow,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection texture() cube,Fail
@@ -920,7 +728,6 @@
 spec@glsl-1.30@execution@tex-miplevel-selection textureoffset 2d,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection textureoffset 2dshadow,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection textureoffset 3d,Fail
-spec@glsl-1.30@execution@tex-miplevel-selection textureoffset(bias) 1darrayshadow,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection textureproj 1d,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection textureproj 1d_projvec4,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection textureproj 1dshadow,Fail
@@ -974,7 +781,6 @@
 spec@glsl-1.50@execution@geometry@primitive-id-restart gl_triangle_strip other,Fail
 spec@glsl-1.50@execution@geometry@tri-strip-ordering-with-prim-restart gl_triangle_strip_adjacency other,Fail
 spec@glsl-1.50@execution@geometry@tri-strip-ordering-with-prim-restart gl_triangle_strip other,Fail
-spec@glsl-1.50@execution@gs-also-uses-smooth-flat-noperspective,Fail
 spec@glsl-1.50@execution@primitive-id-no-gs-first-vertex,Fail
 spec@glsl-1.50@execution@primitive-id-no-gs-quads,Fail
 spec@glsl-1.50@execution@primitive-id-no-gs-quad-strip,Fail
@@ -2555,7 +2361,7 @@
 spec@!opengl 1.0@gl-1.0-logicop@GL_NOOP_MSAA,Fail
 spec@!opengl 1.0@gl-1.0-spot-light,Fail
 spec@!opengl 1.0@gl-1.0-swapbuffers-behavior,ExpectedFail
-spec@!opengl 1.0@rasterpos,Crash
+spec@!opengl 1.0@rasterpos,Fail
 spec@!opengl 1.0@rasterpos@glsl_vs_gs_linked,Fail
 spec@!opengl 1.0@rasterpos@glsl_vs_tes_linked,Fail
 spec@!opengl 1.1@clipflat,Fail
@@ -3353,7 +3159,6 @@
 spec@!opengl 2.0@gl-2.0-large-point-fs,Fail
 spec@!opengl 2.0@gl-2.0-vertexattribpointer,Crash
 spec@!opengl 2.0@occlusion-query-discard,Fail
-spec@!opengl 3.0@required-texture-attachment-formats,Fail
 spec@!opengl 3.0@sampler-cube-shadow,Fail
 spec@!opengl 3.2@gl-3.2-adj-prims cull-back pv-first,ExpectedFail
 spec@!opengl 3.2@gl-3.2-adj-prims cull-front pv-first,ExpectedFail
diff --git a/.gitlab-ci/expectations/host/virgl-gles-flakes.txt b/.gitlab-ci/expectations/host/virgl-gles-flakes.txt
index 5027ae1..4aa4035 100644
--- a/.gitlab-ci/expectations/host/virgl-gles-flakes.txt
+++ b/.gitlab-ci/expectations/host/virgl-gles-flakes.txt
@@ -4,6 +4,10 @@
 shaders@glsl-uniform-interstage-limits@subdivide 5- statechanges
 spec@arb_fragment_layer_viewport@viewport-gs-writes-in-range
 spec@arb_fragment_layer_viewport@layer-gs-writes-in-range
+spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@Basic
+spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic
+spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@MS4
+spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@Per-sample
 spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@glScissor
 spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@glViewport
 spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-roundup-samples
@@ -19,16 +23,6 @@
 spec@arb_shader_image_load_store@atomicity@imageAtomicMin
 spec@arb_shader_image_load_store@atomicity@imageAtomicOr
 spec@arb_shader_image_load_store@atomicity@imageAtomicXor
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/full barrier test/4x4
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/one bit barrier test/4x4
-spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/full barrier test/4x4
-spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/full barrier test/4x4
-spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/one bit barrier test/4x4
-spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/full barrier test/4x4
-spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/one bit barrier test/4x4
-spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/full barrier test/4x4
-spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/full barrier test/4x4
-spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/full barrier test/4x4
 spec@arb_shader_storage_buffer_object@execution@memory-layouts-struct-deref
 spec@arb_shader_storage_buffer_object@execution@ssbo-atomicadd-int
 spec@arb_shader_storage_buffer_object@execution@ssbo-atomicexchange-int
@@ -36,6 +30,7 @@
 spec@arb_shader_storage_buffer_object@layout-std430-write-shader
 spec@arb_timer_query@query gl_timestamp
 spec@arb_timer_query@timestamp-get
+spec@ext_timer_query@time-elapsed
 spec@ext_framebuffer_blit@fbo-blit-check-limits
 spec@ext_framebuffer_blit@fbo-sys-blit
 spec@ext_framebuffer_blit@fbo-sys-sub-blit
diff --git a/.gitlab-ci/expectations/host/virgl-gles-skips.txt b/.gitlab-ci/expectations/host/virgl-gles-skips.txt
index cc3cd4d..e7ff1c8 100644
--- a/.gitlab-ci/expectations/host/virgl-gles-skips.txt
+++ b/.gitlab-ci/expectations/host/virgl-gles-skips.txt
@@ -13,8 +13,6 @@
 # Fails on iris too
 spec@arb_direct_state_access@gettextureimage-formats
 
-spec@arb_texture_buffer_object@formats (fs- arb)*
-spec@arb_texture_buffer_object@formats (vs- arb)*
 spec@nv_primitive_restart@primitive-restart-draw-mode-polygon
 spec@nv_primitive_restart@primitive-restart-draw-mode-quad_strip
 spec@nv_primitive_restart@primitive-restart-draw-mode-quads
@@ -31,3 +29,142 @@
 
 # GLES doesn't support more than one stream
 spec@arb_enhanced_layouts@gs-stream-location-aliasing
+
+# All these tests use a RGBA32F RW image and this is not supported on GLES
+# so skip the tests
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@layer
+spec@arb_shader_image_load_store@layer@image1DArray/layered binding test
+spec@arb_shader_image_load_store@layer@image1DArray/non-layered binding test
+spec@arb_shader_image_load_store@layer@image1D/layered binding test
+spec@arb_shader_image_load_store@layer@image1D/non-layered binding test
+spec@arb_shader_image_load_store@layer@image2DArray/layered binding test
+spec@arb_shader_image_load_store@layer@image2DArray/non-layered binding test
+spec@arb_shader_image_load_store@layer@image2D/layered binding test
+spec@arb_shader_image_load_store@layer@image2D/non-layered binding test
+spec@arb_shader_image_load_store@layer@image2DRect/layered binding test
+spec@arb_shader_image_load_store@layer@image2DRect/non-layered binding test
+spec@arb_shader_image_load_store@layer@image3D/layered binding test
+spec@arb_shader_image_load_store@layer@image3D/non-layered binding test
+spec@arb_shader_image_load_store@layer@imageBuffer/layered binding test
+spec@arb_shader_image_load_store@layer@imageBuffer/non-layered binding test
+spec@arb_shader_image_load_store@layer@imageCubeArray/layered binding test
+spec@arb_shader_image_load_store@layer@imageCubeArray/non-layered binding test
+spec@arb_shader_image_load_store@layer@imageCube/layered binding test
+spec@arb_shader_image_load_store@layer@imageCube/non-layered binding test
+spec@arb_shader_image_load_store@level@1DArray level binding test
+spec@arb_shader_image_load_store@level@1D level binding test
+spec@arb_shader_image_load_store@level@2DArray level binding test
+spec@arb_shader_image_load_store@level@2D level binding test
+spec@arb_shader_image_load_store@level@3D level binding test
+spec@arb_shader_image_load_store@level@CubeArray level binding test
+spec@arb_shader_image_load_store@level@Cube level binding test
+spec@arb_shader_image_load_store@level
diff --git a/.gitlab-ci/expectations/virt/deqp-venus.toml b/.gitlab-ci/expectations/virt/deqp-venus.toml
new file mode 100644
index 0000000..752d7ec
--- /dev/null
+++ b/.gitlab-ci/expectations/virt/deqp-venus.toml
@@ -0,0 +1,6 @@
+[[deqp]]
+deqp = "/install/crosvm-runner.sh"
+caselists = [ "/deqp/mustpass/vk-master.txt" ]
+deqp_args = [ "/deqp/external/vulkancts/modules/vulkan/deqp-vk" ]
+timeout = 30.0 # Starting lots of Crosvm instances simultaneously can take some time
+renderer_check = "Virtio-GPU Venus.*llvmpipe"
diff --git a/.gitlab-ci/expectations/virt/deqp-virgl-gl.toml b/.gitlab-ci/expectations/virt/deqp-virgl-gl.toml
index fc874c4..10daea0 100644
--- a/.gitlab-ci/expectations/virt/deqp-virgl-gl.toml
+++ b/.gitlab-ci/expectations/virt/deqp-virgl-gl.toml
@@ -11,7 +11,7 @@
 ]
 timeout = 360.0 # Starting 8 Crosvm instances simultaneously can take some time
 version_check = "GL ES 3.2.*git"
-renderer_check = "virgl.*llvmpipe"
+renderer_check = "virgl.*LLVMPIPE"
 
 [[deqp]]
 deqp = "/install/crosvm-runner.sh"
diff --git a/.gitlab-ci/expectations/virt/deqp-virgl-gles.toml b/.gitlab-ci/expectations/virt/deqp-virgl-gles.toml
index fc874c4..10daea0 100644
--- a/.gitlab-ci/expectations/virt/deqp-virgl-gles.toml
+++ b/.gitlab-ci/expectations/virt/deqp-virgl-gles.toml
@@ -11,7 +11,7 @@
 ]
 timeout = 360.0 # Starting 8 Crosvm instances simultaneously can take some time
 version_check = "GL ES 3.2.*git"
-renderer_check = "virgl.*llvmpipe"
+renderer_check = "virgl.*LLVMPIPE"
 
 [[deqp]]
 deqp = "/install/crosvm-runner.sh"
diff --git a/.gitlab-ci/expectations/virt/traces-virgl.yml b/.gitlab-ci/expectations/virt/traces-virgl.yml
new file mode 100644
index 0000000..bb4d8b3
--- /dev/null
+++ b/.gitlab-ci/expectations/virt/traces-virgl.yml
@@ -0,0 +1,311 @@
+traces-db:
+  download-url: "https://s3.freedesktop.org/mesa-tracie-public/"
+
+traces:
+  - path: glmark2/desktop:windows=4:effect=blur:blur-radius=5:passes=1:separable=true-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 2fc8433c4a38b796173bda2bcfb924cc
+  - path: glmark2/jellyfish-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 2112a9a5519f39483735509f2ccc61af
+  - path: glxgears/glxgears-2-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: f8eba0fec6e3e0af9cb09844bc73bdc8
+  - path: gputest/furmark-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 2762c809316c58d4eefad6677ecfcb2e
+  - path: gputest/pixmark-piano-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 0d875bda7edc01698342b157c6f51500
+  - path: gputest/triangle-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 7812de00011a3a059892e36cea19c696
+  - path: humus/Portals-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: b697edce7776f1afe294a7e80dfc013e
+  - path: 0ad/0ad-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 350e0cf64d124ba98d90106f61775eb4
+  - path: glmark2/buffer:update-fraction=0.5:update-dispersion=0.9:columns=200:update-method=map:interleave=false-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: f80431e56327354b4c88cc45c7e6633a
+  - path: glmark2/buffer:update-fraction=0.5:update-dispersion=0.9:columns=200:update-method=subdata:interleave=false-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 81e12bfa4ae3b7e63b01edbed71a5941
+  - path: glmark2/buffer:update-fraction=0.5:update-dispersion=0.9:columns=200:update-method=map:interleave=true-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 08e6d00fe3f4414ebfadc9e5f3c3bf0e
+  - path: glmark2/bump:bump-render=height-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 4d5211dfb0fd82a1a1dbb498dc2e5b8b
+  - path: glmark2/bump:bump-render=high-poly-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 4b4d4a4b7bb1341bbd0299c7eb3a6ac9
+  - path: glmark2/bump:bump-render=normals-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 832e5baf289b27dd84a665f1c85f57c2
+  - path: glmark2/conditionals:vertex-steps=0:fragment-steps=0-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: b78f28d97b675fcc7649cced3930650a
+  - path: glmark2/conditionals:vertex-steps=0:fragment-steps=5-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: d0782a516f06a6dddac4f1e1249f41e7
+  - path: glmark2/conditionals:vertex-steps=5:fragment-steps=0-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 1ae280a9c6cae495f2d272516a52167e
+  - path: glmark2/desktop:windows=4:effect=shadow-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: d4b3e8338327859a029c7267c9916524
+  - path: glmark2/effect2d:kernel=0,1,0;1,-4,1;0,1,0;-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 35584880539813436d87bfcbe22cf59b
+  - path: glmark2/effect2d:kernel=1,1,1,1,1;1,1,1,1,1;1,1,1,1,1;-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: b80963dae6ecf40c83bfb16943ef1011
+  - path: glmark2/function:fragment-steps=5:fragment-complexity=low-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: da10cb29cab30c5c068e722b5da7c2e5
+  - path: glmark2/function:fragment-steps=5:fragment-complexity=medium-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 8e40504d9f2ead8c0d02604291bff1b6
+  - path: glmark2/build:use-vbo=false-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 024fc485e1f33461313c956ab1b73bdf
+  - path: glmark2/build:use-vbo=true-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 48c45d16cd410a71aea1a12a73e257d3
+  - path: glmark2/ideas:speed=10000-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: db78cfb035213e31e1435b637b1a8f19
+  - path: glmark2/loop:vertex-steps=5:fragment-steps=5:fragment-loop=false-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 7fee2e864e015353ace431d51d41bb22
+  - path: glmark2/loop:vertex-steps=5:fragment-steps=5:fragment-uniform=false-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: c87127a5c3256c1fe7c79f7931b8f9df
+  - path: glmark2/loop:vertex-steps=5:fragment-steps=5:fragment-uniform=true-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 5fec1f728bda86891db4243130546187
+  - path: glmark2/pulsar:quads=5:texture=false:light=false-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 3e0e6675fb65e00f9128138ff08c2634
+  - path: glmark2/refract-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: cdadfee0518b964433d80c01329ec191
+  - path: glmark2/shading:shading=blinn-phong-inf-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 36b07dad759ca65e52f1abf1667e7ca8
+  - path: glmark2/shading:shading=cel-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: cb41cf2531a06d65f6e4f442ab62ae8d
+  - path: glmark2/shading:shading=gouraud-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 3e5469d5038d7cc94ef3549ce9d8c385
+  - path: glmark2/shading:shading=phong-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: e40abcbb4cfbbbfb499d4b0e6d668f41
+  - path: glmark2/shadow-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 2bb7290f8559ff93305c0e29f3d671e1
+  - path: glmark2/texture:texture-filter=linear-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 914fd8dddb23751d9a187a979d881abb
+  - path: glmark2/texture:texture-filter=mipmap-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: ea1939f3c4e8dd9cdbc26d41f9dc891a
+  - path: glmark2/texture:texture-filter=nearest-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 1ae652bdebd1188ab912a800a4c37166
+# Crash
+#  - path: gputest/gimark-v2.trace
+#    expectations:
+#      - device: gl-virgl
+#        checksum: 2cf40180a1315795389d0dfc18aad988
+  - path: gputest/pixmark-julia-fp32-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 8b3584b1dd8f1d1bb63205564bd78e4e
+  - path: gputest/pixmark-julia-fp64-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 73ccaff82ea764057fb0f93f0024cf84
+  - path: gputest/pixmark-volplosion-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: aef0b32ce99a3b25d35304ca08032833
+  - path: gputest/plot3d-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 817a36e53edccdf946061315596e9cdd
+# Times out
+# - path: gputest/tessmark-v2.trace
+#   expectations:
+#     - device: gl-virgl
+#       checksum: 5d04b8d71517238b9bc8a527574e884b
+  - path: humus/AmbientAperture-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: b33fb8ee73b0c50b14822e170f15ab8a
+  - path: humus/CelShading-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 3629cba72bde53e4275a8365175fde83
+  - path: humus/DynamicBranching3-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 0236b28aa8b26fa60172d71bb040f2e9
+  - path: humus/HDR-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: eab0801aadeae87ce31aa0d4ff55e8f8
+  - path: humus/RaytracedShadows-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: df074a376fd3e7abc4dffdd191db8f4b
+  - path: humus/VolumetricFogging2-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 2eb71553403ad8e0171abc9dc25e5bc1
+  - path: itoral-gl-terrain-demo/demo-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 716d4fe36a6212b161285fed8a423ee8
+  - path: neverball/neverball-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: cc11743f008ccd76adf72695a423436a
+  - path: pathfinder/canvas_moire-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 25ba8f18274126670311bd3ffe058f74
+  - path: pathfinder/canvas_text_v2-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: a1446d0c42a78771240fca6f3b1e10d8
+  - path: pathfinder/demo-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 0702a66c415cfc13d5bae8bec08402cf
+  # host crashes with
+  # "src/mesa/main/arrayobj.c:800:_mesa_update_vao_derived_arrays: Assertion
+  # `attrib->_EffRelativeOffset < binding->Stride' failed. running these.
+  # - path: paraview/pv-manyspheres-v2.trace
+  #   expectations:
+  #     - device: gl-virgl
+  #       checksum: b740377ea4bbb3becd304d1696a55247
+  # - path: paraview/pv-waveletcontour-v2.trace
+  #   expectations:
+  #    - device: gl-virgl
+  #       checksum: db43c733f3f3d5253e263838e58d9111
+  - path: paraview/pv-waveletvolume-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: f4af4067b37c00861fa5911e4c0a6629
+  - path: supertuxkart/supertuxkart-mansion-egl-gles-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 092e8ca38e58aaa83df2a9f0b7b8aee5
+  - path: xonotic/xonotic-keybench-high-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: f3b184bf8858a6ebccd09e7ca032197e
+  - path: valve/counterstrike-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 3bc0e0e39cb3c29f6d76ff07f1f02860
+  - path: valve/counterstrike-source-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: f8e5b19142007be14ce6d18d25ef329d
+  - path: valve/half-life-2-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 6099a13f48bf090ee1d768f98208da70
+  - path: valve/portal-2-v2.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 7489a8412ee2bca45431d208e0006a3e
+# Piglit crashes when trying to run this one
+#  - path: supertuxkart/supertuxkart-antediluvian-abyss.rdc
+#    expectations:
+#      - device: gl-virgl
+#        checksum: 0
+# Piglit crashes when trying to run this one
+#  - path: supertuxkart/supertuxkart-menu.rdc
+#    expectations:
+#      - device: gl-virgl
+#        checksum: 0
+# Piglit crashes when trying to run this one
+#  - path: supertuxkart/supertuxkart-ravenbridge-mansion.rdc
+#    expectations:
+#      - device: gl-virgl
+#        checksum: 0
+  - path: godot/Material Testers.x86_64_2020.04.08_13.38_frame799.rdc
+    expectations:
+      - device: gl-virgl
+        checksum: 232eb48d6689c0117e3cc1660af7f32d
+  # ../src/mesa/main/arrayobj.c:800:_mesa_update_vao_derived_arrays: Assertion `attrib->_EffRelativeOffset < binding->Stride' failed.
+  #- path: ror/ror-default.trace
+  #  expectations:
+      #- device: gl-virgl
+  #- path: nheko/nheko-colors.trace
+  #  expectations:
+      #- device: gl-virgl
+      #  checksum: 3a12c08087e16cfae4729f4e9d6c9387
+  #- path: blender/blender-demo-cube_diorama.trace
+  #  expectations:
+      #- device: gl-virgl
+  #- path: blender/blender-demo-ellie_pose.trace
+  #  expectations:
+      #- device: gl-virgl
+  #- path: freedoom/freedoom-phase2-gl-high.trace
+  #  expectations:
+      #- device: gl-virgl
+  #- path: unvanquished/unvanquished-lowest.trace
+  #  expectations:
+      #- device: gl-virgl
+  #- path: unvanquished/unvanquished-ultra.trace
+  #  expectations:
+      #- device: gl-virgl
+  - path: warzone2100/warzone2100-default.trace
+    expectations:
+      - device: gl-virgl
+        checksum: 1fd3f9b5e5a711bdfac49dc03912e1de
diff --git a/.gitlab-ci/expectations/virt/venus-fails.txt b/.gitlab-ci/expectations/virt/venus-fails.txt
new file mode 100644
index 0000000..8916f9e
--- /dev/null
+++ b/.gitlab-ci/expectations/virt/venus-fails.txt
@@ -0,0 +1,15 @@
+# Failures likely due to lavapipe (i.e. the intersection of observed failures and lvp-fails.txt)
+dEQP-VK.glsl.crash_test.divbyzero_comp,Crash
+
+# Full Venus list
+dEQP-VK.multiview.queries.15_15_15_15,Fail
+dEQP-VK.multiview.queries.15,Fail
+dEQP-VK.multiview.queries.5_10_5_10,Fail
+dEQP-VK.multiview.renderpass2.queries.15_15_15_15,Fail
+dEQP-VK.multiview.renderpass2.queries.15,Fail
+dEQP-VK.multiview.renderpass2.queries.5_10_5_10,Fail
+dEQP-VK.pipeline.extended_dynamic_state.after_pipelines.enable_raster,Fail
+dEQP-VK.pipeline.extended_dynamic_state.before_draw.enable_raster,Fail
+dEQP-VK.pipeline.extended_dynamic_state.between_pipelines.enable_raster,Fail
+dEQP-VK.pipeline.extended_dynamic_state.cmd_buffer_start.enable_raster,Fail
+dEQP-VK.pipeline.extended_dynamic_state.two_draws_dynamic.enable_raster,Fail
diff --git a/.gitlab-ci/expectations/virt/venus-flakes.txt b/.gitlab-ci/expectations/virt/venus-flakes.txt
new file mode 100644
index 0000000..19891bf
--- /dev/null
+++ b/.gitlab-ci/expectations/virt/venus-flakes.txt
@@ -0,0 +1,8 @@
+dEQP-VK.synchronization.*16384
+dEQP-VK.synchronization.*262144
+dEQP-VK.spirv_assembly.instruction.graphics.64bit_compare.double.frag_opfordnotequal_nonan_vector
+dEQP-VK.robustness.buffer_access.fragment.vec4_copy.r32_uint.oob_storage_read.range_4_bytes
+dEQP-VK.robustness.buffer_access.fragment.vec4_copy.r32_uint.oob_storage_write.range_32_bytes
+dEQP-VK.robustness.buffer_access.fragment.texel_copy.r32g32b32a32_sfloat.oob_storage_write.range_3_texels
+dEQP-VK.robustness.buffer_access.fragment.texel_copy.r32g32b32a32_uint.oob_storage_write.range_3_texels
+dEQP-VK.subgroups.ballot_broadcast.compute.subgroupbroadcast_uvec4
diff --git a/.gitlab-ci/expectations/virt/venus-skips.txt b/.gitlab-ci/expectations/virt/venus-skips.txt
new file mode 100644
index 0000000..e67e91b
--- /dev/null
+++ b/.gitlab-ci/expectations/virt/venus-skips.txt
@@ -0,0 +1,2 @@
+# These take so long that cause caselist batches to timeout
+dEQP-VK.pipeline.monolithic.*
\ No newline at end of file
diff --git a/.gitlab-ci/expectations/virt/virgl-gl-fails.txt b/.gitlab-ci/expectations/virt/virgl-gl-fails.txt
index 291f25b..fa9155f 100644
--- a/.gitlab-ci/expectations/virt/virgl-gl-fails.txt
+++ b/.gitlab-ci/expectations/virt/virgl-gl-fails.txt
@@ -27,8 +27,6 @@
 dEQP-GLES3.functional.clipping.point.wide_point_clip,Fail
 dEQP-GLES3.functional.clipping.point.wide_point_clip_viewport_center,Fail
 dEQP-GLES3.functional.clipping.point.wide_point_clip_viewport_corner,Fail
-dEQP-GLES3.functional.draw_buffers_indexed.random.max_implementation_draw_buffers.8,Fail
-dEQP-GLES3.functional.draw_buffers_indexed.random.max_required_draw_buffers.9,Fail
 dEQP-GLES3.functional.fbo.blit.rect.nearest_consistency_mag,Fail
 dEQP-GLES3.functional.fbo.blit.rect.nearest_consistency_mag_reverse_dst_x,Fail
 dEQP-GLES3.functional.fbo.blit.rect.nearest_consistency_mag_reverse_src_dst_x,Fail
@@ -63,95 +61,7 @@
 spec@arb_blend_func_extended@arb_blend_func_extended-fbo-extended-blend-pattern_gles2,Fail
 spec@arb_clear_texture@arb_clear_texture-depth,Fail
 spec@arb_copy_image@arb_copy_image-formats,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_RED_RGTC1/Destination: GL_COMPRESSED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_RGBA_BPTC_UNORM/Destination: GL_COMPRESSED_RGBA_BPTC_UNORM,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT/Destination: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_RGBA_S3TC_DXT3_EXT/Destination: GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_RGBA_S3TC_DXT5_EXT/Destination: GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT/Destination: GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT/Destination: GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_RGB_S3TC_DXT1_EXT/Destination: GL_COMPRESSED_RGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_RG_RGTC2/Destination: GL_COMPRESSED_RG_RGTC2,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_SIGNED_RED_RGTC1/Destination: GL_COMPRESSED_SIGNED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_SIGNED_RG_RGTC2/Destination: GL_COMPRESSED_SIGNED_RG_RGTC2,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM/Destination: GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT/Destination: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,Fail
 spec@arb_copy_image@arb_copy_image-formats@Source: GL_DEPTH_COMPONENT24/Destination: GL_DEPTH_COMPONENT24,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32F/Destination: GL_COMPRESSED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32F/Destination: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32F/Destination: GL_COMPRESSED_RGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32F/Destination: GL_COMPRESSED_SIGNED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32F/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32F/Destination: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32I/Destination: GL_COMPRESSED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32I/Destination: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32I/Destination: GL_COMPRESSED_RGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32I/Destination: GL_COMPRESSED_SIGNED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32I/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32I/Destination: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32UI/Destination: GL_COMPRESSED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32UI/Destination: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32UI/Destination: GL_COMPRESSED_RGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32UI/Destination: GL_COMPRESSED_SIGNED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32UI/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RG32UI/Destination: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16/Destination: GL_COMPRESSED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16/Destination: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16/Destination: GL_COMPRESSED_RGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16/Destination: GL_COMPRESSED_SIGNED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16/Destination: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16I/Destination: GL_COMPRESSED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16I/Destination: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16I/Destination: GL_COMPRESSED_RGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16I/Destination: GL_COMPRESSED_SIGNED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16I/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16I/Destination: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16_SNORM/Destination: GL_COMPRESSED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16_SNORM/Destination: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16_SNORM/Destination: GL_COMPRESSED_RGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16_SNORM/Destination: GL_COMPRESSED_SIGNED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16_SNORM/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16_SNORM/Destination: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16UI/Destination: GL_COMPRESSED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16UI/Destination: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16UI/Destination: GL_COMPRESSED_RGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16UI/Destination: GL_COMPRESSED_SIGNED_RED_RGTC1,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16UI/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA16UI/Destination: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32F/Destination: GL_COMPRESSED_RGBA_BPTC_UNORM,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32F/Destination: GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32F/Destination: GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32F/Destination: GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32F/Destination: GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32F/Destination: GL_COMPRESSED_RG_RGTC2,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32F/Destination: GL_COMPRESSED_SIGNED_RG_RGTC2,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32F/Destination: GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32F/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32F/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32I/Destination: GL_COMPRESSED_RGBA_BPTC_UNORM,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32I/Destination: GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32I/Destination: GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32I/Destination: GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32I/Destination: GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32I/Destination: GL_COMPRESSED_RG_RGTC2,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32I/Destination: GL_COMPRESSED_SIGNED_RG_RGTC2,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32I/Destination: GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32I/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32I/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32UI/Destination: GL_COMPRESSED_RGBA_BPTC_UNORM,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32UI/Destination: GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32UI/Destination: GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32UI/Destination: GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32UI/Destination: GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32UI/Destination: GL_COMPRESSED_RG_RGTC2,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32UI/Destination: GL_COMPRESSED_SIGNED_RG_RGTC2,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32UI/Destination: GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32UI/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,Fail
-spec@arb_copy_image@arb_copy_image-formats@Source: GL_RGBA32UI/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,Fail
 spec@arb_depth_buffer_float@fbo-depthstencil-gl_depth32f_stencil8-copypixels,Fail
 spec@arb_depth_buffer_float@fbo-depthstencil-gl_depth32f_stencil8-drawpixels-24_8,Fail
 spec@arb_depth_buffer_float@fbo-depthstencil-gl_depth32f_stencil8-drawpixels-32f_24_8_rev,Fail
@@ -170,16 +80,15 @@
 spec@arb_depth_texture@texwrap formats bordercolor-swizzled@GL_DEPTH_COMPONENT24- swizzled- border color only,Fail
 spec@arb_depth_texture@texwrap formats bordercolor-swizzled@GL_DEPTH_COMPONENT32- swizzled- border color only,Fail
 spec@arb_direct_state_access@gettextureimage-targets,Fail
+spec@arb_enhanced_layouts@matching_fp64_types_1,Crash
+spec@arb_enhanced_layouts@matching_fp64_types_2,Crash
+spec@arb_enhanced_layouts@matching_fp64_types_3,Crash
 spec@arb_es2_compatibility@texwrap formats bordercolor,Fail
 spec@arb_es2_compatibility@texwrap formats bordercolor@GL_RGB565- border color only,Fail
 spec@arb_es2_compatibility@texwrap formats bordercolor-swizzled,Fail
 spec@arb_es2_compatibility@texwrap formats bordercolor-swizzled@GL_RGB565- swizzled- border color only,Fail
-spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@Basic,Fail
-spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic,Fail
 spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@glScissor,Fail
 spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@glViewport,Fail
-spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@MS4,Fail
-spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@Per-sample,Fail
 spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-roundup-samples,Fail
 spec@arb_get_texture_sub_image@arb_get_texture_sub_image-getcompressed,Crash
 spec@arb_get_texture_sub_image@arb_get_texture_sub_image-get,Fail
@@ -193,7 +102,6 @@
 spec@arb_sample_shading@builtin-gl-sample-position 2,Fail
 spec@arb_shader_atomic_counter_ops@execution@add,Fail
 spec@arb_shader_atomic_counters@fragment-discard,Fail
-spec@arb_shader_atomic_counters@function-argument,Fail
 spec@arb_shader_image_load_store@early-z,Fail
 spec@arb_shader_image_load_store@early-z@occlusion query test/early-z pass,Fail
 spec@arb_shader_image_load_store@layer,Fail
@@ -212,16 +120,8 @@
 spec@arb_shader_image_load_store@semantics@imageLoad/Vertex shader/rgba32f/image2DMS test,Fail
 spec@arb_shader_storage_buffer_object@execution@ssbo-atomiccompswap-int,Fail
 spec@arb_shader_storage_buffer_object@execution@ssbo-atomicexchange-int,Fail
-spec@arb_shader_storage_buffer_object@layout-std140-write-shader,Fail
-spec@arb_shader_storage_buffer_object@layout-std430-write-shader,Fail
 spec@arb_shader_storage_buffer_object@maxblocks,Fail
 spec@arb_shader_texture_lod@execution@arb_shader_texture_lod-texgrad,Fail
-spec@arb_shader_texture_lod@execution@glsl-fs-shadow2dgradarb-07,Fail
-spec@arb_shader_texture_lod@execution@glsl-fs-shadow2dgradarb-08,Fail
-spec@arb_shader_texture_lod@execution@glsl-fs-shadow2dgradarb-cumulative,Fail
-spec@arb_texture_compression_bptc@compressedteximage gl_compressed_rgb_bptc_signed_float,Fail
-spec@arb_texture_compression_bptc@compressedteximage gl_compressed_rgb_bptc_unsigned_float,Fail
-spec@arb_texture_compression_bptc@compressedteximage gl_compressed_srgb_alpha_bptc_unorm,Fail
 spec@arb_texture_compression_bptc@texwrap formats bordercolor,Fail
 spec@arb_texture_compression_bptc@texwrap formats bordercolor@GL_COMPRESSED_RGBA_BPTC_UNORM- border color only,Fail
 spec@arb_texture_compression_bptc@texwrap formats bordercolor@GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT- border color only,Fail
@@ -250,8 +150,6 @@
 spec@arb_texture_float@fbo-blending-formats,Fail
 spec@arb_texture_float@fbo-blending-formats@GL_ALPHA16F_ARB,Fail
 spec@arb_texture_float@fbo-blending-formats@GL_ALPHA32F_ARB,Fail
-spec@arb_texture_float@fbo-blending-formats@GL_INTENSITY16F_ARB,Fail
-spec@arb_texture_float@fbo-blending-formats@GL_INTENSITY32F_ARB,Fail
 spec@arb_texture_float@fbo-blending-formats@GL_RGB32F,Fail
 spec@arb_texture_float@fbo-clear-formats,Fail
 spec@arb_texture_float@fbo-clear-formats@GL_ALPHA16F_ARB,Fail
@@ -292,8 +190,6 @@
 spec@arb_texture_rectangle@copyteximage rect,Fail
 spec@arb_texture_rectangle@copyteximage rect samples=2,Fail
 spec@arb_texture_rectangle@copyteximage rect samples=4,Fail
-spec@arb_texture_rectangle@glsl-fs-shadow2drect-07,Fail
-spec@arb_texture_rectangle@glsl-fs-shadow2drect-08,Fail
 spec@arb_texture_rectangle@texwrap rect bordercolor,Fail
 spec@arb_texture_rectangle@texwrap rect bordercolor@GL_RGBA8- border color only,Fail
 spec@arb_texture_rectangle@texwrap rect proj bordercolor,Fail
@@ -335,32 +231,6 @@
 spec@egl_ext_protected_content@conformance,Fail
 spec@egl_khr_gl_image@egl_khr_gl_renderbuffer_image-clear-shared-image gl_depth_component24,Fail
 spec@egl_khr_surfaceless_context@viewport,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage2DEXT + display list GL_COMPILE_AND_EXECUTE,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage2DEXT + display list GL_COMPILE,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage2DEXT,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage3DEXT + display list GL_COMPILE_AND_EXECUTE,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage3DEXT + display list GL_COMPILE,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage3DEXT,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage2DEXT + display list GL_COMPILE_AND_EXECUTE,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage2DEXT + display list GL_COMPILE,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage2DEXT,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage3DEXT + display list GL_COMPILE_AND_EXECUTE,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage3DEXT + display list GL_COMPILE,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage3DEXT,Fail
-spec@ext_direct_state_access@compressedmultiteximage gl_compressed_rgb_bptc_signed_float,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage2DEXT + display list GL_COMPILE_AND_EXECUTE,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage2DEXT + display list GL_COMPILE,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage2DEXT,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage3DEXT + display list GL_COMPILE_AND_EXECUTE,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage3DEXT + display list GL_COMPILE,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureImage3DEXT,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage2DEXT + display list GL_COMPILE_AND_EXECUTE,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage2DEXT + display list GL_COMPILE,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage2DEXT,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage3DEXT + display list GL_COMPILE_AND_EXECUTE,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage3DEXT + display list GL_COMPILE,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float@CompressedTextureSubImage3DEXT,Fail
-spec@ext_direct_state_access@compressedtextureimage gl_compressed_rgb_bptc_signed_float,Fail
 spec@ext_framebuffer_multisample@alpha-blending-after-rendering 2,Fail
 spec@ext_framebuffer_multisample@blit-mismatched-formats,Fail
 spec@ext_framebuffer_multisample@interpolation 2 centroid-edges,Fail
@@ -372,12 +242,6 @@
 spec@ext_framebuffer_multisample@sample-coverage 2 inverted,Fail
 spec@ext_framebuffer_multisample@sample-coverage 2 non-inverted,Fail
 spec@ext_framebuffer_object@fbo-blending-format-quirks,Fail
-spec@ext_framebuffer_object@fbo-blending-formats,Fail
-spec@ext_framebuffer_object@fbo-blending-formats@GL_INTENSITY12,Fail
-spec@ext_framebuffer_object@fbo-blending-formats@GL_INTENSITY16,Fail
-spec@ext_framebuffer_object@fbo-blending-formats@GL_INTENSITY4,Fail
-spec@ext_framebuffer_object@fbo-blending-formats@GL_INTENSITY8,Fail
-spec@ext_framebuffer_object@fbo-blending-formats@GL_INTENSITY,Fail
 spec@ext_framebuffer_object@fbo-readpixels-depth-formats,Fail
 spec@ext_framebuffer_object@fbo-readpixels-depth-formats@GL_DEPTH_COMPONENT24/GL_FLOAT,Fail
 spec@ext_framebuffer_object@fbo-readpixels-depth-formats@GL_DEPTH_COMPONENT/GL_FLOAT,Fail
@@ -413,10 +277,6 @@
 spec@ext_texture_array@fbo-generatemipmap-array s3tc_dxt1,Fail
 spec@ext_texture_array@gen-mipmap,Fail
 spec@ext_texture_array@getteximage-targets 1d_array,Fail
-spec@ext_texture_array@glsl-fs-shadow1darray-07,Fail
-spec@ext_texture_array@glsl-fs-shadow1darray-08,Fail
-spec@ext_texture_array@glsl-fs-shadow2darray-07,Fail
-spec@ext_texture_array@glsl-fs-shadow2darray-08,Fail
 spec@ext_texture_compression_rgtc@texwrap formats bordercolor,Fail
 spec@ext_texture_compression_rgtc@texwrap formats bordercolor@GL_COMPRESSED_RED_RGTC1- border color only,Fail
 spec@ext_texture_compression_rgtc@texwrap formats bordercolor@GL_COMPRESSED_RG_RGTC2- border color only,Fail
@@ -459,10 +319,6 @@
 spec@ext_texture_shared_exponent@texwrap formats bordercolor@GL_RGB9_E5- border color only,Fail
 spec@ext_texture_shared_exponent@texwrap formats bordercolor-swizzled,Fail
 spec@ext_texture_shared_exponent@texwrap formats bordercolor-swizzled@GL_RGB9_E5- swizzled- border color only,Fail
-spec@ext_texture_snorm@fbo-blending-formats,Fail
-spec@ext_texture_snorm@fbo-blending-formats@GL_INTENSITY16_SNORM,Fail
-spec@ext_texture_snorm@fbo-blending-formats@GL_INTENSITY8_SNORM,Fail
-spec@ext_texture_snorm@fbo-blending-formats@GL_INTENSITY_SNORM,Fail
 spec@ext_texture_snorm@texwrap formats bordercolor,Fail
 spec@ext_texture_snorm@texwrap formats bordercolor@GL_ALPHA16_SNORM- border color only,Fail
 spec@ext_texture_snorm@texwrap formats bordercolor@GL_ALPHA8_SNORM- border color only,Fail
@@ -525,10 +381,7 @@
 spec@ext_texture_srgb@texwrap formats-s3tc bordercolor-swizzled@GL_COMPRESSED_SRGB_ALPHA- swizzled- border color only,Fail
 spec@ext_texture_srgb@texwrap formats-s3tc bordercolor-swizzled@GL_COMPRESSED_SRGB_S3TC_DXT1_EXT- swizzled- border color only,Fail
 spec@ext_texture_srgb@texwrap formats-s3tc bordercolor-swizzled@GL_COMPRESSED_SRGB- swizzled- border color only,Fail
-spec@glsl-1.10@execution@samplers@glsl-fs-shadow1d-07,Fail
-spec@glsl-1.10@execution@samplers@glsl-fs-shadow1d-08,Fail
-spec@glsl-1.10@execution@samplers@glsl-fs-shadow2d-07,Fail
-spec@glsl-1.10@execution@samplers@glsl-fs-shadow2d-08,Fail
+spec@ext_transform_feedback@builtin-varyings gl_culldistance,Fail
 spec@glsl-1.10@execution@samplers@glsl-fs-shadow2d-clamp-z,Fail
 spec@glsl-1.30@execution@texelfetch@fs-texelfetch-isampler1darray,Fail
 spec@glsl-1.30@execution@texelfetch@fs-texelfetch-sampler1darray,Fail
@@ -543,72 +396,29 @@
 spec@glsl-1.50@execution@primitive-id-no-gs-quads,Fail
 spec@glsl-1.50@execution@primitive-id-no-gs-quad-strip,Fail
 spec@glsl-1.50@execution@variable-indexing@gs-input-array-float-index-rd,Fail
-spec@khr_texture_compression_astc@array-gl@12x12 Block Dim,Fail
-spec@khr_texture_compression_astc@array-gl@5x5 Block Dim,Fail
-spec@khr_texture_compression_astc@array-gles@12x12 Block Dim,Fail
-spec@khr_texture_compression_astc@array-gles@5x5 Block Dim,Fail
-spec@khr_texture_compression_astc@array-gles,Fail
-spec@khr_texture_compression_astc@array-gl,Fail
-spec@khr_texture_compression_astc@miptree-gles ldr,Fail
-spec@khr_texture_compression_astc@miptree-gles ldr@LDR Profile,Fail
-spec@khr_texture_compression_astc@miptree-gles srgb,Fail
 spec@khr_texture_compression_astc@miptree-gles srgb-fp,Fail
 spec@khr_texture_compression_astc@miptree-gles srgb-fp@sRGB decode full precision,Fail
-spec@khr_texture_compression_astc@miptree-gles srgb-sd,Fail
-spec@khr_texture_compression_astc@miptree-gles srgb-sd@sRGB skip decode,Fail
-spec@khr_texture_compression_astc@miptree-gles srgb@sRGB decode,Fail
-spec@khr_texture_compression_astc@miptree-gl ldr,Fail
-spec@khr_texture_compression_astc@miptree-gl ldr@LDR Profile,Fail
-spec@khr_texture_compression_astc@miptree-gl srgb,Fail
 spec@khr_texture_compression_astc@miptree-gl srgb-fp,Fail
 spec@khr_texture_compression_astc@miptree-gl srgb-fp@sRGB decode full precision,Fail
-spec@khr_texture_compression_astc@miptree-gl srgb-sd,Fail
-spec@khr_texture_compression_astc@miptree-gl srgb-sd@sRGB skip decode,Fail
-spec@khr_texture_compression_astc@miptree-gl srgb@sRGB decode,Fail
-spec@khr_texture_compression_astc@sliced-3d-miptree-gles ldr,Fail
-spec@khr_texture_compression_astc@sliced-3d-miptree-gles ldr@LDR Profile,Fail
-spec@khr_texture_compression_astc@sliced-3d-miptree-gles srgb,Fail
 spec@khr_texture_compression_astc@sliced-3d-miptree-gles srgb-fp,Fail
 spec@khr_texture_compression_astc@sliced-3d-miptree-gles srgb-fp@sRGB decode full precision,Fail
-spec@khr_texture_compression_astc@sliced-3d-miptree-gles srgb@sRGB decode,Fail
-spec@khr_texture_compression_astc@sliced-3d-miptree-gl ldr,Fail
-spec@khr_texture_compression_astc@sliced-3d-miptree-gl ldr@LDR Profile,Fail
-spec@khr_texture_compression_astc@sliced-3d-miptree-gl srgb,Fail
 spec@khr_texture_compression_astc@sliced-3d-miptree-gl srgb-fp,Fail
 spec@khr_texture_compression_astc@sliced-3d-miptree-gl srgb-fp@sRGB decode full precision,Fail
-spec@khr_texture_compression_astc@sliced-3d-miptree-gl srgb@sRGB decode,Fail
 spec@nv_copy_depth_to_color@nv_copy_depth_to_color 0 0x223344ff,Fail
 spec@nv_copy_depth_to_color@nv_copy_depth_to_color 0 0x76356278,Fail
 spec@nv_copy_depth_to_color@nv_copy_depth_to_color 1 0x223344ff,Fail
 spec@nv_copy_depth_to_color@nv_copy_depth_to_color 1 0x76356278,Fail
 spec@nv_copy_depth_to_color@nv_copy_depth_to_color,Fail
 spec@nv_copy_image@nv_copy_image-formats,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_RED_RGTC1/Destination: GL_COMPRESSED_RED_RGTC1,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_RGBA_BPTC_UNORM/Destination: GL_COMPRESSED_RGBA_BPTC_UNORM,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT/Destination: GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_RGBA_S3TC_DXT3_EXT/Destination: GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_RGBA_S3TC_DXT5_EXT/Destination: GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT/Destination: GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT/Destination: GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_RGB_S3TC_DXT1_EXT/Destination: GL_COMPRESSED_RGB_S3TC_DXT1_EXT,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_RG_RGTC2/Destination: GL_COMPRESSED_RG_RGTC2,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_SIGNED_RED_RGTC1/Destination: GL_COMPRESSED_SIGNED_RED_RGTC1,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_SIGNED_RG_RGTC2/Destination: GL_COMPRESSED_SIGNED_RG_RGTC2,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM/Destination: GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT/Destination: GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,Fail
-spec@nv_copy_image@nv_copy_image-formats@Source: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT/Destination: GL_COMPRESSED_SRGB_S3TC_DXT1_EXT,Fail
 spec@nv_copy_image@nv_copy_image-formats@Source: GL_DEPTH_COMPONENT24/Destination: GL_DEPTH_COMPONENT24,Fail
 spec@nv_read_depth@read_depth_gles3,Fail
 spec@!opengl 1.0@depth-clear-precision-check@depth32,Fail
 spec@!opengl 1.0@depth-clear-precision-check,Fail
-spec@!opengl 1.0@gl-1.0-dlist-bitmap,Fail
 spec@!opengl 1.0@gl-1.0-drawbuffer-modes,Fail
 spec@!opengl 1.0@gl-1.0-edgeflag,Fail
 spec@!opengl 1.0@gl-1.0-edgeflag-quads,Fail
 spec@!opengl 1.0@gl-1.0-swapbuffers-behavior,Fail
-spec@!opengl 1.0@rasterpos,Crash
+spec@!opengl 1.0@rasterpos,Fail
 spec@!opengl 1.0@rasterpos@glsl_vs_gs_linked,Fail
 spec@!opengl 1.0@rasterpos@glsl_vs_tes_linked,Fail
 spec@!opengl 1.1@copypixels-draw-sync,Fail
@@ -641,7 +451,6 @@
 spec@!opengl 1.1@read-front,Fail
 spec@!opengl 1.1@read-front samples=2,Crash
 spec@!opengl 1.1@read-front samples=4,Fail
-spec@!opengl 1.1@streaming-texture-leak,Crash
 spec@!opengl 1.1@texwrap 1d bordercolor,Fail
 spec@!opengl 1.1@texwrap 1d bordercolor@GL_RGBA8- border color only,Fail
 spec@!opengl 1.1@texwrap 1d proj bordercolor,Fail
diff --git a/.gitlab-ci/expectations/virt/virgl-gl-flakes.txt b/.gitlab-ci/expectations/virt/virgl-gl-flakes.txt
index cf24ad0..1101b2c 100644
--- a/.gitlab-ci/expectations/virt/virgl-gl-flakes.txt
+++ b/.gitlab-ci/expectations/virt/virgl-gl-flakes.txt
@@ -34,6 +34,7 @@
 spec@arb_texture_rg@fbo-rg-gl_rg
 spec@arb_timer_query@query gl_timestamp
 spec@arb_timer_query@timestamp-get
+spec@ext_timer_query@time-elapsed
 spec@ext_framebuffer_blit@fbo-blit-check-limits
 spec@ext_framebuffer_blit@fbo-sys-blit
 spec@ext_framebuffer_blit@fbo-sys-sub-blit
@@ -50,6 +51,7 @@
 spec@glsl-4.00@execution@built-in-functions@vs-op-mult-dmat3x4-dvec3
 spec@glsl-4.30@execution@built-in-functions@cs-op-bitand-not-uvec2-uvec2
 spec@glsl-4.30@execution@built-in-functions@cs-op-bitor-abs-not-int-ivec4
+spec@glsl-4.50@execution@ssbo-atomiccompswap-int
 spec@oes_texture_view@sampling-2d-array-as-2d-layer
 spec@oes_viewport_array@viewport-gs-writes-in-range
 spec@!opengl 1.0@gl-1.0-drawbuffer-modes
diff --git a/.gitlab-ci/expectations/virt/virgl-gl-skips.txt b/.gitlab-ci/expectations/virt/virgl-gl-skips.txt
index 1f4dcb1..e9fef33 100644
--- a/.gitlab-ci/expectations/virt/virgl-gl-skips.txt
+++ b/.gitlab-ci/expectations/virt/virgl-gl-skips.txt
@@ -16,9 +16,6 @@
 # Fails on iris too
 spec@arb_direct_state_access@gettextureimage-formats
 
-spec@arb_texture_buffer_object@formats (fs- arb)*
-spec@arb_texture_buffer_object@formats (vs- arb)*
-
 # Skip these as they get skipped with the Intel driver + vtest
 spec@arb_shader_texture_image_samples@builtin-image*
 
diff --git a/.gitlab-ci/expectations/virt/virgl-gles-fails.txt b/.gitlab-ci/expectations/virt/virgl-gles-fails.txt
index 9837c02..03c690e 100644
--- a/.gitlab-ci/expectations/virt/virgl-gles-fails.txt
+++ b/.gitlab-ci/expectations/virt/virgl-gles-fails.txt
@@ -11,8 +11,6 @@
 dEQP-GLES31.functional.shaders.sample_variables.sample_mask_in.bit_count_per_two_samples.multisample_texture_2,Fail
 dEQP-GLES3.functional.clipping.line.wide_line_clip_viewport_center,Fail
 dEQP-GLES3.functional.clipping.line.wide_line_clip_viewport_corner,Fail
-dEQP-GLES3.functional.draw_buffers_indexed.random.max_implementation_draw_buffers.8,Fail
-dEQP-GLES3.functional.draw_buffers_indexed.random.max_required_draw_buffers.9,Fail
 dEQP-GLES3.functional.fbo.blit.rect.nearest_consistency_mag,Fail
 dEQP-GLES3.functional.fbo.blit.rect.nearest_consistency_mag_reverse_dst_x,Fail
 dEQP-GLES3.functional.fbo.blit.rect.nearest_consistency_mag_reverse_src_dst_x,Fail
@@ -23,12 +21,9 @@
 dEQP-GLES3.functional.fbo.blit.rect.nearest_consistency_min_reverse_src_dst_x,Fail
 dEQP-GLES3.functional.fbo.blit.rect.nearest_consistency_min_reverse_src_dst_y,Fail
 dEQP-GLES3.functional.fbo.blit.rect.nearest_consistency_min_reverse_src_x,Fail
-KHR-GL30.glsl_noperspective.functionaltest,Fail
 KHR-GL30.transform_feedback.api_errors_test,Fail
 KHR-GL30.transform_feedback.draw_xfb_stream_instanced_test,Fail
-KHR-GL31.glsl_noperspective.functionaltest,Fail
 KHR-GL31.transform_feedback.draw_xfb_stream_instanced_test,Fail
-KHR-GL32.glsl_noperspective.functionaltest,Fail
 KHR-GL32.transform_feedback.draw_xfb_stream_instanced_test,Fail
 KHR-GL32.transform_feedback_overflow_query_ARB.advanced-single-stream-interleaved-attribs,Fail
 KHR-GL32.transform_feedback_overflow_query_ARB.advanced-single-stream-separate-attribs,Fail
@@ -210,16 +205,17 @@
 spec@arb_draw_indirect@arb_draw_indirect-draw-elements-prim-restart-ugly,Fail
 spec@arb_enhanced_layouts@linker@component-layout@intrastage-vs,Fail
 spec@arb_enhanced_layouts@linker@component-layout@vs-to-fs,Fail
+spec@arb_enhanced_layouts@matching_basic_types_3_loc_1,Fail
+spec@arb_enhanced_layouts@matching_fp64_types_1,Crash
+spec@arb_enhanced_layouts@matching_fp64_types_1_loc_1,Fail
+spec@arb_enhanced_layouts@matching_fp64_types_2,Crash
+spec@arb_enhanced_layouts@matching_fp64_types_2_loc_1,Fail
+spec@arb_enhanced_layouts@matching_fp64_types_3,Crash
+spec@arb_enhanced_layouts@matching_fp64_types_3_loc_1,Fail
 spec@arb_es2_compatibility@texwrap formats bordercolor,Fail
 spec@arb_es2_compatibility@texwrap formats bordercolor@GL_RGB565- border color only,Fail
 spec@arb_es2_compatibility@texwrap formats bordercolor-swizzled,Fail
 spec@arb_es2_compatibility@texwrap formats bordercolor-swizzled@GL_RGB565- swizzled- border color only,Fail
-spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@Basic,Fail
-spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic,Fail
-spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@glScissor,Fail
-spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@glViewport,Fail
-spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@MS4,Fail
-spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@Per-sample,Fail
 spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-query@Basic,Fail
 spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-query@discard,Fail
 spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-query,Fail
@@ -279,8 +275,6 @@
 spec@arb_sample_shading@samplemask 4@noms partition,Fail
 spec@arb_sample_shading@samplemask 4@sample mask_in_one,Fail
 spec@arb_seamless_cube_map@arb_seamless_cubemap,Fail
-spec@arb_shader_atomic_counters@fragment-discard,Fail
-spec@arb_shader_atomic_counters@function-argument,Fail
 spec@arb_shader_image_load_store@bitcast,Fail
 spec@arb_shader_image_load_store@bitcast@r11f_g11f_b10f to rgba8_snorm bitcast test,Fail
 spec@arb_shader_image_load_store@bitcast@r32f to rgba8_snorm bitcast test,Fail
@@ -302,131 +296,6 @@
 spec@arb_shader_image_load_store@early-z@occlusion query test/early-z pass,ExpectedFail
 spec@arb_shader_image_load_store@early-z@occlusion query test/late-z pass,Fail
 spec@arb_shader_image_load_store@execution@disable_early_z,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Pixel/WaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Pixel/WaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Pixel/WaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Pixel/WaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Pixel/WaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Pixel/WaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/one bit barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/full barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/full barrier test/4x4,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/full barrier test/64x64,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/one bit barrier test/16x16,Fail
-spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/one bit barrier test/64x64,Fail
-spec@arb_shader_image_load_store@layer,Fail
-spec@arb_shader_image_load_store@layer@image1DArray/layered binding test,Fail
-spec@arb_shader_image_load_store@layer@image1DArray/non-layered binding test,Fail
-spec@arb_shader_image_load_store@layer@image1D/layered binding test,Fail
-spec@arb_shader_image_load_store@layer@image1D/non-layered binding test,Fail
-spec@arb_shader_image_load_store@layer@image2DArray/layered binding test,Fail
-spec@arb_shader_image_load_store@layer@image2DArray/non-layered binding test,Fail
-spec@arb_shader_image_load_store@layer@image2D/layered binding test,Fail
-spec@arb_shader_image_load_store@layer@image2D/non-layered binding test,Fail
-spec@arb_shader_image_load_store@layer@image2DRect/layered binding test,Fail
-spec@arb_shader_image_load_store@layer@image2DRect/non-layered binding test,Fail
-spec@arb_shader_image_load_store@layer@image3D/layered binding test,Fail
-spec@arb_shader_image_load_store@layer@image3D/non-layered binding test,Fail
-spec@arb_shader_image_load_store@layer@imageBuffer/layered binding test,Fail
-spec@arb_shader_image_load_store@layer@imageBuffer/non-layered binding test,Fail
-spec@arb_shader_image_load_store@layer@imageCubeArray/layered binding test,Fail
-spec@arb_shader_image_load_store@layer@imageCubeArray/non-layered binding test,Fail
-spec@arb_shader_image_load_store@layer@imageCube/layered binding test,Fail
-spec@arb_shader_image_load_store@layer@imageCube/non-layered binding test,Fail
-spec@arb_shader_image_load_store@level@1DArray level binding test,Fail
-spec@arb_shader_image_load_store@level@1D level binding test,Fail
-spec@arb_shader_image_load_store@level@2DArray level binding test,Fail
-spec@arb_shader_image_load_store@level@2D level binding test,Fail
-spec@arb_shader_image_load_store@level@3D level binding test,Fail
-spec@arb_shader_image_load_store@level@CubeArray level binding test,Fail
-spec@arb_shader_image_load_store@level@Cube level binding test,Fail
-spec@arb_shader_image_load_store@level,Fail
 spec@arb_shader_image_load_store@max-images@Combined max image uniforms test,Fail
 spec@arb_shader_image_load_store@max-images,Fail
 spec@arb_shader_image_load_store@max-size,Crash
@@ -437,15 +306,9 @@
 spec@arb_shader_image_load_store@semantics@imageStore/Vertex shader/rgba32f/image1D test,Fail
 spec@arb_shader_storage_buffer_object@execution@indirect,Fail
 spec@arb_shader_storage_buffer_object@execution@ssbo-atomiccompswap-int,ExpectedFail
-spec@arb_shader_storage_buffer_object@layout-std140-write-shader,Fail
-spec@arb_shader_storage_buffer_object@layout-std430-write-shader,Fail
 spec@arb_shader_storage_buffer_object@maxblocks,Fail
-spec@arb_shader_storage_buffer_object@minmax,Fail
 spec@arb_shader_texture_lod@execution@arb_shader_texture_lod-texgradcube,ExpectedFail
 spec@arb_shader_texture_lod@execution@arb_shader_texture_lod-texgrad,ExpectedFail
-spec@arb_shader_texture_lod@execution@glsl-fs-shadow2dgradarb-07,Fail
-spec@arb_shader_texture_lod@execution@glsl-fs-shadow2dgradarb-08,Fail
-spec@arb_shader_texture_lod@execution@glsl-fs-shadow2dgradarb-cumulative,Fail
 spec@arb_shader_texture_lod@execution@tex-miplevel-selection *gradarb 1d,Fail
 spec@arb_shader_texture_lod@execution@tex-miplevel-selection *gradarb 1dshadow,Fail
 spec@arb_shader_texture_lod@execution@tex-miplevel-selection *gradarb 2d,Fail
@@ -504,8 +367,6 @@
 spec@arb_texture_float@fbo-blending-formats,Fail
 spec@arb_texture_float@fbo-blending-formats@GL_ALPHA16F_ARB,Fail
 spec@arb_texture_float@fbo-blending-formats@GL_ALPHA32F_ARB,Fail
-spec@arb_texture_float@fbo-blending-formats@GL_INTENSITY16F_ARB,Fail
-spec@arb_texture_float@fbo-blending-formats@GL_INTENSITY32F_ARB,Fail
 spec@arb_texture_float@fbo-blending-formats@GL_RGB32F,Fail
 spec@arb_texture_float@fbo-clear-formats,Fail
 spec@arb_texture_float@fbo-clear-formats@GL_ALPHA16F_ARB,Fail
@@ -546,8 +407,6 @@
 spec@arb_texture_multisample@arb_texture_multisample-dsa-texelfetch,Fail
 spec@arb_texture_multisample@arb_texture_multisample-dsa-texelfetch@Texture type: GL_RGB9_E5,Fail
 spec@arb_texture_query_lod@execution@fs-texturequerylod-nearest-biased,Fail
-spec@arb_texture_rectangle@glsl-fs-shadow2drect-07,Fail
-spec@arb_texture_rectangle@glsl-fs-shadow2drect-08,Fail
 spec@arb_texture_rectangle@texwrap rect bordercolor,Fail
 spec@arb_texture_rectangle@texwrap rect bordercolor@GL_RGBA8- border color only,Fail
 spec@arb_texture_rectangle@texwrap rect proj bordercolor,Fail
@@ -674,11 +533,6 @@
 spec@ext_framebuffer_object@fbo-blending-formats,Fail
 spec@ext_framebuffer_object@fbo-blending-formats@GL_ALPHA12,Fail
 spec@ext_framebuffer_object@fbo-blending-formats@GL_ALPHA16,Fail
-spec@ext_framebuffer_object@fbo-blending-formats@GL_INTENSITY12,Fail
-spec@ext_framebuffer_object@fbo-blending-formats@GL_INTENSITY16,Fail
-spec@ext_framebuffer_object@fbo-blending-formats@GL_INTENSITY4,Fail
-spec@ext_framebuffer_object@fbo-blending-formats@GL_INTENSITY8,Fail
-spec@ext_framebuffer_object@fbo-blending-formats@GL_INTENSITY,Fail
 spec@ext_framebuffer_object@fbo-blending-snorm,Fail
 spec@ext_framebuffer_object@fbo-clear-formats,Fail
 spec@ext_framebuffer_object@fbo-clear-formats@GL_ALPHA12,Fail
@@ -730,10 +584,6 @@
 spec@ext_texture_array@fbo-generatemipmap-array rgb9_e5,Fail
 spec@ext_texture_array@fbo-generatemipmap-array s3tc_dxt1,Fail
 spec@ext_texture_array@gen-mipmap,Fail
-spec@ext_texture_array@glsl-fs-shadow1darray-07,Fail
-spec@ext_texture_array@glsl-fs-shadow1darray-08,Fail
-spec@ext_texture_array@glsl-fs-shadow2darray-07,Fail
-spec@ext_texture_array@glsl-fs-shadow2darray-08,Fail
 spec@ext_texture_compression_rgtc@fbo-generatemipmap-formats-signed,Fail
 spec@ext_texture_compression_rgtc@fbo-generatemipmap-formats-signed@GL_COMPRESSED_SIGNED_RED_RGTC1,Fail
 spec@ext_texture_compression_rgtc@fbo-generatemipmap-formats-signed@GL_COMPRESSED_SIGNED_RED_RGTC1 NPOT,Fail
@@ -781,10 +631,6 @@
 spec@ext_texture_shared_exponent@texwrap formats bordercolor@GL_RGB9_E5- border color only,Fail
 spec@ext_texture_shared_exponent@texwrap formats bordercolor-swizzled,Fail
 spec@ext_texture_shared_exponent@texwrap formats bordercolor-swizzled@GL_RGB9_E5- swizzled- border color only,Fail
-spec@ext_texture_snorm@fbo-blending-formats,Fail
-spec@ext_texture_snorm@fbo-blending-formats@GL_INTENSITY16_SNORM,Fail
-spec@ext_texture_snorm@fbo-blending-formats@GL_INTENSITY8_SNORM,Fail
-spec@ext_texture_snorm@fbo-blending-formats@GL_INTENSITY_SNORM,Fail
 spec@ext_texture_snorm@multisample-formats 2 gl_ext_texture_snorm,Fail
 spec@ext_texture_snorm@multisample-formats 4 gl_ext_texture_snorm,Fail
 spec@ext_texture_snorm@texwrap formats bordercolor,Fail
@@ -849,12 +695,9 @@
 spec@ext_texture_srgb@texwrap formats-s3tc bordercolor-swizzled@GL_COMPRESSED_SRGB_ALPHA- swizzled- border color only,Fail
 spec@ext_texture_srgb@texwrap formats-s3tc bordercolor-swizzled@GL_COMPRESSED_SRGB_S3TC_DXT1_EXT- swizzled- border color only,Fail
 spec@ext_texture_srgb@texwrap formats-s3tc bordercolor-swizzled@GL_COMPRESSED_SRGB- swizzled- border color only,Fail
+spec@ext_transform_feedback@builtin-varyings gl_culldistance,Fail
 spec@ext_transform_feedback@immediate-reuse-index-buffer,Fail
 spec@ext_transform_feedback@immediate-reuse-uniform-buffer,Fail
-spec@glsl-1.10@execution@samplers@glsl-fs-shadow1d-07,Fail
-spec@glsl-1.10@execution@samplers@glsl-fs-shadow1d-08,Fail
-spec@glsl-1.10@execution@samplers@glsl-fs-shadow2d-07,Fail
-spec@glsl-1.10@execution@samplers@glsl-fs-shadow2d-08,Fail
 spec@glsl-1.10@execution@samplers@glsl-fs-shadow2d-clamp-z,Fail
 spec@glsl-1.20@execution@tex-miplevel-selection gl2:texture() 1d,Fail
 spec@glsl-1.20@execution@tex-miplevel-selection gl2:texture() 1dshadow,Fail
@@ -870,47 +713,6 @@
 spec@glsl-1.20@execution@tex-miplevel-selection gl2:textureproj 2dshadow,Fail
 spec@glsl-1.20@execution@tex-miplevel-selection gl2:textureproj 3d,Fail
 spec@glsl-1.30@execution@fs-texturelod-miplevels-biased,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-mixed,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backcolor-flat-distance,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backcolor-flat-fixed,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backcolor-flat-none,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backcolor-flat-vertex,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backcolor-smooth-distance,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backcolor-smooth-fixed,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backcolor-smooth-none,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backcolor-smooth-vertex,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backsecondarycolor-flat-distance,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backsecondarycolor-flat-fixed,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backsecondarycolor-flat-none,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backsecondarycolor-flat-vertex,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backsecondarycolor-smooth-distance,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backsecondarycolor-smooth-fixed,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backsecondarycolor-smooth-none,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_backsecondarycolor-smooth-vertex,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontcolor-flat-distance,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontcolor-flat-fixed,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontcolor-flat-none,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontcolor-flat-vertex,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontcolor-smooth-distance,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontcolor-smooth-fixed,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontcolor-smooth-none,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontcolor-smooth-vertex,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontsecondarycolor-flat-distance,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontsecondarycolor-flat-fixed,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontsecondarycolor-flat-none,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontsecondarycolor-flat-vertex,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontsecondarycolor-smooth-distance,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontsecondarycolor-smooth-fixed,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontsecondarycolor-smooth-none,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-gl_frontsecondarycolor-smooth-vertex,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-other-flat-distance,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-other-flat-fixed,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-other-flat-none,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-other-flat-vertex,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-other-smooth-distance,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-other-smooth-fixed,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-other-smooth-none,Fail
-spec@glsl-1.30@execution@interpolation@interpolation-noperspective-other-smooth-vertex,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection texture() 1darray,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection texture() 1darrayshadow,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection texture() 1d,Fail
@@ -920,7 +722,6 @@
 spec@glsl-1.30@execution@tex-miplevel-selection texture() 2d,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection texture() 2dshadow,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection texture() 3d,Fail
-spec@glsl-1.30@execution@tex-miplevel-selection texture(bias) 1darrayshadow,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection texture() cubearray,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection texture() cubearrayshadow,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection texture() cube,Fail
@@ -973,7 +774,6 @@
 spec@glsl-1.30@execution@tex-miplevel-selection textureoffset 2d,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection textureoffset 2dshadow,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection textureoffset 3d,Fail
-spec@glsl-1.30@execution@tex-miplevel-selection textureoffset(bias) 1darrayshadow,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection textureproj 1d,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection textureproj 1d_projvec4,Fail
 spec@glsl-1.30@execution@tex-miplevel-selection textureproj 1dshadow,Fail
@@ -1027,7 +827,6 @@
 spec@glsl-1.50@execution@geometry@primitive-id-restart gl_triangle_strip other,Fail
 spec@glsl-1.50@execution@geometry@tri-strip-ordering-with-prim-restart gl_triangle_strip_adjacency other,Fail
 spec@glsl-1.50@execution@geometry@tri-strip-ordering-with-prim-restart gl_triangle_strip other,Fail
-spec@glsl-1.50@execution@gs-also-uses-smooth-flat-noperspective,Fail
 spec@glsl-1.50@execution@primitive-id-no-gs-first-vertex,Fail
 spec@glsl-1.50@execution@primitive-id-no-gs-quads,Fail
 spec@glsl-1.50@execution@primitive-id-no-gs-quad-strip,Fail
@@ -2608,9 +2407,6 @@
 spec@!opengl 1.0@gl-1.0-logicop@GL_NOOP_MSAA,Fail
 spec@!opengl 1.0@gl-1.0-spot-light,Fail
 spec@!opengl 1.0@gl-1.0-swapbuffers-behavior,ExpectedFail
-spec@!opengl 1.0@rasterpos,Crash
-spec@!opengl 1.0@rasterpos@glsl_vs_gs_linked,Fail
-spec@!opengl 1.0@rasterpos@glsl_vs_tes_linked,Fail
 spec@!opengl 1.1@clipflat,Fail
 spec@!opengl 1.1@clipflat@glBegin/End(GL_POLYGON)- glFrontFace(GL_CCW)- glPolygonMode(GL_FILL)- quadrant: center bottom PV: FIRST,Fail
 spec@!opengl 1.1@clipflat@glBegin/End(GL_POLYGON)- glFrontFace(GL_CCW)- glPolygonMode(GL_FILL)- quadrant: center middle PV: FIRST,Fail
@@ -3306,13 +3102,15 @@
 spec@!opengl 1.1@polygon-mode-offset@config 6: Expected white pixel on right edge,Fail
 spec@!opengl 1.1@polygon-mode-offset@config 6: Expected white pixel on top edge,Fail
 spec@!opengl 1.1@polygon-mode-offset,ExpectedFail
+spec@!opengl 1.0@rasterpos,Fail
+spec@!opengl 1.0@rasterpos@glsl_vs_gs_linked,Fail
+spec@!opengl 1.0@rasterpos@glsl_vs_tes_linked,Fail
 spec@!opengl 1.1@read-front clear-front-first,Crash
 spec@!opengl 1.1@read-front clear-front-first samples=2,Crash
 spec@!opengl 1.1@read-front clear-front-first samples=4,Crash
 spec@!opengl 1.1@read-front,Crash
 spec@!opengl 1.1@read-front samples=2,Crash
 spec@!opengl 1.1@read-front samples=4,ExpectedFail
-spec@!opengl 1.1@streaming-texture-leak,Crash
 spec@!opengl 1.1@teximage-colors gl_alpha16@Exact upload-download of GL_ALPHA16,Fail
 spec@!opengl 1.1@teximage-colors gl_r16_snorm@Exact upload-download of GL_R16_SNORM,Fail
 spec@!opengl 1.1@teximage-colors gl_r8_snorm@Exact upload-download of GL_R8_SNORM,Fail
@@ -3413,7 +3211,6 @@
 spec@!opengl 2.0@gl-2.0-large-point-fs,Fail
 spec@!opengl 2.0@gl-2.0-vertexattribpointer,Fail
 spec@!opengl 2.0@occlusion-query-discard,Fail
-spec@!opengl 3.0@required-texture-attachment-formats,Fail
 spec@!opengl 3.0@sampler-cube-shadow,Fail
 spec@!opengl 3.2@gl-3.2-adj-prims cull-back pv-first,ExpectedFail
 spec@!opengl 3.2@gl-3.2-adj-prims cull-front pv-first,ExpectedFail
diff --git a/.gitlab-ci/expectations/virt/virgl-gles-flakes.txt b/.gitlab-ci/expectations/virt/virgl-gles-flakes.txt
index b791a97..5008760 100644
--- a/.gitlab-ci/expectations/virt/virgl-gles-flakes.txt
+++ b/.gitlab-ci/expectations/virt/virgl-gles-flakes.txt
@@ -27,8 +27,12 @@
 spec@arb_depth_texture@depthstencil-render-miplevels 585 d=z16
 spec@arb_fragment_layer_viewport@layer-gs-writes-in-range
 spec@arb_fragment_layer_viewport@viewport-gs-writes-in-range
+spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@Basic
+spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic
 spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@glScissor
+spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@glViewport
 spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@MS4
+spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-atomic@Per-sample
 spec@arb_framebuffer_no_attachments@arb_framebuffer_no_attachments-roundup-samples
 spec@arb_framebuffer_object@arb_framebuffer_object-depth-stencil-blit stencil gl_stencil_index1
 spec@arb_framebuffer_srgb@blit renderbuffer linear_to_srgb upsample disabled clear
@@ -42,6 +46,8 @@
 spec@arb_gpu_shader5@texturegatheroffset@vs-r-0-unorm-2darray
 spec@arb_gpu_shader5@texturegatheroffset@vs-rgb-2-uint-2drect-const
 spec@arb_shader_atomic_counter_ops@execution@add
+spec@arb_shader_atomic_counters@fragment-discard
+spec@arb_shader_atomic_counters@function-argument
 spec@arb_shader_image_load_store@atomicity
 spec@arb_shader_image_load_store@atomicity@imageAtomicAdd
 spec@arb_shader_image_load_store@atomicity@imageAtomicAnd
@@ -51,16 +57,6 @@
 spec@arb_shader_image_load_store@atomicity@imageAtomicMin
 spec@arb_shader_image_load_store@atomicity@imageAtomicOr
 spec@arb_shader_image_load_store@atomicity@imageAtomicXor
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/full barrier test/4x4
-spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/one bit barrier test/4x4
-spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/full barrier test/4x4
-spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/full barrier test/4x4
-spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/one bit barrier test/4x4
-spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/full barrier test/4x4
-spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/one bit barrier test/4x4
-spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/full barrier test/4x4
-spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/full barrier test/4x4
-spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/full barrier test/4x4
 spec@arb_shader_precision@fs-op-assign-div-vec3-float
 spec@arb_shader_storage_buffer_object@execution@memory-layouts-struct-deref
 spec@arb_shader_storage_buffer_object@execution@ssbo-atomicadd-int
@@ -72,6 +68,7 @@
 spec@arb_texture_view@rendering-target@1D view rendering
 spec@arb_timer_query@query gl_timestamp
 spec@arb_timer_query@timestamp-get
+spec@ext_timer_query@time-elapsed
 spec@arb_uniform_buffer_object@rendering-array
 spec@ext_framebuffer_blit@fbo-blit-check-limits
 spec@ext_framebuffer_blit@fbo-sys-blit
diff --git a/.gitlab-ci/expectations/virt/virgl-gles-skips.txt b/.gitlab-ci/expectations/virt/virgl-gles-skips.txt
index eb20f5f..c3ed979 100644
--- a/.gitlab-ci/expectations/virt/virgl-gles-skips.txt
+++ b/.gitlab-ci/expectations/virt/virgl-gles-skips.txt
@@ -13,8 +13,6 @@
 # Fails on iris too
 spec@arb_direct_state_access@gettextureimage-formats
 
-spec@arb_texture_buffer_object@formats (fs- arb)*
-spec@arb_texture_buffer_object@formats (vs- arb)*
 spec@nv_primitive_restart@primitive-restart-draw-mode-polygon
 spec@nv_primitive_restart@primitive-restart-draw-mode-quad_strip
 spec@nv_primitive_restart@primitive-restart-draw-mode-quads
@@ -41,3 +39,143 @@
 
 # GLES doesn't support more than one stream
 spec@arb_enhanced_layouts@gs-stream-location-aliasing
+
+
+# All these tests use a RGBA32F RW image and this is not supported on GLES
+# so skip the tests
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/WaR/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/RaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Buffer update/WaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/RaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Framebuffer/WaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Image/WaR/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Pixel/RaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/RaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Texture update/WaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/full barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/full barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/one bit barrier test/16x16
+spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/one bit barrier test/64x64
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Atomic counter/RaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Element array/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Image/RaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Indirect/RaW/one bit barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Texture fetch/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Uniform buffer/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@host-mem-barrier@Vertex array/RaW/full barrier test/4x4
+spec@arb_shader_image_load_store@layer
+spec@arb_shader_image_load_store@layer@image1DArray/layered binding test
+spec@arb_shader_image_load_store@layer@image1DArray/non-layered binding test
+spec@arb_shader_image_load_store@layer@image1D/layered binding test
+spec@arb_shader_image_load_store@layer@image1D/non-layered binding test
+spec@arb_shader_image_load_store@layer@image2DArray/layered binding test
+spec@arb_shader_image_load_store@layer@image2DArray/non-layered binding test
+spec@arb_shader_image_load_store@layer@image2D/layered binding test
+spec@arb_shader_image_load_store@layer@image2D/non-layered binding test
+spec@arb_shader_image_load_store@layer@image2DRect/layered binding test
+spec@arb_shader_image_load_store@layer@image2DRect/non-layered binding test
+spec@arb_shader_image_load_store@layer@image3D/layered binding test
+spec@arb_shader_image_load_store@layer@image3D/non-layered binding test
+spec@arb_shader_image_load_store@layer@imageBuffer/layered binding test
+spec@arb_shader_image_load_store@layer@imageBuffer/non-layered binding test
+spec@arb_shader_image_load_store@layer@imageCubeArray/layered binding test
+spec@arb_shader_image_load_store@layer@imageCubeArray/non-layered binding test
+spec@arb_shader_image_load_store@layer@imageCube/layered binding test
+spec@arb_shader_image_load_store@layer@imageCube/non-layered binding test
+spec@arb_shader_image_load_store@level@1DArray level binding test
+spec@arb_shader_image_load_store@level@1D level binding test
+spec@arb_shader_image_load_store@level@2DArray level binding test
+spec@arb_shader_image_load_store@level@2D level binding test
+spec@arb_shader_image_load_store@level@3D level binding test
+spec@arb_shader_image_load_store@level@CubeArray level binding test
+spec@arb_shader_image_load_store@level@Cube level binding test
+spec@arb_shader_image_load_store@level
diff --git a/.gitlab-ci/meson/build.sh b/.gitlab-ci/meson/build.sh
index d508b59..6d333cd 100755
--- a/.gitlab-ci/meson/build.sh
+++ b/.gitlab-ci/meson/build.sh
@@ -71,6 +71,9 @@
     ${DRI_LOADERS} \
     ${GALLIUM_ST} \
     -D tests=true \
+    -D render-server=true \
+    -D render-server-worker=process \
+    -D venus-experimental=true \
     --fatal-meson-warnings \
     ${EXTRA_OPTION} && \
 pushd _build && \
diff --git a/METADATA b/METADATA
index a517e62..0c2157a 100644
--- a/METADATA
+++ b/METADATA
@@ -1,10 +1,9 @@
-name: "virglrenderer"
-description:
-    "Virgil is a research project to investigate the possibility of creating a "
-    "virtual 3D GPU for use inside qemu virtual machines, that allows the guest "
-    "operating system to use the capabilities of the host GPU to accelerate 3D "
-    "rendering."
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update virglrenderer
+# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
 
+name: "virglrenderer"
+description: "Virgil is a research project to investigate the possibility of creating a virtual 3D GPU for use inside qemu virtual machines, that allows the guest operating system to use the capabilities of the host GPU to accelerate 3D rendering."
 third_party {
   url {
     type: HOMEPAGE
@@ -14,7 +13,11 @@
     type: GIT
     value: "https://anongit.freedesktop.org/git/virglrenderer.git"
   }
-  version: "master"
+  version: "0.10.4"
   license_type: NOTICE
-  last_upgrade_date { year: 2018 month: 4 day: 10 }
+  last_upgrade_date {
+    year: 2023
+    month: 1
+    day: 18
+  }
 }
diff --git a/config.h.meson b/config.h.meson
index e995c9d..b25a86b 100644
--- a/config.h.meson
+++ b/config.h.meson
@@ -44,6 +44,7 @@
 #mesondefine RENDER_SERVER_EXEC_PATH
 #mesondefine HAVE_EVENTFD_H
 #mesondefine HAVE_DLFCN_H
+#mesondefine ENABLE_VIDEO
 #mesondefine ENABLE_TRACING
 #mesondefine UTIL_ARCH_LITTLE_ENDIAN
 #mesondefine UTIL_ARCH_BIG_ENDIAN
diff --git a/meson.build b/meson.build
index bd5ac88..ddb74da 100644
--- a/meson.build
+++ b/meson.build
@@ -23,7 +23,7 @@
 
 project(
    'virglrenderer', 'c',
-   version: '0.9.0',
+   version: '0.10.4',
    license : 'MIT',
    meson_version : '>= 0.53',
    default_options : ['buildtype=release', 'b_ndebug=if-release',
@@ -37,10 +37,9 @@
 #    interface age
 # 3. If the ABI has changed in an incompatible way increment the binary_age
 #    and set revision and interface_age to zero
-
 binary_age    = 1
-interface_age = 5
-revision      = 3
+interface_age = 7
+revision      = 7
 
 cc = meson.get_compiler('c')
 
@@ -52,6 +51,7 @@
    '-Werror=implicit-function-declaration',
    '-Werror=missing-prototypes',
    '-Wmissing-prototypes',
+   '-Werror=incompatible-pointer-types',
    '-Werror=int-to-pointer-cast',
    '-Wno-overlength-strings',
 ]
@@ -72,7 +72,7 @@
 m_dep = cc.find_library('m', required : false)
 
 conf_data = configuration_data()
-conf_data.set('VERSION', '0.8.1')
+conf_data.set('VERSION', meson.project_version())
 conf_data.set('_GNU_SOURCE', 1)
 conf_data.set('VIRGL_RENDERER_UNSTABLE_APIS', 1)
 
@@ -280,6 +280,13 @@
    endif
 endif
 
+with_video = get_option('video')
+if with_video
+  conf_data.set('ENABLE_VIDEO', 1)
+  libva_dep = dependency('libva')
+  libvadrm_dep = dependency('libva-drm')
+endif
+
 configure_file(input : 'config.h.meson',
                output : 'config.h',
                configuration : conf_data)
@@ -316,6 +323,7 @@
         'drm-msm': with_drm_msm,
         'render server': with_render_server,
         'render server worker': with_render_server ? with_render_server_worker : 'none',
+        'video': with_video,
         'tests': with_tests,
         'fuzzer': with_fuzzer,
         'tracing': with_tracing,
diff --git a/meson_options.txt b/meson_options.txt
index 8ead613..cb77406 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -85,6 +85,13 @@
 )
 
 option(
+  'video',
+  type : 'boolean',
+  value : 'false',
+  description : 'enable support for hardware video acceleration'
+)
+
+option(
   'tests',
   type : 'boolean',
   value : 'false',
diff --git a/server/render_virgl.c b/server/render_virgl.c
index 6cc82ac..fb6b5b7 100644
--- a/server/render_virgl.c
+++ b/server/render_virgl.c
@@ -70,13 +70,12 @@
 static void
 render_virgl_cb_write_context_fence(UNUSED void *cookie,
                                     uint32_t ctx_id,
-                                    uint64_t queue_id,
+                                    uint32_t ring_idx,
                                     uint64_t fence_id)
 {
    struct render_context *ctx = render_virgl_lookup_context(ctx_id);
    assert(ctx);
 
-   const uint32_t ring_idx = queue_id;
    const uint32_t seqno = (uint32_t)fence_id;
    render_context_update_timeline(ctx, ring_idx, seqno);
 }
diff --git a/src/drm/msm/msm_proto.h b/src/drm/msm/msm_proto.h
index 0c8377c..9279475 100644
--- a/src/drm/msm/msm_proto.h
+++ b/src/drm/msm/msm_proto.h
@@ -226,14 +226,6 @@
  * kernel side (ugg).. need to come up with a better story for fencing.
  * We probably need to sort something out for that to handle syncobjs.
  *
- * Note that the bo handles referenced are the host handles, so that
- * they can be directly passed to the host kernel without translation.
- *
- * TODO we can pack the payload tighter (and enforce no-relocs) if we
- * defined our own structs, at the cost of host userspace having to
- * do a bit more work.  Is it worth it?  It could probably be done
- * without extra overhead in guest userspace..
- *
  * No response.
  */
 struct msm_ccmd_gem_submit_req {
@@ -245,16 +237,17 @@
    uint32_t nr_cmds;
 
    /**
-    * What userspace expects the next seqno fence to be.  To avoid having
-    * to wait for host, the guest tracks what it expects to be the next
-    * returned seqno fence.  This is passed to guest just for error
-    * checking.
+    * The fence "seqno" assigned by the guest userspace.  The host SUBMIT
+    * ioctl uses the MSM_SUBMIT_FENCE_SN_IN flag to let the guest assign
+    * the sequence #, to avoid the guest needing to wait for a response
+    * from the host.
     */
    uint32_t fence;
 
    /**
     * Payload is first an array of 'struct drm_msm_gem_submit_bo' of
-    * length determined by nr_bos (note that handles are host handles),
+    * length determined by nr_bos (note that handles are guest resource
+    * ids which are translated to host GEM handles by the host VMM),
     * followed by an array of 'struct drm_msm_gem_submit_cmd' of length
     * determined by nr_cmds
     */
@@ -276,7 +269,7 @@
    uint32_t pad;
    uint32_t off;
 
-   /* Note: packet size aligned to 4 bytes, so the string name may
+   /* Note: packet size aligned to 4 bytes, so the payload may
     * be shorter than the packet header indicates.
     */
    uint32_t len;
diff --git a/src/drm/msm/msm_renderer.c b/src/drm/msm/msm_renderer.c
index 84684f4..a032ad3 100644
--- a/src/drm/msm/msm_renderer.c
+++ b/src/drm/msm/msm_renderer.c
@@ -131,6 +131,7 @@
    bool exported   : 1;
    bool exportable : 1;
    struct virgl_resource *res;
+   void *map;
 };
 
 static struct msm_object *
@@ -419,6 +420,9 @@
 
    msm_remove_object(mctx, obj);
 
+   if (obj->map)
+      munmap(obj->map, obj->size);
+
    gem_close(mctx->fd, obj->handle);
 
    free(obj);
@@ -762,7 +766,15 @@
    }
 
    uint64_t iova = req->iova;
-   ret = gem_info(mctx, obj->handle, MSM_INFO_SET_IOVA, &iova);
+   if (iova) {
+      TRACE_SCOPE_BEGIN("SET_IOVA");
+      ret = gem_info(mctx, obj->handle, MSM_INFO_SET_IOVA, &iova);
+      TRACE_SCOPE_END("SET_IOVA");
+   } else {
+      TRACE_SCOPE_BEGIN("CLEAR_IOVA");
+      ret = gem_info(mctx, obj->handle, MSM_INFO_SET_IOVA, &iova);
+      TRACE_SCOPE_END("CLEAR_IOVA");
+   }
    if (ret) {
       drm_log("SET_IOVA failed: %d (%s)", ret, strerror(errno));
       goto out_error;
@@ -916,18 +928,15 @@
 }
 
 static int
-msm_ccmd_gem_upload(struct msm_context *mctx, const struct msm_ccmd_req *hdr)
+map_object(struct msm_context *mctx, struct msm_object *obj)
 {
-   const struct msm_ccmd_gem_upload_req *req = to_msm_ccmd_gem_upload_req(hdr);
    uint64_t offset;
    int ret;
 
-   if (req->pad || !valid_payload_len(req)) {
-      drm_log("Invalid upload ccmd");
-      return -EINVAL;
-   }
+   if (obj->map)
+      return 0;
 
-   uint32_t handle = handle_from_res_id(mctx, req->res_id);
+   uint32_t handle = handle_from_res_id(mctx, obj->res_id);
    ret = gem_info(mctx, handle, MSM_INFO_GET_OFFSET, &offset);
    if (ret) {
       drm_log("alloc failed: %s", strerror(errno));
@@ -935,15 +944,39 @@
    }
 
    uint8_t *map =
-      mmap(0, req->len + req->off, PROT_READ | PROT_WRITE, MAP_SHARED, mctx->fd, offset);
+      mmap(0, obj->size, PROT_READ | PROT_WRITE, MAP_SHARED, mctx->fd, offset);
    if (map == MAP_FAILED) {
       drm_log("mmap failed: %s", strerror(errno));
       return -ENOMEM;
    }
 
-   memcpy(&map[req->off], req->payload, req->len);
+   obj->map = map;
 
-   munmap(map, req->len);
+   return 0;
+}
+
+static int
+msm_ccmd_gem_upload(struct msm_context *mctx, const struct msm_ccmd_req *hdr)
+{
+   const struct msm_ccmd_gem_upload_req *req = to_msm_ccmd_gem_upload_req(hdr);
+   int ret;
+
+   if (req->pad || !valid_payload_len(req)) {
+      drm_log("Invalid upload ccmd");
+      return -EINVAL;
+   }
+
+   struct msm_object *obj = msm_get_object_from_res_id(mctx, req->res_id);
+   if (!obj) {
+      drm_log("No obj: res_id=%u", req->res_id);
+      return -ENOENT;
+   }
+
+   ret = map_object(mctx, obj);
+   if (ret)
+      return ret;
+
+   memcpy(&obj->map[req->off], req->payload, req->len);
 
    return 0;
 }
@@ -1078,6 +1111,8 @@
    drm_dbg("%s: hdr={cmd=%u, len=%u, seqno=%u, rsp_off=0x%x)", ccmd->name, hdr->cmd,
            hdr->len, hdr->seqno, hdr->rsp_off);
 
+   TRACE_SCOPE_BEGIN(ccmd->name);
+
    /* If the request length from the guest is smaller than the expected
     * size, ie. newer host and older guest, we need to make a copy of
     * the request with the new fields at the end zero initialized.
@@ -1093,6 +1128,8 @@
       ret = ccmd->handler(mctx, hdr);
    }
 
+   TRACE_SCOPE_END(ccmd->name);
+
    if (ret) {
       drm_log("%s: dispatch failed: %d (%s)", ccmd->name, ret, strerror(errno));
       return ret;
@@ -1180,17 +1217,17 @@
 }
 
 static int
-msm_renderer_submit_fence(struct virgl_context *vctx, uint32_t flags, uint64_t queue_id,
+msm_renderer_submit_fence(struct virgl_context *vctx, uint32_t flags, uint32_t ring_idx,
                           uint64_t fence_id)
 {
    struct msm_context *mctx = to_msm_context(vctx);
 
-   drm_dbg("flags=0x%x, queue_id=%" PRIu64 ", fence_id=%" PRIu64, flags,
-           queue_id, fence_id);
+   drm_dbg("flags=0x%x, ring_idx=%" PRIu32 ", fence_id=%" PRIu64, flags,
+           ring_idx, fence_id);
 
-   /* timeline is queue_id-1 (because queue_id 0 is host CPU timeline) */
-   if (queue_id > nr_timelines) {
-      drm_log("invalid queue_id: %" PRIu64, queue_id);
+   /* timeline is ring_idx-1 (because ring_idx 0 is host CPU timeline) */
+   if (ring_idx > nr_timelines) {
+      drm_log("invalid ring_idx: %" PRIu32, ring_idx);
       return -EINVAL;
    }
 
@@ -1198,12 +1235,12 @@
     * meaning by the time ->submit_fence() is called, the fence has
     * already passed.. so just immediate signal:
     */
-   if (queue_id == 0) {
-      vctx->fence_retire(vctx, queue_id, fence_id);
+   if (ring_idx == 0) {
+      vctx->fence_retire(vctx, ring_idx, fence_id);
       return 0;
    }
 
-   return drm_timeline_submit_fence(&mctx->timelines[queue_id - 1], flags, fence_id);
+   return drm_timeline_submit_fence(&mctx->timelines[ring_idx - 1], flags, fence_id);
 }
 
 struct virgl_context *
diff --git a/src/gallium/auxiliary/tgsi/tgsi_build.c b/src/gallium/auxiliary/tgsi/tgsi_build.c
index b06806d..e3b4157 100644
--- a/src/gallium/auxiliary/tgsi/tgsi_build.c
+++ b/src/gallium/auxiliary/tgsi/tgsi_build.c
@@ -379,6 +379,8 @@
 {
    struct tgsi_full_declaration  full_declaration;
 
+   full_declaration.Dim.Index2D = 0;
+   full_declaration.Dim.Padding = 0;
    full_declaration.Declaration  = tgsi_default_declaration();
    full_declaration.Range = tgsi_default_declaration_range();
    full_declaration.Semantic = tgsi_default_declaration_semantic();
diff --git a/src/gallium/auxiliary/tgsi/tgsi_info.c b/src/gallium/auxiliary/tgsi/tgsi_info.c
index d4529b1..87b5c34 100644
--- a/src/gallium/auxiliary/tgsi/tgsi_info.c
+++ b/src/gallium/auxiliary/tgsi/tgsi_info.c
@@ -385,6 +385,7 @@
    case TGSI_OPCODE_BREV:
    case TGSI_OPCODE_D2U:
    case TGSI_OPCODE_CLOCK:
+   case TGSI_OPCODE_UADD:
       return TGSI_TYPE_UNSIGNED;
    case TGSI_OPCODE_ARL:
    case TGSI_OPCODE_ARR:
@@ -401,7 +402,6 @@
    case TGSI_OPCODE_ISGE:
    case TGSI_OPCODE_ISHR:
    case TGSI_OPCODE_ISLT:
-   case TGSI_OPCODE_UADD:
    case TGSI_OPCODE_UARL:
    case TGSI_OPCODE_IABS:
    case TGSI_OPCODE_ISSG:
diff --git a/src/gallium/auxiliary/tgsi/tgsi_text.c b/src/gallium/auxiliary/tgsi/tgsi_text.c
index f7bf032..84443fd 100644
--- a/src/gallium/auxiliary/tgsi/tgsi_text.c
+++ b/src/gallium/auxiliary/tgsi/tgsi_text.c
@@ -580,7 +580,7 @@
    struct parsed_bracket *brackets)
 {
    const char *cur;
-   uint uindex;
+   int index;
 
    memset(brackets, 0, sizeof(struct parsed_bracket));
 
@@ -624,11 +624,11 @@
          brackets->index = 0;
    }
    else {
-      if (!parse_uint( &ctx->cur, &uindex )) {
-         report_error( ctx, "Expected literal unsigned integer" );
+      if (!parse_int( &ctx->cur, &index )) {
+         report_error( ctx, "Expected literal integer" );
          return FALSE;
       }
-      brackets->index = (int) uindex;
+      brackets->index = index;
       brackets->ind_file = TGSI_FILE_NULL;
       brackets->ind_index = 0;
    }
diff --git a/src/gallium/auxiliary/util/u_format.csv b/src/gallium/auxiliary/util/u_format.csv
index 1d743a6..f6e528a 100644
--- a/src/gallium/auxiliary/util/u_format.csv
+++ b/src/gallium/auxiliary/util/u_format.csv
@@ -114,6 +114,7 @@
 PIPE_FORMAT_L8_SRGB               , plain, 1, 1, un8 ,     ,     ,     , xxx1, srgb 
 PIPE_FORMAT_R8_SRGB               , plain, 1, 1, un8 ,     ,     ,     , x001, srgb
 PIPE_FORMAT_L8A8_SRGB             , plain, 1, 1, un8 , un8 ,     ,     , xxxy, srgb 
+PIPE_FORMAT_R8G8_SRGB             , plain, 1, 1, un8 , un8 ,     ,     , xy01, srgb
 PIPE_FORMAT_R8G8B8_SRGB           , plain, 1, 1, un8 , un8 , un8 ,     , xyz1, srgb 
 PIPE_FORMAT_R8G8B8A8_SRGB         , plain, 1, 1, un8 , un8 , un8 , un8 , xyzw, srgb 
 PIPE_FORMAT_A8B8G8R8_SRGB         , plain, 1, 1, un8 , un8 , un8 , un8 , wzyx, srgb
diff --git a/src/gallium/auxiliary/util/u_hash_table.c b/src/gallium/auxiliary/util/u_hash_table.c
index 095112a..2b7a67d 100644
--- a/src/gallium/auxiliary/util/u_hash_table.c
+++ b/src/gallium/auxiliary/util/u_hash_table.c
@@ -46,136 +46,66 @@
 #include "util/u_memory.h"
 #include "util/u_pointer.h"
 #include "util/u_hash_table.h"
+#include "util/hash_table.h"
+#include "ralloc.h"
 
 
 struct util_hash_table
 {
-   struct cso_hash *cso;   
-   
-   /** Hash function */
-   unsigned (*hash)(void *key);
-   
-   /** Compare two keys */
-   int (*compare)(void *key1, void *key2);
+   struct hash_table table;
    
    /** free value */
    void (*destroy)(void *value);
 };
 
-
-struct util_hash_table_item
-{
-   void *key;
-   void *value;
-};
-
-
-static inline struct util_hash_table_item *
-util_hash_table_item(struct cso_hash_iter iter)
-{
-   return (struct util_hash_table_item *)cso_hash_iter_data(iter);
-}
-
-
 struct util_hash_table *
-util_hash_table_create(unsigned (*hash)(void *key),
-                       int (*compare)(void *key1, void *key2),
+util_hash_table_create(uint32_t (*hash)(const void *key),
+                       bool (*equal)(const void *key1, const void *key2),
                        void (*destroy)(void *value))
 {
    struct util_hash_table *ht;
    
-   ht = MALLOC_STRUCT(util_hash_table);
+   ht = ralloc(NULL, struct util_hash_table);
    if(!ht)
       return NULL;
    
-   ht->cso = cso_hash_create();
-   if(!ht->cso) {
-      FREE(ht);
+   if (!_mesa_hash_table_init(&ht->table, ht, hash, equal)) {
+      ralloc_free(ht);
       return NULL;
    }
    
-   ht->hash = hash;
-   ht->compare = compare;
    ht->destroy = destroy;
    
    return ht;
 }
 
-
-static inline struct cso_hash_iter
-util_hash_table_find_iter(struct util_hash_table *ht,
-                          void *key,
-                          unsigned key_hash)
-{
-   struct cso_hash_iter iter;
-   struct util_hash_table_item *item;
-   
-   iter = cso_hash_find(ht->cso, key_hash);
-   while (!cso_hash_iter_is_null(iter)) {
-      item = (struct util_hash_table_item *)cso_hash_iter_data(iter);
-      if (!ht->compare(item->key, key))
-         break;
-      iter = cso_hash_iter_next(iter);
-   }
-   
-   return iter;
-}
-
-
-static inline struct util_hash_table_item *
-util_hash_table_find_item(struct util_hash_table *ht,
-                          void *key,
-                          unsigned key_hash)
-{
-   struct cso_hash_iter iter;
-   struct util_hash_table_item *item;
-   
-   iter = cso_hash_find(ht->cso, key_hash);
-   while (!cso_hash_iter_is_null(iter)) {
-      item = (struct util_hash_table_item *)cso_hash_iter_data(iter);
-      if (!ht->compare(item->key, key))
-         return item;
-      iter = cso_hash_iter_next(iter);
-   }
-   
-   return NULL;
-}
-
-
 enum pipe_error
 util_hash_table_set(struct util_hash_table *ht,
                     void *key,
                     void *value)
 {
-   unsigned key_hash;
-   struct util_hash_table_item *item;
-   struct cso_hash_iter iter;
+   uint32_t key_hash;
+   struct hash_entry *item;
 
    assert(ht);
    if (!ht)
       return PIPE_ERROR_BAD_INPUT;
 
-   key_hash = ht->hash(key);
+   if (!key)
+      return PIPE_ERROR_BAD_INPUT;
 
-   item = util_hash_table_find_item(ht, key, key_hash);
+   key_hash = ht->table.key_hash_function(key);
+
+   item = _mesa_hash_table_search_pre_hashed(&ht->table, key_hash, key);
    if(item) {
-      ht->destroy(item->value);
-      item->value = value;
+      ht->destroy(item->data);
+      item->data = value;
       return PIPE_OK;
    }
-   
-   item = MALLOC_STRUCT(util_hash_table_item);
+
+   item = _mesa_hash_table_insert_pre_hashed(&ht->table, key_hash, key, value);
    if(!item)
       return PIPE_ERROR_OUT_OF_MEMORY;
-   
-   item->key = key;
-   item->value = value;
-   
-   iter = cso_hash_insert(ht->cso, key_hash, item);
-   if(cso_hash_iter_is_null(iter)) {
-      FREE(item);
-      return PIPE_ERROR_OUT_OF_MEMORY;
-   }
 
    return PIPE_OK;
 }
@@ -185,20 +115,20 @@
 util_hash_table_get(struct util_hash_table *ht,
                     void *key)
 {
-   unsigned key_hash;
-   struct util_hash_table_item *item;
+   struct hash_entry *item;
 
    assert(ht);
    if (!ht)
       return NULL;
 
-   key_hash = ht->hash(key);
+   if (!key)
+      return NULL;
 
-   item = util_hash_table_find_item(ht, key, key_hash);
+   item = _mesa_hash_table_search(&ht->table, key);
    if(!item)
       return NULL;
-   
-   return item->value;
+
+   return item->data;
 }
 
 
@@ -206,46 +136,36 @@
 util_hash_table_remove(struct util_hash_table *ht,
                        void *key)
 {
-   unsigned key_hash;
-   struct cso_hash_iter iter;
-   struct util_hash_table_item *item;
+   struct hash_entry *item;
 
    assert(ht);
    if (!ht)
       return;
 
-   key_hash = ht->hash(key);
-
-   iter = util_hash_table_find_iter(ht, key, key_hash);
-   if(cso_hash_iter_is_null(iter))
+   if (!key)
       return;
-   
-   item = util_hash_table_item(iter);
-   assert(item);
-   ht->destroy(item->value);
-   FREE(item);
-   
-   cso_hash_erase(ht->cso, iter);
+
+   item = _mesa_hash_table_search(&ht->table, key);
+   if (!item)
+      return;
+
+   ht->destroy(item->data);
+   _mesa_hash_table_remove(&ht->table, item);
 }
 
 
 void 
 util_hash_table_clear(struct util_hash_table *ht)
 {
-   struct cso_hash_iter iter;
-   struct util_hash_table_item *item;
-
    assert(ht);
    if (!ht)
       return;
 
-   iter = cso_hash_first_node(ht->cso);
-   while (!cso_hash_iter_is_null(iter)) {
-      item = (struct util_hash_table_item *)cso_hash_take(ht->cso, cso_hash_iter_key(iter));
-      ht->destroy(item->value);
-      FREE(item);
-      iter = cso_hash_first_node(ht->cso);
+   hash_table_foreach(&ht->table, item) {
+      ht->destroy(item->data);
    }
+
+   _mesa_hash_table_clear(&ht->table, NULL);
 }
 
 
@@ -255,21 +175,14 @@
                         (void *key, void *value, void *data),
                      void *data)
 {
-   struct cso_hash_iter iter;
-   struct util_hash_table_item *item;
-   enum pipe_error result;
-
    assert(ht);
    if (!ht)
       return PIPE_ERROR_BAD_INPUT;
 
-   iter = cso_hash_first_node(ht->cso);
-   while (!cso_hash_iter_is_null(iter)) {
-      item = (struct util_hash_table_item *)cso_hash_iter_data(iter);
-      result = callback(item->key, item->value, data);
-      if(result != PIPE_OK)
-	 return result;
-      iter = cso_hash_iter_next(iter);
+   hash_table_foreach(&ht->table, item) {
+      enum pipe_error result = callback((void *)item->key, item->data, data);
+      if (result != PIPE_OK)
+         return result;
    }
 
    return PIPE_OK;
@@ -279,22 +192,13 @@
 void
 util_hash_table_destroy(struct util_hash_table *ht)
 {
-   struct cso_hash_iter iter;
-   struct util_hash_table_item *item;
-
    assert(ht);
    if (!ht)
       return;
 
-   iter = cso_hash_first_node(ht->cso);
-   while (!cso_hash_iter_is_null(iter)) {
-      item = (struct util_hash_table_item *)cso_hash_iter_data(iter);
-      ht->destroy(item->value);
-      FREE(item);
-      iter = cso_hash_iter_next(iter);
+   hash_table_foreach(&ht->table, item) {
+      ht->destroy(item->data);
    }
 
-   cso_hash_delete(ht->cso);
-   
-   FREE(ht);
+   ralloc_free(ht);
 }
diff --git a/src/gallium/auxiliary/util/u_hash_table.h b/src/gallium/auxiliary/util/u_hash_table.h
index b4a887b..0848157 100644
--- a/src/gallium/auxiliary/util/u_hash_table.h
+++ b/src/gallium/auxiliary/util/u_hash_table.h
@@ -56,8 +56,8 @@
  * @param compare should return 0 for two equal keys.
  */
 struct util_hash_table *
-util_hash_table_create(unsigned (*hash)(void *key),
-                       int (*compare)(void *key1, void *key2),
+util_hash_table_create(uint32_t (*hash)(const void *key),
+                       bool (*equal)(const void *key1, const void *key2),
                        void (*destroy)(void *value));
 
 
diff --git a/src/gallium/include/pipe/p_format.h b/src/gallium/include/pipe/p_format.h
index 3e2d9ab..ff35c1e 100644
--- a/src/gallium/include/pipe/p_format.h
+++ b/src/gallium/include/pipe/p_format.h
@@ -134,6 +134,7 @@
 /* sRGB formats */
 #define PIPE_FORMAT_L8_SRGB VIRGL_FORMAT_L8_SRGB
 #define PIPE_FORMAT_L8A8_SRGB VIRGL_FORMAT_L8A8_SRGB
+#define PIPE_FORMAT_R8G8_SRGB VIRGL_FORMAT_R8G8_SRGB
 #define PIPE_FORMAT_R8G8B8_SRGB VIRGL_FORMAT_R8G8B8_SRGB
 #define PIPE_FORMAT_A8B8G8R8_SRGB VIRGL_FORMAT_A8B8G8R8_SRGB
 #define PIPE_FORMAT_X8B8G8R8_SRGB VIRGL_FORMAT_X8B8G8R8_SRGB
diff --git a/src/gallium/include/pipe/p_video_enums.h b/src/gallium/include/pipe/p_video_enums.h
new file mode 100644
index 0000000..f785352
--- /dev/null
+++ b/src/gallium/include/pipe/p_video_enums.h
@@ -0,0 +1,148 @@
+/**************************************************************************
+ *
+ * Copyright 2009 Younes Manton.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef PIPE_VIDEO_ENUMS_H
+#define PIPE_VIDEO_ENUMS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum pipe_video_format
+{
+   PIPE_VIDEO_FORMAT_UNKNOWN = 0,
+   PIPE_VIDEO_FORMAT_MPEG12,   /**< MPEG1, MPEG2 */
+   PIPE_VIDEO_FORMAT_MPEG4,    /**< DIVX, XVID */
+   PIPE_VIDEO_FORMAT_VC1,      /**< WMV */
+   PIPE_VIDEO_FORMAT_MPEG4_AVC,/**< H.264 */
+   PIPE_VIDEO_FORMAT_HEVC,     /**< H.265 */
+   PIPE_VIDEO_FORMAT_JPEG,     /**< JPEG */
+   PIPE_VIDEO_FORMAT_VP9,      /**< VP9 */
+   PIPE_VIDEO_FORMAT_AV1       /**< AV1 */
+};
+
+enum pipe_video_profile
+{
+   PIPE_VIDEO_PROFILE_UNKNOWN,
+   PIPE_VIDEO_PROFILE_MPEG1,
+   PIPE_VIDEO_PROFILE_MPEG2_SIMPLE,
+   PIPE_VIDEO_PROFILE_MPEG2_MAIN,
+   PIPE_VIDEO_PROFILE_MPEG4_SIMPLE,
+   PIPE_VIDEO_PROFILE_MPEG4_ADVANCED_SIMPLE,
+   PIPE_VIDEO_PROFILE_VC1_SIMPLE,
+   PIPE_VIDEO_PROFILE_VC1_MAIN,
+   PIPE_VIDEO_PROFILE_VC1_ADVANCED,
+   PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE,
+   PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE,
+   PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN,
+   PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED,
+   PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH,
+   PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10,
+   PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH422,
+   PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH444,
+   PIPE_VIDEO_PROFILE_HEVC_MAIN,
+   PIPE_VIDEO_PROFILE_HEVC_MAIN_10,
+   PIPE_VIDEO_PROFILE_HEVC_MAIN_STILL,
+   PIPE_VIDEO_PROFILE_HEVC_MAIN_12,
+   PIPE_VIDEO_PROFILE_HEVC_MAIN_444,
+   PIPE_VIDEO_PROFILE_JPEG_BASELINE,
+   PIPE_VIDEO_PROFILE_VP9_PROFILE0,
+   PIPE_VIDEO_PROFILE_VP9_PROFILE2,
+   PIPE_VIDEO_PROFILE_AV1_MAIN,
+   PIPE_VIDEO_PROFILE_MAX
+};
+
+/* Video caps, can be different for each codec/profile */
+enum pipe_video_cap
+{
+   PIPE_VIDEO_CAP_SUPPORTED = 0,
+   PIPE_VIDEO_CAP_NPOT_TEXTURES = 1,
+   PIPE_VIDEO_CAP_MAX_WIDTH = 2,
+   PIPE_VIDEO_CAP_MAX_HEIGHT = 3,
+   PIPE_VIDEO_CAP_PREFERED_FORMAT = 4,
+   PIPE_VIDEO_CAP_PREFERS_INTERLACED = 5,
+   PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE = 6,
+   PIPE_VIDEO_CAP_SUPPORTS_INTERLACED = 7,
+   PIPE_VIDEO_CAP_MAX_LEVEL = 8,
+   PIPE_VIDEO_CAP_STACKED_FRAMES = 9,
+   PIPE_VIDEO_CAP_MAX_MACROBLOCKS = 10,
+   PIPE_VIDEO_CAP_MAX_TEMPORAL_LAYERS = 11,
+   PIPE_VIDEO_CAP_EFC_SUPPORTED = 12,
+   PIPE_VIDEO_CAP_ENC_MAX_SLICES_PER_FRAME = 13,
+   PIPE_VIDEO_CAP_ENC_SLICES_STRUCTURE = 14,
+   PIPE_VIDEO_CAP_ENC_MAX_REFERENCES_PER_FRAME = 15,
+};
+
+/* To be used with cap PIPE_VIDEO_CAP_ENC_SLICES_STRUCTURE*/
+/**
+ * pipe_video_cap_slice_structure
+ *
+ * This attribute determines slice structures supported by the
+ * driver for encoding. This attribute is a hint to the user so
+ * that he can choose a suitable surface size and how to arrange
+ * the encoding process of multiple slices per frame.
+ *
+ * More specifically, for H.264 encoding, this attribute
+ * determines the range of accepted values to
+ * h264_slice_descriptor::macroblock_address and
+ * h264_slice_descriptor::num_macroblocks.
+ */
+enum pipe_video_cap_slice_structure
+{
+   /* Driver does not supports multiple slice per frame.*/
+   PIPE_VIDEO_CAP_SLICE_STRUCTURE_NONE = 0x00000000,
+   /* Driver supports a power-of-two number of rows per slice.*/
+   PIPE_VIDEO_CAP_SLICE_STRUCTURE_POWER_OF_TWO_ROWS = 0x00000001,
+   /* Driver supports an arbitrary number of macroblocks per slice.*/
+   PIPE_VIDEO_CAP_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS = 0x00000002,
+   /* Driver support 1 row per slice*/
+   PIPE_VIDEO_CAP_SLICE_STRUCTURE_EQUAL_ROWS = 0x00000004,
+   /* Driver support max encoded slice size per slice */
+   PIPE_VIDEO_CAP_SLICE_STRUCTURE_MAX_SLICE_SIZE = 0x00000008,
+   /* Driver supports an arbitrary number of rows per slice. */
+   PIPE_VIDEO_CAP_SLICE_STRUCTURE_ARBITRARY_ROWS = 0x00000010,
+   /* Driver supports any number of rows per slice but they must be the same
+   *  for all slices except for the last one, which must be equal or smaller
+   *  to the previous slices. */
+   PIPE_VIDEO_CAP_SLICE_STRUCTURE_EQUAL_MULTI_ROWS = 0x00000020,
+};
+
+
+enum pipe_video_entrypoint
+{
+   PIPE_VIDEO_ENTRYPOINT_UNKNOWN,
+   PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
+   PIPE_VIDEO_ENTRYPOINT_IDCT,
+   PIPE_VIDEO_ENTRYPOINT_MC,
+   PIPE_VIDEO_ENTRYPOINT_ENCODE
+};
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* PIPE_VIDEO_ENUMS_H */
diff --git a/src/gallium/include/pipe/p_video_state.h b/src/gallium/include/pipe/p_video_state.h
new file mode 100644
index 0000000..8540f02
--- /dev/null
+++ b/src/gallium/include/pipe/p_video_state.h
@@ -0,0 +1,67 @@
+/**************************************************************************
+ *
+ * Copyright 2022 Younes Manton.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef PIPE_VIDEO_STATE_H
+#define PIPE_VIDEO_STATE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum pipe_h264_slice_type
+{
+   PIPE_H264_SLICE_TYPE_P = 0x0,
+   PIPE_H264_SLICE_TYPE_B = 0x1,
+   PIPE_H264_SLICE_TYPE_I = 0x2,
+   PIPE_H264_SLICE_TYPE_SP = 0x3,
+   PIPE_H264_SLICE_TYPE_SI = 0x4
+};
+
+/* Same enum for h264/h265 */
+enum pipe_h2645_enc_picture_type
+{
+   PIPE_H2645_ENC_PICTURE_TYPE_P = 0x00,
+   PIPE_H2645_ENC_PICTURE_TYPE_B = 0x01,
+   PIPE_H2645_ENC_PICTURE_TYPE_I = 0x02,
+   PIPE_H2645_ENC_PICTURE_TYPE_IDR = 0x03,
+   PIPE_H2645_ENC_PICTURE_TYPE_SKIP = 0x04
+};
+
+enum pipe_h2645_enc_rate_control_method
+{
+   PIPE_H2645_ENC_RATE_CONTROL_METHOD_DISABLE = 0x00,
+   PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT_SKIP = 0x01,
+   PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP = 0x02,
+   PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT = 0x03,
+   PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE = 0x04
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIPE_VIDEO_STATE_H */
diff --git a/src/mesa/util/u_cpu_detect.c b/src/mesa/util/u_cpu_detect.c
index 955d087..d6e51a1 100644
--- a/src/mesa/util/u_cpu_detect.c
+++ b/src/mesa/util/u_cpu_detect.c
@@ -681,7 +681,6 @@
 #if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64)
    if (has_cpuid()) {
       uint32_t regs[4];
-      uint32_t regs2[4];
 
       util_cpu_caps.cacheline = 32;
 
@@ -690,6 +689,7 @@
 
       if (regs[0] >= 0x00000001) {
          unsigned int cacheline;
+         uint32_t regs2[4];
 
          cpuid (0x00000001, regs2);
 
@@ -739,6 +739,24 @@
          cacheline = ((regs2[1] >> 8) & 0xFF) * 8;
          if (cacheline > 0)
             util_cpu_caps.cacheline = cacheline;
+
+         // check for avx512
+         if (((regs2[2] >> 27) & 1) && // OSXSAVE
+             (xgetbv() & (0x7 << 5)) && // OPMASK: upper-256 enabled by OS
+             ((xgetbv() & 6) == 6)) { // XMM/YMM enabled by OS
+            uint32_t regs3[4];
+            cpuid_count(0x00000007, 0x00000000, regs3);
+            util_cpu_caps.has_avx512f    = (regs3[1] >> 16) & 1;
+            util_cpu_caps.has_avx512dq   = (regs3[1] >> 17) & 1;
+            util_cpu_caps.has_avx512ifma = (regs3[1] >> 21) & 1;
+            util_cpu_caps.has_avx512pf   = (regs3[1] >> 26) & 1;
+            util_cpu_caps.has_avx512er   = (regs3[1] >> 27) & 1;
+            util_cpu_caps.has_avx512cd   = (regs3[1] >> 28) & 1;
+            util_cpu_caps.has_avx512bw   = (regs3[1] >> 30) & 1;
+            util_cpu_caps.has_avx512vl   = (regs3[1] >> 31) & 1;
+            util_cpu_caps.has_avx512vbmi = (regs3[2] >>  1) & 1;
+         }
+
       }
       if (util_cpu_caps.has_avx && regs[0] >= 0x00000007) {
          uint32_t regs7[4];
@@ -746,22 +764,6 @@
          util_cpu_caps.has_avx2 = (regs7[1] >> 5) & 1;
       }
 
-      // check for avx512
-      if (((regs2[2] >> 27) & 1) && // OSXSAVE
-          (xgetbv() & (0x7 << 5)) && // OPMASK: upper-256 enabled by OS
-          ((xgetbv() & 6) == 6)) { // XMM/YMM enabled by OS
-         uint32_t regs3[4];
-         cpuid_count(0x00000007, 0x00000000, regs3);
-         util_cpu_caps.has_avx512f    = (regs3[1] >> 16) & 1;
-         util_cpu_caps.has_avx512dq   = (regs3[1] >> 17) & 1;
-         util_cpu_caps.has_avx512ifma = (regs3[1] >> 21) & 1;
-         util_cpu_caps.has_avx512pf   = (regs3[1] >> 26) & 1;
-         util_cpu_caps.has_avx512er   = (regs3[1] >> 27) & 1;
-         util_cpu_caps.has_avx512cd   = (regs3[1] >> 28) & 1;
-         util_cpu_caps.has_avx512bw   = (regs3[1] >> 30) & 1;
-         util_cpu_caps.has_avx512vl   = (regs3[1] >> 31) & 1;
-         util_cpu_caps.has_avx512vbmi = (regs3[2] >>  1) & 1;
-      }
 
       if (regs[1] == 0x756e6547 && regs[2] == 0x6c65746e && regs[3] == 0x49656e69) {
          /* GenuineIntel */
@@ -771,7 +773,7 @@
       cpuid(0x80000000, regs);
 
       if (regs[0] >= 0x80000001) {
-
+         uint32_t regs2[4];
          cpuid(0x80000001, regs2);
 
          util_cpu_caps.has_mmx  |= (regs2[3] >> 23) & 1;
@@ -784,6 +786,7 @@
       }
 
       if (regs[0] >= 0x80000006) {
+         uint32_t regs2[4];
          /* should we really do this if the clflush size above worked? */
          unsigned int cacheline;
          cpuid(0x80000006, regs2);
diff --git a/src/meson.build b/src/meson.build
index 2f94432..d78ac8c 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -160,6 +160,14 @@
    'proxy/proxy_socket.c',
 ]
 
+video_sources = [
+   'virgl_video_hw.h',
+   'virgl_video.c',
+   'virgl_video.h',
+   'vrend_video.c',
+   'vrend_video.h',
+]
+
 virgl_depends = [
    gallium_dep,
    epoxy_dep,
@@ -206,6 +214,11 @@
    virgl_sources += proxy_sources
 endif
 
+if with_video
+  virgl_sources += video_sources
+  virgl_depends += [libva_dep, libvadrm_dep]
+endif
+
 libvirgl = static_library(
    'virgl',
    virgl_sources,
diff --git a/src/proxy/proxy_context.c b/src/proxy/proxy_context.c
index f2a035b..f254afe 100644
--- a/src/proxy/proxy_context.c
+++ b/src/proxy/proxy_context.c
@@ -152,7 +152,7 @@
       const uint32_t ring_idx = u_bit_scan64(&old_busy_mask);
       const uint32_t cur_seqno = proxy_context_load_timeline_seqno(ctx, ring_idx);
       if (!proxy_context_retire_timeline_fences_locked(ctx, ring_idx, cur_seqno))
-         new_busy_mask |= 1 << ring_idx;
+         new_busy_mask |= 1ull << ring_idx;
    }
 
    ctx->timeline_busy_mask = new_busy_mask;
@@ -196,14 +196,12 @@
 static int
 proxy_context_submit_fence(struct virgl_context *base,
                            uint32_t flags,
-                           uint64_t queue_id,
+                           uint32_t ring_idx,
                            uint64_t fence_id)
 {
    struct proxy_context *ctx = (struct proxy_context *)base;
    const uint64_t old_busy_mask = ctx->timeline_busy_mask;
 
-   /* TODO fix virglrenderer to match virtio-gpu spec which uses ring_idx */
-   const uint32_t ring_idx = queue_id;
    if (ring_idx >= PROXY_CONTEXT_TIMELINE_COUNT)
       return -EINVAL;
 
@@ -220,7 +218,7 @@
       mtx_lock(&ctx->timeline_mutex);
 
    list_addtail(&fence->head, &timeline->fences);
-   ctx->timeline_busy_mask |= 1 << ring_idx;
+   ctx->timeline_busy_mask |= 1ull << ring_idx;
 
    if (proxy_renderer.flags & VIRGL_RENDERER_ASYNC_FENCE_CB)
       mtx_unlock(&ctx->timeline_mutex);
@@ -319,7 +317,7 @@
       return false;
    }
 
-   const uint64_t size = lseek64(fd, 0, SEEK_END);
+   const uint64_t size = lseek(fd, 0, SEEK_END);
    if (size != expected_size) {
       proxy_log("failed to validate shm size(%" PRIu64 ") expected(%" PRIu64 ")", size,
                 expected_size);
diff --git a/src/venus/venus-protocol/vn_protocol_renderer.h b/src/venus/venus-protocol/vn_protocol_renderer.h
index f9ecff0..52ef7d5 100644
--- a/src/venus/venus-protocol/vn_protocol_renderer.h
+++ b/src/venus/venus-protocol/vn_protocol_renderer.h
@@ -1,4 +1,4 @@
-/* This file is generated by venus-protocol git-6c35d9f3. */
+/* This file is generated by venus-protocol git-c692a30d. */
 
 /*
  * Copyright 2020 Google LLC
diff --git a/src/venus/venus-protocol/vn_protocol_renderer_command_buffer.h b/src/venus/venus-protocol/vn_protocol_renderer_command_buffer.h
index 249469a..e78502d 100644
--- a/src/venus/venus-protocol/vn_protocol_renderer_command_buffer.h
+++ b/src/venus/venus-protocol/vn_protocol_renderer_command_buffer.h
@@ -14,6 +14,12 @@
 #pragma GCC diagnostic ignored "-Wpointer-arith"
 #pragma GCC diagnostic ignored "-Wunused-parameter"
 
+/*
+ * These structs/unions/commands are not included
+ *
+ *   vkCmdPushDescriptorSetWithTemplateKHR
+ */
+
 /* struct VkCommandBufferAllocateInfo chain */
 
 static inline void *
@@ -456,6 +462,40 @@
     } while (pnext);
 }
 
+/* struct VkMultiDrawInfoEXT */
+
+static inline void
+vn_decode_VkMultiDrawInfoEXT_temp(struct vn_cs_decoder *dec, VkMultiDrawInfoEXT *val)
+{
+    vn_decode_uint32_t(dec, &val->firstVertex);
+    vn_decode_uint32_t(dec, &val->vertexCount);
+}
+
+static inline void
+vn_replace_VkMultiDrawInfoEXT_handle(VkMultiDrawInfoEXT *val)
+{
+    /* skip val->firstVertex */
+    /* skip val->vertexCount */
+}
+
+/* struct VkMultiDrawIndexedInfoEXT */
+
+static inline void
+vn_decode_VkMultiDrawIndexedInfoEXT_temp(struct vn_cs_decoder *dec, VkMultiDrawIndexedInfoEXT *val)
+{
+    vn_decode_uint32_t(dec, &val->firstIndex);
+    vn_decode_uint32_t(dec, &val->indexCount);
+    vn_decode_int32_t(dec, &val->vertexOffset);
+}
+
+static inline void
+vn_replace_VkMultiDrawIndexedInfoEXT_handle(VkMultiDrawIndexedInfoEXT *val)
+{
+    /* skip val->firstIndex */
+    /* skip val->indexCount */
+    /* skip val->vertexOffset */
+}
+
 /* struct VkBufferCopy */
 
 static inline void
@@ -3138,6 +3178,103 @@
     /* skip args->firstInstance */
 }
 
+static inline void vn_decode_vkCmdDrawMultiEXT_args_temp(struct vn_cs_decoder *dec, struct vn_command_vkCmdDrawMultiEXT *args)
+{
+    vn_decode_VkCommandBuffer_lookup(dec, &args->commandBuffer);
+    vn_decode_uint32_t(dec, &args->drawCount);
+    if (vn_peek_array_size(dec)) {
+        const uint32_t iter_count = vn_decode_array_size(dec, args->drawCount);
+        args->pVertexInfo = vn_cs_decoder_alloc_temp(dec, sizeof(*args->pVertexInfo) * iter_count);
+        if (!args->pVertexInfo) return;
+        for (uint32_t i = 0; i < iter_count; i++)
+            vn_decode_VkMultiDrawInfoEXT_temp(dec, &((VkMultiDrawInfoEXT *)args->pVertexInfo)[i]);
+    } else {
+        vn_decode_array_size_unchecked(dec);
+        args->pVertexInfo = NULL;
+    }
+    vn_decode_uint32_t(dec, &args->instanceCount);
+    vn_decode_uint32_t(dec, &args->firstInstance);
+    vn_decode_uint32_t(dec, &args->stride);
+}
+
+static inline void vn_replace_vkCmdDrawMultiEXT_args_handle(struct vn_command_vkCmdDrawMultiEXT *args)
+{
+    vn_replace_VkCommandBuffer_handle(&args->commandBuffer);
+    /* skip args->drawCount */
+    if (args->pVertexInfo) {
+       for (uint32_t i = 0; i < args->drawCount; i++)
+            vn_replace_VkMultiDrawInfoEXT_handle(&((VkMultiDrawInfoEXT *)args->pVertexInfo)[i]);
+    }
+    /* skip args->instanceCount */
+    /* skip args->firstInstance */
+    /* skip args->stride */
+}
+
+static inline void vn_encode_vkCmdDrawMultiEXT_reply(struct vn_cs_encoder *enc, const struct vn_command_vkCmdDrawMultiEXT *args)
+{
+    vn_encode_VkCommandTypeEXT(enc, &(VkCommandTypeEXT){VK_COMMAND_TYPE_vkCmdDrawMultiEXT_EXT});
+
+    /* skip args->commandBuffer */
+    /* skip args->drawCount */
+    /* skip args->pVertexInfo */
+    /* skip args->instanceCount */
+    /* skip args->firstInstance */
+    /* skip args->stride */
+}
+
+static inline void vn_decode_vkCmdDrawMultiIndexedEXT_args_temp(struct vn_cs_decoder *dec, struct vn_command_vkCmdDrawMultiIndexedEXT *args)
+{
+    vn_decode_VkCommandBuffer_lookup(dec, &args->commandBuffer);
+    vn_decode_uint32_t(dec, &args->drawCount);
+    if (vn_peek_array_size(dec)) {
+        const uint32_t iter_count = vn_decode_array_size(dec, args->drawCount);
+        args->pIndexInfo = vn_cs_decoder_alloc_temp(dec, sizeof(*args->pIndexInfo) * iter_count);
+        if (!args->pIndexInfo) return;
+        for (uint32_t i = 0; i < iter_count; i++)
+            vn_decode_VkMultiDrawIndexedInfoEXT_temp(dec, &((VkMultiDrawIndexedInfoEXT *)args->pIndexInfo)[i]);
+    } else {
+        vn_decode_array_size_unchecked(dec);
+        args->pIndexInfo = NULL;
+    }
+    vn_decode_uint32_t(dec, &args->instanceCount);
+    vn_decode_uint32_t(dec, &args->firstInstance);
+    vn_decode_uint32_t(dec, &args->stride);
+    if (vn_decode_simple_pointer(dec)) {
+        args->pVertexOffset = vn_cs_decoder_alloc_temp(dec, sizeof(*args->pVertexOffset));
+        if (!args->pVertexOffset) return;
+        vn_decode_int32_t(dec, (int32_t *)args->pVertexOffset);
+    } else {
+        args->pVertexOffset = NULL;
+    }
+}
+
+static inline void vn_replace_vkCmdDrawMultiIndexedEXT_args_handle(struct vn_command_vkCmdDrawMultiIndexedEXT *args)
+{
+    vn_replace_VkCommandBuffer_handle(&args->commandBuffer);
+    /* skip args->drawCount */
+    if (args->pIndexInfo) {
+       for (uint32_t i = 0; i < args->drawCount; i++)
+            vn_replace_VkMultiDrawIndexedInfoEXT_handle(&((VkMultiDrawIndexedInfoEXT *)args->pIndexInfo)[i]);
+    }
+    /* skip args->instanceCount */
+    /* skip args->firstInstance */
+    /* skip args->stride */
+    /* skip args->pVertexOffset */
+}
+
+static inline void vn_encode_vkCmdDrawMultiIndexedEXT_reply(struct vn_cs_encoder *enc, const struct vn_command_vkCmdDrawMultiIndexedEXT *args)
+{
+    vn_encode_VkCommandTypeEXT(enc, &(VkCommandTypeEXT){VK_COMMAND_TYPE_vkCmdDrawMultiIndexedEXT_EXT});
+
+    /* skip args->commandBuffer */
+    /* skip args->drawCount */
+    /* skip args->pIndexInfo */
+    /* skip args->instanceCount */
+    /* skip args->firstInstance */
+    /* skip args->stride */
+    /* skip args->pVertexOffset */
+}
+
 static inline void vn_decode_vkCmdDrawIndirect_args_temp(struct vn_cs_decoder *dec, struct vn_command_vkCmdDrawIndirect *args)
 {
     vn_decode_VkCommandBuffer_lookup(dec, &args->commandBuffer);
@@ -4287,6 +4424,50 @@
     /* skip args->pCommandBuffers */
 }
 
+static inline void vn_decode_vkCmdPushDescriptorSetKHR_args_temp(struct vn_cs_decoder *dec, struct vn_command_vkCmdPushDescriptorSetKHR *args)
+{
+    vn_decode_VkCommandBuffer_lookup(dec, &args->commandBuffer);
+    vn_decode_VkPipelineBindPoint(dec, &args->pipelineBindPoint);
+    vn_decode_VkPipelineLayout_lookup(dec, &args->layout);
+    vn_decode_uint32_t(dec, &args->set);
+    vn_decode_uint32_t(dec, &args->descriptorWriteCount);
+    if (vn_peek_array_size(dec)) {
+        const uint32_t iter_count = vn_decode_array_size(dec, args->descriptorWriteCount);
+        args->pDescriptorWrites = vn_cs_decoder_alloc_temp(dec, sizeof(*args->pDescriptorWrites) * iter_count);
+        if (!args->pDescriptorWrites) return;
+        for (uint32_t i = 0; i < iter_count; i++)
+            vn_decode_VkWriteDescriptorSet_temp(dec, &((VkWriteDescriptorSet *)args->pDescriptorWrites)[i]);
+    } else {
+        vn_decode_array_size(dec, args->descriptorWriteCount);
+        args->pDescriptorWrites = NULL;
+    }
+}
+
+static inline void vn_replace_vkCmdPushDescriptorSetKHR_args_handle(struct vn_command_vkCmdPushDescriptorSetKHR *args)
+{
+    vn_replace_VkCommandBuffer_handle(&args->commandBuffer);
+    /* skip args->pipelineBindPoint */
+    vn_replace_VkPipelineLayout_handle(&args->layout);
+    /* skip args->set */
+    /* skip args->descriptorWriteCount */
+    if (args->pDescriptorWrites) {
+       for (uint32_t i = 0; i < args->descriptorWriteCount; i++)
+            vn_replace_VkWriteDescriptorSet_handle(&((VkWriteDescriptorSet *)args->pDescriptorWrites)[i]);
+    }
+}
+
+static inline void vn_encode_vkCmdPushDescriptorSetKHR_reply(struct vn_cs_encoder *enc, const struct vn_command_vkCmdPushDescriptorSetKHR *args)
+{
+    vn_encode_VkCommandTypeEXT(enc, &(VkCommandTypeEXT){VK_COMMAND_TYPE_vkCmdPushDescriptorSetKHR_EXT});
+
+    /* skip args->commandBuffer */
+    /* skip args->pipelineBindPoint */
+    /* skip args->layout */
+    /* skip args->set */
+    /* skip args->descriptorWriteCount */
+    /* skip args->pDescriptorWrites */
+}
+
 static inline void vn_decode_vkCmdSetDeviceMask_args_temp(struct vn_cs_decoder *dec, struct vn_command_vkCmdSetDeviceMask *args)
 {
     vn_decode_VkCommandBuffer_lookup(dec, &args->commandBuffer);
@@ -6109,6 +6290,56 @@
     vn_cs_decoder_reset_temp_pool(ctx->decoder);
 }
 
+static inline void vn_dispatch_vkCmdDrawMultiEXT(struct vn_dispatch_context *ctx, VkCommandFlagsEXT flags)
+{
+    struct vn_command_vkCmdDrawMultiEXT args;
+
+    if (!ctx->dispatch_vkCmdDrawMultiEXT) {
+        vn_cs_decoder_set_fatal(ctx->decoder);
+        return;
+    }
+
+    vn_decode_vkCmdDrawMultiEXT_args_temp(ctx->decoder, &args);
+    if (!args.commandBuffer) {
+        vn_cs_decoder_set_fatal(ctx->decoder);
+        return;
+    }
+
+    if (!vn_cs_decoder_get_fatal(ctx->decoder))
+        ctx->dispatch_vkCmdDrawMultiEXT(ctx, &args);
+
+
+    if (!vn_cs_decoder_get_fatal(ctx->decoder) && (flags & VK_COMMAND_GENERATE_REPLY_BIT_EXT))
+       vn_encode_vkCmdDrawMultiEXT_reply(ctx->encoder, &args);
+
+    vn_cs_decoder_reset_temp_pool(ctx->decoder);
+}
+
+static inline void vn_dispatch_vkCmdDrawMultiIndexedEXT(struct vn_dispatch_context *ctx, VkCommandFlagsEXT flags)
+{
+    struct vn_command_vkCmdDrawMultiIndexedEXT args;
+
+    if (!ctx->dispatch_vkCmdDrawMultiIndexedEXT) {
+        vn_cs_decoder_set_fatal(ctx->decoder);
+        return;
+    }
+
+    vn_decode_vkCmdDrawMultiIndexedEXT_args_temp(ctx->decoder, &args);
+    if (!args.commandBuffer) {
+        vn_cs_decoder_set_fatal(ctx->decoder);
+        return;
+    }
+
+    if (!vn_cs_decoder_get_fatal(ctx->decoder))
+        ctx->dispatch_vkCmdDrawMultiIndexedEXT(ctx, &args);
+
+
+    if (!vn_cs_decoder_get_fatal(ctx->decoder) && (flags & VK_COMMAND_GENERATE_REPLY_BIT_EXT))
+       vn_encode_vkCmdDrawMultiIndexedEXT_reply(ctx->encoder, &args);
+
+    vn_cs_decoder_reset_temp_pool(ctx->decoder);
+}
+
 static inline void vn_dispatch_vkCmdDrawIndirect(struct vn_dispatch_context *ctx, VkCommandFlagsEXT flags)
 {
     struct vn_command_vkCmdDrawIndirect args;
@@ -6884,6 +7115,31 @@
     vn_cs_decoder_reset_temp_pool(ctx->decoder);
 }
 
+static inline void vn_dispatch_vkCmdPushDescriptorSetKHR(struct vn_dispatch_context *ctx, VkCommandFlagsEXT flags)
+{
+    struct vn_command_vkCmdPushDescriptorSetKHR args;
+
+    if (!ctx->dispatch_vkCmdPushDescriptorSetKHR) {
+        vn_cs_decoder_set_fatal(ctx->decoder);
+        return;
+    }
+
+    vn_decode_vkCmdPushDescriptorSetKHR_args_temp(ctx->decoder, &args);
+    if (!args.commandBuffer) {
+        vn_cs_decoder_set_fatal(ctx->decoder);
+        return;
+    }
+
+    if (!vn_cs_decoder_get_fatal(ctx->decoder))
+        ctx->dispatch_vkCmdPushDescriptorSetKHR(ctx, &args);
+
+
+    if (!vn_cs_decoder_get_fatal(ctx->decoder) && (flags & VK_COMMAND_GENERATE_REPLY_BIT_EXT))
+       vn_encode_vkCmdPushDescriptorSetKHR_reply(ctx->encoder, &args);
+
+    vn_cs_decoder_reset_temp_pool(ctx->decoder);
+}
+
 static inline void vn_dispatch_vkCmdSetDeviceMask(struct vn_dispatch_context *ctx, VkCommandFlagsEXT flags)
 {
     struct vn_command_vkCmdSetDeviceMask args;
diff --git a/src/venus/venus-protocol/vn_protocol_renderer_defines.h b/src/venus/venus-protocol/vn_protocol_renderer_defines.h
index 38049a9..b95e525 100644
--- a/src/venus/venus-protocol/vn_protocol_renderer_defines.h
+++ b/src/venus/venus-protocol/vn_protocol_renderer_defines.h
@@ -22,6 +22,8 @@
 #define VK_STRUCTURE_TYPE_MEMORY_RESOURCE_PROPERTIES_MESA ((VkStructureType)1000384001)
 #define VK_STRUCTURE_TYPE_IMPORT_MEMORY_RESOURCE_INFO_MESA ((VkStructureType)1000384002)
 #define VK_STRUCTURE_TYPE_MEMORY_RESOURCE_ALLOCATION_SIZE_PROPERTIES_100000_MESA ((VkStructureType)1000384003)
+#define VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_RESOURCE_INFO_100000_MESA ((VkStructureType)1000384004)
+#define VK_STRUCTURE_TYPE_DEVICE_QUEUE_TIMELINE_INFO_MESA ((VkStructureType)1000384005)
 
 typedef enum VkCommandTypeEXT {
     VK_COMMAND_TYPE_vkCreateInstance_EXT = 0,
@@ -326,16 +328,22 @@
     VK_COMMAND_TYPE_vkCmdDrawIndirectByteCountEXT_EXT = 186,
     VK_COMMAND_TYPE_vkGetMemoryFdKHR_EXT = 193,
     VK_COMMAND_TYPE_vkGetMemoryFdPropertiesKHR_EXT = 194,
-    VK_COMMAND_TYPE_vkImportFenceFdKHR_EXT = 238,
-    VK_COMMAND_TYPE_vkGetFenceFdKHR_EXT = 239,
+    VK_COMMAND_TYPE_vkImportSemaphoreFdKHR_EXT = 242,
+    VK_COMMAND_TYPE_vkGetSemaphoreFdKHR_EXT = 243,
+    VK_COMMAND_TYPE_vkCmdPushDescriptorSetKHR_EXT = 249,
+    VK_COMMAND_TYPE_vkCmdPushDescriptorSetWithTemplateKHR_EXT = 250,
     VK_COMMAND_TYPE_vkCmdBeginConditionalRenderingEXT_EXT = 240,
     VK_COMMAND_TYPE_vkCmdEndConditionalRenderingEXT_EXT = 241,
+    VK_COMMAND_TYPE_vkImportFenceFdKHR_EXT = 238,
+    VK_COMMAND_TYPE_vkGetFenceFdKHR_EXT = 239,
     VK_COMMAND_TYPE_vkGetImageDrmFormatModifierPropertiesEXT_EXT = 187,
-    VK_COMMAND_TYPE_vkCmdSetPatchControlPointsEXT_EXT = 233,
-    VK_COMMAND_TYPE_vkCmdSetLogicOpEXT_EXT = 234,
     VK_COMMAND_TYPE_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT_EXT = 235,
     VK_COMMAND_TYPE_vkGetCalibratedTimestampsEXT_EXT = 236,
     VK_COMMAND_TYPE_vkCmdSetLineStippleEXT_EXT = 237,
+    VK_COMMAND_TYPE_vkCmdSetPatchControlPointsEXT_EXT = 233,
+    VK_COMMAND_TYPE_vkCmdSetLogicOpEXT_EXT = 234,
+    VK_COMMAND_TYPE_vkCmdDrawMultiEXT_EXT = 247,
+    VK_COMMAND_TYPE_vkCmdDrawMultiIndexedEXT_EXT = 248,
     VK_COMMAND_TYPE_vkSetReplyCommandStreamMESA_EXT = 178,
     VK_COMMAND_TYPE_vkSeekReplyCommandStreamMESA_EXT = 179,
     VK_COMMAND_TYPE_vkExecuteCommandStreamsMESA_EXT = 180,
@@ -344,6 +352,9 @@
     VK_COMMAND_TYPE_vkNotifyRingMESA_EXT = 190,
     VK_COMMAND_TYPE_vkWriteRingExtraMESA_EXT = 191,
     VK_COMMAND_TYPE_vkGetMemoryResourcePropertiesMESA_EXT = 192,
+    VK_COMMAND_TYPE_vkResetFenceResource100000MESA_EXT = 244,
+    VK_COMMAND_TYPE_vkWaitSemaphoreResource100000MESA_EXT = 245,
+    VK_COMMAND_TYPE_vkImportSemaphoreResource100000MESA_EXT = 246,
     VK_COMMAND_TYPE_vkGetVenusExperimentalFeatureData100000MESA_EXT = 195,
 } VkCommandTypeEXT;
 
@@ -403,6 +414,7 @@
     VkBool32 memoryResourceAllocationSize;
     VkBool32 globalFencing;
     VkBool32 largeRing;
+    VkBool32 syncFdFencing;
 } VkVenusExperimentalFeatures100000MESA;
 
 typedef struct VkMemoryResourceAllocationSizeProperties100000MESA {
@@ -411,6 +423,19 @@
     uint64_t allocationSize;
 } VkMemoryResourceAllocationSizeProperties100000MESA;
 
+typedef struct VkImportSemaphoreResourceInfo100000MESA {
+    VkStructureType sType;
+    const void* pNext;
+    VkSemaphore semaphore;
+    uint32_t resourceId;
+} VkImportSemaphoreResourceInfo100000MESA;
+
+typedef struct VkDeviceQueueTimelineInfoMESA {
+    VkStructureType sType;
+    const void* pNext;
+    uint32_t ringIdx;
+} VkDeviceQueueTimelineInfoMESA;
+
 struct vn_command_vkCreateInstance {
     const VkInstanceCreateInfo* pCreateInfo;
     const VkAllocationCallbacks* pAllocator;
@@ -1235,6 +1260,25 @@
     uint32_t firstInstance;
 };
 
+struct vn_command_vkCmdDrawMultiEXT {
+    VkCommandBuffer commandBuffer;
+    uint32_t drawCount;
+    const VkMultiDrawInfoEXT* pVertexInfo;
+    uint32_t instanceCount;
+    uint32_t firstInstance;
+    uint32_t stride;
+};
+
+struct vn_command_vkCmdDrawMultiIndexedEXT {
+    VkCommandBuffer commandBuffer;
+    uint32_t drawCount;
+    const VkMultiDrawIndexedInfoEXT* pIndexInfo;
+    uint32_t instanceCount;
+    uint32_t firstInstance;
+    uint32_t stride;
+    const int32_t* pVertexOffset;
+};
+
 struct vn_command_vkCmdDrawIndirect {
     VkCommandBuffer commandBuffer;
     VkBuffer buffer;
@@ -1521,6 +1565,15 @@
     VkSparseImageFormatProperties2* pProperties;
 };
 
+struct vn_command_vkCmdPushDescriptorSetKHR {
+    VkCommandBuffer commandBuffer;
+    VkPipelineBindPoint pipelineBindPoint;
+    VkPipelineLayout layout;
+    uint32_t set;
+    uint32_t descriptorWriteCount;
+    const VkWriteDescriptorSet* pDescriptorWrites;
+};
+
 struct vn_command_vkTrimCommandPool {
     VkDevice device;
     VkCommandPool commandPool;
@@ -1556,6 +1609,21 @@
     VkExternalSemaphoreProperties* pExternalSemaphoreProperties;
 };
 
+struct vn_command_vkGetSemaphoreFdKHR {
+    VkDevice device;
+    const VkSemaphoreGetFdInfoKHR* pGetFdInfo;
+    int* pFd;
+
+    VkResult ret;
+};
+
+struct vn_command_vkImportSemaphoreFdKHR {
+    VkDevice device;
+    const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo;
+
+    VkResult ret;
+};
+
 struct vn_command_vkGetPhysicalDeviceExternalFenceProperties {
     VkPhysicalDevice physicalDevice;
     const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo;
@@ -1646,6 +1714,14 @@
     const void* pData;
 };
 
+struct vn_command_vkCmdPushDescriptorSetWithTemplateKHR {
+    VkCommandBuffer commandBuffer;
+    VkDescriptorUpdateTemplate descriptorUpdateTemplate;
+    VkPipelineLayout layout;
+    uint32_t set;
+    const void* pData;
+};
+
 struct vn_command_vkGetBufferMemoryRequirements2 {
     VkDevice device;
     const VkBufferMemoryRequirementsInfo2* pInfo;
@@ -2145,6 +2221,21 @@
     VkResult ret;
 };
 
+struct vn_command_vkResetFenceResource100000MESA {
+    VkDevice device;
+    VkFence fence;
+};
+
+struct vn_command_vkWaitSemaphoreResource100000MESA {
+    VkDevice device;
+    VkSemaphore semaphore;
+};
+
+struct vn_command_vkImportSemaphoreResource100000MESA {
+    VkDevice device;
+    const VkImportSemaphoreResourceInfo100000MESA* pImportSemaphoreResourceInfo;
+};
+
 struct vn_command_vkGetVenusExperimentalFeatureData100000MESA {
     size_t* pDataSize;
     void* pData;
@@ -2267,6 +2358,8 @@
     void (*dispatch_vkCmdBindVertexBuffers)(struct vn_dispatch_context *ctx, struct vn_command_vkCmdBindVertexBuffers *args);
     void (*dispatch_vkCmdDraw)(struct vn_dispatch_context *ctx, struct vn_command_vkCmdDraw *args);
     void (*dispatch_vkCmdDrawIndexed)(struct vn_dispatch_context *ctx, struct vn_command_vkCmdDrawIndexed *args);
+    void (*dispatch_vkCmdDrawMultiEXT)(struct vn_dispatch_context *ctx, struct vn_command_vkCmdDrawMultiEXT *args);
+    void (*dispatch_vkCmdDrawMultiIndexedEXT)(struct vn_dispatch_context *ctx, struct vn_command_vkCmdDrawMultiIndexedEXT *args);
     void (*dispatch_vkCmdDrawIndirect)(struct vn_dispatch_context *ctx, struct vn_command_vkCmdDrawIndirect *args);
     void (*dispatch_vkCmdDrawIndexedIndirect)(struct vn_dispatch_context *ctx, struct vn_command_vkCmdDrawIndexedIndirect *args);
     void (*dispatch_vkCmdDispatch)(struct vn_dispatch_context *ctx, struct vn_command_vkCmdDispatch *args);
@@ -2305,11 +2398,14 @@
     void (*dispatch_vkGetPhysicalDeviceQueueFamilyProperties2)(struct vn_dispatch_context *ctx, struct vn_command_vkGetPhysicalDeviceQueueFamilyProperties2 *args);
     void (*dispatch_vkGetPhysicalDeviceMemoryProperties2)(struct vn_dispatch_context *ctx, struct vn_command_vkGetPhysicalDeviceMemoryProperties2 *args);
     void (*dispatch_vkGetPhysicalDeviceSparseImageFormatProperties2)(struct vn_dispatch_context *ctx, struct vn_command_vkGetPhysicalDeviceSparseImageFormatProperties2 *args);
+    void (*dispatch_vkCmdPushDescriptorSetKHR)(struct vn_dispatch_context *ctx, struct vn_command_vkCmdPushDescriptorSetKHR *args);
     void (*dispatch_vkTrimCommandPool)(struct vn_dispatch_context *ctx, struct vn_command_vkTrimCommandPool *args);
     void (*dispatch_vkGetPhysicalDeviceExternalBufferProperties)(struct vn_dispatch_context *ctx, struct vn_command_vkGetPhysicalDeviceExternalBufferProperties *args);
     void (*dispatch_vkGetMemoryFdKHR)(struct vn_dispatch_context *ctx, struct vn_command_vkGetMemoryFdKHR *args);
     void (*dispatch_vkGetMemoryFdPropertiesKHR)(struct vn_dispatch_context *ctx, struct vn_command_vkGetMemoryFdPropertiesKHR *args);
     void (*dispatch_vkGetPhysicalDeviceExternalSemaphoreProperties)(struct vn_dispatch_context *ctx, struct vn_command_vkGetPhysicalDeviceExternalSemaphoreProperties *args);
+    void (*dispatch_vkGetSemaphoreFdKHR)(struct vn_dispatch_context *ctx, struct vn_command_vkGetSemaphoreFdKHR *args);
+    void (*dispatch_vkImportSemaphoreFdKHR)(struct vn_dispatch_context *ctx, struct vn_command_vkImportSemaphoreFdKHR *args);
     void (*dispatch_vkGetPhysicalDeviceExternalFenceProperties)(struct vn_dispatch_context *ctx, struct vn_command_vkGetPhysicalDeviceExternalFenceProperties *args);
     void (*dispatch_vkGetFenceFdKHR)(struct vn_dispatch_context *ctx, struct vn_command_vkGetFenceFdKHR *args);
     void (*dispatch_vkImportFenceFdKHR)(struct vn_dispatch_context *ctx, struct vn_command_vkImportFenceFdKHR *args);
@@ -2322,6 +2418,7 @@
     void (*dispatch_vkCreateDescriptorUpdateTemplate)(struct vn_dispatch_context *ctx, struct vn_command_vkCreateDescriptorUpdateTemplate *args);
     void (*dispatch_vkDestroyDescriptorUpdateTemplate)(struct vn_dispatch_context *ctx, struct vn_command_vkDestroyDescriptorUpdateTemplate *args);
     void (*dispatch_vkUpdateDescriptorSetWithTemplate)(struct vn_dispatch_context *ctx, struct vn_command_vkUpdateDescriptorSetWithTemplate *args);
+    void (*dispatch_vkCmdPushDescriptorSetWithTemplateKHR)(struct vn_dispatch_context *ctx, struct vn_command_vkCmdPushDescriptorSetWithTemplateKHR *args);
     void (*dispatch_vkGetBufferMemoryRequirements2)(struct vn_dispatch_context *ctx, struct vn_command_vkGetBufferMemoryRequirements2 *args);
     void (*dispatch_vkGetImageMemoryRequirements2)(struct vn_dispatch_context *ctx, struct vn_command_vkGetImageMemoryRequirements2 *args);
     void (*dispatch_vkGetImageSparseMemoryRequirements2)(struct vn_dispatch_context *ctx, struct vn_command_vkGetImageSparseMemoryRequirements2 *args);
@@ -2398,6 +2495,9 @@
     void (*dispatch_vkNotifyRingMESA)(struct vn_dispatch_context *ctx, struct vn_command_vkNotifyRingMESA *args);
     void (*dispatch_vkWriteRingExtraMESA)(struct vn_dispatch_context *ctx, struct vn_command_vkWriteRingExtraMESA *args);
     void (*dispatch_vkGetMemoryResourcePropertiesMESA)(struct vn_dispatch_context *ctx, struct vn_command_vkGetMemoryResourcePropertiesMESA *args);
+    void (*dispatch_vkResetFenceResource100000MESA)(struct vn_dispatch_context *ctx, struct vn_command_vkResetFenceResource100000MESA *args);
+    void (*dispatch_vkWaitSemaphoreResource100000MESA)(struct vn_dispatch_context *ctx, struct vn_command_vkWaitSemaphoreResource100000MESA *args);
+    void (*dispatch_vkImportSemaphoreResource100000MESA)(struct vn_dispatch_context *ctx, struct vn_command_vkImportSemaphoreResource100000MESA *args);
     void (*dispatch_vkGetVenusExperimentalFeatureData100000MESA)(struct vn_dispatch_context *ctx, struct vn_command_vkGetVenusExperimentalFeatureData100000MESA *args);
 };
 
diff --git a/src/venus/venus-protocol/vn_protocol_renderer_descriptor_pool.h b/src/venus/venus-protocol/vn_protocol_renderer_descriptor_pool.h
index 73fd4e0..34058d4 100644
--- a/src/venus/venus-protocol/vn_protocol_renderer_descriptor_pool.h
+++ b/src/venus/venus-protocol/vn_protocol_renderer_descriptor_pool.h
@@ -108,6 +108,14 @@
             vn_decode_VkDescriptorPoolInlineUniformBlockCreateInfo_self_temp(dec, (VkDescriptorPoolInlineUniformBlockCreateInfo *)pnext);
         }
         break;
+    case VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkMutableDescriptorTypeCreateInfoEXT));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkDescriptorPoolCreateInfo_pnext_temp(dec);
+            vn_decode_VkMutableDescriptorTypeCreateInfoEXT_self_temp(dec, (VkMutableDescriptorTypeCreateInfoEXT *)pnext);
+        }
+        break;
     default:
         /* unexpected struct */
         pnext = NULL;
@@ -177,6 +185,9 @@
         case VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO:
             vn_replace_VkDescriptorPoolInlineUniformBlockCreateInfo_handle_self((VkDescriptorPoolInlineUniformBlockCreateInfo *)pnext);
             break;
+        case VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT:
+            vn_replace_VkMutableDescriptorTypeCreateInfoEXT_handle_self((VkMutableDescriptorTypeCreateInfoEXT *)pnext);
+            break;
         default:
             /* ignore unknown/unsupported struct */
             break;
diff --git a/src/venus/venus-protocol/vn_protocol_renderer_descriptor_set.h b/src/venus/venus-protocol/vn_protocol_renderer_descriptor_set.h
index 8630f03..285c65a 100644
--- a/src/venus/venus-protocol/vn_protocol_renderer_descriptor_set.h
+++ b/src/venus/venus-protocol/vn_protocol_renderer_descriptor_set.h
@@ -183,239 +183,6 @@
     } while (pnext);
 }
 
-/* struct VkDescriptorImageInfo */
-
-static inline void
-vn_decode_VkDescriptorImageInfo_temp(struct vn_cs_decoder *dec, VkDescriptorImageInfo *val)
-{
-    vn_decode_VkSampler_lookup(dec, &val->sampler);
-    vn_decode_VkImageView_lookup(dec, &val->imageView);
-    vn_decode_VkImageLayout(dec, &val->imageLayout);
-}
-
-static inline void
-vn_replace_VkDescriptorImageInfo_handle(VkDescriptorImageInfo *val)
-{
-    vn_replace_VkSampler_handle(&val->sampler);
-    vn_replace_VkImageView_handle(&val->imageView);
-    /* skip val->imageLayout */
-}
-
-/* struct VkDescriptorBufferInfo */
-
-static inline void
-vn_decode_VkDescriptorBufferInfo_temp(struct vn_cs_decoder *dec, VkDescriptorBufferInfo *val)
-{
-    vn_decode_VkBuffer_lookup(dec, &val->buffer);
-    vn_decode_VkDeviceSize(dec, &val->offset);
-    vn_decode_VkDeviceSize(dec, &val->range);
-}
-
-static inline void
-vn_replace_VkDescriptorBufferInfo_handle(VkDescriptorBufferInfo *val)
-{
-    vn_replace_VkBuffer_handle(&val->buffer);
-    /* skip val->offset */
-    /* skip val->range */
-}
-
-/* struct VkWriteDescriptorSetInlineUniformBlock chain */
-
-static inline void *
-vn_decode_VkWriteDescriptorSetInlineUniformBlock_pnext_temp(struct vn_cs_decoder *dec)
-{
-    /* no known/supported struct */
-    if (vn_decode_simple_pointer(dec))
-        vn_cs_decoder_set_fatal(dec);
-    return NULL;
-}
-
-static inline void
-vn_decode_VkWriteDescriptorSetInlineUniformBlock_self_temp(struct vn_cs_decoder *dec, VkWriteDescriptorSetInlineUniformBlock *val)
-{
-    /* skip val->{sType,pNext} */
-    vn_decode_uint32_t(dec, &val->dataSize);
-    if (vn_peek_array_size(dec)) {
-        const size_t array_size = vn_decode_array_size(dec, val->dataSize);
-        val->pData = vn_cs_decoder_alloc_temp(dec, array_size);
-        if (!val->pData) return;
-        vn_decode_blob_array(dec, (void *)val->pData, array_size);
-    } else {
-        vn_decode_array_size(dec, val->dataSize);
-        val->pData = NULL;
-    }
-}
-
-static inline void
-vn_decode_VkWriteDescriptorSetInlineUniformBlock_temp(struct vn_cs_decoder *dec, VkWriteDescriptorSetInlineUniformBlock *val)
-{
-    VkStructureType stype;
-    vn_decode_VkStructureType(dec, &stype);
-    if (stype != VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK)
-        vn_cs_decoder_set_fatal(dec);
-
-    val->sType = stype;
-    val->pNext = vn_decode_VkWriteDescriptorSetInlineUniformBlock_pnext_temp(dec);
-    vn_decode_VkWriteDescriptorSetInlineUniformBlock_self_temp(dec, val);
-}
-
-static inline void
-vn_replace_VkWriteDescriptorSetInlineUniformBlock_handle_self(VkWriteDescriptorSetInlineUniformBlock *val)
-{
-    /* skip val->sType */
-    /* skip val->pNext */
-    /* skip val->dataSize */
-    /* skip val->pData */
-}
-
-static inline void
-vn_replace_VkWriteDescriptorSetInlineUniformBlock_handle(VkWriteDescriptorSetInlineUniformBlock *val)
-{
-    struct VkBaseOutStructure *pnext = (struct VkBaseOutStructure *)val;
-
-    do {
-        switch ((int32_t)pnext->sType) {
-        case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK:
-            vn_replace_VkWriteDescriptorSetInlineUniformBlock_handle_self((VkWriteDescriptorSetInlineUniformBlock *)pnext);
-            break;
-        default:
-            /* ignore unknown/unsupported struct */
-            break;
-        }
-        pnext = pnext->pNext;
-    } while (pnext);
-}
-
-/* struct VkWriteDescriptorSet chain */
-
-static inline void *
-vn_decode_VkWriteDescriptorSet_pnext_temp(struct vn_cs_decoder *dec)
-{
-    VkBaseOutStructure *pnext;
-    VkStructureType stype;
-
-    if (!vn_decode_simple_pointer(dec))
-        return NULL;
-
-    vn_decode_VkStructureType(dec, &stype);
-    switch ((int32_t)stype) {
-    case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK:
-        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkWriteDescriptorSetInlineUniformBlock));
-        if (pnext) {
-            pnext->sType = stype;
-            pnext->pNext = vn_decode_VkWriteDescriptorSet_pnext_temp(dec);
-            vn_decode_VkWriteDescriptorSetInlineUniformBlock_self_temp(dec, (VkWriteDescriptorSetInlineUniformBlock *)pnext);
-        }
-        break;
-    default:
-        /* unexpected struct */
-        pnext = NULL;
-        vn_cs_decoder_set_fatal(dec);
-        break;
-    }
-
-    return pnext;
-}
-
-static inline void
-vn_decode_VkWriteDescriptorSet_self_temp(struct vn_cs_decoder *dec, VkWriteDescriptorSet *val)
-{
-    /* skip val->{sType,pNext} */
-    vn_decode_VkDescriptorSet_lookup(dec, &val->dstSet);
-    vn_decode_uint32_t(dec, &val->dstBinding);
-    vn_decode_uint32_t(dec, &val->dstArrayElement);
-    vn_decode_uint32_t(dec, &val->descriptorCount);
-    vn_decode_VkDescriptorType(dec, &val->descriptorType);
-    if (vn_peek_array_size(dec)) {
-        const uint32_t iter_count = vn_decode_array_size(dec, val->descriptorCount);
-        val->pImageInfo = vn_cs_decoder_alloc_temp(dec, sizeof(*val->pImageInfo) * iter_count);
-        if (!val->pImageInfo) return;
-        for (uint32_t i = 0; i < iter_count; i++)
-            vn_decode_VkDescriptorImageInfo_temp(dec, &((VkDescriptorImageInfo *)val->pImageInfo)[i]);
-    } else {
-        vn_decode_array_size_unchecked(dec);
-        val->pImageInfo = NULL;
-    }
-    if (vn_peek_array_size(dec)) {
-        const uint32_t iter_count = vn_decode_array_size(dec, val->descriptorCount);
-        val->pBufferInfo = vn_cs_decoder_alloc_temp(dec, sizeof(*val->pBufferInfo) * iter_count);
-        if (!val->pBufferInfo) return;
-        for (uint32_t i = 0; i < iter_count; i++)
-            vn_decode_VkDescriptorBufferInfo_temp(dec, &((VkDescriptorBufferInfo *)val->pBufferInfo)[i]);
-    } else {
-        vn_decode_array_size_unchecked(dec);
-        val->pBufferInfo = NULL;
-    }
-    if (vn_peek_array_size(dec)) {
-        const uint32_t iter_count = vn_decode_array_size(dec, val->descriptorCount);
-        val->pTexelBufferView = vn_cs_decoder_alloc_temp(dec, sizeof(*val->pTexelBufferView) * iter_count);
-        if (!val->pTexelBufferView) return;
-        for (uint32_t i = 0; i < iter_count; i++)
-            vn_decode_VkBufferView_lookup(dec, &((VkBufferView *)val->pTexelBufferView)[i]);
-    } else {
-        vn_decode_array_size_unchecked(dec);
-        val->pTexelBufferView = NULL;
-    }
-}
-
-static inline void
-vn_decode_VkWriteDescriptorSet_temp(struct vn_cs_decoder *dec, VkWriteDescriptorSet *val)
-{
-    VkStructureType stype;
-    vn_decode_VkStructureType(dec, &stype);
-    if (stype != VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET)
-        vn_cs_decoder_set_fatal(dec);
-
-    val->sType = stype;
-    val->pNext = vn_decode_VkWriteDescriptorSet_pnext_temp(dec);
-    vn_decode_VkWriteDescriptorSet_self_temp(dec, val);
-}
-
-static inline void
-vn_replace_VkWriteDescriptorSet_handle_self(VkWriteDescriptorSet *val)
-{
-    /* skip val->sType */
-    /* skip val->pNext */
-    vn_replace_VkDescriptorSet_handle(&val->dstSet);
-    /* skip val->dstBinding */
-    /* skip val->dstArrayElement */
-    /* skip val->descriptorCount */
-    /* skip val->descriptorType */
-    if (val->pImageInfo) {
-       for (uint32_t i = 0; i < val->descriptorCount; i++)
-            vn_replace_VkDescriptorImageInfo_handle(&((VkDescriptorImageInfo *)val->pImageInfo)[i]);
-    }
-    if (val->pBufferInfo) {
-       for (uint32_t i = 0; i < val->descriptorCount; i++)
-            vn_replace_VkDescriptorBufferInfo_handle(&((VkDescriptorBufferInfo *)val->pBufferInfo)[i]);
-    }
-    if (val->pTexelBufferView) {
-       for (uint32_t i = 0; i < val->descriptorCount; i++)
-            vn_replace_VkBufferView_handle(&((VkBufferView *)val->pTexelBufferView)[i]);
-    }
-}
-
-static inline void
-vn_replace_VkWriteDescriptorSet_handle(VkWriteDescriptorSet *val)
-{
-    struct VkBaseOutStructure *pnext = (struct VkBaseOutStructure *)val;
-
-    do {
-        switch ((int32_t)pnext->sType) {
-        case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
-            vn_replace_VkWriteDescriptorSet_handle_self((VkWriteDescriptorSet *)pnext);
-            break;
-        case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK:
-            vn_replace_VkWriteDescriptorSetInlineUniformBlock_handle_self((VkWriteDescriptorSetInlineUniformBlock *)pnext);
-            break;
-        default:
-            /* ignore unknown/unsupported struct */
-            break;
-        }
-        pnext = pnext->pNext;
-    } while (pnext);
-}
-
 /* struct VkCopyDescriptorSet chain */
 
 static inline void *
diff --git a/src/venus/venus-protocol/vn_protocol_renderer_descriptor_set_layout.h b/src/venus/venus-protocol/vn_protocol_renderer_descriptor_set_layout.h
index da976cb..fe04424 100644
--- a/src/venus/venus-protocol/vn_protocol_renderer_descriptor_set_layout.h
+++ b/src/venus/venus-protocol/vn_protocol_renderer_descriptor_set_layout.h
@@ -137,6 +137,14 @@
             vn_decode_VkDescriptorSetLayoutBindingFlagsCreateInfo_self_temp(dec, (VkDescriptorSetLayoutBindingFlagsCreateInfo *)pnext);
         }
         break;
+    case VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkMutableDescriptorTypeCreateInfoEXT));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkDescriptorSetLayoutCreateInfo_pnext_temp(dec);
+            vn_decode_VkMutableDescriptorTypeCreateInfoEXT_self_temp(dec, (VkMutableDescriptorTypeCreateInfoEXT *)pnext);
+        }
+        break;
     default:
         /* unexpected struct */
         pnext = NULL;
@@ -204,6 +212,9 @@
         case VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO:
             vn_replace_VkDescriptorSetLayoutBindingFlagsCreateInfo_handle_self((VkDescriptorSetLayoutBindingFlagsCreateInfo *)pnext);
             break;
+        case VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT:
+            vn_replace_VkMutableDescriptorTypeCreateInfoEXT_handle_self((VkMutableDescriptorTypeCreateInfoEXT *)pnext);
+            break;
         default:
             /* ignore unknown/unsupported struct */
             break;
diff --git a/src/venus/venus-protocol/vn_protocol_renderer_device.h b/src/venus/venus-protocol/vn_protocol_renderer_device.h
index 4514514..ebc0e53 100644
--- a/src/venus/venus-protocol/vn_protocol_renderer_device.h
+++ b/src/venus/venus-protocol/vn_protocol_renderer_device.h
@@ -1585,6 +1585,115 @@
     } while (pnext);
 }
 
+/* struct VkPhysicalDeviceMultiDrawFeaturesEXT chain */
+
+static inline void
+vn_encode_VkPhysicalDeviceMultiDrawFeaturesEXT_pnext(struct vn_cs_encoder *enc, const void *val)
+{
+    /* no known/supported struct */
+    vn_encode_simple_pointer(enc, NULL);
+}
+
+static inline void
+vn_encode_VkPhysicalDeviceMultiDrawFeaturesEXT_self(struct vn_cs_encoder *enc, const VkPhysicalDeviceMultiDrawFeaturesEXT *val)
+{
+    /* skip val->{sType,pNext} */
+    vn_encode_VkBool32(enc, &val->multiDraw);
+}
+
+static inline void
+vn_encode_VkPhysicalDeviceMultiDrawFeaturesEXT(struct vn_cs_encoder *enc, const VkPhysicalDeviceMultiDrawFeaturesEXT *val)
+{
+    assert(val->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT);
+    vn_encode_VkStructureType(enc, &(VkStructureType){ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT });
+    vn_encode_VkPhysicalDeviceMultiDrawFeaturesEXT_pnext(enc, val->pNext);
+    vn_encode_VkPhysicalDeviceMultiDrawFeaturesEXT_self(enc, val);
+}
+
+static inline void *
+vn_decode_VkPhysicalDeviceMultiDrawFeaturesEXT_pnext_temp(struct vn_cs_decoder *dec)
+{
+    /* no known/supported struct */
+    if (vn_decode_simple_pointer(dec))
+        vn_cs_decoder_set_fatal(dec);
+    return NULL;
+}
+
+static inline void
+vn_decode_VkPhysicalDeviceMultiDrawFeaturesEXT_self_temp(struct vn_cs_decoder *dec, VkPhysicalDeviceMultiDrawFeaturesEXT *val)
+{
+    /* skip val->{sType,pNext} */
+    vn_decode_VkBool32(dec, &val->multiDraw);
+}
+
+static inline void
+vn_decode_VkPhysicalDeviceMultiDrawFeaturesEXT_temp(struct vn_cs_decoder *dec, VkPhysicalDeviceMultiDrawFeaturesEXT *val)
+{
+    VkStructureType stype;
+    vn_decode_VkStructureType(dec, &stype);
+    if (stype != VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT)
+        vn_cs_decoder_set_fatal(dec);
+
+    val->sType = stype;
+    val->pNext = vn_decode_VkPhysicalDeviceMultiDrawFeaturesEXT_pnext_temp(dec);
+    vn_decode_VkPhysicalDeviceMultiDrawFeaturesEXT_self_temp(dec, val);
+}
+
+static inline void *
+vn_decode_VkPhysicalDeviceMultiDrawFeaturesEXT_pnext_partial_temp(struct vn_cs_decoder *dec)
+{
+    /* no known/supported struct */
+    if (vn_decode_simple_pointer(dec))
+        vn_cs_decoder_set_fatal(dec);
+    return NULL;
+}
+
+static inline void
+vn_decode_VkPhysicalDeviceMultiDrawFeaturesEXT_self_partial_temp(struct vn_cs_decoder *dec, VkPhysicalDeviceMultiDrawFeaturesEXT *val)
+{
+    /* skip val->{sType,pNext} */
+    /* skip val->multiDraw */
+}
+
+static inline void
+vn_decode_VkPhysicalDeviceMultiDrawFeaturesEXT_partial_temp(struct vn_cs_decoder *dec, VkPhysicalDeviceMultiDrawFeaturesEXT *val)
+{
+    VkStructureType stype;
+    vn_decode_VkStructureType(dec, &stype);
+    if (stype != VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT)
+        vn_cs_decoder_set_fatal(dec);
+
+    val->sType = stype;
+    val->pNext = vn_decode_VkPhysicalDeviceMultiDrawFeaturesEXT_pnext_partial_temp(dec);
+    vn_decode_VkPhysicalDeviceMultiDrawFeaturesEXT_self_partial_temp(dec, val);
+}
+
+static inline void
+vn_replace_VkPhysicalDeviceMultiDrawFeaturesEXT_handle_self(VkPhysicalDeviceMultiDrawFeaturesEXT *val)
+{
+    /* skip val->sType */
+    /* skip val->pNext */
+    /* skip val->multiDraw */
+}
+
+static inline void
+vn_replace_VkPhysicalDeviceMultiDrawFeaturesEXT_handle(VkPhysicalDeviceMultiDrawFeaturesEXT *val)
+{
+    struct VkBaseOutStructure *pnext = (struct VkBaseOutStructure *)val;
+
+    do {
+        switch ((int32_t)pnext->sType) {
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT:
+            vn_replace_VkPhysicalDeviceMultiDrawFeaturesEXT_handle_self((VkPhysicalDeviceMultiDrawFeaturesEXT *)pnext);
+            break;
+        default:
+            /* ignore unknown/unsupported struct */
+            break;
+        }
+        pnext = pnext->pNext;
+    } while (pnext);
+}
+
 /* struct VkPhysicalDeviceInlineUniformBlockFeatures chain */
 
 static inline void
@@ -3998,6 +4107,119 @@
     } while (pnext);
 }
 
+/* struct VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT chain */
+
+static inline void
+vn_encode_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_pnext(struct vn_cs_encoder *enc, const void *val)
+{
+    /* no known/supported struct */
+    vn_encode_simple_pointer(enc, NULL);
+}
+
+static inline void
+vn_encode_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_self(struct vn_cs_encoder *enc, const VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT *val)
+{
+    /* skip val->{sType,pNext} */
+    vn_encode_VkBool32(enc, &val->primitiveTopologyListRestart);
+    vn_encode_VkBool32(enc, &val->primitiveTopologyPatchListRestart);
+}
+
+static inline void
+vn_encode_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT(struct vn_cs_encoder *enc, const VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT *val)
+{
+    assert(val->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT);
+    vn_encode_VkStructureType(enc, &(VkStructureType){ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT });
+    vn_encode_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_pnext(enc, val->pNext);
+    vn_encode_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_self(enc, val);
+}
+
+static inline void *
+vn_decode_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_pnext_temp(struct vn_cs_decoder *dec)
+{
+    /* no known/supported struct */
+    if (vn_decode_simple_pointer(dec))
+        vn_cs_decoder_set_fatal(dec);
+    return NULL;
+}
+
+static inline void
+vn_decode_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_self_temp(struct vn_cs_decoder *dec, VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT *val)
+{
+    /* skip val->{sType,pNext} */
+    vn_decode_VkBool32(dec, &val->primitiveTopologyListRestart);
+    vn_decode_VkBool32(dec, &val->primitiveTopologyPatchListRestart);
+}
+
+static inline void
+vn_decode_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_temp(struct vn_cs_decoder *dec, VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT *val)
+{
+    VkStructureType stype;
+    vn_decode_VkStructureType(dec, &stype);
+    if (stype != VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT)
+        vn_cs_decoder_set_fatal(dec);
+
+    val->sType = stype;
+    val->pNext = vn_decode_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_pnext_temp(dec);
+    vn_decode_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_self_temp(dec, val);
+}
+
+static inline void *
+vn_decode_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_pnext_partial_temp(struct vn_cs_decoder *dec)
+{
+    /* no known/supported struct */
+    if (vn_decode_simple_pointer(dec))
+        vn_cs_decoder_set_fatal(dec);
+    return NULL;
+}
+
+static inline void
+vn_decode_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_self_partial_temp(struct vn_cs_decoder *dec, VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT *val)
+{
+    /* skip val->{sType,pNext} */
+    /* skip val->primitiveTopologyListRestart */
+    /* skip val->primitiveTopologyPatchListRestart */
+}
+
+static inline void
+vn_decode_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_partial_temp(struct vn_cs_decoder *dec, VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT *val)
+{
+    VkStructureType stype;
+    vn_decode_VkStructureType(dec, &stype);
+    if (stype != VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT)
+        vn_cs_decoder_set_fatal(dec);
+
+    val->sType = stype;
+    val->pNext = vn_decode_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_pnext_partial_temp(dec);
+    vn_decode_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_self_partial_temp(dec, val);
+}
+
+static inline void
+vn_replace_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_handle_self(VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT *val)
+{
+    /* skip val->sType */
+    /* skip val->pNext */
+    /* skip val->primitiveTopologyListRestart */
+    /* skip val->primitiveTopologyPatchListRestart */
+}
+
+static inline void
+vn_replace_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_handle(VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT *val)
+{
+    struct VkBaseOutStructure *pnext = (struct VkBaseOutStructure *)val;
+
+    do {
+        switch ((int32_t)pnext->sType) {
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT:
+            vn_replace_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_handle_self((VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT *)pnext);
+            break;
+        default:
+            /* ignore unknown/unsupported struct */
+            break;
+        }
+        pnext = pnext->pNext;
+    } while (pnext);
+}
+
 /* struct VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures chain */
 
 static inline void
@@ -6074,6 +6296,224 @@
     } while (pnext);
 }
 
+/* struct VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT chain */
+
+static inline void
+vn_encode_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_pnext(struct vn_cs_encoder *enc, const void *val)
+{
+    /* no known/supported struct */
+    vn_encode_simple_pointer(enc, NULL);
+}
+
+static inline void
+vn_encode_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_self(struct vn_cs_encoder *enc, const VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *val)
+{
+    /* skip val->{sType,pNext} */
+    vn_encode_VkBool32(enc, &val->mutableDescriptorType);
+}
+
+static inline void
+vn_encode_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT(struct vn_cs_encoder *enc, const VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *val)
+{
+    assert(val->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT);
+    vn_encode_VkStructureType(enc, &(VkStructureType){ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT });
+    vn_encode_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_pnext(enc, val->pNext);
+    vn_encode_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_self(enc, val);
+}
+
+static inline void *
+vn_decode_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_pnext_temp(struct vn_cs_decoder *dec)
+{
+    /* no known/supported struct */
+    if (vn_decode_simple_pointer(dec))
+        vn_cs_decoder_set_fatal(dec);
+    return NULL;
+}
+
+static inline void
+vn_decode_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_self_temp(struct vn_cs_decoder *dec, VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *val)
+{
+    /* skip val->{sType,pNext} */
+    vn_decode_VkBool32(dec, &val->mutableDescriptorType);
+}
+
+static inline void
+vn_decode_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_temp(struct vn_cs_decoder *dec, VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *val)
+{
+    VkStructureType stype;
+    vn_decode_VkStructureType(dec, &stype);
+    if (stype != VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT)
+        vn_cs_decoder_set_fatal(dec);
+
+    val->sType = stype;
+    val->pNext = vn_decode_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_pnext_temp(dec);
+    vn_decode_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_self_temp(dec, val);
+}
+
+static inline void *
+vn_decode_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_pnext_partial_temp(struct vn_cs_decoder *dec)
+{
+    /* no known/supported struct */
+    if (vn_decode_simple_pointer(dec))
+        vn_cs_decoder_set_fatal(dec);
+    return NULL;
+}
+
+static inline void
+vn_decode_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_self_partial_temp(struct vn_cs_decoder *dec, VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *val)
+{
+    /* skip val->{sType,pNext} */
+    /* skip val->mutableDescriptorType */
+}
+
+static inline void
+vn_decode_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_partial_temp(struct vn_cs_decoder *dec, VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *val)
+{
+    VkStructureType stype;
+    vn_decode_VkStructureType(dec, &stype);
+    if (stype != VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT)
+        vn_cs_decoder_set_fatal(dec);
+
+    val->sType = stype;
+    val->pNext = vn_decode_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_pnext_partial_temp(dec);
+    vn_decode_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_self_partial_temp(dec, val);
+}
+
+static inline void
+vn_replace_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_handle_self(VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *val)
+{
+    /* skip val->sType */
+    /* skip val->pNext */
+    /* skip val->mutableDescriptorType */
+}
+
+static inline void
+vn_replace_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_handle(VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *val)
+{
+    struct VkBaseOutStructure *pnext = (struct VkBaseOutStructure *)val;
+
+    do {
+        switch ((int32_t)pnext->sType) {
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT:
+            vn_replace_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_handle_self((VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *)pnext);
+            break;
+        default:
+            /* ignore unknown/unsupported struct */
+            break;
+        }
+        pnext = pnext->pNext;
+    } while (pnext);
+}
+
+/* struct VkPhysicalDeviceDepthClipControlFeaturesEXT chain */
+
+static inline void
+vn_encode_VkPhysicalDeviceDepthClipControlFeaturesEXT_pnext(struct vn_cs_encoder *enc, const void *val)
+{
+    /* no known/supported struct */
+    vn_encode_simple_pointer(enc, NULL);
+}
+
+static inline void
+vn_encode_VkPhysicalDeviceDepthClipControlFeaturesEXT_self(struct vn_cs_encoder *enc, const VkPhysicalDeviceDepthClipControlFeaturesEXT *val)
+{
+    /* skip val->{sType,pNext} */
+    vn_encode_VkBool32(enc, &val->depthClipControl);
+}
+
+static inline void
+vn_encode_VkPhysicalDeviceDepthClipControlFeaturesEXT(struct vn_cs_encoder *enc, const VkPhysicalDeviceDepthClipControlFeaturesEXT *val)
+{
+    assert(val->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT);
+    vn_encode_VkStructureType(enc, &(VkStructureType){ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT });
+    vn_encode_VkPhysicalDeviceDepthClipControlFeaturesEXT_pnext(enc, val->pNext);
+    vn_encode_VkPhysicalDeviceDepthClipControlFeaturesEXT_self(enc, val);
+}
+
+static inline void *
+vn_decode_VkPhysicalDeviceDepthClipControlFeaturesEXT_pnext_temp(struct vn_cs_decoder *dec)
+{
+    /* no known/supported struct */
+    if (vn_decode_simple_pointer(dec))
+        vn_cs_decoder_set_fatal(dec);
+    return NULL;
+}
+
+static inline void
+vn_decode_VkPhysicalDeviceDepthClipControlFeaturesEXT_self_temp(struct vn_cs_decoder *dec, VkPhysicalDeviceDepthClipControlFeaturesEXT *val)
+{
+    /* skip val->{sType,pNext} */
+    vn_decode_VkBool32(dec, &val->depthClipControl);
+}
+
+static inline void
+vn_decode_VkPhysicalDeviceDepthClipControlFeaturesEXT_temp(struct vn_cs_decoder *dec, VkPhysicalDeviceDepthClipControlFeaturesEXT *val)
+{
+    VkStructureType stype;
+    vn_decode_VkStructureType(dec, &stype);
+    if (stype != VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT)
+        vn_cs_decoder_set_fatal(dec);
+
+    val->sType = stype;
+    val->pNext = vn_decode_VkPhysicalDeviceDepthClipControlFeaturesEXT_pnext_temp(dec);
+    vn_decode_VkPhysicalDeviceDepthClipControlFeaturesEXT_self_temp(dec, val);
+}
+
+static inline void *
+vn_decode_VkPhysicalDeviceDepthClipControlFeaturesEXT_pnext_partial_temp(struct vn_cs_decoder *dec)
+{
+    /* no known/supported struct */
+    if (vn_decode_simple_pointer(dec))
+        vn_cs_decoder_set_fatal(dec);
+    return NULL;
+}
+
+static inline void
+vn_decode_VkPhysicalDeviceDepthClipControlFeaturesEXT_self_partial_temp(struct vn_cs_decoder *dec, VkPhysicalDeviceDepthClipControlFeaturesEXT *val)
+{
+    /* skip val->{sType,pNext} */
+    /* skip val->depthClipControl */
+}
+
+static inline void
+vn_decode_VkPhysicalDeviceDepthClipControlFeaturesEXT_partial_temp(struct vn_cs_decoder *dec, VkPhysicalDeviceDepthClipControlFeaturesEXT *val)
+{
+    VkStructureType stype;
+    vn_decode_VkStructureType(dec, &stype);
+    if (stype != VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT)
+        vn_cs_decoder_set_fatal(dec);
+
+    val->sType = stype;
+    val->pNext = vn_decode_VkPhysicalDeviceDepthClipControlFeaturesEXT_pnext_partial_temp(dec);
+    vn_decode_VkPhysicalDeviceDepthClipControlFeaturesEXT_self_partial_temp(dec, val);
+}
+
+static inline void
+vn_replace_VkPhysicalDeviceDepthClipControlFeaturesEXT_handle_self(VkPhysicalDeviceDepthClipControlFeaturesEXT *val)
+{
+    /* skip val->sType */
+    /* skip val->pNext */
+    /* skip val->depthClipControl */
+}
+
+static inline void
+vn_replace_VkPhysicalDeviceDepthClipControlFeaturesEXT_handle(VkPhysicalDeviceDepthClipControlFeaturesEXT *val)
+{
+    struct VkBaseOutStructure *pnext = (struct VkBaseOutStructure *)val;
+
+    do {
+        switch ((int32_t)pnext->sType) {
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT:
+            vn_replace_VkPhysicalDeviceDepthClipControlFeaturesEXT_handle_self((VkPhysicalDeviceDepthClipControlFeaturesEXT *)pnext);
+            break;
+        default:
+            /* ignore unknown/unsupported struct */
+            break;
+        }
+        pnext = pnext->pNext;
+    } while (pnext);
+}
+
 /* struct VkPhysicalDeviceSynchronization2Features chain */
 
 static inline void
@@ -6183,6 +6623,123 @@
     } while (pnext);
 }
 
+/* struct VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT chain */
+
+static inline void
+vn_encode_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_pnext(struct vn_cs_encoder *enc, const void *val)
+{
+    /* no known/supported struct */
+    vn_encode_simple_pointer(enc, NULL);
+}
+
+static inline void
+vn_encode_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_self(struct vn_cs_encoder *enc, const VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT *val)
+{
+    /* skip val->{sType,pNext} */
+    vn_encode_VkBool32(enc, &val->primitivesGeneratedQuery);
+    vn_encode_VkBool32(enc, &val->primitivesGeneratedQueryWithRasterizerDiscard);
+    vn_encode_VkBool32(enc, &val->primitivesGeneratedQueryWithNonZeroStreams);
+}
+
+static inline void
+vn_encode_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT(struct vn_cs_encoder *enc, const VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT *val)
+{
+    assert(val->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT);
+    vn_encode_VkStructureType(enc, &(VkStructureType){ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT });
+    vn_encode_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_pnext(enc, val->pNext);
+    vn_encode_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_self(enc, val);
+}
+
+static inline void *
+vn_decode_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_pnext_temp(struct vn_cs_decoder *dec)
+{
+    /* no known/supported struct */
+    if (vn_decode_simple_pointer(dec))
+        vn_cs_decoder_set_fatal(dec);
+    return NULL;
+}
+
+static inline void
+vn_decode_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_self_temp(struct vn_cs_decoder *dec, VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT *val)
+{
+    /* skip val->{sType,pNext} */
+    vn_decode_VkBool32(dec, &val->primitivesGeneratedQuery);
+    vn_decode_VkBool32(dec, &val->primitivesGeneratedQueryWithRasterizerDiscard);
+    vn_decode_VkBool32(dec, &val->primitivesGeneratedQueryWithNonZeroStreams);
+}
+
+static inline void
+vn_decode_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_temp(struct vn_cs_decoder *dec, VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT *val)
+{
+    VkStructureType stype;
+    vn_decode_VkStructureType(dec, &stype);
+    if (stype != VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT)
+        vn_cs_decoder_set_fatal(dec);
+
+    val->sType = stype;
+    val->pNext = vn_decode_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_pnext_temp(dec);
+    vn_decode_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_self_temp(dec, val);
+}
+
+static inline void *
+vn_decode_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_pnext_partial_temp(struct vn_cs_decoder *dec)
+{
+    /* no known/supported struct */
+    if (vn_decode_simple_pointer(dec))
+        vn_cs_decoder_set_fatal(dec);
+    return NULL;
+}
+
+static inline void
+vn_decode_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_self_partial_temp(struct vn_cs_decoder *dec, VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT *val)
+{
+    /* skip val->{sType,pNext} */
+    /* skip val->primitivesGeneratedQuery */
+    /* skip val->primitivesGeneratedQueryWithRasterizerDiscard */
+    /* skip val->primitivesGeneratedQueryWithNonZeroStreams */
+}
+
+static inline void
+vn_decode_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_partial_temp(struct vn_cs_decoder *dec, VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT *val)
+{
+    VkStructureType stype;
+    vn_decode_VkStructureType(dec, &stype);
+    if (stype != VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT)
+        vn_cs_decoder_set_fatal(dec);
+
+    val->sType = stype;
+    val->pNext = vn_decode_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_pnext_partial_temp(dec);
+    vn_decode_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_self_partial_temp(dec, val);
+}
+
+static inline void
+vn_replace_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_handle_self(VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT *val)
+{
+    /* skip val->sType */
+    /* skip val->pNext */
+    /* skip val->primitivesGeneratedQuery */
+    /* skip val->primitivesGeneratedQueryWithRasterizerDiscard */
+    /* skip val->primitivesGeneratedQueryWithNonZeroStreams */
+}
+
+static inline void
+vn_replace_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_handle(VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT *val)
+{
+    struct VkBaseOutStructure *pnext = (struct VkBaseOutStructure *)val;
+
+    do {
+        switch ((int32_t)pnext->sType) {
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT:
+            vn_replace_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_handle_self((VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT *)pnext);
+            break;
+        default:
+            /* ignore unknown/unsupported struct */
+            break;
+        }
+        pnext = pnext->pNext;
+    } while (pnext);
+}
+
 /* struct VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT chain */
 
 static inline void
@@ -6783,6 +7340,12 @@
             vn_encode_VkPhysicalDeviceFeatures2_pnext(enc, pnext->pNext);
             vn_encode_VkPhysicalDeviceProtectedMemoryFeatures_self(enc, (const VkPhysicalDeviceProtectedMemoryFeatures *)pnext);
             return;
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT:
+            vn_encode_simple_pointer(enc, pnext);
+            vn_encode_VkStructureType(enc, &pnext->sType);
+            vn_encode_VkPhysicalDeviceFeatures2_pnext(enc, pnext->pNext);
+            vn_encode_VkPhysicalDeviceMultiDrawFeaturesEXT_self(enc, (const VkPhysicalDeviceMultiDrawFeaturesEXT *)pnext);
+            return;
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES:
             vn_encode_simple_pointer(enc, pnext);
             vn_encode_VkStructureType(enc, &pnext->sType);
@@ -6909,6 +7472,12 @@
             vn_encode_VkPhysicalDeviceFeatures2_pnext(enc, pnext->pNext);
             vn_encode_VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures_self(enc, (const VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures *)pnext);
             return;
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT:
+            vn_encode_simple_pointer(enc, pnext);
+            vn_encode_VkStructureType(enc, &pnext->sType);
+            vn_encode_VkPhysicalDeviceFeatures2_pnext(enc, pnext->pNext);
+            vn_encode_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_self(enc, (const VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT *)pnext);
+            return;
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES:
             vn_encode_simple_pointer(enc, pnext);
             vn_encode_VkStructureType(enc, &pnext->sType);
@@ -7005,12 +7574,30 @@
             vn_encode_VkPhysicalDeviceFeatures2_pnext(enc, pnext->pNext);
             vn_encode_VkPhysicalDeviceShaderTerminateInvocationFeatures_self(enc, (const VkPhysicalDeviceShaderTerminateInvocationFeatures *)pnext);
             return;
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT:
+            vn_encode_simple_pointer(enc, pnext);
+            vn_encode_VkStructureType(enc, &pnext->sType);
+            vn_encode_VkPhysicalDeviceFeatures2_pnext(enc, pnext->pNext);
+            vn_encode_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_self(enc, (const VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *)pnext);
+            return;
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT:
+            vn_encode_simple_pointer(enc, pnext);
+            vn_encode_VkStructureType(enc, &pnext->sType);
+            vn_encode_VkPhysicalDeviceFeatures2_pnext(enc, pnext->pNext);
+            vn_encode_VkPhysicalDeviceDepthClipControlFeaturesEXT_self(enc, (const VkPhysicalDeviceDepthClipControlFeaturesEXT *)pnext);
+            return;
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES:
             vn_encode_simple_pointer(enc, pnext);
             vn_encode_VkStructureType(enc, &pnext->sType);
             vn_encode_VkPhysicalDeviceFeatures2_pnext(enc, pnext->pNext);
             vn_encode_VkPhysicalDeviceSynchronization2Features_self(enc, (const VkPhysicalDeviceSynchronization2Features *)pnext);
             return;
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT:
+            vn_encode_simple_pointer(enc, pnext);
+            vn_encode_VkStructureType(enc, &pnext->sType);
+            vn_encode_VkPhysicalDeviceFeatures2_pnext(enc, pnext->pNext);
+            vn_encode_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_self(enc, (const VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT *)pnext);
+            return;
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT:
             vn_encode_simple_pointer(enc, pnext);
             vn_encode_VkStructureType(enc, &pnext->sType);
@@ -7134,6 +7721,14 @@
             vn_decode_VkPhysicalDeviceProtectedMemoryFeatures_self_temp(dec, (VkPhysicalDeviceProtectedMemoryFeatures *)pnext);
         }
         break;
+    case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceMultiDrawFeaturesEXT));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkPhysicalDeviceFeatures2_pnext_temp(dec);
+            vn_decode_VkPhysicalDeviceMultiDrawFeaturesEXT_self_temp(dec, (VkPhysicalDeviceMultiDrawFeaturesEXT *)pnext);
+        }
+        break;
     case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES:
         pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceInlineUniformBlockFeatures));
         if (pnext) {
@@ -7302,6 +7897,14 @@
             vn_decode_VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures_self_temp(dec, (VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures *)pnext);
         }
         break;
+    case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkPhysicalDeviceFeatures2_pnext_temp(dec);
+            vn_decode_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_self_temp(dec, (VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT *)pnext);
+        }
+        break;
     case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES:
         pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures));
         if (pnext) {
@@ -7430,6 +8033,22 @@
             vn_decode_VkPhysicalDeviceShaderTerminateInvocationFeatures_self_temp(dec, (VkPhysicalDeviceShaderTerminateInvocationFeatures *)pnext);
         }
         break;
+    case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkPhysicalDeviceFeatures2_pnext_temp(dec);
+            vn_decode_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_self_temp(dec, (VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *)pnext);
+        }
+        break;
+    case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceDepthClipControlFeaturesEXT));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkPhysicalDeviceFeatures2_pnext_temp(dec);
+            vn_decode_VkPhysicalDeviceDepthClipControlFeaturesEXT_self_temp(dec, (VkPhysicalDeviceDepthClipControlFeaturesEXT *)pnext);
+        }
+        break;
     case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES:
         pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceSynchronization2Features));
         if (pnext) {
@@ -7438,6 +8057,14 @@
             vn_decode_VkPhysicalDeviceSynchronization2Features_self_temp(dec, (VkPhysicalDeviceSynchronization2Features *)pnext);
         }
         break;
+    case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkPhysicalDeviceFeatures2_pnext_temp(dec);
+            vn_decode_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_self_temp(dec, (VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT *)pnext);
+        }
+        break;
     case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT:
         pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT));
         if (pnext) {
@@ -7575,6 +8202,14 @@
             vn_decode_VkPhysicalDeviceProtectedMemoryFeatures_self_partial_temp(dec, (VkPhysicalDeviceProtectedMemoryFeatures *)pnext);
         }
         break;
+    case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceMultiDrawFeaturesEXT));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkPhysicalDeviceFeatures2_pnext_partial_temp(dec);
+            vn_decode_VkPhysicalDeviceMultiDrawFeaturesEXT_self_partial_temp(dec, (VkPhysicalDeviceMultiDrawFeaturesEXT *)pnext);
+        }
+        break;
     case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES:
         pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceInlineUniformBlockFeatures));
         if (pnext) {
@@ -7743,6 +8378,14 @@
             vn_decode_VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures_self_partial_temp(dec, (VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures *)pnext);
         }
         break;
+    case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkPhysicalDeviceFeatures2_pnext_partial_temp(dec);
+            vn_decode_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_self_partial_temp(dec, (VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT *)pnext);
+        }
+        break;
     case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES:
         pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures));
         if (pnext) {
@@ -7871,6 +8514,22 @@
             vn_decode_VkPhysicalDeviceShaderTerminateInvocationFeatures_self_partial_temp(dec, (VkPhysicalDeviceShaderTerminateInvocationFeatures *)pnext);
         }
         break;
+    case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkPhysicalDeviceFeatures2_pnext_partial_temp(dec);
+            vn_decode_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_self_partial_temp(dec, (VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *)pnext);
+        }
+        break;
+    case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceDepthClipControlFeaturesEXT));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkPhysicalDeviceFeatures2_pnext_partial_temp(dec);
+            vn_decode_VkPhysicalDeviceDepthClipControlFeaturesEXT_self_partial_temp(dec, (VkPhysicalDeviceDepthClipControlFeaturesEXT *)pnext);
+        }
+        break;
     case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES:
         pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceSynchronization2Features));
         if (pnext) {
@@ -7879,6 +8538,14 @@
             vn_decode_VkPhysicalDeviceSynchronization2Features_self_partial_temp(dec, (VkPhysicalDeviceSynchronization2Features *)pnext);
         }
         break;
+    case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkPhysicalDeviceFeatures2_pnext_partial_temp(dec);
+            vn_decode_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_self_partial_temp(dec, (VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT *)pnext);
+        }
+        break;
     case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT:
         pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT));
         if (pnext) {
@@ -7988,6 +8655,9 @@
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES:
             vn_replace_VkPhysicalDeviceProtectedMemoryFeatures_handle_self((VkPhysicalDeviceProtectedMemoryFeatures *)pnext);
             break;
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT:
+            vn_replace_VkPhysicalDeviceMultiDrawFeaturesEXT_handle_self((VkPhysicalDeviceMultiDrawFeaturesEXT *)pnext);
+            break;
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES:
             vn_replace_VkPhysicalDeviceInlineUniformBlockFeatures_handle_self((VkPhysicalDeviceInlineUniformBlockFeatures *)pnext);
             break;
@@ -8051,6 +8721,9 @@
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES:
             vn_replace_VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures_handle_self((VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures *)pnext);
             break;
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT:
+            vn_replace_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_handle_self((VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT *)pnext);
+            break;
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES:
             vn_replace_VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures_handle_self((VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures *)pnext);
             break;
@@ -8099,9 +8772,18 @@
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES:
             vn_replace_VkPhysicalDeviceShaderTerminateInvocationFeatures_handle_self((VkPhysicalDeviceShaderTerminateInvocationFeatures *)pnext);
             break;
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT:
+            vn_replace_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_handle_self((VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *)pnext);
+            break;
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT:
+            vn_replace_VkPhysicalDeviceDepthClipControlFeaturesEXT_handle_self((VkPhysicalDeviceDepthClipControlFeaturesEXT *)pnext);
+            break;
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES:
             vn_replace_VkPhysicalDeviceSynchronization2Features_handle_self((VkPhysicalDeviceSynchronization2Features *)pnext);
             break;
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT:
+            vn_replace_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_handle_self((VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT *)pnext);
+            break;
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT:
             vn_replace_VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT_handle_self((VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT *)pnext);
             break;
@@ -8289,6 +8971,14 @@
             vn_decode_VkPhysicalDeviceProtectedMemoryFeatures_self_temp(dec, (VkPhysicalDeviceProtectedMemoryFeatures *)pnext);
         }
         break;
+    case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceMultiDrawFeaturesEXT));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkDeviceCreateInfo_pnext_temp(dec);
+            vn_decode_VkPhysicalDeviceMultiDrawFeaturesEXT_self_temp(dec, (VkPhysicalDeviceMultiDrawFeaturesEXT *)pnext);
+        }
+        break;
     case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES:
         pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceInlineUniformBlockFeatures));
         if (pnext) {
@@ -8457,6 +9147,14 @@
             vn_decode_VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures_self_temp(dec, (VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures *)pnext);
         }
         break;
+    case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkDeviceCreateInfo_pnext_temp(dec);
+            vn_decode_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_self_temp(dec, (VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT *)pnext);
+        }
+        break;
     case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES:
         pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures));
         if (pnext) {
@@ -8585,6 +9283,22 @@
             vn_decode_VkPhysicalDeviceShaderTerminateInvocationFeatures_self_temp(dec, (VkPhysicalDeviceShaderTerminateInvocationFeatures *)pnext);
         }
         break;
+    case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkDeviceCreateInfo_pnext_temp(dec);
+            vn_decode_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_self_temp(dec, (VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *)pnext);
+        }
+        break;
+    case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceDepthClipControlFeaturesEXT));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkDeviceCreateInfo_pnext_temp(dec);
+            vn_decode_VkPhysicalDeviceDepthClipControlFeaturesEXT_self_temp(dec, (VkPhysicalDeviceDepthClipControlFeaturesEXT *)pnext);
+        }
+        break;
     case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES:
         pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceSynchronization2Features));
         if (pnext) {
@@ -8593,6 +9307,14 @@
             vn_decode_VkPhysicalDeviceSynchronization2Features_self_temp(dec, (VkPhysicalDeviceSynchronization2Features *)pnext);
         }
         break;
+    case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkDeviceCreateInfo_pnext_temp(dec);
+            vn_decode_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_self_temp(dec, (VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT *)pnext);
+        }
+        break;
     case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT:
         pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT));
         if (pnext) {
@@ -8770,6 +9492,9 @@
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES:
             vn_replace_VkPhysicalDeviceProtectedMemoryFeatures_handle_self((VkPhysicalDeviceProtectedMemoryFeatures *)pnext);
             break;
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT:
+            vn_replace_VkPhysicalDeviceMultiDrawFeaturesEXT_handle_self((VkPhysicalDeviceMultiDrawFeaturesEXT *)pnext);
+            break;
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES:
             vn_replace_VkPhysicalDeviceInlineUniformBlockFeatures_handle_self((VkPhysicalDeviceInlineUniformBlockFeatures *)pnext);
             break;
@@ -8833,6 +9558,9 @@
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES:
             vn_replace_VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures_handle_self((VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures *)pnext);
             break;
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT:
+            vn_replace_VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT_handle_self((VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT *)pnext);
+            break;
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES:
             vn_replace_VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures_handle_self((VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures *)pnext);
             break;
@@ -8881,9 +9609,18 @@
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES:
             vn_replace_VkPhysicalDeviceShaderTerminateInvocationFeatures_handle_self((VkPhysicalDeviceShaderTerminateInvocationFeatures *)pnext);
             break;
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT:
+            vn_replace_VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT_handle_self((VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *)pnext);
+            break;
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT:
+            vn_replace_VkPhysicalDeviceDepthClipControlFeaturesEXT_handle_self((VkPhysicalDeviceDepthClipControlFeaturesEXT *)pnext);
+            break;
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES:
             vn_replace_VkPhysicalDeviceSynchronization2Features_handle_self((VkPhysicalDeviceSynchronization2Features *)pnext);
             break;
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT:
+            vn_replace_VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT_handle_self((VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT *)pnext);
+            break;
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT:
             vn_replace_VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT_handle_self((VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT *)pnext);
             break;
@@ -8907,6 +9644,114 @@
     } while (pnext);
 }
 
+/* struct VkPhysicalDeviceMultiDrawPropertiesEXT chain */
+
+static inline void
+vn_encode_VkPhysicalDeviceMultiDrawPropertiesEXT_pnext(struct vn_cs_encoder *enc, const void *val)
+{
+    /* no known/supported struct */
+    vn_encode_simple_pointer(enc, NULL);
+}
+
+static inline void
+vn_encode_VkPhysicalDeviceMultiDrawPropertiesEXT_self(struct vn_cs_encoder *enc, const VkPhysicalDeviceMultiDrawPropertiesEXT *val)
+{
+    /* skip val->{sType,pNext} */
+    vn_encode_uint32_t(enc, &val->maxMultiDrawCount);
+}
+
+static inline void
+vn_encode_VkPhysicalDeviceMultiDrawPropertiesEXT(struct vn_cs_encoder *enc, const VkPhysicalDeviceMultiDrawPropertiesEXT *val)
+{
+    assert(val->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT);
+    vn_encode_VkStructureType(enc, &(VkStructureType){ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT });
+    vn_encode_VkPhysicalDeviceMultiDrawPropertiesEXT_pnext(enc, val->pNext);
+    vn_encode_VkPhysicalDeviceMultiDrawPropertiesEXT_self(enc, val);
+}
+
+static inline void *
+vn_decode_VkPhysicalDeviceMultiDrawPropertiesEXT_pnext_partial_temp(struct vn_cs_decoder *dec)
+{
+    /* no known/supported struct */
+    if (vn_decode_simple_pointer(dec))
+        vn_cs_decoder_set_fatal(dec);
+    return NULL;
+}
+
+static inline void
+vn_decode_VkPhysicalDeviceMultiDrawPropertiesEXT_self_partial_temp(struct vn_cs_decoder *dec, VkPhysicalDeviceMultiDrawPropertiesEXT *val)
+{
+    /* skip val->{sType,pNext} */
+    /* skip val->maxMultiDrawCount */
+}
+
+static inline void
+vn_decode_VkPhysicalDeviceMultiDrawPropertiesEXT_partial_temp(struct vn_cs_decoder *dec, VkPhysicalDeviceMultiDrawPropertiesEXT *val)
+{
+    VkStructureType stype;
+    vn_decode_VkStructureType(dec, &stype);
+    if (stype != VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT)
+        vn_cs_decoder_set_fatal(dec);
+
+    val->sType = stype;
+    val->pNext = vn_decode_VkPhysicalDeviceMultiDrawPropertiesEXT_pnext_partial_temp(dec);
+    vn_decode_VkPhysicalDeviceMultiDrawPropertiesEXT_self_partial_temp(dec, val);
+}
+
+/* struct VkPhysicalDevicePushDescriptorPropertiesKHR chain */
+
+static inline void
+vn_encode_VkPhysicalDevicePushDescriptorPropertiesKHR_pnext(struct vn_cs_encoder *enc, const void *val)
+{
+    /* no known/supported struct */
+    vn_encode_simple_pointer(enc, NULL);
+}
+
+static inline void
+vn_encode_VkPhysicalDevicePushDescriptorPropertiesKHR_self(struct vn_cs_encoder *enc, const VkPhysicalDevicePushDescriptorPropertiesKHR *val)
+{
+    /* skip val->{sType,pNext} */
+    vn_encode_uint32_t(enc, &val->maxPushDescriptors);
+}
+
+static inline void
+vn_encode_VkPhysicalDevicePushDescriptorPropertiesKHR(struct vn_cs_encoder *enc, const VkPhysicalDevicePushDescriptorPropertiesKHR *val)
+{
+    assert(val->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR);
+    vn_encode_VkStructureType(enc, &(VkStructureType){ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR });
+    vn_encode_VkPhysicalDevicePushDescriptorPropertiesKHR_pnext(enc, val->pNext);
+    vn_encode_VkPhysicalDevicePushDescriptorPropertiesKHR_self(enc, val);
+}
+
+static inline void *
+vn_decode_VkPhysicalDevicePushDescriptorPropertiesKHR_pnext_partial_temp(struct vn_cs_decoder *dec)
+{
+    /* no known/supported struct */
+    if (vn_decode_simple_pointer(dec))
+        vn_cs_decoder_set_fatal(dec);
+    return NULL;
+}
+
+static inline void
+vn_decode_VkPhysicalDevicePushDescriptorPropertiesKHR_self_partial_temp(struct vn_cs_decoder *dec, VkPhysicalDevicePushDescriptorPropertiesKHR *val)
+{
+    /* skip val->{sType,pNext} */
+    /* skip val->maxPushDescriptors */
+}
+
+static inline void
+vn_decode_VkPhysicalDevicePushDescriptorPropertiesKHR_partial_temp(struct vn_cs_decoder *dec, VkPhysicalDevicePushDescriptorPropertiesKHR *val)
+{
+    VkStructureType stype;
+    vn_decode_VkStructureType(dec, &stype);
+    if (stype != VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR)
+        vn_cs_decoder_set_fatal(dec);
+
+    val->sType = stype;
+    val->pNext = vn_decode_VkPhysicalDevicePushDescriptorPropertiesKHR_pnext_partial_temp(dec);
+    vn_decode_VkPhysicalDevicePushDescriptorPropertiesKHR_self_partial_temp(dec, val);
+}
+
 /* struct VkConformanceVersion */
 
 static inline void
@@ -9868,6 +10713,66 @@
     vn_decode_VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT_self_partial_temp(dec, val);
 }
 
+/* struct VkPhysicalDevicePCIBusInfoPropertiesEXT chain */
+
+static inline void
+vn_encode_VkPhysicalDevicePCIBusInfoPropertiesEXT_pnext(struct vn_cs_encoder *enc, const void *val)
+{
+    /* no known/supported struct */
+    vn_encode_simple_pointer(enc, NULL);
+}
+
+static inline void
+vn_encode_VkPhysicalDevicePCIBusInfoPropertiesEXT_self(struct vn_cs_encoder *enc, const VkPhysicalDevicePCIBusInfoPropertiesEXT *val)
+{
+    /* skip val->{sType,pNext} */
+    vn_encode_uint32_t(enc, &val->pciDomain);
+    vn_encode_uint32_t(enc, &val->pciBus);
+    vn_encode_uint32_t(enc, &val->pciDevice);
+    vn_encode_uint32_t(enc, &val->pciFunction);
+}
+
+static inline void
+vn_encode_VkPhysicalDevicePCIBusInfoPropertiesEXT(struct vn_cs_encoder *enc, const VkPhysicalDevicePCIBusInfoPropertiesEXT *val)
+{
+    assert(val->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT);
+    vn_encode_VkStructureType(enc, &(VkStructureType){ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT });
+    vn_encode_VkPhysicalDevicePCIBusInfoPropertiesEXT_pnext(enc, val->pNext);
+    vn_encode_VkPhysicalDevicePCIBusInfoPropertiesEXT_self(enc, val);
+}
+
+static inline void *
+vn_decode_VkPhysicalDevicePCIBusInfoPropertiesEXT_pnext_partial_temp(struct vn_cs_decoder *dec)
+{
+    /* no known/supported struct */
+    if (vn_decode_simple_pointer(dec))
+        vn_cs_decoder_set_fatal(dec);
+    return NULL;
+}
+
+static inline void
+vn_decode_VkPhysicalDevicePCIBusInfoPropertiesEXT_self_partial_temp(struct vn_cs_decoder *dec, VkPhysicalDevicePCIBusInfoPropertiesEXT *val)
+{
+    /* skip val->{sType,pNext} */
+    /* skip val->pciDomain */
+    /* skip val->pciBus */
+    /* skip val->pciDevice */
+    /* skip val->pciFunction */
+}
+
+static inline void
+vn_decode_VkPhysicalDevicePCIBusInfoPropertiesEXT_partial_temp(struct vn_cs_decoder *dec, VkPhysicalDevicePCIBusInfoPropertiesEXT *val)
+{
+    VkStructureType stype;
+    vn_decode_VkStructureType(dec, &stype);
+    if (stype != VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT)
+        vn_cs_decoder_set_fatal(dec);
+
+    val->sType = stype;
+    val->pNext = vn_decode_VkPhysicalDevicePCIBusInfoPropertiesEXT_pnext_partial_temp(dec);
+    vn_decode_VkPhysicalDevicePCIBusInfoPropertiesEXT_self_partial_temp(dec, val);
+}
+
 /* struct VkPhysicalDeviceDepthStencilResolveProperties chain */
 
 static inline void
@@ -10846,6 +11751,18 @@
 
     while (pnext) {
         switch ((int32_t)pnext->sType) {
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT:
+            vn_encode_simple_pointer(enc, pnext);
+            vn_encode_VkStructureType(enc, &pnext->sType);
+            vn_encode_VkPhysicalDeviceProperties2_pnext(enc, pnext->pNext);
+            vn_encode_VkPhysicalDeviceMultiDrawPropertiesEXT_self(enc, (const VkPhysicalDeviceMultiDrawPropertiesEXT *)pnext);
+            return;
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR:
+            vn_encode_simple_pointer(enc, pnext);
+            vn_encode_VkStructureType(enc, &pnext->sType);
+            vn_encode_VkPhysicalDeviceProperties2_pnext(enc, pnext->pNext);
+            vn_encode_VkPhysicalDevicePushDescriptorPropertiesKHR_self(enc, (const VkPhysicalDevicePushDescriptorPropertiesKHR *)pnext);
+            return;
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES:
             vn_encode_simple_pointer(enc, pnext);
             vn_encode_VkStructureType(enc, &pnext->sType);
@@ -10936,6 +11853,12 @@
             vn_encode_VkPhysicalDeviceProperties2_pnext(enc, pnext->pNext);
             vn_encode_VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT_self(enc, (const VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *)pnext);
             return;
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT:
+            vn_encode_simple_pointer(enc, pnext);
+            vn_encode_VkStructureType(enc, &pnext->sType);
+            vn_encode_VkPhysicalDeviceProperties2_pnext(enc, pnext->pNext);
+            vn_encode_VkPhysicalDevicePCIBusInfoPropertiesEXT_self(enc, (const VkPhysicalDevicePCIBusInfoPropertiesEXT *)pnext);
+            return;
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES:
             vn_encode_simple_pointer(enc, pnext);
             vn_encode_VkStructureType(enc, &pnext->sType);
@@ -11045,6 +11968,22 @@
 
     vn_decode_VkStructureType(dec, &stype);
     switch ((int32_t)stype) {
+    case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceMultiDrawPropertiesEXT));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkPhysicalDeviceProperties2_pnext_partial_temp(dec);
+            vn_decode_VkPhysicalDeviceMultiDrawPropertiesEXT_self_partial_temp(dec, (VkPhysicalDeviceMultiDrawPropertiesEXT *)pnext);
+        }
+        break;
+    case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDevicePushDescriptorPropertiesKHR));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkPhysicalDeviceProperties2_pnext_partial_temp(dec);
+            vn_decode_VkPhysicalDevicePushDescriptorPropertiesKHR_self_partial_temp(dec, (VkPhysicalDevicePushDescriptorPropertiesKHR *)pnext);
+        }
+        break;
     case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES:
         pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceDriverProperties));
         if (pnext) {
@@ -11165,6 +12104,14 @@
             vn_decode_VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT_self_partial_temp(dec, (VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *)pnext);
         }
         break;
+    case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDevicePCIBusInfoPropertiesEXT));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkPhysicalDeviceProperties2_pnext_partial_temp(dec);
+            vn_decode_VkPhysicalDevicePCIBusInfoPropertiesEXT_self_partial_temp(dec, (VkPhysicalDevicePCIBusInfoPropertiesEXT *)pnext);
+        }
+        break;
     case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES:
         pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPhysicalDeviceDepthStencilResolveProperties));
         if (pnext) {
@@ -12783,10 +13730,10 @@
     vn_decode_VkPhysicalDeviceGroupProperties_self_partial_temp(dec, val);
 }
 
-/* struct VkDeviceQueueInfo2 chain */
+/* struct VkDeviceQueueTimelineInfoMESA chain */
 
 static inline void *
-vn_decode_VkDeviceQueueInfo2_pnext_temp(struct vn_cs_decoder *dec)
+vn_decode_VkDeviceQueueTimelineInfoMESA_pnext_temp(struct vn_cs_decoder *dec)
 {
     /* no known/supported struct */
     if (vn_decode_simple_pointer(dec))
@@ -12795,6 +13742,83 @@
 }
 
 static inline void
+vn_decode_VkDeviceQueueTimelineInfoMESA_self_temp(struct vn_cs_decoder *dec, VkDeviceQueueTimelineInfoMESA *val)
+{
+    /* skip val->{sType,pNext} */
+    vn_decode_uint32_t(dec, &val->ringIdx);
+}
+
+static inline void
+vn_decode_VkDeviceQueueTimelineInfoMESA_temp(struct vn_cs_decoder *dec, VkDeviceQueueTimelineInfoMESA *val)
+{
+    VkStructureType stype;
+    vn_decode_VkStructureType(dec, &stype);
+    if (stype != VK_STRUCTURE_TYPE_DEVICE_QUEUE_TIMELINE_INFO_MESA)
+        vn_cs_decoder_set_fatal(dec);
+
+    val->sType = stype;
+    val->pNext = vn_decode_VkDeviceQueueTimelineInfoMESA_pnext_temp(dec);
+    vn_decode_VkDeviceQueueTimelineInfoMESA_self_temp(dec, val);
+}
+
+static inline void
+vn_replace_VkDeviceQueueTimelineInfoMESA_handle_self(VkDeviceQueueTimelineInfoMESA *val)
+{
+    /* skip val->sType */
+    /* skip val->pNext */
+    /* skip val->ringIdx */
+}
+
+static inline void
+vn_replace_VkDeviceQueueTimelineInfoMESA_handle(VkDeviceQueueTimelineInfoMESA *val)
+{
+    struct VkBaseOutStructure *pnext = (struct VkBaseOutStructure *)val;
+
+    do {
+        switch ((int32_t)pnext->sType) {
+        case VK_STRUCTURE_TYPE_DEVICE_QUEUE_TIMELINE_INFO_MESA:
+            vn_replace_VkDeviceQueueTimelineInfoMESA_handle_self((VkDeviceQueueTimelineInfoMESA *)pnext);
+            break;
+        default:
+            /* ignore unknown/unsupported struct */
+            break;
+        }
+        pnext = pnext->pNext;
+    } while (pnext);
+}
+
+/* struct VkDeviceQueueInfo2 chain */
+
+static inline void *
+vn_decode_VkDeviceQueueInfo2_pnext_temp(struct vn_cs_decoder *dec)
+{
+    VkBaseOutStructure *pnext;
+    VkStructureType stype;
+
+    if (!vn_decode_simple_pointer(dec))
+        return NULL;
+
+    vn_decode_VkStructureType(dec, &stype);
+    switch ((int32_t)stype) {
+    case VK_STRUCTURE_TYPE_DEVICE_QUEUE_TIMELINE_INFO_MESA:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkDeviceQueueTimelineInfoMESA));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkDeviceQueueInfo2_pnext_temp(dec);
+            vn_decode_VkDeviceQueueTimelineInfoMESA_self_temp(dec, (VkDeviceQueueTimelineInfoMESA *)pnext);
+        }
+        break;
+    default:
+        /* unexpected struct */
+        pnext = NULL;
+        vn_cs_decoder_set_fatal(dec);
+        break;
+    }
+
+    return pnext;
+}
+
+static inline void
 vn_decode_VkDeviceQueueInfo2_self_temp(struct vn_cs_decoder *dec, VkDeviceQueueInfo2 *val)
 {
     /* skip val->{sType,pNext} */
@@ -12836,6 +13860,9 @@
         case VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2:
             vn_replace_VkDeviceQueueInfo2_handle_self((VkDeviceQueueInfo2 *)pnext);
             break;
+        case VK_STRUCTURE_TYPE_DEVICE_QUEUE_TIMELINE_INFO_MESA:
+            vn_replace_VkDeviceQueueTimelineInfoMESA_handle_self((VkDeviceQueueTimelineInfoMESA *)pnext);
+            break;
         default:
             /* ignore unknown/unsupported struct */
             break;
diff --git a/src/venus/venus-protocol/vn_protocol_renderer_device_memory.h b/src/venus/venus-protocol/vn_protocol_renderer_device_memory.h
index 5376085..e549f09 100644
--- a/src/venus/venus-protocol/vn_protocol_renderer_device_memory.h
+++ b/src/venus/venus-protocol/vn_protocol_renderer_device_memory.h
@@ -19,6 +19,8 @@
  *
  *   VkImportMemoryFdInfoKHR
  *   vkMapMemory
+ *   vkGetMemoryFdKHR
+ *   vkGetMemoryFdPropertiesKHR
  */
 
 /* struct VkExportMemoryAllocateInfo chain */
@@ -556,6 +558,150 @@
     } while (pnext);
 }
 
+/* struct VkMemoryResourceAllocationSizeProperties100000MESA chain */
+
+static inline void
+vn_encode_VkMemoryResourceAllocationSizeProperties100000MESA_pnext(struct vn_cs_encoder *enc, const void *val)
+{
+    /* no known/supported struct */
+    vn_encode_simple_pointer(enc, NULL);
+}
+
+static inline void
+vn_encode_VkMemoryResourceAllocationSizeProperties100000MESA_self(struct vn_cs_encoder *enc, const VkMemoryResourceAllocationSizeProperties100000MESA *val)
+{
+    /* skip val->{sType,pNext} */
+    vn_encode_uint64_t(enc, &val->allocationSize);
+}
+
+static inline void
+vn_encode_VkMemoryResourceAllocationSizeProperties100000MESA(struct vn_cs_encoder *enc, const VkMemoryResourceAllocationSizeProperties100000MESA *val)
+{
+    assert(val->sType == VK_STRUCTURE_TYPE_MEMORY_RESOURCE_ALLOCATION_SIZE_PROPERTIES_100000_MESA);
+    vn_encode_VkStructureType(enc, &(VkStructureType){ VK_STRUCTURE_TYPE_MEMORY_RESOURCE_ALLOCATION_SIZE_PROPERTIES_100000_MESA });
+    vn_encode_VkMemoryResourceAllocationSizeProperties100000MESA_pnext(enc, val->pNext);
+    vn_encode_VkMemoryResourceAllocationSizeProperties100000MESA_self(enc, val);
+}
+
+static inline void *
+vn_decode_VkMemoryResourceAllocationSizeProperties100000MESA_pnext_partial_temp(struct vn_cs_decoder *dec)
+{
+    /* no known/supported struct */
+    if (vn_decode_simple_pointer(dec))
+        vn_cs_decoder_set_fatal(dec);
+    return NULL;
+}
+
+static inline void
+vn_decode_VkMemoryResourceAllocationSizeProperties100000MESA_self_partial_temp(struct vn_cs_decoder *dec, VkMemoryResourceAllocationSizeProperties100000MESA *val)
+{
+    /* skip val->{sType,pNext} */
+    /* skip val->allocationSize */
+}
+
+static inline void
+vn_decode_VkMemoryResourceAllocationSizeProperties100000MESA_partial_temp(struct vn_cs_decoder *dec, VkMemoryResourceAllocationSizeProperties100000MESA *val)
+{
+    VkStructureType stype;
+    vn_decode_VkStructureType(dec, &stype);
+    if (stype != VK_STRUCTURE_TYPE_MEMORY_RESOURCE_ALLOCATION_SIZE_PROPERTIES_100000_MESA)
+        vn_cs_decoder_set_fatal(dec);
+
+    val->sType = stype;
+    val->pNext = vn_decode_VkMemoryResourceAllocationSizeProperties100000MESA_pnext_partial_temp(dec);
+    vn_decode_VkMemoryResourceAllocationSizeProperties100000MESA_self_partial_temp(dec, val);
+}
+
+/* struct VkMemoryResourcePropertiesMESA chain */
+
+static inline void
+vn_encode_VkMemoryResourcePropertiesMESA_pnext(struct vn_cs_encoder *enc, const void *val)
+{
+    const VkBaseInStructure *pnext = val;
+
+    while (pnext) {
+        switch ((int32_t)pnext->sType) {
+        case VK_STRUCTURE_TYPE_MEMORY_RESOURCE_ALLOCATION_SIZE_PROPERTIES_100000_MESA:
+            vn_encode_simple_pointer(enc, pnext);
+            vn_encode_VkStructureType(enc, &pnext->sType);
+            vn_encode_VkMemoryResourcePropertiesMESA_pnext(enc, pnext->pNext);
+            vn_encode_VkMemoryResourceAllocationSizeProperties100000MESA_self(enc, (const VkMemoryResourceAllocationSizeProperties100000MESA *)pnext);
+            return;
+        default:
+            /* ignore unknown/unsupported struct */
+            break;
+        }
+        pnext = pnext->pNext;
+    }
+
+    vn_encode_simple_pointer(enc, NULL);
+}
+
+static inline void
+vn_encode_VkMemoryResourcePropertiesMESA_self(struct vn_cs_encoder *enc, const VkMemoryResourcePropertiesMESA *val)
+{
+    /* skip val->{sType,pNext} */
+    vn_encode_uint32_t(enc, &val->memoryTypeBits);
+}
+
+static inline void
+vn_encode_VkMemoryResourcePropertiesMESA(struct vn_cs_encoder *enc, const VkMemoryResourcePropertiesMESA *val)
+{
+    assert(val->sType == VK_STRUCTURE_TYPE_MEMORY_RESOURCE_PROPERTIES_MESA);
+    vn_encode_VkStructureType(enc, &(VkStructureType){ VK_STRUCTURE_TYPE_MEMORY_RESOURCE_PROPERTIES_MESA });
+    vn_encode_VkMemoryResourcePropertiesMESA_pnext(enc, val->pNext);
+    vn_encode_VkMemoryResourcePropertiesMESA_self(enc, val);
+}
+
+static inline void *
+vn_decode_VkMemoryResourcePropertiesMESA_pnext_partial_temp(struct vn_cs_decoder *dec)
+{
+    VkBaseOutStructure *pnext;
+    VkStructureType stype;
+
+    if (!vn_decode_simple_pointer(dec))
+        return NULL;
+
+    vn_decode_VkStructureType(dec, &stype);
+    switch ((int32_t)stype) {
+    case VK_STRUCTURE_TYPE_MEMORY_RESOURCE_ALLOCATION_SIZE_PROPERTIES_100000_MESA:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkMemoryResourceAllocationSizeProperties100000MESA));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkMemoryResourcePropertiesMESA_pnext_partial_temp(dec);
+            vn_decode_VkMemoryResourceAllocationSizeProperties100000MESA_self_partial_temp(dec, (VkMemoryResourceAllocationSizeProperties100000MESA *)pnext);
+        }
+        break;
+    default:
+        /* unexpected struct */
+        pnext = NULL;
+        vn_cs_decoder_set_fatal(dec);
+        break;
+    }
+
+    return pnext;
+}
+
+static inline void
+vn_decode_VkMemoryResourcePropertiesMESA_self_partial_temp(struct vn_cs_decoder *dec, VkMemoryResourcePropertiesMESA *val)
+{
+    /* skip val->{sType,pNext} */
+    /* skip val->memoryTypeBits */
+}
+
+static inline void
+vn_decode_VkMemoryResourcePropertiesMESA_partial_temp(struct vn_cs_decoder *dec, VkMemoryResourcePropertiesMESA *val)
+{
+    VkStructureType stype;
+    vn_decode_VkStructureType(dec, &stype);
+    if (stype != VK_STRUCTURE_TYPE_MEMORY_RESOURCE_PROPERTIES_MESA)
+        vn_cs_decoder_set_fatal(dec);
+
+    val->sType = stype;
+    val->pNext = vn_decode_VkMemoryResourcePropertiesMESA_pnext_partial_temp(dec);
+    vn_decode_VkMemoryResourcePropertiesMESA_self_partial_temp(dec, val);
+}
+
 static inline void vn_decode_vkAllocateMemory_args_temp(struct vn_cs_decoder *dec, struct vn_command_vkAllocateMemory *args)
 {
     vn_decode_VkDevice_lookup(dec, &args->device);
@@ -781,6 +927,38 @@
     /* skip args->pInfo */
 }
 
+static inline void vn_decode_vkGetMemoryResourcePropertiesMESA_args_temp(struct vn_cs_decoder *dec, struct vn_command_vkGetMemoryResourcePropertiesMESA *args)
+{
+    vn_decode_VkDevice_lookup(dec, &args->device);
+    vn_decode_uint32_t(dec, &args->resourceId);
+    if (vn_decode_simple_pointer(dec)) {
+        args->pMemoryResourceProperties = vn_cs_decoder_alloc_temp(dec, sizeof(*args->pMemoryResourceProperties));
+        if (!args->pMemoryResourceProperties) return;
+        vn_decode_VkMemoryResourcePropertiesMESA_partial_temp(dec, args->pMemoryResourceProperties);
+    } else {
+        args->pMemoryResourceProperties = NULL;
+        vn_cs_decoder_set_fatal(dec);
+    }
+}
+
+static inline void vn_replace_vkGetMemoryResourcePropertiesMESA_args_handle(struct vn_command_vkGetMemoryResourcePropertiesMESA *args)
+{
+    vn_replace_VkDevice_handle(&args->device);
+    /* skip args->resourceId */
+    /* skip args->pMemoryResourceProperties */
+}
+
+static inline void vn_encode_vkGetMemoryResourcePropertiesMESA_reply(struct vn_cs_encoder *enc, const struct vn_command_vkGetMemoryResourcePropertiesMESA *args)
+{
+    vn_encode_VkCommandTypeEXT(enc, &(VkCommandTypeEXT){VK_COMMAND_TYPE_vkGetMemoryResourcePropertiesMESA_EXT});
+
+    vn_encode_VkResult(enc, &args->ret);
+    /* skip args->device */
+    /* skip args->resourceId */
+    if (vn_encode_simple_pointer(enc, args->pMemoryResourceProperties))
+        vn_encode_VkMemoryResourcePropertiesMESA(enc, args->pMemoryResourceProperties);
+}
+
 static inline void vn_dispatch_vkAllocateMemory(struct vn_dispatch_context *ctx, VkCommandFlagsEXT flags)
 {
     struct vn_command_vkAllocateMemory args;
@@ -968,6 +1146,35 @@
     vn_cs_decoder_reset_temp_pool(ctx->decoder);
 }
 
+static inline void vn_dispatch_vkGetMemoryResourcePropertiesMESA(struct vn_dispatch_context *ctx, VkCommandFlagsEXT flags)
+{
+    struct vn_command_vkGetMemoryResourcePropertiesMESA args;
+
+    if (!ctx->dispatch_vkGetMemoryResourcePropertiesMESA) {
+        vn_cs_decoder_set_fatal(ctx->decoder);
+        return;
+    }
+
+    vn_decode_vkGetMemoryResourcePropertiesMESA_args_temp(ctx->decoder, &args);
+    if (!args.device) {
+        vn_cs_decoder_set_fatal(ctx->decoder);
+        return;
+    }
+
+    if (!vn_cs_decoder_get_fatal(ctx->decoder))
+        ctx->dispatch_vkGetMemoryResourcePropertiesMESA(ctx, &args);
+
+#ifdef DEBUG
+    if (!vn_cs_decoder_get_fatal(ctx->decoder) && vn_dispatch_should_log_result(args.ret))
+        vn_dispatch_debug_log(ctx, "vkGetMemoryResourcePropertiesMESA returned %d", args.ret);
+#endif
+
+    if (!vn_cs_decoder_get_fatal(ctx->decoder) && (flags & VK_COMMAND_GENERATE_REPLY_BIT_EXT))
+       vn_encode_vkGetMemoryResourcePropertiesMESA_reply(ctx->encoder, &args);
+
+    vn_cs_decoder_reset_temp_pool(ctx->decoder);
+}
+
 #pragma GCC diagnostic pop
 
 #endif /* VN_PROTOCOL_RENDERER_DEVICE_MEMORY_H */
diff --git a/src/venus/venus-protocol/vn_protocol_renderer_dispatches.h b/src/venus/venus-protocol/vn_protocol_renderer_dispatches.h
index a059585..725a0e7 100644
--- a/src/venus/venus-protocol/vn_protocol_renderer_dispatches.h
+++ b/src/venus/venus-protocol/vn_protocol_renderer_dispatches.h
@@ -150,6 +150,8 @@
     case VK_COMMAND_TYPE_vkCmdBindVertexBuffers_EXT: return "vkCmdBindVertexBuffers";
     case VK_COMMAND_TYPE_vkCmdDraw_EXT: return "vkCmdDraw";
     case VK_COMMAND_TYPE_vkCmdDrawIndexed_EXT: return "vkCmdDrawIndexed";
+    case VK_COMMAND_TYPE_vkCmdDrawMultiEXT_EXT: return "vkCmdDrawMultiEXT";
+    case VK_COMMAND_TYPE_vkCmdDrawMultiIndexedEXT_EXT: return "vkCmdDrawMultiIndexedEXT";
     case VK_COMMAND_TYPE_vkCmdDrawIndirect_EXT: return "vkCmdDrawIndirect";
     case VK_COMMAND_TYPE_vkCmdDrawIndexedIndirect_EXT: return "vkCmdDrawIndexedIndirect";
     case VK_COMMAND_TYPE_vkCmdDispatch_EXT: return "vkCmdDispatch";
@@ -188,6 +190,7 @@
     case VK_COMMAND_TYPE_vkGetPhysicalDeviceQueueFamilyProperties2_EXT: return "vkGetPhysicalDeviceQueueFamilyProperties2";
     case VK_COMMAND_TYPE_vkGetPhysicalDeviceMemoryProperties2_EXT: return "vkGetPhysicalDeviceMemoryProperties2";
     case VK_COMMAND_TYPE_vkGetPhysicalDeviceSparseImageFormatProperties2_EXT: return "vkGetPhysicalDeviceSparseImageFormatProperties2";
+    case VK_COMMAND_TYPE_vkCmdPushDescriptorSetKHR_EXT: return "vkCmdPushDescriptorSetKHR";
     case VK_COMMAND_TYPE_vkTrimCommandPool_EXT: return "vkTrimCommandPool";
     case VK_COMMAND_TYPE_vkGetPhysicalDeviceExternalBufferProperties_EXT: return "vkGetPhysicalDeviceExternalBufferProperties";
     case VK_COMMAND_TYPE_vkGetPhysicalDeviceExternalSemaphoreProperties_EXT: return "vkGetPhysicalDeviceExternalSemaphoreProperties";
@@ -276,20 +279,26 @@
     case VK_COMMAND_TYPE_vkNotifyRingMESA_EXT: return "vkNotifyRingMESA";
     case VK_COMMAND_TYPE_vkWriteRingExtraMESA_EXT: return "vkWriteRingExtraMESA";
     case VK_COMMAND_TYPE_vkGetMemoryResourcePropertiesMESA_EXT: return "vkGetMemoryResourcePropertiesMESA";
+    case VK_COMMAND_TYPE_vkResetFenceResource100000MESA_EXT: return "vkResetFenceResource100000MESA";
+    case VK_COMMAND_TYPE_vkWaitSemaphoreResource100000MESA_EXT: return "vkWaitSemaphoreResource100000MESA";
+    case VK_COMMAND_TYPE_vkImportSemaphoreResource100000MESA_EXT: return "vkImportSemaphoreResource100000MESA";
     case VK_COMMAND_TYPE_vkGetVenusExperimentalFeatureData100000MESA_EXT: return "vkGetVenusExperimentalFeatureData100000MESA";
     case VK_COMMAND_TYPE_vkGetDeviceProcAddr_EXT: return "vkGetDeviceProcAddr";
     case VK_COMMAND_TYPE_vkGetInstanceProcAddr_EXT: return "vkGetInstanceProcAddr";
     case VK_COMMAND_TYPE_vkMapMemory_EXT: return "vkMapMemory";
     case VK_COMMAND_TYPE_vkGetMemoryFdKHR_EXT: return "vkGetMemoryFdKHR";
     case VK_COMMAND_TYPE_vkGetMemoryFdPropertiesKHR_EXT: return "vkGetMemoryFdPropertiesKHR";
+    case VK_COMMAND_TYPE_vkGetSemaphoreFdKHR_EXT: return "vkGetSemaphoreFdKHR";
+    case VK_COMMAND_TYPE_vkImportSemaphoreFdKHR_EXT: return "vkImportSemaphoreFdKHR";
     case VK_COMMAND_TYPE_vkGetFenceFdKHR_EXT: return "vkGetFenceFdKHR";
     case VK_COMMAND_TYPE_vkImportFenceFdKHR_EXT: return "vkImportFenceFdKHR";
     case VK_COMMAND_TYPE_vkUpdateDescriptorSetWithTemplate_EXT: return "vkUpdateDescriptorSetWithTemplate";
+    case VK_COMMAND_TYPE_vkCmdPushDescriptorSetWithTemplateKHR_EXT: return "vkCmdPushDescriptorSetWithTemplateKHR";
     default: return "unknown";
     }
 }
 
-static void (*const vn_dispatch_table[242])(struct vn_dispatch_context *ctx, VkCommandFlagsEXT flags) = {
+static void (*const vn_dispatch_table[251])(struct vn_dispatch_context *ctx, VkCommandFlagsEXT flags) = {
     [VK_COMMAND_TYPE_vkCreateInstance_EXT] = vn_dispatch_vkCreateInstance,
     [VK_COMMAND_TYPE_vkDestroyInstance_EXT] = vn_dispatch_vkDestroyInstance,
     [VK_COMMAND_TYPE_vkEnumeratePhysicalDevices_EXT] = vn_dispatch_vkEnumeratePhysicalDevices,
@@ -397,6 +406,8 @@
     [VK_COMMAND_TYPE_vkCmdBindVertexBuffers_EXT] = vn_dispatch_vkCmdBindVertexBuffers,
     [VK_COMMAND_TYPE_vkCmdDraw_EXT] = vn_dispatch_vkCmdDraw,
     [VK_COMMAND_TYPE_vkCmdDrawIndexed_EXT] = vn_dispatch_vkCmdDrawIndexed,
+    [VK_COMMAND_TYPE_vkCmdDrawMultiEXT_EXT] = vn_dispatch_vkCmdDrawMultiEXT,
+    [VK_COMMAND_TYPE_vkCmdDrawMultiIndexedEXT_EXT] = vn_dispatch_vkCmdDrawMultiIndexedEXT,
     [VK_COMMAND_TYPE_vkCmdDrawIndirect_EXT] = vn_dispatch_vkCmdDrawIndirect,
     [VK_COMMAND_TYPE_vkCmdDrawIndexedIndirect_EXT] = vn_dispatch_vkCmdDrawIndexedIndirect,
     [VK_COMMAND_TYPE_vkCmdDispatch_EXT] = vn_dispatch_vkCmdDispatch,
@@ -435,6 +446,7 @@
     [VK_COMMAND_TYPE_vkGetPhysicalDeviceQueueFamilyProperties2_EXT] = vn_dispatch_vkGetPhysicalDeviceQueueFamilyProperties2,
     [VK_COMMAND_TYPE_vkGetPhysicalDeviceMemoryProperties2_EXT] = vn_dispatch_vkGetPhysicalDeviceMemoryProperties2,
     [VK_COMMAND_TYPE_vkGetPhysicalDeviceSparseImageFormatProperties2_EXT] = vn_dispatch_vkGetPhysicalDeviceSparseImageFormatProperties2,
+    [VK_COMMAND_TYPE_vkCmdPushDescriptorSetKHR_EXT] = vn_dispatch_vkCmdPushDescriptorSetKHR,
     [VK_COMMAND_TYPE_vkTrimCommandPool_EXT] = vn_dispatch_vkTrimCommandPool,
     [VK_COMMAND_TYPE_vkGetPhysicalDeviceExternalBufferProperties_EXT] = vn_dispatch_vkGetPhysicalDeviceExternalBufferProperties,
     [VK_COMMAND_TYPE_vkGetPhysicalDeviceExternalSemaphoreProperties_EXT] = vn_dispatch_vkGetPhysicalDeviceExternalSemaphoreProperties,
@@ -523,6 +535,9 @@
     [VK_COMMAND_TYPE_vkNotifyRingMESA_EXT] = vn_dispatch_vkNotifyRingMESA,
     [VK_COMMAND_TYPE_vkWriteRingExtraMESA_EXT] = vn_dispatch_vkWriteRingExtraMESA,
     [VK_COMMAND_TYPE_vkGetMemoryResourcePropertiesMESA_EXT] = vn_dispatch_vkGetMemoryResourcePropertiesMESA,
+    [VK_COMMAND_TYPE_vkResetFenceResource100000MESA_EXT] = vn_dispatch_vkResetFenceResource100000MESA,
+    [VK_COMMAND_TYPE_vkWaitSemaphoreResource100000MESA_EXT] = vn_dispatch_vkWaitSemaphoreResource100000MESA,
+    [VK_COMMAND_TYPE_vkImportSemaphoreResource100000MESA_EXT] = vn_dispatch_vkImportSemaphoreResource100000MESA,
     [VK_COMMAND_TYPE_vkGetVenusExperimentalFeatureData100000MESA_EXT] = vn_dispatch_vkGetVenusExperimentalFeatureData100000MESA,
 };
 
@@ -538,7 +553,7 @@
 #ifdef DEBUG
         TRACE_SCOPE_SLOW(vn_dispatch_command_name(cmd_type));
 #endif
-        if (cmd_type < 242 && vn_dispatch_table[cmd_type])
+        if (cmd_type < 251 && vn_dispatch_table[cmd_type])
             vn_dispatch_table[cmd_type](ctx, cmd_flags);
         else
             vn_cs_decoder_set_fatal(ctx->decoder);
diff --git a/src/venus/venus-protocol/vn_protocol_renderer_fence.h b/src/venus/venus-protocol/vn_protocol_renderer_fence.h
index e4cfac5..6677bef 100644
--- a/src/venus/venus-protocol/vn_protocol_renderer_fence.h
+++ b/src/venus/venus-protocol/vn_protocol_renderer_fence.h
@@ -18,6 +18,7 @@
  * These structs/unions/commands are not included
  *
  *   vkGetFenceFdKHR
+ *   vkImportFenceFdKHR
  */
 
 /* struct VkExportFenceCreateInfo chain */
@@ -330,6 +331,26 @@
     /* skip args->timeout */
 }
 
+static inline void vn_decode_vkResetFenceResource100000MESA_args_temp(struct vn_cs_decoder *dec, struct vn_command_vkResetFenceResource100000MESA *args)
+{
+    vn_decode_VkDevice_lookup(dec, &args->device);
+    vn_decode_VkFence_lookup(dec, &args->fence);
+}
+
+static inline void vn_replace_vkResetFenceResource100000MESA_args_handle(struct vn_command_vkResetFenceResource100000MESA *args)
+{
+    vn_replace_VkDevice_handle(&args->device);
+    vn_replace_VkFence_handle(&args->fence);
+}
+
+static inline void vn_encode_vkResetFenceResource100000MESA_reply(struct vn_cs_encoder *enc, const struct vn_command_vkResetFenceResource100000MESA *args)
+{
+    vn_encode_VkCommandTypeEXT(enc, &(VkCommandTypeEXT){VK_COMMAND_TYPE_vkResetFenceResource100000MESA_EXT});
+
+    /* skip args->device */
+    /* skip args->fence */
+}
+
 static inline void vn_dispatch_vkCreateFence(struct vn_dispatch_context *ctx, VkCommandFlagsEXT flags)
 {
     struct vn_command_vkCreateFence args;
@@ -471,6 +492,31 @@
     vn_cs_decoder_reset_temp_pool(ctx->decoder);
 }
 
+static inline void vn_dispatch_vkResetFenceResource100000MESA(struct vn_dispatch_context *ctx, VkCommandFlagsEXT flags)
+{
+    struct vn_command_vkResetFenceResource100000MESA args;
+
+    if (!ctx->dispatch_vkResetFenceResource100000MESA) {
+        vn_cs_decoder_set_fatal(ctx->decoder);
+        return;
+    }
+
+    vn_decode_vkResetFenceResource100000MESA_args_temp(ctx->decoder, &args);
+    if (!args.device) {
+        vn_cs_decoder_set_fatal(ctx->decoder);
+        return;
+    }
+
+    if (!vn_cs_decoder_get_fatal(ctx->decoder))
+        ctx->dispatch_vkResetFenceResource100000MESA(ctx, &args);
+
+
+    if (!vn_cs_decoder_get_fatal(ctx->decoder) && (flags & VK_COMMAND_GENERATE_REPLY_BIT_EXT))
+       vn_encode_vkResetFenceResource100000MESA_reply(ctx->encoder, &args);
+
+    vn_cs_decoder_reset_temp_pool(ctx->decoder);
+}
+
 #pragma GCC diagnostic pop
 
 #endif /* VN_PROTOCOL_RENDERER_FENCE_H */
diff --git a/src/venus/venus-protocol/vn_protocol_renderer_handles.h b/src/venus/venus-protocol/vn_protocol_renderer_handles.h
index f0b9b31..e0beea1 100644
--- a/src/venus/venus-protocol/vn_protocol_renderer_handles.h
+++ b/src/venus/venus-protocol/vn_protocol_renderer_handles.h
@@ -26,7 +26,7 @@
     vn_decode_uint64_t(dec, &id);
     if (vn_cs_handle_indirect_id(VK_OBJECT_TYPE_INSTANCE)) {
         *val = vn_cs_decoder_alloc_temp(dec, sizeof(vn_object_id));
-        if (!val)
+        if (!*val)
             return;
     }
     vn_cs_handle_store_id((void **)val, id, VK_OBJECT_TYPE_INSTANCE);
@@ -62,7 +62,7 @@
     vn_decode_uint64_t(dec, &id);
     if (vn_cs_handle_indirect_id(VK_OBJECT_TYPE_PHYSICAL_DEVICE)) {
         *val = vn_cs_decoder_alloc_temp(dec, sizeof(vn_object_id));
-        if (!val)
+        if (!*val)
             return;
     }
     vn_cs_handle_store_id((void **)val, id, VK_OBJECT_TYPE_PHYSICAL_DEVICE);
@@ -98,7 +98,7 @@
     vn_decode_uint64_t(dec, &id);
     if (vn_cs_handle_indirect_id(VK_OBJECT_TYPE_DEVICE)) {
         *val = vn_cs_decoder_alloc_temp(dec, sizeof(vn_object_id));
-        if (!val)
+        if (!*val)
             return;
     }
     vn_cs_handle_store_id((void **)val, id, VK_OBJECT_TYPE_DEVICE);
@@ -134,7 +134,7 @@
     vn_decode_uint64_t(dec, &id);
     if (vn_cs_handle_indirect_id(VK_OBJECT_TYPE_QUEUE)) {
         *val = vn_cs_decoder_alloc_temp(dec, sizeof(vn_object_id));
-        if (!val)
+        if (!*val)
             return;
     }
     vn_cs_handle_store_id((void **)val, id, VK_OBJECT_TYPE_QUEUE);
@@ -170,7 +170,7 @@
     vn_decode_uint64_t(dec, &id);
     if (vn_cs_handle_indirect_id(VK_OBJECT_TYPE_COMMAND_BUFFER)) {
         *val = vn_cs_decoder_alloc_temp(dec, sizeof(vn_object_id));
-        if (!val)
+        if (!*val)
             return;
     }
     vn_cs_handle_store_id((void **)val, id, VK_OBJECT_TYPE_COMMAND_BUFFER);
diff --git a/src/venus/venus-protocol/vn_protocol_renderer_info.h b/src/venus/venus-protocol/vn_protocol_renderer_info.h
index f319c31..9ccccef 100644
--- a/src/venus/venus-protocol/vn_protocol_renderer_info.h
+++ b/src/venus/venus-protocol/vn_protocol_renderer_info.h
@@ -12,7 +12,7 @@
 
 struct vn_info_extension_table {
    union {
-      bool enabled[90];
+      bool enabled[99];
       struct {
          bool EXT_4444_formats;
          bool EXT_calibrated_timestamps;
@@ -20,6 +20,7 @@
          bool EXT_conditional_rendering;
          bool EXT_conservative_rasterization;
          bool EXT_custom_border_color;
+         bool EXT_depth_clip_control;
          bool EXT_depth_clip_enable;
          bool EXT_descriptor_indexing;
          bool EXT_extended_dynamic_state;
@@ -32,8 +33,13 @@
          bool EXT_index_type_uint8;
          bool EXT_inline_uniform_block;
          bool EXT_line_rasterization;
+         bool EXT_multi_draw;
+         bool EXT_mutable_descriptor_type;
+         bool EXT_pci_bus_info;
          bool EXT_pipeline_creation_cache_control;
          bool EXT_pipeline_creation_feedback;
+         bool EXT_primitive_topology_list_restart;
+         bool EXT_primitives_generated_query;
          bool EXT_private_data;
          bool EXT_provoking_vertex;
          bool EXT_queue_family_foreign;
@@ -73,6 +79,7 @@
          bool KHR_external_memory_fd;
          bool KHR_external_semaphore;
          bool KHR_external_semaphore_capabilities;
+         bool KHR_external_semaphore_fd;
          bool KHR_format_feature_flags2;
          bool KHR_get_memory_requirements2;
          bool KHR_get_physical_device_properties2;
@@ -83,6 +90,7 @@
          bool KHR_maintenance3;
          bool KHR_maintenance4;
          bool KHR_multiview;
+         bool KHR_push_descriptor;
          bool KHR_relaxed_block_layout;
          bool KHR_sampler_mirror_clamp_to_edge;
          bool KHR_sampler_ycbcr_conversion;
@@ -104,11 +112,12 @@
          bool KHR_vulkan_memory_model;
          bool KHR_zero_initialize_workgroup_memory;
          bool MESA_venus_protocol;
+         bool VALVE_mutable_descriptor_type;
       };
    };
 };
 
-#define VN_INFO_EXTENSION_MAX_NUMBER (414)
+#define VN_INFO_EXTENSION_MAX_NUMBER (495)
 
 struct vn_info_extension {
    const char *name;
@@ -117,14 +126,15 @@
 };
 
 /* sorted by extension names for bsearch */
-static const uint32_t _vn_info_extension_count = 90;
-static const struct vn_info_extension _vn_info_extensions[90] = {
+static const uint32_t _vn_info_extension_count = 99;
+static const struct vn_info_extension _vn_info_extensions[99] = {
    { "VK_EXT_4444_formats", 341, 1 },
    { "VK_EXT_calibrated_timestamps", 185, 2 },
    { "VK_EXT_command_serialization", 384, 0 },
    { "VK_EXT_conditional_rendering", 82, 2 },
    { "VK_EXT_conservative_rasterization", 102, 1 },
    { "VK_EXT_custom_border_color", 288, 12 },
+   { "VK_EXT_depth_clip_control", 356, 1 },
    { "VK_EXT_depth_clip_enable", 103, 1 },
    { "VK_EXT_descriptor_indexing", 162, 2 },
    { "VK_EXT_extended_dynamic_state", 268, 1 },
@@ -137,8 +147,13 @@
    { "VK_EXT_index_type_uint8", 266, 1 },
    { "VK_EXT_inline_uniform_block", 139, 1 },
    { "VK_EXT_line_rasterization", 260, 1 },
+   { "VK_EXT_multi_draw", 393, 1 },
+   { "VK_EXT_mutable_descriptor_type", 495, 1 },
+   { "VK_EXT_pci_bus_info", 213, 2 },
    { "VK_EXT_pipeline_creation_cache_control", 298, 3 },
    { "VK_EXT_pipeline_creation_feedback", 193, 1 },
+   { "VK_EXT_primitive_topology_list_restart", 357, 1 },
+   { "VK_EXT_primitives_generated_query", 383, 1 },
    { "VK_EXT_private_data", 296, 1 },
    { "VK_EXT_provoking_vertex", 255, 1 },
    { "VK_EXT_queue_family_foreign", 127, 1 },
@@ -178,7 +193,8 @@
    { "VK_KHR_external_memory_fd", 75, 1 },
    { "VK_KHR_external_semaphore", 78, 1 },
    { "VK_KHR_external_semaphore_capabilities", 77, 1 },
-   { "VK_KHR_format_feature_flags2", 361, 1 },
+   { "VK_KHR_external_semaphore_fd", 80, 1 },
+   { "VK_KHR_format_feature_flags2", 361, 2 },
    { "VK_KHR_get_memory_requirements2", 147, 1 },
    { "VK_KHR_get_physical_device_properties2", 60, 2 },
    { "VK_KHR_image_format_list", 148, 1 },
@@ -188,6 +204,7 @@
    { "VK_KHR_maintenance3", 169, 1 },
    { "VK_KHR_maintenance4", 414, 2 },
    { "VK_KHR_multiview", 54, 1 },
+   { "VK_KHR_push_descriptor", 81, 2 },
    { "VK_KHR_relaxed_block_layout", 145, 1 },
    { "VK_KHR_sampler_mirror_clamp_to_edge", 15, 3 },
    { "VK_KHR_sampler_ycbcr_conversion", 157, 14 },
@@ -209,6 +226,7 @@
    { "VK_KHR_vulkan_memory_model", 212, 3 },
    { "VK_KHR_zero_initialize_workgroup_memory", 326, 1 },
    { "VK_MESA_venus_protocol", 385, 100000 },
+   { "VK_VALVE_mutable_descriptor_type", 352, 1 },
 };
 
 static inline uint32_t
@@ -220,7 +238,7 @@
 static inline uint32_t
 vn_info_vk_xml_version(void)
 {
-    return VK_MAKE_API_VERSION(0, 1, 3, 204);
+    return VK_MAKE_API_VERSION(0, 1, 3, 228);
 }
 
 static inline int
diff --git a/src/venus/venus-protocol/vn_protocol_renderer_pipeline.h b/src/venus/venus-protocol/vn_protocol_renderer_pipeline.h
index 8701daf..554e5e5 100644
--- a/src/venus/venus-protocol/vn_protocol_renderer_pipeline.h
+++ b/src/venus/venus-protocol/vn_protocol_renderer_pipeline.h
@@ -142,6 +142,14 @@
 
     vn_decode_VkStructureType(dec, &stype);
     switch ((int32_t)stype) {
+    case VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkShaderModuleCreateInfo));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkPipelineShaderStageCreateInfo_pnext_temp(dec);
+            vn_decode_VkShaderModuleCreateInfo_self_temp(dec, (VkShaderModuleCreateInfo *)pnext);
+        }
+        break;
     case VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO:
         pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPipelineShaderStageRequiredSubgroupSizeCreateInfo));
         if (pnext) {
@@ -221,6 +229,9 @@
         case VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO:
             vn_replace_VkPipelineShaderStageCreateInfo_handle_self((VkPipelineShaderStageCreateInfo *)pnext);
             break;
+        case VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO:
+            vn_replace_VkShaderModuleCreateInfo_handle_self((VkShaderModuleCreateInfo *)pnext);
+            break;
         case VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO:
             vn_replace_VkPipelineShaderStageRequiredSubgroupSizeCreateInfo_handle_self((VkPipelineShaderStageRequiredSubgroupSizeCreateInfo *)pnext);
             break;
@@ -669,10 +680,10 @@
     } while (pnext);
 }
 
-/* struct VkPipelineViewportStateCreateInfo chain */
+/* struct VkPipelineViewportDepthClipControlCreateInfoEXT chain */
 
 static inline void *
-vn_decode_VkPipelineViewportStateCreateInfo_pnext_temp(struct vn_cs_decoder *dec)
+vn_decode_VkPipelineViewportDepthClipControlCreateInfoEXT_pnext_temp(struct vn_cs_decoder *dec)
 {
     /* no known/supported struct */
     if (vn_decode_simple_pointer(dec))
@@ -681,6 +692,83 @@
 }
 
 static inline void
+vn_decode_VkPipelineViewportDepthClipControlCreateInfoEXT_self_temp(struct vn_cs_decoder *dec, VkPipelineViewportDepthClipControlCreateInfoEXT *val)
+{
+    /* skip val->{sType,pNext} */
+    vn_decode_VkBool32(dec, &val->negativeOneToOne);
+}
+
+static inline void
+vn_decode_VkPipelineViewportDepthClipControlCreateInfoEXT_temp(struct vn_cs_decoder *dec, VkPipelineViewportDepthClipControlCreateInfoEXT *val)
+{
+    VkStructureType stype;
+    vn_decode_VkStructureType(dec, &stype);
+    if (stype != VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT)
+        vn_cs_decoder_set_fatal(dec);
+
+    val->sType = stype;
+    val->pNext = vn_decode_VkPipelineViewportDepthClipControlCreateInfoEXT_pnext_temp(dec);
+    vn_decode_VkPipelineViewportDepthClipControlCreateInfoEXT_self_temp(dec, val);
+}
+
+static inline void
+vn_replace_VkPipelineViewportDepthClipControlCreateInfoEXT_handle_self(VkPipelineViewportDepthClipControlCreateInfoEXT *val)
+{
+    /* skip val->sType */
+    /* skip val->pNext */
+    /* skip val->negativeOneToOne */
+}
+
+static inline void
+vn_replace_VkPipelineViewportDepthClipControlCreateInfoEXT_handle(VkPipelineViewportDepthClipControlCreateInfoEXT *val)
+{
+    struct VkBaseOutStructure *pnext = (struct VkBaseOutStructure *)val;
+
+    do {
+        switch ((int32_t)pnext->sType) {
+        case VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT:
+            vn_replace_VkPipelineViewportDepthClipControlCreateInfoEXT_handle_self((VkPipelineViewportDepthClipControlCreateInfoEXT *)pnext);
+            break;
+        default:
+            /* ignore unknown/unsupported struct */
+            break;
+        }
+        pnext = pnext->pNext;
+    } while (pnext);
+}
+
+/* struct VkPipelineViewportStateCreateInfo chain */
+
+static inline void *
+vn_decode_VkPipelineViewportStateCreateInfo_pnext_temp(struct vn_cs_decoder *dec)
+{
+    VkBaseOutStructure *pnext;
+    VkStructureType stype;
+
+    if (!vn_decode_simple_pointer(dec))
+        return NULL;
+
+    vn_decode_VkStructureType(dec, &stype);
+    switch ((int32_t)stype) {
+    case VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkPipelineViewportDepthClipControlCreateInfoEXT));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkPipelineViewportStateCreateInfo_pnext_temp(dec);
+            vn_decode_VkPipelineViewportDepthClipControlCreateInfoEXT_self_temp(dec, (VkPipelineViewportDepthClipControlCreateInfoEXT *)pnext);
+        }
+        break;
+    default:
+        /* unexpected struct */
+        pnext = NULL;
+        vn_cs_decoder_set_fatal(dec);
+        break;
+    }
+
+    return pnext;
+}
+
+static inline void
 vn_decode_VkPipelineViewportStateCreateInfo_self_temp(struct vn_cs_decoder *dec, VkPipelineViewportStateCreateInfo *val)
 {
     /* skip val->{sType,pNext} */
@@ -750,6 +838,9 @@
         case VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO:
             vn_replace_VkPipelineViewportStateCreateInfo_handle_self((VkPipelineViewportStateCreateInfo *)pnext);
             break;
+        case VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT:
+            vn_replace_VkPipelineViewportDepthClipControlCreateInfoEXT_handle_self((VkPipelineViewportDepthClipControlCreateInfoEXT *)pnext);
+            break;
         default:
             /* ignore unknown/unsupported struct */
             break;
@@ -1678,7 +1769,7 @@
         if (!val->pColorAttachmentFormats) return;
         vn_decode_VkFormat_array(dec, (VkFormat *)val->pColorAttachmentFormats, array_size);
     } else {
-        vn_decode_array_size(dec, val->colorAttachmentCount);
+        vn_decode_array_size_unchecked(dec);
         val->pColorAttachmentFormats = NULL;
     }
     vn_decode_VkFormat(dec, &val->depthAttachmentFormat);
@@ -1780,7 +1871,7 @@
         for (uint32_t i = 0; i < iter_count; i++)
             vn_decode_VkPipelineShaderStageCreateInfo_temp(dec, &((VkPipelineShaderStageCreateInfo *)val->pStages)[i]);
     } else {
-        vn_decode_array_size(dec, val->stageCount);
+        vn_decode_array_size_unchecked(dec);
         val->pStages = NULL;
     }
     if (vn_decode_simple_pointer(dec)) {
@@ -1817,7 +1908,6 @@
         vn_decode_VkPipelineRasterizationStateCreateInfo_temp(dec, (VkPipelineRasterizationStateCreateInfo *)val->pRasterizationState);
     } else {
         val->pRasterizationState = NULL;
-        vn_cs_decoder_set_fatal(dec);
     }
     if (vn_decode_simple_pointer(dec)) {
         val->pMultisampleState = vn_cs_decoder_alloc_temp(dec, sizeof(*val->pMultisampleState));
diff --git a/src/venus/venus-protocol/vn_protocol_renderer_semaphore.h b/src/venus/venus-protocol/vn_protocol_renderer_semaphore.h
index f3cb5a1..bded7e6 100644
--- a/src/venus/venus-protocol/vn_protocol_renderer_semaphore.h
+++ b/src/venus/venus-protocol/vn_protocol_renderer_semaphore.h
@@ -14,6 +14,13 @@
 #pragma GCC diagnostic ignored "-Wpointer-arith"
 #pragma GCC diagnostic ignored "-Wunused-parameter"
 
+/*
+ * These structs/unions/commands are not included
+ *
+ *   vkGetSemaphoreFdKHR
+ *   vkImportSemaphoreFdKHR
+ */
+
 /* struct VkExportSemaphoreCreateInfo chain */
 
 static inline void *
@@ -304,6 +311,65 @@
     } while (pnext);
 }
 
+/* struct VkImportSemaphoreResourceInfo100000MESA chain */
+
+static inline void *
+vn_decode_VkImportSemaphoreResourceInfo100000MESA_pnext_temp(struct vn_cs_decoder *dec)
+{
+    /* no known/supported struct */
+    if (vn_decode_simple_pointer(dec))
+        vn_cs_decoder_set_fatal(dec);
+    return NULL;
+}
+
+static inline void
+vn_decode_VkImportSemaphoreResourceInfo100000MESA_self_temp(struct vn_cs_decoder *dec, VkImportSemaphoreResourceInfo100000MESA *val)
+{
+    /* skip val->{sType,pNext} */
+    vn_decode_VkSemaphore_lookup(dec, &val->semaphore);
+    vn_decode_uint32_t(dec, &val->resourceId);
+}
+
+static inline void
+vn_decode_VkImportSemaphoreResourceInfo100000MESA_temp(struct vn_cs_decoder *dec, VkImportSemaphoreResourceInfo100000MESA *val)
+{
+    VkStructureType stype;
+    vn_decode_VkStructureType(dec, &stype);
+    if (stype != VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_RESOURCE_INFO_100000_MESA)
+        vn_cs_decoder_set_fatal(dec);
+
+    val->sType = stype;
+    val->pNext = vn_decode_VkImportSemaphoreResourceInfo100000MESA_pnext_temp(dec);
+    vn_decode_VkImportSemaphoreResourceInfo100000MESA_self_temp(dec, val);
+}
+
+static inline void
+vn_replace_VkImportSemaphoreResourceInfo100000MESA_handle_self(VkImportSemaphoreResourceInfo100000MESA *val)
+{
+    /* skip val->sType */
+    /* skip val->pNext */
+    vn_replace_VkSemaphore_handle(&val->semaphore);
+    /* skip val->resourceId */
+}
+
+static inline void
+vn_replace_VkImportSemaphoreResourceInfo100000MESA_handle(VkImportSemaphoreResourceInfo100000MESA *val)
+{
+    struct VkBaseOutStructure *pnext = (struct VkBaseOutStructure *)val;
+
+    do {
+        switch ((int32_t)pnext->sType) {
+        case VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_RESOURCE_INFO_100000_MESA:
+            vn_replace_VkImportSemaphoreResourceInfo100000MESA_handle_self((VkImportSemaphoreResourceInfo100000MESA *)pnext);
+            break;
+        default:
+            /* ignore unknown/unsupported struct */
+            break;
+        }
+        pnext = pnext->pNext;
+    } while (pnext);
+}
+
 static inline void vn_decode_vkCreateSemaphore_args_temp(struct vn_cs_decoder *dec, struct vn_command_vkCreateSemaphore *args)
 {
     vn_decode_VkDevice_lookup(dec, &args->device);
@@ -470,6 +536,54 @@
     /* skip args->pSignalInfo */
 }
 
+static inline void vn_decode_vkWaitSemaphoreResource100000MESA_args_temp(struct vn_cs_decoder *dec, struct vn_command_vkWaitSemaphoreResource100000MESA *args)
+{
+    vn_decode_VkDevice_lookup(dec, &args->device);
+    vn_decode_VkSemaphore_lookup(dec, &args->semaphore);
+}
+
+static inline void vn_replace_vkWaitSemaphoreResource100000MESA_args_handle(struct vn_command_vkWaitSemaphoreResource100000MESA *args)
+{
+    vn_replace_VkDevice_handle(&args->device);
+    vn_replace_VkSemaphore_handle(&args->semaphore);
+}
+
+static inline void vn_encode_vkWaitSemaphoreResource100000MESA_reply(struct vn_cs_encoder *enc, const struct vn_command_vkWaitSemaphoreResource100000MESA *args)
+{
+    vn_encode_VkCommandTypeEXT(enc, &(VkCommandTypeEXT){VK_COMMAND_TYPE_vkWaitSemaphoreResource100000MESA_EXT});
+
+    /* skip args->device */
+    /* skip args->semaphore */
+}
+
+static inline void vn_decode_vkImportSemaphoreResource100000MESA_args_temp(struct vn_cs_decoder *dec, struct vn_command_vkImportSemaphoreResource100000MESA *args)
+{
+    vn_decode_VkDevice_lookup(dec, &args->device);
+    if (vn_decode_simple_pointer(dec)) {
+        args->pImportSemaphoreResourceInfo = vn_cs_decoder_alloc_temp(dec, sizeof(*args->pImportSemaphoreResourceInfo));
+        if (!args->pImportSemaphoreResourceInfo) return;
+        vn_decode_VkImportSemaphoreResourceInfo100000MESA_temp(dec, (VkImportSemaphoreResourceInfo100000MESA *)args->pImportSemaphoreResourceInfo);
+    } else {
+        args->pImportSemaphoreResourceInfo = NULL;
+        vn_cs_decoder_set_fatal(dec);
+    }
+}
+
+static inline void vn_replace_vkImportSemaphoreResource100000MESA_args_handle(struct vn_command_vkImportSemaphoreResource100000MESA *args)
+{
+    vn_replace_VkDevice_handle(&args->device);
+    if (args->pImportSemaphoreResourceInfo)
+        vn_replace_VkImportSemaphoreResourceInfo100000MESA_handle((VkImportSemaphoreResourceInfo100000MESA *)args->pImportSemaphoreResourceInfo);
+}
+
+static inline void vn_encode_vkImportSemaphoreResource100000MESA_reply(struct vn_cs_encoder *enc, const struct vn_command_vkImportSemaphoreResource100000MESA *args)
+{
+    vn_encode_VkCommandTypeEXT(enc, &(VkCommandTypeEXT){VK_COMMAND_TYPE_vkImportSemaphoreResource100000MESA_EXT});
+
+    /* skip args->device */
+    /* skip args->pImportSemaphoreResourceInfo */
+}
+
 static inline void vn_dispatch_vkCreateSemaphore(struct vn_dispatch_context *ctx, VkCommandFlagsEXT flags)
 {
     struct vn_command_vkCreateSemaphore args;
@@ -611,6 +725,56 @@
     vn_cs_decoder_reset_temp_pool(ctx->decoder);
 }
 
+static inline void vn_dispatch_vkWaitSemaphoreResource100000MESA(struct vn_dispatch_context *ctx, VkCommandFlagsEXT flags)
+{
+    struct vn_command_vkWaitSemaphoreResource100000MESA args;
+
+    if (!ctx->dispatch_vkWaitSemaphoreResource100000MESA) {
+        vn_cs_decoder_set_fatal(ctx->decoder);
+        return;
+    }
+
+    vn_decode_vkWaitSemaphoreResource100000MESA_args_temp(ctx->decoder, &args);
+    if (!args.device) {
+        vn_cs_decoder_set_fatal(ctx->decoder);
+        return;
+    }
+
+    if (!vn_cs_decoder_get_fatal(ctx->decoder))
+        ctx->dispatch_vkWaitSemaphoreResource100000MESA(ctx, &args);
+
+
+    if (!vn_cs_decoder_get_fatal(ctx->decoder) && (flags & VK_COMMAND_GENERATE_REPLY_BIT_EXT))
+       vn_encode_vkWaitSemaphoreResource100000MESA_reply(ctx->encoder, &args);
+
+    vn_cs_decoder_reset_temp_pool(ctx->decoder);
+}
+
+static inline void vn_dispatch_vkImportSemaphoreResource100000MESA(struct vn_dispatch_context *ctx, VkCommandFlagsEXT flags)
+{
+    struct vn_command_vkImportSemaphoreResource100000MESA args;
+
+    if (!ctx->dispatch_vkImportSemaphoreResource100000MESA) {
+        vn_cs_decoder_set_fatal(ctx->decoder);
+        return;
+    }
+
+    vn_decode_vkImportSemaphoreResource100000MESA_args_temp(ctx->decoder, &args);
+    if (!args.device) {
+        vn_cs_decoder_set_fatal(ctx->decoder);
+        return;
+    }
+
+    if (!vn_cs_decoder_get_fatal(ctx->decoder))
+        ctx->dispatch_vkImportSemaphoreResource100000MESA(ctx, &args);
+
+
+    if (!vn_cs_decoder_get_fatal(ctx->decoder) && (flags & VK_COMMAND_GENERATE_REPLY_BIT_EXT))
+       vn_encode_vkImportSemaphoreResource100000MESA_reply(ctx->encoder, &args);
+
+    vn_cs_decoder_reset_temp_pool(ctx->decoder);
+}
+
 #pragma GCC diagnostic pop
 
 #endif /* VN_PROTOCOL_RENDERER_SEMAPHORE_H */
diff --git a/src/venus/venus-protocol/vn_protocol_renderer_shader_module.h b/src/venus/venus-protocol/vn_protocol_renderer_shader_module.h
index e83a275..81006b6 100644
--- a/src/venus/venus-protocol/vn_protocol_renderer_shader_module.h
+++ b/src/venus/venus-protocol/vn_protocol_renderer_shader_module.h
@@ -14,75 +14,6 @@
 #pragma GCC diagnostic ignored "-Wpointer-arith"
 #pragma GCC diagnostic ignored "-Wunused-parameter"
 
-/* struct VkShaderModuleCreateInfo chain */
-
-static inline void *
-vn_decode_VkShaderModuleCreateInfo_pnext_temp(struct vn_cs_decoder *dec)
-{
-    /* no known/supported struct */
-    if (vn_decode_simple_pointer(dec))
-        vn_cs_decoder_set_fatal(dec);
-    return NULL;
-}
-
-static inline void
-vn_decode_VkShaderModuleCreateInfo_self_temp(struct vn_cs_decoder *dec, VkShaderModuleCreateInfo *val)
-{
-    /* skip val->{sType,pNext} */
-    vn_decode_VkFlags(dec, &val->flags);
-    vn_decode_size_t(dec, &val->codeSize);
-    if (vn_peek_array_size(dec)) {
-        const size_t array_size = vn_decode_array_size(dec, val->codeSize / 4);
-        val->pCode = vn_cs_decoder_alloc_temp(dec, sizeof(*val->pCode) * array_size);
-        if (!val->pCode) return;
-        vn_decode_uint32_t_array(dec, (uint32_t *)val->pCode, array_size);
-    } else {
-        vn_decode_array_size(dec, val->codeSize / 4);
-        val->pCode = NULL;
-    }
-}
-
-static inline void
-vn_decode_VkShaderModuleCreateInfo_temp(struct vn_cs_decoder *dec, VkShaderModuleCreateInfo *val)
-{
-    VkStructureType stype;
-    vn_decode_VkStructureType(dec, &stype);
-    if (stype != VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO)
-        vn_cs_decoder_set_fatal(dec);
-
-    val->sType = stype;
-    val->pNext = vn_decode_VkShaderModuleCreateInfo_pnext_temp(dec);
-    vn_decode_VkShaderModuleCreateInfo_self_temp(dec, val);
-}
-
-static inline void
-vn_replace_VkShaderModuleCreateInfo_handle_self(VkShaderModuleCreateInfo *val)
-{
-    /* skip val->sType */
-    /* skip val->pNext */
-    /* skip val->flags */
-    /* skip val->codeSize */
-    /* skip val->pCode */
-}
-
-static inline void
-vn_replace_VkShaderModuleCreateInfo_handle(VkShaderModuleCreateInfo *val)
-{
-    struct VkBaseOutStructure *pnext = (struct VkBaseOutStructure *)val;
-
-    do {
-        switch ((int32_t)pnext->sType) {
-        case VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO:
-            vn_replace_VkShaderModuleCreateInfo_handle_self((VkShaderModuleCreateInfo *)pnext);
-            break;
-        default:
-            /* ignore unknown/unsupported struct */
-            break;
-        }
-        pnext = pnext->pNext;
-    } while (pnext);
-}
-
 static inline void vn_decode_vkCreateShaderModule_args_temp(struct vn_cs_decoder *dec, struct vn_command_vkCreateShaderModule *args)
 {
     vn_decode_VkDevice_lookup(dec, &args->device);
diff --git a/src/venus/venus-protocol/vn_protocol_renderer_structs.h b/src/venus/venus-protocol/vn_protocol_renderer_structs.h
index 99f978b..21d22c2 100644
--- a/src/venus/venus-protocol/vn_protocol_renderer_structs.h
+++ b/src/venus/venus-protocol/vn_protocol_renderer_structs.h
@@ -482,6 +482,75 @@
     } while (pnext);
 }
 
+/* struct VkShaderModuleCreateInfo chain */
+
+static inline void *
+vn_decode_VkShaderModuleCreateInfo_pnext_temp(struct vn_cs_decoder *dec)
+{
+    /* no known/supported struct */
+    if (vn_decode_simple_pointer(dec))
+        vn_cs_decoder_set_fatal(dec);
+    return NULL;
+}
+
+static inline void
+vn_decode_VkShaderModuleCreateInfo_self_temp(struct vn_cs_decoder *dec, VkShaderModuleCreateInfo *val)
+{
+    /* skip val->{sType,pNext} */
+    vn_decode_VkFlags(dec, &val->flags);
+    vn_decode_size_t(dec, &val->codeSize);
+    if (vn_peek_array_size(dec)) {
+        const size_t array_size = vn_decode_array_size(dec, val->codeSize / 4);
+        val->pCode = vn_cs_decoder_alloc_temp(dec, sizeof(*val->pCode) * array_size);
+        if (!val->pCode) return;
+        vn_decode_uint32_t_array(dec, (uint32_t *)val->pCode, array_size);
+    } else {
+        vn_decode_array_size(dec, val->codeSize / 4);
+        val->pCode = NULL;
+    }
+}
+
+static inline void
+vn_decode_VkShaderModuleCreateInfo_temp(struct vn_cs_decoder *dec, VkShaderModuleCreateInfo *val)
+{
+    VkStructureType stype;
+    vn_decode_VkStructureType(dec, &stype);
+    if (stype != VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO)
+        vn_cs_decoder_set_fatal(dec);
+
+    val->sType = stype;
+    val->pNext = vn_decode_VkShaderModuleCreateInfo_pnext_temp(dec);
+    vn_decode_VkShaderModuleCreateInfo_self_temp(dec, val);
+}
+
+static inline void
+vn_replace_VkShaderModuleCreateInfo_handle_self(VkShaderModuleCreateInfo *val)
+{
+    /* skip val->sType */
+    /* skip val->pNext */
+    /* skip val->flags */
+    /* skip val->codeSize */
+    /* skip val->pCode */
+}
+
+static inline void
+vn_replace_VkShaderModuleCreateInfo_handle(VkShaderModuleCreateInfo *val)
+{
+    struct VkBaseOutStructure *pnext = (struct VkBaseOutStructure *)val;
+
+    do {
+        switch ((int32_t)pnext->sType) {
+        case VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO:
+            vn_replace_VkShaderModuleCreateInfo_handle_self((VkShaderModuleCreateInfo *)pnext);
+            break;
+        default:
+            /* ignore unknown/unsupported struct */
+            break;
+        }
+        pnext = pnext->pNext;
+    } while (pnext);
+}
+
 /* struct VkViewport */
 
 static inline void
@@ -606,21 +675,21 @@
     switch (tag) {
     case 0:
         {
-        const size_t array_size = vn_decode_array_size(dec, 4);
-        vn_decode_float_array(dec, val->float32, array_size);
-    }
+            const size_t array_size = vn_decode_array_size(dec, 4);
+            vn_decode_float_array(dec, val->float32, array_size);
+        }
         break;
     case 1:
         {
-        const size_t array_size = vn_decode_array_size(dec, 4);
-        vn_decode_int32_t_array(dec, val->int32, array_size);
-    }
+            const size_t array_size = vn_decode_array_size(dec, 4);
+            vn_decode_int32_t_array(dec, val->int32, array_size);
+        }
         break;
     case 2:
         {
-        const size_t array_size = vn_decode_array_size(dec, 4);
-        vn_decode_uint32_t_array(dec, val->uint32, array_size);
-    }
+            const size_t array_size = vn_decode_array_size(dec, 4);
+            vn_decode_uint32_t_array(dec, val->uint32, array_size);
+        }
         break;
     default:
         vn_cs_decoder_set_fatal(dec);
@@ -628,6 +697,334 @@
     }
 }
 
+/* struct VkMutableDescriptorTypeListEXT */
+
+static inline void
+vn_decode_VkMutableDescriptorTypeListEXT_temp(struct vn_cs_decoder *dec, VkMutableDescriptorTypeListEXT *val)
+{
+    vn_decode_uint32_t(dec, &val->descriptorTypeCount);
+    if (vn_peek_array_size(dec)) {
+        const size_t array_size = vn_decode_array_size(dec, val->descriptorTypeCount);
+        val->pDescriptorTypes = vn_cs_decoder_alloc_temp(dec, sizeof(*val->pDescriptorTypes) * array_size);
+        if (!val->pDescriptorTypes) return;
+        vn_decode_VkDescriptorType_array(dec, (VkDescriptorType *)val->pDescriptorTypes, array_size);
+    } else {
+        vn_decode_array_size(dec, val->descriptorTypeCount);
+        val->pDescriptorTypes = NULL;
+    }
+}
+
+static inline void
+vn_replace_VkMutableDescriptorTypeListEXT_handle(VkMutableDescriptorTypeListEXT *val)
+{
+    /* skip val->descriptorTypeCount */
+    /* skip val->pDescriptorTypes */
+}
+
+/* struct VkMutableDescriptorTypeCreateInfoEXT chain */
+
+static inline void *
+vn_decode_VkMutableDescriptorTypeCreateInfoEXT_pnext_temp(struct vn_cs_decoder *dec)
+{
+    /* no known/supported struct */
+    if (vn_decode_simple_pointer(dec))
+        vn_cs_decoder_set_fatal(dec);
+    return NULL;
+}
+
+static inline void
+vn_decode_VkMutableDescriptorTypeCreateInfoEXT_self_temp(struct vn_cs_decoder *dec, VkMutableDescriptorTypeCreateInfoEXT *val)
+{
+    /* skip val->{sType,pNext} */
+    vn_decode_uint32_t(dec, &val->mutableDescriptorTypeListCount);
+    if (vn_peek_array_size(dec)) {
+        const uint32_t iter_count = vn_decode_array_size(dec, val->mutableDescriptorTypeListCount);
+        val->pMutableDescriptorTypeLists = vn_cs_decoder_alloc_temp(dec, sizeof(*val->pMutableDescriptorTypeLists) * iter_count);
+        if (!val->pMutableDescriptorTypeLists) return;
+        for (uint32_t i = 0; i < iter_count; i++)
+            vn_decode_VkMutableDescriptorTypeListEXT_temp(dec, &((VkMutableDescriptorTypeListEXT *)val->pMutableDescriptorTypeLists)[i]);
+    } else {
+        vn_decode_array_size(dec, val->mutableDescriptorTypeListCount);
+        val->pMutableDescriptorTypeLists = NULL;
+    }
+}
+
+static inline void
+vn_decode_VkMutableDescriptorTypeCreateInfoEXT_temp(struct vn_cs_decoder *dec, VkMutableDescriptorTypeCreateInfoEXT *val)
+{
+    VkStructureType stype;
+    vn_decode_VkStructureType(dec, &stype);
+    if (stype != VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT)
+        vn_cs_decoder_set_fatal(dec);
+
+    val->sType = stype;
+    val->pNext = vn_decode_VkMutableDescriptorTypeCreateInfoEXT_pnext_temp(dec);
+    vn_decode_VkMutableDescriptorTypeCreateInfoEXT_self_temp(dec, val);
+}
+
+static inline void
+vn_replace_VkMutableDescriptorTypeCreateInfoEXT_handle_self(VkMutableDescriptorTypeCreateInfoEXT *val)
+{
+    /* skip val->sType */
+    /* skip val->pNext */
+    /* skip val->mutableDescriptorTypeListCount */
+    if (val->pMutableDescriptorTypeLists) {
+       for (uint32_t i = 0; i < val->mutableDescriptorTypeListCount; i++)
+            vn_replace_VkMutableDescriptorTypeListEXT_handle(&((VkMutableDescriptorTypeListEXT *)val->pMutableDescriptorTypeLists)[i]);
+    }
+}
+
+static inline void
+vn_replace_VkMutableDescriptorTypeCreateInfoEXT_handle(VkMutableDescriptorTypeCreateInfoEXT *val)
+{
+    struct VkBaseOutStructure *pnext = (struct VkBaseOutStructure *)val;
+
+    do {
+        switch ((int32_t)pnext->sType) {
+        case VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT:
+            vn_replace_VkMutableDescriptorTypeCreateInfoEXT_handle_self((VkMutableDescriptorTypeCreateInfoEXT *)pnext);
+            break;
+        default:
+            /* ignore unknown/unsupported struct */
+            break;
+        }
+        pnext = pnext->pNext;
+    } while (pnext);
+}
+
+/* struct VkDescriptorImageInfo */
+
+static inline void
+vn_decode_VkDescriptorImageInfo_temp(struct vn_cs_decoder *dec, VkDescriptorImageInfo *val)
+{
+    vn_decode_VkSampler_lookup(dec, &val->sampler);
+    vn_decode_VkImageView_lookup(dec, &val->imageView);
+    vn_decode_VkImageLayout(dec, &val->imageLayout);
+}
+
+static inline void
+vn_replace_VkDescriptorImageInfo_handle(VkDescriptorImageInfo *val)
+{
+    vn_replace_VkSampler_handle(&val->sampler);
+    vn_replace_VkImageView_handle(&val->imageView);
+    /* skip val->imageLayout */
+}
+
+/* struct VkDescriptorBufferInfo */
+
+static inline void
+vn_decode_VkDescriptorBufferInfo_temp(struct vn_cs_decoder *dec, VkDescriptorBufferInfo *val)
+{
+    vn_decode_VkBuffer_lookup(dec, &val->buffer);
+    vn_decode_VkDeviceSize(dec, &val->offset);
+    vn_decode_VkDeviceSize(dec, &val->range);
+}
+
+static inline void
+vn_replace_VkDescriptorBufferInfo_handle(VkDescriptorBufferInfo *val)
+{
+    vn_replace_VkBuffer_handle(&val->buffer);
+    /* skip val->offset */
+    /* skip val->range */
+}
+
+/* struct VkWriteDescriptorSetInlineUniformBlock chain */
+
+static inline void *
+vn_decode_VkWriteDescriptorSetInlineUniformBlock_pnext_temp(struct vn_cs_decoder *dec)
+{
+    /* no known/supported struct */
+    if (vn_decode_simple_pointer(dec))
+        vn_cs_decoder_set_fatal(dec);
+    return NULL;
+}
+
+static inline void
+vn_decode_VkWriteDescriptorSetInlineUniformBlock_self_temp(struct vn_cs_decoder *dec, VkWriteDescriptorSetInlineUniformBlock *val)
+{
+    /* skip val->{sType,pNext} */
+    vn_decode_uint32_t(dec, &val->dataSize);
+    if (vn_peek_array_size(dec)) {
+        const size_t array_size = vn_decode_array_size(dec, val->dataSize);
+        val->pData = vn_cs_decoder_alloc_temp(dec, array_size);
+        if (!val->pData) return;
+        vn_decode_blob_array(dec, (void *)val->pData, array_size);
+    } else {
+        vn_decode_array_size(dec, val->dataSize);
+        val->pData = NULL;
+    }
+}
+
+static inline void
+vn_decode_VkWriteDescriptorSetInlineUniformBlock_temp(struct vn_cs_decoder *dec, VkWriteDescriptorSetInlineUniformBlock *val)
+{
+    VkStructureType stype;
+    vn_decode_VkStructureType(dec, &stype);
+    if (stype != VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK)
+        vn_cs_decoder_set_fatal(dec);
+
+    val->sType = stype;
+    val->pNext = vn_decode_VkWriteDescriptorSetInlineUniformBlock_pnext_temp(dec);
+    vn_decode_VkWriteDescriptorSetInlineUniformBlock_self_temp(dec, val);
+}
+
+static inline void
+vn_replace_VkWriteDescriptorSetInlineUniformBlock_handle_self(VkWriteDescriptorSetInlineUniformBlock *val)
+{
+    /* skip val->sType */
+    /* skip val->pNext */
+    /* skip val->dataSize */
+    /* skip val->pData */
+}
+
+static inline void
+vn_replace_VkWriteDescriptorSetInlineUniformBlock_handle(VkWriteDescriptorSetInlineUniformBlock *val)
+{
+    struct VkBaseOutStructure *pnext = (struct VkBaseOutStructure *)val;
+
+    do {
+        switch ((int32_t)pnext->sType) {
+        case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK:
+            vn_replace_VkWriteDescriptorSetInlineUniformBlock_handle_self((VkWriteDescriptorSetInlineUniformBlock *)pnext);
+            break;
+        default:
+            /* ignore unknown/unsupported struct */
+            break;
+        }
+        pnext = pnext->pNext;
+    } while (pnext);
+}
+
+/* struct VkWriteDescriptorSet chain */
+
+static inline void *
+vn_decode_VkWriteDescriptorSet_pnext_temp(struct vn_cs_decoder *dec)
+{
+    VkBaseOutStructure *pnext;
+    VkStructureType stype;
+
+    if (!vn_decode_simple_pointer(dec))
+        return NULL;
+
+    vn_decode_VkStructureType(dec, &stype);
+    switch ((int32_t)stype) {
+    case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK:
+        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkWriteDescriptorSetInlineUniformBlock));
+        if (pnext) {
+            pnext->sType = stype;
+            pnext->pNext = vn_decode_VkWriteDescriptorSet_pnext_temp(dec);
+            vn_decode_VkWriteDescriptorSetInlineUniformBlock_self_temp(dec, (VkWriteDescriptorSetInlineUniformBlock *)pnext);
+        }
+        break;
+    default:
+        /* unexpected struct */
+        pnext = NULL;
+        vn_cs_decoder_set_fatal(dec);
+        break;
+    }
+
+    return pnext;
+}
+
+static inline void
+vn_decode_VkWriteDescriptorSet_self_temp(struct vn_cs_decoder *dec, VkWriteDescriptorSet *val)
+{
+    /* skip val->{sType,pNext} */
+    vn_decode_VkDescriptorSet_lookup(dec, &val->dstSet);
+    vn_decode_uint32_t(dec, &val->dstBinding);
+    vn_decode_uint32_t(dec, &val->dstArrayElement);
+    vn_decode_uint32_t(dec, &val->descriptorCount);
+    vn_decode_VkDescriptorType(dec, &val->descriptorType);
+    if (vn_peek_array_size(dec)) {
+        const uint32_t iter_count = vn_decode_array_size(dec, val->descriptorCount);
+        val->pImageInfo = vn_cs_decoder_alloc_temp(dec, sizeof(*val->pImageInfo) * iter_count);
+        if (!val->pImageInfo) return;
+        for (uint32_t i = 0; i < iter_count; i++)
+            vn_decode_VkDescriptorImageInfo_temp(dec, &((VkDescriptorImageInfo *)val->pImageInfo)[i]);
+    } else {
+        vn_decode_array_size_unchecked(dec);
+        val->pImageInfo = NULL;
+    }
+    if (vn_peek_array_size(dec)) {
+        const uint32_t iter_count = vn_decode_array_size(dec, val->descriptorCount);
+        val->pBufferInfo = vn_cs_decoder_alloc_temp(dec, sizeof(*val->pBufferInfo) * iter_count);
+        if (!val->pBufferInfo) return;
+        for (uint32_t i = 0; i < iter_count; i++)
+            vn_decode_VkDescriptorBufferInfo_temp(dec, &((VkDescriptorBufferInfo *)val->pBufferInfo)[i]);
+    } else {
+        vn_decode_array_size_unchecked(dec);
+        val->pBufferInfo = NULL;
+    }
+    if (vn_peek_array_size(dec)) {
+        const uint32_t iter_count = vn_decode_array_size(dec, val->descriptorCount);
+        val->pTexelBufferView = vn_cs_decoder_alloc_temp(dec, sizeof(*val->pTexelBufferView) * iter_count);
+        if (!val->pTexelBufferView) return;
+        for (uint32_t i = 0; i < iter_count; i++)
+            vn_decode_VkBufferView_lookup(dec, &((VkBufferView *)val->pTexelBufferView)[i]);
+    } else {
+        vn_decode_array_size_unchecked(dec);
+        val->pTexelBufferView = NULL;
+    }
+}
+
+static inline void
+vn_decode_VkWriteDescriptorSet_temp(struct vn_cs_decoder *dec, VkWriteDescriptorSet *val)
+{
+    VkStructureType stype;
+    vn_decode_VkStructureType(dec, &stype);
+    if (stype != VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET)
+        vn_cs_decoder_set_fatal(dec);
+
+    val->sType = stype;
+    val->pNext = vn_decode_VkWriteDescriptorSet_pnext_temp(dec);
+    vn_decode_VkWriteDescriptorSet_self_temp(dec, val);
+}
+
+static inline void
+vn_replace_VkWriteDescriptorSet_handle_self(VkWriteDescriptorSet *val)
+{
+    /* skip val->sType */
+    /* skip val->pNext */
+    vn_replace_VkDescriptorSet_handle(&val->dstSet);
+    /* skip val->dstBinding */
+    /* skip val->dstArrayElement */
+    /* skip val->descriptorCount */
+    /* skip val->descriptorType */
+    if (val->pImageInfo) {
+       for (uint32_t i = 0; i < val->descriptorCount; i++)
+            vn_replace_VkDescriptorImageInfo_handle(&((VkDescriptorImageInfo *)val->pImageInfo)[i]);
+    }
+    if (val->pBufferInfo) {
+       for (uint32_t i = 0; i < val->descriptorCount; i++)
+            vn_replace_VkDescriptorBufferInfo_handle(&((VkDescriptorBufferInfo *)val->pBufferInfo)[i]);
+    }
+    if (val->pTexelBufferView) {
+       for (uint32_t i = 0; i < val->descriptorCount; i++)
+            vn_replace_VkBufferView_handle(&((VkBufferView *)val->pTexelBufferView)[i]);
+    }
+}
+
+static inline void
+vn_replace_VkWriteDescriptorSet_handle(VkWriteDescriptorSet *val)
+{
+    struct VkBaseOutStructure *pnext = (struct VkBaseOutStructure *)val;
+
+    do {
+        switch ((int32_t)pnext->sType) {
+        case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
+            vn_replace_VkWriteDescriptorSet_handle_self((VkWriteDescriptorSet *)pnext);
+            break;
+        case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK:
+            vn_replace_VkWriteDescriptorSetInlineUniformBlock_handle_self((VkWriteDescriptorSetInlineUniformBlock *)pnext);
+            break;
+        default:
+            /* ignore unknown/unsupported struct */
+            break;
+        }
+        pnext = pnext->pNext;
+    } while (pnext);
+}
+
 /* struct VkMemoryDedicatedRequirements chain */
 
 static inline void
diff --git a/src/venus/venus-protocol/vn_protocol_renderer_transport.h b/src/venus/venus-protocol/vn_protocol_renderer_transport.h
index 570ee57..0d9e7d7 100644
--- a/src/venus/venus-protocol/vn_protocol_renderer_transport.h
+++ b/src/venus/venus-protocol/vn_protocol_renderer_transport.h
@@ -14,14 +14,6 @@
 #pragma GCC diagnostic ignored "-Wpointer-arith"
 #pragma GCC diagnostic ignored "-Wunused-parameter"
 
-/*
- * These structs/unions/commands are not included
- *
- *   vkGetMemoryFdKHR
- *   vkGetMemoryFdPropertiesKHR
- *   vkImportFenceFdKHR
- */
-
 /* struct VkCommandStreamDescriptionMESA */
 
 static inline void
@@ -135,150 +127,6 @@
     } while (pnext);
 }
 
-/* struct VkMemoryResourceAllocationSizeProperties100000MESA chain */
-
-static inline void
-vn_encode_VkMemoryResourceAllocationSizeProperties100000MESA_pnext(struct vn_cs_encoder *enc, const void *val)
-{
-    /* no known/supported struct */
-    vn_encode_simple_pointer(enc, NULL);
-}
-
-static inline void
-vn_encode_VkMemoryResourceAllocationSizeProperties100000MESA_self(struct vn_cs_encoder *enc, const VkMemoryResourceAllocationSizeProperties100000MESA *val)
-{
-    /* skip val->{sType,pNext} */
-    vn_encode_uint64_t(enc, &val->allocationSize);
-}
-
-static inline void
-vn_encode_VkMemoryResourceAllocationSizeProperties100000MESA(struct vn_cs_encoder *enc, const VkMemoryResourceAllocationSizeProperties100000MESA *val)
-{
-    assert(val->sType == VK_STRUCTURE_TYPE_MEMORY_RESOURCE_ALLOCATION_SIZE_PROPERTIES_100000_MESA);
-    vn_encode_VkStructureType(enc, &(VkStructureType){ VK_STRUCTURE_TYPE_MEMORY_RESOURCE_ALLOCATION_SIZE_PROPERTIES_100000_MESA });
-    vn_encode_VkMemoryResourceAllocationSizeProperties100000MESA_pnext(enc, val->pNext);
-    vn_encode_VkMemoryResourceAllocationSizeProperties100000MESA_self(enc, val);
-}
-
-static inline void *
-vn_decode_VkMemoryResourceAllocationSizeProperties100000MESA_pnext_partial_temp(struct vn_cs_decoder *dec)
-{
-    /* no known/supported struct */
-    if (vn_decode_simple_pointer(dec))
-        vn_cs_decoder_set_fatal(dec);
-    return NULL;
-}
-
-static inline void
-vn_decode_VkMemoryResourceAllocationSizeProperties100000MESA_self_partial_temp(struct vn_cs_decoder *dec, VkMemoryResourceAllocationSizeProperties100000MESA *val)
-{
-    /* skip val->{sType,pNext} */
-    /* skip val->allocationSize */
-}
-
-static inline void
-vn_decode_VkMemoryResourceAllocationSizeProperties100000MESA_partial_temp(struct vn_cs_decoder *dec, VkMemoryResourceAllocationSizeProperties100000MESA *val)
-{
-    VkStructureType stype;
-    vn_decode_VkStructureType(dec, &stype);
-    if (stype != VK_STRUCTURE_TYPE_MEMORY_RESOURCE_ALLOCATION_SIZE_PROPERTIES_100000_MESA)
-        vn_cs_decoder_set_fatal(dec);
-
-    val->sType = stype;
-    val->pNext = vn_decode_VkMemoryResourceAllocationSizeProperties100000MESA_pnext_partial_temp(dec);
-    vn_decode_VkMemoryResourceAllocationSizeProperties100000MESA_self_partial_temp(dec, val);
-}
-
-/* struct VkMemoryResourcePropertiesMESA chain */
-
-static inline void
-vn_encode_VkMemoryResourcePropertiesMESA_pnext(struct vn_cs_encoder *enc, const void *val)
-{
-    const VkBaseInStructure *pnext = val;
-
-    while (pnext) {
-        switch ((int32_t)pnext->sType) {
-        case VK_STRUCTURE_TYPE_MEMORY_RESOURCE_ALLOCATION_SIZE_PROPERTIES_100000_MESA:
-            vn_encode_simple_pointer(enc, pnext);
-            vn_encode_VkStructureType(enc, &pnext->sType);
-            vn_encode_VkMemoryResourcePropertiesMESA_pnext(enc, pnext->pNext);
-            vn_encode_VkMemoryResourceAllocationSizeProperties100000MESA_self(enc, (const VkMemoryResourceAllocationSizeProperties100000MESA *)pnext);
-            return;
-        default:
-            /* ignore unknown/unsupported struct */
-            break;
-        }
-        pnext = pnext->pNext;
-    }
-
-    vn_encode_simple_pointer(enc, NULL);
-}
-
-static inline void
-vn_encode_VkMemoryResourcePropertiesMESA_self(struct vn_cs_encoder *enc, const VkMemoryResourcePropertiesMESA *val)
-{
-    /* skip val->{sType,pNext} */
-    vn_encode_uint32_t(enc, &val->memoryTypeBits);
-}
-
-static inline void
-vn_encode_VkMemoryResourcePropertiesMESA(struct vn_cs_encoder *enc, const VkMemoryResourcePropertiesMESA *val)
-{
-    assert(val->sType == VK_STRUCTURE_TYPE_MEMORY_RESOURCE_PROPERTIES_MESA);
-    vn_encode_VkStructureType(enc, &(VkStructureType){ VK_STRUCTURE_TYPE_MEMORY_RESOURCE_PROPERTIES_MESA });
-    vn_encode_VkMemoryResourcePropertiesMESA_pnext(enc, val->pNext);
-    vn_encode_VkMemoryResourcePropertiesMESA_self(enc, val);
-}
-
-static inline void *
-vn_decode_VkMemoryResourcePropertiesMESA_pnext_partial_temp(struct vn_cs_decoder *dec)
-{
-    VkBaseOutStructure *pnext;
-    VkStructureType stype;
-
-    if (!vn_decode_simple_pointer(dec))
-        return NULL;
-
-    vn_decode_VkStructureType(dec, &stype);
-    switch ((int32_t)stype) {
-    case VK_STRUCTURE_TYPE_MEMORY_RESOURCE_ALLOCATION_SIZE_PROPERTIES_100000_MESA:
-        pnext = vn_cs_decoder_alloc_temp(dec, sizeof(VkMemoryResourceAllocationSizeProperties100000MESA));
-        if (pnext) {
-            pnext->sType = stype;
-            pnext->pNext = vn_decode_VkMemoryResourcePropertiesMESA_pnext_partial_temp(dec);
-            vn_decode_VkMemoryResourceAllocationSizeProperties100000MESA_self_partial_temp(dec, (VkMemoryResourceAllocationSizeProperties100000MESA *)pnext);
-        }
-        break;
-    default:
-        /* unexpected struct */
-        pnext = NULL;
-        vn_cs_decoder_set_fatal(dec);
-        break;
-    }
-
-    return pnext;
-}
-
-static inline void
-vn_decode_VkMemoryResourcePropertiesMESA_self_partial_temp(struct vn_cs_decoder *dec, VkMemoryResourcePropertiesMESA *val)
-{
-    /* skip val->{sType,pNext} */
-    /* skip val->memoryTypeBits */
-}
-
-static inline void
-vn_decode_VkMemoryResourcePropertiesMESA_partial_temp(struct vn_cs_decoder *dec, VkMemoryResourcePropertiesMESA *val)
-{
-    VkStructureType stype;
-    vn_decode_VkStructureType(dec, &stype);
-    if (stype != VK_STRUCTURE_TYPE_MEMORY_RESOURCE_PROPERTIES_MESA)
-        vn_cs_decoder_set_fatal(dec);
-
-    val->sType = stype;
-    val->pNext = vn_decode_VkMemoryResourcePropertiesMESA_pnext_partial_temp(dec);
-    vn_decode_VkMemoryResourcePropertiesMESA_self_partial_temp(dec, val);
-}
-
 static inline void vn_decode_vkSetReplyCommandStreamMESA_args_temp(struct vn_cs_decoder *dec, struct vn_command_vkSetReplyCommandStreamMESA *args)
 {
     if (vn_decode_simple_pointer(dec)) {
@@ -476,38 +324,6 @@
     /* skip args->value */
 }
 
-static inline void vn_decode_vkGetMemoryResourcePropertiesMESA_args_temp(struct vn_cs_decoder *dec, struct vn_command_vkGetMemoryResourcePropertiesMESA *args)
-{
-    vn_decode_VkDevice_lookup(dec, &args->device);
-    vn_decode_uint32_t(dec, &args->resourceId);
-    if (vn_decode_simple_pointer(dec)) {
-        args->pMemoryResourceProperties = vn_cs_decoder_alloc_temp(dec, sizeof(*args->pMemoryResourceProperties));
-        if (!args->pMemoryResourceProperties) return;
-        vn_decode_VkMemoryResourcePropertiesMESA_partial_temp(dec, args->pMemoryResourceProperties);
-    } else {
-        args->pMemoryResourceProperties = NULL;
-        vn_cs_decoder_set_fatal(dec);
-    }
-}
-
-static inline void vn_replace_vkGetMemoryResourcePropertiesMESA_args_handle(struct vn_command_vkGetMemoryResourcePropertiesMESA *args)
-{
-    vn_replace_VkDevice_handle(&args->device);
-    /* skip args->resourceId */
-    /* skip args->pMemoryResourceProperties */
-}
-
-static inline void vn_encode_vkGetMemoryResourcePropertiesMESA_reply(struct vn_cs_encoder *enc, const struct vn_command_vkGetMemoryResourcePropertiesMESA *args)
-{
-    vn_encode_VkCommandTypeEXT(enc, &(VkCommandTypeEXT){VK_COMMAND_TYPE_vkGetMemoryResourcePropertiesMESA_EXT});
-
-    vn_encode_VkResult(enc, &args->ret);
-    /* skip args->device */
-    /* skip args->resourceId */
-    if (vn_encode_simple_pointer(enc, args->pMemoryResourceProperties))
-        vn_encode_VkMemoryResourcePropertiesMESA(enc, args->pMemoryResourceProperties);
-}
-
 static inline void vn_decode_vkGetVenusExperimentalFeatureData100000MESA_args_temp(struct vn_cs_decoder *dec, struct vn_command_vkGetVenusExperimentalFeatureData100000MESA *args)
 {
     if (vn_decode_simple_pointer(dec)) {
@@ -695,35 +511,6 @@
     vn_cs_decoder_reset_temp_pool(ctx->decoder);
 }
 
-static inline void vn_dispatch_vkGetMemoryResourcePropertiesMESA(struct vn_dispatch_context *ctx, VkCommandFlagsEXT flags)
-{
-    struct vn_command_vkGetMemoryResourcePropertiesMESA args;
-
-    if (!ctx->dispatch_vkGetMemoryResourcePropertiesMESA) {
-        vn_cs_decoder_set_fatal(ctx->decoder);
-        return;
-    }
-
-    vn_decode_vkGetMemoryResourcePropertiesMESA_args_temp(ctx->decoder, &args);
-    if (!args.device) {
-        vn_cs_decoder_set_fatal(ctx->decoder);
-        return;
-    }
-
-    if (!vn_cs_decoder_get_fatal(ctx->decoder))
-        ctx->dispatch_vkGetMemoryResourcePropertiesMESA(ctx, &args);
-
-#ifdef DEBUG
-    if (!vn_cs_decoder_get_fatal(ctx->decoder) && vn_dispatch_should_log_result(args.ret))
-        vn_dispatch_debug_log(ctx, "vkGetMemoryResourcePropertiesMESA returned %d", args.ret);
-#endif
-
-    if (!vn_cs_decoder_get_fatal(ctx->decoder) && (flags & VK_COMMAND_GENERATE_REPLY_BIT_EXT))
-       vn_encode_vkGetMemoryResourcePropertiesMESA_reply(ctx->encoder, &args);
-
-    vn_cs_decoder_reset_temp_pool(ctx->decoder);
-}
-
 static inline void vn_dispatch_vkGetVenusExperimentalFeatureData100000MESA(struct vn_dispatch_context *ctx, VkCommandFlagsEXT flags)
 {
     struct vn_command_vkGetVenusExperimentalFeatureData100000MESA args;
diff --git a/src/venus/venus-protocol/vn_protocol_renderer_types.h b/src/venus/venus-protocol/vn_protocol_renderer_types.h
index 69aa060..0e6e18b 100644
--- a/src/venus/venus-protocol/vn_protocol_renderer_types.h
+++ b/src/venus/venus-protocol/vn_protocol_renderer_types.h
@@ -497,6 +497,20 @@
     vn_decode_int32_t(dec, (int32_t *)val);
 }
 
+/* enum VkPipelineLayoutCreateFlagBits */
+
+static inline void
+vn_encode_VkPipelineLayoutCreateFlagBits(struct vn_cs_encoder *enc, const VkPipelineLayoutCreateFlagBits *val)
+{
+    vn_encode_int32_t(enc, (const int32_t *)val);
+}
+
+static inline void
+vn_decode_VkPipelineLayoutCreateFlagBits(struct vn_cs_decoder *dec, VkPipelineLayoutCreateFlagBits *val)
+{
+    vn_decode_int32_t(dec, (int32_t *)val);
+}
+
 /* enum VkPipelineCacheCreateFlagBits */
 
 static inline void
@@ -567,6 +581,20 @@
     vn_decode_int32_t(dec, (int32_t *)val);
 }
 
+/* enum VkInstanceCreateFlagBits */
+
+static inline void
+vn_encode_VkInstanceCreateFlagBits(struct vn_cs_encoder *enc, const VkInstanceCreateFlagBits *val)
+{
+    vn_encode_int32_t(enc, (const int32_t *)val);
+}
+
+static inline void
+vn_decode_VkInstanceCreateFlagBits(struct vn_cs_decoder *dec, VkInstanceCreateFlagBits *val)
+{
+    vn_decode_int32_t(dec, (int32_t *)val);
+}
+
 /* enum VkDeviceQueueCreateFlagBits */
 
 static inline void
diff --git a/src/venus/venus-protocol/vn_protocol_renderer_util.h b/src/venus/venus-protocol/vn_protocol_renderer_util.h
index dea29c3..0f243be 100644
--- a/src/venus/venus-protocol/vn_protocol_renderer_util.h
+++ b/src/venus/venus-protocol/vn_protocol_renderer_util.h
@@ -62,6 +62,8 @@
    PFN_vkCmdDrawIndirect CmdDrawIndirect;
    PFN_vkCmdDrawIndirectByteCountEXT CmdDrawIndirectByteCountEXT;
    PFN_vkCmdDrawIndirectCount CmdDrawIndirectCount;
+   PFN_vkCmdDrawMultiEXT CmdDrawMultiEXT;
+   PFN_vkCmdDrawMultiIndexedEXT CmdDrawMultiIndexedEXT;
    PFN_vkCmdEndConditionalRenderingEXT CmdEndConditionalRenderingEXT;
    PFN_vkCmdEndQuery CmdEndQuery;
    PFN_vkCmdEndQueryIndexedEXT CmdEndQueryIndexedEXT;
@@ -76,6 +78,8 @@
    PFN_vkCmdPipelineBarrier CmdPipelineBarrier;
    PFN_vkCmdPipelineBarrier2 CmdPipelineBarrier2;
    PFN_vkCmdPushConstants CmdPushConstants;
+   PFN_vkCmdPushDescriptorSetKHR CmdPushDescriptorSetKHR;
+   PFN_vkCmdPushDescriptorSetWithTemplateKHR CmdPushDescriptorSetWithTemplateKHR;
    PFN_vkCmdResetEvent CmdResetEvent;
    PFN_vkCmdResetEvent2 CmdResetEvent2;
    PFN_vkCmdResetQueryPool CmdResetQueryPool;
@@ -197,7 +201,9 @@
    PFN_vkGetQueryPoolResults GetQueryPoolResults;
    PFN_vkGetRenderAreaGranularity GetRenderAreaGranularity;
    PFN_vkGetSemaphoreCounterValue GetSemaphoreCounterValue;
+   PFN_vkGetSemaphoreFdKHR GetSemaphoreFdKHR;
    PFN_vkImportFenceFdKHR ImportFenceFdKHR;
+   PFN_vkImportSemaphoreFdKHR ImportSemaphoreFdKHR;
    PFN_vkInvalidateMappedMemoryRanges InvalidateMappedMemoryRanges;
    PFN_vkMapMemory MapMemory;
    PFN_vkMergePipelineCaches MergePipelineCaches;
@@ -336,6 +342,12 @@
       api_version >= VK_API_VERSION_1_2 ? VN_GDPA(dev, vkCmdDrawIndirectCount) :
       ext_table->KHR_draw_indirect_count ? VN_GDPA(dev, vkCmdDrawIndirectCountKHR) :
       NULL;
+   proc_table->CmdDrawMultiEXT =
+      ext_table->EXT_multi_draw ? VN_GDPA(dev, vkCmdDrawMultiEXT) :
+      NULL;
+   proc_table->CmdDrawMultiIndexedEXT =
+      ext_table->EXT_multi_draw ? VN_GDPA(dev, vkCmdDrawMultiIndexedEXT) :
+      NULL;
    proc_table->CmdEndConditionalRenderingEXT =
       ext_table->EXT_conditional_rendering ? VN_GDPA(dev, vkCmdEndConditionalRenderingEXT) :
       NULL;
@@ -368,6 +380,12 @@
       ext_table->KHR_synchronization2 ? VN_GDPA(dev, vkCmdPipelineBarrier2KHR) :
       NULL;
    proc_table->CmdPushConstants = VN_GDPA(dev, vkCmdPushConstants);
+   proc_table->CmdPushDescriptorSetKHR =
+      ext_table->KHR_push_descriptor ? VN_GDPA(dev, vkCmdPushDescriptorSetKHR) :
+      NULL;
+   proc_table->CmdPushDescriptorSetWithTemplateKHR =
+      ext_table->KHR_push_descriptor ? VN_GDPA(dev, vkCmdPushDescriptorSetWithTemplateKHR) :
+      NULL;
    proc_table->CmdResetEvent = VN_GDPA(dev, vkCmdResetEvent);
    proc_table->CmdResetEvent2 =
       api_version >= VK_API_VERSION_1_3 ? VN_GDPA(dev, vkCmdResetEvent2) :
@@ -627,9 +645,15 @@
       api_version >= VK_API_VERSION_1_2 ? VN_GDPA(dev, vkGetSemaphoreCounterValue) :
       ext_table->KHR_timeline_semaphore ? VN_GDPA(dev, vkGetSemaphoreCounterValueKHR) :
       NULL;
+   proc_table->GetSemaphoreFdKHR =
+      ext_table->KHR_external_semaphore_fd ? VN_GDPA(dev, vkGetSemaphoreFdKHR) :
+      NULL;
    proc_table->ImportFenceFdKHR =
       ext_table->KHR_external_fence_fd ? VN_GDPA(dev, vkImportFenceFdKHR) :
       NULL;
+   proc_table->ImportSemaphoreFdKHR =
+      ext_table->KHR_external_semaphore_fd ? VN_GDPA(dev, vkImportSemaphoreFdKHR) :
+      NULL;
    proc_table->InvalidateMappedMemoryRanges = VN_GDPA(dev, vkInvalidateMappedMemoryRanges);
    proc_table->MapMemory = VN_GDPA(dev, vkMapMemory);
    proc_table->MergePipelineCaches = VN_GDPA(dev, vkMergePipelineCaches);
diff --git a/src/venus/venus-protocol/vulkan.h b/src/venus/venus-protocol/vulkan.h
index 004fa70..3510ac9 100644
--- a/src/venus/venus-protocol/vulkan.h
+++ b/src/venus/venus-protocol/vulkan.h
@@ -38,7 +38,6 @@
 
 
 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
-#include <wayland-client.h>
 #include "vulkan_wayland.h"
 #endif
 
diff --git a/src/venus/venus-protocol/vulkan_core.h b/src/venus/venus-protocol/vulkan_core.h
index 228e4ef..6cc788e 100644
--- a/src/venus/venus-protocol/vulkan_core.h
+++ b/src/venus/venus-protocol/vulkan_core.h
@@ -72,7 +72,7 @@
 #define VK_API_VERSION_1_0 VK_MAKE_API_VERSION(0, 1, 0, 0)// Patch version should always be set to 0
 
 // Version of this file
-#define VK_HEADER_VERSION 204
+#define VK_HEADER_VERSION 228
 
 // Complete version of this file
 #define VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION(0, 1, 3, VK_HEADER_VERSION)
@@ -120,7 +120,6 @@
 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorPool)
 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer)
 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkCommandPool)
-#define VK_UUID_SIZE                      16U
 #define VK_ATTACHMENT_UNUSED              (~0U)
 #define VK_FALSE                          0U
 #define VK_LOD_CLAMP_NONE                 1000.0F
@@ -131,10 +130,11 @@
 #define VK_TRUE                           1U
 #define VK_WHOLE_SIZE                     (~0ULL)
 #define VK_MAX_MEMORY_TYPES               32U
-#define VK_MAX_MEMORY_HEAPS               16U
 #define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE  256U
+#define VK_UUID_SIZE                      16U
 #define VK_MAX_EXTENSION_NAME_SIZE        256U
 #define VK_MAX_DESCRIPTION_SIZE           256U
+#define VK_MAX_MEMORY_HEAPS               16U
 
 typedef enum VkResult {
     VK_SUCCESS = 0,
@@ -168,6 +168,24 @@
     VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001,
     VK_ERROR_VALIDATION_FAILED_EXT = -1000011001,
     VK_ERROR_INVALID_SHADER_NV = -1000012000,
+#ifdef VK_ENABLE_BETA_EXTENSIONS
+    VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR = -1000023000,
+#endif
+#ifdef VK_ENABLE_BETA_EXTENSIONS
+    VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR = -1000023001,
+#endif
+#ifdef VK_ENABLE_BETA_EXTENSIONS
+    VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR = -1000023002,
+#endif
+#ifdef VK_ENABLE_BETA_EXTENSIONS
+    VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR = -1000023003,
+#endif
+#ifdef VK_ENABLE_BETA_EXTENSIONS
+    VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR = -1000023004,
+#endif
+#ifdef VK_ENABLE_BETA_EXTENSIONS
+    VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR = -1000023005,
+#endif
     VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT = -1000158000,
     VK_ERROR_NOT_PERMITTED_KHR = -1000174001,
     VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT = -1000255000,
@@ -175,6 +193,7 @@
     VK_THREAD_DONE_KHR = 1000268001,
     VK_OPERATION_DEFERRED_KHR = 1000268002,
     VK_OPERATION_NOT_DEFERRED_KHR = 1000268003,
+    VK_ERROR_COMPRESSION_EXHAUSTED_EXT = -1000338000,
     VK_ERROR_OUT_OF_POOL_MEMORY_KHR = VK_ERROR_OUT_OF_POOL_MEMORY,
     VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR = VK_ERROR_INVALID_EXTERNAL_HANDLE,
     VK_ERROR_FRAGMENTATION_EXT = VK_ERROR_FRAGMENTATION,
@@ -425,19 +444,19 @@
     VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT = 1000022001,
     VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT = 1000022002,
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_PROFILE_KHR = 1000023000,
+    VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR = 1000023000,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
     VK_STRUCTURE_TYPE_VIDEO_CAPABILITIES_KHR = 1000023001,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_KHR = 1000023002,
+    VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR = 1000023002,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_GET_MEMORY_PROPERTIES_KHR = 1000023003,
+    VK_STRUCTURE_TYPE_VIDEO_SESSION_MEMORY_REQUIREMENTS_KHR = 1000023003,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_BIND_MEMORY_KHR = 1000023004,
+    VK_STRUCTURE_TYPE_BIND_VIDEO_SESSION_MEMORY_INFO_KHR = 1000023004,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
     VK_STRUCTURE_TYPE_VIDEO_SESSION_CREATE_INFO_KHR = 1000023005,
@@ -458,13 +477,13 @@
     VK_STRUCTURE_TYPE_VIDEO_CODING_CONTROL_INFO_KHR = 1000023010,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_KHR = 1000023011,
+    VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR = 1000023011,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_QUEUE_FAMILY_PROPERTIES_2_KHR = 1000023012,
+    VK_STRUCTURE_TYPE_QUEUE_FAMILY_VIDEO_PROPERTIES_KHR = 1000023012,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_PROFILES_KHR = 1000023013,
+    VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR = 1000023013,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_FORMAT_INFO_KHR = 1000023014,
@@ -473,11 +492,17 @@
     VK_STRUCTURE_TYPE_VIDEO_FORMAT_PROPERTIES_KHR = 1000023015,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_QUEUE_FAMILY_QUERY_RESULT_STATUS_PROPERTIES_2_KHR = 1000023016,
+    VK_STRUCTURE_TYPE_QUEUE_FAMILY_QUERY_RESULT_STATUS_PROPERTIES_KHR = 1000023016,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
     VK_STRUCTURE_TYPE_VIDEO_DECODE_INFO_KHR = 1000024000,
 #endif
+#ifdef VK_ENABLE_BETA_EXTENSIONS
+    VK_STRUCTURE_TYPE_VIDEO_DECODE_CAPABILITIES_KHR = 1000024001,
+#endif
+#ifdef VK_ENABLE_BETA_EXTENSIONS
+    VK_STRUCTURE_TYPE_VIDEO_DECODE_USAGE_INFO_KHR = 1000024002,
+#endif
     VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000,
     VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001,
     VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002,
@@ -493,94 +518,88 @@
     VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_CAPABILITIES_EXT = 1000038000,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_CREATE_INFO_EXT = 1000038001,
+    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000038001,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000038002,
+    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT = 1000038002,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT = 1000038003,
+    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_VCL_FRAME_INFO_EXT = 1000038003,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_VCL_FRAME_INFO_EXT = 1000038004,
+    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_DPB_SLOT_INFO_EXT = 1000038004,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_DPB_SLOT_INFO_EXT = 1000038005,
+    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_NALU_SLICE_INFO_EXT = 1000038005,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_NALU_SLICE_EXT = 1000038006,
+    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_EMIT_PICTURE_PARAMETERS_INFO_EXT = 1000038006,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_EMIT_PICTURE_PARAMETERS_EXT = 1000038007,
+    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PROFILE_INFO_EXT = 1000038007,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PROFILE_EXT = 1000038008,
+    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_RATE_CONTROL_INFO_EXT = 1000038008,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_RATE_CONTROL_INFO_EXT = 1000038009,
+    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_RATE_CONTROL_LAYER_INFO_EXT = 1000038009,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_RATE_CONTROL_LAYER_INFO_EXT = 1000038010,
+    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_REFERENCE_LISTS_INFO_EXT = 1000038010,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
     VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_CAPABILITIES_EXT = 1000039000,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_CREATE_INFO_EXT = 1000039001,
+    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000039001,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000039002,
+    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_ADD_INFO_EXT = 1000039002,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_ADD_INFO_EXT = 1000039003,
+    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_VCL_FRAME_INFO_EXT = 1000039003,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_VCL_FRAME_INFO_EXT = 1000039004,
+    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_DPB_SLOT_INFO_EXT = 1000039004,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_DPB_SLOT_INFO_EXT = 1000039005,
+    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_NALU_SLICE_SEGMENT_INFO_EXT = 1000039005,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_NALU_SLICE_EXT = 1000039006,
+    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_EMIT_PICTURE_PARAMETERS_INFO_EXT = 1000039006,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_EMIT_PICTURE_PARAMETERS_EXT = 1000039007,
+    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_PROFILE_INFO_EXT = 1000039007,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_PROFILE_EXT = 1000039008,
+    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_REFERENCE_LISTS_INFO_EXT = 1000039008,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_REFERENCE_LISTS_EXT = 1000039009,
+    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_RATE_CONTROL_INFO_EXT = 1000039009,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_RATE_CONTROL_INFO_EXT = 1000039010,
-#endif
-#ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_RATE_CONTROL_LAYER_INFO_EXT = 1000039011,
+    VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_RATE_CONTROL_LAYER_INFO_EXT = 1000039010,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
     VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_CAPABILITIES_EXT = 1000040000,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_CREATE_INFO_EXT = 1000040001,
+    VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PICTURE_INFO_EXT = 1000040001,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PICTURE_INFO_EXT = 1000040002,
+    VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_MVC_INFO_EXT = 1000040002,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_MVC_EXT = 1000040003,
+    VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PROFILE_INFO_EXT = 1000040003,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PROFILE_EXT = 1000040004,
+    VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000040004,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000040005,
+    VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT = 1000040005,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT = 1000040006,
-#endif
-#ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_DPB_SLOT_INFO_EXT = 1000040007,
+    VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_DPB_SLOT_INFO_EXT = 1000040006,
 #endif
     VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000,
     VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR = 1000044006,
@@ -598,6 +617,9 @@
     VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000,
     VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT = 1000067000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT = 1000067001,
+    VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT = 1000068000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES_EXT = 1000068001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES_EXT = 1000068002,
     VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073000,
     VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073001,
     VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR = 1000073002,
@@ -745,22 +767,19 @@
     VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_CAPABILITIES_EXT = 1000187000,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_CREATE_INFO_EXT = 1000187001,
+    VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000187001,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_EXT = 1000187002,
+    VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_EXT = 1000187002,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_EXT = 1000187003,
+    VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PROFILE_INFO_EXT = 1000187003,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PROFILE_EXT = 1000187004,
+    VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PICTURE_INFO_EXT = 1000187004,
 #endif
 #ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PICTURE_INFO_EXT = 1000187005,
-#endif
-#ifdef VK_ENABLE_BETA_EXTENSIONS
-    VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_DPB_SLOT_INFO_EXT = 1000187006,
+    VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_DPB_SLOT_INFO_EXT = 1000187005,
 #endif
     VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR = 1000174000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR = 1000388000,
@@ -773,7 +792,6 @@
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_FEATURES_NV = 1000201000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV = 1000202000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV = 1000202001,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_NV = 1000203000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV = 1000204000,
     VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_EXCLUSIVE_SCISSOR_STATE_CREATE_INFO_NV = 1000205000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV = 1000205002,
@@ -872,10 +890,34 @@
 #ifdef VK_ENABLE_BETA_EXTENSIONS
     VK_STRUCTURE_TYPE_VIDEO_ENCODE_RATE_CONTROL_LAYER_INFO_KHR = 1000299002,
 #endif
+#ifdef VK_ENABLE_BETA_EXTENSIONS
+    VK_STRUCTURE_TYPE_VIDEO_ENCODE_CAPABILITIES_KHR = 1000299003,
+#endif
+#ifdef VK_ENABLE_BETA_EXTENSIONS
+    VK_STRUCTURE_TYPE_VIDEO_ENCODE_USAGE_INFO_KHR = 1000299004,
+#endif
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV = 1000300000,
     VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV = 1000300001,
+    VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECT_CREATE_INFO_EXT = 1000311000,
+    VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECTS_INFO_EXT = 1000311001,
+    VK_STRUCTURE_TYPE_EXPORT_METAL_DEVICE_INFO_EXT = 1000311002,
+    VK_STRUCTURE_TYPE_EXPORT_METAL_COMMAND_QUEUE_INFO_EXT = 1000311003,
+    VK_STRUCTURE_TYPE_EXPORT_METAL_BUFFER_INFO_EXT = 1000311004,
+    VK_STRUCTURE_TYPE_IMPORT_METAL_BUFFER_INFO_EXT = 1000311005,
+    VK_STRUCTURE_TYPE_EXPORT_METAL_TEXTURE_INFO_EXT = 1000311006,
+    VK_STRUCTURE_TYPE_IMPORT_METAL_TEXTURE_INFO_EXT = 1000311007,
+    VK_STRUCTURE_TYPE_EXPORT_METAL_IO_SURFACE_INFO_EXT = 1000311008,
+    VK_STRUCTURE_TYPE_IMPORT_METAL_IO_SURFACE_INFO_EXT = 1000311009,
+    VK_STRUCTURE_TYPE_EXPORT_METAL_SHARED_EVENT_INFO_EXT = 1000311010,
+    VK_STRUCTURE_TYPE_IMPORT_METAL_SHARED_EVENT_INFO_EXT = 1000311011,
     VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_2_NV = 1000314008,
     VK_STRUCTURE_TYPE_CHECKPOINT_DATA_2_NV = 1000314009,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT = 1000320000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT = 1000320001,
+    VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT = 1000320002,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_FEATURES_AMD = 1000321000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR = 1000203000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_PROPERTIES_KHR = 1000322000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR = 1000323000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV = 1000326000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV = 1000326001,
@@ -883,17 +925,22 @@
     VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_MOTION_TRIANGLES_DATA_NV = 1000327000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV = 1000327001,
     VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MOTION_INFO_NV = 1000327002,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT = 1000328000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT = 1000328001,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT = 1000330000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_FEATURES_EXT = 1000332000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT = 1000332001,
     VK_STRUCTURE_TYPE_COPY_COMMAND_TRANSFORM_INFO_QCOM = 1000333000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR = 1000336000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT = 1000338000,
+    VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT = 1000338001,
+    VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2_EXT = 1000338002,
+    VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2_EXT = 1000338003,
+    VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT = 1000338004,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT = 1000339000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT = 1000340000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_ARM = 1000342000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT = 1000344000,
     VK_STRUCTURE_TYPE_DIRECTFB_SURFACE_CREATE_INFO_EXT = 1000346000,
-    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_VALVE = 1000351000,
-    VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_VALVE = 1000351002,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT = 1000352000,
     VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT = 1000352001,
     VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT = 1000352002,
@@ -922,21 +969,54 @@
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INVOCATION_MASK_FEATURES_HUAWEI = 1000370000,
     VK_STRUCTURE_TYPE_MEMORY_GET_REMOTE_ADDRESS_INFO_NV = 1000371000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_RDMA_FEATURES_NV = 1000371001,
+    VK_STRUCTURE_TYPE_PIPELINE_PROPERTIES_IDENTIFIER_EXT = 1000372000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROPERTIES_FEATURES_EXT = 1000372001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_FEATURES_EXT = 1000376000,
+    VK_STRUCTURE_TYPE_SUBPASS_RESOLVE_PERFORMANCE_QUERY_EXT = 1000376001,
+    VK_STRUCTURE_TYPE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_INFO_EXT = 1000376002,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT = 1000377000,
     VK_STRUCTURE_TYPE_SCREEN_SURFACE_CREATE_INFO_QNX = 1000378000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COLOR_WRITE_ENABLE_FEATURES_EXT = 1000381000,
     VK_STRUCTURE_TYPE_PIPELINE_COLOR_WRITE_CREATE_INFO_EXT = 1000381001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT = 1000382000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MAINTENANCE_1_FEATURES_KHR = 1000386000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT = 1000391000,
     VK_STRUCTURE_TYPE_IMAGE_VIEW_MIN_LOD_CREATE_INFO_EXT = 1000391001,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT = 1000392000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT = 1000392001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT = 1000393000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT = 1000411000,
     VK_STRUCTURE_TYPE_SAMPLER_BORDER_COLOR_COMPONENT_MAPPING_CREATE_INFO_EXT = 1000411001,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT = 1000412000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_SET_HOST_MAPPING_FEATURES_VALVE = 1000420000,
+    VK_STRUCTURE_TYPE_DESCRIPTOR_SET_BINDING_REFERENCE_VALVE = 1000420001,
+    VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_HOST_MAPPING_INFO_VALVE = 1000420002,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_EXT = 1000421000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NON_SEAMLESS_CUBE_MAP_FEATURES_EXT = 1000422000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_QCOM = 1000425000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_QCOM = 1000425001,
     VK_STRUCTURE_TYPE_SUBPASS_FRAGMENT_DENSITY_MAP_OFFSET_END_INFO_QCOM = 1000425002,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINEAR_COLOR_ATTACHMENT_FEATURES_NV = 1000430000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT = 1000437000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_FEATURES_QCOM = 1000440000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_PROPERTIES_QCOM = 1000440001,
+    VK_STRUCTURE_TYPE_IMAGE_VIEW_SAMPLE_WEIGHT_CREATE_INFO_QCOM = 1000440002,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_MERGE_FEEDBACK_FEATURES_EXT = 1000458000,
+    VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_CONTROL_EXT = 1000458001,
+    VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_FEEDBACK_CREATE_INFO_EXT = 1000458002,
+    VK_STRUCTURE_TYPE_RENDER_PASS_SUBPASS_FEEDBACK_CREATE_INFO_EXT = 1000458003,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_FEATURES_EXT = 1000462000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_PROPERTIES_EXT = 1000462001,
+    VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_MODULE_IDENTIFIER_CREATE_INFO_EXT = 1000462002,
+    VK_STRUCTURE_TYPE_SHADER_MODULE_IDENTIFIER_EXT = 1000462003,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT = 1000342000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_DITHERING_FEATURES_EXT = 1000465000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_PROPERTIES_FEATURES_QCOM = 1000484000,
+    VK_STRUCTURE_TYPE_TILE_PROPERTIES_QCOM = 1000484001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_AMIGO_PROFILING_FEATURES_SEC = 1000485000,
+    VK_STRUCTURE_TYPE_AMIGO_PROFILING_SUBMIT_INFO_SEC = 1000485001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT = 1000351000,
+    VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT = 1000351002,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES,
     VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT,
@@ -1042,6 +1122,7 @@
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES,
     VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_NV = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES,
     VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
@@ -1098,7 +1179,11 @@
     VK_STRUCTURE_TYPE_IMAGE_BLIT_2_KHR = VK_STRUCTURE_TYPE_IMAGE_BLIT_2,
     VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2_KHR = VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2,
     VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2_KHR = VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_ARM = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_VALVE = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT,
+    VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_VALVE = VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT,
     VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3_KHR = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3,
+    VK_STRUCTURE_TYPE_PIPELINE_INFO_EXT = VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_EXT = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR,
     VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT = VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES,
@@ -1108,6 +1193,11 @@
     VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF
 } VkStructureType;
 
+typedef enum VkPipelineCacheHeaderVersion {
+    VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1,
+    VK_PIPELINE_CACHE_HEADER_VERSION_MAX_ENUM = 0x7FFFFFFF
+} VkPipelineCacheHeaderVersion;
+
 typedef enum VkImageLayout {
     VK_IMAGE_LAYOUT_UNDEFINED = 0,
     VK_IMAGE_LAYOUT_GENERAL = 1,
@@ -1148,6 +1238,7 @@
 #ifdef VK_ENABLE_BETA_EXTENSIONS
     VK_IMAGE_LAYOUT_VIDEO_ENCODE_DPB_KHR = 1000299002,
 #endif
+    VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT = 1000339000,
     VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
     VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
     VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR,
@@ -1217,11 +1308,6 @@
     VK_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF
 } VkObjectType;
 
-typedef enum VkPipelineCacheHeaderVersion {
-    VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1,
-    VK_PIPELINE_CACHE_HEADER_VERSION_MAX_ENUM = 0x7FFFFFFF
-} VkPipelineCacheHeaderVersion;
-
 typedef enum VkVendorId {
     VK_VENDOR_ID_VIV = 0x10001,
     VK_VENDOR_ID_VSI = 0x10002,
@@ -1590,6 +1676,10 @@
 #ifdef VK_ENABLE_BETA_EXTENSIONS
     VK_QUERY_TYPE_VIDEO_ENCODE_BITSTREAM_BUFFER_RANGE_KHR = 1000299000,
 #endif
+    VK_QUERY_TYPE_MESH_PRIMITIVES_GENERATED_EXT = 1000328000,
+    VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT = 1000382000,
+    VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_BOTTOM_LEVEL_POINTERS_KHR = 1000386000,
+    VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SIZE_KHR = 1000386001,
     VK_QUERY_TYPE_MAX_ENUM = 0x7FFFFFFF
 } VkQueryType;
 
@@ -1849,8 +1939,8 @@
 typedef enum VkFilter {
     VK_FILTER_NEAREST = 0,
     VK_FILTER_LINEAR = 1,
-    VK_FILTER_CUBIC_IMG = 1000015000,
-    VK_FILTER_CUBIC_EXT = VK_FILTER_CUBIC_IMG,
+    VK_FILTER_CUBIC_EXT = 1000015000,
+    VK_FILTER_CUBIC_IMG = VK_FILTER_CUBIC_EXT,
     VK_FILTER_MAX_ENUM = 0x7FFFFFFF
 } VkFilter;
 
@@ -1885,8 +1975,11 @@
     VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK = 1000138000,
     VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR = 1000150000,
     VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000,
-    VK_DESCRIPTOR_TYPE_MUTABLE_VALVE = 1000351000,
+    VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM = 1000440000,
+    VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM = 1000440001,
+    VK_DESCRIPTOR_TYPE_MUTABLE_EXT = 1000351000,
     VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK,
+    VK_DESCRIPTOR_TYPE_MUTABLE_VALVE = VK_DESCRIPTOR_TYPE_MUTABLE_EXT,
     VK_DESCRIPTOR_TYPE_MAX_ENUM = 0x7FFFFFFF
 } VkDescriptorType;
 
@@ -1984,14 +2077,15 @@
     VK_IMAGE_ASPECT_PLANE_0_BIT = 0x00000010,
     VK_IMAGE_ASPECT_PLANE_1_BIT = 0x00000020,
     VK_IMAGE_ASPECT_PLANE_2_BIT = 0x00000040,
+    VK_IMAGE_ASPECT_NONE = 0,
     VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT = 0x00000080,
     VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT = 0x00000100,
     VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT = 0x00000200,
     VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT = 0x00000400,
-    VK_IMAGE_ASPECT_NONE_KHR = 0,
     VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = VK_IMAGE_ASPECT_PLANE_0_BIT,
     VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = VK_IMAGE_ASPECT_PLANE_1_BIT,
     VK_IMAGE_ASPECT_PLANE_2_BIT_KHR = VK_IMAGE_ASPECT_PLANE_2_BIT,
+    VK_IMAGE_ASPECT_NONE_KHR = VK_IMAGE_ASPECT_NONE,
     VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
 } VkImageAspectFlagBits;
 typedef VkFlags VkImageAspectFlags;
@@ -2020,7 +2114,6 @@
     VK_FORMAT_FEATURE_DISJOINT_BIT = 0x00400000,
     VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT = 0x00800000,
     VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT = 0x00010000,
-    VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000,
 #ifdef VK_ENABLE_BETA_EXTENSIONS
     VK_FORMAT_FEATURE_VIDEO_DECODE_OUTPUT_BIT_KHR = 0x02000000,
 #endif
@@ -2028,6 +2121,7 @@
     VK_FORMAT_FEATURE_VIDEO_DECODE_DPB_BIT_KHR = 0x04000000,
 #endif
     VK_FORMAT_FEATURE_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR = 0x20000000,
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT = 0x00002000,
     VK_FORMAT_FEATURE_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x01000000,
     VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x40000000,
 #ifdef VK_ENABLE_BETA_EXTENSIONS
@@ -2036,6 +2130,7 @@
 #ifdef VK_ENABLE_BETA_EXTENSIONS
     VK_FORMAT_FEATURE_VIDEO_ENCODE_DPB_BIT_KHR = 0x10000000,
 #endif
+    VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT,
     VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT,
     VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = VK_FORMAT_FEATURE_TRANSFER_DST_BIT,
     VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT_EXT = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT,
@@ -2046,7 +2141,6 @@
     VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT,
     VK_FORMAT_FEATURE_DISJOINT_BIT_KHR = VK_FORMAT_FEATURE_DISJOINT_BIT,
     VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR = VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT,
-    VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT = VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG,
     VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
 } VkFormatFeatureFlagBits;
 typedef VkFlags VkFormatFeatureFlags;
@@ -2067,6 +2161,8 @@
     VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV = 0x00002000,
     VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT = 0x00001000,
     VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT = 0x00004000,
+    VK_IMAGE_CREATE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_BIT_EXT = 0x00040000,
+    VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT = 0x00020000,
     VK_IMAGE_CREATE_FRAGMENT_DENSITY_MAP_OFFSET_BIT_QCOM = 0x00008000,
     VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT,
     VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT,
@@ -2119,11 +2215,19 @@
 #ifdef VK_ENABLE_BETA_EXTENSIONS
     VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR = 0x00008000,
 #endif
+    VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 0x00080000,
     VK_IMAGE_USAGE_INVOCATION_MASK_BIT_HUAWEI = 0x00040000,
+    VK_IMAGE_USAGE_SAMPLE_WEIGHT_BIT_QCOM = 0x00100000,
+    VK_IMAGE_USAGE_SAMPLE_BLOCK_MATCH_BIT_QCOM = 0x00200000,
     VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV = VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
     VK_IMAGE_USAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
 } VkImageUsageFlagBits;
 typedef VkFlags VkImageUsageFlags;
+
+typedef enum VkInstanceCreateFlagBits {
+    VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR = 0x00000001,
+    VK_INSTANCE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkInstanceCreateFlagBits;
 typedef VkFlags VkInstanceCreateFlags;
 
 typedef enum VkMemoryHeapFlagBits {
@@ -2194,14 +2298,16 @@
     VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000,
     VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR = 0x02000000,
     VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR = 0x00200000,
-    VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV = 0x00080000,
-    VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV = 0x00100000,
     VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 0x00800000,
     VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = 0x00400000,
     VK_PIPELINE_STAGE_COMMAND_PREPROCESS_BIT_NV = 0x00020000,
+    VK_PIPELINE_STAGE_TASK_SHADER_BIT_EXT = 0x00080000,
+    VK_PIPELINE_STAGE_MESH_SHADER_BIT_EXT = 0x00100000,
     VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV = VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
     VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_NV = VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR,
     VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV = VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
+    VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV = VK_PIPELINE_STAGE_TASK_SHADER_BIT_EXT,
+    VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV = VK_PIPELINE_STAGE_MESH_SHADER_BIT_EXT,
     VK_PIPELINE_STAGE_NONE_KHR = VK_PIPELINE_STAGE_NONE,
     VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
 } VkPipelineStageFlagBits;
@@ -2248,6 +2354,8 @@
     VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT = 0x00000100,
     VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT = 0x00000200,
     VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 0x00000400,
+    VK_QUERY_PIPELINE_STATISTIC_TASK_SHADER_INVOCATIONS_BIT_EXT = 0x00000800,
+    VK_QUERY_PIPELINE_STATISTIC_MESH_SHADER_INVOCATIONS_BIT_EXT = 0x00001000,
     VK_QUERY_PIPELINE_STATISTIC_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
 } VkQueryPipelineStatisticFlagBits;
 typedef VkFlags VkQueryPipelineStatisticFlags;
@@ -2360,7 +2468,11 @@
     VK_PIPELINE_CREATE_CAPTURE_INTERNAL_REPRESENTATIONS_BIT_KHR = 0x00000080,
     VK_PIPELINE_CREATE_INDIRECT_BINDABLE_BIT_NV = 0x00040000,
     VK_PIPELINE_CREATE_LIBRARY_BIT_KHR = 0x00000800,
+    VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT = 0x00800000,
+    VK_PIPELINE_CREATE_LINK_TIME_OPTIMIZATION_BIT_EXT = 0x00000400,
     VK_PIPELINE_CREATE_RAY_TRACING_ALLOW_MOTION_BIT_NV = 0x00100000,
+    VK_PIPELINE_CREATE_COLOR_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 0x02000000,
+    VK_PIPELINE_CREATE_DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT = 0x04000000,
     VK_PIPELINE_CREATE_DISPATCH_BASE = VK_PIPELINE_CREATE_DISPATCH_BASE_BIT,
     VK_PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR = VK_PIPELINE_CREATE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
     VK_PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT = VK_PIPELINE_CREATE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT,
@@ -2396,8 +2508,8 @@
     VK_SHADER_STAGE_MISS_BIT_KHR = 0x00000800,
     VK_SHADER_STAGE_INTERSECTION_BIT_KHR = 0x00001000,
     VK_SHADER_STAGE_CALLABLE_BIT_KHR = 0x00002000,
-    VK_SHADER_STAGE_TASK_BIT_NV = 0x00000040,
-    VK_SHADER_STAGE_MESH_BIT_NV = 0x00000080,
+    VK_SHADER_STAGE_TASK_BIT_EXT = 0x00000040,
+    VK_SHADER_STAGE_MESH_BIT_EXT = 0x00000080,
     VK_SHADER_STAGE_SUBPASS_SHADING_BIT_HUAWEI = 0x00004000,
     VK_SHADER_STAGE_RAYGEN_BIT_NV = VK_SHADER_STAGE_RAYGEN_BIT_KHR,
     VK_SHADER_STAGE_ANY_HIT_BIT_NV = VK_SHADER_STAGE_ANY_HIT_BIT_KHR,
@@ -2405,6 +2517,8 @@
     VK_SHADER_STAGE_MISS_BIT_NV = VK_SHADER_STAGE_MISS_BIT_KHR,
     VK_SHADER_STAGE_INTERSECTION_BIT_NV = VK_SHADER_STAGE_INTERSECTION_BIT_KHR,
     VK_SHADER_STAGE_CALLABLE_BIT_NV = VK_SHADER_STAGE_CALLABLE_BIT_KHR,
+    VK_SHADER_STAGE_TASK_BIT_NV = VK_SHADER_STAGE_TASK_BIT_EXT,
+    VK_SHADER_STAGE_MESH_BIT_NV = VK_SHADER_STAGE_MESH_BIT_EXT,
     VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
 } VkShaderStageFlagBits;
 
@@ -2424,24 +2538,34 @@
 typedef VkFlags VkPipelineMultisampleStateCreateFlags;
 
 typedef enum VkPipelineDepthStencilStateCreateFlagBits {
-    VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM = 0x00000001,
-    VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_ARM = 0x00000002,
+    VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT = 0x00000001,
+    VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT = 0x00000002,
+    VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM = VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT,
+    VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_ARM = VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT,
     VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
 } VkPipelineDepthStencilStateCreateFlagBits;
 typedef VkFlags VkPipelineDepthStencilStateCreateFlags;
 
 typedef enum VkPipelineColorBlendStateCreateFlagBits {
-    VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_ARM = 0x00000001,
+    VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_EXT = 0x00000001,
+    VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_ARM = VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_EXT,
     VK_PIPELINE_COLOR_BLEND_STATE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
 } VkPipelineColorBlendStateCreateFlagBits;
 typedef VkFlags VkPipelineColorBlendStateCreateFlags;
 typedef VkFlags VkPipelineDynamicStateCreateFlags;
+
+typedef enum VkPipelineLayoutCreateFlagBits {
+    VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT = 0x00000002,
+    VK_PIPELINE_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkPipelineLayoutCreateFlagBits;
 typedef VkFlags VkPipelineLayoutCreateFlags;
 typedef VkFlags VkShaderStageFlags;
 
 typedef enum VkSamplerCreateFlagBits {
     VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT = 0x00000001,
     VK_SAMPLER_CREATE_SUBSAMPLED_COARSE_RECONSTRUCTION_BIT_EXT = 0x00000002,
+    VK_SAMPLER_CREATE_NON_SEAMLESS_CUBE_MAP_BIT_EXT = 0x00000004,
+    VK_SAMPLER_CREATE_IMAGE_PROCESSING_BIT_QCOM = 0x00000010,
     VK_SAMPLER_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
 } VkSamplerCreateFlagBits;
 typedef VkFlags VkSamplerCreateFlags;
@@ -2449,8 +2573,9 @@
 typedef enum VkDescriptorPoolCreateFlagBits {
     VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001,
     VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT = 0x00000002,
-    VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE = 0x00000004,
+    VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT = 0x00000004,
     VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT,
+    VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE = VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT,
     VK_DESCRIPTOR_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
 } VkDescriptorPoolCreateFlagBits;
 typedef VkFlags VkDescriptorPoolCreateFlags;
@@ -2459,8 +2584,9 @@
 typedef enum VkDescriptorSetLayoutCreateFlagBits {
     VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT = 0x00000002,
     VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR = 0x00000001,
-    VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE = 0x00000004,
+    VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_EXT = 0x00000004,
     VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT,
+    VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE = VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_EXT,
     VK_DESCRIPTOR_SET_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
 } VkDescriptorSetLayoutCreateFlagBits;
 typedef VkFlags VkDescriptorSetLayoutCreateFlags;
@@ -2475,6 +2601,7 @@
     VK_DEPENDENCY_BY_REGION_BIT = 0x00000001,
     VK_DEPENDENCY_DEVICE_GROUP_BIT = 0x00000004,
     VK_DEPENDENCY_VIEW_LOCAL_BIT = 0x00000002,
+    VK_DEPENDENCY_FEEDBACK_LOOP_BIT_EXT = 0x00000008,
     VK_DEPENDENCY_VIEW_LOCAL_BIT_KHR = VK_DEPENDENCY_VIEW_LOCAL_BIT,
     VK_DEPENDENCY_DEVICE_GROUP_BIT_KHR = VK_DEPENDENCY_DEVICE_GROUP_BIT,
     VK_DEPENDENCY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
@@ -2499,9 +2626,13 @@
     VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX = 0x00000002,
     VK_SUBPASS_DESCRIPTION_FRAGMENT_REGION_BIT_QCOM = 0x00000004,
     VK_SUBPASS_DESCRIPTION_SHADER_RESOLVE_BIT_QCOM = 0x00000008,
-    VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_ARM = 0x00000010,
-    VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM = 0x00000020,
-    VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_ARM = 0x00000040,
+    VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT = 0x00000010,
+    VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT = 0x00000020,
+    VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT = 0x00000040,
+    VK_SUBPASS_DESCRIPTION_ENABLE_LEGACY_DITHERING_BIT_EXT = 0x00000080,
+    VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_ARM = VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT,
+    VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM = VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT,
+    VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_ARM = VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT,
     VK_SUBPASS_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
 } VkSubpassDescriptionFlagBits;
 typedef VkFlags VkSubpassDescriptionFlags;
@@ -5504,6 +5635,7 @@
     VK_DRIVER_ID_MESA_PANVK = 20,
     VK_DRIVER_ID_SAMSUNG_PROPRIETARY = 21,
     VK_DRIVER_ID_MESA_VENUS = 22,
+    VK_DRIVER_ID_MESA_DOZEN = 23,
     VK_DRIVER_ID_AMD_PROPRIETARY_KHR = VK_DRIVER_ID_AMD_PROPRIETARY,
     VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR = VK_DRIVER_ID_AMD_OPEN_SOURCE,
     VK_DRIVER_ID_MESA_RADV_KHR = VK_DRIVER_ID_MESA_RADV,
@@ -6259,10 +6391,6 @@
     VK_TOOL_PURPOSE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
 } VkToolPurposeFlagBits;
 typedef VkFlags VkToolPurposeFlags;
-
-typedef enum VkPrivateDataSlotCreateFlagBits {
-    VK_PRIVATE_DATA_SLOT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
-} VkPrivateDataSlotCreateFlagBits;
 typedef VkFlags VkPrivateDataSlotCreateFlags;
 typedef VkFlags64 VkPipelineStageFlags2;
 
@@ -6338,8 +6466,11 @@
 static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 0x00800000ULL;
 static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_NV = 0x00080000ULL;
 static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_NV = 0x00100000ULL;
+static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_EXT = 0x00080000ULL;
+static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_EXT = 0x00100000ULL;
 static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_SUBPASS_SHADING_BIT_HUAWEI = 0x8000000000ULL;
 static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_INVOCATION_MASK_BIT_HUAWEI = 0x10000000000ULL;
+static const VkPipelineStageFlagBits2 VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_COPY_BIT_KHR = 0x10000000ULL;
 
 typedef VkFlags64 VkAccessFlags2;
 
@@ -6414,6 +6545,7 @@
 static const VkAccessFlagBits2 VK_ACCESS_2_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 0x01000000ULL;
 static const VkAccessFlagBits2 VK_ACCESS_2_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000ULL;
 static const VkAccessFlagBits2 VK_ACCESS_2_INVOCATION_MASK_READ_BIT_HUAWEI = 0x8000000000ULL;
+static const VkAccessFlagBits2 VK_ACCESS_2_SHADER_BINDING_TABLE_READ_BIT_KHR = 0x10000000000ULL;
 
 
 typedef enum VkSubmitFlagBits {
@@ -6427,6 +6559,7 @@
     VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT = 0x00000001,
     VK_RENDERING_SUSPENDING_BIT = 0x00000002,
     VK_RENDERING_RESUMING_BIT = 0x00000004,
+    VK_RENDERING_ENABLE_LEGACY_DITHERING_BIT_EXT = 0x00000008,
     VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR = VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT,
     VK_RENDERING_SUSPENDING_BIT_KHR = VK_RENDERING_SUSPENDING_BIT,
     VK_RENDERING_RESUMING_BIT_KHR = VK_RENDERING_RESUMING_BIT,
@@ -6507,6 +6640,10 @@
 static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_VIDEO_ENCODE_DPB_BIT_KHR = 0x10000000ULL;
 #endif
 static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_LINEAR_COLOR_ATTACHMENT_BIT_NV = 0x4000000000ULL;
+static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_WEIGHT_IMAGE_BIT_QCOM = 0x400000000ULL;
+static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_WEIGHT_SAMPLED_IMAGE_BIT_QCOM = 0x800000000ULL;
+static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLOCK_MATCHING_BIT_QCOM = 0x1000000000ULL;
+static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BOX_FILTER_SAMPLED_BIT_QCOM = 0x2000000000ULL;
 
 typedef struct VkPhysicalDeviceVulkan13Features {
     VkStructureType    sType;
@@ -9366,6 +9503,23 @@
 #endif
 
 
+#define VK_KHR_fragment_shader_barycentric 1
+#define VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_SPEC_VERSION 1
+#define VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME "VK_KHR_fragment_shader_barycentric"
+typedef struct VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           fragmentShaderBarycentric;
+} VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR;
+
+typedef struct VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           triStripVertexOrderIndependentOfProvokingVertex;
+} VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR;
+
+
+
 #define VK_KHR_shader_subgroup_uniform_control_flow 1
 #define VK_KHR_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_SPEC_VERSION 1
 #define VK_KHR_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_EXTENSION_NAME "VK_KHR_shader_subgroup_uniform_control_flow"
@@ -9458,7 +9612,7 @@
 
 
 #define VK_KHR_format_feature_flags2 1
-#define VK_KHR_FORMAT_FEATURE_FLAGS_2_SPEC_VERSION 1
+#define VK_KHR_FORMAT_FEATURE_FLAGS_2_SPEC_VERSION 2
 #define VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME "VK_KHR_format_feature_flags2"
 typedef VkFormatFeatureFlags2 VkFormatFeatureFlags2KHR;
 
@@ -9468,6 +9622,47 @@
 
 
 
+#define VK_KHR_ray_tracing_maintenance1 1
+#define VK_KHR_RAY_TRACING_MAINTENANCE_1_SPEC_VERSION 1
+#define VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME "VK_KHR_ray_tracing_maintenance1"
+typedef struct VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           rayTracingMaintenance1;
+    VkBool32           rayTracingPipelineTraceRaysIndirect2;
+} VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR;
+
+typedef struct VkTraceRaysIndirectCommand2KHR {
+    VkDeviceAddress    raygenShaderRecordAddress;
+    VkDeviceSize       raygenShaderRecordSize;
+    VkDeviceAddress    missShaderBindingTableAddress;
+    VkDeviceSize       missShaderBindingTableSize;
+    VkDeviceSize       missShaderBindingTableStride;
+    VkDeviceAddress    hitShaderBindingTableAddress;
+    VkDeviceSize       hitShaderBindingTableSize;
+    VkDeviceSize       hitShaderBindingTableStride;
+    VkDeviceAddress    callableShaderBindingTableAddress;
+    VkDeviceSize       callableShaderBindingTableSize;
+    VkDeviceSize       callableShaderBindingTableStride;
+    uint32_t           width;
+    uint32_t           height;
+    uint32_t           depth;
+} VkTraceRaysIndirectCommand2KHR;
+
+typedef void (VKAPI_PTR *PFN_vkCmdTraceRaysIndirect2KHR)(VkCommandBuffer commandBuffer, VkDeviceAddress indirectDeviceAddress);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkCmdTraceRaysIndirect2KHR(
+    VkCommandBuffer                             commandBuffer,
+    VkDeviceAddress                             indirectDeviceAddress);
+#endif
+
+
+#define VK_KHR_portability_enumeration 1
+#define VK_KHR_PORTABILITY_ENUMERATION_SPEC_VERSION 1
+#define VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME "VK_KHR_portability_enumeration"
+
+
 #define VK_KHR_maintenance4 1
 #define VK_KHR_MAINTENANCE_4_SPEC_VERSION 2
 #define VK_KHR_MAINTENANCE_4_EXTENSION_NAME "VK_KHR_maintenance4"
@@ -10153,6 +10348,51 @@
 
 
 
+#define VK_EXT_pipeline_robustness 1
+#define VK_EXT_PIPELINE_ROBUSTNESS_SPEC_VERSION 1
+#define VK_EXT_PIPELINE_ROBUSTNESS_EXTENSION_NAME "VK_EXT_pipeline_robustness"
+
+typedef enum VkPipelineRobustnessBufferBehaviorEXT {
+    VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DEVICE_DEFAULT_EXT = 0,
+    VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DISABLED_EXT = 1,
+    VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT = 2,
+    VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2_EXT = 3,
+    VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkPipelineRobustnessBufferBehaviorEXT;
+
+typedef enum VkPipelineRobustnessImageBehaviorEXT {
+    VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT_EXT = 0,
+    VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DISABLED_EXT = 1,
+    VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_EXT = 2,
+    VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_2_EXT = 3,
+    VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkPipelineRobustnessImageBehaviorEXT;
+typedef struct VkPhysicalDevicePipelineRobustnessFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           pipelineRobustness;
+} VkPhysicalDevicePipelineRobustnessFeaturesEXT;
+
+typedef struct VkPhysicalDevicePipelineRobustnessPropertiesEXT {
+    VkStructureType                          sType;
+    void*                                    pNext;
+    VkPipelineRobustnessBufferBehaviorEXT    defaultRobustnessStorageBuffers;
+    VkPipelineRobustnessBufferBehaviorEXT    defaultRobustnessUniformBuffers;
+    VkPipelineRobustnessBufferBehaviorEXT    defaultRobustnessVertexInputs;
+    VkPipelineRobustnessImageBehaviorEXT     defaultRobustnessImages;
+} VkPhysicalDevicePipelineRobustnessPropertiesEXT;
+
+typedef struct VkPipelineRobustnessCreateInfoEXT {
+    VkStructureType                          sType;
+    const void*                              pNext;
+    VkPipelineRobustnessBufferBehaviorEXT    storageBuffers;
+    VkPipelineRobustnessBufferBehaviorEXT    uniformBuffers;
+    VkPipelineRobustnessBufferBehaviorEXT    vertexInputs;
+    VkPipelineRobustnessImageBehaviorEXT     images;
+} VkPipelineRobustnessCreateInfoEXT;
+
+
+
 #define VK_EXT_conditional_rendering 1
 #define VK_EXT_CONDITIONAL_RENDERING_SPEC_VERSION 2
 #define VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME "VK_EXT_conditional_rendering"
@@ -11883,11 +12123,7 @@
 #define VK_NV_fragment_shader_barycentric 1
 #define VK_NV_FRAGMENT_SHADER_BARYCENTRIC_SPEC_VERSION 1
 #define VK_NV_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME "VK_NV_fragment_shader_barycentric"
-typedef struct VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV {
-    VkStructureType    sType;
-    void*              pNext;
-    VkBool32           fragmentShaderBarycentric;
-} VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV;
+typedef VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV;
 
 
 
@@ -12779,6 +13015,7 @@
     VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NV = 5,
     VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NV = 6,
     VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_TASKS_NV = 7,
+    VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_NV = 1000328000,
     VK_INDIRECT_COMMANDS_TOKEN_TYPE_MAX_ENUM_NV = 0x7FFFFFFF
 } VkIndirectCommandsTokenTypeNV;
 
@@ -12988,7 +13225,7 @@
 
 
 #define VK_QCOM_render_pass_transform 1
-#define VK_QCOM_RENDER_PASS_TRANSFORM_SPEC_VERSION 2
+#define VK_QCOM_RENDER_PASS_TRANSFORM_SPEC_VERSION 3
 #define VK_QCOM_RENDER_PASS_TRANSFORM_EXTENSION_NAME "VK_QCOM_render_pass_transform"
 typedef struct VkRenderPassTransformBeginInfoQCOM {
     VkStructureType                  sType;
@@ -13127,8 +13364,6 @@
 #define VK_EXT_PRIVATE_DATA_EXTENSION_NAME "VK_EXT_private_data"
 typedef VkPrivateDataSlotCreateFlags VkPrivateDataSlotCreateFlagsEXT;
 
-typedef VkPrivateDataSlotCreateFlagBits VkPrivateDataSlotCreateFlagBitsEXT;
-
 typedef VkPhysicalDevicePrivateDataFeatures VkPhysicalDevicePrivateDataFeaturesEXT;
 
 typedef VkDevicePrivateDataCreateInfo VkDevicePrivateDataCreateInfoEXT;
@@ -13176,13 +13411,14 @@
 
 
 #define VK_NV_device_diagnostics_config 1
-#define VK_NV_DEVICE_DIAGNOSTICS_CONFIG_SPEC_VERSION 1
+#define VK_NV_DEVICE_DIAGNOSTICS_CONFIG_SPEC_VERSION 2
 #define VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME "VK_NV_device_diagnostics_config"
 
 typedef enum VkDeviceDiagnosticsConfigFlagBitsNV {
     VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV = 0x00000001,
     VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV = 0x00000002,
     VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV = 0x00000004,
+    VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_ERROR_REPORTING_BIT_NV = 0x00000008,
     VK_DEVICE_DIAGNOSTICS_CONFIG_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF
 } VkDeviceDiagnosticsConfigFlagBitsNV;
 typedef VkFlags VkDeviceDiagnosticsConfigFlagsNV;
@@ -13205,6 +13441,50 @@
 #define VK_QCOM_RENDER_PASS_STORE_OPS_EXTENSION_NAME "VK_QCOM_render_pass_store_ops"
 
 
+#define VK_EXT_graphics_pipeline_library 1
+#define VK_EXT_GRAPHICS_PIPELINE_LIBRARY_SPEC_VERSION 1
+#define VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME "VK_EXT_graphics_pipeline_library"
+
+typedef enum VkGraphicsPipelineLibraryFlagBitsEXT {
+    VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT = 0x00000001,
+    VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT = 0x00000002,
+    VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT = 0x00000004,
+    VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT = 0x00000008,
+    VK_GRAPHICS_PIPELINE_LIBRARY_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkGraphicsPipelineLibraryFlagBitsEXT;
+typedef VkFlags VkGraphicsPipelineLibraryFlagsEXT;
+typedef struct VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           graphicsPipelineLibrary;
+} VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT;
+
+typedef struct VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           graphicsPipelineLibraryFastLinking;
+    VkBool32           graphicsPipelineLibraryIndependentInterpolationDecoration;
+} VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT;
+
+typedef struct VkGraphicsPipelineLibraryCreateInfoEXT {
+    VkStructureType                      sType;
+    void*                                pNext;
+    VkGraphicsPipelineLibraryFlagsEXT    flags;
+} VkGraphicsPipelineLibraryCreateInfoEXT;
+
+
+
+#define VK_AMD_shader_early_and_late_fragment_tests 1
+#define VK_AMD_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_SPEC_VERSION 1
+#define VK_AMD_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_EXTENSION_NAME "VK_AMD_shader_early_and_late_fragment_tests"
+typedef struct VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           shaderEarlyAndLateFragmentTests;
+} VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD;
+
+
+
 #define VK_NV_fragment_shading_rate_enums 1
 #define VK_NV_FRAGMENT_SHADING_RATE_ENUMS_SPEC_VERSION 1
 #define VK_NV_FRAGMENT_SHADING_RATE_ENUMS_EXTENSION_NAME "VK_NV_fragment_shading_rate_enums"
@@ -13401,6 +13681,103 @@
 
 
 
+#define VK_EXT_image_compression_control 1
+#define VK_EXT_IMAGE_COMPRESSION_CONTROL_SPEC_VERSION 1
+#define VK_EXT_IMAGE_COMPRESSION_CONTROL_EXTENSION_NAME "VK_EXT_image_compression_control"
+
+typedef enum VkImageCompressionFlagBitsEXT {
+    VK_IMAGE_COMPRESSION_DEFAULT_EXT = 0,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_DEFAULT_EXT = 0x00000001,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT = 0x00000002,
+    VK_IMAGE_COMPRESSION_DISABLED_EXT = 0x00000004,
+    VK_IMAGE_COMPRESSION_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkImageCompressionFlagBitsEXT;
+typedef VkFlags VkImageCompressionFlagsEXT;
+
+typedef enum VkImageCompressionFixedRateFlagBitsEXT {
+    VK_IMAGE_COMPRESSION_FIXED_RATE_NONE_EXT = 0,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_1BPC_BIT_EXT = 0x00000001,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_2BPC_BIT_EXT = 0x00000002,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_3BPC_BIT_EXT = 0x00000004,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_4BPC_BIT_EXT = 0x00000008,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_5BPC_BIT_EXT = 0x00000010,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_6BPC_BIT_EXT = 0x00000020,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_7BPC_BIT_EXT = 0x00000040,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_8BPC_BIT_EXT = 0x00000080,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_9BPC_BIT_EXT = 0x00000100,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_10BPC_BIT_EXT = 0x00000200,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_11BPC_BIT_EXT = 0x00000400,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_12BPC_BIT_EXT = 0x00000800,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_13BPC_BIT_EXT = 0x00001000,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_14BPC_BIT_EXT = 0x00002000,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_15BPC_BIT_EXT = 0x00004000,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_16BPC_BIT_EXT = 0x00008000,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_17BPC_BIT_EXT = 0x00010000,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_18BPC_BIT_EXT = 0x00020000,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_19BPC_BIT_EXT = 0x00040000,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_20BPC_BIT_EXT = 0x00080000,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_21BPC_BIT_EXT = 0x00100000,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_22BPC_BIT_EXT = 0x00200000,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_23BPC_BIT_EXT = 0x00400000,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_24BPC_BIT_EXT = 0x00800000,
+    VK_IMAGE_COMPRESSION_FIXED_RATE_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkImageCompressionFixedRateFlagBitsEXT;
+typedef VkFlags VkImageCompressionFixedRateFlagsEXT;
+typedef struct VkPhysicalDeviceImageCompressionControlFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           imageCompressionControl;
+} VkPhysicalDeviceImageCompressionControlFeaturesEXT;
+
+typedef struct VkImageCompressionControlEXT {
+    VkStructureType                         sType;
+    const void*                             pNext;
+    VkImageCompressionFlagsEXT              flags;
+    uint32_t                                compressionControlPlaneCount;
+    VkImageCompressionFixedRateFlagsEXT*    pFixedRateFlags;
+} VkImageCompressionControlEXT;
+
+typedef struct VkSubresourceLayout2EXT {
+    VkStructureType        sType;
+    void*                  pNext;
+    VkSubresourceLayout    subresourceLayout;
+} VkSubresourceLayout2EXT;
+
+typedef struct VkImageSubresource2EXT {
+    VkStructureType       sType;
+    void*                 pNext;
+    VkImageSubresource    imageSubresource;
+} VkImageSubresource2EXT;
+
+typedef struct VkImageCompressionPropertiesEXT {
+    VkStructureType                        sType;
+    void*                                  pNext;
+    VkImageCompressionFlagsEXT             imageCompressionFlags;
+    VkImageCompressionFixedRateFlagsEXT    imageCompressionFixedRateFlags;
+} VkImageCompressionPropertiesEXT;
+
+typedef void (VKAPI_PTR *PFN_vkGetImageSubresourceLayout2EXT)(VkDevice device, VkImage image, const VkImageSubresource2EXT* pSubresource, VkSubresourceLayout2EXT* pLayout);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkGetImageSubresourceLayout2EXT(
+    VkDevice                                    device,
+    VkImage                                     image,
+    const VkImageSubresource2EXT*               pSubresource,
+    VkSubresourceLayout2EXT*                    pLayout);
+#endif
+
+
+#define VK_EXT_attachment_feedback_loop_layout 1
+#define VK_EXT_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_SPEC_VERSION 2
+#define VK_EXT_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_EXTENSION_NAME "VK_EXT_attachment_feedback_loop_layout"
+typedef struct VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           attachmentFeedbackLoopLayout;
+} VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT;
+
+
+
 #define VK_EXT_4444_formats 1
 #define VK_EXT_4444_FORMATS_SPEC_VERSION  1
 #define VK_EXT_4444_FORMATS_EXTENSION_NAME "VK_EXT_4444_formats"
@@ -13416,13 +13793,15 @@
 #define VK_ARM_rasterization_order_attachment_access 1
 #define VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_SPEC_VERSION 1
 #define VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME "VK_ARM_rasterization_order_attachment_access"
-typedef struct VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM {
+typedef struct VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT {
     VkStructureType    sType;
-    const void*        pNext;
+    void*              pNext;
     VkBool32           rasterizationOrderColorAttachmentAccess;
     VkBool32           rasterizationOrderDepthAttachmentAccess;
     VkBool32           rasterizationOrderStencilAttachmentAccess;
-} VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM;
+} VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT;
+
+typedef VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM;
 
 
 
@@ -13458,23 +13837,29 @@
 #define VK_VALVE_mutable_descriptor_type 1
 #define VK_VALVE_MUTABLE_DESCRIPTOR_TYPE_SPEC_VERSION 1
 #define VK_VALVE_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME "VK_VALVE_mutable_descriptor_type"
-typedef struct VkPhysicalDeviceMutableDescriptorTypeFeaturesVALVE {
+typedef struct VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT {
     VkStructureType    sType;
     void*              pNext;
     VkBool32           mutableDescriptorType;
-} VkPhysicalDeviceMutableDescriptorTypeFeaturesVALVE;
+} VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT;
 
-typedef struct VkMutableDescriptorTypeListVALVE {
+typedef VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT VkPhysicalDeviceMutableDescriptorTypeFeaturesVALVE;
+
+typedef struct VkMutableDescriptorTypeListEXT {
     uint32_t                   descriptorTypeCount;
     const VkDescriptorType*    pDescriptorTypes;
-} VkMutableDescriptorTypeListVALVE;
+} VkMutableDescriptorTypeListEXT;
 
-typedef struct VkMutableDescriptorTypeCreateInfoVALVE {
-    VkStructureType                            sType;
-    const void*                                pNext;
-    uint32_t                                   mutableDescriptorTypeListCount;
-    const VkMutableDescriptorTypeListVALVE*    pMutableDescriptorTypeLists;
-} VkMutableDescriptorTypeCreateInfoVALVE;
+typedef VkMutableDescriptorTypeListEXT VkMutableDescriptorTypeListVALVE;
+
+typedef struct VkMutableDescriptorTypeCreateInfoEXT {
+    VkStructureType                          sType;
+    const void*                              pNext;
+    uint32_t                                 mutableDescriptorTypeListCount;
+    const VkMutableDescriptorTypeListEXT*    pMutableDescriptorTypeLists;
+} VkMutableDescriptorTypeCreateInfoEXT;
+
+typedef VkMutableDescriptorTypeCreateInfoEXT VkMutableDescriptorTypeCreateInfoVALVE;
 
 
 
@@ -13644,6 +14029,57 @@
 #endif
 
 
+#define VK_EXT_pipeline_properties 1
+#define VK_EXT_PIPELINE_PROPERTIES_SPEC_VERSION 1
+#define VK_EXT_PIPELINE_PROPERTIES_EXTENSION_NAME "VK_EXT_pipeline_properties"
+typedef VkPipelineInfoKHR VkPipelineInfoEXT;
+
+typedef struct VkPipelinePropertiesIdentifierEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    uint8_t            pipelineIdentifier[VK_UUID_SIZE];
+} VkPipelinePropertiesIdentifierEXT;
+
+typedef struct VkPhysicalDevicePipelinePropertiesFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           pipelinePropertiesIdentifier;
+} VkPhysicalDevicePipelinePropertiesFeaturesEXT;
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetPipelinePropertiesEXT)(VkDevice device, const VkPipelineInfoEXT* pPipelineInfo, VkBaseOutStructure* pPipelineProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelinePropertiesEXT(
+    VkDevice                                    device,
+    const VkPipelineInfoEXT*                    pPipelineInfo,
+    VkBaseOutStructure*                         pPipelineProperties);
+#endif
+
+
+#define VK_EXT_multisampled_render_to_single_sampled 1
+#define VK_EXT_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_SPEC_VERSION 1
+#define VK_EXT_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_EXTENSION_NAME "VK_EXT_multisampled_render_to_single_sampled"
+typedef struct VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           multisampledRenderToSingleSampled;
+} VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT;
+
+typedef struct VkSubpassResolvePerformanceQueryEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           optimal;
+} VkSubpassResolvePerformanceQueryEXT;
+
+typedef struct VkMultisampledRenderToSingleSampledInfoEXT {
+    VkStructureType          sType;
+    const void*              pNext;
+    VkBool32                 multisampledRenderToSingleSampledEnable;
+    VkSampleCountFlagBits    rasterizationSamples;
+} VkMultisampledRenderToSingleSampledInfoEXT;
+
+
+
 #define VK_EXT_extended_dynamic_state2 1
 #define VK_EXT_EXTENDED_DYNAMIC_STATE_2_SPEC_VERSION 1
 #define VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME "VK_EXT_extended_dynamic_state2"
@@ -13710,6 +14146,19 @@
 #endif
 
 
+#define VK_EXT_primitives_generated_query 1
+#define VK_EXT_PRIMITIVES_GENERATED_QUERY_SPEC_VERSION 1
+#define VK_EXT_PRIMITIVES_GENERATED_QUERY_EXTENSION_NAME "VK_EXT_primitives_generated_query"
+typedef struct VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           primitivesGeneratedQuery;
+    VkBool32           primitivesGeneratedQueryWithRasterizerDiscard;
+    VkBool32           primitivesGeneratedQueryWithNonZeroStreams;
+} VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT;
+
+
+
 #define VK_EXT_global_priority_query 1
 #define VK_EXT_GLOBAL_PRIORITY_QUERY_SPEC_VERSION 1
 #define VK_EXT_GLOBAL_PRIORITY_QUERY_EXTENSION_NAME "VK_EXT_global_priority_query"
@@ -13786,6 +14235,18 @@
 #endif
 
 
+#define VK_EXT_image_2d_view_of_3d 1
+#define VK_EXT_IMAGE_2D_VIEW_OF_3D_SPEC_VERSION 1
+#define VK_EXT_IMAGE_2D_VIEW_OF_3D_EXTENSION_NAME "VK_EXT_image_2d_view_of_3d"
+typedef struct VkPhysicalDeviceImage2DViewOf3DFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           image2DViewOf3D;
+    VkBool32           sampler2DViewOf3D;
+} VkPhysicalDeviceImage2DViewOf3DFeaturesEXT;
+
+
+
 #define VK_EXT_load_store_op_none 1
 #define VK_EXT_LOAD_STORE_OP_NONE_SPEC_VERSION 1
 #define VK_EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME "VK_EXT_load_store_op_none"
@@ -13829,6 +14290,67 @@
 #endif
 
 
+#define VK_VALVE_descriptor_set_host_mapping 1
+#define VK_VALVE_DESCRIPTOR_SET_HOST_MAPPING_SPEC_VERSION 1
+#define VK_VALVE_DESCRIPTOR_SET_HOST_MAPPING_EXTENSION_NAME "VK_VALVE_descriptor_set_host_mapping"
+typedef struct VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           descriptorSetHostMapping;
+} VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE;
+
+typedef struct VkDescriptorSetBindingReferenceVALVE {
+    VkStructureType          sType;
+    const void*              pNext;
+    VkDescriptorSetLayout    descriptorSetLayout;
+    uint32_t                 binding;
+} VkDescriptorSetBindingReferenceVALVE;
+
+typedef struct VkDescriptorSetLayoutHostMappingInfoVALVE {
+    VkStructureType    sType;
+    void*              pNext;
+    size_t             descriptorOffset;
+    uint32_t           descriptorSize;
+} VkDescriptorSetLayoutHostMappingInfoVALVE;
+
+typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetLayoutHostMappingInfoVALVE)(VkDevice device, const VkDescriptorSetBindingReferenceVALVE* pBindingReference, VkDescriptorSetLayoutHostMappingInfoVALVE* pHostMapping);
+typedef void (VKAPI_PTR *PFN_vkGetDescriptorSetHostMappingVALVE)(VkDevice device, VkDescriptorSet descriptorSet, void** ppData);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetLayoutHostMappingInfoVALVE(
+    VkDevice                                    device,
+    const VkDescriptorSetBindingReferenceVALVE* pBindingReference,
+    VkDescriptorSetLayoutHostMappingInfoVALVE*  pHostMapping);
+
+VKAPI_ATTR void VKAPI_CALL vkGetDescriptorSetHostMappingVALVE(
+    VkDevice                                    device,
+    VkDescriptorSet                             descriptorSet,
+    void**                                      ppData);
+#endif
+
+
+#define VK_EXT_depth_clamp_zero_one 1
+#define VK_EXT_DEPTH_CLAMP_ZERO_ONE_SPEC_VERSION 1
+#define VK_EXT_DEPTH_CLAMP_ZERO_ONE_EXTENSION_NAME "VK_EXT_depth_clamp_zero_one"
+typedef struct VkPhysicalDeviceDepthClampZeroOneFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           depthClampZeroOne;
+} VkPhysicalDeviceDepthClampZeroOneFeaturesEXT;
+
+
+
+#define VK_EXT_non_seamless_cube_map 1
+#define VK_EXT_NON_SEAMLESS_CUBE_MAP_SPEC_VERSION 1
+#define VK_EXT_NON_SEAMLESS_CUBE_MAP_EXTENSION_NAME "VK_EXT_non_seamless_cube_map"
+typedef struct VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           nonSeamlessCubeMap;
+} VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT;
+
+
+
 #define VK_QCOM_fragment_density_map_offset 1
 #define VK_QCOM_FRAGMENT_DENSITY_MAP_OFFSET_SPEC_VERSION 1
 #define VK_QCOM_FRAGMENT_DENSITY_MAP_OFFSET_EXTENSION_NAME "VK_QCOM_fragment_density_map_offset"
@@ -13865,10 +14387,227 @@
 
 
 #define VK_GOOGLE_surfaceless_query 1
-#define VK_GOOGLE_SURFACELESS_QUERY_SPEC_VERSION 1
+#define VK_GOOGLE_SURFACELESS_QUERY_SPEC_VERSION 2
 #define VK_GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME "VK_GOOGLE_surfaceless_query"
 
 
+#define VK_EXT_image_compression_control_swapchain 1
+#define VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_SPEC_VERSION 1
+#define VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_EXTENSION_NAME "VK_EXT_image_compression_control_swapchain"
+typedef struct VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           imageCompressionControlSwapchain;
+} VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT;
+
+
+
+#define VK_QCOM_image_processing 1
+#define VK_QCOM_IMAGE_PROCESSING_SPEC_VERSION 1
+#define VK_QCOM_IMAGE_PROCESSING_EXTENSION_NAME "VK_QCOM_image_processing"
+typedef struct VkImageViewSampleWeightCreateInfoQCOM {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkOffset2D         filterCenter;
+    VkExtent2D         filterSize;
+    uint32_t           numPhases;
+} VkImageViewSampleWeightCreateInfoQCOM;
+
+typedef struct VkPhysicalDeviceImageProcessingFeaturesQCOM {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           textureSampleWeighted;
+    VkBool32           textureBoxFilter;
+    VkBool32           textureBlockMatch;
+} VkPhysicalDeviceImageProcessingFeaturesQCOM;
+
+typedef struct VkPhysicalDeviceImageProcessingPropertiesQCOM {
+    VkStructureType    sType;
+    void*              pNext;
+    uint32_t           maxWeightFilterPhases;
+    VkExtent2D         maxWeightFilterDimension;
+    VkExtent2D         maxBlockMatchRegion;
+    VkExtent2D         maxBoxFilterBlockSize;
+} VkPhysicalDeviceImageProcessingPropertiesQCOM;
+
+
+
+#define VK_EXT_subpass_merge_feedback 1
+#define VK_EXT_SUBPASS_MERGE_FEEDBACK_SPEC_VERSION 2
+#define VK_EXT_SUBPASS_MERGE_FEEDBACK_EXTENSION_NAME "VK_EXT_subpass_merge_feedback"
+
+typedef enum VkSubpassMergeStatusEXT {
+    VK_SUBPASS_MERGE_STATUS_MERGED_EXT = 0,
+    VK_SUBPASS_MERGE_STATUS_DISALLOWED_EXT = 1,
+    VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SIDE_EFFECTS_EXT = 2,
+    VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SAMPLES_MISMATCH_EXT = 3,
+    VK_SUBPASS_MERGE_STATUS_NOT_MERGED_VIEWS_MISMATCH_EXT = 4,
+    VK_SUBPASS_MERGE_STATUS_NOT_MERGED_ALIASING_EXT = 5,
+    VK_SUBPASS_MERGE_STATUS_NOT_MERGED_DEPENDENCIES_EXT = 6,
+    VK_SUBPASS_MERGE_STATUS_NOT_MERGED_INCOMPATIBLE_INPUT_ATTACHMENT_EXT = 7,
+    VK_SUBPASS_MERGE_STATUS_NOT_MERGED_TOO_MANY_ATTACHMENTS_EXT = 8,
+    VK_SUBPASS_MERGE_STATUS_NOT_MERGED_INSUFFICIENT_STORAGE_EXT = 9,
+    VK_SUBPASS_MERGE_STATUS_NOT_MERGED_DEPTH_STENCIL_COUNT_EXT = 10,
+    VK_SUBPASS_MERGE_STATUS_NOT_MERGED_RESOLVE_ATTACHMENT_REUSE_EXT = 11,
+    VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SINGLE_SUBPASS_EXT = 12,
+    VK_SUBPASS_MERGE_STATUS_NOT_MERGED_UNSPECIFIED_EXT = 13,
+    VK_SUBPASS_MERGE_STATUS_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkSubpassMergeStatusEXT;
+typedef struct VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           subpassMergeFeedback;
+} VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT;
+
+typedef struct VkRenderPassCreationControlEXT {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkBool32           disallowMerging;
+} VkRenderPassCreationControlEXT;
+
+typedef struct VkRenderPassCreationFeedbackInfoEXT {
+    uint32_t    postMergeSubpassCount;
+} VkRenderPassCreationFeedbackInfoEXT;
+
+typedef struct VkRenderPassCreationFeedbackCreateInfoEXT {
+    VkStructureType                         sType;
+    const void*                             pNext;
+    VkRenderPassCreationFeedbackInfoEXT*    pRenderPassFeedback;
+} VkRenderPassCreationFeedbackCreateInfoEXT;
+
+typedef struct VkRenderPassSubpassFeedbackInfoEXT {
+    VkSubpassMergeStatusEXT    subpassMergeStatus;
+    char                       description[VK_MAX_DESCRIPTION_SIZE];
+    uint32_t                   postMergeIndex;
+} VkRenderPassSubpassFeedbackInfoEXT;
+
+typedef struct VkRenderPassSubpassFeedbackCreateInfoEXT {
+    VkStructureType                        sType;
+    const void*                            pNext;
+    VkRenderPassSubpassFeedbackInfoEXT*    pSubpassFeedback;
+} VkRenderPassSubpassFeedbackCreateInfoEXT;
+
+
+
+#define VK_EXT_shader_module_identifier 1
+#define VK_MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT 32U
+#define VK_EXT_SHADER_MODULE_IDENTIFIER_SPEC_VERSION 1
+#define VK_EXT_SHADER_MODULE_IDENTIFIER_EXTENSION_NAME "VK_EXT_shader_module_identifier"
+typedef struct VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           shaderModuleIdentifier;
+} VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT;
+
+typedef struct VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    uint8_t            shaderModuleIdentifierAlgorithmUUID[VK_UUID_SIZE];
+} VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT;
+
+typedef struct VkPipelineShaderStageModuleIdentifierCreateInfoEXT {
+    VkStructureType    sType;
+    const void*        pNext;
+    uint32_t           identifierSize;
+    const uint8_t*     pIdentifier;
+} VkPipelineShaderStageModuleIdentifierCreateInfoEXT;
+
+typedef struct VkShaderModuleIdentifierEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    uint32_t           identifierSize;
+    uint8_t            identifier[VK_MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT];
+} VkShaderModuleIdentifierEXT;
+
+typedef void (VKAPI_PTR *PFN_vkGetShaderModuleIdentifierEXT)(VkDevice device, VkShaderModule shaderModule, VkShaderModuleIdentifierEXT* pIdentifier);
+typedef void (VKAPI_PTR *PFN_vkGetShaderModuleCreateInfoIdentifierEXT)(VkDevice device, const VkShaderModuleCreateInfo* pCreateInfo, VkShaderModuleIdentifierEXT* pIdentifier);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkGetShaderModuleIdentifierEXT(
+    VkDevice                                    device,
+    VkShaderModule                              shaderModule,
+    VkShaderModuleIdentifierEXT*                pIdentifier);
+
+VKAPI_ATTR void VKAPI_CALL vkGetShaderModuleCreateInfoIdentifierEXT(
+    VkDevice                                    device,
+    const VkShaderModuleCreateInfo*             pCreateInfo,
+    VkShaderModuleIdentifierEXT*                pIdentifier);
+#endif
+
+
+#define VK_EXT_rasterization_order_attachment_access 1
+#define VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_SPEC_VERSION 1
+#define VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME "VK_EXT_rasterization_order_attachment_access"
+
+
+#define VK_EXT_legacy_dithering 1
+#define VK_EXT_LEGACY_DITHERING_SPEC_VERSION 1
+#define VK_EXT_LEGACY_DITHERING_EXTENSION_NAME "VK_EXT_legacy_dithering"
+typedef struct VkPhysicalDeviceLegacyDitheringFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           legacyDithering;
+} VkPhysicalDeviceLegacyDitheringFeaturesEXT;
+
+
+
+#define VK_QCOM_tile_properties 1
+#define VK_QCOM_TILE_PROPERTIES_SPEC_VERSION 1
+#define VK_QCOM_TILE_PROPERTIES_EXTENSION_NAME "VK_QCOM_tile_properties"
+typedef struct VkPhysicalDeviceTilePropertiesFeaturesQCOM {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           tileProperties;
+} VkPhysicalDeviceTilePropertiesFeaturesQCOM;
+
+typedef struct VkTilePropertiesQCOM {
+    VkStructureType    sType;
+    void*              pNext;
+    VkExtent3D         tileSize;
+    VkExtent2D         apronSize;
+    VkOffset2D         origin;
+} VkTilePropertiesQCOM;
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetFramebufferTilePropertiesQCOM)(VkDevice device, VkFramebuffer framebuffer, uint32_t* pPropertiesCount, VkTilePropertiesQCOM* pProperties);
+typedef VkResult (VKAPI_PTR *PFN_vkGetDynamicRenderingTilePropertiesQCOM)(VkDevice device, const VkRenderingInfo* pRenderingInfo, VkTilePropertiesQCOM* pProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetFramebufferTilePropertiesQCOM(
+    VkDevice                                    device,
+    VkFramebuffer                               framebuffer,
+    uint32_t*                                   pPropertiesCount,
+    VkTilePropertiesQCOM*                       pProperties);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetDynamicRenderingTilePropertiesQCOM(
+    VkDevice                                    device,
+    const VkRenderingInfo*                      pRenderingInfo,
+    VkTilePropertiesQCOM*                       pProperties);
+#endif
+
+
+#define VK_SEC_amigo_profiling 1
+#define VK_SEC_AMIGO_PROFILING_SPEC_VERSION 1
+#define VK_SEC_AMIGO_PROFILING_EXTENSION_NAME "VK_SEC_amigo_profiling"
+typedef struct VkPhysicalDeviceAmigoProfilingFeaturesSEC {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           amigoProfiling;
+} VkPhysicalDeviceAmigoProfilingFeaturesSEC;
+
+typedef struct VkAmigoProfilingSubmitInfoSEC {
+    VkStructureType    sType;
+    const void*        pNext;
+    uint64_t           firstDrawTimestamp;
+    uint64_t           swapBufferTimestamp;
+} VkAmigoProfilingSubmitInfoSEC;
+
+
+
+#define VK_EXT_mutable_descriptor_type 1
+#define VK_EXT_MUTABLE_DESCRIPTOR_TYPE_SPEC_VERSION 1
+#define VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME "VK_EXT_mutable_descriptor_type"
+
+
 #define VK_KHR_acceleration_structure 1
 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkAccelerationStructureKHR)
 #define VK_KHR_ACCELERATION_STRUCTURE_SPEC_VERSION 13
@@ -14308,6 +15047,87 @@
 } VkPhysicalDeviceRayQueryFeaturesKHR;
 
 
+
+#define VK_EXT_mesh_shader 1
+#define VK_EXT_MESH_SHADER_SPEC_VERSION   1
+#define VK_EXT_MESH_SHADER_EXTENSION_NAME "VK_EXT_mesh_shader"
+typedef struct VkPhysicalDeviceMeshShaderFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           taskShader;
+    VkBool32           meshShader;
+    VkBool32           multiviewMeshShader;
+    VkBool32           primitiveFragmentShadingRateMeshShader;
+    VkBool32           meshShaderQueries;
+} VkPhysicalDeviceMeshShaderFeaturesEXT;
+
+typedef struct VkPhysicalDeviceMeshShaderPropertiesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    uint32_t           maxTaskWorkGroupTotalCount;
+    uint32_t           maxTaskWorkGroupCount[3];
+    uint32_t           maxTaskWorkGroupInvocations;
+    uint32_t           maxTaskWorkGroupSize[3];
+    uint32_t           maxTaskPayloadSize;
+    uint32_t           maxTaskSharedMemorySize;
+    uint32_t           maxTaskPayloadAndSharedMemorySize;
+    uint32_t           maxMeshWorkGroupTotalCount;
+    uint32_t           maxMeshWorkGroupCount[3];
+    uint32_t           maxMeshWorkGroupInvocations;
+    uint32_t           maxMeshWorkGroupSize[3];
+    uint32_t           maxMeshSharedMemorySize;
+    uint32_t           maxMeshPayloadAndSharedMemorySize;
+    uint32_t           maxMeshOutputMemorySize;
+    uint32_t           maxMeshPayloadAndOutputMemorySize;
+    uint32_t           maxMeshOutputComponents;
+    uint32_t           maxMeshOutputVertices;
+    uint32_t           maxMeshOutputPrimitives;
+    uint32_t           maxMeshOutputLayers;
+    uint32_t           maxMeshMultiviewViewCount;
+    uint32_t           meshOutputPerVertexGranularity;
+    uint32_t           meshOutputPerPrimitiveGranularity;
+    uint32_t           maxPreferredTaskWorkGroupInvocations;
+    uint32_t           maxPreferredMeshWorkGroupInvocations;
+    VkBool32           prefersLocalInvocationVertexOutput;
+    VkBool32           prefersLocalInvocationPrimitiveOutput;
+    VkBool32           prefersCompactVertexOutput;
+    VkBool32           prefersCompactPrimitiveOutput;
+} VkPhysicalDeviceMeshShaderPropertiesEXT;
+
+typedef struct VkDrawMeshTasksIndirectCommandEXT {
+    uint32_t    groupCountX;
+    uint32_t    groupCountY;
+    uint32_t    groupCountZ;
+} VkDrawMeshTasksIndirectCommandEXT;
+
+typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksEXT)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
+typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksIndirectEXT)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride);
+typedef void (VKAPI_PTR *PFN_vkCmdDrawMeshTasksIndirectCountEXT)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksEXT(
+    VkCommandBuffer                             commandBuffer,
+    uint32_t                                    groupCountX,
+    uint32_t                                    groupCountY,
+    uint32_t                                    groupCountZ);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksIndirectEXT(
+    VkCommandBuffer                             commandBuffer,
+    VkBuffer                                    buffer,
+    VkDeviceSize                                offset,
+    uint32_t                                    drawCount,
+    uint32_t                                    stride);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdDrawMeshTasksIndirectCountEXT(
+    VkCommandBuffer                             commandBuffer,
+    VkBuffer                                    buffer,
+    VkDeviceSize                                offset,
+    VkBuffer                                    countBuffer,
+    VkDeviceSize                                countBufferOffset,
+    uint32_t                                    maxDrawCount,
+    uint32_t                                    stride);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/venus/vkr_allocator.c b/src/venus/vkr_allocator.c
index 878c563..b0144ea 100644
--- a/src/venus/vkr_allocator.c
+++ b/src/venus/vkr_allocator.c
@@ -132,7 +132,7 @@
 }
 
 void
-vkr_allocator_fini()
+vkr_allocator_fini(void)
 {
    if (!vkr_allocator_initialized)
       return;
@@ -152,7 +152,7 @@
 }
 
 int
-vkr_allocator_init()
+vkr_allocator_init(void)
 {
    VkResult res;
 
diff --git a/src/venus/vkr_command_buffer.c b/src/venus/vkr_command_buffer.c
index 1019759..abb2bef 100644
--- a/src/venus/vkr_command_buffer.c
+++ b/src/venus/vkr_command_buffer.c
@@ -797,6 +797,67 @@
    VKR_CMD_CALL(CmdEndRendering, args);
 }
 
+static void
+vkr_dispatch_vkCmdPipelineBarrier2(UNUSED struct vn_dispatch_context *ctx,
+                                   struct vn_command_vkCmdPipelineBarrier2 *args)
+{
+   VKR_CMD_CALL(CmdPipelineBarrier2, args, args->pDependencyInfo);
+}
+
+static void
+vkr_dispatch_vkCmdResetEvent2(UNUSED struct vn_dispatch_context *ctx,
+                              struct vn_command_vkCmdResetEvent2 *args)
+{
+   VKR_CMD_CALL(CmdResetEvent2, args, args->event, args->stageMask);
+}
+
+static void
+vkr_dispatch_vkCmdSetEvent2(UNUSED struct vn_dispatch_context *ctx,
+                            struct vn_command_vkCmdSetEvent2 *args)
+{
+   VKR_CMD_CALL(CmdSetEvent2, args, args->event, args->pDependencyInfo);
+}
+
+static void
+vkr_dispatch_vkCmdWaitEvents2(UNUSED struct vn_dispatch_context *ctx,
+                              struct vn_command_vkCmdWaitEvents2 *args)
+{
+   VKR_CMD_CALL(CmdWaitEvents2, args, args->eventCount, args->pEvents,
+                args->pDependencyInfos);
+}
+
+static void
+vkr_dispatch_vkCmdWriteTimestamp2(UNUSED struct vn_dispatch_context *ctx,
+                                  struct vn_command_vkCmdWriteTimestamp2 *args)
+{
+   VKR_CMD_CALL(CmdWriteTimestamp2, args, args->stage, args->queryPool, args->query);
+}
+
+static void
+vkr_dispatch_vkCmdDrawMultiEXT(UNUSED struct vn_dispatch_context *dispatch,
+                               struct vn_command_vkCmdDrawMultiEXT *args)
+{
+   VKR_CMD_CALL(CmdDrawMultiEXT, args, args->drawCount, args->pVertexInfo,
+                args->instanceCount, args->firstInstance, args->stride);
+}
+
+static void
+vkr_dispatch_vkCmdDrawMultiIndexedEXT(UNUSED struct vn_dispatch_context *dispatch,
+                                      struct vn_command_vkCmdDrawMultiIndexedEXT *args)
+{
+   VKR_CMD_CALL(CmdDrawMultiIndexedEXT, args, args->drawCount, args->pIndexInfo,
+                args->instanceCount, args->firstInstance, args->stride,
+                args->pVertexOffset);
+}
+
+static void
+vkr_dispatch_vkCmdPushDescriptorSetKHR(UNUSED struct vn_dispatch_context *dispatch,
+                                       struct vn_command_vkCmdPushDescriptorSetKHR *args)
+{
+   VKR_CMD_CALL(CmdPushDescriptorSetKHR, args, args->pipelineBindPoint, args->layout,
+                args->set, args->descriptorWriteCount, args->pDescriptorWrites);
+}
+
 void
 vkr_context_init_command_pool_dispatch(struct vkr_context *ctx)
 {
@@ -911,6 +972,13 @@
    dispatch->dispatch_vkCmdBeginRendering = vkr_dispatch_vkCmdBeginRendering;
    dispatch->dispatch_vkCmdEndRendering = vkr_dispatch_vkCmdEndRendering;
 
+   /* VK_KHR_synchronization2 */
+   dispatch->dispatch_vkCmdPipelineBarrier2 = vkr_dispatch_vkCmdPipelineBarrier2;
+   dispatch->dispatch_vkCmdResetEvent2 = vkr_dispatch_vkCmdResetEvent2;
+   dispatch->dispatch_vkCmdSetEvent2 = vkr_dispatch_vkCmdSetEvent2;
+   dispatch->dispatch_vkCmdWaitEvents2 = vkr_dispatch_vkCmdWaitEvents2;
+   dispatch->dispatch_vkCmdWriteTimestamp2 = vkr_dispatch_vkCmdWriteTimestamp2;
+
    /* VK_EXT_extended_dynamic_state2 */
    dispatch->dispatch_vkCmdSetRasterizerDiscardEnable =
       vkr_dispatch_vkCmdSetRasterizerDiscardEnable;
@@ -926,4 +994,12 @@
       vkr_dispatch_vkCmdBeginConditionalRenderingEXT;
    dispatch->dispatch_vkCmdEndConditionalRenderingEXT =
       vkr_dispatch_vkCmdEndConditionalRenderingEXT;
+
+   /* VK_EXT_multi_draw */
+   dispatch->dispatch_vkCmdDrawMultiEXT = vkr_dispatch_vkCmdDrawMultiEXT;
+   dispatch->dispatch_vkCmdDrawMultiIndexedEXT = vkr_dispatch_vkCmdDrawMultiIndexedEXT;
+
+   /* VK_KHR_push_descriptor */
+   dispatch->dispatch_vkCmdPushDescriptorSetKHR = vkr_dispatch_vkCmdPushDescriptorSetKHR;
+   dispatch->dispatch_vkCmdPushDescriptorSetWithTemplateKHR = NULL;
 }
diff --git a/src/venus/vkr_common.c b/src/venus/vkr_common.c
index b2e8598..e3c3362 100644
--- a/src/venus/vkr_common.c
+++ b/src/venus/vkr_common.c
@@ -71,45 +71,56 @@
    .KHR_dynamic_rendering = true,
    .KHR_format_feature_flags2 = false,
    .KHR_maintenance4 = true,
-   .KHR_shader_integer_dot_product = false,
-   .KHR_shader_non_semantic_info = false,
-   .KHR_shader_terminate_invocation = false,
-   .KHR_synchronization2 = false,
-   .KHR_zero_initialize_workgroup_memory = false,
+   .KHR_shader_integer_dot_product = true,
+   .KHR_shader_non_semantic_info = true,
+   .KHR_shader_terminate_invocation = true,
+   .KHR_synchronization2 = true,
+   .KHR_zero_initialize_workgroup_memory = true,
    .EXT_4444_formats = true,
    .EXT_extended_dynamic_state = true,
    .EXT_extended_dynamic_state2 = true,
    .EXT_image_robustness = true,
    .EXT_inline_uniform_block = true,
-   .EXT_pipeline_creation_cache_control = false,
-   .EXT_pipeline_creation_feedback = false,
-   .EXT_private_data = false,
+   .EXT_pipeline_creation_cache_control = true,
+   .EXT_pipeline_creation_feedback = true,
+   /* TODO(VK_EXT_private_data): Support natively in the guest */
+   .EXT_private_data = true,
    .EXT_shader_demote_to_helper_invocation = true,
-   .EXT_subgroup_size_control = false,
-   .EXT_texel_buffer_alignment = false,
-   .EXT_texture_compression_astc_hdr = false,
-   .EXT_tooling_info = false,
-   .EXT_ycbcr_2plane_444_formats = false,
+   .EXT_subgroup_size_control = true,
+   .EXT_texel_buffer_alignment = true,
+   .EXT_texture_compression_astc_hdr = true,
+   .EXT_tooling_info = false, /* implementation in driver */
+   .EXT_ycbcr_2plane_444_formats = true,
    /* KHR extensions */
-   .KHR_external_fence_fd = false,
+   .KHR_external_fence_fd = true,
    .KHR_external_memory_fd = true,
+   .KHR_external_semaphore_fd = true,
+   .KHR_push_descriptor = true,
    /* EXT extensions */
    .EXT_calibrated_timestamps = true,
    .EXT_conservative_rasterization = true,
    .EXT_conditional_rendering = true,
    .EXT_custom_border_color = true,
+   .EXT_depth_clip_control = true,
    .EXT_depth_clip_enable = true,
    .EXT_external_memory_dma_buf = true,
    .EXT_image_drm_format_modifier = true,
    .EXT_image_view_min_lod = true,
    .EXT_index_type_uint8 = true,
    .EXT_line_rasterization = true,
+   .EXT_multi_draw = true,
+   .EXT_mutable_descriptor_type = true,
+   .EXT_pci_bus_info = true,
+   .EXT_primitive_topology_list_restart = true,
+   .EXT_primitives_generated_query = true,
    .EXT_provoking_vertex = true,
    .EXT_queue_family_foreign = true,
    .EXT_robustness2 = true,
    .EXT_shader_stencil_export = true,
    .EXT_transform_feedback = true,
    .EXT_vertex_attribute_divisor = true,
+   /* vendor extensions */
+   .VALVE_mutable_descriptor_type = true,
 };
 
 void
@@ -219,5 +230,5 @@
       arr->objects[i] = obj;
    }
 
-   return arr;
+   return true;
 }
diff --git a/src/venus/vkr_common.h b/src/venus/vkr_common.h
index e1c9ce5..df1ca32 100644
--- a/src/venus/vkr_common.h
+++ b/src/venus/vkr_common.h
@@ -35,7 +35,7 @@
 #include "vkr_renderer.h"
 
 /* cap instance and device api versions to this */
-#define VKR_MAX_API_VERSION VK_API_VERSION_1_2
+#define VKR_MAX_API_VERSION VK_API_VERSION_1_3
 
 #define VKR_DEBUG(category) (unlikely(vkr_debug_flags & VKR_DEBUG_##category))
 
diff --git a/src/venus/vkr_context.c b/src/venus/vkr_context.c
index 9ecb9cd..26dfaa0 100644
--- a/src/venus/vkr_context.c
+++ b/src/venus/vkr_context.c
@@ -120,25 +120,58 @@
    vkr_context_init_command_buffer_dispatch(ctx);
 }
 
+static struct vkr_cpu_sync *
+vkr_alloc_cpu_sync(uint32_t flags, uint32_t ring_idx, uint64_t fence_id)
+{
+   struct vkr_cpu_sync *sync;
+   sync = malloc(sizeof(*sync));
+   if (!sync)
+      return NULL;
+
+   sync->flags = flags;
+   sync->fence_id = fence_id;
+   sync->ring_idx = ring_idx;
+   list_inithead(&sync->head);
+
+   return sync;
+}
+
 static int
 vkr_context_submit_fence_locked(struct virgl_context *base,
                                 uint32_t flags,
-                                uint64_t queue_id,
+                                uint32_t ring_idx,
                                 uint64_t fence_id)
 {
    struct vkr_context *ctx = (struct vkr_context *)base;
-   struct vn_device_proc_table *vk;
-   struct vkr_queue *queue;
    VkResult result;
 
-   queue = vkr_context_get_object(ctx, queue_id);
-   if (!queue)
+   if (ring_idx >= ARRAY_SIZE(ctx->sync_queues)) {
+      vkr_log("invalid sync ring_idx %u", ring_idx);
       return -EINVAL;
+   }
+
+   if (ring_idx == 0) {
+      if (vkr_renderer_flags & VKR_RENDERER_ASYNC_FENCE_CB) {
+         ctx->base.fence_retire(&ctx->base, ring_idx, fence_id);
+      } else {
+         struct vkr_cpu_sync *sync = vkr_alloc_cpu_sync(flags, ring_idx, fence_id);
+         if (!sync)
+            return -ENOMEM;
+
+         list_addtail(&sync->head, &ctx->signaled_cpu_syncs);
+      }
+      return 0;
+   } else if (!ctx->sync_queues[ring_idx]) {
+      vkr_log("invalid ring_idx %u", ring_idx);
+      return -EINVAL;
+   }
+
+   struct vkr_queue *queue = ctx->sync_queues[ring_idx];
    struct vkr_device *dev = queue->device;
-   vk = &dev->proc_table;
+   struct vn_device_proc_table *vk = &dev->proc_table;
 
    struct vkr_queue_sync *sync =
-      vkr_device_alloc_queue_sync(dev, flags, queue_id, fence_id);
+      vkr_device_alloc_queue_sync(dev, flags, ring_idx, fence_id);
    if (!sync)
       return -ENOMEM;
 
@@ -168,14 +201,18 @@
 static int
 vkr_context_submit_fence(struct virgl_context *base,
                          uint32_t flags,
-                         uint64_t queue_id,
+                         uint32_t ring_idx,
                          uint64_t fence_id)
 {
    struct vkr_context *ctx = (struct vkr_context *)base;
    int ret;
 
+   /* always merge fences */
+   assert(!(flags & ~VIRGL_RENDERER_FENCE_FLAG_MERGEABLE));
+   flags = VIRGL_RENDERER_FENCE_FLAG_MERGEABLE;
+
    mtx_lock(&ctx->mutex);
-   ret = vkr_context_submit_fence_locked(base, flags, queue_id, fence_id);
+   ret = vkr_context_submit_fence_locked(base, flags, ring_idx, fence_id);
    mtx_unlock(&ctx->mutex);
    return ret;
 }
@@ -191,12 +228,20 @@
 
    /* retire syncs from destroyed devices */
    LIST_FOR_EACH_ENTRY_SAFE (sync, sync_tmp, &ctx->signaled_syncs, head) {
-      /* queue_id might have already get reused but is opaque to the clients */
-      ctx->base.fence_retire(&ctx->base, sync->queue_id, sync->fence_id);
+      /* ring_idx might have already get reused but is opaque to the clients */
+      ctx->base.fence_retire(&ctx->base, sync->ring_idx, sync->fence_id);
       free(sync);
    }
    list_inithead(&ctx->signaled_syncs);
 
+   /* retire syncs from CPU timeline */
+   struct vkr_cpu_sync *cpu_sync, *cpu_sync_tmp;
+   LIST_FOR_EACH_ENTRY_SAFE (cpu_sync, cpu_sync_tmp, &ctx->signaled_cpu_syncs, head) {
+      ctx->base.fence_retire(&ctx->base, cpu_sync->ring_idx, cpu_sync->fence_id);
+      free(cpu_sync);
+   }
+   list_inithead(&ctx->signaled_cpu_syncs);
+
    /* flush first and once because the per-queue sync threads might write to
     * it any time
     */
@@ -211,7 +256,7 @@
       vkr_queue_get_signaled_syncs(queue, &retired_syncs, &queue_empty);
 
       LIST_FOR_EACH_ENTRY_SAFE (sync, sync_tmp, &retired_syncs, head) {
-         ctx->base.fence_retire(&ctx->base, sync->queue_id, sync->fence_id);
+         ctx->base.fence_retire(&ctx->base, sync->ring_idx, sync->fence_id);
          vkr_device_free_queue_sync(dev, sync);
       }
 
@@ -359,7 +404,7 @@
          return ret;
 
       if (fd_type == VIRGL_RESOURCE_FD_DMABUF &&
-          (uint64_t)lseek64(fd, 0, SEEK_END) < blob_size) {
+          (uint64_t)lseek(fd, 0, SEEK_END) < blob_size) {
          close(fd);
          return -EINVAL;
       }
@@ -538,6 +583,10 @@
    LIST_FOR_EACH_ENTRY_SAFE (sync, tmp, &ctx->signaled_syncs, head)
       free(sync);
 
+   struct vkr_queue_sync *cpu_sync, *cpu_sync_tmp;
+   LIST_FOR_EACH_ENTRY_SAFE (cpu_sync, cpu_sync_tmp, &ctx->signaled_cpu_syncs, head)
+      free(cpu_sync);
+
    if (ctx->fence_eventfd >= 0)
       close(ctx->fence_eventfd);
 
@@ -645,6 +694,7 @@
    list_inithead(&ctx->rings);
    list_inithead(&ctx->busy_queues);
    list_inithead(&ctx->signaled_syncs);
+   list_inithead(&ctx->signaled_cpu_syncs);
 
    return &ctx->base;
 
diff --git a/src/venus/vkr_context.h b/src/venus/vkr_context.h
index ccbf5d9..c6f7e11 100644
--- a/src/venus/vkr_context.h
+++ b/src/venus/vkr_context.h
@@ -42,6 +42,14 @@
    VKR_CONTEXT_VALIDATE_FULL,
 };
 
+struct vkr_cpu_sync {
+   uint32_t flags;
+   uint32_t ring_idx;
+   uint64_t fence_id;
+
+   struct list_head head;
+};
+
 struct vkr_context {
    struct virgl_context base;
 
@@ -62,6 +70,9 @@
    int fence_eventfd;
    struct list_head busy_queues;
    struct list_head signaled_syncs;
+   struct list_head signaled_cpu_syncs;
+
+   struct vkr_queue *sync_queues[64];
 
    struct vkr_instance *instance;
    char *instance_name;
diff --git a/src/venus/vkr_device.h b/src/venus/vkr_device.h
index 4a5a109..c7a2a5c 100644
--- a/src/venus/vkr_device.h
+++ b/src/venus/vkr_device.h
@@ -6,9 +6,10 @@
 #ifndef VKR_DEVICE_H
 #define VKR_DEVICE_H
 
+#include "vkr_common.h"
+
 #include "venus-protocol/vn_protocol_renderer_util.h"
 
-#include "vkr_common.h"
 #include "vkr_context.h"
 
 struct vkr_device {
diff --git a/src/venus/vkr_device_object.py b/src/venus/vkr_device_object.py
index c45be01..282c39e 100644
--- a/src/venus/vkr_device_object.py
+++ b/src/venus/vkr_device_object.py
@@ -170,7 +170,12 @@
    if (vkr_{create_func_name}_init_array(ctx, args, arr) != VK_SUCCESS)
       return args->ret;
 
-   if (vkr_{create_func_name}_create_driver_handles(ctx, args, arr) != VK_SUCCESS) {{
+   if (vkr_{create_func_name}_create_driver_handles(ctx, args, arr) < VK_SUCCESS) {{
+      /* In case the client expects a reply, clear all returned handles to
+       * VK_NULL_HANDLE.
+       */
+      memset(args->{create_objs}, 0,
+             args->{create_count} * sizeof(args->{create_objs}[0]));
       object_array_fini(arr);
       return args->ret;
    }}
@@ -234,14 +239,22 @@
 vkr_{create_func_name}_add_array(
    struct vkr_context *ctx,
    struct vkr_device *dev,
-   struct object_array *arr)
+   struct object_array *arr,
+   {vk_type} *args_{create_objs})
 {{
    for (uint32_t i = 0; i < arr->count; i++) {{
       struct vkr_{vkr_type} *obj = arr->objects[i];
 
       obj->base.handle.{vkr_type} = (({vk_type} *)arr->handle_storage)[i];
 
-      vkr_device_add_object(ctx, dev, &obj->base);
+      /* Individual pipelines may fail creation. */
+      if (obj->base.handle.{vkr_type} == VK_NULL_HANDLE) {{
+         free(obj);
+         arr->objects[i] = NULL;
+         args_{create_objs}[i] = VK_NULL_HANDLE;
+      }} else {{
+         vkr_device_add_object(ctx, dev, &obj->base);
+      }}
    }}
 
    arr->objects_stolen = true;
diff --git a/src/venus/vkr_physical_device.c b/src/venus/vkr_physical_device.c
index 633e07b..686fec0 100644
--- a/src/venus/vkr_physical_device.c
+++ b/src/venus/vkr_physical_device.c
@@ -16,7 +16,7 @@
 static struct gbm_device *vkr_gbm_dev;
 
 static void
-vkr_gbm_device_init_once()
+vkr_gbm_device_init_once(void)
 {
    struct virgl_gbm *vkr_gbm = virgl_gbm_init(-1);
    if (!vkr_gbm) {
@@ -244,9 +244,6 @@
 
    VkPhysicalDeviceProperties *props = &physical_dev->properties;
    props->apiVersion = vkr_api_version_cap_minor(props->apiVersion, VKR_MAX_API_VERSION);
-   props->driverVersion = 0;
-
-   /* TODO lie about props->pipelineCacheUUID and patch cache header */
 }
 
 static void
@@ -524,59 +521,8 @@
    UNUSED struct vn_dispatch_context *dispatch,
    struct vn_command_vkGetPhysicalDeviceProperties2 *args)
 {
-   struct vkr_physical_device *physical_dev =
-      vkr_physical_device_from_handle(args->physicalDevice);
-
    vn_replace_vkGetPhysicalDeviceProperties2_args_handle(args);
    vkGetPhysicalDeviceProperties2(args->physicalDevice, args->pProperties);
-
-   union {
-      VkBaseOutStructure *pnext;
-      VkPhysicalDeviceProperties2 *props;
-      VkPhysicalDeviceVulkan11Properties *vk11;
-      VkPhysicalDeviceVulkan12Properties *vk12;
-      VkPhysicalDeviceIDProperties *id;
-      VkPhysicalDeviceDriverProperties *driver;
-   } u;
-
-   u.pnext = (VkBaseOutStructure *)args->pProperties;
-   while (u.pnext) {
-      switch (u.pnext->sType) {
-      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2:
-         u.props->properties = physical_dev->properties;
-         break;
-      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES:
-         memset(u.vk11->deviceUUID, 0, sizeof(u.vk11->deviceUUID));
-         memset(u.vk11->driverUUID, 0, sizeof(u.vk11->driverUUID));
-         memset(u.vk11->deviceLUID, 0, sizeof(u.vk11->deviceLUID));
-         u.vk11->deviceNodeMask = 0;
-         u.vk11->deviceLUIDValid = false;
-         break;
-      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES:
-         u.vk12->driverID = 0;
-         memset(u.vk12->driverName, 0, sizeof(u.vk12->driverName));
-         memset(u.vk12->driverInfo, 0, sizeof(u.vk12->driverInfo));
-         memset(&u.vk12->conformanceVersion, 0, sizeof(u.vk12->conformanceVersion));
-         break;
-      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES:
-         memset(u.id->deviceUUID, 0, sizeof(u.id->deviceUUID));
-         memset(u.id->driverUUID, 0, sizeof(u.id->driverUUID));
-         memset(u.id->deviceLUID, 0, sizeof(u.id->deviceLUID));
-         u.id->deviceNodeMask = 0;
-         u.id->deviceLUIDValid = false;
-         break;
-      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES:
-         u.driver->driverID = 0;
-         memset(u.driver->driverName, 0, sizeof(u.driver->driverName));
-         memset(u.driver->driverInfo, 0, sizeof(u.driver->driverInfo));
-         memset(&u.driver->conformanceVersion, 0, sizeof(u.driver->conformanceVersion));
-         break;
-      default:
-         break;
-      }
-
-      u.pnext = u.pnext->pNext;
-   }
 }
 
 static void
diff --git a/src/venus/vkr_physical_device.h b/src/venus/vkr_physical_device.h
index 8cafa8b..03c2ace 100644
--- a/src/venus/vkr_physical_device.h
+++ b/src/venus/vkr_physical_device.h
@@ -27,6 +27,7 @@
    bool EXT_external_memory_dma_buf;
 
    bool KHR_external_fence_fd;
+   bool KHR_external_semaphore_fd;
 
    VkPhysicalDeviceMemoryProperties memory_properties;
    VkPhysicalDeviceIDProperties id_properties;
diff --git a/src/venus/vkr_pipeline.c b/src/venus/vkr_pipeline.c
index 8fd1b05..967d237 100644
--- a/src/venus/vkr_pipeline.c
+++ b/src/venus/vkr_pipeline.c
@@ -81,10 +81,10 @@
    struct vkr_device *dev = vkr_device_from_handle(args->device);
    struct object_array arr;
 
-   if (vkr_graphics_pipeline_create_array(ctx, args, &arr) != VK_SUCCESS)
+   if (vkr_graphics_pipeline_create_array(ctx, args, &arr) < VK_SUCCESS)
       return;
 
-   vkr_pipeline_add_array(ctx, dev, &arr);
+   vkr_pipeline_add_array(ctx, dev, &arr, args->pPipelines);
 }
 
 static void
@@ -95,10 +95,10 @@
    struct vkr_device *dev = vkr_device_from_handle(args->device);
    struct object_array arr;
 
-   if (vkr_compute_pipeline_create_array(ctx, args, &arr) != VK_SUCCESS)
+   if (vkr_compute_pipeline_create_array(ctx, args, &arr) < VK_SUCCESS)
       return;
 
-   vkr_pipeline_add_array(ctx, dev, &arr);
+   vkr_pipeline_add_array(ctx, dev, &arr, args->pPipelines);
 }
 
 static void
diff --git a/src/venus/vkr_queue.c b/src/venus/vkr_queue.c
index 213a47f..3b38d8c 100644
--- a/src/venus/vkr_queue.c
+++ b/src/venus/vkr_queue.c
@@ -7,13 +7,14 @@
 
 #include "venus-protocol/vn_protocol_renderer_queue.h"
 
+#include "vkr_context.h"
 #include "vkr_physical_device.h"
 #include "vkr_queue_gen.h"
 
 struct vkr_queue_sync *
 vkr_device_alloc_queue_sync(struct vkr_device *dev,
                             uint32_t fence_flags,
-                            uint64_t queue_id,
+                            uint32_t ring_idx,
                             uint64_t fence_id)
 {
    struct vn_device_proc_table *vk = &dev->proc_table;
@@ -56,7 +57,7 @@
 
    sync->device_lost = false;
    sync->flags = fence_flags;
-   sync->queue_id = queue_id;
+   sync->ring_idx = ring_idx;
    sync->fence_id = fence_id;
 
    return sync;
@@ -131,7 +132,7 @@
    struct vn_device_proc_table *vk = &dev->proc_table;
 
    if (vkr_renderer_flags & VKR_RENDERER_ASYNC_FENCE_CB) {
-      ctx->base.fence_retire(&ctx->base, sync->queue_id, sync->fence_id);
+      ctx->base.fence_retire(&ctx->base, sync->ring_idx, sync->fence_id);
       vkr_device_free_queue_sync(dev, sync);
    } else {
       vk->DestroyFence(dev->base.handle.device, sync->fence, NULL);
@@ -177,6 +178,9 @@
    list_del(&queue->busy_head);
    list_del(&queue->base.track_head);
 
+   if (queue->ring_idx > 0)
+      ctx->sync_queues[queue->ring_idx] = NULL;
+
    if (queue->base.id)
       vkr_context_remove_object(ctx, &queue->base);
    else
@@ -225,7 +229,7 @@
       list_del(&sync->head);
 
       if (vkr_renderer_flags & VKR_RENDERER_ASYNC_FENCE_CB) {
-         ctx->base.fence_retire(&ctx->base, sync->queue_id, sync->fence_id);
+         ctx->base.fence_retire(&ctx->base, sync->ring_idx, sync->fence_id);
          vkr_device_free_queue_sync(queue->device, sync);
       } else {
          list_addtail(&sync->head, &queue->signaled_syncs);
@@ -363,6 +367,26 @@
       return;
    }
 
+   const VkDeviceQueueTimelineInfoMESA *timeline_info = vkr_find_struct(
+      args->pQueueInfo->pNext, VK_STRUCTURE_TYPE_DEVICE_QUEUE_TIMELINE_INFO_MESA);
+   if (timeline_info) {
+      if (timeline_info->ringIdx == 0 ||
+          timeline_info->ringIdx >= ARRAY_SIZE(ctx->sync_queues)) {
+         vkr_log("invalid ring_idx %d", timeline_info->ringIdx);
+         vkr_cs_decoder_set_fatal(&ctx->decoder);
+         return;
+      }
+
+      if (ctx->sync_queues[timeline_info->ringIdx]) {
+         vkr_log("sync_queue %d already bound", timeline_info->ringIdx);
+         vkr_cs_decoder_set_fatal(&ctx->decoder);
+         return;
+      }
+
+      queue->ring_idx = timeline_info->ringIdx;
+      ctx->sync_queues[timeline_info->ringIdx] = queue;
+   }
+
    const vkr_object_id id =
       vkr_cs_handle_load_id((const void **)args->pQueue, VK_OBJECT_TYPE_QUEUE);
    vkr_queue_assign_object_id(ctx, queue, id);
@@ -402,6 +426,18 @@
 }
 
 static void
+vkr_dispatch_vkQueueSubmit2(UNUSED struct vn_dispatch_context *dispatch,
+                            struct vn_command_vkQueueSubmit2 *args)
+{
+   struct vkr_queue *queue = vkr_queue_from_handle(args->queue);
+   struct vn_device_proc_table *vk = &queue->device->proc_table;
+
+   vn_replace_vkQueueSubmit2_args_handle(args);
+   args->ret =
+      vk->QueueSubmit2(args->queue, args->submitCount, args->pSubmits, args->fence);
+}
+
+static void
 vkr_dispatch_vkCreateFence(struct vn_dispatch_context *dispatch,
                            struct vn_command_vkCreateFence *args)
 {
@@ -454,6 +490,33 @@
 }
 
 static void
+vkr_dispatch_vkResetFenceResource100000MESA(
+   struct vn_dispatch_context *dispatch,
+   struct vn_command_vkResetFenceResource100000MESA *args)
+{
+   struct vkr_context *ctx = dispatch->data;
+   struct vkr_device *dev = vkr_device_from_handle(args->device);
+   struct vn_device_proc_table *vk = &dev->proc_table;
+   int fd = -1;
+
+   vn_replace_vkResetFenceResource100000MESA_args_handle(args);
+
+   const VkFenceGetFdInfoKHR info = {
+      .sType = VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR,
+      .fence = args->fence,
+      .handleType = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT,
+   };
+   VkResult result = vk->GetFenceFdKHR(args->device, &info, &fd);
+   if (result != VK_SUCCESS) {
+      vkr_cs_decoder_set_fatal(&ctx->decoder);
+      return;
+   }
+
+   if (fd >= 0)
+      close(fd);
+}
+
+static void
 vkr_dispatch_vkCreateSemaphore(struct vn_dispatch_context *dispatch,
                                struct vn_command_vkCreateSemaphore *args)
 {
@@ -505,6 +568,61 @@
 }
 
 static void
+vkr_dispatch_vkWaitSemaphoreResource100000MESA(
+   struct vn_dispatch_context *dispatch,
+   struct vn_command_vkWaitSemaphoreResource100000MESA *args)
+{
+   struct vkr_context *ctx = dispatch->data;
+   struct vkr_device *dev = vkr_device_from_handle(args->device);
+   struct vn_device_proc_table *vk = &dev->proc_table;
+   int fd = -1;
+
+   vn_replace_vkWaitSemaphoreResource100000MESA_args_handle(args);
+
+   const VkSemaphoreGetFdInfoKHR info = {
+      .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
+      .semaphore = args->semaphore,
+      .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
+   };
+   VkResult result = vk->GetSemaphoreFdKHR(args->device, &info, &fd);
+   if (result != VK_SUCCESS) {
+      vkr_cs_decoder_set_fatal(&ctx->decoder);
+      return;
+   }
+
+   if (fd >= 0)
+      close(fd);
+}
+
+static void
+vkr_dispatch_vkImportSemaphoreResource100000MESA(
+   struct vn_dispatch_context *dispatch,
+   struct vn_command_vkImportSemaphoreResource100000MESA *args)
+{
+   struct vkr_context *ctx = dispatch->data;
+   struct vkr_device *dev = vkr_device_from_handle(args->device);
+   struct vn_device_proc_table *vk = &dev->proc_table;
+
+   vn_replace_vkImportSemaphoreResource100000MESA_args_handle(args);
+
+   const VkImportSemaphoreResourceInfo100000MESA *res_info =
+      args->pImportSemaphoreResourceInfo;
+
+   /* resourceId 0 is for importing a signaled payload to sync_fd fence */
+   assert(!res_info->resourceId);
+
+   const VkImportSemaphoreFdInfoKHR import_info = {
+      .sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR,
+      .semaphore = res_info->semaphore,
+      .flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT,
+      .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
+      .fd = -1,
+   };
+   if (vk->ImportSemaphoreFdKHR(args->device, &import_info) != VK_SUCCESS)
+      vkr_cs_decoder_set_fatal(&ctx->decoder);
+}
+
+static void
 vkr_dispatch_vkCreateEvent(struct vn_dispatch_context *dispatch,
                            struct vn_command_vkCreateEvent *args)
 {
@@ -561,6 +679,9 @@
    dispatch->dispatch_vkQueueSubmit = vkr_dispatch_vkQueueSubmit;
    dispatch->dispatch_vkQueueBindSparse = vkr_dispatch_vkQueueBindSparse;
    dispatch->dispatch_vkQueueWaitIdle = vkr_dispatch_vkQueueWaitIdle;
+
+   /* VK_KHR_synchronization2 */
+   dispatch->dispatch_vkQueueSubmit2 = vkr_dispatch_vkQueueSubmit2;
 }
 
 void
@@ -573,6 +694,9 @@
    dispatch->dispatch_vkResetFences = vkr_dispatch_vkResetFences;
    dispatch->dispatch_vkGetFenceStatus = vkr_dispatch_vkGetFenceStatus;
    dispatch->dispatch_vkWaitForFences = vkr_dispatch_vkWaitForFences;
+
+   dispatch->dispatch_vkResetFenceResource100000MESA =
+      vkr_dispatch_vkResetFenceResource100000MESA;
 }
 
 void
@@ -586,6 +710,11 @@
       vkr_dispatch_vkGetSemaphoreCounterValue;
    dispatch->dispatch_vkWaitSemaphores = vkr_dispatch_vkWaitSemaphores;
    dispatch->dispatch_vkSignalSemaphore = vkr_dispatch_vkSignalSemaphore;
+
+   dispatch->dispatch_vkWaitSemaphoreResource100000MESA =
+      vkr_dispatch_vkWaitSemaphoreResource100000MESA;
+   dispatch->dispatch_vkImportSemaphoreResource100000MESA =
+      vkr_dispatch_vkImportSemaphoreResource100000MESA;
 }
 
 void
diff --git a/src/venus/vkr_queue.h b/src/venus/vkr_queue.h
index 2350be2..4ca9d64 100644
--- a/src/venus/vkr_queue.h
+++ b/src/venus/vkr_queue.h
@@ -13,7 +13,7 @@
    bool device_lost;
 
    uint32_t flags;
-   uint64_t queue_id;
+   uint32_t ring_idx;
    uint64_t fence_id;
 
    struct list_head head;
@@ -29,6 +29,9 @@
    uint32_t family;
    uint32_t index;
 
+   /* only used when client driver uses multiple timelines */
+   uint32_t ring_idx;
+
    /* Submitted fences are added to pending_syncs first.  How submitted fences
     * are retired depends on VKR_RENDERER_THREAD_SYNC and
     * VKR_RENDERER_ASYNC_FENCE_CB.
@@ -87,7 +90,7 @@
 struct vkr_queue_sync *
 vkr_device_alloc_queue_sync(struct vkr_device *dev,
                             uint32_t fence_flags,
-                            uint64_t queue_id,
+                            uint32_t ring_idx,
                             uint64_t fence_id);
 
 void
diff --git a/src/venus/vkr_renderer.c b/src/venus/vkr_renderer.c
index ecc00eb..64ab372 100644
--- a/src/venus/vkr_renderer.c
+++ b/src/venus/vkr_renderer.c
@@ -47,6 +47,7 @@
       c->vk_extension_mask1[0] |= 0x1u;
 
       c->allow_vk_wait_syncs = 1;
+      c->supports_multiple_timelines = 1;
    }
 
    return sizeof(*c);
diff --git a/src/venus/vkr_transport.c b/src/venus/vkr_transport.c
index 745b124..361c7f3 100644
--- a/src/venus/vkr_transport.c
+++ b/src/venus/vkr_transport.c
@@ -225,8 +225,8 @@
 
    const size_t buf_size = vkr_region_size(&layout->buffer);
    if (buf_size > VKR_RING_BUFFER_MAX_SIZE || !util_is_power_of_two_nonzero(buf_size)) {
-      vkr_log("ring buffer size (%lu) must be a power of two and not exceed %lu",
-              buf_size, VKR_RING_BUFFER_MAX_SIZE);
+      vkr_log("ring buffer size (%z) must be a power of two and not exceed %lu", buf_size,
+              VKR_RING_BUFFER_MAX_SIZE);
       return false;
    }
 
@@ -319,6 +319,7 @@
       .memoryResourceAllocationSize = VK_TRUE,
       .globalFencing = VK_FALSE,
       .largeRing = VK_TRUE,
+      .syncFdFencing = VK_TRUE,
    };
 
    vn_replace_vkGetVenusExperimentalFeatureData100000MESA_args_handle(args);
diff --git a/src/venus_hw.h b/src/venus_hw.h
index 23a3497..18bd196 100644
--- a/src/venus_hw.h
+++ b/src/venus_hw.h
@@ -54,6 +54,16 @@
     * shifts the responsibilities to the client drivers.
     */
    uint32_t allow_vk_wait_syncs;
+
+   /* This flag indicates that the renderer supports multiple fencing
+    * timelines. The client driver is expected to associate each VkQueue with
+    * one of these timelines at queue creation by binding it with an unused
+    * ring_idx. Queues created without a ring_idx binding are associated to a
+    * shared legacy timeline. The special ring_idx==0 is reserved for CPU
+    * fences that are signaled by the renderer immediately upon consumption of
+    * the associated renderer submission.
+    */
+   uint32_t supports_multiple_timelines;
 };
 #endif
 
diff --git a/src/virgl_context.c b/src/virgl_context.c
index f8c005a..b74aad9 100644
--- a/src/virgl_context.c
+++ b/src/virgl_context.c
@@ -44,7 +44,7 @@
 virgl_context_table_init(void)
 {
    virgl_context_table = util_hash_table_create(hash_func_u32,
-                                                compare_func,
+                                                equal_func,
                                                 virgl_context_destroy_func);
    return virgl_context_table ? 0 : ENOMEM;
 }
diff --git a/src/virgl_context.h b/src/virgl_context.h
index 4bf1370..046948d 100644
--- a/src/virgl_context.h
+++ b/src/virgl_context.h
@@ -52,7 +52,7 @@
 struct virgl_context;
 
 typedef void (*virgl_context_fence_retire)(struct virgl_context *ctx,
-                                           uint64_t queue_id,
+                                           uint32_t ring_idx,
                                            uint64_t fence_id);
 
 /**
@@ -120,7 +120,7 @@
    /* submit a fence to the queue identified by queue_id */
    int (*submit_fence)(struct virgl_context *ctx,
                        uint32_t flags,
-                       uint64_t queue_id,
+                       uint32_t ring_idx,
                        uint64_t fence_id);
 };
 
diff --git a/src/virgl_hw.h b/src/virgl_hw.h
index be64717..dfbcf81 100644
--- a/src/virgl_hw.h
+++ b/src/virgl_hw.h
@@ -344,6 +344,10 @@
    VIRGL_FORMAT_A8L8_SRGB               = 261,
 
    VIRGL_FORMAT_A1B5G5R5_UNORM          = 262,
+   VIRGL_FORMAT_A1R5G5B5_UNORM          = 263,
+   VIRGL_FORMAT_A2B10G10R10_UNORM       = 264,
+   VIRGL_FORMAT_A2R10G10B10_UNORM       = 265,
+   VIRGL_FORMAT_A4R4G4B4_UNORM          = 266,
 
    VIRGL_FORMAT_X8B8G8R8_SNORM          = 268,
 
@@ -399,6 +403,12 @@
    VIRGL_FORMAT_P012                    = 315,
    VIRGL_FORMAT_P016                    = 316,
 
+   VIRGL_FORMAT_B8G8R8_UNORM            = 317,
+   VIRGL_FORMAT_R3G3B2_UNORM            = 318,
+   VIRGL_FORMAT_R4G4B4A4_UNORM          = 319,
+   VIRGL_FORMAT_R5G5B5A1_UNORM          = 320,
+   VIRGL_FORMAT_R5G6B5_UNORM            = 321,
+
    VIRGL_FORMAT_MAX /* = PIPE_FORMAT_COUNT */,
 
    /* Below formats must not be used in the guest. */
@@ -428,7 +438,7 @@
 #define VIRGL_CAP_QBO                  (1 << 16)
 #define VIRGL_CAP_TRANSFER             (1 << 17)
 #define VIRGL_CAP_FBO_MIXED_COLOR_FORMATS  (1 << 18)
-#define VIRGL_CAP_FAKE_FP64            (1 << 19)
+#define VIRGL_CAP_HOST_IS_GLES         (1 << 19)
 #define VIRGL_CAP_BIND_COMMAND_ARGS    (1 << 20)
 #define VIRGL_CAP_MULTI_DRAW_INDIRECT  (1 << 21)
 #define VIRGL_CAP_INDIRECT_PARAMS      (1 << 22)
@@ -442,6 +452,9 @@
 #define VIRGL_CAP_CLEAR_TEXTURE        (1 << 30)
 #define VIRGL_CAP_ARB_BUFFER_STORAGE   (1 << 31)
 
+// Legacy alias
+#define VIRGL_CAP_FAKE_FP64            VIRGL_CAP_HOST_IS_GLES
+
 /* These are used by the capability_bits_v2 field in virgl_caps_v2. */
 #define VIRGL_CAP_V2_BLEND_EQUATION       (1 << 0)
 #define VIRGL_CAP_V2_UNTYPED_RESOURCE     (1 << 1)
@@ -453,6 +466,7 @@
 #define VIRGL_CAP_V2_COPY_TRANSFER_BOTH_DIRECTIONS (1 << 7)
 #define VIRGL_CAP_V2_SCANOUT_USES_GBM     (1 << 8)
 #define VIRGL_CAP_V2_SSO                  (1 << 9)
+#define VIRGL_CAP_V2_TEXTURE_SHADOW_LOD   (1 << 10)
 
 /* virgl bind flags - these are compatible with mesa 10.5 gallium.
  * but are fixed, no other should be passed to virgl either.
@@ -554,6 +568,26 @@
         uint32_t max_texture_gather_components;
 };
 
+struct virgl_video_caps {
+        uint32_t profile:8;
+        uint32_t entrypoint:8;
+        uint32_t max_level:8;
+        uint32_t stacked_frames:8;
+
+        uint32_t max_width:16;
+        uint32_t max_height:16;
+
+        uint32_t prefered_format:16;
+        uint32_t max_macroblocks:16;
+
+        uint32_t npot_texture:1;
+        uint32_t supports_progressive:1;
+        uint32_t supports_interlaced:1;
+        uint32_t prefers_interlaced:1;
+        uint32_t max_temporal_layers:8;
+        uint32_t reserved:20;
+};
+
 /*
  * This struct should be growable when used in capset 2,
  * so we shouldn't have to add a v3 ever.
@@ -611,6 +645,9 @@
         uint32_t max_texture_image_units;
         struct virgl_supported_format_mask supported_multisample_formats;
         uint32_t max_const_buffer_size[6]; // PIPE_SHADER_TYPES
+        uint32_t num_video_caps;
+        struct virgl_video_caps video_caps[32];
+        uint32_t max_uniform_block_size;
 };
 
 union virgl_caps {
@@ -641,6 +678,7 @@
         VIRGL_ERROR_CTX_TRANSFER_IOV_BOUNDS,
         VIRGL_ERROR_CTX_ILLEGAL_DUAL_SRC_BLEND,
         VIRGL_ERROR_CTX_UNSUPPORTED_FUNCTION,
+        VIRGL_ERROR_CTX_ILLEGAL_PROGRAM_PIPELINE,
 };
 
 /**
diff --git a/src/virgl_protocol.h b/src/virgl_protocol.h
index cb378c1..98aa431 100644
--- a/src/virgl_protocol.h
+++ b/src/virgl_protocol.h
@@ -117,6 +117,18 @@
    VIRGL_CCMD_GET_MEMORY_INFO,
    VIRGL_CCMD_SEND_STRING_MARKER,
    VIRGL_CCMD_LINK_SHADER,
+
+   /* video codec */
+   VIRGL_CCMD_CREATE_VIDEO_CODEC,
+   VIRGL_CCMD_DESTROY_VIDEO_CODEC,
+   VIRGL_CCMD_CREATE_VIDEO_BUFFER,
+   VIRGL_CCMD_DESTROY_VIDEO_BUFFER,
+   VIRGL_CCMD_BEGIN_FRAME,
+   VIRGL_CCMD_DECODE_MACROBLOCK,
+   VIRGL_CCMD_DECODE_BITSTREAM,
+   VIRGL_CCMD_ENCODE_BITSTREAM,
+   VIRGL_CCMD_END_FRAME,
+
    VIRGL_MAX_COMMANDS
 };
 
@@ -687,4 +699,59 @@
 #define VIRGL_LINK_SHADER_TESS_EVAL_HANDLE 5
 #define VIRGL_LINK_SHADER_COMPUTE_HANDLE 6
 
+/* VIRGL_CCMD_CREATE_VIDEO_CODEC */
+#define VIRGL_CREATE_VIDEO_CODEC_MIN_SIZE   7
+#define VIRGL_CREATE_VIDEO_CODEC_HANDLE     1
+#define VIRGL_CREATE_VIDEO_CODEC_PROFILE    2
+#define VIRGL_CREATE_VIDEO_CODEC_ENTRYPOINT 3
+#define VIRGL_CREATE_VIDEO_CODEC_CHROMA_FMT 4
+#define VIRGL_CREATE_VIDEO_CODEC_LEVEL      5
+#define VIRGL_CREATE_VIDEO_CODEC_WIDTH      6
+#define VIRGL_CREATE_VIDEO_CODEC_HEIGHT     7
+#define VIRGL_CREATE_VIDEO_CODEC_MAX_REF    8
+
+/* VIRGL_CCMD_DESTROY_VIDEO_CODEC */
+#define VIRGL_DESTROY_VIDEO_CODEC_MIN_SIZE  1
+#define VIRGL_DESTROY_VIDEO_CODEC_HANDLE    1
+
+/* VIRGL_CCMD_CREATE_VIDEO_BUFFER */
+#define VIRGL_CREATE_VIDEO_BUFFER_MIN_SIZE  5
+#define VIRGL_CREATE_VIDEO_BUFFER_HANDLE    1
+#define VIRGL_CREATE_VIDEO_BUFFER_FORMAT    2
+#define VIRGL_CREATE_VIDEO_BUFFER_WIDTH     3
+#define VIRGL_CREATE_VIDEO_BUFFER_HEIGHT    4
+#define VIRGL_CREATE_VIDEO_BUFFER_RES_BASE  5
+
+/* VIRGL_CCMD_DESTROY_VIDEO_BUFFER */
+#define VIRGL_DESTROY_VIDEO_BUFFER_MIN_SIZE 1
+#define VIRGL_DESTROY_VIDEO_BUFFER_HANDLE   1
+
+/* VIRGL_CCMD_BEGIN_FRAME */
+#define VIRGL_BEGIN_FRAME_MIN_SIZE          2
+#define VIRGL_BEGIN_FRAME_CDC_HANDLE        1
+#define VIRGL_BEGIN_FRAME_TGT_HANDLE        2
+
+/* VIRGL_CCMD_DECODE_MACROBLOCK */
+
+/* VIRGL_CCMD_DECODE_BITSTREAM */
+#define VIRGL_DECODE_BS_MIN_SIZE            5
+#define VIRGL_DECODE_BS_CDC_HANDLE          1
+#define VIRGL_DECODE_BS_TGT_HANDLE          2
+#define VIRGL_DECODE_BS_DSC_HANDLE          3
+#define VIRGL_DECODE_BS_BUF_HANDLE          4
+#define VIRGL_DECODE_BS_BUF_SIZE            5
+
+/* VIRGL_CCMD_ENCODE_BITSTREAM */
+#define VIRGL_ENCODE_BS_MIN_SIZE            5
+#define VIRGL_ENCODE_BS_CDC_HANDLE          1
+#define VIRGL_ENCODE_BS_SRC_HANDLE          2
+#define VIRGL_ENCODE_BS_DEST_HANDLE         3
+#define VIRGL_ENCODE_BS_DESC_HANDLE         4
+#define VIRGL_ENCODE_BS_FEED_HANDLE         5
+
+/* VIRGL_CCMD_END_FRAME */
+#define VIRGL_END_FRAME_MIN_SIZE            2
+#define VIRGL_END_FRAME_CDC_HANDLE          1
+#define VIRGL_END_FRAME_TGT_HANDLE          2
+
 #endif
diff --git a/src/virgl_resource.c b/src/virgl_resource.c
index 260e291..7f2c3e6 100644
--- a/src/virgl_resource.c
+++ b/src/virgl_resource.c
@@ -57,7 +57,7 @@
 virgl_resource_table_init(const struct virgl_resource_pipe_callbacks *callbacks)
 {
    virgl_resource_table = util_hash_table_create(hash_func_u32,
-                                                 compare_func,
+                                                 equal_func,
                                                  virgl_resource_destroy_func);
    if (!virgl_resource_table)
       return ENOMEM;
diff --git a/src/virgl_util.c b/src/virgl_util.c
index 15d867d..6ef1802 100644
--- a/src/virgl_util.c
+++ b/src/virgl_util.c
@@ -53,20 +53,15 @@
 #include <stdio.h>
 #endif
 
-unsigned hash_func_u32(void *key)
+uint32_t hash_func_u32(const void *key)
 {
    intptr_t ip = pointer_to_intptr(key);
-   return (unsigned)(ip & 0xffffffff);
+   return (uint32_t)(ip & 0xffffffff);
 }
 
-int compare_func(void *key1, void *key2)
+bool equal_func(const void *key1, const void *key2)
 {
-   if (key1 < key2)
-      return -1;
-   if (key1 > key2)
-      return 1;
-   else
-      return 0;
+   return key1 == key2;
 }
 
 bool has_eventfd(void)
@@ -187,9 +182,14 @@
 #endif
 
 #if ENABLE_TRACING == TRACE_WITH_PERFETTO
+static void on_tracing_state_change(bool enabled) {
+    virgl_log("%s: tracing state change: %d\n", __func__, enabled);
+}
+
 void trace_init(void)
 {
    struct vperfetto_min_config config = {
+      .on_tracing_state_change = on_tracing_state_change,
       .init_flags = VPERFETTO_INIT_FLAG_USE_SYSTEM_BACKEND,
             .filename = NULL,
             .shmem_size_hint_kb = 32 * 1024,
diff --git a/src/virgl_util.h b/src/virgl_util.h
index 05649d1..d92ed29 100644
--- a/src/virgl_util.h
+++ b/src/virgl_util.h
@@ -58,9 +58,9 @@
     return (mask == bit);
 }
 
-unsigned hash_func_u32(void *key);
+uint32_t hash_func_u32(const void *key);
 
-int compare_func(void *key1, void *key2);
+bool equal_func(const void *key1, const void *key2);
 
 bool has_eventfd(void);
 int create_eventfd(unsigned int initval);
@@ -122,7 +122,7 @@
 #define TRACE_FUNC()
 #define TRACE_SCOPE(SCOPE)
 #define TRACE_SCOPE_SLOW(SCOPE)
-#define TRACE_SCOPE_BEGIN(SCOPE, VAR)
+#define TRACE_SCOPE_BEGIN(SCOPE)
 #define TRACE_SCOPE_END(VAR)
 #endif /* ENABLE_TRACING */
 
diff --git a/src/virgl_video.c b/src/virgl_video.c
new file mode 100644
index 0000000..025ce00
--- /dev/null
+++ b/src/virgl_video.c
@@ -0,0 +1,2347 @@
+/**************************************************************************
+ *
+ * Copyright (C) 2022 Kylin Software Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * @file
+ * Implementation of general video codec interface.
+ *
+ * This implementation is currently based on VA-API, and other interfaces,
+ * such as VDPAU and proprietary interfaces, can also be considered in the
+ * future.
+ *
+ * Two objects are implemented here:
+ * virgl_video_buffer:
+ *   Buffer for storing raw YUV formatted data. Currently, it is a wrapper
+ *   for VASurface.
+ * virgl_video_codec:
+ *   Represents a video encoder or decoder. It's a wrapper of VAContext and
+ *   mainly provides the following methods:
+ *   - virgl_video_begin_frame()
+ *     It calls vaBeginPicture() to prepare for encoding and decoding. For
+ *     encoding, it also needs to upload the raw picture data from the guest
+ *     side into the local VASurface.
+ *   - virgl_video_decode_bitstream()
+ *     It constructs the decoding-related VABuffers according to the picture
+ *     description information, and then calls vaRenderPicture() for decoding.
+ *   - virgl_video_encode_bitstream()
+ *     It constructs the encoding-related VABuffers according to the picture
+ *     description information, and then calls vaRenderPicture() for encoding.
+ *   - virgl_video_end_frame()
+ *     It calls vaEndPicture() to end encoding and decoding. After decoding,
+ *     it transmits the raw picture data from VASurface to the guest side,
+ *     and after encoding, it transmits the result and the coded data in
+ *     VACodedBuffer to the guest side.
+ *
+ * @author Feng Jiang <jiangfeng@kylinos.cn>
+ */
+
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <epoxy/gl.h>
+#include <epoxy/egl.h>
+#include <va/va.h>
+#include <va/va_drm.h>
+#include <va/va_drmcommon.h>
+#include <drm_fourcc.h>
+
+#include "pipe/p_video_state.h"
+#include "util/u_memory.h"
+#include "virgl_hw.h"
+#include "virgl_video_hw.h"
+#include "virgl_util.h"
+#include "virgl_video.h"
+
+/*
+ * The max size of codec buffer is approximately:
+ *   num_of_macroblocks * max_size_of_per_macroblock + size_of_some_headers
+ * Now, we only support YUV420 formats, this means that we have a limit of
+ * 3200 bits(400 Bytes) per macroblock. To simplify the calculation, we
+ * directly use 512 instead of 400.
+ */
+#define CODED_BUF_DEFAULT_SIZE(width, height) \
+    ((width) * (height) / (16 * 16) * 512)
+
+struct virgl_video_buffer {
+    enum pipe_format format;
+    uint32_t width;
+    uint32_t height;
+    bool interlanced;
+    VASurfaceID va_sfc;
+    struct virgl_video_dma_buf *dmabuf;
+    void *opaque;                               /* User opaque data */
+};
+
+
+struct virgl_video_codec {
+   enum pipe_video_profile profile;
+   uint32_t level;
+   enum pipe_video_entrypoint entrypoint;
+   enum pipe_video_chroma_format chroma_format;
+   uint32_t width;
+   uint32_t height;
+   uint32_t max_references;
+   VAContextID va_ctx;
+   VAConfigID  va_cfg;
+   struct virgl_video_buffer *buffer;
+   struct virgl_video_buffer *ref_pic_list[32]; /* Enc: reference pictures */
+   VABufferID  va_coded_buf;                    /* Enc: VACodedBuffer */
+   void *opaque;                                /* User opaque data */
+};
+
+
+static VADisplay va_dpy;
+
+static struct virgl_video_callbacks *callbacks = NULL;
+
+static enum pipe_video_profile pipe_profile_from_va(VAProfile profile)
+{
+   switch (profile) {
+   case VAProfileMPEG2Simple:
+      return PIPE_VIDEO_PROFILE_MPEG2_SIMPLE;
+   case VAProfileMPEG2Main:
+      return PIPE_VIDEO_PROFILE_MPEG2_MAIN;
+   case VAProfileMPEG4Simple:
+      return PIPE_VIDEO_PROFILE_MPEG4_SIMPLE;
+   case VAProfileMPEG4AdvancedSimple:
+      return PIPE_VIDEO_PROFILE_MPEG4_ADVANCED_SIMPLE;
+   case VAProfileVC1Simple:
+      return PIPE_VIDEO_PROFILE_VC1_SIMPLE;
+   case VAProfileVC1Main:
+      return PIPE_VIDEO_PROFILE_VC1_MAIN;
+   case VAProfileVC1Advanced:
+      return PIPE_VIDEO_PROFILE_VC1_ADVANCED;
+   case VAProfileH264ConstrainedBaseline:
+      return PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE;
+   case VAProfileH264Main:
+      return PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN;
+   case VAProfileH264High:
+      return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH;
+   case VAProfileHEVCMain:
+      return PIPE_VIDEO_PROFILE_HEVC_MAIN;
+   case VAProfileHEVCMain10:
+      return PIPE_VIDEO_PROFILE_HEVC_MAIN_10;
+   case VAProfileJPEGBaseline:
+      return PIPE_VIDEO_PROFILE_JPEG_BASELINE;
+   case VAProfileVP9Profile0:
+      return PIPE_VIDEO_PROFILE_VP9_PROFILE0;
+   case VAProfileVP9Profile2:
+      return PIPE_VIDEO_PROFILE_VP9_PROFILE2;
+   case VAProfileAV1Profile0:
+      return PIPE_VIDEO_PROFILE_AV1_MAIN;
+   case VAProfileNone:
+       return PIPE_VIDEO_PROFILE_UNKNOWN;
+   default:
+      return PIPE_VIDEO_PROFILE_UNKNOWN;
+   }
+}
+
+/* NOTE: mesa va frontend only supports VLD and EncSlice */
+static enum pipe_video_entrypoint pipe_entrypoint_from_va(
+        VAEntrypoint entrypoint)
+{
+    switch (entrypoint) {
+    case VAEntrypointVLD:
+        return PIPE_VIDEO_ENTRYPOINT_BITSTREAM;
+    case VAEntrypointIDCT:
+        return PIPE_VIDEO_ENTRYPOINT_IDCT;
+    case VAEntrypointMoComp:
+        return PIPE_VIDEO_ENTRYPOINT_MC;
+    case VAEntrypointEncSlice: /* fall through */
+    case VAEntrypointEncSliceLP:
+        return PIPE_VIDEO_ENTRYPOINT_ENCODE;
+    default:
+        return PIPE_VIDEO_ENTRYPOINT_UNKNOWN;
+    }
+}
+
+static enum pipe_format pipe_format_from_va_fourcc(unsigned format)
+{
+   switch(format) {
+   case VA_FOURCC('N','V','1','2'):
+      return PIPE_FORMAT_NV12;
+/* TODO: These are already defined in mesa, but not yet in virglrenderer
+   case VA_FOURCC('P','0','1','0'):
+      return PIPE_FORMAT_P010;
+   case VA_FOURCC('P','0','1','6'):
+      return PIPE_FORMAT_P016;
+*/
+   case VA_FOURCC('I','4','2','0'):
+      return PIPE_FORMAT_IYUV;
+   case VA_FOURCC('Y','V','1','2'):
+      return PIPE_FORMAT_YV12;
+   case VA_FOURCC('Y','U','Y','V'):
+   case VA_FOURCC('Y','U','Y','2'):
+      return PIPE_FORMAT_YUYV;
+   case VA_FOURCC('U','Y','V','Y'):
+      return PIPE_FORMAT_UYVY;
+   case VA_FOURCC('B','G','R','A'):
+      return PIPE_FORMAT_B8G8R8A8_UNORM;
+   case VA_FOURCC('R','G','B','A'):
+      return PIPE_FORMAT_R8G8B8A8_UNORM;
+   case VA_FOURCC('B','G','R','X'):
+      return PIPE_FORMAT_B8G8R8X8_UNORM;
+   case VA_FOURCC('R','G','B','X'):
+      return PIPE_FORMAT_R8G8B8X8_UNORM;
+   default:
+      return PIPE_FORMAT_NONE;
+   }
+}
+
+
+static VAProfile va_profile_from_pipe(enum pipe_video_profile profile)
+{
+   switch (profile) {
+   case PIPE_VIDEO_PROFILE_MPEG2_SIMPLE:
+      return VAProfileMPEG2Simple;
+   case PIPE_VIDEO_PROFILE_MPEG2_MAIN:
+      return VAProfileMPEG2Main;
+   case PIPE_VIDEO_PROFILE_MPEG4_SIMPLE:
+      return VAProfileMPEG4Simple;
+   case PIPE_VIDEO_PROFILE_MPEG4_ADVANCED_SIMPLE:
+      return VAProfileMPEG4AdvancedSimple;
+   case PIPE_VIDEO_PROFILE_VC1_SIMPLE:
+      return VAProfileVC1Simple;
+   case PIPE_VIDEO_PROFILE_VC1_MAIN:
+      return VAProfileVC1Main;
+   case PIPE_VIDEO_PROFILE_VC1_ADVANCED:
+      return VAProfileVC1Advanced;
+   case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:
+      return VAProfileH264ConstrainedBaseline;
+   case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
+      return VAProfileH264Main;
+   case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
+      return VAProfileH264High;
+   case PIPE_VIDEO_PROFILE_HEVC_MAIN:
+      return VAProfileHEVCMain;
+   case PIPE_VIDEO_PROFILE_HEVC_MAIN_10:
+      return VAProfileHEVCMain10;
+   case PIPE_VIDEO_PROFILE_JPEG_BASELINE:
+      return VAProfileJPEGBaseline;
+   case PIPE_VIDEO_PROFILE_VP9_PROFILE0:
+      return VAProfileVP9Profile0;
+   case PIPE_VIDEO_PROFILE_VP9_PROFILE2:
+      return VAProfileVP9Profile2;
+   case PIPE_VIDEO_PROFILE_AV1_MAIN:
+      return VAProfileAV1Profile0;
+   case PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED:
+   case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10:
+   case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH422:
+   case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH444:
+   case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE:
+   case PIPE_VIDEO_PROFILE_HEVC_MAIN_12:
+   case PIPE_VIDEO_PROFILE_HEVC_MAIN_STILL:
+   case PIPE_VIDEO_PROFILE_HEVC_MAIN_444:
+   case PIPE_VIDEO_PROFILE_UNKNOWN:
+      return VAProfileNone;
+   default:
+      return -1;
+   }
+}
+
+/*
+ * There is no invalid entrypoint defined in libva,
+ * so add this definition to make the code clear
+ */
+#define VAEntrypointNone 0
+static int va_entrypoint_from_pipe(enum pipe_video_entrypoint entrypoint)
+{
+    switch (entrypoint) {
+    case PIPE_VIDEO_ENTRYPOINT_BITSTREAM:
+        return VAEntrypointVLD;
+    case PIPE_VIDEO_ENTRYPOINT_IDCT:
+        return VAEntrypointIDCT;
+    case PIPE_VIDEO_ENTRYPOINT_MC:
+        return VAEntrypointMoComp;
+    case PIPE_VIDEO_ENTRYPOINT_ENCODE:
+        return VAEntrypointEncSlice;
+    default:
+        return VAEntrypointNone;
+    }
+}
+
+static uint32_t va_format_from_pipe_chroma(
+        enum pipe_video_chroma_format chroma_format)
+{
+    switch (chroma_format) {
+    case PIPE_VIDEO_CHROMA_FORMAT_400:
+        return VA_RT_FORMAT_YUV400;
+    case PIPE_VIDEO_CHROMA_FORMAT_420:
+        return VA_RT_FORMAT_YUV420;
+    case PIPE_VIDEO_CHROMA_FORMAT_422:
+        return VA_RT_FORMAT_YUV422;
+    case PIPE_VIDEO_CHROMA_FORMAT_444:
+        return VA_RT_FORMAT_YUV444;
+    case PIPE_VIDEO_CHROMA_FORMAT_NONE:
+    default:
+        return 0;
+    }
+}
+
+static uint32_t drm_format_from_va_fourcc(uint32_t va_fourcc)
+{
+    switch (va_fourcc) {
+    case VA_FOURCC_NV12:
+        return DRM_FORMAT_NV12;
+    case VA_FOURCC_NV21:
+        return DRM_FORMAT_NV21;
+    default:
+        return DRM_FORMAT_INVALID;
+    }
+}
+
+static void fill_video_dma_buf(struct virgl_video_dma_buf *dmabuf,
+                               const VADRMPRIMESurfaceDescriptor *desc)
+{
+    unsigned i, j, obj_idx;
+    struct virgl_video_dma_buf_plane *plane;
+
+/*
+    virgl_log("surface: fourcc=0x%08x, size=%ux%u, num_objects=%u,
+              num_layers=%u\n", desc->fourcc, desc->width, desc->height,
+              desc->num_objects, desc->num_layers);
+
+    for (i = 0; i < desc->num_objects; i++)
+        virgl_log("  objects[%u]: fd=%d, size=%u, modifier=0x%lx\n",
+                  i, desc->objects[i].fd, desc->objects[i].size,
+                  desc->objects[i].drm_format_modifier);
+
+    for (i = 0; i < desc->num_layers; i++)
+        virgl_log("  layers[%u] : format=0x%08x, num_planes=%u, "
+                  "obj=%u,%u,%u,%u, offset=%u,%u,%u,%u, pitch=%u,%u,%u,%u\n",
+                  i, desc->layers[i].drm_format, desc->layers[i].num_planes,
+                  desc->layers[i].object_index[0],
+                  desc->layers[i].object_index[1],
+                  desc->layers[i].object_index[2],
+                  desc->layers[i].object_index[3],
+                  desc->layers[i].offset[0],
+                  desc->layers[i].offset[1],
+                  desc->layers[i].offset[2],
+                  desc->layers[i].offset[3],
+                  desc->layers[i].pitch[0],
+                  desc->layers[i].pitch[1],
+                  desc->layers[i].pitch[2],
+                  desc->layers[i].pitch[3]);
+*/
+
+    dmabuf->drm_format = drm_format_from_va_fourcc(desc->fourcc);
+    dmabuf->width = desc->width;
+    dmabuf->height = desc->height;
+
+    for (i = 0, dmabuf->num_planes = 0; i < desc->num_layers; i++) {
+        for (j = 0; j < desc->layers[i].num_planes &&
+                    dmabuf->num_planes < ARRAY_SIZE(dmabuf->planes); j++) {
+
+            obj_idx = desc->layers[i].object_index[j];
+            plane = &dmabuf->planes[dmabuf->num_planes++];
+            plane->drm_format = desc->layers[i].drm_format;
+            plane->offset     = desc->layers[i].offset[j];
+            plane->pitch      = desc->layers[i].pitch[j];
+            plane->fd         = desc->objects[obj_idx].fd;
+            plane->size       = desc->objects[obj_idx].size;
+            plane->modifier   = desc->objects[obj_idx].drm_format_modifier;
+        }
+    }
+}
+
+static struct virgl_video_dma_buf *export_video_dma_buf(
+                                        struct virgl_video_buffer *buffer,
+                                        unsigned flags)
+{
+    struct virgl_video_dma_buf *dmabuf;
+    uint32_t exp_flags;
+    VAStatus va_stat;
+    VADRMPRIMESurfaceDescriptor desc;
+
+    exp_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS;
+
+    if (flags & VIRGL_VIDEO_DMABUF_READ_ONLY)
+        exp_flags |= VA_EXPORT_SURFACE_READ_ONLY;
+
+    if (flags & VIRGL_VIDEO_DMABUF_WRITE_ONLY)
+        exp_flags |= VA_EXPORT_SURFACE_WRITE_ONLY;
+
+    dmabuf = calloc(1, sizeof(*dmabuf));
+    if (!dmabuf)
+        return NULL;
+
+    va_stat = vaExportSurfaceHandle(va_dpy, buffer->va_sfc,
+                    VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, exp_flags, &desc);
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("export surface failed, err = 0x%X\n", va_stat);
+        goto free_dmabuf;
+    }
+
+    fill_video_dma_buf(dmabuf, &desc);
+    dmabuf->flags = flags;
+    dmabuf->buf   = buffer;
+
+    return dmabuf;
+
+free_dmabuf:
+    free(dmabuf);
+    return NULL;
+}
+
+static void destroy_video_dma_buf(struct virgl_video_dma_buf *dmabuf)
+{
+    unsigned i;
+
+    if (dmabuf) {
+        for (i = 0; i < dmabuf->num_planes; i++)
+            close(dmabuf->planes[i].fd);
+
+        free(dmabuf);
+    }
+}
+
+static void encode_upload_picture(struct virgl_video_codec *codec,
+                                  struct virgl_video_buffer *buffer)
+{
+    VAStatus va_stat;
+
+    if (!callbacks || !callbacks->encode_upload_picture)
+        return;
+
+    va_stat = vaSyncSurface(va_dpy, buffer->va_sfc);
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("sync surface failed, err = 0x%x\n", va_stat);
+        return;
+    }
+
+    if (!buffer->dmabuf)
+        buffer->dmabuf = export_video_dma_buf(buffer, VIRGL_VIDEO_DMABUF_WRITE_ONLY);
+
+    if (buffer->dmabuf)
+        callbacks->encode_upload_picture(codec, buffer->dmabuf);
+}
+
+static void encode_completed(struct virgl_video_codec *codec,
+                             struct virgl_video_buffer *buffer)
+{
+    VAStatus va_stat;
+    VACodedBufferSegment *buf, *buf_list;
+    void **coded_bufs = NULL;
+    unsigned *coded_sizes = NULL;
+    unsigned i, num_coded_bufs = 0;
+
+    if (!callbacks || !callbacks->encode_completed)
+        return;
+
+    va_stat = vaMapBuffer(va_dpy, codec->va_coded_buf, (void **)(&buf_list));
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("map coded buffer failed, err = 0x%x\n", va_stat);
+        return;
+    }
+
+    for (buf = buf_list; buf; buf = (VACodedBufferSegment *)buf->next)
+        num_coded_bufs++;
+
+    coded_bufs = calloc(num_coded_bufs, sizeof(void *));
+    coded_sizes = calloc(num_coded_bufs, sizeof(unsigned));
+    if (!coded_bufs || !coded_sizes) {
+        virgl_log("alloc memory failed, num_coded_bufs %u\n", num_coded_bufs);
+        goto fail_unmap_buffer;
+    }
+
+    for (buf = buf_list, i = 0; buf; buf = (VACodedBufferSegment *)buf->next) {
+        coded_bufs[i]  = buf->buf;
+        coded_sizes[i++] = buf->size;
+    }
+
+    callbacks->encode_completed(codec, buffer->dmabuf, NULL, num_coded_bufs,
+                                (const void * const*)coded_bufs, coded_sizes);
+
+fail_unmap_buffer:
+    vaUnmapBuffer(va_dpy, codec->va_coded_buf);
+    free(coded_bufs);
+    free(coded_sizes);
+}
+
+static void decode_completed(struct virgl_video_codec *codec,
+                             struct virgl_video_buffer *buffer)
+{
+    if (!callbacks || !callbacks->decode_completed)
+        return;
+
+    if (!buffer->dmabuf)
+        buffer->dmabuf = export_video_dma_buf(buffer, VIRGL_VIDEO_DMABUF_READ_ONLY);
+
+    if (buffer->dmabuf)
+        callbacks->decode_completed(codec, buffer->dmabuf);
+}
+
+static VASurfaceID get_enc_ref_pic(struct virgl_video_codec *codec,
+                                   uint32_t frame_num)
+{
+    uint32_t idx;
+    struct virgl_video_create_buffer_args args;
+
+    if (frame_num == VA_INVALID_ID)
+        return VA_INVALID_ID;
+
+    idx = frame_num % ARRAY_SIZE(codec->ref_pic_list);
+
+    if (!codec->ref_pic_list[idx]) {
+        args.format = PIPE_FORMAT_NV21;
+        args.width = codec->width;
+        args.height = codec->height;
+        args.interlaced = 0;
+        args.opaque = NULL;
+        codec->ref_pic_list[idx] = virgl_video_create_buffer(&args);
+        if (!codec->ref_pic_list[idx]) {
+            virgl_log("create ref pic for frame_num %u failed\n", frame_num);
+            return VA_INVALID_ID;
+        }
+    }
+
+    return codec->ref_pic_list[idx]->va_sfc;
+}
+
+int virgl_video_init(int drm_fd,
+                     struct virgl_video_callbacks *cbs, unsigned int flags)
+{
+    VAStatus va_stat;
+    int major_ver, minor_ver;
+    const char *driver;
+
+    (void)flags;
+
+    if (drm_fd < 0) {
+        virgl_log("invalid drm fd: %d\n", drm_fd);
+        return -1;
+    }
+
+    va_dpy = vaGetDisplayDRM(drm_fd);
+    if (!va_dpy) {
+        virgl_log("get va display failed\n");
+        return -1;
+    }
+
+    va_stat = vaInitialize(va_dpy, &major_ver, &minor_ver);
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("init va library failed\n");
+        virgl_video_destroy();
+        return -1;
+    }
+
+    virgl_log("VA-API version: %d.%d\n", major_ver, minor_ver);
+
+    driver = vaQueryVendorString(va_dpy);
+    virgl_log("Driver version: %s\n", driver ? driver : "<unknown>");
+
+    if (!driver || !strstr(driver, "Mesa Gallium")) {
+        virgl_log("only supports mesa va drivers now\n");
+        virgl_video_destroy();
+        return -1;
+    }
+
+    callbacks = cbs;
+
+    return 0;
+}
+
+void virgl_video_destroy(void)
+{
+    if (va_dpy) {
+        vaTerminate(va_dpy);
+        va_dpy = NULL;
+    }
+
+    callbacks = NULL;
+}
+
+static int fill_vcaps_entry(VAProfile profile, VAEntrypoint entrypoint,
+                            struct virgl_video_caps *vcaps)
+{
+    VAConfigID cfg;
+    VASurfaceAttrib *attrs;
+    unsigned i, num_attrs;
+
+    /* FIXME: default values */
+    vcaps->profile = pipe_profile_from_va(profile);
+    vcaps->entrypoint = pipe_entrypoint_from_va(entrypoint);
+    vcaps->max_level = 0;
+    vcaps->stacked_frames = 0;
+    vcaps->max_width = 0;
+    vcaps->max_height = 0;
+    vcaps->prefered_format = PIPE_FORMAT_NONE;
+    vcaps->max_macroblocks = 1;
+    vcaps->npot_texture = 1;
+    vcaps->supports_progressive = 1;
+    vcaps->supports_interlaced = 0;
+    vcaps->prefers_interlaced = 0;
+    vcaps->max_temporal_layers = 0;
+
+    vaCreateConfig(va_dpy, profile, entrypoint, NULL, 0, &cfg);
+
+    vaQuerySurfaceAttributes(va_dpy, cfg, NULL, &num_attrs);
+    attrs = calloc(num_attrs, sizeof(VASurfaceAttrib));
+    if (!attrs)
+        return -1;
+
+    vaQuerySurfaceAttributes(va_dpy, cfg, attrs, &num_attrs);
+    for (i = 0; i < num_attrs; i++) {
+        switch (attrs[i].type) {
+        case VASurfaceAttribMaxHeight:
+            vcaps->max_height = attrs[i].value.value.i;
+            break;
+        case VASurfaceAttribMaxWidth:
+            vcaps->max_width = attrs[i].value.value.i;
+            break;
+        case VASurfaceAttribPixelFormat:
+            if (PIPE_FORMAT_NONE == vcaps->prefered_format)
+                vcaps->prefered_format = \
+                    pipe_format_from_va_fourcc(attrs[i].value.value.i);
+            break;
+        default:
+            break;
+        }
+    }
+
+    free(attrs);
+
+    vaDestroyConfig(va_dpy, cfg);
+
+    return 0;
+}
+
+int virgl_video_fill_caps(union virgl_caps *caps)
+{
+    int i, j;
+    int num_profiles, num_entrypoints;
+    VAProfile *profiles = NULL;
+    VAEntrypoint *entrypoints = NULL;
+
+    if (!va_dpy || !caps)
+        return -1;
+
+    num_entrypoints = vaMaxNumEntrypoints(va_dpy);
+    entrypoints = calloc(num_entrypoints, sizeof(VAEntrypoint));
+    if (!entrypoints)
+        return -1;
+
+    num_profiles = vaMaxNumProfiles(va_dpy);
+    profiles = calloc(num_profiles, sizeof(VAProfile));
+    if (!profiles) {
+        free(entrypoints);
+        return -1;
+    }
+
+    vaQueryConfigProfiles(va_dpy, profiles, &num_profiles);
+    for (i = 0, caps->v2.num_video_caps = 0; i < num_profiles; i++) {
+        /* only support H.264 and H.265 now */
+        if (profiles[i] != VAProfileH264Main &&
+            profiles[i] != VAProfileH264High &&
+            profiles[i] != VAProfileH264ConstrainedBaseline &&
+            profiles[i] != VAProfileHEVCMain)
+            continue;
+
+        vaQueryConfigEntrypoints(va_dpy, profiles[i],
+                                 entrypoints, &num_entrypoints);
+        for (j = 0; j < num_entrypoints &&
+             caps->v2.num_video_caps < ARRAY_SIZE(caps->v2.video_caps); j++) {
+            /* support encoding and decoding */
+            if (VAEntrypointVLD != entrypoints[j] &&
+                VAEntrypointEncSlice != entrypoints[j])
+                continue;
+
+            fill_vcaps_entry(profiles[i], entrypoints[j],
+                    &caps->v2.video_caps[caps->v2.num_video_caps++]);
+        }
+    }
+
+    free(profiles);
+    free(entrypoints);
+
+    return 0;
+}
+
+struct virgl_video_codec *virgl_video_create_codec(
+        const struct virgl_video_create_codec_args *args)
+{
+    VAStatus va_stat;
+    VAConfigID cfg;
+    VAContextID ctx;
+    VAConfigAttrib attr;
+    VAProfile profile;
+    VAEntrypoint entrypoint;
+    uint32_t format;
+    struct virgl_video_codec *codec;
+
+    if (!va_dpy || !args)
+        return NULL;
+
+    profile = va_profile_from_pipe(args->profile);
+    entrypoint = va_entrypoint_from_pipe(args->entrypoint);
+    format = va_format_from_pipe_chroma(args->chroma_format);
+    if (VAProfileNone == profile || VAEntrypointNone == entrypoint)
+        return NULL;
+
+    codec = (struct virgl_video_codec *)calloc(1, sizeof(*codec));
+    if (!codec)
+        return NULL;
+
+    attr.type = VAConfigAttribRTFormat;
+    vaGetConfigAttributes(va_dpy, profile, entrypoint, &attr, 1);
+    if (!(attr.value & format)) {
+        virgl_log("format 0x%x not supported, supported formats: 0x%x\n",
+                  format, attr.value);
+        goto err;
+    }
+
+    va_stat = vaCreateConfig(va_dpy, profile, entrypoint, &attr, 1, &cfg);
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("create config failed, err = 0x%x\n", va_stat);
+        goto err;
+    }
+    codec->va_cfg = cfg;
+
+    va_stat = vaCreateContext(va_dpy, cfg, args->width, args->height,
+                                VA_PROGRESSIVE, NULL, 0, &ctx);
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("create context failed, err = 0x%x\n", va_stat);
+        goto err;
+    }
+    codec->va_ctx = ctx;
+
+    codec->profile = args->profile;
+    codec->level = args->level;
+    codec->entrypoint = args->entrypoint;
+    codec->chroma_format = args->chroma_format;
+    codec->width = args->width;
+    codec->height = args->height;
+    codec->max_references = args->max_references;
+    codec->opaque = args->opaque;
+
+    if (entrypoint == VAEntrypointEncSlice) {
+        vaCreateBuffer(va_dpy, codec->va_ctx, VAEncCodedBufferType,
+                       CODED_BUF_DEFAULT_SIZE(codec->width, codec->height),
+                       1, NULL, &codec->va_coded_buf);
+    }
+
+    return codec;
+
+err:
+    virgl_video_destroy_codec(codec);
+
+    return NULL;
+}
+
+void virgl_video_destroy_codec(struct virgl_video_codec *codec)
+{
+    unsigned i;
+
+    if (!va_dpy || !codec)
+        return;
+
+    if (codec->va_ctx)
+        vaDestroyContext(va_dpy, codec->va_ctx);
+
+    if (codec->va_cfg)
+        vaDestroyConfig(va_dpy, codec->va_cfg);
+
+    if (codec->va_coded_buf)
+        vaDestroyBuffer(va_dpy, codec->va_coded_buf);
+
+    for (i = 0; i < ARRAY_SIZE(codec->ref_pic_list); i++) {
+        if (codec->ref_pic_list[i])
+            free(codec->ref_pic_list[i]);
+    }
+
+    free(codec);
+}
+
+struct virgl_video_buffer *virgl_video_create_buffer(
+        const struct virgl_video_create_buffer_args *args)
+{
+    VAStatus va_stat;
+    VASurfaceID sfc;
+    uint32_t format;
+    struct virgl_video_buffer *buffer;
+
+    if (!va_dpy || !args)
+        return NULL;
+
+    /*
+     * FIXME: always use YUV420 now,
+     * may be use va_format_from_pipe(args->format)
+     */
+    format = VA_RT_FORMAT_YUV420;
+    if (!format) {
+        virgl_log("pipe format %d not supported\n", args->format);
+        return NULL;
+    }
+
+    buffer = (struct virgl_video_buffer *)calloc(1, sizeof(*buffer));
+    if (!buffer)
+        return NULL;
+
+    va_stat = vaCreateSurfaces(va_dpy, format,
+                               args->width, args->height, &sfc, 1, NULL, 0);
+    if (VA_STATUS_SUCCESS != va_stat) {
+        free(buffer);
+        return NULL;
+    }
+
+    buffer->va_sfc = sfc;
+    buffer->format = args->format;
+    buffer->width  = args->width;
+    buffer->height = args->height;
+    buffer->opaque = args->opaque;
+
+    return buffer;
+}
+
+void virgl_video_destroy_buffer(struct virgl_video_buffer *buffer)
+{
+    if (!va_dpy || !buffer)
+        return;
+
+    if (buffer->dmabuf)
+        destroy_video_dma_buf(buffer->dmabuf);
+
+    if (buffer->va_sfc)
+        vaDestroySurfaces(va_dpy, &buffer->va_sfc, 1);
+
+    free(buffer);
+}
+
+void *virgl_video_codec_opaque_data(struct virgl_video_codec *codec)
+{
+    return codec ? codec->opaque : NULL;
+}
+
+enum pipe_video_profile virgl_video_codec_profile(
+        const struct virgl_video_codec *codec)
+{
+    return codec ? codec->profile : PIPE_VIDEO_PROFILE_UNKNOWN;
+}
+
+uint32_t virgl_video_buffer_id(const struct virgl_video_buffer *buffer)
+{
+    return (uint32_t)(buffer ? buffer->va_sfc : VA_INVALID_SURFACE);
+}
+
+void *virgl_video_buffer_opaque_data(struct virgl_video_buffer *buffer)
+{
+    return buffer ? buffer->opaque : NULL;
+}
+
+int virgl_video_begin_frame(struct virgl_video_codec *codec,
+                            struct virgl_video_buffer *target)
+{
+    VAStatus va_stat;
+
+    if (!va_dpy || !codec || !target)
+        return -1;
+
+    if (codec->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE)
+        encode_upload_picture(codec, target);
+
+    codec->buffer = target;
+    va_stat = vaBeginPicture(va_dpy, codec->va_ctx, target->va_sfc);
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("begin picture failed, err = 0x%x\n", va_stat);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+#define ITEM_SET(dest, src, member) \
+        (dest)->member = (src)->member
+
+#define ITEM_CPY(dest, src, member) \
+        memcpy(&(dest)->member, &(src)->member, sizeof((dest)->member))
+
+
+static void h264_init_picture(VAPictureH264 *pic)
+{
+    pic->picture_id           = VA_INVALID_SURFACE;
+    pic->frame_idx            = 0;
+    pic->flags                = VA_PICTURE_H264_INVALID;
+    pic->TopFieldOrderCnt     = 0;
+    pic->BottomFieldOrderCnt  = 0;
+}
+
+/*
+ * Refer to vlVaHandlePictureParameterBufferH264() in mesa,
+ * and comment out some unused parameters.
+ */
+static void h264_fill_picture_param(struct virgl_video_codec *codec,
+                            struct virgl_video_buffer *target,
+                            const struct virgl_h264_picture_desc *desc,
+                            VAPictureParameterBufferH264 *vapp)
+{
+    unsigned i;
+    VAPictureH264 *pic;
+
+    (void)codec;
+
+    /* CurrPic */
+    pic = &vapp->CurrPic;
+    pic->picture_id = target->va_sfc;
+    pic->frame_idx  = desc->frame_num;
+    pic->flags = desc->is_reference ? VA_PICTURE_H264_SHORT_TERM_REFERENCE : 0;
+    if (desc->field_pic_flag)
+        pic->flags |= (desc->bottom_field_flag ? VA_PICTURE_H264_BOTTOM_FIELD
+                                               : VA_PICTURE_H264_TOP_FIELD);
+    pic->TopFieldOrderCnt = desc->field_order_cnt[0];
+    pic->BottomFieldOrderCnt = desc->field_order_cnt[1];
+
+
+    /* ReferenceFrames */
+    for (i = 0; i < ARRAY_SIZE(vapp->ReferenceFrames); i++)
+        h264_init_picture(&vapp->ReferenceFrames[i]);
+
+    for (i = 0; i < desc->num_ref_frames; i++) {
+        pic = &vapp->ReferenceFrames[i];
+
+        pic->picture_id = desc->buffer_id[i];
+        pic->frame_idx  = desc->frame_num_list[i];
+        pic->flags = (desc->is_long_term[i]
+                      ? VA_PICTURE_H264_LONG_TERM_REFERENCE
+                      : VA_PICTURE_H264_SHORT_TERM_REFERENCE);
+        if (desc->top_is_reference[i] && desc->bottom_is_reference[i]) {
+            // Full frame. This block intentionally left blank. No flags set.
+        } else {
+            if (desc->top_is_reference[i])
+                pic->flags |= VA_PICTURE_H264_TOP_FIELD;
+            else
+                pic->flags |= VA_PICTURE_H264_BOTTOM_FIELD;
+        }
+        pic->TopFieldOrderCnt = desc->field_order_cnt_list[i][0];
+        pic->BottomFieldOrderCnt = desc->field_order_cnt_list[i][1];
+    }
+
+    //vapp->picture_width_in_mbs_minus1  = (codec->width - 1) / 16;
+    //vapp->picture_height_in_mbs_minus1 = (codec->height - 1) / 16;
+    ITEM_SET(vapp, &desc->pps.sps, bit_depth_luma_minus8);
+    ITEM_SET(vapp, &desc->pps.sps, bit_depth_chroma_minus8);
+    ITEM_SET(vapp, desc, num_ref_frames);
+
+    ITEM_SET(&vapp->seq_fields.bits, &desc->pps.sps, chroma_format_idc);
+    //vapp->seq_fields.bits.residual_colour_transform_flag       = 0;
+    //vapp->seq_fields.bits.gaps_in_frame_num_value_allowed_flag = 0;
+    ITEM_SET(&vapp->seq_fields.bits, &desc->pps.sps, frame_mbs_only_flag);
+    ITEM_SET(&vapp->seq_fields.bits,
+             &desc->pps.sps, mb_adaptive_frame_field_flag);
+    ITEM_SET(&vapp->seq_fields.bits, &desc->pps.sps, direct_8x8_inference_flag);
+    ITEM_SET(&vapp->seq_fields.bits, &desc->pps.sps, MinLumaBiPredSize8x8);
+    ITEM_SET(&vapp->seq_fields.bits, &desc->pps.sps, log2_max_frame_num_minus4);
+    ITEM_SET(&vapp->seq_fields.bits, &desc->pps.sps, pic_order_cnt_type);
+    ITEM_SET(&vapp->seq_fields.bits,
+             &desc->pps.sps, log2_max_pic_order_cnt_lsb_minus4);
+    ITEM_SET(&vapp->seq_fields.bits,
+             &desc->pps.sps, delta_pic_order_always_zero_flag);
+
+    //ITEM_SET(vapp, &desc->pps, num_slice_groups_minus1);
+    //ITEM_SET(vapp, &desc->pps, slice_group_map_type);
+    //ITEM_SET(vapp, &desc->pps, slice_group_change_rate_minus1);
+    ITEM_SET(vapp, &desc->pps, pic_init_qp_minus26);
+    ITEM_SET(vapp, &desc->pps, pic_init_qs_minus26);
+    ITEM_SET(vapp, &desc->pps, chroma_qp_index_offset);
+    ITEM_SET(vapp, &desc->pps, second_chroma_qp_index_offset);
+
+    ITEM_SET(&vapp->pic_fields.bits, &desc->pps, entropy_coding_mode_flag);
+    ITEM_SET(&vapp->pic_fields.bits, &desc->pps, weighted_pred_flag);
+    ITEM_SET(&vapp->pic_fields.bits, &desc->pps, weighted_bipred_idc);
+    ITEM_SET(&vapp->pic_fields.bits, &desc->pps, transform_8x8_mode_flag);
+    ITEM_SET(&vapp->pic_fields.bits, desc,       field_pic_flag);
+    ITEM_SET(&vapp->pic_fields.bits, &desc->pps, constrained_intra_pred_flag);
+    vapp->pic_fields.bits.pic_order_present_flag =
+             desc->pps.bottom_field_pic_order_in_frame_present_flag;
+    ITEM_SET(&vapp->pic_fields.bits,
+             &desc->pps, deblocking_filter_control_present_flag);
+    ITEM_SET(&vapp->pic_fields.bits,
+             &desc->pps, redundant_pic_cnt_present_flag);
+    vapp->pic_fields.bits.reference_pic_flag = desc->is_reference;
+
+    ITEM_SET(vapp, desc, frame_num);
+}
+
+
+ /* Refer to vlVaHandleIQMatrixBufferH264() in mesa */
+static void h264_fill_iq_matrix(const struct virgl_h264_picture_desc *desc,
+                                VAIQMatrixBufferH264 *vaiqm)
+{
+    ITEM_CPY(vaiqm, &desc->pps, ScalingList4x4);
+    ITEM_CPY(vaiqm, &desc->pps, ScalingList8x8);
+}
+
+/*
+ * Refer to vlVaHandleSliceParameterBufferH264() in mesa,
+ * and comment out some unused parameters.
+ */
+static void h264_fill_slice_param(const struct virgl_h264_picture_desc *desc,
+                                  VASliceParameterBufferH264 *vasp)
+{
+    //vasp->slice_data_size;
+    //vasp->slice_data_offset;
+    //vasp->slice_data_flag;
+    //vasp->slice_data_bit_offset;
+    //vasp->first_mb_in_slice;
+    //vasp->slice_type;
+    //vasp->direct_spatial_mv_pred_flag;
+    ITEM_SET(vasp, desc, num_ref_idx_l0_active_minus1);
+    ITEM_SET(vasp, desc, num_ref_idx_l1_active_minus1);
+    //vasp->cabac_init_idc;
+    //vasp->slice_qp_delta;
+    //vasp->disable_deblocking_filter_idc;
+    //vasp->slice_alpha_c0_offset_div2;
+    //vasp->slice_beta_offset_div2;
+    //vasp->RefPicList0[32];
+    //vasp->RefPicList1[32];
+
+    /* see pred_weight_table */
+    //vasp->luma_log2_weight_denom;
+    //vasp->chroma_log2_weight_denom;
+    //vasp->luma_weight_l0_flag;
+    //vasp->luma_weight_l0[32];
+    //vasp->luma_offset_l0[32];
+    //vasp->chroma_weight_l0_flag;
+    //vasp->chroma_weight_l0[32][2];
+    //vasp->chroma_offset_l0[32][2];
+    //vasp->luma_weight_l1_flag;
+    //vasp->luma_weight_l1[32];
+    //vasp->luma_offset_l1[32];
+    //vasp->chroma_weight_l1_flag;
+    //vasp->chroma_weight_l1[32][2];
+    //vasp->chroma_offset_l1[32][2];
+}
+
+/*
+ * Refer to vlVaHandleVAEncPictureParameterBufferTypeH264() in mesa,
+ * and comment out some unused parameters.
+ */
+static void h264_fill_enc_picture_param(
+                            struct virgl_video_codec *codec,
+                            struct virgl_video_buffer *source,
+                            const struct virgl_h264_enc_picture_desc *desc,
+                            VAEncPictureParameterBufferH264 *param)
+{
+    unsigned i;
+
+    (void)codec;
+    (void)source;
+
+    /* CurrPic */
+    param->CurrPic.picture_id = get_enc_ref_pic(codec, desc->frame_num);
+    //CurrPic.frame_idx;
+    //CurrPic.flags;
+    param->CurrPic.TopFieldOrderCnt = desc->pic_order_cnt;
+    //CurrPic.BottomFieldOrderCnt;
+
+    /* ReferenceFrames */
+    for (i = 0; i < ARRAY_SIZE(param->ReferenceFrames); i++)
+        h264_init_picture(&param->ReferenceFrames[i]);
+
+    /* coded_buf */
+    param->coded_buf = codec->va_coded_buf;
+
+    //pic_parameter_set_id;
+    //seq_parameter_set_id;
+    //last_picture;
+    //frame_num
+    param->pic_init_qp = desc->quant_i_frames;
+    param->num_ref_idx_l0_active_minus1 = desc->num_ref_idx_l0_active_minus1;
+    param->num_ref_idx_l1_active_minus1 = desc->num_ref_idx_l1_active_minus1;
+    //chroma_qp_index_offset;
+    //second_chroma_qp_index_offset;
+
+    /* pic_fields */
+    param->pic_fields.bits.idr_pic_flag =
+                      (desc->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR);
+    param->pic_fields.bits.reference_pic_flag = !desc->not_referenced;
+    param->pic_fields.bits.entropy_coding_mode_flag = desc->pic_ctrl.enc_cabac_enable;
+    //pic_fields.bits.weighted_pred_flag
+    //pic_fields.bits.weighted_bipred_idc
+    //pic_fields.bits.constrained_intra_pred_flag
+    //pic_fields.bits.transform_8x8_mode_flag
+    //pic_fields.bits.deblocking_filter_control_present_flag
+    //pic_fields.bits.redundant_pic_cnt_present_flag
+    //pic_fields.bits.pic_order_present_flag
+    //pic_fields.bits.pic_scaling_matrix_present_flag
+
+}
+
+/*
+ * Refer to vlVaHandleVAEncSliceParameterBufferTypeH264() in mesa,
+ * and comment out some unused parameters.
+ */
+static void h264_fill_enc_slice_param(
+                            struct virgl_video_codec *codec,
+                            struct virgl_video_buffer *source,
+                            const struct virgl_h264_enc_picture_desc *desc,
+                            VAEncSliceParameterBufferH264 *param)
+{
+    unsigned i;
+    const struct virgl_h264_slice_descriptor *sd;
+
+    (void)codec;
+    (void)source;
+
+    /* Get the lastest slice descriptor */
+    if (desc->num_slice_descriptors &&
+        desc->num_slice_descriptors <= ARRAY_SIZE(desc->slices_descriptors)) {
+        sd = &desc->slices_descriptors[desc->num_slice_descriptors - 1];
+        param->macroblock_address = sd->macroblock_address;
+        param->num_macroblocks    = sd->num_macroblocks;
+        //macroblock_info;
+    }
+
+    switch (desc->picture_type) {
+    case PIPE_H2645_ENC_PICTURE_TYPE_P:
+        param->slice_type = 0;
+        break;
+    case PIPE_H2645_ENC_PICTURE_TYPE_B:
+        param->slice_type = 1;
+        break;
+    case PIPE_H2645_ENC_PICTURE_TYPE_I:
+    case PIPE_H2645_ENC_PICTURE_TYPE_IDR: /* fall through */
+        param->slice_type = 2;
+        break;
+    case PIPE_H2645_ENC_PICTURE_TYPE_SKIP:
+    default:
+        break;
+    }
+
+    //pic_parameter_set_id;
+    //idr_pic_id;
+    //pic_order_cnt_lsb;
+    //delta_pic_order_cnt_bottom;
+    //delta_pic_order_cnt[2];
+    //direct_spatial_mv_pred_flag;
+
+    /*
+     * Sine num_ref_idx_l0_active_minus1 and num_ref_idx_l1_active_minus1
+     * have been passed by VAEncPictureParameterBufferH264,
+     * num_ref_idx_active_override_flag is always set to 0.
+     */
+    param->num_ref_idx_active_override_flag = 0;
+    //num_ref_idx_l0_active_minus1
+    //num_ref_idx_l1_active_minus1
+
+    /* Reference List */
+    for (i = 0; i < 32; i++) {
+        h264_init_picture(&param->RefPicList0[i]);
+        h264_init_picture(&param->RefPicList1[i]);
+
+        param->RefPicList0[i].picture_id =
+                    get_enc_ref_pic(codec, desc->ref_idx_l0_list[i]);
+        param->RefPicList1[i].picture_id =
+                    get_enc_ref_pic(codec, desc->ref_idx_l1_list[i]);
+
+        if (param->RefPicList0[i].picture_id != VA_INVALID_ID)
+            param->RefPicList0[i].flags = VA_PICTURE_H264_SHORT_TERM_REFERENCE;
+
+        if (param->RefPicList1[i].picture_id != VA_INVALID_ID)
+            param->RefPicList1[i].flags = VA_PICTURE_H264_SHORT_TERM_REFERENCE;
+    }
+
+    //luma_log2_weight_denom;
+    //chroma_log2_weight_denom;
+    //luma_weight_l0_flag;
+    //luma_weight_l0[32];
+    //luma_offset_l0[32];
+    //chroma_weight_l0_flag;
+    //chroma_weight_l0[32][2];
+    //chroma_offset_l0[32][2];
+    //luma_weight_l1_flag;
+    //luma_weight_l1[32];
+    //luma_offset_l1[32];
+    //chroma_weight_l1_flag;
+    //chroma_weight_l1[32][2];
+    //chroma_offset_l1[32][2];
+    param->cabac_init_idc = desc->pic_ctrl.enc_cabac_init_idc;
+    //slice_qp_delta;
+    //disable_deblocking_filter_idc;
+    //slice_alpha_c0_offset_div2;
+    //slice_beta_offset_div2;
+
+}
+
+/*
+ * Refer to vlVaHandleVAEncSequenceParameterBufferTypeH264() in mesa,
+ * and comment out some unused parameters.
+ */
+static void h264_fill_enc_seq_param(
+                            struct virgl_video_codec *codec,
+                            struct virgl_video_buffer *source,
+                            const struct virgl_h264_enc_picture_desc *desc,
+                            VAEncSequenceParameterBufferH264 *param)
+{
+    (void)codec;
+    (void)source;
+
+    //seq_parameter_set_id;
+    param->level_idc = codec->level;
+    //intra_period;
+    param->intra_idr_period = desc->intra_idr_period;
+    //ip_period;
+    //bits_per_second;
+    param->max_num_ref_frames = codec->max_references;
+    //picture_width_in_mbs;
+    //picture_height_in_mbs;
+
+    /* seq_fields.bits */
+    //seq_fields.bits.chroma_format_idc
+    //seq_fields.bits.frame_mbs_only_flag
+    //seq_fields.bits.mb_adaptive_frame_field_flag
+    //seq_fields.bits.seq_scaling_matrix_present_flag
+    //seq_fields.bits.direct_8x8_inference_flag
+    //seq_fields.bits.log2_max_frame_num_minus4
+    ITEM_SET(&param->seq_fields.bits, &desc->seq, pic_order_cnt_type);
+    //seq_fields.bit.log2_max_pic_order_cnt_lsb_minus4
+    //seq_fields.bit.delta_pic_order_always_zero_flag
+
+    //bit_depth_luma_minus8;
+    //bit_depth_chroma_minus8;
+
+    //num_ref_frames_in_pic_order_cnt_cycle;
+    //offset_for_non_ref_pic;
+    //offset_for_top_to_bottom_field;
+    //offset_for_ref_frame[256];
+    if (desc->seq.enc_frame_cropping_flag) {
+        param->frame_cropping_flag      = desc->seq.enc_frame_cropping_flag;
+        param->frame_crop_left_offset   = desc->seq.enc_frame_crop_left_offset;
+        param->frame_crop_right_offset  = desc->seq.enc_frame_crop_right_offset;
+        param->frame_crop_top_offset    = desc->seq.enc_frame_crop_top_offset;
+        param->frame_crop_bottom_offset = desc->seq.enc_frame_crop_bottom_offset;
+    }
+
+    ITEM_SET(param, &desc->seq, vui_parameters_present_flag);
+
+    // vui_fields.bits
+    if (desc->seq.vui_parameters_present_flag) {
+        ITEM_SET(&param->vui_fields.bits, &desc->seq.vui_flags,
+                 aspect_ratio_info_present_flag);
+        ITEM_SET(&param->vui_fields.bits, &desc->seq.vui_flags,
+                 timing_info_present_flag);
+    }
+    //vui_fields.bits.bitstream_restriction_flag
+    //vui_fields.bits.log2_max_mv_length_horizontal
+    //vui_fields.bits.log2_max_mv_length_vertical
+    //vui_fields.bits.fixed_frame_rate_flag
+    //vui_fields.bits.low_delay_hrd_flag
+    //vui_fields.bits.motion_vectors_over_pic_boundaries_flag
+
+    if (desc->seq.vui_parameters_present_flag) {
+        ITEM_SET(param, &desc->seq, aspect_ratio_idc);
+        ITEM_SET(param, &desc->seq, sar_width);
+        ITEM_SET(param, &desc->seq, sar_height);
+    }
+    ITEM_SET(param, &desc->seq, num_units_in_tick);
+    ITEM_SET(param, &desc->seq, time_scale);
+}
+
+/*
+ * Refer to vlVaHandleVAEncMiscParameterTypeRateControlH264() in mesa,
+ * and comment out some unused parameters.
+ */
+static void h264_fill_enc_misc_param_rate_ctrl(
+                            struct virgl_video_codec *codec,
+                            struct virgl_video_buffer *source,
+                            const struct virgl_h264_enc_picture_desc *desc,
+                            VAEncMiscParameterRateControl *param)
+{
+    unsigned temporal_id = 0; /* always 0 now */
+    const struct virgl_h264_enc_rate_control *rc = &desc->rate_ctrl[temporal_id];
+
+    (void)codec;
+    (void)source;
+
+    param->bits_per_second = rc->peak_bitrate;
+    if (desc->rate_ctrl[0].rate_ctrl_method !=
+        PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT) {
+        param->target_percentage = rc->target_bitrate *
+                                   param->bits_per_second / 100.0;
+    }
+    //window_size;
+    //initial_qp;
+    param->min_qp = rc->min_qp;
+    //basic_unit_size;
+
+    /* rc_flags */
+    //rc_flags.bits.reset
+    param->rc_flags.bits.disable_frame_skip = !rc->skip_frame_enable;
+    param->rc_flags.bits.disable_bit_stuffing = !rc->fill_data_enable;
+    //rc_flags.bits.mb_rate_control
+    param->rc_flags.bits.temporal_id = temporal_id;
+    //rc_flags.bits.cfs_I_frames
+    //rc_flags.bits.enable_parallel_brc
+    //rc_flags.bits.enable_dynamic_scaling
+    //rc_flags.bits.frame_tolerance_mode
+
+    //ICQ_quality_factor;
+    param->max_qp = rc->max_qp;
+    //quality_factor;
+    //target_frame_size;
+}
+
+/*
+ * Refer to vlVaHandleVAEncMiscParameterTypeFrameRateH264() in mesa,
+ * and comment out some unused parameters.
+ */
+static void h264_fill_enc_misc_param_frame_rate(
+                            struct virgl_video_codec *codec,
+                            struct virgl_video_buffer *source,
+                            const struct virgl_h264_enc_picture_desc *desc,
+                            VAEncMiscParameterFrameRate *param)
+{
+    unsigned temporal_id = 0; /* always 0 now */
+    const struct virgl_h264_enc_rate_control *rc = &desc->rate_ctrl[temporal_id];
+
+    (void)codec;
+    (void)source;
+
+    param->framerate = rc->frame_rate_num | (rc->frame_rate_den << 16);
+    param->framerate_flags.bits.temporal_id = temporal_id;
+}
+
+static int h264_decode_bitstream(struct virgl_video_codec *codec,
+                                 struct virgl_video_buffer *target,
+                                 const struct virgl_h264_picture_desc *desc,
+                                 unsigned num_buffers,
+                                 const void * const *buffers,
+                                 const unsigned *sizes)
+{
+    unsigned i;
+    int err = 0;
+    VAStatus va_stat;
+    VABufferID *slice_data_buf, pic_param_buf, iq_matrix_buf, slice_param_buf;
+    VAPictureParameterBufferH264 pic_param;
+    VAIQMatrixBufferH264 iq_matrix;
+    VASliceParameterBufferH264 slice_param;
+
+    slice_data_buf = calloc(num_buffers, sizeof(VABufferID));
+    if (!slice_data_buf) {
+        virgl_log("alloc slice data buffer id failed\n");
+        return -1;
+    }
+
+    h264_fill_picture_param(codec, target, desc, &pic_param);
+    vaCreateBuffer(va_dpy, codec->va_ctx, VAPictureParameterBufferType,
+                   sizeof(pic_param), 1, &pic_param, &pic_param_buf);
+
+    h264_fill_iq_matrix(desc, &iq_matrix);
+    vaCreateBuffer(va_dpy, codec->va_ctx, VAIQMatrixBufferType,
+                   sizeof(iq_matrix), 1, &iq_matrix, &iq_matrix_buf);
+
+    h264_fill_slice_param(desc, &slice_param);
+    vaCreateBuffer(va_dpy, codec->va_ctx, VASliceParameterBufferType,
+                   sizeof(slice_param), 1, &slice_param, &slice_param_buf);
+
+    for (i = 0; i < num_buffers; i++) {
+        vaCreateBuffer(va_dpy, codec->va_ctx, VASliceDataBufferType,
+                      sizes[i], 1, (void *)(buffers[i]), &slice_data_buf[i]);
+    }
+
+    va_stat = vaRenderPicture(va_dpy, codec->va_ctx, &pic_param_buf, 1);
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("render picture param failed, err = 0x%x\n", va_stat);
+        err = -1;
+        goto err;
+    }
+
+    va_stat = vaRenderPicture(va_dpy, codec->va_ctx, &iq_matrix_buf, 1);
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("render iq matrix failed, err = 0x%x\n", va_stat);
+        err = -1;
+        goto err;
+    }
+
+    va_stat = vaRenderPicture(va_dpy, codec->va_ctx, &slice_param_buf, 1);
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("render slice param failed, err = 0x%x\n", va_stat);
+        err = -1;
+        goto err;
+    }
+
+    for (i = 0; i < num_buffers; i++) {
+        va_stat = vaRenderPicture(va_dpy, codec->va_ctx, &slice_data_buf[i], 1);
+
+        if (VA_STATUS_SUCCESS != va_stat) {
+            virgl_log("render slice data failed, err = 0x%x\n", va_stat);
+            err = -1;
+        }
+    }
+
+err:
+    vaDestroyBuffer(va_dpy, pic_param_buf);
+    vaDestroyBuffer(va_dpy, iq_matrix_buf);
+    vaDestroyBuffer(va_dpy, slice_param_buf);
+    for (i = 0; i < num_buffers; i++)
+        vaDestroyBuffer(va_dpy, slice_data_buf[i]);
+    free(slice_data_buf);
+
+    return err;
+}
+
+static int h264_encode_render_sequence(
+                            struct virgl_video_codec *codec,
+                            struct virgl_video_buffer *source,
+                            const struct virgl_h264_enc_picture_desc *desc)
+{
+    int err = 0;
+    VAStatus va_stat;
+    VAEncSequenceParameterBufferH264 seq_param;
+    VAEncMiscParameterBuffer *misc_param;
+    VABufferID seq_param_buf, rc_param_buf, fr_param_buf;
+
+    memset(&seq_param, 0, sizeof(seq_param));
+    h264_fill_enc_seq_param(codec, source, desc, &seq_param);
+    vaCreateBuffer(va_dpy, codec->va_ctx, VAEncSequenceParameterBufferType,
+                   sizeof(seq_param), 1, &seq_param, &seq_param_buf);
+
+    vaCreateBuffer(va_dpy, codec->va_ctx, VAEncMiscParameterBufferType,
+                   sizeof(VAEncMiscParameterBuffer) +
+                   sizeof(VAEncMiscParameterRateControl), 1, NULL, &rc_param_buf);
+    vaMapBuffer(va_dpy, rc_param_buf, (void **)&misc_param);
+    misc_param->type = VAEncMiscParameterTypeRateControl;
+    h264_fill_enc_misc_param_rate_ctrl(codec, source, desc,
+                    (VAEncMiscParameterRateControl *)misc_param->data);
+    vaUnmapBuffer(va_dpy, rc_param_buf);
+
+    vaCreateBuffer(va_dpy, codec->va_ctx, VAEncMiscParameterBufferType,
+                   sizeof(VAEncMiscParameterBuffer) +
+                   sizeof(VAEncMiscParameterFrameRate), 1, NULL, &fr_param_buf);
+    vaMapBuffer(va_dpy, fr_param_buf, (void **)&misc_param);
+    misc_param->type = VAEncMiscParameterTypeFrameRate;
+    h264_fill_enc_misc_param_frame_rate(codec, source, desc,
+                    (VAEncMiscParameterFrameRate *)misc_param->data);
+    vaUnmapBuffer(va_dpy, fr_param_buf);
+
+    va_stat = vaRenderPicture(va_dpy, codec->va_ctx, &seq_param_buf, 1);
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("render h264 sequence param failed, err = 0x%x\n", va_stat);
+        err = -1;
+        goto error;
+    }
+
+    va_stat = vaRenderPicture(va_dpy, codec->va_ctx, &rc_param_buf, 1);
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("render h264 rate control param failed, err = 0x%x\n", va_stat);
+        err = -1;
+        goto error;
+    }
+
+    va_stat = vaRenderPicture(va_dpy, codec->va_ctx, &fr_param_buf, 1);
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("render h264 frame rate param failed, err = 0x%x\n", va_stat);
+        err = -1;
+        goto error;
+    }
+
+error:
+    vaDestroyBuffer(va_dpy, seq_param_buf);
+    vaDestroyBuffer(va_dpy, rc_param_buf);
+    vaDestroyBuffer(va_dpy, fr_param_buf);
+
+    return err;
+}
+
+static int h264_encode_render_picture(
+                            struct virgl_video_codec *codec,
+                            struct virgl_video_buffer *source,
+                            const struct virgl_h264_enc_picture_desc *desc)
+{
+    VAStatus va_stat;
+    VABufferID pic_param_buf;
+    VAEncPictureParameterBufferH264 pic_param;
+
+    memset(&pic_param, 0, sizeof(pic_param));
+    h264_fill_enc_picture_param(codec, source, desc, &pic_param);
+    vaCreateBuffer(va_dpy, codec->va_ctx, VAEncPictureParameterBufferType,
+                   sizeof(pic_param), 1, &pic_param, &pic_param_buf);
+
+    va_stat = vaRenderPicture(va_dpy, codec->va_ctx, &pic_param_buf, 1);
+    vaDestroyBuffer(va_dpy, pic_param_buf);
+
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("render h264 picture param failed, err = 0x%x\n", va_stat);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int h264_encode_render_slice(
+                            struct virgl_video_codec *codec,
+                            struct virgl_video_buffer *source,
+                            const struct virgl_h264_enc_picture_desc *desc)
+{
+    VAStatus va_stat;
+    VABufferID slice_param_buf;
+    VAEncSliceParameterBufferH264 slice_param;
+
+    memset(&slice_param, 0, sizeof(slice_param));
+    h264_fill_enc_slice_param(codec, source, desc, &slice_param);
+    vaCreateBuffer(va_dpy, codec->va_ctx, VAEncSliceParameterBufferType,
+                   sizeof(slice_param), 1, &slice_param, &slice_param_buf);
+
+    va_stat = vaRenderPicture(va_dpy, codec->va_ctx, &slice_param_buf, 1);
+    vaDestroyBuffer(va_dpy, slice_param_buf);
+
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("render h264 slice param failed, err = 0x%x\n", va_stat);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int h264_encode_bitstream(
+                            struct virgl_video_codec *codec,
+                            struct virgl_video_buffer *source,
+                            const struct virgl_h264_enc_picture_desc *desc)
+{
+    if (desc->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR) {
+        h264_encode_render_sequence(codec, source, desc);
+    }
+
+    h264_encode_render_picture(codec, source, desc);
+    h264_encode_render_slice(codec, source, desc);
+
+    return 0;
+}
+
+static void h265_init_picture(VAPictureHEVC *pic)
+{
+    pic->picture_id     = VA_INVALID_SURFACE;
+    pic->pic_order_cnt  = 0;
+    pic->flags          = VA_PICTURE_HEVC_INVALID;
+}
+
+/*
+ * Refer to vlVaHandlePictureParameterBufferHEVC() in mesa,
+ * and comment out some unused parameters.
+ */
+static void h265_fill_picture_param(struct virgl_video_codec *codec,
+                            struct virgl_video_buffer *target,
+                            const struct virgl_h265_picture_desc *desc,
+                            VAPictureParameterBufferHEVC *vapp)
+{
+    unsigned i;
+
+    (void)codec;
+    (void)target;
+
+    //vapp->CurrPic.picture_id
+    vapp->CurrPic.pic_order_cnt = desc->CurrPicOrderCntVal;
+    //vapp->CurrPic.flags
+
+    for (i = 0; i < 15; i++) {
+        vapp->ReferenceFrames[i].pic_order_cnt = desc->PicOrderCntVal[i];
+        vapp->ReferenceFrames[i].picture_id = desc->ref[i];
+        vapp->ReferenceFrames[i].flags = VA_INVALID_SURFACE == desc->ref[i]
+                                       ? VA_PICTURE_HEVC_INVALID : 0;
+    }
+    for (i = 0; i < desc->NumPocStCurrBefore; i++)
+        vapp->ReferenceFrames[desc->RefPicSetStCurrBefore[i]].flags |= \
+                VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE;
+    for (i = 0; i < desc->NumPocStCurrAfter; i++)
+        vapp->ReferenceFrames[desc->RefPicSetStCurrAfter[i]].flags |= \
+                VA_PICTURE_HEVC_RPS_ST_CURR_AFTER;
+    for (i = 0; i < desc->NumPocLtCurr; i++)
+        vapp->ReferenceFrames[desc->RefPicSetLtCurr[i]].flags |= \
+                VA_PICTURE_HEVC_RPS_LT_CURR;
+
+    ITEM_SET(vapp, &desc->pps.sps, pic_width_in_luma_samples);
+    ITEM_SET(vapp, &desc->pps.sps, pic_height_in_luma_samples);
+
+    ITEM_SET(&vapp->pic_fields.bits, &desc->pps.sps, chroma_format_idc);
+    ITEM_SET(&vapp->pic_fields.bits,
+             &desc->pps.sps, separate_colour_plane_flag);
+    ITEM_SET(&vapp->pic_fields.bits, &desc->pps.sps, pcm_enabled_flag);
+    ITEM_SET(&vapp->pic_fields.bits,
+             &desc->pps.sps, scaling_list_enabled_flag);
+    ITEM_SET(&vapp->pic_fields.bits,
+             &desc->pps, transform_skip_enabled_flag);
+    ITEM_SET(&vapp->pic_fields.bits, &desc->pps.sps, amp_enabled_flag);
+    ITEM_SET(&vapp->pic_fields.bits,
+             &desc->pps.sps, strong_intra_smoothing_enabled_flag);
+    ITEM_SET(&vapp->pic_fields.bits, &desc->pps, sign_data_hiding_enabled_flag);
+    ITEM_SET(&vapp->pic_fields.bits, &desc->pps, constrained_intra_pred_flag);
+    ITEM_SET(&vapp->pic_fields.bits, &desc->pps, cu_qp_delta_enabled_flag);
+    ITEM_SET(&vapp->pic_fields.bits, &desc->pps, weighted_pred_flag);
+    ITEM_SET(&vapp->pic_fields.bits, &desc->pps, weighted_bipred_flag);
+    ITEM_SET(&vapp->pic_fields.bits,
+             &desc->pps, transquant_bypass_enabled_flag);
+    ITEM_SET(&vapp->pic_fields.bits, &desc->pps, tiles_enabled_flag);
+    ITEM_SET(&vapp->pic_fields.bits,
+             &desc->pps, entropy_coding_sync_enabled_flag);
+    ITEM_SET(&vapp->pic_fields.bits, &desc->pps,
+             pps_loop_filter_across_slices_enabled_flag);
+    if (desc->pps.tiles_enabled_flag)
+        ITEM_SET(&vapp->pic_fields.bits,
+                 &desc->pps, loop_filter_across_tiles_enabled_flag);
+    if (desc->pps.sps.pcm_enabled_flag)
+        ITEM_SET(&vapp->pic_fields.bits,
+                 &desc->pps.sps, pcm_loop_filter_disabled_flag);
+    //ITEM_SET(vapp->pic_fields.bits, desc->pps.sps, NoPicReorderingFlag);
+    //ITEM_SET(vapp->pic_fields.bits, desc->pps.sps, NoBiPredFlag);
+
+    ITEM_SET(vapp, &desc->pps.sps, sps_max_dec_pic_buffering_minus1);
+    ITEM_SET(vapp, &desc->pps.sps, bit_depth_luma_minus8);
+    ITEM_SET(vapp, &desc->pps.sps, bit_depth_chroma_minus8);
+    if (desc->pps.sps.pcm_enabled_flag) {
+        ITEM_SET(vapp, &desc->pps.sps, pcm_sample_bit_depth_luma_minus1);
+        ITEM_SET(vapp, &desc->pps.sps, pcm_sample_bit_depth_chroma_minus1);
+    }
+    ITEM_SET(vapp, &desc->pps.sps, log2_min_luma_coding_block_size_minus3);
+    ITEM_SET(vapp, &desc->pps.sps, log2_diff_max_min_luma_coding_block_size);
+    ITEM_SET(vapp, &desc->pps.sps, log2_min_transform_block_size_minus2);
+    ITEM_SET(vapp, &desc->pps.sps, log2_diff_max_min_transform_block_size);
+    if (desc->pps.sps.pcm_enabled_flag) {
+        ITEM_SET(vapp, &desc->pps.sps,
+                 log2_min_pcm_luma_coding_block_size_minus3);
+        ITEM_SET(vapp, &desc->pps.sps,
+                 log2_diff_max_min_pcm_luma_coding_block_size);
+    }
+    ITEM_SET(vapp, &desc->pps.sps, max_transform_hierarchy_depth_intra);
+    ITEM_SET(vapp, &desc->pps.sps, max_transform_hierarchy_depth_inter);
+    ITEM_SET(vapp, &desc->pps, init_qp_minus26);
+    ITEM_SET(vapp, &desc->pps, diff_cu_qp_delta_depth);
+    ITEM_SET(vapp, &desc->pps, pps_cb_qp_offset);
+    ITEM_SET(vapp, &desc->pps, pps_cr_qp_offset);
+    ITEM_SET(vapp, &desc->pps, log2_parallel_merge_level_minus2);
+    if (desc->pps.tiles_enabled_flag) {
+        ITEM_SET(vapp, &desc->pps, num_tile_columns_minus1);
+        ITEM_SET(vapp, &desc->pps, num_tile_rows_minus1);
+        ITEM_CPY(vapp, &desc->pps, column_width_minus1);
+        ITEM_CPY(vapp, &desc->pps, row_height_minus1);
+    }
+
+    ITEM_SET(&vapp->slice_parsing_fields.bits,
+             &desc->pps, lists_modification_present_flag);
+    ITEM_SET(&vapp->slice_parsing_fields.bits,
+             &desc->pps.sps, long_term_ref_pics_present_flag);
+    ITEM_SET(&vapp->slice_parsing_fields.bits,
+             &desc->pps.sps, sps_temporal_mvp_enabled_flag);
+    ITEM_SET(&vapp->slice_parsing_fields.bits,
+             &desc->pps, cabac_init_present_flag);
+    ITEM_SET(&vapp->slice_parsing_fields.bits,
+             &desc->pps, output_flag_present_flag);
+    ITEM_SET(&vapp->slice_parsing_fields.bits,
+             &desc->pps, dependent_slice_segments_enabled_flag);
+    ITEM_SET(&vapp->slice_parsing_fields.bits,
+             &desc->pps, pps_slice_chroma_qp_offsets_present_flag);
+    ITEM_SET(&vapp->slice_parsing_fields.bits,
+             &desc->pps.sps, sample_adaptive_offset_enabled_flag);
+    ITEM_SET(&vapp->slice_parsing_fields.bits,
+             &desc->pps, deblocking_filter_override_enabled_flag);
+    vapp->slice_parsing_fields.bits.pps_disable_deblocking_filter_flag = \
+             desc->pps.pps_deblocking_filter_disabled_flag;
+    ITEM_SET(&vapp->slice_parsing_fields.bits,
+             &desc->pps, slice_segment_header_extension_present_flag);
+    vapp->slice_parsing_fields.bits.RapPicFlag = desc->RAPPicFlag;
+    vapp->slice_parsing_fields.bits.IdrPicFlag = desc->IDRPicFlag;
+    //vapp->slice_parsing_fields.bits.IntraPicFlag
+
+    ITEM_SET(vapp, &desc->pps.sps, log2_max_pic_order_cnt_lsb_minus4);
+    ITEM_SET(vapp, &desc->pps.sps, num_short_term_ref_pic_sets);
+    vapp->num_long_term_ref_pic_sps = desc->pps.sps.num_long_term_ref_pics_sps;
+    ITEM_SET(vapp, &desc->pps, num_ref_idx_l0_default_active_minus1);
+    ITEM_SET(vapp, &desc->pps, num_ref_idx_l1_default_active_minus1);
+    ITEM_SET(vapp, &desc->pps, pps_beta_offset_div2);
+    ITEM_SET(vapp, &desc->pps, pps_tc_offset_div2);
+    ITEM_SET(vapp, &desc->pps, num_extra_slice_header_bits);
+
+    ITEM_SET(vapp, &desc->pps, st_rps_bits);
+}
+
+/*
+ * Refer to vlVaHandleSliceParameterBufferHEVC() in mesa,
+ * and comment out some unused parameters.
+ */
+static void h265_fill_slice_param(const struct virgl_h265_picture_desc *desc,
+                                  VASliceParameterBufferHEVC *vapp)
+{
+    unsigned i, j;
+
+    //slice_data_size;
+    //slice_data_offset;
+    //slice_data_flag;
+    //slice_data_byte_offset;
+    //slice_segment_address;
+    for (i = 0; i < 2; i++) {
+        for (j = 0; j < 15; j++)
+            vapp->RefPicList[i][j] = desc->RefPicList[i][j];
+    }
+    //LongSliceFlags;
+    //collocated_ref_idx;
+    //num_ref_idx_l0_active_minus1;
+    //num_ref_idx_l1_active_minus1;
+    //slice_qp_delta;
+    //slice_cb_qp_offset;
+    //slice_cr_qp_offset;
+    //slice_beta_offset_div2;
+    //slice_tc_offset_div2;
+    //luma_log2_weight_denom;
+    //delta_chroma_log2_weight_denom;
+    //delta_luma_weight_l0[15];
+    //luma_offset_l0[15];
+    //delta_chroma_weight_l0[15][2];
+    //ChromaOffsetL0[15][2];
+    //delta_luma_weight_l1[15];
+    //luma_offset_l1[15];
+    //delta_chroma_weight_l1[15][2];
+    //ChromaOffsetL1[15][2];
+    //five_minus_max_num_merge_cand;
+    //num_entry_point_offsets;
+    //entry_offset_to_subset_array;
+    //slice_data_num_emu_prevn_bytes;
+    //va_reserved[VA_PADDING_LOW - 2];
+}
+
+/*
+ * Refer to vlVaHandleVAEncSequenceParameterBufferTypeHEVC() in mesa,
+ * and comment out some unused parameters.
+ */
+static void h265_fill_enc_seq_param(
+                            struct virgl_video_codec *codec,
+                            struct virgl_video_buffer *source,
+                            const struct virgl_h265_enc_picture_desc *desc,
+                            VAEncSequenceParameterBufferHEVC *param)
+{
+    (void)codec;
+    (void)source;
+
+    ITEM_SET(param, &desc->seq, general_profile_idc);
+    ITEM_SET(param, &desc->seq, general_level_idc);
+    ITEM_SET(param, &desc->seq, general_tier_flag);
+    ITEM_SET(param, &desc->seq, intra_period);
+    //intra_idr_period
+    ITEM_SET(param, &desc->seq, ip_period);
+    //bits_per_second
+    ITEM_SET(param, &desc->seq, pic_width_in_luma_samples);
+    ITEM_SET(param, &desc->seq, pic_height_in_luma_samples);
+
+    /* seq_fields.bits */
+    ITEM_SET(&param->seq_fields.bits, &desc->seq, chroma_format_idc);
+    //seq_fields.bits.separate_colour_plane_flag
+    ITEM_SET(&param->seq_fields.bits, &desc->seq, bit_depth_luma_minus8);
+    ITEM_SET(&param->seq_fields.bits, &desc->seq, bit_depth_chroma_minus8);
+    //seq_fields.bits.scaling_list_enabled_flag
+    ITEM_SET(&param->seq_fields.bits, &desc->seq, strong_intra_smoothing_enabled_flag);
+    ITEM_SET(&param->seq_fields.bits, &desc->seq, amp_enabled_flag);
+    ITEM_SET(&param->seq_fields.bits, &desc->seq, sample_adaptive_offset_enabled_flag);
+    ITEM_SET(&param->seq_fields.bits, &desc->seq, pcm_enabled_flag);
+    //seq_fields.bits.pcm_loop_filter_disabled_flag
+    ITEM_SET(&param->seq_fields.bits, &desc->seq, sps_temporal_mvp_enabled_flag);
+    //seq_fields.bits.low_delay_seq
+    //seq_fields.bits.hierachical_flag
+    //seq_fields.bits.reserved_bits
+
+    ITEM_SET(param, &desc->seq, log2_min_luma_coding_block_size_minus3);
+    ITEM_SET(param, &desc->seq, log2_diff_max_min_luma_coding_block_size);
+    ITEM_SET(param, &desc->seq, log2_min_transform_block_size_minus2);
+    ITEM_SET(param, &desc->seq, log2_diff_max_min_transform_block_size);
+    ITEM_SET(param, &desc->seq, max_transform_hierarchy_depth_inter);
+    ITEM_SET(param, &desc->seq, max_transform_hierarchy_depth_intra);
+    //pcm_sample_bit_depth_luma_minus1
+    //pcm_sample_bit_depth_chroma_minus1
+    //log2_min_pcm_luma_coding_block_size_minus3
+    //log2_max_pcm_luma_coding_block_size_minus3
+    ITEM_SET(param, &desc->seq, vui_parameters_present_flag);
+
+    /* vui_fields.bits */
+    if (desc->seq.vui_parameters_present_flag) {
+        ITEM_SET(&param->vui_fields.bits, &desc->seq.vui_flags,
+                 aspect_ratio_info_present_flag);
+    }
+    //vui_fields.bits.neutral_chroma_indication_flag
+    //vui_fields.bits.field_seq_flag
+    if (desc->seq.vui_parameters_present_flag) {
+        param->vui_fields.bits.vui_timing_info_present_flag =
+            desc->seq.vui_flags.timing_info_present_flag;
+    }
+    //vui_fields.bits.bitstream_restriction_flag
+    //vui_fields.bits.tiles_fixed_structure_flag
+    //vui_fields.bits.motion_vectors_over_pic_boundaries_flag
+    //vui_fields.bits.restricted_ref_pic_lists_flag
+    //vui_fields.bits.log2_max_mv_length_horizontal
+    //vui_fields.bits.log2_max_mv_length_vertical
+
+    if (desc->seq.vui_parameters_present_flag) {
+        ITEM_SET(param, &desc->seq, aspect_ratio_idc);
+        ITEM_SET(param, &desc->seq, sar_width);
+        ITEM_SET(param, &desc->seq, sar_height);
+    }
+    param->vui_num_units_in_tick = desc->seq.num_units_in_tick;
+    param->vui_time_scale = desc->seq.time_scale;
+    //min_spatial_segmentation_idc
+    //max_bytes_per_pic_denom
+    //max_bits_per_min_cu_denom
+
+    //scc_fields.bits.palette_mode_enabled_flag
+}
+
+/*
+ * Refer to vlVaHandleVAEncPictureParameterBufferTypeHEVC() in mesa,
+ * and comment out some unused parameters.
+ */
+static void h265_fill_enc_picture_param(
+                            struct virgl_video_codec *codec,
+                            struct virgl_video_buffer *source,
+                            const struct virgl_h265_enc_picture_desc *desc,
+                            VAEncPictureParameterBufferHEVC *param)
+{
+    unsigned i;
+
+    (void)source;
+
+    param->decoded_curr_pic.picture_id = get_enc_ref_pic(codec, desc->frame_num);
+    param->decoded_curr_pic.pic_order_cnt = desc->pic_order_cnt;
+
+    for (i = 0; i < 15; i++) {
+        h265_init_picture(&param->reference_frames[i]);
+    }
+
+    param->coded_buf = codec->va_coded_buf;
+    //collocated_ref_pic_index
+    //last_picture
+    param->pic_init_qp = desc->rc.quant_i_frames;
+    //diff_cu_qp_delta_depth
+    //pps_cb_qp_offset
+    //pps_cr_qp_offset
+    //num_tile_columns_minus1
+    //num_tile_rows_minus1
+    //column_width_minus1[19]
+    //row_height_minus1[21]
+    ITEM_SET(param, &desc->pic, log2_parallel_merge_level_minus2);
+    //ctu_max_bitsize_allowed
+    param->num_ref_idx_l0_default_active_minus1 = desc->num_ref_idx_l0_active_minus1;
+    param->num_ref_idx_l1_default_active_minus1 = desc->num_ref_idx_l1_active_minus1;
+    //slice_pic_parameter_set_id
+    ITEM_SET(param, &desc->pic, nal_unit_type);
+
+    param->pic_fields.bits.idr_pic_flag =
+        (desc->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR);
+    switch (desc->picture_type) {
+    case PIPE_H2645_ENC_PICTURE_TYPE_IDR: /* fallthrough */
+    case PIPE_H2645_ENC_PICTURE_TYPE_I:
+        param->pic_fields.bits.coding_type = 1;
+        break;
+    case PIPE_H2645_ENC_PICTURE_TYPE_P:
+        param->pic_fields.bits.coding_type = 2;
+        break;
+    case PIPE_H2645_ENC_PICTURE_TYPE_B:
+        param->pic_fields.bits.coding_type = 3;
+        break;
+    default:
+        break;
+    }
+
+    param->pic_fields.bits.reference_pic_flag = !desc->not_referenced;
+    //pic_fields.bits.dependent_slice_segments_enabled_flag
+    //pic_fields.bits.sign_data_hiding_enabled_flag
+    ITEM_SET(&param->pic_fields.bits, &desc->pic, constrained_intra_pred_flag);
+    ITEM_SET(&param->pic_fields.bits, &desc->pic, transform_skip_enabled_flag);
+    //pic_fields.bits.cu_qp_delta_enabled_flag
+    //pic_fields.bits.weighted_pred_flag
+    //pic_fields.bits.weighted_bipred_flag
+    //pic_fields.bits.transquant_bypass_enabled_flag
+    //pic_fields.bits.tiles_enabled_flag
+    //pic_fields.bits.entropy_coding_sync_enabled_flag
+    //pic_fields.bits.loop_filter_across_tiles_enabled_flag
+    ITEM_SET(&param->pic_fields.bits, &desc->pic,
+             pps_loop_filter_across_slices_enabled_flag);
+    //pic_fields.bits.scaling_list_data_present_flag
+    //pic_fields.bits.screen_content_flag
+    //pic_fields.bits.enable_gpu_weighted_prediction
+    //pic_fields.bits.no_output_of_prior_pics_flag
+
+    //hierarchical_level_plus1
+    //scc_fields.bits.pps_curr_pic_ref_enabled_flag
+}
+
+/*
+ * Refer to vlVaHandleVAEncSliceParameterBufferTypeHEVC() in mesa,
+ * and comment out some unused parameters.
+ */
+static void h265_fill_enc_slice_param(
+                            struct virgl_video_codec *codec,
+                            struct virgl_video_buffer *source,
+                            const struct virgl_h265_enc_picture_desc *desc,
+                            VAEncSliceParameterBufferHEVC *param)
+{
+    unsigned i;
+    const struct virgl_h265_slice_descriptor *sd;
+
+    (void)source;
+
+    /* Get the lastest slice descriptor */
+    if (desc->num_slice_descriptors &&
+        desc->num_slice_descriptors <= ARRAY_SIZE(desc->slices_descriptors)) {
+        sd = &desc->slices_descriptors[desc->num_slice_descriptors - 1];
+        ITEM_SET(param, sd, slice_segment_address);
+        ITEM_SET(param, sd, num_ctu_in_slice);
+    }
+
+    switch (desc->picture_type) {
+    case PIPE_H2645_ENC_PICTURE_TYPE_P:
+        param->slice_type = 0;
+        break;
+    case PIPE_H2645_ENC_PICTURE_TYPE_B:
+        param->slice_type = 1;
+        break;
+    case PIPE_H2645_ENC_PICTURE_TYPE_I:
+    case PIPE_H2645_ENC_PICTURE_TYPE_IDR: /* fall through */
+        param->slice_type = 2;
+        break;
+    case PIPE_H2645_ENC_PICTURE_TYPE_SKIP:
+    default:
+        break;
+    }
+
+    //slice_pic_parameter_set_id
+
+    //num_ref_idx_l0_active_minus1
+    //num_ref_idx_l1_active_minus1
+
+    for (i = 0; i < 15; i++) {
+        h265_init_picture(&param->ref_pic_list0[i]);
+        h265_init_picture(&param->ref_pic_list1[i]);
+
+        param->ref_pic_list0[i].picture_id =
+                    get_enc_ref_pic(codec, desc->ref_idx_l0_list[i]);
+        param->ref_pic_list1[i].picture_id =
+                    get_enc_ref_pic(codec, desc->ref_idx_l1_list[i]);
+
+        if (param->ref_pic_list0[i].picture_id != VA_INVALID_ID)
+            param->ref_pic_list0[i].flags = VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE;
+
+        if (param->ref_pic_list1[i].picture_id != VA_INVALID_ID)
+            param->ref_pic_list1[i].flags = VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE;
+    }
+
+    //luma_log2_weight_denom
+    //delta_chroma_log2_weight_denom
+    //delta_luma_weight_l0[15]
+    //luma_offset_l0[15]
+    //delta_chroma_weight_l0[15][2]
+    //chroma_offset_l0[15][2]
+    //delta_luma_weight_l1[15]
+    //luma_offset_l1[15]
+    //delta_chroma_weight_l1[15][2]
+    //chroma_offset_l1[15][2]
+    ITEM_SET(param, &desc->slice, max_num_merge_cand);
+    //slice_qp_delta
+    ITEM_SET(param, &desc->slice, slice_cb_qp_offset);
+    ITEM_SET(param, &desc->slice, slice_cr_qp_offset);
+    ITEM_SET(param, &desc->slice, slice_beta_offset_div2);
+    ITEM_SET(param, &desc->slice, slice_tc_offset_div2);
+
+    //slice_fields.bits.last_slice_of_pic_flag
+    //slice_fields.bits.dependent_slice_segment_flag
+    //slice_fields.bits.colour_plane_id
+    //slice_fields.bits.slice_temporal_mvp_enabled_flag
+    //slice_fields.bits.slice_sao_luma_flag
+    //slice_fields.bits.slice_sao_chroma_flag
+    /*
+     * Sine num_ref_idx_l0_active_minus1 and num_ref_idx_l1_active_minus1
+     * have been passed by VAEncPictureParameterBufferHEVC,
+     * num_ref_idx_active_override_flag is always set to 0.
+     */
+    param->slice_fields.bits.num_ref_idx_active_override_flag = 0;
+    //slice_fields.bits.mvd_l1_zero_flag
+    ITEM_SET(&param->slice_fields.bits, &desc->slice, cabac_init_flag);
+    ITEM_SET(&param->slice_fields.bits, &desc->slice,
+             slice_deblocking_filter_disabled_flag);
+    ITEM_SET(&param->slice_fields.bits,
+             &desc->slice, slice_loop_filter_across_slices_enabled_flag);
+    //slice_fields.bits.collocated_from_l0_flag
+
+    //pred_weight_table_bit_offset
+    //pred_weight_table_bit_length;
+}
+
+/*
+ * Refer to vlVaHandleVAEncMiscParameterTypeRateControlHEVC() in mesa,
+ * and comment out some unused parameters.
+ */
+static void h265_fill_enc_misc_param_rate_ctrl(
+                            struct virgl_video_codec *codec,
+                            struct virgl_video_buffer *source,
+                            const struct virgl_h265_enc_picture_desc *desc,
+                            VAEncMiscParameterRateControl *param)
+{
+    (void)codec;
+    (void)source;
+
+    param->bits_per_second = desc->rc.peak_bitrate;
+    if (desc->rc.rate_ctrl_method !=
+        PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT) {
+        param->target_percentage = desc->rc.target_bitrate *
+                                   param->bits_per_second / 100.0;
+    }
+    //window_size;
+    //initial_qp;
+    param->min_qp = desc->rc.min_qp;
+    //basic_unit_size;
+
+    /* rc_flags */
+    //rc_flags.bits.reset
+    param->rc_flags.bits.disable_frame_skip = !desc->rc.skip_frame_enable;
+    param->rc_flags.bits.disable_bit_stuffing = !desc->rc.fill_data_enable;
+    //rc_flags.bits.mb_rate_control
+    //rc_flags.bits.temporal_id
+    //rc_flags.bits.cfs_I_frames
+    //rc_flags.bits.enable_parallel_brc
+    //rc_flags.bits.enable_dynamic_scaling
+    //rc_flags.bits.frame_tolerance_mode
+
+    //ICQ_quality_factor;
+    param->max_qp = desc->rc.max_qp;
+    //quality_factor;
+    //target_frame_size;
+}
+
+/*
+ * Refer to vlVaHandleVAEncMiscParameterTypeFrameRateHEVC() in mesa,
+ * and comment out some unused parameters.
+ */
+static void h265_fill_enc_misc_param_frame_rate(
+                            struct virgl_video_codec *codec,
+                            struct virgl_video_buffer *source,
+                            const struct virgl_h265_enc_picture_desc *desc,
+                            VAEncMiscParameterFrameRate *param)
+{
+    (void)codec;
+    (void)source;
+
+    param->framerate = desc->rc.frame_rate_num | (desc->rc.frame_rate_den << 16);
+    //framerate_flags
+}
+
+static int h265_decode_bitstream(struct virgl_video_codec *codec,
+                                 struct virgl_video_buffer *target,
+                                 const struct virgl_h265_picture_desc *desc,
+                                 unsigned num_buffers,
+                                 const void * const *buffers,
+                                 const unsigned *sizes)
+{
+    unsigned i;
+    int err = 0;
+    VAStatus va_stat;
+    VABufferID *slice_data_buf, pic_param_buf, slice_param_buf;
+    VAPictureParameterBufferHEVC pic_param = {0};
+    VASliceParameterBufferHEVC slice_param = {0};
+
+    slice_data_buf = calloc(num_buffers, sizeof(VABufferID));
+    if (!slice_data_buf) {
+        virgl_log("alloc slice data buffer id failed\n");
+        return -1;
+    }
+
+    h265_fill_picture_param(codec, target, desc, &pic_param);
+    vaCreateBuffer(va_dpy, codec->va_ctx, VAPictureParameterBufferType,
+                   sizeof(pic_param), 1, &pic_param, &pic_param_buf);
+
+    h265_fill_slice_param(desc, &slice_param);
+    vaCreateBuffer(va_dpy, codec->va_ctx, VASliceParameterBufferType,
+                   sizeof(slice_param), 1, &slice_param, &slice_param_buf);
+
+    for (i = 0; i < num_buffers; i++) {
+        vaCreateBuffer(va_dpy, codec->va_ctx, VASliceDataBufferType,
+                      sizes[i], 1, (void *)(buffers[i]), &slice_data_buf[i]);
+    }
+
+    va_stat = vaRenderPicture(va_dpy, codec->va_ctx, &pic_param_buf, 1);
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("render picture param failed, err = 0x%x\n", va_stat);
+        err = -1;
+        goto err;
+    }
+
+    va_stat = vaRenderPicture(va_dpy, codec->va_ctx, &slice_param_buf, 1);
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("render slice param failed, err = 0x%x\n", va_stat);
+        err = -1;
+        goto err;
+    }
+
+    for (i = 0; i < num_buffers; i++) {
+        va_stat = vaRenderPicture(va_dpy, codec->va_ctx, &slice_data_buf[i], 1);
+
+        if (VA_STATUS_SUCCESS != va_stat) {
+            virgl_log("render slice data failed, err = 0x%x\n", va_stat);
+            err = -1;
+        }
+    }
+
+err:
+    vaDestroyBuffer(va_dpy, pic_param_buf);
+    vaDestroyBuffer(va_dpy, slice_param_buf);
+    for (i = 0; i < num_buffers; i++)
+        vaDestroyBuffer(va_dpy, slice_data_buf[i]);
+    free(slice_data_buf);
+
+    return err;
+}
+
+static int h265_encode_render_sequence(
+                            struct virgl_video_codec *codec,
+                            struct virgl_video_buffer *source,
+                            const struct virgl_h265_enc_picture_desc *desc)
+{
+    int err = 0;
+    VAStatus va_stat;
+    VAEncSequenceParameterBufferHEVC seq_param;
+    VAEncMiscParameterBuffer *misc_param;
+    VABufferID seq_param_buf, rc_param_buf, fr_param_buf;
+
+    memset(&seq_param, 0, sizeof(seq_param));
+    h265_fill_enc_seq_param(codec, source, desc, &seq_param);
+    vaCreateBuffer(va_dpy, codec->va_ctx, VAEncSequenceParameterBufferType,
+                   sizeof(seq_param), 1, &seq_param, &seq_param_buf);
+
+    vaCreateBuffer(va_dpy, codec->va_ctx, VAEncMiscParameterBufferType,
+                   sizeof(VAEncMiscParameterBuffer) +
+                   sizeof(VAEncMiscParameterRateControl), 1, NULL, &rc_param_buf);
+    vaMapBuffer(va_dpy, rc_param_buf, (void **)&misc_param);
+    misc_param->type = VAEncMiscParameterTypeRateControl;
+    h265_fill_enc_misc_param_rate_ctrl(codec, source, desc,
+                    (VAEncMiscParameterRateControl *)misc_param->data);
+    vaUnmapBuffer(va_dpy, rc_param_buf);
+
+    vaCreateBuffer(va_dpy, codec->va_ctx, VAEncMiscParameterBufferType,
+                   sizeof(VAEncMiscParameterBuffer) +
+                   sizeof(VAEncMiscParameterFrameRate), 1, NULL, &fr_param_buf);
+    vaMapBuffer(va_dpy, fr_param_buf, (void **)&misc_param);
+    misc_param->type = VAEncMiscParameterTypeFrameRate;
+    h265_fill_enc_misc_param_frame_rate(codec, source, desc,
+                    (VAEncMiscParameterFrameRate *)misc_param->data);
+    vaUnmapBuffer(va_dpy, fr_param_buf);
+
+    va_stat = vaRenderPicture(va_dpy, codec->va_ctx, &seq_param_buf, 1);
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("render h265 sequence param failed, err = 0x%x\n", va_stat);
+        err = -1;
+        goto error;
+    }
+
+    va_stat = vaRenderPicture(va_dpy, codec->va_ctx, &rc_param_buf, 1);
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("render h265 rate control param failed, err = 0x%x\n", va_stat);
+        err = -1;
+        goto error;
+    }
+
+    va_stat = vaRenderPicture(va_dpy, codec->va_ctx, &fr_param_buf, 1);
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("render h265 frame rate param failed, err = 0x%x\n", va_stat);
+        err = -1;
+        goto error;
+    }
+
+error:
+    vaDestroyBuffer(va_dpy, seq_param_buf);
+    vaDestroyBuffer(va_dpy, rc_param_buf);
+    vaDestroyBuffer(va_dpy, fr_param_buf);
+
+    return err;
+}
+
+static int h265_encode_render_picture(
+                            struct virgl_video_codec *codec,
+                            struct virgl_video_buffer *source,
+                            const struct virgl_h265_enc_picture_desc *desc)
+{
+    VAStatus va_stat;
+    VABufferID pic_param_buf;
+    VAEncPictureParameterBufferHEVC pic_param;
+
+    memset(&pic_param, 0, sizeof(pic_param));
+    h265_fill_enc_picture_param(codec, source, desc, &pic_param);
+    vaCreateBuffer(va_dpy, codec->va_ctx, VAEncPictureParameterBufferType,
+                   sizeof(pic_param), 1, &pic_param, &pic_param_buf);
+
+    va_stat = vaRenderPicture(va_dpy, codec->va_ctx, &pic_param_buf, 1);
+    vaDestroyBuffer(va_dpy, pic_param_buf);
+
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("render h265 picture param failed, err = 0x%x\n", va_stat);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int h265_encode_render_slice(
+                            struct virgl_video_codec *codec,
+                            struct virgl_video_buffer *source,
+                            const struct virgl_h265_enc_picture_desc *desc)
+{
+    VAStatus va_stat;
+    VABufferID slice_param_buf;
+    VAEncSliceParameterBufferHEVC slice_param;
+
+    memset(&slice_param, 0, sizeof(slice_param));
+    h265_fill_enc_slice_param(codec, source, desc, &slice_param);
+    vaCreateBuffer(va_dpy, codec->va_ctx, VAEncSliceParameterBufferType,
+                   sizeof(slice_param), 1, &slice_param, &slice_param_buf);
+
+    va_stat = vaRenderPicture(va_dpy, codec->va_ctx, &slice_param_buf, 1);
+    vaDestroyBuffer(va_dpy, slice_param_buf);
+
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("render h265 slice param failed, err = 0x%x\n", va_stat);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int h265_encode_bitstream(
+                            struct virgl_video_codec *codec,
+                            struct virgl_video_buffer *source,
+                            const struct virgl_h265_enc_picture_desc *desc)
+{
+    if (desc->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR) {
+        h265_encode_render_sequence(codec, source, desc);
+    }
+
+    h265_encode_render_picture(codec, source, desc);
+    h265_encode_render_slice(codec, source, desc);
+
+    return 0;
+}
+
+int virgl_video_decode_bitstream(struct virgl_video_codec *codec,
+                                 struct virgl_video_buffer *target,
+                                 const union virgl_picture_desc *desc,
+                                 unsigned num_buffers,
+                                 const void * const *buffers,
+                                 const unsigned *sizes)
+{
+
+    if (!va_dpy || !codec || !target || !desc
+        || !num_buffers || !buffers || !sizes)
+        return -1;
+
+    if (desc->base.profile != codec->profile) {
+        virgl_log("profiles not matched, picture: %d, codec: %d\n",
+                desc->base.profile, codec->profile);
+        return -1;
+    }
+
+    switch (codec->profile) {
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE:
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED:
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10:
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH422:
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH444:
+        return h264_decode_bitstream(codec, target, &desc->h264,
+                                     num_buffers, buffers, sizes);
+    case PIPE_VIDEO_PROFILE_HEVC_MAIN:
+    case PIPE_VIDEO_PROFILE_HEVC_MAIN_10:
+    case PIPE_VIDEO_PROFILE_HEVC_MAIN_STILL:
+    case PIPE_VIDEO_PROFILE_HEVC_MAIN_12:
+    case PIPE_VIDEO_PROFILE_HEVC_MAIN_444:
+        return h265_decode_bitstream(codec, target, &desc->h265,
+                                     num_buffers, buffers, sizes);
+    default:
+        break;
+    }
+
+    return -1;
+}
+
+int virgl_video_encode_bitstream(struct virgl_video_codec *codec,
+                                 struct virgl_video_buffer *source,
+                                 const union virgl_picture_desc *desc)
+{
+    if (!va_dpy || !codec || !source || !desc)
+        return -1;
+
+    if (desc->base.profile != codec->profile) {
+        virgl_log("profiles not matched, picture: %d, codec: %d\n",
+                desc->base.profile, codec->profile);
+        return -1;
+    }
+
+    switch (codec->profile) {
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE:
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED:
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10:
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH422:
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH444:
+        return h264_encode_bitstream(codec, source, &desc->h264_enc);
+    case PIPE_VIDEO_PROFILE_HEVC_MAIN:
+    case PIPE_VIDEO_PROFILE_HEVC_MAIN_10:
+    case PIPE_VIDEO_PROFILE_HEVC_MAIN_STILL:
+    case PIPE_VIDEO_PROFILE_HEVC_MAIN_12:
+    case PIPE_VIDEO_PROFILE_HEVC_MAIN_444:
+        return h265_encode_bitstream(codec, source, &desc->h265_enc);
+    default:
+        break;
+    }
+
+    return -1;
+}
+
+int virgl_video_end_frame(struct virgl_video_codec *codec,
+                          struct virgl_video_buffer *target)
+{
+    VAStatus va_stat;
+
+    if (!va_dpy || !codec || !target)
+        return -1;
+
+    va_stat = vaEndPicture(va_dpy, codec->va_ctx);
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("end picture failed, err = 0x%x\n", va_stat);
+        return -1;
+    }
+
+    va_stat = vaSyncSurface(va_dpy, target->va_sfc);
+    if (VA_STATUS_SUCCESS != va_stat) {
+        virgl_log("sync surface failed, err = 0x%x\n", va_stat);
+        return -1;
+    }
+
+    if (codec->entrypoint != PIPE_VIDEO_ENTRYPOINT_ENCODE) {
+        decode_completed(codec, target);
+    } else {
+        encode_completed(codec, target);
+    }
+
+    return 0;
+}
+
diff --git a/src/virgl_video.h b/src/virgl_video.h
new file mode 100644
index 0000000..68e3889
--- /dev/null
+++ b/src/virgl_video.h
@@ -0,0 +1,161 @@
+/**************************************************************************
+ *
+ * Copyright (C) 2022 Kylin Software Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * @file
+ * General video encoding and decoding interface.
+ *
+ * This file provides a general video interface, which mainly contains
+ * two objects:
+ *
+ * virgl_video_buffer:
+ *   Buffer for storing raw YUV formatted data. In VA-API based
+ *   implementations, it is usually associated with a surface.
+ *
+ * virgl_video_codec:
+ *   Represents an encoder or decoder. In VA-API based implementations, it
+ *   usually corresponds to a context.
+ *
+ * @author Feng Jiang <jiangfeng@kylinos.cn>
+ */
+
+#ifndef VIRGL_VIDEO_H
+#define VIRGL_VIDEO_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "pipe/p_format.h"
+#include "pipe/p_video_enums.h"
+
+struct virgl_video_codec;
+struct virgl_video_buffer;
+union virgl_caps;
+union virgl_picture_desc;
+
+struct virgl_video_create_codec_args {
+    enum pipe_video_profile profile;
+    enum pipe_video_entrypoint entrypoint;
+    enum pipe_video_chroma_format chroma_format;
+    uint32_t level;
+    uint32_t width;
+    uint32_t height;
+    uint32_t max_references;
+    uint32_t flags;
+    void *opaque;
+};
+
+struct virgl_video_create_buffer_args {
+    enum pipe_format format;
+    uint32_t width;
+    uint32_t height;
+    bool interlaced;
+    void *opaque;
+};
+
+/* flags for virgl_video_dma_buffers */
+#define VIRGL_VIDEO_DMABUF_READ_ONLY        0x0001
+#define VIRGL_VIDEO_DMABUF_WRITE_ONLY       0x0002
+#define VIRGL_VIDEO_DMABUF_READ_WRITE       0x0003
+
+struct virgl_video_dma_buf {
+    struct virgl_video_buffer *buf;
+
+    uint32_t drm_format;
+    uint32_t width;
+    uint32_t height;
+    uint32_t flags;
+
+    uint32_t num_planes;
+    struct virgl_video_dma_buf_plane {
+        uint32_t drm_format;
+        int fd;
+        uint32_t size;
+        int modifier;
+        uint32_t offset;
+        uint32_t pitch;
+    } planes[4];
+};
+
+/*
+ * Use callback functions instead of directly exporting the video buffer
+ * through an interface like virgl_video_export_buffer() is because the
+ * underlying implementation may not be VA-API. The callback function can
+ * better shield the underlying logic differences.
+ */
+struct virgl_video_callbacks {
+    /* Callback when decoding is complete, used to download the decoded picture
+     * from the video buffer */
+    void (*decode_completed)(struct virgl_video_codec *codec,
+                             const struct virgl_video_dma_buf *dmabuf);
+
+    /* Upload the picture data to be encoded to the video buffer */
+    void (*encode_upload_picture)(struct virgl_video_codec *codec,
+                                  const struct virgl_video_dma_buf *dmabuf);
+
+    /* Callback when encoding is complete, used to download the encoded data
+     * and reference picture */
+    void (*encode_completed)(struct virgl_video_codec *codec,
+                             const struct virgl_video_dma_buf *src_buf,
+                             const struct virgl_video_dma_buf *ref_buf,
+                             unsigned num_coded_bufs,
+                             const void * const *coded_bufs,
+                             const unsigned *coded_sizes);
+};
+
+int virgl_video_init(int drm_fd,
+                     struct virgl_video_callbacks *cbs,
+                     unsigned int flags);
+void virgl_video_destroy(void);
+
+int virgl_video_fill_caps(union virgl_caps *caps);
+
+struct virgl_video_codec *virgl_video_create_codec(
+        const struct virgl_video_create_codec_args *args);
+void virgl_video_destroy_codec(struct virgl_video_codec *codec);
+uint32_t virgl_video_codec_profile(const struct virgl_video_codec *codec);
+void *virgl_video_codec_opaque_data(struct virgl_video_codec *codec);
+
+struct virgl_video_buffer *virgl_video_create_buffer(
+        const struct virgl_video_create_buffer_args *args);
+void virgl_video_destroy_buffer(struct virgl_video_buffer *buffer);
+uint32_t virgl_video_buffer_id(const struct virgl_video_buffer *buffer);
+void *virgl_video_buffer_opaque_data(struct virgl_video_buffer *buffer);
+
+int virgl_video_begin_frame(struct virgl_video_codec *codec,
+                            struct virgl_video_buffer *target);
+int virgl_video_decode_bitstream(struct virgl_video_codec *codec,
+                                 struct virgl_video_buffer *target,
+                                 const union virgl_picture_desc *desc,
+                                 unsigned num_buffers,
+                                 const void * const *buffers,
+                                 const unsigned *sizes);
+int virgl_video_encode_bitstream(struct virgl_video_codec *codec,
+                                 struct virgl_video_buffer *source,
+                                 const union virgl_picture_desc *desc);
+int virgl_video_end_frame(struct virgl_video_codec *codec,
+                          struct virgl_video_buffer *target);
+
+#endif /* VIRGL_VIDEO_H */
+
diff --git a/src/virgl_video_hw.h b/src/virgl_video_hw.h
new file mode 100644
index 0000000..2f50f96
--- /dev/null
+++ b/src/virgl_video_hw.h
@@ -0,0 +1,585 @@
+/**************************************************************************
+ *
+ * Copyright (C) 2022 Kylin Software Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * @file
+ * Data structure definition of video hardware layer.
+ *
+ * These structures are used for communication between host and guest, and
+ * they are 4-byte aligned.
+ *
+ * 'virgl_picture_desc' and other related structures mainly describe sequence
+ * parameters, picture parameters, slice parameters, etc., as well as some
+ * context information for encoding and decoding. The video backend needs them
+ * to reconstruct VA-API calls.
+ *
+ * @author Feng Jiang <jiangfeng@kylinos.cn>
+ */
+
+#ifndef VIRGL_VIDEO_HW_H
+#define VIRGL_VIDEO_HW_H
+
+#include <stdint.h>
+
+struct virgl_base_picture_desc {
+    uint16_t profile;       /* enum pipe_video_profile */
+    uint8_t entry_point;    /* enum pipe_video_entrypoint */
+    uint8_t protected_playback;
+    uint8_t decrypt_key[256];
+    uint32_t key_size;
+
+};
+
+struct virgl_enc_quality_modes {
+    uint32_t level;
+    uint32_t preset_mode;
+    uint32_t pre_encode_mode;
+    uint32_t vbaq_mode;
+};
+
+/* H.264 sequence parameter set */
+struct virgl_h264_sps {
+    uint8_t  level_idc;
+    uint8_t  chroma_format_idc;
+    uint8_t  separate_colour_plane_flag;
+    uint8_t  bit_depth_luma_minus8;
+
+    uint8_t  bit_depth_chroma_minus8;
+    uint8_t  seq_scaling_matrix_present_flag;
+    uint8_t  ScalingList4x4[6][16];
+    uint8_t  ScalingList8x8[6][64];
+
+    uint8_t  log2_max_frame_num_minus4;
+    uint8_t  pic_order_cnt_type;
+    uint8_t  log2_max_pic_order_cnt_lsb_minus4;
+    uint8_t  delta_pic_order_always_zero_flag;
+
+    int32_t  offset_for_non_ref_pic;
+    int32_t  offset_for_top_to_bottom_field;
+    int32_t  offset_for_ref_frame[256];
+
+    uint8_t  num_ref_frames_in_pic_order_cnt_cycle;
+    uint8_t  max_num_ref_frames;
+    uint8_t  frame_mbs_only_flag;
+    uint8_t  mb_adaptive_frame_field_flag;
+
+    uint8_t  direct_8x8_inference_flag;
+    uint8_t  MinLumaBiPredSize8x8;
+    uint8_t  reserved[2];
+};
+
+/* H.264 picture parameter set */
+struct virgl_h264_pps {
+    struct virgl_h264_sps sps; /* Seq Param Set */
+
+    uint8_t  entropy_coding_mode_flag;
+    uint8_t  bottom_field_pic_order_in_frame_present_flag;
+    uint8_t  num_slice_groups_minus1;
+    uint8_t  slice_group_map_type;
+
+    uint8_t  slice_group_change_rate_minus1;
+    uint8_t  num_ref_idx_l0_default_active_minus1;
+    uint8_t  num_ref_idx_l1_default_active_minus1;
+    uint8_t  weighted_pred_flag;
+
+    uint8_t  weighted_bipred_idc;
+    int8_t   pic_init_qp_minus26;
+    int8_t   pic_init_qs_minus26;
+    int8_t   chroma_qp_index_offset;
+
+    uint8_t  deblocking_filter_control_present_flag;
+    uint8_t  constrained_intra_pred_flag;
+    uint8_t  redundant_pic_cnt_present_flag;
+    uint8_t  transform_8x8_mode_flag;
+
+    uint8_t  ScalingList4x4[6][16];
+    uint8_t  ScalingList8x8[6][64];
+
+    int8_t   second_chroma_qp_index_offset;
+    uint8_t  reserved[3];
+};
+
+struct virgl_h264_picture_desc {
+    struct virgl_base_picture_desc base;
+
+    struct virgl_h264_pps pps;  /* Picture Param Set */
+
+    uint32_t frame_num;
+
+    uint8_t  field_pic_flag;
+    uint8_t  bottom_field_flag;
+    uint8_t  num_ref_idx_l0_active_minus1;
+    uint8_t  num_ref_idx_l1_active_minus1;
+
+    uint32_t slice_count;
+    int32_t  field_order_cnt[2];
+
+    uint8_t  is_long_term[16];
+    uint8_t  top_is_reference[16];
+    uint8_t  bottom_is_reference[16];
+    uint32_t field_order_cnt_list[16][2];
+    uint32_t frame_num_list[16];
+    uint32_t buffer_id[16];
+
+    uint8_t  is_reference;
+    uint8_t  num_ref_frames;
+    uint8_t  reserved[2];
+};
+
+struct virgl_h264_enc_seq_param
+{
+   uint32_t enc_constraint_set_flags;
+   uint32_t enc_frame_cropping_flag;
+   uint32_t enc_frame_crop_left_offset;
+   uint32_t enc_frame_crop_right_offset;
+   uint32_t enc_frame_crop_top_offset;
+   uint32_t enc_frame_crop_bottom_offset;
+   uint32_t pic_order_cnt_type;
+   uint32_t num_temporal_layers;
+   uint32_t vui_parameters_present_flag;
+   struct {
+      uint32_t aspect_ratio_info_present_flag: 1;
+      uint32_t timing_info_present_flag: 1;
+      uint32_t reserved:30;
+   } vui_flags;
+   uint32_t aspect_ratio_idc;
+   uint32_t sar_width;
+   uint32_t sar_height;
+   uint32_t num_units_in_tick;
+   uint32_t time_scale;
+};
+
+struct virgl_h264_enc_rate_control
+{
+    uint32_t target_bitrate;
+    uint32_t peak_bitrate;
+    uint32_t frame_rate_num;
+    uint32_t frame_rate_den;
+    uint32_t vbv_buffer_size;
+    uint32_t vbv_buf_lv;
+    uint32_t target_bits_picture;
+    uint32_t peak_bits_picture_integer;
+    uint32_t peak_bits_picture_fraction;
+    uint32_t fill_data_enable;
+    uint32_t skip_frame_enable;
+    uint32_t enforce_hrd;
+    uint32_t max_au_size;
+    uint32_t max_qp;
+    uint32_t min_qp;
+
+    uint8_t  rate_ctrl_method; /* see enum pipe_h2645_enc_rate_control_method */
+    uint8_t  reserved[3];
+};
+
+struct virgl_h264_enc_motion_estimation
+{
+    uint32_t motion_est_quarter_pixel;
+    uint32_t enc_disable_sub_mode;
+    uint32_t lsmvert;
+    uint32_t enc_en_ime_overw_dis_subm;
+    uint32_t enc_ime_overw_dis_subm_no;
+    uint32_t enc_ime2_search_range_x;
+    uint32_t enc_ime2_search_range_y;
+};
+
+struct virgl_h264_enc_pic_control
+{
+    uint32_t enc_cabac_enable;
+    uint32_t enc_cabac_init_idc;
+};
+
+struct virgl_h264_slice_descriptor
+{
+   uint32_t macroblock_address;
+   uint32_t num_macroblocks;
+
+   uint8_t  slice_type; /* see enum pipe_h264_slice_type  */
+   uint8_t  reserved[3];
+};
+
+struct virgl_h264_enc_picture_desc
+{
+   struct virgl_base_picture_desc base;
+
+   struct virgl_h264_enc_seq_param seq;
+   struct virgl_h264_enc_rate_control rate_ctrl[4];
+   struct virgl_h264_enc_motion_estimation motion_est;
+   struct virgl_h264_enc_pic_control pic_ctrl;
+
+   uint32_t intra_idr_period;
+
+   uint32_t quant_i_frames;
+   uint32_t quant_p_frames;
+   uint32_t quant_b_frames;
+
+   uint32_t frame_num;
+   uint32_t frame_num_cnt;
+   uint32_t p_remain;
+   uint32_t i_remain;
+   uint32_t idr_pic_id;
+   uint32_t gop_cnt;
+   uint32_t pic_order_cnt;
+   uint32_t num_ref_idx_l0_active_minus1;
+   uint32_t num_ref_idx_l1_active_minus1;
+   uint32_t ref_idx_l0_list[32];
+   uint8_t  l0_is_long_term[32];
+   uint32_t ref_idx_l1_list[32];
+   uint8_t  l1_is_long_term[32];
+   uint32_t gop_size;
+   struct virgl_enc_quality_modes quality_modes;
+
+   uint32_t num_slice_descriptors;
+   struct virgl_h264_slice_descriptor slices_descriptors[128];
+
+   uint8_t  picture_type; /* see enum pipe_h2645_enc_picture_type */
+   uint8_t  not_referenced;
+   uint8_t  is_ltr;
+   uint8_t  enable_vui;
+
+   uint32_t ltr_index;
+};
+
+
+struct virgl_h265_sps
+{
+   uint32_t pic_width_in_luma_samples;
+   uint32_t pic_height_in_luma_samples;
+
+   uint8_t chroma_format_idc;
+   uint8_t separate_colour_plane_flag;
+   uint8_t bit_depth_luma_minus8;
+   uint8_t bit_depth_chroma_minus8;
+
+   uint8_t log2_max_pic_order_cnt_lsb_minus4;
+   uint8_t sps_max_dec_pic_buffering_minus1;
+   uint8_t log2_min_luma_coding_block_size_minus3;
+   uint8_t log2_diff_max_min_luma_coding_block_size;
+
+   uint8_t log2_min_transform_block_size_minus2;
+   uint8_t log2_diff_max_min_transform_block_size;
+   uint8_t max_transform_hierarchy_depth_inter;
+   uint8_t max_transform_hierarchy_depth_intra;
+
+   uint8_t ScalingList4x4[6][16];
+   uint8_t ScalingList8x8[6][64];
+   uint8_t ScalingList16x16[6][64];
+   uint8_t ScalingList32x32[2][64];
+
+   uint8_t ScalingListDCCoeff16x16[6];
+   uint8_t ScalingListDCCoeff32x32[2];
+
+   uint8_t scaling_list_enabled_flag;
+   uint8_t amp_enabled_flag;
+   uint8_t sample_adaptive_offset_enabled_flag;
+   uint8_t pcm_enabled_flag;
+
+   uint8_t pcm_sample_bit_depth_luma_minus1;
+   uint8_t pcm_sample_bit_depth_chroma_minus1;
+   uint8_t log2_min_pcm_luma_coding_block_size_minus3;
+   uint8_t log2_diff_max_min_pcm_luma_coding_block_size;
+
+   uint8_t pcm_loop_filter_disabled_flag;
+   uint8_t num_short_term_ref_pic_sets;
+   uint8_t long_term_ref_pics_present_flag;
+   uint8_t num_long_term_ref_pics_sps;
+
+   uint8_t sps_temporal_mvp_enabled_flag;
+   uint8_t strong_intra_smoothing_enabled_flag;
+   uint8_t reserved[2];
+};
+
+struct virgl_h265_pps
+{
+   struct virgl_h265_sps sps;
+
+   uint8_t dependent_slice_segments_enabled_flag;
+   uint8_t output_flag_present_flag;
+   uint8_t num_extra_slice_header_bits;
+   uint8_t sign_data_hiding_enabled_flag;
+
+   uint8_t cabac_init_present_flag;
+   uint8_t num_ref_idx_l0_default_active_minus1;
+   uint8_t num_ref_idx_l1_default_active_minus1;
+   int8_t init_qp_minus26;
+
+   uint8_t constrained_intra_pred_flag;
+   uint8_t transform_skip_enabled_flag;
+   uint8_t cu_qp_delta_enabled_flag;
+   uint8_t diff_cu_qp_delta_depth;
+
+   int8_t pps_cb_qp_offset;
+   int8_t pps_cr_qp_offset;
+   uint8_t pps_slice_chroma_qp_offsets_present_flag;
+   uint8_t weighted_pred_flag;
+
+   uint8_t weighted_bipred_flag;
+   uint8_t transquant_bypass_enabled_flag;
+   uint8_t tiles_enabled_flag;
+   uint8_t entropy_coding_sync_enabled_flag;
+
+   uint16_t column_width_minus1[20];
+   uint16_t row_height_minus1[22];
+
+   uint8_t num_tile_columns_minus1;
+   uint8_t num_tile_rows_minus1;
+   uint8_t uniform_spacing_flag;
+   uint8_t loop_filter_across_tiles_enabled_flag;
+
+   uint8_t pps_loop_filter_across_slices_enabled_flag;
+   uint8_t deblocking_filter_control_present_flag;
+   uint8_t deblocking_filter_override_enabled_flag;
+   uint8_t pps_deblocking_filter_disabled_flag;
+
+   int8_t pps_beta_offset_div2;
+   int8_t pps_tc_offset_div2;
+   uint8_t lists_modification_present_flag;
+   uint8_t log2_parallel_merge_level_minus2;
+
+   uint16_t st_rps_bits;
+   uint8_t slice_segment_header_extension_present_flag;
+   uint8_t reserved;
+};
+
+struct virgl_h265_picture_desc
+{
+   struct virgl_base_picture_desc base;
+
+   struct virgl_h265_pps pps;
+
+   int32_t CurrPicOrderCntVal;
+   uint32_t ref[16];
+   int32_t PicOrderCntVal[16];
+
+   uint32_t NumPocTotalCurr;
+   uint32_t NumDeltaPocsOfRefRpsIdx;
+   uint32_t NumShortTermPictureSliceHeaderBits;
+   uint32_t NumLongTermPictureSliceHeaderBits;
+
+   uint8_t IsLongTerm[16];
+
+   uint8_t IDRPicFlag;
+   uint8_t RAPPicFlag;
+   uint8_t CurrRpsIdx;
+   uint8_t NumPocStCurrBefore;
+
+   uint8_t NumPocStCurrAfter;
+   uint8_t NumPocLtCurr;
+   uint8_t UseRefPicList;
+   uint8_t UseStRpsBits;
+
+   uint8_t RefPicSetStCurrBefore[8];
+   uint8_t RefPicSetStCurrAfter[8];
+   uint8_t RefPicSetLtCurr[8];
+
+   uint8_t RefPicList[2][15];
+   uint8_t reserved[2];
+};
+
+struct virgl_h265_enc_seq_param
+{
+   uint8_t  general_profile_idc;
+   uint8_t  general_level_idc;
+   uint8_t  general_tier_flag;
+   uint8_t  strong_intra_smoothing_enabled_flag;
+
+   uint32_t intra_period;
+   uint32_t ip_period;
+
+   uint16_t pic_width_in_luma_samples;
+   uint16_t pic_height_in_luma_samples;
+
+   uint32_t chroma_format_idc;
+   uint32_t bit_depth_luma_minus8;
+   uint32_t bit_depth_chroma_minus8;
+
+   uint8_t  amp_enabled_flag;
+   uint8_t  sample_adaptive_offset_enabled_flag;
+   uint8_t  pcm_enabled_flag;
+   uint8_t  sps_temporal_mvp_enabled_flag;
+
+   uint8_t  log2_min_luma_coding_block_size_minus3;
+   uint8_t  log2_diff_max_min_luma_coding_block_size;
+   uint8_t  log2_min_transform_block_size_minus2;
+   uint8_t  log2_diff_max_min_transform_block_size;
+
+   uint16_t conf_win_left_offset;
+   uint16_t conf_win_right_offset;
+   uint16_t conf_win_top_offset;
+   uint16_t conf_win_bottom_offset;
+
+   uint32_t vui_parameters_present_flag;
+   struct {
+      uint32_t aspect_ratio_info_present_flag: 1;
+      uint32_t timing_info_present_flag: 1;
+      uint32_t reserved:30;
+   } vui_flags;
+   uint32_t aspect_ratio_idc;
+   uint32_t sar_width;
+   uint32_t sar_height;
+   uint32_t num_units_in_tick;
+   uint32_t time_scale;
+
+   uint8_t  max_transform_hierarchy_depth_inter;
+   uint8_t  max_transform_hierarchy_depth_intra;
+   uint8_t  conformance_window_flag;
+   uint8_t  reserved;
+};
+
+struct virgl_h265_enc_pic_param
+{
+   uint8_t log2_parallel_merge_level_minus2;
+   uint8_t nal_unit_type;
+   uint8_t constrained_intra_pred_flag;
+   uint8_t pps_loop_filter_across_slices_enabled_flag;
+
+   uint8_t transform_skip_enabled_flag;
+   uint8_t reserved[3];
+};
+
+struct virgl_h265_enc_slice_param
+{
+   uint8_t max_num_merge_cand;
+   int8_t  slice_cb_qp_offset;
+   int8_t  slice_cr_qp_offset;
+   int8_t  slice_beta_offset_div2;
+
+   uint32_t slice_deblocking_filter_disabled_flag;
+
+   int8_t  slice_tc_offset_div2;
+   uint8_t cabac_init_flag;
+   uint8_t slice_loop_filter_across_slices_enabled_flag;
+   uint8_t reserved;
+};
+
+struct virgl_h265_enc_rate_control
+{
+   uint32_t target_bitrate;
+   uint32_t peak_bitrate;
+   uint32_t frame_rate_num;
+   uint32_t frame_rate_den;
+   uint32_t quant_i_frames;
+   uint32_t quant_p_frames;
+   uint32_t quant_b_frames;
+   uint32_t vbv_buffer_size;
+   uint32_t vbv_buf_lv;
+   uint32_t target_bits_picture;
+   uint32_t peak_bits_picture_integer;
+   uint32_t peak_bits_picture_fraction;
+   uint32_t fill_data_enable;
+   uint32_t skip_frame_enable;
+   uint32_t enforce_hrd;
+   uint32_t max_au_size;
+   uint32_t max_qp;
+   uint32_t min_qp;
+
+   uint8_t  rate_ctrl_method; /* see enum pipe_h2645_enc_rate_control_method */
+   uint8_t  reserved[3];
+};
+
+struct virgl_h265_slice_descriptor
+{
+   uint32_t slice_segment_address;
+   uint32_t num_ctu_in_slice;
+
+   uint8_t  slice_type; /* see enum pipe_h265_slice_type */
+   uint8_t  reserved[3];
+};
+
+struct virgl_h265_enc_picture_desc
+{
+   struct virgl_base_picture_desc base;
+
+   struct virgl_h265_enc_seq_param seq;
+   struct virgl_h265_enc_pic_param pic;
+   struct virgl_h265_enc_slice_param slice;
+   struct virgl_h265_enc_rate_control rc;
+
+   uint32_t decoded_curr_pic;
+   uint32_t reference_frames[16];
+   uint32_t frame_num;
+   uint32_t pic_order_cnt;
+   uint32_t pic_order_cnt_type;
+   uint32_t num_ref_idx_l0_active_minus1;
+   uint32_t num_ref_idx_l1_active_minus1;
+   uint32_t ref_idx_l0_list[15];
+   uint32_t ref_idx_l1_list[15];
+   uint32_t num_slice_descriptors;
+   struct virgl_h265_slice_descriptor slices_descriptors[128];
+   struct virgl_enc_quality_modes quality_modes;
+
+   uint8_t  picture_type; /* see enum pipe_h2645_enc_picture_type */
+   uint8_t  not_referenced;
+   uint8_t  reserved[2];
+};
+
+struct virgl_mpeg4_picture_desc
+{
+   struct virgl_base_picture_desc base;
+
+   int32_t trd[2];
+   int32_t trb[2];
+   uint16_t vop_time_increment_resolution;
+   uint8_t vop_coding_type;
+   uint8_t vop_fcode_forward;
+   uint8_t vop_fcode_backward;
+   uint8_t resync_marker_disable;
+   uint8_t interlaced;
+   uint8_t quant_type;
+   uint8_t quarter_sample;
+   uint8_t short_video_header;
+   uint8_t rounding_control;
+   uint8_t alternate_vertical_scan_flag;
+   uint8_t top_field_first;
+
+   uint8_t intra_matrix[64];
+   uint8_t non_intra_matrix[64];
+
+   uint32_t ref[2];
+};
+
+union virgl_picture_desc {
+    struct virgl_base_picture_desc base;
+    struct virgl_h264_picture_desc h264;
+    struct virgl_h265_picture_desc h265;
+    struct virgl_mpeg4_picture_desc mpeg4;
+    struct virgl_h264_enc_picture_desc h264_enc;
+    struct virgl_h265_enc_picture_desc h265_enc;
+};
+
+enum virgl_video_encode_stat {
+    VIRGL_VIDEO_ENCODE_STAT_NOT_STARTED = 0,
+    VIRGL_VIDEO_ENCODE_STAT_IN_PROGRESS,
+    VIRGL_VIDEO_ENCODE_STAT_SUCCESS,
+    VIRGL_VIDEO_ENCODE_STAT_FAILURE,
+};
+
+struct virgl_video_encode_feedback {
+    uint8_t stat;           /* see enum virgl_video_encode_stat */
+    uint8_t reserved[3];
+
+    uint32_t coded_size;    /* size of encoded data in bytes */
+};
+
+#endif /* VIRGL_VIDEO_HW_H */
+
diff --git a/src/virglrenderer.c b/src/virglrenderer.c
index b70aa61..c0294f6 100644
--- a/src/virglrenderer.c
+++ b/src/virglrenderer.c
@@ -185,12 +185,12 @@
 }
 
 static void per_context_fence_retire(struct virgl_context *ctx,
-                                     uint64_t queue_id,
+                                     uint32_t ring_idx,
                                      uint64_t fence_id)
 {
    state.cbs->write_context_fence(state.cookie,
                                   ctx->ctx_id,
-                                  queue_id,
+                                  ring_idx,
                                   fence_id);
 }
 
@@ -405,15 +405,16 @@
 
 int virgl_renderer_context_create_fence(uint32_t ctx_id,
                                         uint32_t flags,
-                                        uint64_t queue_id,
+                                        uint32_t ring_idx,
                                         uint64_t fence_id)
 {
+   TRACE_FUNC();
    struct virgl_context *ctx = virgl_context_lookup(ctx_id);
    if (!ctx)
       return -EINVAL;
 
    assert(state.cbs->version >= 3 && state.cbs->write_context_fence);
-   return ctx->submit_fence(ctx, flags, queue_id, fence_id);
+   return ctx->submit_fence(ctx, flags, ring_idx, fence_id);
 }
 
 void virgl_renderer_context_poll(uint32_t ctx_id)
@@ -436,7 +437,6 @@
 
 void virgl_renderer_force_ctx_0(void)
 {
-   TRACE_FUNC();
    if (state.vrend_initialized)
       vrend_renderer_force_ctx_0();
 }
@@ -564,11 +564,20 @@
    return state.cbs->make_current(state.cookie, 0, ctx);
 }
 
+static int get_drm_fd(void)
+{
+   if (state.cbs->get_drm_fd)
+      return state.cbs->get_drm_fd(state.cookie);
+
+   return -1;
+}
+
 static const struct vrend_if_cbs vrend_cbs = {
    ctx0_fence_retire,
    create_gl_context,
    destroy_gl_context,
    make_current,
+   get_drm_fd,
 };
 
 static int
@@ -596,11 +605,29 @@
                                              height);
 }
 
+static bool
+virgl_context_foreach_retire_fences(struct virgl_context *ctx,
+                                    UNUSED void* data)
+{
+   /* vrend contexts are polled explicitly by the caller */
+   if (ctx->capset_id != VIRGL_RENDERER_CAPSET_VIRGL &&
+       ctx->capset_id != VIRGL_RENDERER_CAPSET_VIRGL2)
+   {
+      assert(ctx->retire_fences);
+      ctx->retire_fences(ctx);
+   }
+   return true;
+}
+
 void virgl_renderer_poll(void)
 {
    TRACE_FUNC();
    if (state.vrend_initialized)
       vrend_renderer_poll();
+
+   struct virgl_context_foreach_args args;
+   args.callback = virgl_context_foreach_retire_fences;
+   virgl_context_foreach(&args);
 }
 
 void virgl_renderer_cleanup(UNUSED void *cookie)
@@ -652,8 +679,9 @@
       return -EBUSY;
 
    if (!state.client_initialized) {
-      if (cbs && (cbs->version < 1 ||
-                  cbs->version > VIRGL_RENDERER_CALLBACKS_VERSION))
+      if (!cbs ||
+          cbs->version < 1 ||
+          cbs->version > VIRGL_RENDERER_CALLBACKS_VERSION)
          return -1;
 
       state.cookie = cookie;
@@ -703,18 +731,23 @@
       void *egl_display = NULL;
 
       if (!cbs->create_gl_context || !cbs->destroy_gl_context ||
-          !cbs->make_current)
+          !cbs->make_current) {
+         ret = EINVAL;
          goto fail;
+      }
 
       egl_display = state.cbs->get_egl_display(cookie);
 
-      if (!egl_display)
+      if (!egl_display) {
+         ret = -1;
          goto fail;
-
+      }
       ret = vrend_winsys_init_external(egl_display);
 
-      if (ret)
+      if (ret) {
+         ret = -1;
          goto fail;
+      }
 
       state.external_winsys_initialized = true;
    }
@@ -733,6 +766,8 @@
          renderer_flags |= VREND_USE_ASYNC_FENCE_CB;
       if (flags & VIRGL_RENDERER_USE_EXTERNAL_BLOB)
          renderer_flags |= VREND_USE_EXTERNAL_BLOB;
+      if (flags & VIRGL_RENDERER_USE_VIDEO)
+         renderer_flags |= VREND_USE_VIDEO;
 
       ret = vrend_renderer_init(&vrend_cbs, renderer_flags);
       if (ret)
@@ -1088,6 +1123,7 @@
 int
 virgl_renderer_resource_export_blob(uint32_t res_id, uint32_t *fd_type, int *fd)
 {
+   TRACE_FUNC();
    struct virgl_resource *res = virgl_resource_lookup(res_id);
    if (!res)
       return EINVAL;
diff --git a/src/virglrenderer.h b/src/virglrenderer.h
index 21fca95..40991d1 100644
--- a/src/virglrenderer.h
+++ b/src/virglrenderer.h
@@ -78,7 +78,7 @@
    int (*get_drm_fd)(void *cookie);
 
 #ifdef VIRGL_RENDERER_UNSTABLE_APIS
-   void (*write_context_fence)(void *cookie, uint32_t ctx_id, uint64_t queue_id, uint64_t fence_id);
+   void (*write_context_fence)(void *cookie, uint32_t ctx_id, uint32_t ring_idx, uint64_t fence_id);
 
    /* version 0: a connected socket of type SOCK_SEQPACKET */
    int (*get_server_fd)(void *cookie, uint32_t version);
@@ -140,6 +140,10 @@
  */
 #define VIRGL_RENDERER_DRM           (1 << 10)
 
+/* Video encode/decode */
+#define VIRGL_RENDERER_USE_VIDEO     (1 << 11)
+
+
 #endif /* VIRGL_RENDERER_UNSTABLE_APIS */
 
 VIRGL_EXPORT int virgl_renderer_init(void *cookie, int flags, struct virgl_renderer_callbacks *cb);
@@ -308,12 +312,6 @@
 
 VIRGL_EXPORT int virgl_renderer_execute(void *execute_args, uint32_t execute_size);
 
-/*
- * These are unstable APIs for development only. Use these for development/testing purposes
- * only, not in production
- */
-#ifdef VIRGL_RENDERER_UNSTABLE_APIS
-
 #define VIRGL_RENDERER_CONTEXT_FLAG_CAPSET_ID_MASK 0xff
 
 VIRGL_EXPORT int virgl_renderer_context_create_with_flags(uint32_t ctx_id,
@@ -364,6 +362,12 @@
 VIRGL_EXPORT int
 virgl_renderer_resource_export_blob(uint32_t res_id, uint32_t *fd_type, int *fd);
 
+/*
+ * These are unstable APIs for development only. Use these for development/testing purposes
+ * only, not in production
+ */
+#ifdef VIRGL_RENDERER_UNSTABLE_APIS
+
 struct virgl_renderer_resource_import_blob_args
 {
    uint32_t res_handle;
@@ -382,7 +386,7 @@
 #define VIRGL_RENDERER_FENCE_FLAG_MERGEABLE      (1 << 0)
 VIRGL_EXPORT int virgl_renderer_context_create_fence(uint32_t ctx_id,
                                                      uint32_t flags,
-                                                     uint64_t queue_id,
+                                                     uint32_t ring_idx,
                                                      uint64_t fence_id);
 VIRGL_EXPORT void virgl_renderer_context_poll(uint32_t ctx_id); /* force fences */
 VIRGL_EXPORT int virgl_renderer_context_get_poll_fd(uint32_t ctx_id);
diff --git a/src/vrend_blitter.c b/src/vrend_blitter.c
index c92ea05..aa5e7a8 100644
--- a/src/vrend_blitter.c
+++ b/src/vrend_blitter.c
@@ -428,19 +428,24 @@
    return prog_id;
 }
 
-static uint32_t program_hash_func(void *key)
+static uint32_t program_hash_func(const void *key)
 {
    return XXH32(key, sizeof(struct blit_prog_key), 0);
 }
 
-static int program_comp_func(void *key1, void *key2)
+static bool program_equal_func(const void *key1, const void *key2)
 {
-   return memcmp(key1, key2, sizeof(struct blit_prog_key));
+   return memcmp(key1, key2, sizeof(struct blit_prog_key)) == 0;
 }
 
 static void program_destroy_func(void *shader_id)
 {
-   GLuint id = ((uint64_t)(shader_id)) & 0xffffffff;
+   GLuint id;
+#if __SIZEOF_POINTER__  == 8
+   id = ((uint64_t)(shader_id)) & 0xffffffff;
+#else
+   id = (GLuint)(shader_id);
+#endif
    glDeleteProgram(id);
 }
 
@@ -455,7 +460,7 @@
    }
 
    vrend_blit_ctx.blit_programs = util_hash_table_create(program_hash_func,
-                                                         program_comp_func,
+                                                         program_equal_func,
                                                          program_destroy_func);
 
    blit_ctx->use_gles = epoxy_is_desktop_gl() == 0;
diff --git a/src/vrend_debug.c b/src/vrend_debug.c
index 8c1cd93..9143013 100644
--- a/src/vrend_debug.c
+++ b/src/vrend_debug.c
@@ -82,6 +82,15 @@
    "GET_MEMORY_INFO",
    "SEND_STRING_MARKER",
    "LINK_SHADER",
+   "CREATE_VIDEO_CODEC",
+   "DESTROY_VIDEO_CODEC",
+   "CREATE_VIDEO_BUFFER",
+   "DESTROY_VIDEO_BUFFER",
+   "BEGIN_FRAME",
+   "DECODE_MACROBLOCK",
+   "DECODE_BITSTREAM",
+   "ENCODE_BITSTREAM",
+   "END_FRAME",
 };
 
 static const char *object_type_names[VIRGL_MAX_OBJECTS] = {
@@ -156,7 +165,7 @@
    return retval;
 }
 
-void vrend_init_debug_flags()
+void vrend_init_debug_flags(void)
 {
    if (!vrend_debug_flags_initalized)  {
       vrend_debug_flags_initalized = 1;
diff --git a/src/vrend_decode.c b/src/vrend_decode.c
index 3bd3f15..8bf6de7 100644
--- a/src/vrend_decode.c
+++ b/src/vrend_decode.c
@@ -41,6 +41,10 @@
 #include "vrend_tweaks.h"
 #include "virgl_util.h"
 
+#ifdef ENABLE_VIDEO
+#include "vrend_video.h"
+#endif
+
 /* decode side */
 #define DECODE_MAX_TOKENS 8000
 
@@ -229,8 +233,7 @@
    arr[2] = get_buf_entry(buf, VIRGL_TEXTURE_ARRAY_C);
    arr[3] = get_buf_entry(buf, VIRGL_TEXTURE_ARRAY_D);
 
-   vrend_clear_texture(ctx, handle, level, &box, (void *) &arr);
-   return 0;
+   return vrend_clear_texture(ctx, handle, level, &box, (void *) &arr);
 }
 
 static int vrend_decode_set_viewport_state(struct vrend_context *ctx, const uint32_t *buf, uint32_t length)
@@ -669,6 +672,7 @@
    state.compare_func = (tmp >> 16) & 0x7;
    state.seamless_cube_map = (tmp >> 19) & 0x1;
    state.max_anisotropy = (float)((tmp >> 20) & 0x3f);
+   state.normalized_coords = 0;
 
    state.lod_bias = uif(get_buf_entry(buf, VIRGL_OBJ_SAMPLER_STATE_LOD_BIAS));
    state.min_lod = uif(get_buf_entry(buf, VIRGL_OBJ_SAMPLER_STATE_MIN_LOD));
@@ -1168,7 +1172,7 @@
    handles[PIPE_SHADER_TESS_EVAL] = get_buf_entry(buf, VIRGL_LINK_SHADER_TESS_EVAL_HANDLE);
    handles[PIPE_SHADER_COMPUTE] = get_buf_entry(buf, VIRGL_LINK_SHADER_COMPUTE_HANDLE);
 
-   vrend_link_program(ctx, handles);
+   vrend_link_program_hook(ctx, handles);
    return 0;
 }
 
@@ -1628,6 +1632,187 @@
    return 0;
 }
 
+#ifdef ENABLE_VIDEO
+/* video codec related functions */
+
+static int vrend_decode_create_video_codec(struct vrend_context *ctx,
+                                           const uint32_t *buf,
+                                           uint32_t length)
+{
+   struct vrend_video_context *vctx = vrend_context_get_video_ctx(ctx);
+
+   if (length < VIRGL_CREATE_VIDEO_CODEC_MIN_SIZE)
+      return EINVAL;
+
+   uint32_t handle     = get_buf_entry(buf, VIRGL_CREATE_VIDEO_CODEC_HANDLE);
+   uint32_t profile    = get_buf_entry(buf, VIRGL_CREATE_VIDEO_CODEC_PROFILE);
+   uint32_t entrypoint = get_buf_entry(buf, VIRGL_CREATE_VIDEO_CODEC_ENTRYPOINT);
+   uint32_t chroma_fmt = get_buf_entry(buf, VIRGL_CREATE_VIDEO_CODEC_CHROMA_FMT);
+   uint32_t level      = get_buf_entry(buf, VIRGL_CREATE_VIDEO_CODEC_LEVEL);
+   uint32_t width      = get_buf_entry(buf, VIRGL_CREATE_VIDEO_CODEC_WIDTH);
+   uint32_t height     = get_buf_entry(buf, VIRGL_CREATE_VIDEO_CODEC_HEIGHT);
+   uint32_t max_ref    = 2; /* The max number of ref frames is 2 by default */
+
+   if (length >= VIRGL_CREATE_VIDEO_CODEC_MAX_REF)
+      max_ref = get_buf_entry(buf, VIRGL_CREATE_VIDEO_CODEC_MAX_REF);
+
+   vrend_video_create_codec(vctx, handle, profile, entrypoint,
+                            chroma_fmt, level, width, height, max_ref, 0);
+
+   return 0;
+}
+
+static int vrend_decode_destroy_video_codec(struct vrend_context *ctx,
+                                            const uint32_t *buf,
+                                            uint32_t length)
+{
+   struct vrend_video_context *vctx = vrend_context_get_video_ctx(ctx);
+
+    if (length < VIRGL_DESTROY_VIDEO_CODEC_MIN_SIZE)
+       return EINVAL;
+
+   uint32_t handle = get_buf_entry(buf, VIRGL_DESTROY_VIDEO_CODEC_HANDLE);
+   vrend_video_destroy_codec(vctx, handle);
+
+   return 0;
+}
+
+static int vrend_decode_create_video_buffer(struct vrend_context *ctx,
+                                            const uint32_t *buf,
+                                            uint32_t length)
+{
+   uint32_t i, num_res;
+   uint32_t res_handles[VREND_VIDEO_BUFFER_PLANE_NUM];
+   struct vrend_video_context *vctx = vrend_context_get_video_ctx(ctx);
+
+   if (length < VIRGL_CREATE_VIDEO_BUFFER_MIN_SIZE)
+      return EINVAL;
+
+   num_res = length - VIRGL_CREATE_VIDEO_BUFFER_RES_BASE + 1;
+   if (num_res > VREND_VIDEO_BUFFER_PLANE_NUM)
+       num_res = VREND_VIDEO_BUFFER_PLANE_NUM;
+
+   uint32_t handle = get_buf_entry(buf, VIRGL_CREATE_VIDEO_BUFFER_HANDLE);
+   uint32_t format = get_buf_entry(buf, VIRGL_CREATE_VIDEO_BUFFER_FORMAT);
+   uint32_t width  = get_buf_entry(buf, VIRGL_CREATE_VIDEO_BUFFER_WIDTH);
+   uint32_t height = get_buf_entry(buf, VIRGL_CREATE_VIDEO_BUFFER_HEIGHT);
+
+   memset(res_handles, 0, sizeof(res_handles));
+   for (i = 0; i < num_res; i++)
+       res_handles[i] = get_buf_entry(buf,
+                                      VIRGL_CREATE_VIDEO_BUFFER_RES_BASE + i);
+
+   vrend_video_create_buffer(vctx, handle, format, width, height,
+                                      res_handles, num_res);
+
+   return 0;
+}
+
+static int vrend_decode_destroy_video_buffer(struct vrend_context *ctx,
+                                             const uint32_t *buf,
+                                             uint32_t length)
+{
+   struct vrend_video_context *vctx = vrend_context_get_video_ctx(ctx);
+
+   if (length < VIRGL_DESTROY_VIDEO_BUFFER_MIN_SIZE)
+      return EINVAL;
+
+   uint32_t handle = get_buf_entry(buf, VIRGL_DESTROY_VIDEO_BUFFER_HANDLE);
+   vrend_video_destroy_buffer(vctx, handle);
+
+   return 0;
+}
+
+static int vrend_decode_begin_frame(struct vrend_context *ctx,
+                                    const uint32_t *buf,
+                                    uint32_t length)
+{
+   struct vrend_video_context *vctx = vrend_context_get_video_ctx(ctx);
+
+   if (length < VIRGL_BEGIN_FRAME_MIN_SIZE)
+      return EINVAL;
+
+   uint32_t cdc_handle = get_buf_entry(buf, VIRGL_BEGIN_FRAME_CDC_HANDLE);
+   uint32_t tgt_handle = get_buf_entry(buf, VIRGL_BEGIN_FRAME_TGT_HANDLE);
+   vrend_video_begin_frame(vctx, cdc_handle, tgt_handle);
+
+   return 0;
+}
+
+static int vrend_decode_decode_bitstream(struct vrend_context *ctx,
+                                         const uint32_t *buf,
+                                         uint32_t length)
+{
+   struct vrend_video_context *vctx = vrend_context_get_video_ctx(ctx);
+
+   if (length < VIRGL_DECODE_BS_MIN_SIZE)
+      return EINVAL;
+
+   uint32_t cdc_handle = get_buf_entry(buf, VIRGL_DECODE_BS_CDC_HANDLE);
+   uint32_t tgt_handle = get_buf_entry(buf, VIRGL_DECODE_BS_TGT_HANDLE);
+   uint32_t dsc_handle = get_buf_entry(buf, VIRGL_DECODE_BS_DSC_HANDLE);
+   uint32_t buf_handle = get_buf_entry(buf, VIRGL_DECODE_BS_BUF_HANDLE);
+   uint32_t buf_size   = get_buf_entry(buf, VIRGL_DECODE_BS_BUF_SIZE);
+
+   vrend_video_decode_bitstream(vctx, cdc_handle, tgt_handle,
+                                dsc_handle, 1, &buf_handle, &buf_size);
+
+   return 0;
+}
+
+static int vrend_decode_encode_bitstream(struct vrend_context *ctx,
+                                         const uint32_t *buf,
+                                         uint32_t length)
+{
+   struct vrend_video_context *vctx = vrend_context_get_video_ctx(ctx);
+
+   if (length < VIRGL_ENCODE_BS_MIN_SIZE)
+      return EINVAL;
+
+   uint32_t cdc_handle  = get_buf_entry(buf, VIRGL_ENCODE_BS_CDC_HANDLE);
+   uint32_t src_handle  = get_buf_entry(buf, VIRGL_ENCODE_BS_SRC_HANDLE);
+   uint32_t dest_handle = get_buf_entry(buf, VIRGL_ENCODE_BS_DEST_HANDLE);
+   uint32_t desc_handle = get_buf_entry(buf, VIRGL_ENCODE_BS_DESC_HANDLE);
+   uint32_t feed_handle = get_buf_entry(buf, VIRGL_ENCODE_BS_FEED_HANDLE);
+
+   vrend_video_encode_bitstream(vctx, cdc_handle, src_handle, dest_handle,
+                                desc_handle, feed_handle);
+
+   return 0;
+}
+
+static int vrend_decode_end_frame(struct vrend_context *ctx,
+                                  const uint32_t *buf,
+                                  uint32_t length)
+{
+   struct vrend_video_context *vctx = vrend_context_get_video_ctx(ctx);
+
+   if (length < VIRGL_END_FRAME_MIN_SIZE)
+      return EINVAL;
+
+   uint32_t cdc_handle = get_buf_entry(buf, VIRGL_END_FRAME_CDC_HANDLE);
+   uint32_t tgt_handle = get_buf_entry(buf, VIRGL_END_FRAME_TGT_HANDLE);
+
+   vrend_video_end_frame(vctx, cdc_handle, tgt_handle);
+
+   return 0;
+}
+
+#else
+
+static int vrend_unsupported(struct vrend_context *ctx,
+                                    const uint32_t *buf,
+                                    uint32_t length)
+{
+   (void)ctx;
+   (void)buf;
+   (void)length;
+   return EINVAL;
+}
+
+#endif /* ENABLE_VIDEO */
+
+
 typedef int (*vrend_decode_callback)(struct vrend_context *ctx, const uint32_t *buf, uint32_t length);
 
 static int vrend_decode_dummy(struct vrend_context *ctx, const uint32_t *buf, uint32_t length)
@@ -1692,6 +1877,27 @@
    [VIRGL_CCMD_GET_MEMORY_INFO] = vrend_decode_get_memory_info,
    [VIRGL_CCMD_SEND_STRING_MARKER] = vrend_decode_send_string_marker,
    [VIRGL_CCMD_LINK_SHADER] = vrend_decode_link_shader,
+#ifdef ENABLE_VIDEO
+   [VIRGL_CCMD_CREATE_VIDEO_CODEC] = vrend_decode_create_video_codec,
+   [VIRGL_CCMD_DESTROY_VIDEO_CODEC] = vrend_decode_destroy_video_codec,
+   [VIRGL_CCMD_CREATE_VIDEO_BUFFER] = vrend_decode_create_video_buffer,
+   [VIRGL_CCMD_DESTROY_VIDEO_BUFFER] = vrend_decode_destroy_video_buffer,
+   [VIRGL_CCMD_BEGIN_FRAME] = vrend_decode_begin_frame,
+   [VIRGL_CCMD_DECODE_MACROBLOCK] = vrend_decode_dummy,
+   [VIRGL_CCMD_DECODE_BITSTREAM] = vrend_decode_decode_bitstream,
+   [VIRGL_CCMD_ENCODE_BITSTREAM] = vrend_decode_encode_bitstream,
+   [VIRGL_CCMD_END_FRAME] = vrend_decode_end_frame,
+#else
+   [VIRGL_CCMD_CREATE_VIDEO_CODEC] = vrend_unsupported,
+   [VIRGL_CCMD_DESTROY_VIDEO_CODEC] = vrend_unsupported,
+   [VIRGL_CCMD_CREATE_VIDEO_BUFFER] = vrend_unsupported,
+   [VIRGL_CCMD_DESTROY_VIDEO_BUFFER] = vrend_unsupported,
+   [VIRGL_CCMD_BEGIN_FRAME] = vrend_unsupported,
+   [VIRGL_CCMD_DECODE_MACROBLOCK] = vrend_unsupported,
+   [VIRGL_CCMD_DECODE_BITSTREAM] = vrend_unsupported,
+   [VIRGL_CCMD_ENCODE_BITSTREAM] = vrend_unsupported,
+   [VIRGL_CCMD_END_FRAME] = vrend_unsupported,
+#endif
 };
 
 static int vrend_decode_ctx_submit_cmd(struct virgl_context *ctx,
@@ -1760,12 +1966,12 @@
 
 static int vrend_decode_ctx_submit_fence(struct virgl_context *ctx,
                                          uint32_t flags,
-                                         uint64_t queue_id,
+                                         uint32_t ring_idx,
                                          uint64_t fence_id)
 {
    struct vrend_decode_ctx *dctx = (struct vrend_decode_ctx *)ctx;
 
-   if (queue_id)
+   if (ring_idx)
       return -EINVAL;
 
    return vrend_renderer_create_fence(dctx->grctx, flags, fence_id);
diff --git a/src/vrend_formats.c b/src/vrend_formats.c
index 50c393a..fde607c 100644
--- a/src/vrend_formats.c
+++ b/src/vrend_formats.c
@@ -292,6 +292,8 @@
 
   { VIRGL_FORMAT_L8_SRGB, GL_SR8_EXT, GL_RED, GL_UNSIGNED_BYTE, RRR1_SWIZZLE },
   { VIRGL_FORMAT_R8_SRGB, GL_SR8_EXT, GL_RED, GL_UNSIGNED_BYTE, NO_SWIZZLE },
+
+  { VIRGL_FORMAT_R8G8_SRGB, GL_SRG8_EXT, GL_RG, GL_UNSIGNED_BYTE, NO_SWIZZLE },
 };
 
 static struct vrend_format_table bit10_formats[] = {
@@ -424,46 +426,6 @@
     glBindTexture(GL_TEXTURE_2D, tex_id);
     glBindFramebuffer(GL_FRAMEBUFFER, fb_id);
 
-    /* we can't probe compressed formats, as we'd need valid payloads to
-     * glCompressedTexImage2D. Let's just check for extensions instead.
-     */
-    if (table[i].format < VIRGL_FORMAT_MAX) {
-       const struct util_format_description *desc = util_format_description(table[i].format);
-       switch (desc->layout) {
-       case UTIL_FORMAT_LAYOUT_S3TC:
-          if (epoxy_has_gl_extension("GL_S3_s3tc") ||
-              epoxy_has_gl_extension("GL_EXT_texture_compression_s3tc"))
-             vrend_insert_format(&table[i], VIRGL_BIND_SAMPLER_VIEW, flags);
-          continue;
-
-       case UTIL_FORMAT_LAYOUT_RGTC:
-          if (epoxy_has_gl_extension("GL_ARB_texture_compression_rgtc") ||
-              epoxy_has_gl_extension("GL_EXT_texture_compression_rgtc") )
-             vrend_insert_format(&table[i], VIRGL_BIND_SAMPLER_VIEW, flags);
-          continue;
-
-       case UTIL_FORMAT_LAYOUT_ETC:
-          if ((table[i].format == VIRGL_FORMAT_ETC1_RGB8 &&
-               epoxy_has_gl_extension("GL_OES_compressed_ETC1_RGB8_texture")) ||
-               (table[i].format != VIRGL_FORMAT_ETC1_RGB8 && gles_ver >= 30))
-             vrend_insert_format(&table[i], VIRGL_BIND_SAMPLER_VIEW, flags);
-          continue;
-
-       case UTIL_FORMAT_LAYOUT_BPTC:
-          if (epoxy_has_gl_extension("GL_ARB_texture_compression_bptc") ||
-              epoxy_has_gl_extension("GL_EXT_texture_compression_bptc"))
-             vrend_insert_format(&table[i], VIRGL_BIND_SAMPLER_VIEW, flags);
-          continue;
-
-         case UTIL_FORMAT_LAYOUT_ASTC:
-               if(epoxy_has_gl_extension("GL_KHR_texture_compression_astc_ldr"))
-                   vrend_insert_format(&table[i], VIRGL_BIND_SAMPLER_VIEW, flags);
-          continue;
-       default:
-          ;/* do logic below */
-       }
-    }
-
     /* The error state should be clear here */
     status = glGetError();
     assert(status == GL_NO_ERROR);
@@ -560,7 +522,17 @@
   }
 }
 
+static void vrend_add_compressed_formats(struct vrend_format_table *table, int num_entries)
+{
+   int flags = epoxy_is_desktop_gl() ? VIRGL_TEXTURE_CAN_READBACK : 0;
+   for (int i = 0; i < num_entries; i++) {
+      vrend_insert_format(&table[i], VIRGL_BIND_SAMPLER_VIEW, flags);
+   }
+}
+
+
 #define add_formats(x) vrend_add_formats((x), ARRAY_SIZE((x)))
+#define add_compressed_formats(x) vrend_add_compressed_formats((x), ARRAY_SIZE((x)))
 
 void vrend_build_format_list_common(void)
 {
@@ -590,10 +562,20 @@
   add_formats(snorm_la_formats);
 
   /* compressed */
-  add_formats(etc2_formats);
-  add_formats(rgtc_formats);
-  add_formats(dxtn_formats);
-  add_formats(dxtn_srgb_formats);
+  if (epoxy_has_gl_extension("GL_S3_s3tc") ||
+      epoxy_has_gl_extension("GL_EXT_texture_compression_s3tc") ||
+      epoxy_has_gl_extension("GL_ANGLE_texture_compression_dxt")) {
+     add_compressed_formats(dxtn_formats);
+     add_compressed_formats(dxtn_srgb_formats);
+  }
+
+  if (epoxy_has_gl_extension("GL_ARB_texture_compression_rgtc") ||
+      epoxy_has_gl_extension("GL_EXT_texture_compression_rgtc") )
+     add_compressed_formats(rgtc_formats);
+
+  if (epoxy_has_gl_extension("GL_ARB_texture_compression_bptc") ||
+      epoxy_has_gl_extension("GL_EXT_texture_compression_bptc"))
+     add_compressed_formats(bptc_formats);
 
   add_formats(srgb_formats);
 
@@ -601,8 +583,6 @@
 
   add_formats(packed_float_formats);
   add_formats(exponent_float_formats);
-
-  add_formats(bptc_formats);
 }
 
 
@@ -632,7 +612,14 @@
    */
   add_formats(gles_z32_format);
   add_formats(gles_bit10_formats);
-  add_formats(astc_formats);
+
+  if (epoxy_has_gl_extension("GL_KHR_texture_compression_astc_ldr"))
+     add_compressed_formats(astc_formats);
+
+  if (epoxy_gl_version() >= 30) {
+     add_compressed_formats(etc2_formats);
+  }
+
 }
 
 /* glTexStorage may not support all that is supported by glTexImage,
@@ -684,7 +671,7 @@
    }
 }
 
-bool vrend_check_framebuffer_mixed_color_attachements()
+bool vrend_check_framebuffer_mixed_color_attachements(void)
 {
    GLuint tex_id[2];
    GLuint fb_id;
@@ -881,20 +868,21 @@
         (src == VIRGL_FORMAT_ASTC_10x8 && dst == VIRGL_FORMAT_ASTC_10x8_SRGB) ||
         (src == VIRGL_FORMAT_ASTC_10x10 && dst == VIRGL_FORMAT_ASTC_10x10_SRGB) ||
         (src == VIRGL_FORMAT_ASTC_12x10 && dst == VIRGL_FORMAT_ASTC_12x10_SRGB) ||
-        (src == VIRGL_FORMAT_ASTC_12x12 && dst == VIRGL_FORMAT_ASTC_12x12_SRGB))
+        (src == VIRGL_FORMAT_ASTC_12x12 && dst == VIRGL_FORMAT_ASTC_12x12_SRGB) ||
+        (src == VIRGL_FORMAT_ETC2_R11_UNORM && dst == VIRGL_FORMAT_ETC2_R11_SNORM) ||
+        (src == VIRGL_FORMAT_ETC2_RG11_UNORM && dst == VIRGL_FORMAT_ETC2_RG11_SNORM) ||
+        (src == VIRGL_FORMAT_ETC2_RGBA8 && dst == VIRGL_FORMAT_ETC2_SRGBA8) ||
+        (src == VIRGL_FORMAT_ETC2_RGB8A1 && dst == VIRGL_FORMAT_ETC2_SRGB8A1) ||
+        (src == VIRGL_FORMAT_ETC2_RGB8 && dst == VIRGL_FORMAT_ETC2_SRGB8))
          return true;
    }
 
    if ((src == VIRGL_FORMAT_RGTC1_UNORM && dst == VIRGL_FORMAT_RGTC1_SNORM) ||
        (src == VIRGL_FORMAT_RGTC2_UNORM && dst == VIRGL_FORMAT_RGTC2_SNORM) ||
        (src == VIRGL_FORMAT_BPTC_RGBA_UNORM && dst == VIRGL_FORMAT_BPTC_SRGBA) ||
-       (src == VIRGL_FORMAT_BPTC_RGB_FLOAT && dst == VIRGL_FORMAT_BPTC_RGB_UFLOAT) ||
-       (src == VIRGL_FORMAT_ETC2_R11_UNORM && dst == VIRGL_FORMAT_ETC2_R11_SNORM) ||
-       (src == VIRGL_FORMAT_ETC2_RG11_UNORM && dst == VIRGL_FORMAT_ETC2_RG11_SNORM) ||
-       (src == VIRGL_FORMAT_ETC2_RGBA8 && dst == VIRGL_FORMAT_ETC2_SRGBA8) ||
-       (src == VIRGL_FORMAT_ETC2_RGB8A1 && dst == VIRGL_FORMAT_ETC2_SRGB8A1) ||
-       (src == VIRGL_FORMAT_ETC2_RGB8 && dst == VIRGL_FORMAT_ETC2_SRGB8))
-      return true;
+       (src == VIRGL_FORMAT_BPTC_RGB_FLOAT && dst == VIRGL_FORMAT_BPTC_RGB_UFLOAT))
+       return true;
+
    return false;
 }
 
diff --git a/src/vrend_object.c b/src/vrend_object.c
index 7025cd9..084e4ff 100644
--- a/src/vrend_object.c
+++ b/src/vrend_object.c
@@ -61,7 +61,7 @@
 struct util_hash_table *vrend_object_init_ctx_table(void)
 {
    struct util_hash_table *ctx_hash;
-   ctx_hash = util_hash_table_create(hash_func_u32, compare_func, free_object);
+   ctx_hash = util_hash_table_create(hash_func_u32, equal_func, free_object);
    return ctx_hash;
 }
 
@@ -82,7 +82,7 @@
 vrend_ctx_resource_init_table(void)
 {
    return util_hash_table_create(hash_func_u32,
-                                 compare_func,
+                                 equal_func,
                                  vrend_ctx_resource_destroy_func);
 }
 
diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c
index 5a433b0..4b7ee36 100644
--- a/src/vrend_renderer.c
+++ b/src/vrend_renderer.c
@@ -64,6 +64,10 @@
 #include <epoxy/glx.h>
 #endif
 
+#ifdef ENABLE_VIDEO
+#include <vrend_video.h>
+#endif
+
 /*
  * VIRGL_RENDERER_CAPSET_VIRGL has version 0 and 1, but they are both
  * virgl_caps_v1 and are exactly the same.
@@ -141,7 +145,7 @@
    feat_depth_clamp,
    feat_draw_instance,
    feat_dual_src_blend,
-   feat_egl_image_external,
+   feat_egl_image,
    feat_egl_image_storage,
    feat_enhanced_layouts,
    feat_fb_no_attach,
@@ -168,6 +172,7 @@
    feat_multi_draw_indirect,
    feat_nv_conditional_render,
    feat_nv_prim_restart,
+   feat_shader_noperspective_interpolation,
    feat_nvx_gpu_memory_info,
    feat_polygon_offset_clamp,
    feat_occlusion_query,
@@ -192,6 +197,7 @@
    feat_texture_gather,
    feat_texture_multisample,
    feat_texture_query_lod,
+   feat_texture_shadow_lod,
    feat_texture_srgb_decode,
    feat_texture_storage,
    feat_texture_view,
@@ -244,7 +250,7 @@
    FEAT(dual_src_blend, 33, UNAVAIL,  "GL_ARB_blend_func_extended", "GL_EXT_blend_func_extended" ),
    FEAT(depth_clamp, 32, UNAVAIL, "GL_ARB_depth_clamp", "GL_EXT_depth_clamp", "GL_NV_depth_clamp"),
    FEAT(enhanced_layouts, 44, UNAVAIL, "GL_ARB_enhanced_layouts"),
-   FEAT(egl_image_external, UNAVAIL, UNAVAIL, "GL_OES_EGL_image_external"),
+   FEAT(egl_image, UNAVAIL, UNAVAIL, "GL_OES_EGL_image"),
    FEAT(egl_image_storage, UNAVAIL, UNAVAIL, "GL_EXT_EGL_image_storage"),
    FEAT(fb_no_attach, 43, 31,  "GL_ARB_framebuffer_no_attachments" ),
    FEAT(framebuffer_fetch, UNAVAIL, UNAVAIL,  "GL_EXT_shader_framebuffer_fetch" ),
@@ -270,6 +276,7 @@
    FEAT(multi_draw_indirect, 43, UNAVAIL,  "GL_ARB_multi_draw_indirect", "GL_EXT_multi_draw_indirect" ),
    FEAT(nv_conditional_render, UNAVAIL, UNAVAIL,  "GL_NV_conditional_render" ),
    FEAT(nv_prim_restart, UNAVAIL, UNAVAIL,  "GL_NV_primitive_restart" ),
+   FEAT(shader_noperspective_interpolation, 31, UNAVAIL, "GL_NV_shader_noperspective_interpolation", "GL_EXT_gpu_shader4"),
    FEAT(nvx_gpu_memory_info, UNAVAIL, UNAVAIL, "GL_NVX_gpu_memory_info" ),
    FEAT(polygon_offset_clamp, 46, UNAVAIL,  "GL_ARB_polygon_offset_clamp", "GL_EXT_polygon_offset_clamp"),
    FEAT(occlusion_query, 15, UNAVAIL, "GL_ARB_occlusion_query"),
@@ -294,6 +301,7 @@
    FEAT(texture_gather, 40, 31,  "GL_ARB_texture_gather" ),
    FEAT(texture_multisample, 32, 31,  "GL_ARB_texture_multisample" ),
    FEAT(texture_query_lod, 40, UNAVAIL, "GL_ARB_texture_query_lod", "GL_EXT_texture_query_lod"),
+   FEAT(texture_shadow_lod, UNAVAIL, UNAVAIL, "GL_EXT_texture_shadow_lod"),
    FEAT(texture_srgb_decode, UNAVAIL, UNAVAIL,  "GL_EXT_texture_sRGB_decode" ),
    FEAT(texture_storage, 42, 30,  "GL_ARB_texture_storage" ),
    FEAT(texture_view, 43, UNAVAIL,  "GL_ARB_texture_view", "GL_OES_texture_view", "GL_EXT_texture_view" ),
@@ -342,6 +350,7 @@
    uint32_t max_texture_2d_size;
    uint32_t max_texture_3d_size;
    uint32_t max_texture_cube_size;
+   uint32_t max_shader_patch_varyings;
 
    /* inferred GL caching type */
    uint32_t inferred_gl_caching_type;
@@ -367,6 +376,7 @@
 
 struct sysval_uniform_block {
    GLfloat clipp[VIRGL_NUM_CLIP_PLANES][4];
+   GLuint stipple_pattern[VREND_POLYGON_STIPPLE_SIZE][4];
    GLfloat winsys_adjust_y;
    GLfloat alpha_ref_val;
    GLfloat clip_plane_enabled;
@@ -404,7 +414,11 @@
 struct vrend_linked_shader_program {
    struct list_head head;
    struct list_head sl[PIPE_SHADER_TYPES];
-   GLuint id;
+   bool is_pipeline;
+   union {
+       GLuint program;
+       GLuint pipeline;
+   } id;
 
    bool dual_src_linked;
    struct vrend_shader *ss[PIPE_SHADER_TYPES];
@@ -421,11 +435,10 @@
    GLuint *attrib_locs;
    uint32_t shadow_samp_mask[PIPE_SHADER_TYPES];
 
-   GLuint virgl_block_id;
-   GLuint virgl_block_bind;
-   GLuint ubo_sysval_buffer_id;
-
-   GLint fs_stipple_loc;
+   GLuint separate_virgl_block_id[PIPE_SHADER_TYPES];
+   GLint virgl_block_bind;
+   uint32_t sysvalue_data_cookie;
+   GLint ubo_sysval_buffer_id;
 
    uint32_t images_used_mask[PIPE_SHADER_TYPES];
    GLint *img_locs[PIPE_SHADER_TYPES];
@@ -447,8 +460,11 @@
 
    struct vrend_strarray glsl_strings;
    GLuint id;
+   GLuint program_id; /* only used for separable shaders */
+   GLuint last_pipeline_id;
    uint32_t uid;
    bool is_compiled;
+   bool is_linked; /* only used for separable shaders */
    struct vrend_shader_key key;
    struct list_head programs;
 };
@@ -456,7 +472,6 @@
 struct vrend_shader_selector {
    struct pipe_reference reference;
 
-   unsigned num_shaders;
    enum pipe_shader_type type;
    struct vrend_shader_info sinfo;
 
@@ -681,7 +696,7 @@
    bool viewport_is_negative;
    /* this is set if the contents of the FBO look upside down when viewed
       with 0,0 as the bottom corner */
-   bool inverted_fbo_content;
+   bool fbo_origin_upper_left;
 
    GLuint blit_fb_ids[2];
 
@@ -694,7 +709,6 @@
    bool stencil_test_enabled;
    bool framebuffer_srgb_enabled;
 
-   GLuint program_id;
    int last_shader_idx;
 
    GLint draw_indirect_buffer;
@@ -728,6 +742,10 @@
    int prim_mode;
    bool drawing;
    struct vrend_context *parent;
+   struct sysval_uniform_block sysvalue_data;
+   uint32_t sysvalue_data_cookie;
+   uint32_t current_program_id;
+   uint32_t current_pipeline_id;
 };
 
 struct vrend_untyped_resource {
@@ -741,6 +759,10 @@
    struct list_head sub_ctxs;
    struct list_head vrend_resources;
 
+#ifdef ENABLE_VIDEO
+   struct vrend_video_context *video;
+#endif
+
    struct vrend_sub_context *sub;
    struct vrend_sub_context *sub0;
 
@@ -748,9 +770,6 @@
    /* has this ctx gotten an error? */
    bool in_error;
    bool ctx_switch_pending;
-   bool pstip_inited;
-
-   GLuint pstipple_tex_id;
 
    enum virgl_ctx_errors last_error;
 
@@ -786,7 +805,6 @@
    void *fence_retire_data;
 };
 
-static struct vrend_resource *vrend_renderer_ctx_res_lookup(struct vrend_context *ctx, int res_handle);
 static void vrend_pause_render_condition(struct vrend_context *ctx, bool pause);
 static void vrend_update_viewport_state(struct vrend_sub_context *sub_ctx);
 static void vrend_update_scissor_state(struct vrend_sub_context *sub_ctx);
@@ -1008,6 +1026,7 @@
    [VIRGL_ERROR_CTX_TRANSFER_IOV_BOUNDS]   = "IOV data size exceeds resource capacity",
    [VIRGL_ERROR_CTX_ILLEGAL_DUAL_SRC_BLEND]= "Dual source blend not supported",
    [VIRGL_ERROR_CTX_UNSUPPORTED_FUNCTION]  = "Unsupported host function called",
+   [VIRGL_ERROR_CTX_ILLEGAL_PROGRAM_PIPELINE] = "Illegal shader program pipeline",
 };
 
 void vrend_report_context_error_internal(const char *fname, struct vrend_context *ctx,
@@ -1197,6 +1216,8 @@
       vrend_destroy_program(ent);
    }
 
+   if (shader->sel->sinfo.separable_program)
+       glDeleteProgram(shader->program_id);
    glDeleteShader(shader->id);
    strarray_free(&shader->glsl_strings, true);
    free(shader);
@@ -1258,6 +1279,14 @@
       vrend_shader_dump(shader);
       return false;
    }
+
+   if (shader->sel->sinfo.separable_program) {
+       shader->program_id = glCreateProgram();
+       shader->last_pipeline_id = 0xffffffff;
+       glProgramParameteri(shader->program_id, GL_PROGRAM_SEPARABLE, GL_TRUE);
+       glAttachShader(shader->program_id, shader->id);
+   }
+
    shader->is_compiled = true;
    return true;
 }
@@ -1304,25 +1333,36 @@
       gltype == GL_TIME_ELAPSED;
 }
 
-static void vrend_use_program(struct vrend_sub_context *sub_ctx, GLuint program_id)
+static inline void use_program(struct vrend_sub_context *sub_ctx, uint32_t id)
 {
-   if (sub_ctx->program_id != program_id) {
-      glUseProgram(program_id);
-      sub_ctx->program_id = program_id;
-   }
+      if (sub_ctx->current_program_id != id) {
+         sub_ctx->current_program_id = id;
+         glUseProgram(id);
+      }
 }
 
-static void vrend_init_pstipple_texture(struct vrend_context *ctx)
+static inline void bind_pipeline(struct vrend_sub_context *sub_ctx, uint32_t id)
 {
-   glGenTextures(1, &ctx->pstipple_tex_id);
-   glBindTexture(GL_TEXTURE_2D, ctx->pstipple_tex_id);
-   glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 32, 32, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
-   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+      if (sub_ctx->current_pipeline_id != id) {
+         sub_ctx->current_pipeline_id = id;
+         glBindProgramPipeline(id);
+      }
+}
 
-   ctx->pstip_inited = true;
+static void vrend_use_program(struct vrend_sub_context *sub_ctx,
+                              struct vrend_linked_shader_program *program)
+{
+   GLuint id = !program ? 0 :
+                          program->is_pipeline ? program->id.pipeline :
+                                                 program->id.program;
+   if (program && program->is_pipeline) {
+      use_program(sub_ctx, 0);
+      bind_pipeline(sub_ctx, id);
+   } else {
+       if (has_feature(feat_separate_shader_objects))
+          bind_pipeline(sub_ctx, 0);
+       use_program(sub_ctx, id);
+   }
 }
 
 static void vrend_depth_test_enable(struct vrend_context *ctx, bool depth_test_enable)
@@ -1470,6 +1510,26 @@
          free(varyings[i]);
 }
 
+static inline int
+vrend_get_uniform_location(struct vrend_linked_shader_program *sprog,
+                           char *name, int shader_type)
+{
+    assert(!sprog->is_pipeline || sprog->ss[shader_type]->sel->sinfo.separable_program);
+
+    GLint id = sprog->is_pipeline ?
+                  sprog->ss[shader_type]->program_id :
+                  sprog->id.program;
+
+    return glGetUniformLocation(id, name);
+}
+
+static inline void
+vrend_set_active_pipeline_stage(struct vrend_linked_shader_program *sprog, int shader_type)
+{
+    if (sprog->is_pipeline && sprog->ss[shader_type])
+        glActiveShaderProgram(sprog->id.pipeline, sprog->ss[shader_type]->program_id);
+}
+
 static int bind_sampler_locs(struct vrend_linked_shader_program *sprog,
                              enum pipe_shader_type shader_type, int next_sampler_id)
 {
@@ -1496,13 +1556,17 @@
          } else
             snprintf(name, 32, "%ssamp%d", prefix, i);
 
-         glUniform1i(glGetUniformLocation(sprog->id, name), next_sampler_id++);
+         vrend_set_active_pipeline_stage(sprog, shader_type);
+         glUniform1i(vrend_get_uniform_location(sprog, name, shader_type),
+                     next_sampler_id++);
 
          if (sinfo->shadow_samp_mask & (1 << i)) {
             snprintf(name, 32, "%sshadmask%d", prefix, i);
-            sprog->shadow_samp_mask_locs[shader_type][sampler_index] = glGetUniformLocation(sprog->id, name);
+            sprog->shadow_samp_mask_locs[shader_type][sampler_index] =
+               vrend_get_uniform_location(sprog, name, shader_type);
             snprintf(name, 32, "%sshadadd%d", prefix, i);
-            sprog->shadow_samp_add_locs[shader_type][sampler_index] = glGetUniformLocation(sprog->id, name);
+            sprog->shadow_samp_add_locs[shader_type][sampler_index] =
+               vrend_get_uniform_location(sprog, name, shader_type);
          }
          sampler_index++;
       }
@@ -1522,9 +1586,36 @@
   if (sprog->ss[shader_type]->sel->sinfo.num_consts) {
      char name[32];
      snprintf(name, 32, "%sconst0", pipe_shader_to_prefix(shader_type));
-     sprog->const_location[shader_type] = glGetUniformLocation(sprog->id, name);
+     sprog->const_location[shader_type] = vrend_get_uniform_location(sprog, name,
+                                                                     shader_type);
   } else
-      sprog->const_location[shader_type] = -1;
+     sprog->const_location[shader_type] = -1;
+}
+
+static inline GLuint
+vrend_get_uniform_block_index(struct vrend_linked_shader_program *sprog,
+                              char *name, int shader_type)
+{
+    assert(!sprog->is_pipeline || sprog->ss[shader_type]->sel->sinfo.separable_program);
+
+    GLuint id = sprog->is_pipeline ?
+                  sprog->ss[shader_type]->program_id :
+                  sprog->id.program;
+
+    return glGetUniformBlockIndex(id, name);
+}
+
+static inline void
+vrend_uniform_block_binding(struct vrend_linked_shader_program *sprog,
+                            int shader_type, int loc, int value)
+{
+    assert(!sprog->is_pipeline || sprog->ss[shader_type]->sel->sinfo.separable_program);
+
+    GLint id = sprog->is_pipeline ?
+                  sprog->ss[shader_type]->program_id :
+                  sprog->id.program;
+
+    glUniformBlockBinding(id, loc, value);
 }
 
 static int bind_ubo_locs(struct vrend_linked_shader_program *sprog,
@@ -1543,8 +1634,8 @@
          else
             snprintf(name, 32, "%subo%d", prefix, ubo_idx);
 
-         GLuint loc = glGetUniformBlockIndex(sprog->id, name);
-         glUniformBlockBinding(sprog->id, loc, next_ubo_id++);
+         GLuint loc = vrend_get_uniform_block_index(sprog, name, shader_type);
+         vrend_uniform_block_binding(sprog, shader_type, loc, next_ubo_id++);
       }
    }
 
@@ -1553,6 +1644,75 @@
    return next_ubo_id;
 }
 
+static void bind_virgl_block_loc(struct vrend_linked_shader_program *sprog,
+                                 enum pipe_shader_type shader_type,
+                                 int virgl_block_ubo_id)
+{
+   sprog->separate_virgl_block_id[shader_type] =
+	 vrend_get_uniform_block_index(sprog, "VirglBlock", shader_type);
+
+   if (sprog->separate_virgl_block_id[shader_type] != GL_INVALID_INDEX) {
+      bool created_virgl_block_buffer = false;
+
+      if (sprog->virgl_block_bind == -1) {
+         sprog->virgl_block_bind = virgl_block_ubo_id;
+         if (sprog->ubo_sysval_buffer_id == -1) {
+             glGenBuffers(1, (GLuint *) &sprog->ubo_sysval_buffer_id);
+             created_virgl_block_buffer = true;
+         }
+      }
+
+      vrend_set_active_pipeline_stage(sprog, shader_type);
+      vrend_uniform_block_binding(sprog, shader_type,
+		                  sprog->separate_virgl_block_id[shader_type],
+				  sprog->virgl_block_bind);
+
+      GLint virgl_block_size;
+      int prog_id = sprog->is_pipeline ? sprog->ss[shader_type]->program_id :
+                                         sprog->id.program;
+      glGetActiveUniformBlockiv(prog_id, sprog->separate_virgl_block_id[shader_type],
+				GL_UNIFORM_BLOCK_DATA_SIZE, &virgl_block_size);
+      assert((size_t) virgl_block_size >= sizeof(struct sysval_uniform_block));
+
+      if (created_virgl_block_buffer) {
+         glBindBuffer(GL_UNIFORM_BUFFER, sprog->ubo_sysval_buffer_id);
+         glBufferData(GL_UNIFORM_BUFFER, virgl_block_size, NULL, GL_DYNAMIC_DRAW);
+         glBindBuffer(GL_UNIFORM_BUFFER, 0);
+      }
+   }
+}
+
+static void rebind_ubo_and_sampler_locs(struct vrend_linked_shader_program *sprog,
+                                        enum pipe_shader_type last_shader)
+{
+   int next_sampler_id = 0;
+   int next_ubo_id = 0;
+
+   for (enum pipe_shader_type shader_type = PIPE_SHADER_VERTEX;
+        shader_type <= last_shader;
+        shader_type++) {
+      if (!sprog->ss[shader_type])
+         continue;
+
+      next_sampler_id = bind_sampler_locs(sprog, shader_type, next_sampler_id);
+      next_ubo_id = bind_ubo_locs(sprog, shader_type, next_ubo_id);
+
+      if (sprog->is_pipeline)
+         sprog->ss[shader_type]->last_pipeline_id = sprog->id.pipeline;
+   }
+
+   /* Now `next_ubo_id` is the last ubo id, which is used for the VirglBlock. */
+   sprog->virgl_block_bind = -1;
+   for (enum pipe_shader_type shader_type = PIPE_SHADER_VERTEX;
+        shader_type <= last_shader;
+        shader_type++) {
+      if (!sprog->ss[shader_type])
+         continue;
+
+      bind_virgl_block_loc(sprog, shader_type, next_ubo_id);
+   }
+}
+
 static void bind_ssbo_locs(struct vrend_linked_shader_program *sprog,
                            enum pipe_shader_type shader_type)
 {
@@ -1589,7 +1749,8 @@
          struct vrend_array *img_array = &sinfo->image_arrays[i];
          for (int j = 0; j < img_array->array_size; j++) {
             snprintf(name, 32, "%simg%d[%d]", prefix, img_array->first, j);
-            sprog->img_locs[shader_type][img_array->first + j] = glGetUniformLocation(sprog->id, name);
+            sprog->img_locs[shader_type][img_array->first + j] =
+               vrend_get_uniform_location(sprog, name, shader_type);
             if (sprog->img_locs[shader_type][img_array->first + j] == -1)
                vrend_printf( "failed to get uniform loc for image %s\n", name);
          }
@@ -1598,7 +1759,8 @@
       for (i = 0; i < nsamp; i++) {
          if (mask & (1 << i)) {
             snprintf(name, 32, "%simg%d", prefix, i);
-            sprog->img_locs[shader_type][i] = glGetUniformLocation(sprog->id, name);
+            sprog->img_locs[shader_type][i] =
+               vrend_get_uniform_location(sprog, name, shader_type);
             if (sprog->img_locs[shader_type][i] == -1)
                vrend_printf( "failed to get uniform loc for image %s\n", name);
          } else {
@@ -1609,22 +1771,90 @@
    sprog->images_used_mask[shader_type] = mask;
 }
 
+static bool vrend_link(GLuint id)
+{
+   GLint lret;
+   glLinkProgram(id);
+   glGetProgramiv(id, GL_LINK_STATUS, &lret);
+   if (lret == GL_FALSE) {
+      char infolog[65536];
+      int len;
+      glGetProgramInfoLog(id, 65536, &len, infolog);
+      vrend_printf("Error linking program:\n%s\n", infolog);
+      return false;
+   }
+   return true;
+}
+
+static bool vrend_link_separable_shader(struct vrend_sub_context *sub_ctx,
+                                        struct vrend_shader *shader, int type)
+{
+   int i;
+   char name[64];
+
+   if (type == PIPE_SHADER_VERTEX || type == PIPE_SHADER_GEOMETRY ||
+       type == PIPE_SHADER_TESS_EVAL)
+       set_stream_out_varyings(sub_ctx, shader->program_id, &shader->sel->sinfo);
+
+   if (type == PIPE_SHADER_FRAGMENT && shader->sel->sinfo.num_outputs > 1) {
+      bool dual_src_linked = util_blend_state_is_dual(&sub_ctx->blend_state, 0);
+      if (dual_src_linked) {
+         if (has_feature(feat_dual_src_blend)) {
+            if (!vrend_state.use_gles) {
+               glBindFragDataLocationIndexed(shader->program_id, 0, 0, "fsout_c0");
+               glBindFragDataLocationIndexed(shader->program_id, 0, 1, "fsout_c1");
+            } else {
+               glBindFragDataLocationIndexedEXT(shader->program_id, 0, 0, "fsout_c0");
+               glBindFragDataLocationIndexedEXT(shader->program_id, 0, 1, "fsout_c1");
+            }
+         } else {
+            vrend_report_context_error(sub_ctx->parent, VIRGL_ERROR_CTX_ILLEGAL_DUAL_SRC_BLEND, 0);
+         }
+      } else if (!vrend_state.use_gles && has_feature(feat_dual_src_blend)) {
+         /* On GLES without dual source blending we emit the layout directly in the shader
+          * so there is no need to define the binding here */
+         for (int i = 0; i < shader->sel->sinfo.num_outputs; ++i) {
+            if (shader->sel->sinfo.fs_output_layout[i] >= 0) {
+               char buf[64];
+               snprintf(buf, sizeof(buf), "fsout_c%d",
+                        shader->sel->sinfo.fs_output_layout[i]);
+               glBindFragDataLocationIndexed(shader->program_id,
+                                             shader->sel->sinfo.fs_output_layout[i],
+                                             0, buf);
+            }
+         }
+      }
+   }
+
+   if (type == PIPE_SHADER_VERTEX && has_feature(feat_gles31_vertex_attrib_binding)) {
+      uint32_t mask = shader->sel->sinfo.attrib_input_mask;
+      while (mask) {
+         i = u_bit_scan(&mask);
+         snprintf(name, 32, "in_%d", i);
+         glBindAttribLocation(shader->program_id, i, name);
+      }
+   }
+
+   shader->is_linked = vrend_link(shader->program_id);
+
+   if (!shader->is_linked) {
+      /* dump shaders */
+      vrend_report_context_error(sub_ctx->parent, VIRGL_ERROR_CTX_ILLEGAL_SHADER, 0);
+      vrend_shader_dump(shader);
+   }
+
+   return shader->is_linked;
+}
+
 static struct vrend_linked_shader_program *add_cs_shader_program(struct vrend_context *ctx,
                                                                  struct vrend_shader *cs)
 {
    struct vrend_linked_shader_program *sprog = CALLOC_STRUCT(vrend_linked_shader_program);
    GLuint prog_id;
-   GLint lret;
    prog_id = glCreateProgram();
    glAttachShader(prog_id, cs->id);
-   glLinkProgram(prog_id);
 
-   glGetProgramiv(prog_id, GL_LINK_STATUS, &lret);
-   if (lret == GL_FALSE) {
-      char infolog[65536];
-      int len;
-      glGetProgramInfoLog(prog_id, 65536, &len, infolog);
-      vrend_printf("got error linking\n%s\n", infolog);
+   if (!vrend_link(prog_id)) {
       /* dump shaders */
       vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_SHADER, 0);
       vrend_shader_dump(cs);
@@ -1635,10 +1865,10 @@
    sprog->ss[PIPE_SHADER_COMPUTE] = cs;
 
    list_add(&sprog->sl[PIPE_SHADER_COMPUTE], &cs->programs);
-   sprog->id = prog_id;
+   sprog->id.program = prog_id;
    list_addtail(&sprog->head, &ctx->sub->cs_programs);
 
-   vrend_use_program(ctx->sub, prog_id);
+   vrend_use_program(ctx->sub, sprog);
 
    bind_sampler_locs(sprog, PIPE_SHADER_COMPUTE, 0);
    bind_ubo_locs(sprog, PIPE_SHADER_COMPUTE, 0);
@@ -1648,49 +1878,78 @@
    return sprog;
 }
 
+static inline bool
+vrend_link_stage(struct vrend_shader *stage) {
+   if (!stage->is_linked)
+      stage->is_linked = vrend_link(stage->program_id);
+   return stage->is_linked;
+}
+
 static struct vrend_linked_shader_program *add_shader_program(struct vrend_sub_context *sub_ctx,
                                                               struct vrend_shader *vs,
                                                               struct vrend_shader *fs,
                                                               struct vrend_shader *gs,
                                                               struct vrend_shader *tcs,
-                                                              struct vrend_shader *tes)
+                                                              struct vrend_shader *tes,
+                                                              bool separable)
 {
    struct vrend_linked_shader_program *sprog = CALLOC_STRUCT(vrend_linked_shader_program);
    char name[64];
    int i;
-   GLuint prog_id;
-   GLint lret;
+   GLuint prog_id = 0;
+   GLuint pipeline_id = 0;
+   GLuint vs_id, fs_id, gs_id, tes_id = 0;
    enum pipe_shader_type last_shader;
    if (!sprog)
       return NULL;
 
-   prog_id = glCreateProgram();
-   glAttachShader(prog_id, vs->id);
-   if (tcs && tcs->id > 0)
-      glAttachShader(prog_id, tcs->id);
-   if (tes && tes->id > 0)
-      glAttachShader(prog_id, tes->id);
+   if (separable) {
+       glGenProgramPipelines(1, &pipeline_id);
+
+       vs_id = vs->program_id;
+       fs_id = fs->program_id;
+       if (gs)
+           gs_id = gs->program_id;
+       if (tes)
+           tes_id = tes->program_id;
+   } else { /* inseparable programs */
+       prog_id = glCreateProgram();
+       glAttachShader(prog_id, vs->id);
+       if (tcs && tcs->id > 0)
+          glAttachShader(prog_id, tcs->id);
+       if (tes && tes->id > 0)
+          glAttachShader(prog_id, tes->id);
+       if (gs && gs->id > 0)
+          glAttachShader(prog_id, gs->id);
+       glAttachShader(prog_id, fs->id);
+
+       /* For the non-separable codepath (the usual path), all these shader stages are
+        * contained inside a single program. */
+       vs_id = prog_id;
+       fs_id = prog_id;
+       if (gs)
+           gs_id = prog_id;
+       if (tes)
+           tes_id = prog_id;
+   }
 
    if (gs) {
-      if (gs->id > 0)
-         glAttachShader(prog_id, gs->id);
-      set_stream_out_varyings(sub_ctx, prog_id, &gs->sel->sinfo);
+      set_stream_out_varyings(sub_ctx, gs_id, &gs->sel->sinfo);
    } else if (tes)
-      set_stream_out_varyings(sub_ctx, prog_id, &tes->sel->sinfo);
+      set_stream_out_varyings(sub_ctx, tes_id, &tes->sel->sinfo);
    else
-      set_stream_out_varyings(sub_ctx, prog_id, &vs->sel->sinfo);
-   glAttachShader(prog_id, fs->id);
+      set_stream_out_varyings(sub_ctx, vs_id, &vs->sel->sinfo);
 
    if (fs->sel->sinfo.num_outputs > 1) {
       sprog->dual_src_linked = util_blend_state_is_dual(&sub_ctx->blend_state, 0);
       if (sprog->dual_src_linked) {
          if (has_feature(feat_dual_src_blend)) {
             if (!vrend_state.use_gles) {
-               glBindFragDataLocationIndexed(prog_id, 0, 0, "fsout_c0");
-               glBindFragDataLocationIndexed(prog_id, 0, 1, "fsout_c1");
+               glBindFragDataLocationIndexed(fs_id, 0, 0, "fsout_c0");
+               glBindFragDataLocationIndexed(fs_id, 0, 1, "fsout_c1");
             } else {
-               glBindFragDataLocationIndexedEXT(prog_id, 0, 0, "fsout_c0");
-               glBindFragDataLocationIndexedEXT(prog_id, 0, 1, "fsout_c1");
+               glBindFragDataLocationIndexedEXT(fs_id, 0, 0, "fsout_c0");
+               glBindFragDataLocationIndexedEXT(fs_id, 0, 1, "fsout_c1");
             }
          } else {
             vrend_report_context_error(sub_ctx->parent, VIRGL_ERROR_CTX_ILLEGAL_DUAL_SRC_BLEND, 0);
@@ -1702,7 +1961,7 @@
             if (fs->sel->sinfo.fs_output_layout[i] >= 0) {
                char buf[64];
                snprintf(buf, sizeof(buf), "fsout_c%d", fs->sel->sinfo.fs_output_layout[i]);
-               glBindFragDataLocationIndexed(prog_id, fs->sel->sinfo.fs_output_layout[i], 0, buf);
+               glBindFragDataLocationIndexed(fs_id, fs->sel->sinfo.fs_output_layout[i], 0, buf);
             }
          }
       }
@@ -1714,18 +1973,30 @@
       while (mask) {
          i = u_bit_scan(&mask);
          snprintf(name, 32, "in_%d", i);
-         glBindAttribLocation(prog_id, i, name);
+         glBindAttribLocation(vs_id, i, name);
       }
    }
 
-   glLinkProgram(prog_id);
+   bool link_success;
+   if (separable) { /* separable programs */
+      link_success = vrend_link_stage(vs);
+      link_success &= vrend_link_stage(fs);
+      if (gs) link_success &= vrend_link_stage(gs);
+      if (tcs) link_success &= vrend_link_stage(tcs);
+      if (tes) link_success &= vrend_link_stage(tes);
+   } else { /* non-separable programs */
+      link_success = vrend_link(prog_id);
+   }
 
-   glGetProgramiv(prog_id, GL_LINK_STATUS, &lret);
-   if (lret == GL_FALSE) {
-      char infolog[65536];
-      int len;
-      glGetProgramInfoLog(prog_id, 65536, &len, infolog);
-      vrend_printf("got error linking\n%s\n", infolog);
+   if (!link_success) {
+      if (separable) {
+         glDeleteProgramPipelines(1, &pipeline_id);
+      } else {
+         glDeleteProgram(prog_id);
+      }
+
+      free(sprog);
+
       /* dump shaders */
       vrend_report_context_error(sub_ctx->parent, VIRGL_ERROR_CTX_ILLEGAL_SHADER, 0);
       vrend_shader_dump(vs);
@@ -1736,11 +2007,24 @@
       if (gs)
          vrend_shader_dump(gs);
       vrend_shader_dump(fs);
-      glDeleteProgram(prog_id);
-      free(sprog);
       return NULL;
    }
 
+   if (separable) {
+       glUseProgramStages(pipeline_id, GL_VERTEX_SHADER_BIT, vs->program_id);
+       if (tcs) glUseProgramStages(pipeline_id, GL_TESS_CONTROL_SHADER_BIT, tcs->program_id);
+       if (tes) glUseProgramStages(pipeline_id, GL_TESS_EVALUATION_SHADER_BIT, tes->program_id);
+       if (gs) glUseProgramStages(pipeline_id, GL_GEOMETRY_SHADER_BIT, gs->program_id);
+       glUseProgramStages(pipeline_id, GL_FRAGMENT_SHADER_BIT, fs->program_id);
+
+       glValidateProgramPipeline(pipeline_id);
+       GLint validation_status;
+       glGetProgramPipelineiv(pipeline_id, GL_VALIDATE_STATUS, &validation_status);
+       if (!validation_status) {
+           vrend_report_context_error(sub_ctx->parent, VIRGL_ERROR_CTX_ILLEGAL_PROGRAM_PIPELINE, 0);
+       }
+   }
+
    sprog->ss[PIPE_SHADER_VERTEX] = vs;
    sprog->ss[PIPE_SHADER_FRAGMENT] = fs;
    sprog->vs_fs_key = (((uint64_t)fs->id) << 32) | (vs->id & ~VREND_PROGRAM_NQUEUE_MASK) |
@@ -1760,46 +2044,31 @@
       list_add(&sprog->sl[PIPE_SHADER_TESS_EVAL], &tes->programs);
 
    last_shader = tes ? PIPE_SHADER_TESS_EVAL : (gs ? PIPE_SHADER_GEOMETRY : PIPE_SHADER_FRAGMENT);
-   sprog->id = prog_id;
+
+   sprog->is_pipeline = separable;
+   if (sprog->is_pipeline)
+       sprog->id.pipeline = pipeline_id;
+   else
+       sprog->id.program = prog_id;
 
    list_addtail(&sprog->head, &sub_ctx->gl_programs[vs->id & VREND_PROGRAM_NQUEUE_MASK]);
 
-   if (fs->key.pstipple_tex)
-      sprog->fs_stipple_loc = glGetUniformLocation(prog_id, "pstipple_sampler");
-   else
-      sprog->fs_stipple_loc = -1;
+   sprog->virgl_block_bind = -1;
+   sprog->ubo_sysval_buffer_id = -1;
 
-   vrend_use_program(sub_ctx, prog_id);
+   vrend_use_program(sub_ctx, sprog);
 
-   int next_ubo_id = 0, next_sampler_id = 0;
    for (enum pipe_shader_type shader_type = PIPE_SHADER_VERTEX;
         shader_type <= last_shader;
         shader_type++) {
       if (!sprog->ss[shader_type])
          continue;
 
-      next_sampler_id = bind_sampler_locs(sprog, shader_type, next_sampler_id);
       bind_const_locs(sprog, shader_type);
-      next_ubo_id = bind_ubo_locs(sprog, shader_type, next_ubo_id);
       bind_image_locs(sprog, shader_type);
       bind_ssbo_locs(sprog, shader_type);
    }
-
-   sprog->virgl_block_id = glGetUniformBlockIndex(prog_id, "VirglBlock");
-   if (sprog->virgl_block_id != GL_INVALID_INDEX) {
-      sprog->virgl_block_bind = next_ubo_id++;
-      glUniformBlockBinding(prog_id, sprog->virgl_block_id, sprog->virgl_block_bind);
-
-      GLint virgl_block_size;
-      glGetActiveUniformBlockiv(prog_id, sprog->virgl_block_id,
-                                GL_UNIFORM_BLOCK_DATA_SIZE, &virgl_block_size);
-      assert((size_t) virgl_block_size >= sizeof(struct sysval_uniform_block));
-
-      glGenBuffers(1, &sprog->ubo_sysval_buffer_id);
-      glBindBuffer(GL_UNIFORM_BUFFER, sprog->ubo_sysval_buffer_id);
-      glBufferData(GL_UNIFORM_BUFFER, virgl_block_size, NULL, GL_DYNAMIC_DRAW);
-      glBindBuffer(GL_UNIFORM_BUFFER, 0);
-   }
+   rebind_ubo_and_sampler_locs(sprog, last_shader);
 
    if (!has_feature(feat_gles31_vertex_attrib_binding)) {
       if (vs->sel->sinfo.num_inputs) {
@@ -1807,7 +2076,7 @@
          if (sprog->attrib_locs) {
             for (i = 0; i < vs->sel->sinfo.num_inputs; i++) {
                snprintf(name, 32, "in_%d", i);
-               sprog->attrib_locs[i] = glGetAttribLocation(prog_id, name);
+               sprog->attrib_locs[i] = glGetAttribLocation(vs_id, name);
             }
          }
       } else
@@ -1874,11 +2143,15 @@
    if (ent->ref_context && ent->ref_context->prog == ent)
       ent->ref_context->prog = NULL;
 
-   if (ent->virgl_block_id != GL_INVALID_INDEX) {
-      glDeleteBuffers(1, &ent->ubo_sysval_buffer_id);
+   if (ent->ubo_sysval_buffer_id != -1) {
+       glDeleteBuffers(1, (GLuint *) &ent->ubo_sysval_buffer_id);
    }
 
-   glDeleteProgram(ent->id);
+   if (ent->is_pipeline)
+       glDeleteProgramPipelines(1, &ent->id.pipeline);
+   else
+       glDeleteProgram(ent->id.program);
+
    list_del(&ent->head);
 
    for (i = PIPE_SHADER_VERTEX; i <= PIPE_SHADER_COMPUTE; i++) {
@@ -2706,7 +2979,7 @@
    int old_num;
    GLenum status;
    GLint new_height = -1;
-   bool new_ibf = false;
+   bool new_fbo_origin_upper_left = false;
 
    struct vrend_sub_context *sub_ctx = ctx->sub;
 
@@ -2755,10 +3028,10 @@
    /* find a buffer to set fb_height from */
    if (sub_ctx->nr_cbufs == 0 && !sub_ctx->zsurf) {
       new_height = 0;
-      new_ibf = false;
+      new_fbo_origin_upper_left = false;
    } else if (sub_ctx->nr_cbufs == 0) {
       new_height = u_minify(sub_ctx->zsurf->texture->base.height0, sub_ctx->zsurf->val0);
-      new_ibf = sub_ctx->zsurf->texture->y_0_top ? true : false;
+      new_fbo_origin_upper_left = sub_ctx->zsurf->texture->y_0_top ? true : false;
    }
    else {
       surf = NULL;
@@ -2773,13 +3046,14 @@
          return;
       }
       new_height = u_minify(surf->texture->base.height0, surf->val0);
-      new_ibf = surf->texture->y_0_top ? true : false;
+      new_fbo_origin_upper_left = surf->texture->y_0_top ? true : false;
    }
 
    if (new_height != -1) {
-      if (sub_ctx->fb_height != (uint32_t)new_height || sub_ctx->inverted_fbo_content != new_ibf) {
+      if (sub_ctx->fb_height != (uint32_t)new_height ||
+          sub_ctx->fbo_origin_upper_left != new_fbo_origin_upper_left) {
          sub_ctx->fb_height = new_height;
-         sub_ctx->inverted_fbo_content = new_ibf;
+         sub_ctx->fbo_origin_upper_left = new_fbo_origin_upper_left;
          sub_ctx->viewport_state_dirty = (1 << 0);
       }
    }
@@ -2871,8 +3145,12 @@
       }
 
       if (idx == 0) {
-         if (ctx->sub->viewport_is_negative != viewport_is_negative)
+         if (ctx->sub->viewport_is_negative != viewport_is_negative) {
             ctx->sub->viewport_is_negative = viewport_is_negative;
+            ctx->sub->sysvalue_data.winsys_adjust_y =
+                  viewport_is_negative ? -1.f : 1.f;
+            ctx->sub->sysvalue_data_cookie++;
+         }
       }
    }
 }
@@ -3165,6 +3443,48 @@
    vrend_set_num_vbo_sub(ctx->sub, num_vbo);
 }
 
+static GLenum vrend_get_arb_format(enum virgl_formats format)
+{
+   switch (format) {
+   case VIRGL_FORMAT_A8_UNORM: return GL_R8;
+   case VIRGL_FORMAT_A8_SINT: return GL_R8I;
+   case VIRGL_FORMAT_A8_UINT: return GL_R8UI;
+   case VIRGL_FORMAT_L8_UNORM: return GL_R8;
+   case VIRGL_FORMAT_L8_SINT: return GL_R8I;
+   case VIRGL_FORMAT_L8_UINT: return GL_R8UI;
+   case VIRGL_FORMAT_L16_UNORM: return GL_R16F;
+   case VIRGL_FORMAT_L16_SINT: return GL_R16I;
+   case VIRGL_FORMAT_L16_UINT: return GL_R16UI;
+   case VIRGL_FORMAT_L16_FLOAT: return GL_R16F;
+   case VIRGL_FORMAT_L32_SINT: return GL_R32F;
+   case VIRGL_FORMAT_L32_UINT: return GL_R32I;
+   case VIRGL_FORMAT_L32_FLOAT: return GL_R32UI;
+   case VIRGL_FORMAT_L8A8_UNORM: return GL_RG8;
+   case VIRGL_FORMAT_L8A8_SINT: return GL_RG8I;
+   case VIRGL_FORMAT_L8A8_UINT: return GL_RG8UI;
+   case VIRGL_FORMAT_L16A16_UNORM: return GL_RG16;
+   case VIRGL_FORMAT_L16A16_SINT: return GL_RG16I;
+   case VIRGL_FORMAT_L16A16_UINT: return GL_RG16UI;
+   case VIRGL_FORMAT_L16A16_FLOAT: return GL_RG16F;
+   case VIRGL_FORMAT_L32A32_FLOAT: return GL_RG32F;
+   case VIRGL_FORMAT_L32A32_SINT: return GL_RG32I;
+   case VIRGL_FORMAT_L32A32_UINT: return GL_RG32UI;
+   case VIRGL_FORMAT_I8_UNORM: return GL_R8;
+   case VIRGL_FORMAT_I8_SINT: return GL_R8I;
+   case VIRGL_FORMAT_I8_UINT: return GL_R8UI;
+   case VIRGL_FORMAT_I16_UNORM: return GL_R16;
+   case VIRGL_FORMAT_I16_SINT: return GL_R16I;
+   case VIRGL_FORMAT_I16_UINT: return GL_R16UI;
+   case VIRGL_FORMAT_I16_FLOAT: return GL_R16F;
+   case VIRGL_FORMAT_I32_FLOAT: return GL_R32F;
+   case VIRGL_FORMAT_I32_SINT: return GL_R32I;
+   case VIRGL_FORMAT_I32_UINT: return GL_R32UI;
+   default:
+      vrend_printf("Texture format %s unsupported for texture buffers\n", util_format_name(format));
+      return GL_R8;
+   }
+}
+
 void vrend_set_single_sampler_view(struct vrend_context *ctx,
                                    uint32_t shader_type,
                                    uint32_t index,
@@ -3252,6 +3572,12 @@
 
          glBindTexture(GL_TEXTURE_BUFFER, view->texture->tbo_tex_id);
          internalformat = tex_conv_table[view->format].internalformat;
+
+         if (internalformat == GL_NONE ||
+             (vrend_state.use_gles && internalformat == GL_ALPHA8)) {
+            internalformat = vrend_get_arb_format(view->format);
+         }
+
          if (has_feature(feat_texture_buffer_range)) {
             unsigned offset = view->val0;
             unsigned size = view->val1 - view->val0 + 1;
@@ -3486,12 +3812,17 @@
 
 
    struct vrend_shader_selector *prev = prev_type != PIPE_SHADER_INVALID ? sub_ctx->shaders[prev_type] : NULL;
+
    if (prev) {
-      key->input = prev->sinfo.out;
-      memcpy(key->force_invariant_inputs, prev->sinfo.invariant_outputs, 4 * sizeof(uint32_t));
-      memcpy(key->prev_stage_generic_and_patch_outputs_layout,
-             prev->sinfo.generic_outputs_layout,
-             prev->sinfo.out.num_generic_and_patch * sizeof (struct vrend_layout_info));
+      if (!prev->sinfo.separable_program || !sel->sinfo.separable_program) {
+         key->require_input_arrays = prev->sinfo.has_output_arrays;
+         key->in_generic_expected_mask = prev->sinfo.out_generic_emitted_mask;
+         key->in_texcoord_expected_mask = prev->sinfo.out_texcoord_emitted_mask;
+         key->in_patch_expected_mask = prev->sinfo.out_patch_emitted_mask;
+         key->in_arrays = prev->sinfo.output_arrays;
+
+         memcpy(key->force_invariant_inputs, prev->sinfo.invariant_outputs, 4 * sizeof(uint32_t));
+      }
 
       key->num_in_clip = sub_ctx->shaders[prev_type]->current->var_sinfo.num_out_clip;
       key->num_in_cull = sub_ctx->shaders[prev_type]->current->var_sinfo.num_out_cull;
@@ -3503,7 +3834,7 @@
    enum pipe_shader_type next_type = PIPE_SHADER_INVALID;
 
    if (type == PIPE_SHADER_FRAGMENT) {
-      key->fs.invert_origin = !sub_ctx->inverted_fbo_content;
+      key->fs.lower_left_origin = !sub_ctx->fbo_origin_upper_left;
       key->fs.swizzle_output_rgb_to_bgr = sub_ctx->swizzle_output_rgb_to_bgr;
       key->fs.needs_manual_srgb_encode_bitmask = sub_ctx->needs_manual_srgb_encode_bitmask;
       if (vrend_state.use_gles && can_emulate_logicop(sub_ctx->blend_state.logicop_func)) {
@@ -3562,22 +3893,28 @@
    }
 
    if (next_type != PIPE_SHADER_INVALID && sub_ctx->shaders[next_type]) {
-      key->output = sub_ctx->shaders[next_type]->sinfo.in;
+      if (!sub_ctx->shaders[next_type]->sinfo.separable_program ||
+          !sel->sinfo.separable_program) {
+         struct vrend_shader_selector *next = sub_ctx->shaders[next_type];
 
-      /* FS gets the clip/cull info in the key from this shader, so
-       * we can avoid re-translating this shader by not updating the
-       * info in the key */
-      if (next_type != PIPE_SHADER_FRAGMENT) {
-         key->num_out_clip = sub_ctx->shaders[next_type]->current->var_sinfo.num_in_clip;
-         key->num_out_cull = sub_ctx->shaders[next_type]->current->var_sinfo.num_in_cull;
-      }
+         key->use_pervertex_in = next->sinfo.use_pervertex_in;
+         key->require_output_arrays = next->sinfo.has_input_arrays;
+         key->out_generic_expected_mask = next->sinfo.in_generic_emitted_mask;
+         key->out_texcoord_expected_mask = next->sinfo.in_texcoord_emitted_mask;
 
-      if (next_type == PIPE_SHADER_FRAGMENT) {
-         struct vrend_shader *fs =
-               sub_ctx->shaders[PIPE_SHADER_FRAGMENT]->current;
-         key->fs_info = fs->var_sinfo.fs_info;
-         if (type == PIPE_SHADER_VERTEX) {
-            if (sub_ctx->shaders[type]) {
+         /* FS gets the clip/cull info in the key from this shader, so
+          * we can avoid re-translating this shader by not updating the
+          * info in the key */
+         if (next_type != PIPE_SHADER_FRAGMENT) {
+            key->num_out_clip = sub_ctx->shaders[next_type]->current->var_sinfo.num_in_clip;
+            key->num_out_cull = sub_ctx->shaders[next_type]->current->var_sinfo.num_in_cull;
+         }
+
+         if (next_type == PIPE_SHADER_FRAGMENT) {
+            struct vrend_shader *fs =
+                  sub_ctx->shaders[PIPE_SHADER_FRAGMENT]->current;
+            key->fs_info = fs->var_sinfo.fs_info;
+            if (type == PIPE_SHADER_VERTEX && sub_ctx->shaders[type]) {
                uint32_t fog_input = sub_ctx->shaders[next_type]->sinfo.fog_input_mask;
                uint32_t fog_output = sub_ctx->shaders[type]->sinfo.fog_output_mask;
 
@@ -3590,6 +3927,77 @@
    }
 }
 
+static bool vrend_get_swizzle(struct vrend_sampler_view *view,
+                              GLint swizzle[4])
+{
+   static const GLint OOOR[] = {GL_ZERO, GL_ZERO, GL_ZERO, GL_RED};
+   static const GLint RRR1[] = {GL_RED, GL_RED, GL_RED, GL_ONE};
+   static const GLint RRRG[] = {GL_RED, GL_RED, GL_RED, GL_GREEN};
+   static const GLint RRRR[] = {GL_RED, GL_RED, GL_RED, GL_RED};
+
+   switch (view->format) {
+   case VIRGL_FORMAT_A8_UNORM:
+   case VIRGL_FORMAT_A8_SINT:
+   case VIRGL_FORMAT_A8_UINT:
+   case VIRGL_FORMAT_A16_UNORM:
+   case VIRGL_FORMAT_A16_SINT:
+   case VIRGL_FORMAT_A16_UINT:
+   case VIRGL_FORMAT_A16_FLOAT:
+   case VIRGL_FORMAT_A32_SINT:
+   case VIRGL_FORMAT_A32_UINT:
+   case VIRGL_FORMAT_A32_FLOAT:
+      memcpy(swizzle, OOOR, 4 * sizeof(GLuint));
+      return true;
+   case VIRGL_FORMAT_L8_UNORM:
+   case VIRGL_FORMAT_L8_SINT:
+   case VIRGL_FORMAT_L8_UINT:
+   case VIRGL_FORMAT_L16_UNORM:
+   case VIRGL_FORMAT_L16_SINT:
+   case VIRGL_FORMAT_L16_UINT:
+   case VIRGL_FORMAT_L16_FLOAT:
+   case VIRGL_FORMAT_L32_SINT:
+   case VIRGL_FORMAT_L32_UINT:
+   case VIRGL_FORMAT_L32_FLOAT:
+      memcpy(swizzle, RRR1, 4 * sizeof(GLuint));
+      return true;
+   case VIRGL_FORMAT_L8A8_UNORM:
+   case VIRGL_FORMAT_L8A8_SINT:
+   case VIRGL_FORMAT_L8A8_UINT:
+   case VIRGL_FORMAT_L16A16_UNORM:
+   case VIRGL_FORMAT_L16A16_SINT:
+   case VIRGL_FORMAT_L16A16_UINT:
+   case VIRGL_FORMAT_L16A16_FLOAT:
+   case VIRGL_FORMAT_L32A32_FLOAT:
+   case VIRGL_FORMAT_L32A32_SINT:
+   case VIRGL_FORMAT_L32A32_UINT:
+      memcpy(swizzle, RRRG, 4 * sizeof(GLuint));
+      return true;
+   case VIRGL_FORMAT_I8_UNORM:
+   case VIRGL_FORMAT_I8_SINT:
+   case VIRGL_FORMAT_I8_UINT:
+   case VIRGL_FORMAT_I16_UNORM:
+   case VIRGL_FORMAT_I16_SINT:
+   case VIRGL_FORMAT_I16_UINT:
+   case VIRGL_FORMAT_I16_FLOAT:
+   case VIRGL_FORMAT_I32_FLOAT:
+   case VIRGL_FORMAT_I32_SINT:
+   case VIRGL_FORMAT_I32_UINT:
+      memcpy(swizzle, RRRR, 4 * sizeof(GLuint));
+      return true;
+   default:
+      if (tex_conv_table[view->format].flags & VIRGL_TEXTURE_NEED_SWIZZLE) {
+         swizzle[0] = tex_conv_table[view->format].swizzle[0];
+         swizzle[1] = tex_conv_table[view->format].swizzle[1];
+         swizzle[2] = tex_conv_table[view->format].swizzle[2];
+         swizzle[3] = tex_conv_table[view->format].swizzle[3];
+         return true;
+      } else {
+         return false;
+      }
+   }
+}
+
+
 static inline void vrend_fill_shader_key(struct vrend_sub_context *sub_ctx,
                                          struct vrend_shader_selector *sel,
                                          struct vrend_shader_key *key)
@@ -3631,7 +4039,7 @@
          }
       }
 
-      key->pstipple_tex = sub_ctx->rs_state.poly_stipple_enable;
+      key->pstipple_enabled = sub_ctx->rs_state.poly_stipple_enable;
       key->color_two_side = sub_ctx->rs_state.light_twoside;
 
       key->flatshade = sub_ctx->rs_state.flatshade ? true : false;
@@ -3660,14 +4068,15 @@
          vrend_shader_sampler_views_mask_set(key->sampler_views_emulated_rect_mask, i);
       }
 
-      if (view->texture->target == GL_TEXTURE_BUFFER &&
-         tex_conv_table[view->format].flags & VIRGL_TEXTURE_NEED_SWIZZLE) {
-
-         vrend_shader_sampler_views_mask_set(key->sampler_views_lower_swizzle_mask, i);
-         key->tex_swizzle[i] = to_pipe_swizzle(view->gl_swizzle[0])  |
-               to_pipe_swizzle(view->gl_swizzle[1]) << 3 |
-               to_pipe_swizzle(view->gl_swizzle[2]) << 6 |
-               to_pipe_swizzle(view->gl_swizzle[3]) << 9;
+      if (view->texture->target == GL_TEXTURE_BUFFER) {
+         GLint swizzle[4];
+         if (vrend_get_swizzle(view, swizzle)) {
+            vrend_shader_sampler_views_mask_set(key->sampler_views_lower_swizzle_mask, i);
+            key->tex_swizzle[i] = to_pipe_swizzle(swizzle[0])  |
+                                  to_pipe_swizzle(swizzle[1]) << 3 |
+                                  to_pipe_swizzle(swizzle[2]) << 6 |
+                                  to_pipe_swizzle(swizzle[3]) << 9;
+         }
       }
    }
 }
@@ -3711,12 +4120,13 @@
    memset(&key, 0, sizeof(key));
    vrend_fill_shader_key(sub_ctx, sel, &key);
 
-   if (sel->current && !memcmp(&sel->current->key, &key, sizeof(key)))
-      return 0;
+   if (sel->current) {
+      if (!memcmp(&sel->current->key, &key, sizeof(key)))
+         return 0;
 
-   if (sel->num_shaders > 1) {
       struct vrend_shader *p = sel->current;
       struct vrend_shader *c = p->next_variant;
+
       while (c && memcmp(&c->key, &key, sizeof(key)) != 0) {
          p = c;
          c = c->next_variant;
@@ -3740,7 +4150,6 @@
          FREE(shader);
          return r;
       }
-      sel->num_shaders++;
    }
    if (dirty)
       *dirty = true;
@@ -3771,15 +4180,13 @@
                                struct vrend_shader_selector *sel,
                                const struct tgsi_token *tokens)
 {
-   int r;
-
    sel->tokens = tgsi_dup_tokens(tokens);
 
-   r = vrend_shader_select(ctx->sub, sel, NULL);
-   if (r) {
-      return EINVAL;
-   }
-   return 0;
+   if (!ctx->shader_cfg.use_gles && sel->type != PIPE_SHADER_COMPUTE)
+      sel->sinfo.separable_program =
+            vrend_shader_query_separable_program(sel->tokens, &ctx->shader_cfg);
+
+   return vrend_shader_select(ctx->sub, sel, NULL) ? EINVAL : 0;
 }
 
 int vrend_create_shader(struct vrend_context *ctx,
@@ -3791,7 +4198,6 @@
 {
    struct vrend_shader_selector *sel = NULL;
    int ret_handle;
-   bool new_shader = true, long_shader = false;
    bool finished = false;
    int ret;
 
@@ -3811,11 +4217,13 @@
        !has_feature(feat_compute_shader))
       return EINVAL;
 
-   if (offlen & VIRGL_OBJ_SHADER_OFFSET_CONT)
-      new_shader = false;
-   else if (((offlen + 3) / 4) > pkt_length)
-      long_shader = true;
-
+   /* offlen & VIRGL_OBJ_SHADER_OFFSET_CONT declares whether we have a new shader or
+    * a shader continuation
+    *
+    * offlen & ~VIRGL_OBJ_SHADER_OFFSET_CONT
+    *  is the total shader length for   a new shader (new_shader == true)
+    *  the continuation offset for a shader continuation (new_shader == false) */
+   bool new_shader = !(offlen & VIRGL_OBJ_SHADER_OFFSET_CONT);
    struct vrend_sub_context *sub_ctx = ctx->sub;
 
    /* if we have an in progress one - don't allow a new shader
@@ -3827,24 +4235,30 @@
          return EINVAL;
    }
 
+   const uint32_t pkt_length_bytes = pkt_length * 4;
+
    if (new_shader) {
+      const uint32_t expected_token_count = (offlen + 3) / 4;  /* round up count */
+      if (expected_token_count < pkt_length)
+        return EINVAL;
+
       sel = vrend_create_shader_state(so_info, req_local_mem, type);
-     if (sel == NULL)
-       return ENOMEM;
+      if (sel == NULL)
+         return ENOMEM;
 
-     sel->buf_len = ((offlen + 3) / 4) * 4; /* round up buffer size */
-     sel->tmp_buf = malloc(sel->buf_len);
-     if (!sel->tmp_buf) {
-        ret = ENOMEM;
-        goto error;
-     }
+      sel->buf_len = expected_token_count * 4;
+      sel->tmp_buf = malloc(sel->buf_len);
+      if (!sel->tmp_buf) {
+         ret = ENOMEM;
+         goto error;
+      }
 
-     memcpy(sel->tmp_buf, shd_text, pkt_length * 4);
-     if (long_shader) {
-        sel->buf_offset = pkt_length * 4;
-        sub_ctx->long_shader_in_progress_handle[type] = handle;
-     } else
-        finished = true;
+      memcpy(sel->tmp_buf, shd_text, pkt_length_bytes);
+      if (expected_token_count > pkt_length) {
+         sel->buf_offset = pkt_length_bytes;
+         sub_ctx->long_shader_in_progress_handle[type] = handle;
+      } else
+         finished = true;
    } else {
       sel = vrend_object_lookup(sub_ctx->object_hash, handle, VIRGL_OBJECT_SHADER);
       if (!sel) {
@@ -3862,23 +4276,23 @@
       }
 
       /*make sure no overflow */
-      if (pkt_length * 4 < pkt_length ||
-          pkt_length * 4 + sel->buf_offset < pkt_length * 4 ||
-          pkt_length * 4 + sel->buf_offset < sel->buf_offset) {
+      if (pkt_length_bytes < pkt_length ||
+          pkt_length_bytes + sel->buf_offset < pkt_length_bytes ||
+          pkt_length_bytes + sel->buf_offset < sel->buf_offset) {
             ret = EINVAL;
             goto error;
           }
 
-      if ((pkt_length * 4 + sel->buf_offset) > sel->buf_len) {
-         vrend_printf( "Got too large shader continuation %d vs %d\n",
-                 pkt_length * 4 + sel->buf_offset, sel->buf_len);
+      if ((pkt_length_bytes + sel->buf_offset) > sel->buf_len) {
+         vrend_printf("Got too large shader continuation %d vs %d\n",
+                      pkt_length_bytes + sel->buf_offset, sel->buf_len);
          ret = EINVAL;
          goto error;
       }
 
-      memcpy(sel->tmp_buf + sel->buf_offset, shd_text, pkt_length * 4);
+      memcpy(sel->tmp_buf + sel->buf_offset, shd_text, pkt_length_bytes);
 
-      sel->buf_offset += pkt_length * 4;
+      sel->buf_offset += pkt_length_bytes;
       if (sel->buf_offset >= sel->buf_len) {
          finished = true;
          shd_text = sel->tmp_buf;
@@ -3889,7 +4303,7 @@
       struct tgsi_token *tokens;
 
       /* check for null termination */
-      uint32_t last_chunk_offset = sel->buf_offset ? sel->buf_offset : pkt_length * 4;
+      uint32_t last_chunk_offset = sel->buf_offset ? sel->buf_offset : pkt_length_bytes;
       if (last_chunk_offset < 4 || !memchr(shd_text + last_chunk_offset - 4, '\0', 4)) {
          ret = EINVAL;
          goto error;
@@ -4004,7 +4418,7 @@
    if (sub_ctx->viewport_state_dirty)
       vrend_update_viewport_state(sub_ctx);
 
-   vrend_use_program(sub_ctx, 0);
+   vrend_use_program(ctx->sub, NULL);
 
    glDisable(GL_SCISSOR_TEST);
 
@@ -4147,7 +4561,7 @@
       glDisable(GL_SCISSOR_TEST);
 }
 
-void vrend_clear_texture(struct vrend_context* ctx,
+int vrend_clear_texture(struct vrend_context* ctx,
                          uint32_t handle, uint32_t level,
                          const struct pipe_box *box,
                          const void * data)
@@ -4155,11 +4569,10 @@
    GLenum format, type;
    struct vrend_resource *res;
 
-   if (handle)
-      res = vrend_renderer_ctx_res_lookup(ctx, handle);
-   else {
-      vrend_printf( "cannot find resource for handle %d\n", handle);
-      return;
+   res = vrend_renderer_ctx_res_lookup(ctx, handle);
+   if (!res) {
+      vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, handle);
+      return EINVAL;
    }
 
    enum virgl_formats fmt = res->base.format;
@@ -4188,6 +4601,7 @@
                          box->width, box->height, box->depth,
                          format, type, data);
    }
+   return 0;
 }
 
 static void vrend_update_scissor_state(struct vrend_sub_context *sub_ctx)
@@ -4472,6 +4886,24 @@
       struct vrend_sampler_view *tview = sviews->views[i];
       if ((dirty & (1 << i)) && tview) {
          if (sub_ctx->prog->shadow_samp_mask[shader_type] & (1 << i)) {
+            struct vrend_texture *tex = (struct vrend_texture *)tview->texture;
+
+            /* The modes LUMINANCE, INTENSITY, and ALPHA only apply when a depth texture
+             * is used by a sampler that returns an RGBA value, i.e. by sampler*D, if
+             * the texture is queries by using sampler*Shadow then these swizzles must
+             * not be applied, therefore, reset the swizzled to the default */
+            static const GLint swizzle[] = {GL_RED,GL_GREEN,GL_BLUE,GL_ALPHA};
+            if (memcmp(tex->cur_swizzle, swizzle, 4 * sizeof(GLint))) {
+               if (vrend_state.use_gles) {
+                  for (unsigned int i = 0; i < 4; ++i) {
+                     glTexParameteri(tview->texture->target, GL_TEXTURE_SWIZZLE_R + i, swizzle[i]);
+                  }
+               } else {
+                  glTexParameteriv(tview->texture->target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
+               }
+               memcpy(tex->cur_swizzle, swizzle, 4 * sizeof(GLint));
+            }
+
             glUniform4f(sub_ctx->prog->shadow_samp_mask_locs[shader_type][sampler_index],
                         (tview->gl_swizzle[0] == GL_ZERO || tview->gl_swizzle[0] == GL_ONE) ? 0.0 : 1.0,
                         (tview->gl_swizzle[1] == GL_ZERO || tview->gl_swizzle[1] == GL_ONE) ? 0.0 : 1.0,
@@ -4652,6 +5084,11 @@
          /* glTexBuffer doesn't accept GL_RGBA8_SNORM, find an appropriate replacement. */
          uint32_t format = (iview->format == GL_RGBA8_SNORM) ? GL_RGBA8UI : iview->format;
 
+         if (format == GL_NONE ||
+             (vrend_state.use_gles && format == GL_ALPHA8)) {
+            format = vrend_get_arb_format(iview->vformat);
+         }
+
          glBindBufferARB(GL_TEXTURE_BUFFER, iview->texture->id);
          glBindTexture(GL_TEXTURE_BUFFER, iview->texture->tbo_tex_id);
 
@@ -4708,49 +5145,34 @@
 static void
 vrend_fill_sysval_uniform_block (struct vrend_sub_context *sub_ctx)
 {
-   if (sub_ctx->prog->virgl_block_id == GL_INVALID_INDEX)
+   if (sub_ctx->prog->virgl_block_bind == -1)
       return;
 
-   struct sysval_uniform_block virgl_uniform_block;
-   memset(&virgl_uniform_block, 0, sizeof(struct sysval_uniform_block));
-
-   if (vrend_state.use_core_profile)
-      virgl_uniform_block.alpha_ref_val = sub_ctx->dsa_state.alpha.ref_value;
-
-   virgl_uniform_block.winsys_adjust_y = sub_ctx->viewport_is_negative ? -1.f : 1.f;
-
-   if (has_feature(feat_cull_distance)) {
-      if (sub_ctx->rs_state.clip_plane_enable) {
-         virgl_uniform_block.clip_plane_enabled = 1.f;
-         for (int i = 0 ; i < VIRGL_NUM_CLIP_PLANES; i++) {
-            memcpy(&virgl_uniform_block.clipp[i],
-                   (const GLfloat *) &sub_ctx->ucp_state.ucp[i], sizeof(GLfloat) * 4);
-         }
-      } else {
-         virgl_uniform_block.clip_plane_enabled = 0.f;
-      }
+   if (sub_ctx->sysvalue_data_cookie != sub_ctx->prog->sysvalue_data_cookie) {
+      glBindBuffer(GL_UNIFORM_BUFFER, sub_ctx->prog->ubo_sysval_buffer_id);
+      glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(struct sysval_uniform_block),
+                      &sub_ctx->sysvalue_data);
+      glBindBuffer(GL_UNIFORM_BUFFER, 0);
+      sub_ctx->prog->sysvalue_data_cookie = sub_ctx->sysvalue_data_cookie;
    }
-
-   glBindBuffer(GL_UNIFORM_BUFFER, sub_ctx->prog->ubo_sysval_buffer_id);
-   glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(struct sysval_uniform_block),
-                   &virgl_uniform_block);
-   glBindBuffer(GL_UNIFORM_BUFFER, 0);
 }
 
 static void vrend_draw_bind_objects(struct vrend_sub_context *sub_ctx, bool new_program)
 {
    int next_ubo_id = 0, next_sampler_id = 0;
    for (int shader_type = PIPE_SHADER_VERTEX; shader_type <= sub_ctx->last_shader_idx; shader_type++) {
+      vrend_set_active_pipeline_stage(sub_ctx->prog, shader_type);
+
       next_ubo_id = vrend_draw_bind_ubo_shader(sub_ctx, shader_type, next_ubo_id);
       vrend_draw_bind_const_shader(sub_ctx, shader_type, new_program);
-      next_sampler_id = vrend_draw_bind_samplers_shader(sub_ctx, shader_type,
-                                                        next_sampler_id);
+      next_sampler_id = vrend_draw_bind_samplers_shader(sub_ctx, shader_type, next_sampler_id);
 
       vrend_draw_bind_images_shader(sub_ctx, shader_type);
       vrend_draw_bind_ssbo_shader(sub_ctx, shader_type);
 
       if (vrend_state.use_gles) {
          if (sub_ctx->prog->tex_levels_uniform_id[shader_type] != -1) {
+            vrend_set_active_pipeline_stage(sub_ctx->prog, shader_type);
             glUniform1iv(sub_ctx->prog->tex_levels_uniform_id[shader_type],
                          sub_ctx->n_samplers[shader_type],
                          sub_ctx->texture_levels[shader_type]);
@@ -4758,18 +5180,14 @@
       }
    }
 
-   if (sub_ctx->prog->virgl_block_id != GL_INVALID_INDEX)
+   if (sub_ctx->prog->virgl_block_bind != -1)
       glBindBufferRange(GL_UNIFORM_BUFFER, sub_ctx->prog->virgl_block_bind,
                         sub_ctx->prog->ubo_sysval_buffer_id,
                         0, sizeof(struct sysval_uniform_block));
 
    vrend_draw_bind_abo_shader(sub_ctx);
 
-   if (vrend_state.use_core_profile && sub_ctx->prog->fs_stipple_loc != -1) {
-      glActiveTexture(GL_TEXTURE0 + next_sampler_id);
-      glBindTexture(GL_TEXTURE_2D, sub_ctx->parent->pstipple_tex_id);
-      glUniform1i(sub_ctx->prog->fs_stipple_loc, next_sampler_id);
-   }
+   vrend_set_active_pipeline_stage(sub_ctx->prog, PIPE_SHADER_FRAGMENT);
 }
 
 static
@@ -4803,7 +5221,6 @@
    sel->tokens = NULL;
    sel->current = shader;
    sub_ctx->shaders[PIPE_SHADER_TESS_CTRL] = sel;
-   sub_ctx->shaders[PIPE_SHADER_TESS_CTRL]->num_shaders = 1;
 
    vrend_compile_shader(sub_ctx, shader);
 }
@@ -4890,11 +5307,17 @@
        (shaders[PIPE_SHADER_TESS_EVAL] && !shaders[PIPE_SHADER_TESS_EVAL]->current))
       goto fail;
 
-   GLuint vs_id = shaders[PIPE_SHADER_VERTEX]->current->id;
-   GLuint fs_id = shaders[PIPE_SHADER_FRAGMENT]->current->id;
-   GLuint gs_id = shaders[PIPE_SHADER_GEOMETRY] ? shaders[PIPE_SHADER_GEOMETRY]->current->id : 0;
-   GLuint tcs_id = shaders[PIPE_SHADER_TESS_CTRL] ? shaders[PIPE_SHADER_TESS_CTRL]->current->id : 0;
-   GLuint tes_id = shaders[PIPE_SHADER_TESS_EVAL] ? shaders[PIPE_SHADER_TESS_EVAL]->current->id : 0;
+   struct vrend_shader *vs = shaders[PIPE_SHADER_VERTEX]->current;
+   struct vrend_shader *fs = shaders[PIPE_SHADER_FRAGMENT]->current;
+   struct vrend_shader *gs = shaders[PIPE_SHADER_GEOMETRY] ? shaders[PIPE_SHADER_GEOMETRY]->current : NULL;
+   struct vrend_shader *tcs = shaders[PIPE_SHADER_TESS_CTRL] ? shaders[PIPE_SHADER_TESS_CTRL]->current : NULL;
+   struct vrend_shader *tes = shaders[PIPE_SHADER_TESS_EVAL] ? shaders[PIPE_SHADER_TESS_EVAL]->current : NULL;
+
+   GLuint vs_id = vs->id;
+   GLuint fs_id = fs->id;
+   GLuint gs_id = !gs ? 0 : gs->id;
+   GLuint tcs_id = !tcs ? 0 : tcs->id;
+   GLuint tes_id = !tes ? 0 : tes->id;
 
    if (shaders[PIPE_SHADER_FRAGMENT]->current->sel->sinfo.num_outputs <= 1)
       dual_src = false;
@@ -4907,6 +5330,12 @@
                     tes_id == sub_ctx->prog_ids[PIPE_SHADER_TESS_EVAL] &&
                     sub_ctx->prog->dual_src_linked == dual_src;
 
+   bool separable = vs->sel->sinfo.separable_program &&
+                    fs->sel->sinfo.separable_program &&
+                    (!gs || gs->sel->sinfo.separable_program) &&
+                    (!tcs || tcs->sel->sinfo.separable_program) &&
+                    (!tes || tes->sel->sinfo.separable_program);
+
    if (!same_prog) {
       prog = lookup_shader_program(sub_ctx, vs_id, fs_id, gs_id, tcs_id, tes_id, dual_src);
       if (!prog) {
@@ -4915,10 +5344,34 @@
                                    sub_ctx->shaders[PIPE_SHADER_FRAGMENT]->current,
                                    gs_id ? sub_ctx->shaders[PIPE_SHADER_GEOMETRY]->current : NULL,
                                    tcs_id ? sub_ctx->shaders[PIPE_SHADER_TESS_CTRL]->current : NULL,
-                                   tes_id ? sub_ctx->shaders[PIPE_SHADER_TESS_EVAL]->current : NULL);
+                                   tes_id ? sub_ctx->shaders[PIPE_SHADER_TESS_EVAL]->current : NULL,
+                                   separable);
          if (!prog)
             return false;
          prog->gles_use_query_texturelevel_mask = gles_emulate_query_texture_levels_mask;
+      } else if (separable) {
+          /* UBO block bindings are reset to zero if the programs are
+           * re-linked.  With separable shaders, the program can be relinked
+           * because it's shared across multiple pipelines and some things like
+           * transform feedback require relinking, so we have to make sure the
+           * blocks are bound. */
+          enum pipe_shader_type last_shader = tes_id ? PIPE_SHADER_TESS_EVAL :
+                (gs_id ? PIPE_SHADER_GEOMETRY :
+                         PIPE_SHADER_FRAGMENT);
+          bool need_rebind = false;
+
+          for (enum pipe_shader_type shader_type = PIPE_SHADER_VERTEX;
+               shader_type <= last_shader && !need_rebind;
+               shader_type++) {
+             if (!prog->ss[shader_type])
+                continue;
+             need_rebind |= prog->ss[shader_type]->last_pipeline_id != prog->id.pipeline;
+          }
+
+          if (need_rebind) {
+             vrend_use_program(sub_ctx, prog);
+             rebind_ubo_and_sampler_locs(prog, last_shader);
+          }
       }
 
       sub_ctx->last_shader_idx = sub_ctx->shaders[PIPE_SHADER_TESS_EVAL] ? PIPE_SHADER_TESS_EVAL : (sub_ctx->shaders[PIPE_SHADER_GEOMETRY] ? PIPE_SHADER_GEOMETRY : PIPE_SHADER_FRAGMENT);
@@ -4950,14 +5403,22 @@
    return false;
 }
 
-void vrend_link_program(struct vrend_context *ctx, uint32_t *handles)
+void vrend_link_program_hook(struct vrend_context *ctx, uint32_t *handles)
 {
    /* Pre-compiling compute shaders needs some additional work */
    if (handles[PIPE_SHADER_COMPUTE])
       return;
 
+   struct vrend_shader_selector *vs = vrend_object_lookup(ctx->sub->object_hash,
+                                                          handles[PIPE_SHADER_VERTEX],
+                                                          VIRGL_OBJECT_SHADER);
+   struct vrend_shader_selector *fs = vrend_object_lookup(ctx->sub->object_hash,
+                                                          handles[PIPE_SHADER_FRAGMENT],
+                                                          VIRGL_OBJECT_SHADER);
+
    /* If we can't force linking, exit early */
-   if (!handles[PIPE_SHADER_VERTEX] || !handles[PIPE_SHADER_FRAGMENT])
+   if ((!handles[PIPE_SHADER_VERTEX] || !handles[PIPE_SHADER_FRAGMENT]) &&
+       (!vs || !vs->sinfo.separable_program) && (!fs || !fs->sinfo.separable_program))
        return;
 
    /* We can't link a pre-link a TCS without a TES, exit early */
@@ -4975,6 +5436,17 @@
       vrend_bind_shader(ctx, handles[type], type);
    }
 
+   /* Force early-linking for separable shaders, since they don't depend on other stages */
+   for (uint32_t type = 0; type < PIPE_SHADER_TYPES; ++type) {
+       if (ctx->sub->shaders[type] && ctx->sub->shaders[type]->sinfo.separable_program) {
+           if (!ctx->sub->shaders[type]->current->is_compiled)
+               vrend_compile_shader(ctx->sub, ctx->sub->shaders[type]->current);
+           if (!ctx->sub->shaders[type]->current->is_linked)
+               vrend_link_separable_shader(ctx->sub, ctx->sub->shaders[type]->current, type);
+       }
+   }
+
+   /* Force early-link of the whole shader program. */
    vrend_select_program(ctx->sub, 1);
 
    ctx->sub->shader_dirty = true;
@@ -5072,7 +5544,7 @@
       return 0;
    }
 
-   vrend_use_program(sub_ctx, sub_ctx->prog->id);
+   vrend_use_program(sub_ctx, sub_ctx->prog);
 
    if (vrend_state.use_gles) {
       /* PIPE_SHADER and TGSI_SHADER have different ordering, so use two
@@ -5081,7 +5553,8 @@
          if (sub_ctx->prog->gles_use_query_texturelevel_mask & (1 << i)) {
             char loc_name[32];
             snprintf(loc_name, 32, "%s_texlod", pipe_shader_to_prefix(i));
-            sub_ctx->prog->tex_levels_uniform_id[i] = glGetUniformLocation(sub_ctx->prog->id, loc_name);
+            sub_ctx->prog->tex_levels_uniform_id[i] =
+               vrend_get_uniform_location(sub_ctx->prog, loc_name, i);
          } else {
             sub_ctx->prog->tex_levels_uniform_id[i] = -1;
          }
@@ -5326,8 +5799,9 @@
       return;
    }
 
-   vrend_use_program(sub_ctx, sub_ctx->prog->id);
+   vrend_use_program(sub_ctx, sub_ctx->prog);
 
+   vrend_set_active_pipeline_stage(sub_ctx->prog, PIPE_SHADER_COMPUTE);
    vrend_draw_bind_ubo_shader(sub_ctx, PIPE_SHADER_COMPUTE, 0);
    vrend_draw_bind_const_shader(sub_ctx, PIPE_SHADER_COMPUTE, new_program);
    vrend_draw_bind_samplers_shader(sub_ctx, PIPE_SHADER_COMPUTE, 0);
@@ -5556,13 +6030,12 @@
       if (state->rt[0].colormask != sub_ctx->hw_blend_state.rt[0].colormask ||
           (sub_ctx->hw_blend_state.independent_blend_enable &&
            !state->independent_blend_enable)) {
-         int i;
-         for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++)
-            sub_ctx->hw_blend_state.rt[i].colormask = state->rt[i].colormask;
          glColorMask(state->rt[0].colormask & PIPE_MASK_R ? GL_TRUE : GL_FALSE,
                      state->rt[0].colormask & PIPE_MASK_G ? GL_TRUE : GL_FALSE,
                      state->rt[0].colormask & PIPE_MASK_B ? GL_TRUE : GL_FALSE,
                      state->rt[0].colormask & PIPE_MASK_A ? GL_TRUE : GL_FALSE);
+         for (int i = 0; i < PIPE_MAX_COLOR_BUFS; i++)
+            sub_ctx->hw_blend_state.rt[i].colormask = state->rt[0].colormask;
       }
    }
    sub_ctx->hw_blend_state.independent_blend_enable = state->independent_blend_enable;
@@ -5724,6 +6197,11 @@
    ctx->sub->dsa_state = *state;
    ctx->sub->dsa = state;
 
+   if (ctx->sub->sysvalue_data.alpha_ref_val != state->alpha.ref_value) {
+      ctx->sub->sysvalue_data.alpha_ref_val = state->alpha.ref_value;
+      ctx->sub->sysvalue_data_cookie++;
+   }
+
    vrend_hw_emit_dsa(ctx);
 }
 
@@ -5732,7 +6210,7 @@
    struct pipe_rasterizer_state *state = &sub_ctx->rs_state;
    int front_ccw = state->front_ccw;
 
-   front_ccw ^= (sub_ctx->inverted_fbo_content ? 0 : 1);
+   front_ccw ^= (sub_ctx->fbo_origin_upper_left ? 0 : 1);
    if (front_ccw)
       glFrontFace(GL_CCW);
    else
@@ -5920,9 +6398,6 @@
          glEnable(GL_POLYGON_STIPPLE);
       else
          glDisable(GL_POLYGON_STIPPLE);
-   } else if (state->poly_stipple_enable) {
-      if (!ctx->pstip_inited)
-         vrend_init_pstipple_texture(ctx);
    }
 
    if (state->point_quad_rasterization) {
@@ -5975,6 +6450,13 @@
          else
             glDisable(GL_CLIP_PLANE0 + i);
       }
+
+      ctx->sub->sysvalue_data_cookie++;
+      if (ctx->sub->rs_state.clip_plane_enable) {
+         ctx->sub->sysvalue_data.clip_plane_enabled = 1.f;
+      } else {
+         ctx->sub->sysvalue_data.clip_plane_enabled = 0.f;
+      }
    }
    if (vrend_state.use_core_profile == false) {
       glLineStipple(state->line_stipple_factor, state->line_stipple_pattern);
@@ -6330,18 +6812,13 @@
 
 static bool do_wait(struct vrend_fence *fence, bool can_block)
 {
-   bool done = false;
-   int timeout = can_block ? 1000000000 : 0;
-
 #ifdef HAVE_EPOXY_EGL_H
-   if (vrend_state.use_egl_fence) {
-      do {
-         done = virgl_egl_client_wait_fence(egl, fence->eglsyncobj, timeout);
-      } while (!done && can_block);
-      return done;
-   }
+   if (vrend_state.use_egl_fence)
+      return virgl_egl_client_wait_fence(egl, fence->eglsyncobj, can_block);
 #endif
 
+   bool done = false;
+   int timeout = can_block ? 1000000000 : 0;
    do {
       GLenum glret = glClientWaitSync(fence->glsyncobj, 0, timeout);
       if (glret == GL_WAIT_FAILED) {
@@ -6621,7 +7098,7 @@
    return &callbacks;
 }
 
-static bool use_integer() {
+static bool use_integer(void) {
    if (getenv("VIRGL_USE_INTEGER"))
       return true;
 
@@ -6773,6 +7250,15 @@
       return EINVAL;
    }
 
+#ifdef ENABLE_VIDEO
+   if (flags & VREND_USE_VIDEO) {
+        if (vrend_clicbs->get_drm_fd)
+            vrend_video_init(vrend_clicbs->get_drm_fd());
+        else
+            vrend_printf("video disabled due to missing get_drm_fd\n");
+   }
+#endif
+
    return 0;
 }
 
@@ -6789,6 +7275,10 @@
    vrend_free_fences();
    vrend_blitter_fini();
 
+#ifdef ENABLE_VIDEO
+   vrend_video_fini();
+#endif
+
    vrend_destroy_context(vrend_state.ctx0);
 
    vrend_state.current_ctx = NULL;
@@ -6880,11 +7370,6 @@
       vrend_state.current_hw_ctx = NULL;
    }
 
-   if (vrend_state.use_core_profile) {
-      if (ctx->pstip_inited)
-         glDeleteTextures(1, &ctx->pstipple_tex_id);
-      ctx->pstip_inited = false;
-   }
    vrend_clicbs->make_current(ctx->sub->gl_context);
    /* reset references on framebuffers */
    vrend_set_framebuffer_state(ctx, 0, NULL, 0);
@@ -6907,6 +7392,10 @@
 
    vrend_free_fences_for_context(ctx);
 
+#ifdef ENABLE_VIDEO
+   vrend_video_destroy_context(ctx->video);
+#endif
+
    LIST_FOR_EACH_ENTRY_SAFE(untyped_res, untyped_res_tmp, &ctx->untyped_resources, head)
       free(untyped_res);
    vrend_ctx_resource_fini_table(ctx->res_hash);
@@ -6938,9 +7427,14 @@
    list_inithead(&grctx->sub_ctxs);
    list_inithead(&grctx->vrend_resources);
 
+#ifdef ENABLE_VIDEO
+   grctx->video = vrend_video_create_context(grctx);
+#endif
+
    grctx->res_hash = vrend_ctx_resource_init_table();
    list_inithead(&grctx->untyped_resources);
 
+   grctx->shader_cfg.max_shader_patch_varyings = vrend_state.max_shader_patch_varyings;
    grctx->shader_cfg.use_gles = vrend_state.use_gles;
    grctx->shader_cfg.use_core_profile = vrend_state.use_core_profile;
    grctx->shader_cfg.use_explicit_locations = vrend_state.use_explicit_locations;
@@ -6953,6 +7447,8 @@
    grctx->shader_cfg.has_dual_src_blend = has_feature(feat_dual_src_blend);
    grctx->shader_cfg.has_fbfetch_coherent = has_feature(feat_framebuffer_fetch);
    grctx->shader_cfg.has_cull_distance = has_feature(feat_cull_distance);
+   grctx->shader_cfg.has_nopersective = has_feature(feat_shader_noperspective_interpolation);
+   grctx->shader_cfg.has_texture_shadow_lod = has_feature(feat_texture_shadow_lod);
 
    vrend_renderer_create_sub_ctx(grctx, 0);
    vrend_renderer_set_sub_ctx(grctx, 0);
@@ -7462,8 +7958,9 @@
       if (has_bit(gr->storage_bits, VREND_STORAGE_GL_IMMUTABLE) &&
           has_feature(feat_egl_image_storage)) {
          glEGLImageTargetTexStorageEXT(gr->target, (GLeglImageOES) image_oes, NULL);
-      } else if (has_feature(feat_egl_image_external)) {
+      } else if (has_feature(feat_egl_image)) {
          gr->storage_bits &= ~VREND_STORAGE_GL_IMMUTABLE;
+         assert(gr->target == GL_TEXTURE_2D);
          glEGLImageTargetTexture2DOES(gr->target, (GLeglImageOES) image_oes);
          if ((format == VIRGL_FORMAT_NV12 ||
               format == VIRGL_FORMAT_NV21 ||
@@ -7472,7 +7969,7 @@
             vrend_printf("glEGLImageTargetTexture2DOES maybe fail\n");
          }
       } else {
-         vrend_printf( "missing GL_OES_EGL_image_external extensions\n");
+         vrend_printf( "missing GL_OES_EGL_image extensions\n");
          glBindTexture(gr->target, 0);
          return EINVAL;
       }
@@ -7866,9 +8363,9 @@
     */
    int w = box->width > 0 ? box->width : 1;
    int h = box->height > 0 ? box->height : 1;
-   int d = box->depth > 0 ? box->depth : 1;
-   int nblocksx = util_format_get_nblocksx(pres->format, w);
-   int nblocksy = util_format_get_nblocksy(pres->format, h);
+   uint64_t d = box->depth > 0 ? box->depth : 1;
+   uint64_t nblocksx = util_format_get_nblocksx(pres->format, w);
+   uint64_t nblocksy = util_format_get_nblocksy(pres->format, h);
 
    /* Calculate the box size, not including the last layer. The last layer
     * is the only one which may be incomplete, and is the only layer for
@@ -8006,10 +8503,7 @@
       uint32_t stride = info->stride;
       uint32_t layer_stride = info->layer_stride;
 
-      if (ctx)
-         vrend_use_program(ctx->sub, 0);
-      else
-         glUseProgram(0);
+      vrend_use_program(ctx->sub, 0);
 
       if (!stride)
          stride = util_format_get_nblocksx(res->base.format, u_minify(res->base.width0, info->level)) * elsize;
@@ -8094,15 +8588,11 @@
          buffers = GL_COLOR_ATTACHMENT0;
          glDrawBuffers(1, &buffers);
          glDisable(GL_BLEND);
-         if (ctx) {
-            vrend_depth_test_enable(ctx, false);
-            vrend_alpha_test_enable(ctx, false);
-            vrend_stencil_test_enable(ctx->sub, false);
-         } else {
-            glDisable(GL_DEPTH_TEST);
-            glDisable(GL_ALPHA_TEST);
-            glDisable(GL_STENCIL_TEST);
-         }
+
+         vrend_depth_test_enable(ctx, false);
+         vrend_alpha_test_enable(ctx, false);
+         vrend_stencil_test_enable(ctx->sub, false);
+
          glPixelZoom(1.0f, res->y_0_top ? -1.0f : 1.0f);
          glWindowPos2i(info->box->x, res->y_0_top ? (int)res->base.height0 - info->box->y : info->box->y);
          glDrawPixels(info->box->width, info->box->height, glformat, gltype,
@@ -8382,10 +8872,7 @@
    int row_stride = info->stride / elsize;
    GLint old_fbo;
 
-   if (ctx)
-      vrend_use_program(ctx->sub, 0);
-   else
-      glUseProgram(0);
+   vrend_use_program(ctx->sub, 0);
 
    enum virgl_formats fmt = res->base.format;
 
@@ -8887,59 +9374,41 @@
                              uint32_t num_scissor,
                              struct pipe_scissor_state *ss)
 {
-   uint i, idx;
-
-   if (start_slot > PIPE_MAX_VIEWPORTS ||
-       num_scissor > (PIPE_MAX_VIEWPORTS - start_slot)) {
+   if (start_slot < PIPE_MAX_VIEWPORTS &&
+       start_slot + num_scissor <= PIPE_MAX_VIEWPORTS) {
+      for (uint i = 0; i < num_scissor; i++) {
+         uint idx = start_slot + i;
+         ctx->sub->ss[idx] = ss[i];
+         ctx->sub->scissor_state_dirty |= (1 << idx);
+      }
+   } else
       vrend_report_buffer_error(ctx, 0);
-      return;
-   }
-
-   for (i = 0; i < num_scissor; i++) {
-      idx = start_slot + i;
-      ctx->sub->ss[idx] = ss[i];
-      ctx->sub->scissor_state_dirty |= (1 << idx);
-   }
 }
 
 void vrend_set_polygon_stipple(struct vrend_context *ctx,
                                struct pipe_poly_stipple *ps)
 {
    if (vrend_state.use_core_profile) {
-      static const unsigned bit31 = 1u << 31;
-      GLubyte *stip = calloc(1, 1024);
-      int i, j;
 
-      if (!ctx->pstip_inited)
-         vrend_init_pstipple_texture(ctx);
-
-      if (!stip)
-         return;
-
-      for (i = 0; i < 32; i++) {
-         for (j = 0; j < 32; j++) {
-            if (ps->stipple[i] & (bit31 >> j))
-               stip[i * 32 + j] = 0;
-            else
-               stip[i * 32 + j] = 255;
-         }
-      }
-
-      glBindTexture(GL_TEXTURE_2D, ctx->pstipple_tex_id);
-      glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 32, 32,
-                      GL_RED, GL_UNSIGNED_BYTE, stip);
-      glBindTexture(GL_TEXTURE_2D, 0);
-
-      free(stip);
-      return;
+      /* std140 aligns array elements at 16 byte */
+      for (int i = 0; i < VREND_POLYGON_STIPPLE_SIZE ; ++i)
+         ctx->sub->sysvalue_data.stipple_pattern[i][0] = ps->stipple[i];
+      ctx->sub->sysvalue_data_cookie++;
+   } else {
+      glPolygonStipple((const GLubyte *)ps->stipple);
    }
-   glPolygonStipple((const GLubyte *)ps->stipple);
 }
 
 void vrend_set_clip_state(struct vrend_context *ctx, struct pipe_clip_state *ucp)
 {
    if (vrend_state.use_core_profile) {
       ctx->sub->ucp_state = *ucp;
+
+      ctx->sub->sysvalue_data_cookie++;
+      for (int i = 0 ; i < VIRGL_NUM_CLIP_PLANES; i++) {
+         memcpy(&ctx->sub->sysvalue_data.clipp[i],
+                (const GLfloat *) &ctx->sub->ucp_state.ucp[i], sizeof(GLfloat) * 4);
+      }
    } else {
       int i, j;
       GLdouble val[4];
@@ -9789,6 +10258,7 @@
 {
    unsigned int comp_flags = 0;
    struct vrend_resource *src_res, *dst_res;
+   int src_width, src_height, dst_width, dst_height;
    src_res = vrend_renderer_ctx_res_lookup(ctx, src_handle);
    dst_res = vrend_renderer_ctx_res_lookup(ctx, dst_handle);
 
@@ -9851,6 +10321,11 @@
       !(vrend_resource_needs_srgb_decode(src_res, info->src.format) ||
         vrend_resource_needs_srgb_encode(dst_res, info->dst.format));
 
+   src_width  = u_minify(src_res->base.width0,  info->src.level);
+   src_height = u_minify(src_res->base.height0, info->src.level);
+   dst_width  = u_minify(dst_res->base.width0,  info->dst.level);
+   dst_height = u_minify(dst_res->base.height0, info->dst.level);
+
    /* The Gallium blit function can be called for a general blit that may
     * scale, convert the data, and apply some rander states, or it is called via
     * glCopyImageSubData. If the src or the dst image are equal, or the two
@@ -9865,6 +10340,10 @@
        !info->scissor_enable && (info->filter == PIPE_TEX_FILTER_NEAREST) &&
        !info->alpha_blend && (info->mask == PIPE_MASK_RGBA) &&
        src_res->base.nr_samples == dst_res->base.nr_samples &&
+       info->src.box.x + info->src.box.width  <= src_width &&
+       info->dst.box.x + info->dst.box.width  <= dst_width &&
+       info->src.box.y + info->src.box.height <= src_height &&
+       info->dst.box.y + info->dst.box.height <= dst_height &&
        info->src.box.width == info->dst.box.width &&
        info->src.box.height == info->dst.box.height &&
        info->src.box.depth == info->dst.box.depth) {
@@ -10198,11 +10677,8 @@
                        uint32_t query_type, uint32_t query_index,
                        uint32_t res_handle, UNUSED uint32_t offset)
 {
-   struct vrend_query *q;
-   struct vrend_resource *res;
-   uint32_t ret_handle;
    bool fake_samples_passed = false;
-   res = vrend_renderer_ctx_res_lookup(ctx, res_handle);
+   struct vrend_resource *res = vrend_renderer_ctx_res_lookup(ctx, res_handle);
    if (!res || !has_bit(res->storage_bits, VREND_STORAGE_HOST_SYSTEM_MEMORY)) {
       vrend_report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, res_handle);
       return EINVAL;
@@ -10222,10 +10698,12 @@
       return EINVAL;
    }
 
-   q = CALLOC_STRUCT(vrend_query);
+   struct vrend_query *q = CALLOC_STRUCT(vrend_query);
    if (!q)
       return ENOMEM;
 
+   int err = 0;
+
    list_inithead(&q->waiting_queries);
    q->type = query_type;
    q->index = query_index;
@@ -10240,20 +10718,22 @@
       q->gltype = GL_SAMPLES_PASSED_ARB;
       break;
    case PIPE_QUERY_OCCLUSION_PREDICATE:
-      if (has_feature(feat_occlusion_query_boolean)) {
+      if (has_feature(feat_occlusion_query_boolean))
          q->gltype = GL_ANY_SAMPLES_PASSED;
-         break;
-      } else
-         return EINVAL;
+      else
+         err = EINVAL;
+      break;
    case PIPE_QUERY_TIMESTAMP:
-      if (!has_feature(feat_timer_query))
-         return EINVAL;
-      q->gltype = GL_TIMESTAMP;
+      if (has_feature(feat_timer_query))
+         q->gltype = GL_TIMESTAMP;
+      else
+         err = EINVAL;
       break;
    case PIPE_QUERY_TIME_ELAPSED:
-      if (!has_feature(feat_timer_query))
-         return EINVAL;
-      q->gltype = GL_TIME_ELAPSED;
+      if (has_feature(feat_timer_query))
+         q->gltype = GL_TIME_ELAPSED;
+      else
+         err = EINVAL;
       break;
    case PIPE_QUERY_PRIMITIVES_GENERATED:
       q->gltype = GL_PRIMITIVES_GENERATED;
@@ -10265,29 +10745,34 @@
       q->gltype = GL_ANY_SAMPLES_PASSED_CONSERVATIVE;
       break;
    case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
-      if (!has_feature(feat_transform_feedback_overflow_query))
-         return EINVAL;
-      q->gltype = GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB;
+      if (has_feature(feat_transform_feedback_overflow_query))
+         q->gltype = GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB;
+      else
+         err = EINVAL;
       break;
    case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
-      if (!has_feature(feat_transform_feedback_overflow_query))
-         return EINVAL;
-      q->gltype = GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB;
+      if (has_feature(feat_transform_feedback_overflow_query))
+         q->gltype = GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB;
+      else
+         err = EINVAL;
       break;
    default:
       vrend_printf("unknown query object received %d\n", q->type);
       break;
    }
 
-   glGenQueries(1, &q->id);
-
-   ret_handle = vrend_renderer_object_insert(ctx, q, handle,
-                                             VIRGL_OBJECT_QUERY);
-   if (!ret_handle) {
-      FREE(q);
-      return ENOMEM;
+   if (!err) {
+      glGenQueries(1, &q->id);
+      if (!vrend_renderer_object_insert(ctx, q, handle, VIRGL_OBJECT_QUERY)) {
+         glDeleteQueries(1, &q->id);
+         err = ENOMEM;
+      }
    }
-   return 0;
+
+   if (err)
+      FREE(q);
+
+   return err;
 }
 
 static void vrend_destroy_query(struct vrend_query *query)
@@ -10587,15 +11072,13 @@
 
    version_str = glGetString(GL_SHADING_LANGUAGE_VERSION);
    if (vrend_state.use_gles) {
-      char tmp[20];
-      c = sscanf((const char *)version_str, "%s %s %s %s %i.%i",
-                  tmp, tmp, tmp, tmp, &major_local, &minor_local);
-      assert(c == 6);
+      c = sscanf((const char *)version_str, "%*s %*s %*s %*s %i.%i",
+                  &major_local, &minor_local);
    } else {
       c = sscanf((const char *)version_str, "%i.%i",
                   &major_local, &minor_local);
-      assert(c == 2);
    }
+   assert(c == 2);
 
    return (major_local * 100) + minor_local;
 }
@@ -10847,6 +11330,10 @@
       caps->v1.max_viewports = 1;
    }
 
+   if (has_feature(feat_timer_query)) {
+      caps->v1.bset.timer_query = 1;
+   }
+
    /* Common limits for all backends. */
    caps->v1.max_render_targets = vrend_state.max_draw_buffers;
 
@@ -10885,11 +11372,18 @@
     * this value to avoid regressions when a guest with a new mesa version is
     * run on an old virgl host. Use it also to indicate non-cap fixes on the
     * host that help enable features in the guest. */
-   caps->v2.host_feature_check_version = 12;
+   caps->v2.host_feature_check_version = 15;
 
    /* Forward host GL_RENDERER to the guest. */
    strncpy(caps->v2.renderer, renderer, sizeof(caps->v2.renderer) - 1);
 
+   /* glamor reject llvmpipe, and since the renderer string is
+    * composed of "virgl" and this renderer string we have to
+    * hide the "llvmpipe" part */
+   char *llvmpipe_string = strstr(caps->v2.renderer, "llvmpipe");
+   if (llvmpipe_string)
+      memcpy(llvmpipe_string, "LLVMPIPE", 8);
+
    glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, range);
    caps->v2.min_aliased_point_size = range[0];
    caps->v2.max_aliased_point_size = range[1];
@@ -10944,6 +11438,8 @@
    } else
       caps->v2.max_shader_patch_varyings = 0;
 
+   vrend_state.max_shader_patch_varyings = caps->v2.max_shader_patch_varyings;
+
    if (has_feature(feat_texture_gather)) {
        glGetIntegerv(GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET, &caps->v2.min_texture_gather_offset);
        glGetIntegerv(GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET, &caps->v2.max_texture_gather_offset);
@@ -11009,49 +11505,57 @@
    }
 
    if (has_feature(feat_atomic_counters)) {
-      glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS,
-                    (GLint*)(caps->v2.max_atomic_counters + PIPE_SHADER_VERTEX));
-      glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS,
-                    (GLint*)(caps->v2.max_atomic_counter_buffers + PIPE_SHADER_VERTEX));
 
-      /* OpenGL ES doesn't have the atomicCounter*() operations, force lowering to ssbo */
-      if (gles_ver > 0) {
-         caps->v2.max_atomic_counters[PIPE_SHADER_FRAGMENT] = 0;
-      } else {
+      /* On GLES hosts we want atomics to be lowered to SSBOs */
+      if (gl_ver > 0) {
+         glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS,
+                       (GLint*)(caps->v2.max_atomic_counters + PIPE_SHADER_VERTEX));
          glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS,
                        (GLint*)(caps->v2.max_atomic_counters + PIPE_SHADER_FRAGMENT));
+
+         if (has_feature(feat_geometry_shader)) {
+            glGetIntegerv(GL_MAX_GEOMETRY_ATOMIC_COUNTERS,
+                          (GLint*)(caps->v2.max_atomic_counters + PIPE_SHADER_GEOMETRY));
+         }
+
+         if (has_feature(feat_tessellation)) {
+            glGetIntegerv(GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS,
+                          (GLint*)(caps->v2.max_atomic_counters + PIPE_SHADER_TESS_CTRL));
+            glGetIntegerv(GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS,
+                          (GLint*)(caps->v2.max_atomic_counters + PIPE_SHADER_TESS_EVAL));
+         }
+
+         if (has_feature(feat_compute_shader)) {
+            glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS,
+                          (GLint*)(caps->v2.max_atomic_counters + PIPE_SHADER_COMPUTE));
+         }
+
+         glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTERS,
+                       (GLint*)&caps->v2.max_combined_atomic_counters);
       }
 
+      glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS,
+                    (GLint*)(caps->v2.max_atomic_counter_buffers + PIPE_SHADER_VERTEX));
+
       glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS,
                     (GLint*)(caps->v2.max_atomic_counter_buffers + PIPE_SHADER_FRAGMENT));
 
-      if (has_feature(feat_geometry_shader)) {
-         glGetIntegerv(GL_MAX_GEOMETRY_ATOMIC_COUNTERS,
-                       (GLint*)(caps->v2.max_atomic_counters + PIPE_SHADER_GEOMETRY));
+      if (has_feature(feat_geometry_shader))
          glGetIntegerv(GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS,
                        (GLint*)(caps->v2.max_atomic_counter_buffers + PIPE_SHADER_GEOMETRY));
-      }
 
       if (has_feature(feat_tessellation)) {
-         glGetIntegerv(GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS,
-                       (GLint*)(caps->v2.max_atomic_counters + PIPE_SHADER_TESS_CTRL));
          glGetIntegerv(GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS,
                        (GLint*)(caps->v2.max_atomic_counter_buffers + PIPE_SHADER_TESS_CTRL));
-         glGetIntegerv(GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS,
-                       (GLint*)(caps->v2.max_atomic_counters + PIPE_SHADER_TESS_EVAL));
          glGetIntegerv(GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS,
                        (GLint*)(caps->v2.max_atomic_counter_buffers + PIPE_SHADER_TESS_EVAL));
       }
 
       if (has_feature(feat_compute_shader)) {
-         glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS,
-                       (GLint*)(caps->v2.max_atomic_counters + PIPE_SHADER_COMPUTE));
          glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS,
                        (GLint*)(caps->v2.max_atomic_counter_buffers + PIPE_SHADER_COMPUTE));
       }
 
-      glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTERS,
-                    (GLint*)&caps->v2.max_combined_atomic_counters);
       glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS,
                     (GLint*)&caps->v2.max_combined_atomic_counter_buffers);
    }
@@ -11108,7 +11612,7 @@
 
    /* We want to expose ARB_gpu_shader_fp64 when running on top of ES */
    if (vrend_state.use_gles) {
-      caps->v2.capability_bits |= VIRGL_CAP_FAKE_FP64;
+      caps->v2.capability_bits |= VIRGL_CAP_HOST_IS_GLES;
    }
 
    if (has_feature(feat_indirect_draw))
@@ -11164,7 +11668,8 @@
 
    if (has_feature(feat_arb_buffer_storage) && !vrend_state.use_external_blob) {
       const char *vendor = (const char *)glGetString(GL_VENDOR);
-      bool is_mesa = ((strstr(renderer, "Mesa") != NULL) || (strstr(renderer, "DRM") != NULL));
+      bool is_mesa = ((strstr(renderer, "Mesa") != NULL) || (strstr(renderer, "DRM") != NULL) ||
+                      (strstr(renderer, "llvmpipe") != NULL));
       /*
        * Intel GPUs (aside from Atom, which doesn't expose GL4.5) are cache-coherent.
        * Mesa AMDGPUs use write-combine mappings for coherent/persistent memory (see
@@ -11179,6 +11684,8 @@
             vrend_state.inferred_gl_caching_type = VIRGL_RENDERER_MAP_CACHE_CACHED;
          else if (strstr(vendor, "AMD") != NULL)
             vrend_state.inferred_gl_caching_type = VIRGL_RENDERER_MAP_CACHE_WC;
+         else if (strstr(vendor, "Mesa") != NULL)
+            vrend_state.inferred_gl_caching_type = VIRGL_RENDERER_MAP_CACHE_CACHED;
       } else {
          /* This is an educated guess since things don't explode with VMX + Nvidia. */
          if (strstr(renderer, "Quadro K2200") != NULL)
@@ -11192,11 +11699,12 @@
 #ifdef ENABLE_MINIGBM_ALLOCATION
    if (gbm) {
       if (has_feature(feat_memory_object) && has_feature(feat_memory_object_fd)) {
-         if (!strcmp(gbm_device_get_backend_name(gbm->device), "i915") &&
+         if ((!strcmp(gbm_device_get_backend_name(gbm->device), "i915") ||
+              !strcmp(gbm_device_get_backend_name(gbm->device), "amdgpu")) &&
              !vrend_winsys_different_gpu())
             caps->v2.capability_bits |= VIRGL_CAP_ARB_BUFFER_STORAGE;
       }
-      caps->v2.capability_bits |= VIRGL_CAP_V2_SCANOUT_USES_GBM;
+      caps->v2.capability_bits_v2 |= VIRGL_CAP_V2_SCANOUT_USES_GBM;
    }
 #endif
 
@@ -11227,6 +11735,9 @@
    if (vrend_winsys_different_gpu())
       caps->v2.capability_bits_v2 |= VIRGL_CAP_V2_DIFFERENT_GPU;
 
+   if (has_feature(feat_texture_shadow_lod))
+      caps->v2.capability_bits_v2 |= VIRGL_CAP_V2_TEXTURE_SHADOW_LOD;
+
    // we use capability bits (not a version of protocol), because
    // we disable this on client side if virglrenderer is used under
    // vtest. vtest can't support this, because size of resource
@@ -11244,13 +11755,17 @@
    glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max);
    caps->v2.max_texture_image_units = MIN2(max, PIPE_MAX_SHADER_SAMPLER_VIEWS);
 
+   if (has_feature(feat_ubo)) {
+      glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &max);
+      caps->v2.max_uniform_block_size = max;
+   }
+
    /* Propagate the max of Uniform Components */
    glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &max);
    caps->v2.max_const_buffer_size[PIPE_SHADER_VERTEX] = max * 4;
 
-   /* We might insert a `sampler2D pstipple_sampler` so reduce by 1 */
    glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &max);
-   caps->v2.max_const_buffer_size[PIPE_SHADER_FRAGMENT] = max * 4 - 1;
+   caps->v2.max_const_buffer_size[PIPE_SHADER_FRAGMENT] = max * 4;
 
    if (has_feature(feat_geometry_shader)) {
       glGetIntegerv(GL_MAX_GEOMETRY_UNIFORM_COMPONENTS, &max);
@@ -11268,6 +11783,15 @@
       glGetIntegerv(GL_MAX_COMPUTE_UNIFORM_COMPONENTS, &max);
       caps->v2.max_const_buffer_size[PIPE_SHADER_COMPUTE] = max * 4;
    }
+
+   if (has_feature(feat_separate_shader_objects))
+      caps->v2.capability_bits_v2 |= VIRGL_CAP_V2_SSO;
+
+#ifdef ENABLE_VIDEO
+   vrend_video_fill_caps(caps);
+#else
+   caps->v2.num_video_caps = 0;
+#endif
 }
 
 void vrend_renderer_fill_caps(uint32_t set, uint32_t version,
@@ -11390,6 +11914,7 @@
 
 void vrend_renderer_force_ctx_0(void)
 {
+   TRACE_FUNC();
    vrend_state.current_ctx = NULL;
    vrend_state.current_hw_ctx = NULL;
    vrend_hw_switch_context(vrend_state.ctx0, true);
@@ -11475,7 +12000,7 @@
    vrend_ctx_resource_remove(ctx->res_hash, res->res_id);
 }
 
-static struct vrend_resource *vrend_renderer_ctx_res_lookup(struct vrend_context *ctx, int res_handle)
+struct vrend_resource *vrend_renderer_ctx_res_lookup(struct vrend_context *ctx, int res_handle)
 {
    return vrend_ctx_resource_lookup(ctx->res_hash, res_handle);
 }
@@ -11583,6 +12108,9 @@
 
    sub->object_hash = vrend_object_init_ctx_table();
 
+   sub->sysvalue_data.winsys_adjust_y = 1.f;
+   sub->sysvalue_data_cookie = 1;
+
    ctx->sub = sub;
    list_add(&sub->head, &ctx->sub_ctxs);
    if (sub_ctx_id == 0)
@@ -12017,3 +12545,11 @@
                                  length, message);
     }
 }
+
+#ifdef ENABLE_VIDEO
+struct vrend_video_context *vrend_context_get_video_ctx(struct vrend_context *ctx)
+{
+    return ctx->video;
+}
+#endif
+
diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h
index a9090ff..2aedf50 100644
--- a/src/vrend_renderer.h
+++ b/src/vrend_renderer.h
@@ -122,11 +122,13 @@
    virgl_gl_context (*create_gl_context)(int scanout, struct virgl_gl_ctx_param *params);
    void (*destroy_gl_context)(virgl_gl_context ctx);
    int (*make_current)(virgl_gl_context ctx);
+   int (*get_drm_fd)(void);
 };
 
 #define VREND_USE_THREAD_SYNC (1 << 0)
 #define VREND_USE_EXTERNAL_BLOB (1 << 1)
 #define VREND_USE_ASYNC_FENCE_CB (1 << 2)
+#define VREND_USE_VIDEO          (1 << 3)
 
 bool vrend_check_no_error(struct vrend_context *ctx);
 
@@ -149,7 +151,7 @@
                         const char *shd_text, uint32_t offlen, uint32_t num_tokens,
                         uint32_t type, uint32_t pkt_length);
 
-void vrend_link_program(struct vrend_context *ctx, uint32_t *handles);
+void vrend_link_program_hook(struct vrend_context *ctx, uint32_t *handles);
 
 void vrend_bind_shader(struct vrend_context *ctx,
                        uint32_t type,
@@ -162,10 +164,10 @@
                  const union pipe_color_union *color,
                  double depth, unsigned stencil);
 
-void vrend_clear_texture(struct vrend_context* ctx,
-                         uint32_t handle, uint32_t level,
-                         const struct pipe_box *box,
-                         const void * data);
+int vrend_clear_texture(struct vrend_context* ctx,
+                        uint32_t handle, uint32_t level,
+                        const struct pipe_box *box,
+                        const void * data);
 
 int vrend_draw_vbo(struct vrend_context *ctx,
                    const struct pipe_draw_info *info,
@@ -421,6 +423,9 @@
 void vrend_check_texture_multisample(struct vrend_format_table *table,
                                      bool enable_storage);
 
+struct vrend_resource *vrend_renderer_ctx_res_lookup(struct vrend_context *ctx,
+                                                     int res_handle);
+
 void vrend_renderer_resource_destroy(struct vrend_resource *res);
 
 static inline void
@@ -549,4 +554,7 @@
 void vrend_renderer_get_meminfo(struct vrend_context *ctx, uint32_t res_handle);
 
 void vrend_context_emit_string_marker(struct vrend_context *ctx, GLsizei length, const char * message);
+
+struct vrend_video_context *vrend_context_get_video_ctx(struct vrend_context *ctx);
+
 #endif
diff --git a/src/vrend_shader.c b/src/vrend_shader.c
index 8536073..60d7eb7 100644
--- a/src/vrend_shader.c
+++ b/src/vrend_shader.c
@@ -75,10 +75,15 @@
 #define SHADER_REQ_SAMPLER_BUF        (1ULL << 31)
 #define SHADER_REQ_GEOMETRY_SHADER    (1ULL << 32)
 #define SHADER_REQ_BLEND_EQUATION_ADVANCED (1ULL << 33)
+#define SHADER_REQ_EXPLICIT_ATTRIB_LOCATION (1ULL << 34)
+#define SHADER_REQ_SHADER_NOPERSPECTIVE_INTERPOLATION (1ULL << 35)
+#define SHADER_REQ_TEXTURE_SHADOW_LOD (1ULL << 36)
 
 #define FRONT_COLOR_EMITTED (1 << 0)
 #define BACK_COLOR_EMITTED  (1 << 1);
 
+#define MAX_VARYING 32
+
 enum vrend_sysval_uniform {
    UNIFORM_WINSYS_ADJUST_Y,
    UNIFORM_CLIP_PLANE,
@@ -106,6 +111,7 @@
    struct tgsi_declaration_image decl;
    enum tgsi_return_type image_return;
    bool vflag;
+   bool coherent;
 };
 
 #define MAX_IMMEDIATE 1024
@@ -150,6 +156,7 @@
    bool override_no_wm : 1;
    bool is_int : 1;
    bool fbfetch_used : 1;
+   bool needs_override : 1;
 };
 
 struct vrend_io_range {
@@ -256,6 +263,7 @@
    int abo_offsets[32];
 
    uint64_t shader_req_bits;
+   uint64_t patches_emitted_mask;
 
    struct pipe_stream_output_info *so;
    char **so_names;
@@ -263,7 +271,7 @@
    bool write_all_cbufs;
    uint32_t shadow_samp_mask;
 
-   int fs_coord_origin, fs_pixel_center;
+   bool fs_lower_left_origin, fs_integer_pixel_center;
    int fs_depth_layout;
    uint32_t fs_blend_equation_advanced;
 
@@ -289,6 +297,7 @@
    bool write_mul_utemp;
    bool write_mul_itemp;
    bool has_sample_input;
+   bool has_noperspective;
    bool early_depth_stencil;
    bool has_file_memory;
    bool force_color_two_side;
@@ -296,12 +305,16 @@
    bool has_pointsize_input;
    bool has_pointsize_output;
 
+   bool has_input_arrays;
+   bool has_output_arrays;
+
    int tcs_vertices_out;
    int tes_prim_mode;
    int tes_spacing;
    int tes_vertex_order;
    int tes_point_mode;
    bool is_last_vertex_stage;
+   bool require_dummy_value;
 
    uint16_t local_cs_block_size[3];
 };
@@ -332,6 +345,7 @@
     { SHADER_REQ_SHADER_ATOMIC_FLOAT, "NV_shader_atomic_float"},
     { SHADER_REQ_CONSERVATIVE_DEPTH, "ARB_conservative_depth"},
     {SHADER_REQ_BLEND_EQUATION_ADVANCED, "KHR_blend_equation_advanced"},
+    { SHADER_REQ_TEXTURE_SHADOW_LOD, "EXT_texture_shadow_lod"},
 };
 
 enum vrend_type_qualifier {
@@ -362,11 +376,12 @@
   enum vrend_type_qualifier udstconv;
   enum vrend_type_qualifier idstconv;
   bool dst_override_no_wm[2];
+  int32_t dest_index;
 };
 
 struct source_info {
    enum vrend_type_qualifier svec4;
-   uint32_t sreg_index;
+   int32_t sreg_index;
    bool tg4_has_component;
    bool override_no_wm[3];
    bool override_no_cast[3];
@@ -586,15 +601,14 @@
 
 static inline bool fs_emit_layout(const struct dump_ctx *ctx)
 {
-   if (ctx->fs_pixel_center)
+   if (ctx->fs_integer_pixel_center)
       return true;
-   /* if coord origin is 0 and invert is 0 - emit origin_upper_left,
-      if coord_origin is 0 and invert is 1 - emit nothing (lower)
-      if coord origin is 1 and invert is 0 - emit nothing (lower)
-      if coord_origin is 1 and invert is 1 - emit origin upper left */
-   if (!(ctx->fs_coord_origin ^ ctx->key->fs.invert_origin))
-      return true;
-   return false;
+
+   /* if fs_lower_left_origin is 0 and lower_left_origin is 0 - emit origin_upper_left,
+      if fs_lower_left_origin is 0 and lower_left_origin is 1 - emit nothing (lower)
+      if fs_lower_left_origin is 1 and lower_left_origin is 0 - emit nothing (lower)
+      if fs_lower_left_origin is 1 and lower_left_origin is 1 - emit origin_upper_left */
+   return ctx->fs_lower_left_origin == ctx->key->fs.lower_left_origin;
 }
 
 static const char *get_stage_input_name_prefix(const struct dump_ctx *ctx, int processor)
@@ -1197,7 +1211,7 @@
                          const struct tgsi_full_declaration *decl)
 {
    struct vrend_shader_io *overlap_io = find_overlapping_io(io, num_io, decl);
-   if (overlap_io) {
+   if (overlap_io && !overlap_io->needs_override) {
       int delta = new_io->first - overlap_io->first;
       if (delta >= 0) {
          new_io->array_offset = delta;
@@ -1229,16 +1243,18 @@
          if (ctx->inputs[j].name == decl->Semantic.Name &&
              ctx->inputs[j].sid == decl->Semantic.Index &&
              ctx->inputs[j].first == decl->Range.First &&
-             ctx->inputs[j].usage_mask  == decl->Declaration.UsageMask &&
              ((!decl->Declaration.Array && ctx->inputs[j].array_id == 0) ||
-              (ctx->inputs[j].array_id  == decl->Array.ArrayID)))
+              (ctx->inputs[j].array_id  == decl->Array.ArrayID))) {
             return true;
+         }
       }
+
       i = ctx->num_inputs++;
       if (ctx->num_inputs > ARRAY_SIZE(ctx->inputs)) {
          vrend_printf( "Number of inputs exceeded, max is %lu\n", ARRAY_SIZE(ctx->inputs));
          return false;
       }
+
       if (iter->processor.Processor == TGSI_PROCESSOR_VERTEX) {
          ctx->attrib_input_mask |= (1 << decl->Range.First);
          ctx->inputs[i].type = get_type(ctx->key->vs.attrib_signed_int_bitmask,
@@ -1261,14 +1277,38 @@
       ctx->inputs[i].glsl_gl_block = false;
       ctx->inputs[i].overlapping_array = NULL;
 
-      if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT &&
-          decl->Interp.Location == TGSI_INTERPOLATE_LOC_SAMPLE) {
-         ctx->shader_req_bits |= SHADER_REQ_GPU_SHADER5;
-         ctx->has_sample_input = true;
+      if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT) {
+         if (decl->Interp.Location == TGSI_INTERPOLATE_LOC_SAMPLE) {
+            ctx->shader_req_bits |= SHADER_REQ_GPU_SHADER5;
+            ctx->has_sample_input = true;
+         }
+         if (decl->Interp.Interpolate == TGSI_INTERPOLATE_LINEAR && ctx->cfg->use_gles &&
+             ctx->cfg->has_nopersective) {
+            ctx->shader_req_bits |= SHADER_REQ_SHADER_NOPERSPECTIVE_INTERPOLATION;
+            ctx->has_noperspective = true;
+         }
       }
 
       map_overlapping_io_array(ctx->inputs, &ctx->inputs[i], ctx->num_inputs, decl);
 
+      if (!ctx->inputs[i].glsl_predefined_no_emit) {
+
+         /* If the output of the previous shader contained arrays we
+          * have to check whether a non-array input here should be part
+          * of an array */
+         for (uint32_t j = 0; j < ctx->key->in_arrays.num_arrays; j++) {
+            const struct vrend_shader_io_array *array = &ctx->key->in_arrays.layout[j];
+
+            if (array->name == decl->Semantic.Name &&
+                array->sid <= decl->Semantic.Index &&
+                array->sid + array->size >= decl->Semantic.Index) {
+               ctx->inputs[i].sid = array->sid;
+               ctx->inputs[i].last = MAX2(ctx->inputs[i].first + array->size, ctx->inputs[i].last);
+               break;
+            }
+         }
+      }
+
       if (ctx->inputs[i].first != ctx->inputs[i].last)
          ctx->glsl_ver_required = require_glsl_ver(ctx, 150);
 
@@ -1307,7 +1347,7 @@
 
                   if (ctx->front_face_emitted == false) {
                      int k = ctx->num_inputs++;
-                     if (ctx->num_inputs > ARRAY_SIZE(ctx->inputs)) {
+                     if (ctx->num_inputs >= ARRAY_SIZE(ctx->inputs)) {
                         vrend_printf( "Number of inputs exceeded, max is %lu\n", ARRAY_SIZE(ctx->inputs));
                         return false;
                      }
@@ -1410,7 +1450,7 @@
             ctx->inputs[i].glsl_no_index = true;
             ctx->inputs[i].glsl_gl_block = true;
          } else if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT) {
-            if (ctx->cfg->use_gles && ctx->fs_pixel_center) {
+            if (ctx->cfg->use_gles && ctx->fs_integer_pixel_center) {
                name_prefix = "(gl_FragCoord - vec4(0.5, 0.5, 0.0, 0.0))";
             } else
                name_prefix = "gl_FragCoord";
@@ -1513,7 +1553,6 @@
          if (ctx->outputs[j].name == decl->Semantic.Name &&
              ctx->outputs[j].sid == decl->Semantic.Index &&
              ctx->outputs[j].first == decl->Range.First &&
-             ctx->outputs[j].usage_mask == decl->Declaration.UsageMask &&
              ((!decl->Declaration.Array && ctx->outputs[j].array_id == 0) ||
               (ctx->outputs[j].array_id  == decl->Array.ArrayID)))
             return true;
@@ -1913,10 +1952,10 @@
          ctx->write_all_cbufs = true;
       break;
    case TGSI_PROPERTY_FS_COORD_ORIGIN:
-      ctx->fs_coord_origin = prop->u[0].Data;
+      ctx->fs_lower_left_origin = prop->u[0].Data ? true : false;
       break;
    case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER:
-      ctx->fs_pixel_center = prop->u[0].Data;
+      ctx->fs_integer_pixel_center = prop->u[0].Data ? true : false;
       break;
    case TGSI_PROPERTY_FS_DEPTH_LAYOUT:
       /* If the host doesn't support this, then we can savely ignore this,
@@ -1985,7 +2024,14 @@
       }
       break;
    case TGSI_PROPERTY_SEPARABLE_PROGRAM:
-      ctx->separable_program = prop->u[0].Data;
+      /* GLES is very strict in how separable shaders interfaces should be matched.
+       * It doesn't allow, for example, inputs without matching outputs. So, we just
+       * disable separable shaders for GLES. */
+      if (!ctx->cfg->use_gles) {
+          ctx->separable_program = prop->u[0].Data;
+          ctx->shader_req_bits |= SHADER_REQ_SEPERATE_SHADER_OBJECTS;
+          ctx->shader_req_bits |= SHADER_REQ_EXPLICIT_ATTRIB_LOCATION;
+      }
       break;
    default:
       vrend_printf("unhandled property: %x\n", prop->Property.PropertyName);
@@ -2100,8 +2146,17 @@
 
 static void emit_pstipple_pass(struct vrend_glsl_strbufs *glsl_strbufs)
 {
-   emit_buf(glsl_strbufs, "stip_temp = texture(pstipple_sampler, vec2(gl_FragCoord.x / 32.0, gl_FragCoord.y / 32.0)).x;\n");
-   emit_buf(glsl_strbufs, "if (stip_temp > 0.0) {\n\tdiscard;\n}\n");
+   static_assert(VREND_POLYGON_STIPPLE_SIZE == 32,
+         "According to the spec stipple size must be 32");
+
+   const int mask = VREND_POLYGON_STIPPLE_SIZE - 1;
+
+   emit_buf(glsl_strbufs, "{\n");
+   emit_buff(glsl_strbufs, "   int spx = int(gl_FragCoord.x) & %d;\n", mask);
+   emit_buff(glsl_strbufs, "   int spy = int(gl_FragCoord.y) & %d;\n", mask);
+   emit_buf(glsl_strbufs, "   stip_temp = stipple_pattern[spy] & (0x80000000u >> spx);\n");
+   emit_buf(glsl_strbufs, "   if (stip_temp == 0u) {\n      discard;\n   }\n");
+   emit_buf(glsl_strbufs, "}\n");
    glsl_strbufs->required_sysval_uniform_decls |= BIT(UNIFORM_PSTIPPLE_SAMPLER);
 }
 
@@ -2304,7 +2359,10 @@
 
    if (ctx->prog_type == TGSI_PROCESSOR_TESS_CTRL)
       prefix = "gl_out[gl_InvocationID].";
-   if (ctx->num_out_clip_dist == 0 && ctx->is_last_vertex_stage) {
+
+   if (ctx->num_out_clip_dist == 0 &&
+       ctx->is_last_vertex_stage &&
+       ctx->num_outputs + 2 <= MAX_VARYING) {
       emit_buff(glsl_strbufs, "if (clip_plane_enabled) {\n");
       for (i = 0; i < 8; i++) {
          emit_buff(glsl_strbufs, "  %sgl_ClipDistance[%d] = dot(%s, clipp[%d]);\n",
@@ -2408,7 +2466,12 @@
    char src_fb[PIPE_MAX_COLOR_BUFS][64];
    double scale[PIPE_MAX_COLOR_BUFS];
    int mask[PIPE_MAX_COLOR_BUFS];
-   char full_op[PIPE_MAX_COLOR_BUFS][128 + 8];
+
+   struct vrend_strbuf full_op_buf[PIPE_MAX_COLOR_BUFS];
+   for (int i = 0; i < PIPE_MAX_COLOR_BUFS; ++i) {
+      strbuf_alloc(&full_op_buf[i], 134);
+   }
+
 
    for (unsigned i = 0; i < ctx->num_outputs; i++) {
       mask[i] = (1 << ctx->key->fs.surface_component_bits[i]) - 1;
@@ -2446,67 +2509,52 @@
    for (unsigned i = 0; i < ctx->num_outputs; i++) {
       switch (ctx->key->fs.logicop_func) {
       case PIPE_LOGICOP_CLEAR:
-         snprintf(full_op[i], ARRAY_SIZE(full_op[i]),
-                  "%s", "vec4(0)");
+         strbuf_fmt(&full_op_buf[i], "%s", "vec4(0)");
          break;
       case PIPE_LOGICOP_NOOP:
-         full_op[i][0]= 0;
+         strbuf_fmt(&full_op_buf[i], "%s", "");
          break;
       case PIPE_LOGICOP_SET:
-         snprintf(full_op[i], ARRAY_SIZE(full_op[i]),
-                  "%s", "vec4(1)");
+         strbuf_fmt(&full_op_buf[i], "%s", "vec4(1)");
          break;
       case PIPE_LOGICOP_COPY:
-         snprintf(full_op[i], ARRAY_SIZE(full_op[i]),
-                  "fsout_tmp_c%d", i);
+         strbuf_fmt(&full_op_buf[i], "fsout_tmp_c%d", i);
          break;
       case PIPE_LOGICOP_COPY_INVERTED:
-         snprintf(full_op[i], ARRAY_SIZE(full_op[i]),
-                  "~%s", src[i]);
+         strbuf_fmt(&full_op_buf[i], "~%s", src[i]);
          break;
       case PIPE_LOGICOP_INVERT:
-         snprintf(full_op[i], ARRAY_SIZE(full_op[i]),
-                  "~%s", src_fb[i]);
+         strbuf_fmt(&full_op_buf[i], "~%s", src_fb[i]);
          break;
       case PIPE_LOGICOP_AND:
-         snprintf(full_op[i], ARRAY_SIZE(full_op[i]),
-                  "%s & %s", src[i], src_fb[i]);
+         strbuf_fmt(&full_op_buf[i], "%s & %s", src[i], src_fb[i]);
          break;
       case PIPE_LOGICOP_NAND:
-         snprintf(full_op[i], ARRAY_SIZE(full_op[i]),
-                  "~( %s & %s )", src[i], src_fb[i]);
+         strbuf_fmt(&full_op_buf[i], "~( %s & %s )", src[i], src_fb[i]);
          break;
       case PIPE_LOGICOP_NOR:
-         snprintf(full_op[i], ARRAY_SIZE(full_op[i]),
-                  "~( %s | %s )", src[i], src_fb[i]);
+         strbuf_fmt(&full_op_buf[i], "~( %s | %s )", src[i], src_fb[i]);
          break;
       case PIPE_LOGICOP_AND_INVERTED:
-         snprintf(full_op[i], ARRAY_SIZE(full_op[i]),
-                  "~%s & %s", src[i], src_fb[i]);
+         strbuf_fmt(&full_op_buf[i], "~%s & %s", src[i], src_fb[i]);
          break;
       case PIPE_LOGICOP_AND_REVERSE:
-         snprintf(full_op[i], ARRAY_SIZE(full_op[i]),
-                  "%s & ~%s", src[i], src_fb[i]);
+         strbuf_fmt(&full_op_buf[i], "%s & ~%s", src[i], src_fb[i]);
          break;
       case PIPE_LOGICOP_XOR:
-         snprintf(full_op[i], ARRAY_SIZE(full_op[i]),
-                  "%s ^%s", src[i], src_fb[i]);
+         strbuf_fmt(&full_op_buf[i], "%s ^%s", src[i], src_fb[i]);
          break;
       case PIPE_LOGICOP_EQUIV:
-         snprintf(full_op[i], ARRAY_SIZE(full_op[i]),
-                  "~( %s ^ %s )", src[i], src_fb[i]);
+         strbuf_fmt(&full_op_buf[i], "~( %s ^ %s )", src[i], src_fb[i]);
          break;
       case PIPE_LOGICOP_OR_INVERTED:
-         snprintf(full_op[i], ARRAY_SIZE(full_op[i]),
-                  "~%s | %s", src[i], src_fb[i]);
+         strbuf_fmt(&full_op_buf[i], "~%s | %s", src[i], src_fb[i]);
          break;
       case PIPE_LOGICOP_OR_REVERSE:
-         snprintf(full_op[i], ARRAY_SIZE(full_op[i]),
-                  "%s | ~%s", src[i], src_fb[i]);
+         strbuf_fmt(&full_op_buf[i], "%s | ~%s", src[i], src_fb[i]);
          break;
       case PIPE_LOGICOP_OR:
-         snprintf(full_op[i], ARRAY_SIZE(full_op[i]),
-                  "%s | %s", src[i], src_fb[i]);
+         strbuf_fmt(&full_op_buf[i], "%s | %s", src[i], src_fb[i]);
          break;
       }
    }
@@ -2518,10 +2566,10 @@
       case PIPE_LOGICOP_COPY:
       case PIPE_LOGICOP_CLEAR:
       case PIPE_LOGICOP_SET:
-         emit_buff(glsl_strbufs, "fsout_c%d = %s;\n", i, full_op[i]);
+         emit_buff(glsl_strbufs, "fsout_c%d = %s;\n", i, full_op_buf[i].buf);
          break;
       default:
-         emit_buff(glsl_strbufs, "fsout_c%d = vec4((%s) & %d) / %f;\n", i, full_op[i], mask[i], scale[i]);
+         emit_buff(glsl_strbufs, "fsout_c%d = vec4((%s) & %d) / %f;\n", i, full_op_buf[i].buf, mask[i], scale[i]);
       }
    }
 }
@@ -2561,7 +2609,7 @@
 static void handle_fragment_proc_exit(const struct dump_ctx *ctx,
                                       struct vrend_glsl_strbufs *glsl_strbufs)
 {
-    if (ctx->key->pstipple_tex)
+    if (ctx->key->pstipple_enabled)
        emit_pstipple_pass(glsl_strbufs);
 
     if (ctx->key->fs.cbufs_are_a8_bitmask)
@@ -2755,8 +2803,6 @@
 static const char *get_tex_inst_ext(const struct tgsi_full_instruction *inst)
 {
    switch (inst->Instruction.Opcode) {
-   case TGSI_OPCODE_LODQ:
-      return "QueryLOD";
    case TGSI_OPCODE_TXP:
       if (inst->Texture.Texture == TGSI_TEXTURE_CUBE ||
           inst->Texture.Texture == TGSI_TEXTURE_2D_ARRAY ||
@@ -2792,25 +2838,32 @@
    }
 }
 
-static void get_temp(const struct dump_ctx *ctx,
-              bool indirect_dim, int dim, int reg,
-              char buf[static 64])
+static void
+get_temp(const struct dump_ctx *ctx,
+         bool indirect_dim, int dim, int reg,
+         char buf[static 64], bool *require_dummy_value)
 {
    struct vrend_temp_range *range = find_temp_range(ctx, reg);
-   if (indirect_dim) {
-      snprintf(buf, 64, "temp%d[addr%d + %d]", range->first, dim, reg - range->first);
-   } else {
-      if (range->array_id > 0) {
-         snprintf(buf, 64, "temp%d[%d]", range->first, reg - range->first);
+   if (range) {
+      if (indirect_dim) {
+         snprintf(buf, 64, "temp%d[addr%d + %d]", range->first, dim, reg - range->first);
       } else {
-         snprintf(buf, 64, "temp%d", reg);
+         if (range->array_id > 0) {
+            snprintf(buf, 64, "temp%d[%d]", range->first, reg - range->first);
+         } else {
+            snprintf(buf, 64, "temp%d", reg);
+         }
       }
+   } else {
+      snprintf(buf, 64, "dummy_value");
+      *require_dummy_value = true;
    }
 }
 
 static bool fill_offset_buffer(const struct dump_ctx *ctx,
                                const struct tgsi_full_instruction *inst,
-                               struct vrend_strbuf *offset_buf)
+                               struct vrend_strbuf *offset_buf,
+                               bool *require_dummy_value)
 {
    if (inst->TexOffsets[0].File == TGSI_FILE_IMMEDIATE) {
       const struct immed *imd = &ctx->imm[inst->TexOffsets[0].Index];
@@ -2842,7 +2895,7 @@
       }
    } else if (inst->TexOffsets[0].File == TGSI_FILE_TEMPORARY) {
       char temp_buf[64];
-      get_temp(ctx, false, 0, inst->TexOffsets[0].Index, temp_buf);
+      get_temp(ctx, false, 0, inst->TexOffsets[0].Index, temp_buf, require_dummy_value);
       switch (inst->Texture.Texture) {
       case TGSI_TEXTURE_1D:
       case TGSI_TEXTURE_1D_ARRAY:
@@ -2923,6 +2976,57 @@
    return true;
 }
 
+static void
+emit_lodq(struct dump_ctx *ctx,
+          const struct tgsi_full_instruction *inst,
+          const struct source_info *sinfo,
+          const struct dest_info *dinfo,
+          const char *srcs[4],
+          const char *dst,
+          const char *writemask)
+{
+   ctx->shader_req_bits |= SHADER_REQ_LODQ;
+
+   set_texture_reqs(ctx, inst, sinfo->sreg_index);
+
+   emit_buff(&ctx->glsl_strbufs, "%s = %s(textureQueryLOD(%s, ",
+          dst, get_string(dinfo->dstconv), srcs[1]);
+
+   switch (inst->Texture.Texture) {
+   case TGSI_TEXTURE_1D:
+   case TGSI_TEXTURE_1D_ARRAY:
+   case TGSI_TEXTURE_SHADOW1D:
+   case TGSI_TEXTURE_SHADOW1D_ARRAY:
+      if (ctx->cfg->use_gles)
+         emit_buff(&ctx->glsl_strbufs, "vec2(%s.x, 0)", srcs[0]);
+      else
+         emit_buff(&ctx->glsl_strbufs, "%s.x", srcs[0]);
+      break;
+   case TGSI_TEXTURE_2D:
+   case TGSI_TEXTURE_2D_ARRAY:
+   case TGSI_TEXTURE_2D_MSAA:
+   case TGSI_TEXTURE_2D_ARRAY_MSAA:
+   case TGSI_TEXTURE_RECT:
+   case TGSI_TEXTURE_SHADOW2D:
+   case TGSI_TEXTURE_SHADOW2D_ARRAY:
+   case TGSI_TEXTURE_SHADOWRECT:
+      emit_buff(&ctx->glsl_strbufs, "%s.xy", srcs[0]);
+      break;
+   case TGSI_TEXTURE_3D:
+   case TGSI_TEXTURE_CUBE:
+   case TGSI_TEXTURE_SHADOWCUBE:
+   case TGSI_TEXTURE_SHADOWCUBE_ARRAY:
+   case TGSI_TEXTURE_CUBE_ARRAY:
+      emit_buff(&ctx->glsl_strbufs, "%s.xyz", srcs[0]);
+      break;
+   default:
+      emit_buff(&ctx->glsl_strbufs, "%s", srcs[0]);
+      break;
+   }
+
+   emit_buff(&ctx->glsl_strbufs, ")%s);\n", writemask);
+}
+
 // TODO Consider exposing non-const ctx-> members as args to make *ctx const
 static void translate_tex(struct dump_ctx *ctx,
                           const struct tgsi_full_instruction *inst,
@@ -2933,11 +3037,11 @@
                           const char *writemask)
 {
    enum vrend_type_qualifier txfi = TYPE_CONVERSION_NONE;
-   unsigned twm = TGSI_WRITEMASK_NONE, gwm = TGSI_WRITEMASK_NONE;
+   const char *src_swizzle;
    enum vrend_type_qualifier dtypeprefix = TYPE_CONVERSION_NONE;
    bool is_shad;
 
-   int sampler_index;
+   int sampler_index = 1;
    const char *tex_ext;
 
    struct vrend_strbuf bias_buf;
@@ -2964,30 +3068,25 @@
       break;
    }
 
-   sampler_index = 1;
-
-   if (inst->Instruction.Opcode == TGSI_OPCODE_LODQ)
-      ctx->shader_req_bits |= SHADER_REQ_LODQ;
-
    switch (inst->Texture.Texture) {
    case TGSI_TEXTURE_1D:
    case TGSI_TEXTURE_BUFFER:
       if (inst->Instruction.Opcode == TGSI_OPCODE_TXP)
-         twm = TGSI_WRITEMASK_NONE;
+         src_swizzle = "";
       else
-         twm = TGSI_WRITEMASK_X;
+         src_swizzle = ".x";
       txfi = INT;
       break;
    case TGSI_TEXTURE_1D_ARRAY:
-      twm = TGSI_WRITEMASK_XY;
+      src_swizzle = ".xy";
       txfi = IVEC2;
       break;
    case TGSI_TEXTURE_2D:
    case TGSI_TEXTURE_RECT:
       if (inst->Instruction.Opcode == TGSI_OPCODE_TXP)
-         twm = TGSI_WRITEMASK_NONE;
+         src_swizzle = "";
       else
-         twm = TGSI_WRITEMASK_XY;
+         src_swizzle = ".xy";
       txfi = IVEC2;
       break;
    case TGSI_TEXTURE_SHADOW1D:
@@ -2996,24 +3095,24 @@
    case TGSI_TEXTURE_SHADOWRECT:
    case TGSI_TEXTURE_3D:
       if (inst->Instruction.Opcode == TGSI_OPCODE_TXP)
-         twm = TGSI_WRITEMASK_NONE;
+         src_swizzle = "";
       else if (inst->Instruction.Opcode == TGSI_OPCODE_TG4)
-         twm = TGSI_WRITEMASK_XY;
+         src_swizzle = ".xy";
       else
-         twm = TGSI_WRITEMASK_XYZ;
+         src_swizzle = ".xyz";
       txfi = IVEC3;
       break;
    case TGSI_TEXTURE_CUBE:
    case TGSI_TEXTURE_2D_ARRAY:
-      twm = TGSI_WRITEMASK_XYZ;
+      src_swizzle = ".xyz";
       txfi = IVEC3;
       break;
    case TGSI_TEXTURE_2D_MSAA:
-      twm = TGSI_WRITEMASK_XY;
+      src_swizzle = ".xy";
       txfi = IVEC2;
       break;
    case TGSI_TEXTURE_2D_ARRAY_MSAA:
-      twm = TGSI_WRITEMASK_XYZ;
+      src_swizzle = ".xyz";
       txfi = IVEC3;
       break;
 
@@ -3025,57 +3124,33 @@
       if (inst->Instruction.Opcode == TGSI_OPCODE_TG4 &&
           inst->Texture.Texture != TGSI_TEXTURE_CUBE_ARRAY &&
           inst->Texture.Texture != TGSI_TEXTURE_SHADOWCUBE_ARRAY)
-         twm = TGSI_WRITEMASK_XYZ;
+         src_swizzle = ".xyz";
       else
-         twm = TGSI_WRITEMASK_NONE;
+         src_swizzle = "";
       txfi = TYPE_CONVERSION_NONE;
       break;
    }
 
-   if (inst->Instruction.Opcode == TGSI_OPCODE_TXD) {
-      switch (inst->Texture.Texture) {
-      case TGSI_TEXTURE_1D:
-      case TGSI_TEXTURE_SHADOW1D:
-      case TGSI_TEXTURE_1D_ARRAY:
-      case TGSI_TEXTURE_SHADOW1D_ARRAY:
-         gwm = TGSI_WRITEMASK_X;
-         break;
-      case TGSI_TEXTURE_2D:
-      case TGSI_TEXTURE_SHADOW2D:
-      case TGSI_TEXTURE_2D_ARRAY:
-      case TGSI_TEXTURE_SHADOW2D_ARRAY:
-      case TGSI_TEXTURE_RECT:
-      case TGSI_TEXTURE_SHADOWRECT:
-         gwm = TGSI_WRITEMASK_XY;
-         break;
-      case TGSI_TEXTURE_3D:
-      case TGSI_TEXTURE_CUBE:
-      case TGSI_TEXTURE_SHADOWCUBE:
-      case TGSI_TEXTURE_CUBE_ARRAY:
-         gwm = TGSI_WRITEMASK_XYZ;
-         break;
-      default:
-         gwm = TGSI_WRITEMASK_NONE;
-         break;
-      }
-   }
-
    switch (inst->Instruction.Opcode) {
-   case TGSI_OPCODE_TXB2:
-   case TGSI_OPCODE_TXL2:
    case TGSI_OPCODE_TEX2:
       sampler_index = 2;
-      if (inst->Instruction.Opcode != TGSI_OPCODE_TEX2)
+      if (inst->Texture.Texture == TGSI_TEXTURE_SHADOWCUBE_ARRAY)
          strbuf_appendf(&bias_buf, ", %s.x", srcs[1]);
-      else if (inst->Texture.Texture == TGSI_TEXTURE_SHADOWCUBE_ARRAY)
-         strbuf_appendf(&bias_buf, ", float(%s)", srcs[1]);
+      break;
+   case TGSI_OPCODE_TXB2:
+   case TGSI_OPCODE_TXL2:
+      sampler_index = 2;
+      strbuf_appendf(&bias_buf, ", %s.x", srcs[1]);
+      if (inst->Texture.Texture == TGSI_TEXTURE_SHADOWCUBE_ARRAY)
+         strbuf_appendf(&bias_buf, ", %s.y", srcs[1]);
       break;
    case TGSI_OPCODE_TXB:
    case TGSI_OPCODE_TXL:
       /* On GLES we emulate the 1D array by using a 2D array, for this
-       * there is no shadow lookup with bias. To avoid that compiling an
-       * invalid shader results in a crash we ignore the bias value */
-      if (!(ctx->cfg->use_gles &&
+       * there is no shadow lookup with bias unless EXT_texture_shadow_lod is used.
+       * To avoid that compiling an invalid shader results in a crash we ignore
+       * the bias value */
+      if (!(ctx->cfg->use_gles && !ctx->cfg->has_texture_shadow_lod &&
             TGSI_TEXTURE_SHADOW1D_ARRAY == inst->Texture.Texture))
          strbuf_appendf(&bias_buf, ", %s.w", srcs[0]);
       break;
@@ -3090,14 +3165,35 @@
          strbuf_appendf(&bias_buf, ", int(%s.w)", srcs[0]);
       break;
    case TGSI_OPCODE_TXD:
-      if (ctx->cfg->use_gles && (inst->Texture.Texture == TGSI_TEXTURE_1D ||
-                                 inst->Texture.Texture == TGSI_TEXTURE_SHADOW1D ||
-                                 inst->Texture.Texture == TGSI_TEXTURE_1D_ARRAY ||
-                                 inst->Texture.Texture == TGSI_TEXTURE_SHADOW1D_ARRAY))
-         strbuf_appendf(&bias_buf, ", vec2(%s%s, 0), vec2(%s%s, 0)", srcs[1], get_wm_string(gwm), srcs[2], get_wm_string(gwm));
-      else
-         strbuf_appendf(&bias_buf, ", %s%s, %s%s", srcs[1], get_wm_string(gwm), srcs[2], get_wm_string(gwm));
       sampler_index = 3;
+      switch (inst->Texture.Texture) {
+      case TGSI_TEXTURE_1D:
+      case TGSI_TEXTURE_SHADOW1D:
+      case TGSI_TEXTURE_1D_ARRAY:
+      case TGSI_TEXTURE_SHADOW1D_ARRAY:
+         if (ctx->cfg->use_gles)
+            strbuf_appendf(&bias_buf, ", vec2(%s.x, 0), vec2(%s.x, 0)", srcs[1], srcs[2]);
+         else
+            strbuf_appendf(&bias_buf, ", %s.x, %s.x", srcs[1], srcs[2]);
+         break;
+      case TGSI_TEXTURE_2D:
+      case TGSI_TEXTURE_SHADOW2D:
+      case TGSI_TEXTURE_2D_ARRAY:
+      case TGSI_TEXTURE_SHADOW2D_ARRAY:
+      case TGSI_TEXTURE_RECT:
+      case TGSI_TEXTURE_SHADOWRECT:
+         strbuf_appendf(&bias_buf, ", %s.xy, %s.xy", srcs[1], srcs[2]);
+         break;
+      case TGSI_TEXTURE_3D:
+      case TGSI_TEXTURE_CUBE:
+      case TGSI_TEXTURE_SHADOWCUBE:
+      case TGSI_TEXTURE_CUBE_ARRAY:
+         strbuf_appendf(&bias_buf, ", %s.xyz, %s.xyz", srcs[1], srcs[2]);
+         break;
+      default:
+         strbuf_appendf(&bias_buf, ", %s, %s", srcs[1], srcs[2]);
+         break;
+      }
       break;
    case TGSI_OPCODE_TG4:
       sampler_index = 2;
@@ -3143,6 +3239,19 @@
    const char *bias = bias_buf.buf;
    const char *offset = offset_buf.buf;
 
+   // EXT_texture_shadow_lod defines a few more functions handling bias
+   if (bias &&
+       (inst->Texture.Texture == TGSI_TEXTURE_SHADOW2D_ARRAY ||
+        inst->Texture.Texture == TGSI_TEXTURE_SHADOWCUBE ||
+        inst->Texture.Texture == TGSI_TEXTURE_SHADOWCUBE_ARRAY))
+      ctx->shader_req_bits |= SHADER_REQ_TEXTURE_SHADOW_LOD;
+
+   // EXT_texture_shadow_lod also adds the missing textureOffset for 2DArrayShadow in GLES
+   if ((bias || offset) && ctx->cfg->use_gles &&
+       (inst->Texture.Texture == TGSI_TEXTURE_SHADOW1D_ARRAY ||
+        inst->Texture.Texture == TGSI_TEXTURE_SHADOW2D_ARRAY))
+      ctx->shader_req_bits |= SHADER_REQ_TEXTURE_SHADOW_LOD;
+
    if (inst->Texture.NumOffsets == 1) {
       if (inst->TexOffsets[0].Index >= (int)ARRAY_SIZE(ctx->imm)) {
          vrend_printf( "Immediate exceeded, max is %lu\n", ARRAY_SIZE(ctx->imm));
@@ -3150,7 +3259,7 @@
          goto cleanup;
       }
 
-      if (!fill_offset_buffer(ctx, inst, &offset_buf)) {
+      if (!fill_offset_buffer(ctx, inst, &offset_buf, &ctx->require_dummy_value)) {
          set_buf_error(&ctx->glsl_strbufs);
          goto cleanup;
       }
@@ -3161,13 +3270,14 @@
       }
    }
 
+   char buf[255];
+   const char *new_srcs[4] = { buf, srcs[1], srcs[2], srcs[3] };
+
    /* We have to unnormalize the coordinate for all but the texel fetch instruction */
    if (inst->Instruction.Opcode != TGSI_OPCODE_TXF &&
        vrend_shader_sampler_views_mask_get(ctx->key->sampler_views_emulated_rect_mask, sinfo->sreg_index)) {
 
-      char buf[255];
       const char *bias = "";
-      const char *new_srcs[4] = { buf, srcs[1], srcs[2], srcs[3] };
 
       /* No LOD for these texture types, but on GLES we emulate RECT by using
        * a normal 2D texture, so we have to give LOD 0 */
@@ -3212,21 +3322,21 @@
          if (inst->Texture.Texture == TGSI_TEXTURE_1D)
             emit_buff(&ctx->glsl_strbufs, "%s = %s(%s(texelFetch%s(%s, ivec2(%s(%s%s), 0)%s%s)%s));\n",
                       dst, get_string(dinfo->dstconv), get_string(dtypeprefix),
-                      tex_ext, srcs[sampler_index], get_string(txfi), srcs[0],
-                      get_wm_string(twm), bias, offset,
+                      tex_ext, srcs[sampler_index], get_string(txfi),
+                      srcs[0], src_swizzle, bias, offset,
                       dinfo->dst_override_no_wm[0] ? "" : writemask);
          else if (inst->Texture.Texture == TGSI_TEXTURE_1D_ARRAY) {
             /* the y coordinate must go into the z element and the y must be zero */
             emit_buff(&ctx->glsl_strbufs, "%s = %s(%s(texelFetch%s(%s, ivec3(%s(%s%s), 0).xzy%s%s)%s));\n",
                       dst, get_string(dinfo->dstconv), get_string(dtypeprefix),
-                      tex_ext, srcs[sampler_index], get_string(txfi), srcs[0],
-                      get_wm_string(twm), bias, offset,
+                      tex_ext, srcs[sampler_index], get_string(txfi),
+                      srcs[0], src_swizzle, bias, offset,
                       dinfo->dst_override_no_wm[0] ? "" : writemask);
          } else {
             emit_buff(&ctx->glsl_strbufs, "%s = %s(%s(texelFetch%s(%s, %s(%s%s), 0%s)%s));\n",
                       dst, get_string(dinfo->dstconv), get_string(dtypeprefix),
-                      tex_ext, srcs[sampler_index], get_string(txfi), srcs[0],
-                      get_wm_string(twm), offset,
+                      tex_ext, srcs[sampler_index], get_string(txfi),
+                      srcs[0], src_swizzle, offset,
                       dinfo->dst_override_no_wm[0] ? "" : writemask);
          }
       } else {
@@ -3242,8 +3352,8 @@
           */
          emit_buff(&ctx->glsl_strbufs, "{\n  vec4 val = %s(texelFetch%s(%s, %s(%s%s)%s%s));\n",
                    get_string(dtypeprefix),
-                   tex_ext, srcs[sampler_index], get_string(txfi), srcs[0],
-                   get_wm_string(twm), bias, offset);
+                   tex_ext, srcs[sampler_index], get_string(txfi),
+                   srcs[0], src_swizzle, bias, offset);
 
          if (vrend_shader_sampler_views_mask_get(ctx->key->sampler_views_lower_swizzle_mask, sinfo->sreg_index)) {
             int16_t  packed_swizzles = ctx->key->tex_swizzle[sinfo->sreg_index];
@@ -3256,7 +3366,19 @@
                int swz = (packed_swizzles >> (i * 3)) & 7;
                switch (swz) {
                case PIPE_SWIZZLE_ZERO : emit_buf(&ctx->glsl_strbufs,  "0.0"); break;
-               case PIPE_SWIZZLE_ONE : emit_buf(&ctx->glsl_strbufs,  "1.0"); break;
+               case PIPE_SWIZZLE_ONE :
+                  switch (dtypeprefix) {
+                  case UINT_BITS_TO_FLOAT:
+                     emit_buf(&ctx->glsl_strbufs,  "uintBitsToFloat(1u)");
+                     break;
+                  case INT_BITS_TO_FLOAT:
+                     emit_buf(&ctx->glsl_strbufs,  "intBitsToFloat(1)");
+                     break;
+                  default:
+                     emit_buf(&ctx->glsl_strbufs,  "1.0");
+                     break;
+                  }
+                  break;
                default:
                   emit_buff(&ctx->glsl_strbufs,  "val%s", get_swizzle_string(swz));
                }
@@ -3289,21 +3411,21 @@
                emit_buff(&ctx->glsl_strbufs, "%s = %s(%s(vec4(vec4(texture%s(%s, vec4(%s%s.xzw, 0).xwyz %s%s)) * %sshadmask%d + %sshadadd%d)%s));\n",
                          dst, get_string(dinfo->dstconv),
                          get_string(dtypeprefix), tex_ext, srcs[sampler_index],
-                         srcs[0], get_wm_string(twm), offset, bias, cname,
-                         src->Register.Index, cname,
-                         src->Register.Index, writemask);
+                         srcs[0], src_swizzle, offset, bias,
+                         cname, src->Register.Index,
+                         cname, src->Register.Index, writemask);
             else
                emit_buff(&ctx->glsl_strbufs, "%s = %s(%s(vec4(vec4(texture%s(%s, vec3(%s%s.xz, 0).xzy %s%s)) * %sshadmask%d + %sshadadd%d)%s));\n",
                          dst, get_string(dinfo->dstconv),
                          get_string(dtypeprefix), tex_ext, srcs[sampler_index],
-                         srcs[0], get_wm_string(twm), offset, bias, cname,
-                         src->Register.Index, cname,
-                         src->Register.Index, writemask);
+                         srcs[0], src_swizzle, offset, bias,
+                         cname, src->Register.Index,
+                         cname, src->Register.Index, writemask);
          } else if (inst->Texture.Texture == TGSI_TEXTURE_SHADOW1D_ARRAY) {
             emit_buff(&ctx->glsl_strbufs, "%s = %s(%s(vec4(vec4(texture%s(%s, vec4(%s%s, 0).xwyz %s%s)) * %sshadmask%d + %sshadadd%d)%s));\n",
                       dst, get_string(dinfo->dstconv), get_string(dtypeprefix),
                       tex_ext, srcs[sampler_index], srcs[0],
-                      get_wm_string(twm), offset, bias, cname,
+                      src_swizzle, offset, bias, cname,
                       src->Register.Index, cname,
                       src->Register.Index, writemask);
          }
@@ -3311,9 +3433,9 @@
          emit_buff(&ctx->glsl_strbufs, "%s = %s(%s(vec4(vec4(texture%s(%s, %s%s%s%s)) * %sshadmask%d + %sshadadd%d)%s));\n",
                    dst, get_string(dinfo->dstconv), get_string(dtypeprefix),
                    tex_ext, srcs[sampler_index], srcs[0],
-                   get_wm_string(twm), offset, bias, cname,
-                   src->Register.Index, cname,
-                   src->Register.Index, writemask);
+                   src_swizzle, offset, bias,
+                   cname, src->Register.Index,
+                   cname, src->Register.Index, writemask);
    } else {
       /* OpenGL ES do not support 1D texture
        * so we use a 2D texture with a parameter set to 0.5
@@ -3332,7 +3454,7 @@
                emit_buff(&ctx->glsl_strbufs, "%s = %s(%s(texture%s(%s, vec2(%s%s, 0.5) %s%s)%s));\n",
                          dst, get_string(dinfo->dstconv),
                          get_string(dtypeprefix), tex_ext, srcs[sampler_index],
-                         srcs[0], get_wm_string(twm), offset, bias,
+                         srcs[0], src_swizzle, offset, bias,
                          dinfo->dst_override_no_wm[0] ? "" : writemask);
          } else if (inst->Texture.Texture == TGSI_TEXTURE_1D_ARRAY) {
             if (inst->Instruction.Opcode == TGSI_OPCODE_TXP)
@@ -3345,13 +3467,13 @@
                emit_buff(&ctx->glsl_strbufs, "%s = %s(%s(texture%s(%s, vec3(%s%s, 0).xzy %s%s)%s));\n",
                          dst, get_string(dinfo->dstconv),
                          get_string(dtypeprefix), tex_ext, srcs[sampler_index],
-                         srcs[0], get_wm_string(twm), offset, bias,
+                         srcs[0], src_swizzle, offset, bias,
                          dinfo->dst_override_no_wm[0] ? "" : writemask);
          }
       } else {
          emit_buff(&ctx->glsl_strbufs, "%s = %s(%s(texture%s(%s, %s%s%s%s)%s));\n",
                    dst, get_string(dinfo->dstconv), get_string(dtypeprefix),
-                   tex_ext, srcs[sampler_index], srcs[0], get_wm_string(twm),
+                   tex_ext, srcs[sampler_index], srcs[0], src_swizzle,
                    offset, bias, dinfo->dst_override_no_wm[0] ? "" : writemask);
       }
    }
@@ -3427,7 +3549,6 @@
                       struct vrend_strbuf *result,
                       const struct tgsi_full_src_register *src,
                       int input_idx,
-                      bool gl_in,
                       const char *stypeprefix,
                       int offset)
 {
@@ -3450,10 +3571,7 @@
    else
       snprintf(clip_indirect, 32, "%d + %d", src->Register.Index - offset, base_idx);
 
-   if (gl_in)
-      strbuf_fmt(result, "%s(clip_dist_temp[%s].%s)", stypeprefix, clip_indirect, swz);
-   else
-      strbuf_fmt(result, "%s(clip_dist_temp[%s].%s)", stypeprefix, clip_indirect, swz);
+   strbuf_fmt(result, "%s(clip_dist_temp[%s].%s)", stypeprefix, clip_indirect, swz);
 }
 
 
@@ -3499,6 +3617,20 @@
    return false;
 }
 
+static void set_image_qualifier(struct vrend_shader_image images[],
+                                uint32_t image_used_mask,
+                                const struct tgsi_full_instruction *inst,
+                                uint32_t reg_index, bool indirect)
+{
+   if (inst->Memory.Qualifier == TGSI_MEMORY_COHERENT) {
+      if (indirect) {
+         while (image_used_mask)
+            images[u_bit_scan(&image_used_mask)].coherent = true;
+      } else
+         images[reg_index].coherent = true;
+   }
+}
+
 static void set_memory_qualifier(uint8_t ssbo_memory_qualifier[],
                                  uint32_t ssbo_used_mask,
                                  const struct tgsi_full_instruction *inst,
@@ -3529,14 +3661,24 @@
 translate_store(const struct dump_ctx *ctx,
                 struct vrend_glsl_strbufs *glsl_strbufs,
                 uint8_t ssbo_memory_qualifier[],
+                struct vrend_shader_image images[],
                 const struct tgsi_full_instruction *inst,
                 struct source_info *sinfo,
                 const char *srcs[4],
+                const struct dest_info *dinfo,
                 const char *dst)
 {
    const struct tgsi_full_dst_register *dst_reg = &inst->Dst[0];
 
+   assert(dinfo->dest_index >= 0);
    if (dst_reg->Register.File == TGSI_FILE_IMAGE) {
+
+      /* bail out if we want to write to a non-existing image */
+      if (!((1 << dinfo->dest_index) & ctx->images_used_mask))
+            return;
+
+      set_image_qualifier(images, ctx->images_used_mask, inst, inst->Src[0].Register.Index, inst->Src[0].Register.Indirect);
+
       bool is_ms = false;
       enum vrend_type_qualifier coord_prefix = get_coord_prefix(ctx->images[dst_reg->Register.Index].decl.Resource, &is_ms, ctx->cfg->use_gles);
       enum tgsi_return_type itype;
@@ -3628,8 +3770,7 @@
    }
 }
 
-
-static void
+static bool
 translate_load(const struct dump_ctx *ctx,
                struct vrend_glsl_strbufs *glsl_strbufs,
                uint8_t ssbo_memory_qualifier[],
@@ -3643,6 +3784,15 @@
 {
    const struct tgsi_full_src_register *src = &inst->Src[0];
    if (src->Register.File == TGSI_FILE_IMAGE) {
+
+      /* Bail out if we want to load from an image that is not actually used */
+      assert(sinfo->sreg_index >= 0);
+      if (!((1 << sinfo->sreg_index) & ctx->images_used_mask))
+            return false;
+
+      set_image_qualifier(images, ctx->images_used_mask, inst, inst->Src[0].Register.Index, inst->Src[0].Register.Indirect);
+
+
       bool is_ms = false;
       enum vrend_type_qualifier coord_prefix = get_coord_prefix(ctx->images[sinfo->sreg_index].decl.Resource, &is_ms, ctx->cfg->use_gles);
       enum vrend_type_qualifier dtypeprefix = TYPE_CONVERSION_NONE;
@@ -3708,11 +3858,13 @@
 
       set_memory_qualifier(ssbo_memory_qualifier, ctx->ssbo_used_mask, inst, inst->Src[0].Register.Index, inst->Src[0].Register.Indirect);
 
-      strcpy(mydst, dst);
-      char *wmp = strchr(mydst, '.');
+      const char *d = dst;
+      char *md = mydst;
+      unsigned i = 0;
+      while ((i < sizeof(mydst) - 1) && *d && *d != '.')
+         *md++ = *d++;
+      *md = 0;
 
-      if (wmp)
-         wmp[0] = 0;
       emit_buff(glsl_strbufs, "ssbo_addr_temp = uint(floatBitsToUint(%s)) >> 2;\n", srcs[1]);
 
       atomic_op[0] = atomic_src[0] = '\0';
@@ -3748,6 +3900,7 @@
    } else if (src->Register.File == TGSI_FILE_HW_ATOMIC) {
       emit_buff(glsl_strbufs, "%s = uintBitsToFloat(atomicCounter(%s));\n", dst, srcs[0]);
    }
+   return true;
 }
 
 static const char *get_atomic_opname(int tgsi_opcode, bool *is_cas)
@@ -4094,7 +4247,8 @@
          struct vrend_shader_io *output = &ctx->outputs[j];
 
          if (inst->Instruction.Precise) {
-            if (!output->invariant && output->name != TGSI_SEMANTIC_CLIPVERTEX) {
+            if (!output->invariant && output->name != TGSI_SEMANTIC_CLIPVERTEX &&
+                ctx->cfg->has_gpu_shader5) {
                output->precise = true;
                ctx->shader_req_bits |= SHADER_REQ_GPU_SHADER5;
             }
@@ -4186,14 +4340,15 @@
       }
       else if (dst_reg->Register.File == TGSI_FILE_TEMPORARY) {
          char temp_buf[64];
-         get_temp(ctx, dst_reg->Register.Indirect, 0, dst_reg->Register.Index, temp_buf);
-         struct vrend_temp_range *range = find_temp_range(ctx, dst_reg->Register.Index);
-         if (!range)
-            return false;
+         get_temp(ctx, dst_reg->Register.Indirect, 0, dst_reg->Register.Index,
+                  temp_buf, &ctx->require_dummy_value);
          strbuf_fmt(&dst_bufs[i], "%s%s", temp_buf, writemask);
          if (inst->Instruction.Precise) {
-            range->precise_result |= true;
-            ctx->shader_req_bits |= SHADER_REQ_GPU_SHADER5;
+            struct vrend_temp_range *range = find_temp_range(ctx, dst_reg->Register.Index);
+            if (range && ctx->cfg->has_gpu_shader5) {
+               range->precise_result = true;
+               ctx->shader_req_bits |= SHADER_REQ_GPU_SHADER5;
+            }
          }
       }
       else if (dst_reg->Register.File == TGSI_FILE_IMAGE) {
@@ -4207,6 +4362,7 @@
                strbuf_fmt(&dst_bufs[i], "%simg%d[%d]", cname, basearrayidx, dst_reg->Register.Index - basearrayidx);
          } else
             strbuf_fmt(&dst_bufs[i], "%simg%d", cname, dst_reg->Register.Index);
+         dinfo->dest_index = dst_reg->Register.Index;
       } else if (dst_reg->Register.File == TGSI_FILE_BUFFER) {
          const char *cname = tgsi_proc_to_prefix(ctx->prog_type);
          if (ctx->info.indirect_files & (1 << TGSI_FILE_BUFFER)) {
@@ -4219,6 +4375,7 @@
                strbuf_fmt(&dst_bufs[i], "%sssboarr%s[%d].%sssbocontents%d", cname, atomic_str, dst_reg->Register.Index - base, cname, base);
          } else
             strbuf_fmt(&dst_bufs[i], "%sssbocontents%d", cname, dst_reg->Register.Index);
+         dinfo->dest_index = dst_reg->Register.Index;
       } else if (dst_reg->Register.File == TGSI_FILE_MEMORY) {
          strbuf_fmt(&dst_bufs[i], "values");
       } else if (dst_reg->Register.File == TGSI_FILE_ADDRESS) {
@@ -4288,10 +4445,16 @@
 
    enum io_decl_type decl_type = decl_plain;
 
-   if (io->first != io->last && prefer_generic_io_block(ctx, iot)) {
-      const char *stage_prefix = iot == io_in ? get_stage_input_name_prefix(ctx, ctx->prog_type) :
-                                                get_stage_output_name_prefix(ctx->prog_type);
-      get_blockvarname(outvarname, stage_prefix, io, arrayname);
+   if ((io->first != io->last || io->overlapping_array) &&
+       prefer_generic_io_block(ctx, iot)) {
+
+      const struct vrend_shader_io *array = io->overlapping_array ?
+            io->overlapping_array : io;
+
+      const char *stage_prefix = iot == io_in ?
+                                    get_stage_input_name_prefix(ctx, ctx->prog_type) :
+                                    get_stage_output_name_prefix(ctx->prog_type);
+      get_blockvarname(outvarname, stage_prefix, array, arrayname);
       arrayname = outvarname;
       decl_type = decl_block;
    }
@@ -4462,7 +4625,7 @@
             strbuf_fmt(src_buf, "%s(%s ? 1.0 : -1.0)", get_string(stypeprefix), input->glsl_name);
          else if (input->name == TGSI_SEMANTIC_CLIPDIST) {
             if (ctx->prog_type == TGSI_PROCESSOR_FRAGMENT)
-               load_clipdist_fs(ctx, src_buf, src, j, false, get_string(stypeprefix), input->first);
+               load_clipdist_fs(ctx, src_buf, src, j, get_string(stypeprefix), input->first);
             else
                create_swizzled_clipdist(ctx, src_buf, src, j, false, get_string(stypeprefix), prefix, arrayname, input->first);
          }  else if (input->name == TGSI_SEMANTIC_TESSOUTER ||
@@ -4484,13 +4647,14 @@
             if (inst->Instruction.Opcode == TGSI_OPCODE_INTERP_SAMPLE && i == 1) {
                strbuf_fmt(src_buf, "floatBitsToInt(%s%s%s%s)", prefix, input->glsl_name, arrayname, swizzle);
             } else if (input->name == TGSI_SEMANTIC_GENERIC) {
-               struct vrend_shader_io *io = ctx->generic_ios.input_range.used ? &ctx->generic_ios.input_range.io : &ctx->inputs[j];
-               get_source_info_generic(ctx, io_in, srcstypeprefix, prefix, src, io, arrayname, swizzle, src_buf);
+               get_source_info_generic(ctx, io_in, srcstypeprefix, prefix, src,
+                                       &ctx->inputs[j], arrayname, swizzle, src_buf);
             } else if (input->name == TGSI_SEMANTIC_TEXCOORD) {
-               get_source_info_generic(ctx, io_in, srcstypeprefix, prefix, src, &ctx->inputs[j], arrayname, swizzle, src_buf);
+               get_source_info_generic(ctx, io_in, srcstypeprefix, prefix, src,
+                                       &ctx->inputs[j], arrayname, swizzle, src_buf);
             } else if (input->name == TGSI_SEMANTIC_PATCH) {
-               struct vrend_shader_io *io = ctx->patch_ios.input_range.used ? &ctx->patch_ios.input_range.io : &ctx->inputs[j];
-               get_source_info_patch(srcstypeprefix, prefix, src, io, arrayname, swizzle, src_buf);
+               get_source_info_patch(srcstypeprefix, prefix, src,
+                                     &ctx->inputs[j], arrayname, swizzle, src_buf);
             } else if (input->name == TGSI_SEMANTIC_POSITION && ctx->prog_type == TGSI_PROCESSOR_VERTEX &&
                        input->first != input->last) {
                if (src->Register.Indirect)
@@ -4551,7 +4715,8 @@
             stypeprefix = FLOAT_BITS_TO_INT;
          }
          char temp_buf[64];
-         get_temp(ctx, src->Register.Indirect, src->Indirect.Index, src->Register.Index, temp_buf);
+         get_temp(ctx, src->Register.Indirect, src->Indirect.Index, src->Register.Index,
+                  temp_buf, &ctx->require_dummy_value);
          strbuf_fmt(src_buf, "%s%c%s%s%s%c", get_string(stypeprefix), stprefix ? '(' : ' ', prefix, temp_buf, swizzle, stprefix ? ')' : ' ');
       } else if (src->Register.File == TGSI_FILE_CONSTANT) {
          const char *cname = tgsi_proc_to_prefix(ctx->prog_type);
@@ -4678,7 +4843,9 @@
          }
 
          /* build up a vec4 of immediates */
-         strbuf_fmt(src_buf, "%s(%s%s(", get_string(imm_stypeprefix), prefix, get_string(vtype));
+         strbuf_fmt(src_buf, "%s%s(%s(", prefix,
+                    get_string(imm_stypeprefix), get_string(vtype));
+
          for (uint32_t j = 0; j < 4; j++) {
             if (j == 0)
                idx = src->Register.SwizzleX;
@@ -4859,180 +5026,89 @@
    }
    return true;
 }
+
 /* We have indirect IO access, but the guest actually send separate values, so
- * now we have to emulate an array.
- */
-static
-void rewrite_io_ranged(struct dump_ctx *ctx)
+ * now we have to emulate arrays by putting IO values into arrays according
+ * to semantic. Only join elements that are consecutive. */
+static int
+make_array_from_semantic(struct vrend_shader_io *io, int start_index,
+                         int num_entries, enum tgsi_semantic semantic)
+{
+   struct vrend_shader_io *io_out_range = &io[start_index];
+
+   int last_sid = io_out_range->sid;
+   for (int i = start_index + 1; i < num_entries; ++i) {
+      if (io[i].name == semantic && (io[i].sid - last_sid == 1)) {
+         io[i].glsl_predefined_no_emit = true;
+         last_sid = io[i].sid;
+         io[i].array_offset = io[i].sid - io_out_range->sid;
+         io_out_range->last = io_out_range->first + io[i].array_offset;
+         io[i].overlapping_array = io_out_range;
+      } else {
+         break;
+      }
+   }
+   return io_out_range->last + 1;
+}
+
+static bool
+collapse_vars_to_arrays(struct vrend_shader_io *io,
+                           int num_entries,
+                           enum tgsi_semantic semantic)
+{
+
+   bool retval = 0;
+   int start_index = 0;
+   while (start_index < num_entries) {
+      if (io[start_index].name == semantic && !io[start_index].glsl_predefined_no_emit) {
+         int new_start_index = make_array_from_semantic(io, start_index, num_entries, semantic);
+         retval |= io[start_index].first != io[start_index].last;
+         start_index = new_start_index;
+      } else {
+         ++start_index;
+      }
+   }
+
+   io->num_components = 4;
+   io->usage_mask = 0xf;
+   return retval;
+}
+
+static void
+rewrite_io_ranged(struct dump_ctx *ctx)
 {
    if ((ctx->info.indirect_files & (1 << TGSI_FILE_INPUT)) ||
-       ctx->key->input.num_indirect_generic ||
-       ctx->key->input.num_indirect_patch) {
+       ctx->key->require_input_arrays) {
 
-      for (uint i = 0; i < ctx->num_inputs; ++i) {
-         if (ctx->inputs[i].name == TGSI_SEMANTIC_PATCH) {
-            ctx->inputs[i].glsl_predefined_no_emit = true;
-            if (ctx->inputs[i].sid < ctx->patch_ios.input_range.io.sid || ctx->patch_ios.input_range.used == false) {
-               ctx->patch_ios.input_range.io.sid = ctx->inputs[i].sid;
-               ctx->patch_ios.input_range.io.first = i;
-               ctx->patch_ios.input_range.io.name = TGSI_SEMANTIC_PATCH;
-               ctx->patch_ios.input_range.used = true;
-               if (ctx->cfg->has_arrays_of_arrays && !ctx->cfg->use_gles)
-                  ctx->shader_req_bits |= SHADER_REQ_ARRAYS_OF_ARRAYS;
-            }
-            if (i > ctx->patch_ios.input_range.io.last)
-               ctx->patch_ios.input_range.io.last = i;
-         }
+      bool generic_array = collapse_vars_to_arrays(ctx->inputs, ctx->num_inputs,
+                                                  TGSI_SEMANTIC_GENERIC);
+      bool patch_array = collapse_vars_to_arrays(ctx->inputs, ctx->num_inputs,
+                                                 TGSI_SEMANTIC_PATCH);
 
-         if (ctx->inputs[i].name == TGSI_SEMANTIC_GENERIC) {
-            ctx->inputs[i].glsl_predefined_no_emit = true;
-            if (ctx->inputs[i].sid < ctx->generic_ios.input_range.io.sid || ctx->generic_ios.input_range.used == false) {
-               ctx->generic_ios.input_range.io.sid = ctx->inputs[i].sid;
-               ctx->generic_ios.input_range.io.first = i;
-               ctx->generic_ios.input_range.io.name = TGSI_SEMANTIC_GENERIC;
-               ctx->generic_ios.input_range.used = true;
-               if (ctx->cfg->has_arrays_of_arrays && !ctx->cfg->use_gles)
-                  ctx->shader_req_bits |= SHADER_REQ_ARRAYS_OF_ARRAYS;
-            }
-            if (i > ctx->generic_ios.input_range.io.last)
-               ctx->generic_ios.input_range.io.last = i;
-         }
-      }
-
-      if (ctx->key->input.num_indirect_generic > 0)
-         ctx->generic_ios.input_range.io.last = ctx->generic_ios.input_range.io.first +
-            ctx->key->input.num_indirect_generic - 1;
-
-      if (ctx->key->input.num_indirect_patch > 0)
-         ctx->patch_ios.input_range.io.last = ctx->patch_ios.input_range.io.first +
-            ctx->key->input.num_indirect_patch - 1;
-
-      snprintf(ctx->patch_ios.input_range.io.glsl_name, 64, "%s_p%d",
-               get_stage_input_name_prefix(ctx, ctx->prog_type), ctx->patch_ios.input_range.io.sid);
-      snprintf(ctx->generic_ios.input_range.io.glsl_name, 64, "%s_g%d",
-               get_stage_input_name_prefix(ctx, ctx->prog_type), ctx->generic_ios.input_range.io.sid);
-
-      ctx->generic_ios.input_range.io.num_components = 4;
-      ctx->generic_ios.input_range.io.usage_mask = 0xf;
-
-      ctx->patch_ios.input_range.io.num_components = 4;
-      ctx->patch_ios.input_range.io.usage_mask = 0xf;
+      ctx->has_input_arrays = generic_array || patch_array;
 
       if (prefer_generic_io_block(ctx, io_in))
-          ctx->glsl_ver_required = require_glsl_ver(ctx, 150);
+         ctx->glsl_ver_required = require_glsl_ver(ctx, 150);
    }
 
    if ((ctx->info.indirect_files & (1 << TGSI_FILE_OUTPUT)) ||
-       ctx->key->output.num_indirect_generic ||
-       ctx->key->output.num_indirect_patch) {
+       ctx->key->require_output_arrays) {
 
-      for (uint i = 0; i < ctx->num_outputs; ++i) {
-         if (ctx->outputs[i].name == TGSI_SEMANTIC_PATCH) {
-            ctx->outputs[i].glsl_predefined_no_emit = true;
-            if (ctx->outputs[i].sid < ctx->patch_ios.output_range.io.sid || ctx->patch_ios.output_range.used == false) {
-               ctx->patch_ios.output_range.io.sid = ctx->outputs[i].sid;
-               ctx->patch_ios.output_range.io.first = i;
-               ctx->patch_ios.output_range.io.name = TGSI_SEMANTIC_PATCH;
-               ctx->patch_ios.output_range.used = true;
-               if (ctx->cfg->has_arrays_of_arrays && !ctx->cfg->use_gles)
-                  ctx->shader_req_bits |= SHADER_REQ_ARRAYS_OF_ARRAYS;
-            }
-            if (i > ctx->patch_ios.output_range.io.last) {
-               ctx->patch_ios.output_range.io.last = i;
-            }
-         }
+      bool generic_array = collapse_vars_to_arrays(ctx->outputs, ctx->num_outputs,
+                                                  TGSI_SEMANTIC_GENERIC);
+      bool patch_array = collapse_vars_to_arrays(ctx->outputs, ctx->num_outputs,
+                                                TGSI_SEMANTIC_PATCH);
 
-         if (ctx->outputs[i].name == TGSI_SEMANTIC_GENERIC) {
-            ctx->outputs[i].glsl_predefined_no_emit = true;
-            if (ctx->outputs[i].sid < ctx->generic_ios.output_range.io.sid || ctx->generic_ios.output_range.used == false) {
-               ctx->generic_ios.output_range.io.sid = ctx->outputs[i].sid;
-               ctx->generic_ios.output_range.io.first = i;
-               ctx->generic_ios.output_range.io.name = TGSI_SEMANTIC_GENERIC;
-               ctx->generic_ios.output_range.used = true;
-               if (ctx->cfg->has_arrays_of_arrays && !ctx->cfg->use_gles)
-                  ctx->shader_req_bits |= SHADER_REQ_ARRAYS_OF_ARRAYS;
-            }
-            if (i > ctx->generic_ios.output_range.io.last) {
-               ctx->generic_ios.output_range.io.last = i;
-            }
-         }
-      }
-
-      if (ctx->key->output.num_indirect_generic > 0)
-         ctx->generic_ios.output_range.io.last = ctx->generic_ios.output_range.io.first +
-            ctx->key->output.num_indirect_generic - 1;
-
-      if (ctx->key->output.num_indirect_patch > 0)
-         ctx->patch_ios.output_range.io.last = ctx->patch_ios.output_range.io.first +
-            ctx->key->output.num_indirect_patch - 1;
-
-      snprintf(ctx->patch_ios.output_range.io.glsl_name, 64, "%s_p%d",
-               get_stage_output_name_prefix(ctx->prog_type), ctx->patch_ios.output_range.io.sid);
-      snprintf(ctx->generic_ios.output_range.io.glsl_name, 64, "%s_g%d",
-               get_stage_output_name_prefix(ctx->prog_type), ctx->generic_ios.output_range.io.sid);
-
-      ctx->generic_ios.output_range.io.num_components = 4;
-      ctx->generic_ios.output_range.io.usage_mask = 0xf;
-
-      ctx->patch_ios.output_range.io.num_components = 4;
-      ctx->patch_ios.output_range.io.usage_mask = 0xf;
+      ctx->has_output_arrays = generic_array || patch_array;
 
       if (prefer_generic_io_block(ctx, io_out))
-          ctx->glsl_ver_required = require_glsl_ver(ctx, 150);
-   }
-}
-
-
-static void rename_variables(unsigned nio, struct vrend_shader_io *io,
-                             const char *name_prefix, unsigned coord_replace)
-{
-   /* Rename the generic and patch variables after applying all identifications */
-   for (unsigned i = 0; i < nio; ++i) {
-      if ((io[i].name != TGSI_SEMANTIC_GENERIC &&
-          io[i].name != TGSI_SEMANTIC_PATCH) ||
-          (coord_replace & (1 << io[i].sid)))
-         continue;
-      char io_type =  io[i].name == TGSI_SEMANTIC_GENERIC ? 'g' : 'p';
-      snprintf(io[i].glsl_name, 64, "%s_%c%d", name_prefix, io_type, io[i].sid);
-   }
-}
-
-static
-void rewrite_components(unsigned nio, struct vrend_shader_io *io,
-                        const char *name_prefix, unsigned coord_replace,
-                        bool no_input_arrays)
-{
-   if (!nio)
-      return;
-
-   for (unsigned i = 0; i < nio - 1; ++i) {
-      if ((io[i].name != TGSI_SEMANTIC_GENERIC &&
-           io[i].name != TGSI_SEMANTIC_PATCH) ||
-          io[i].glsl_predefined_no_emit)
-         continue;
-
-      for (unsigned j = i + 1; j < nio;  ++j) {
-         if ((io[j].name != TGSI_SEMANTIC_GENERIC &&
-              io[j].name != TGSI_SEMANTIC_PATCH) ||
-             io[j].glsl_predefined_no_emit)
-            continue;
-         if (io[i].first == io[j].first)
-            io[j].glsl_predefined_no_emit = true;
-      }
+         ctx->glsl_ver_required = require_glsl_ver(ctx, 150);
    }
 
-   for (unsigned i = 0; i < nio; ++i) {
-      if ((io[i].name != TGSI_SEMANTIC_GENERIC &&
-           io[i].name != TGSI_SEMANTIC_PATCH) ||
-          !no_input_arrays)
-         continue;
+   if ((ctx->has_output_arrays || ctx->has_input_arrays)
+       && ctx->cfg->has_arrays_of_arrays && !ctx->cfg->use_gles)
+      ctx->shader_req_bits |= SHADER_REQ_ARRAYS_OF_ARRAYS;
 
-      io[i].usage_mask = 0xf;
-      io[i].num_components = 4;
-      io[i].override_no_wm = false;
-   }
-
-   rename_variables(nio, io, name_prefix, coord_replace);
 }
 
 static
@@ -5135,14 +5211,112 @@
       /* The guest didn't send real arrays, do we might have to add a big array
        * for all generic and another for patch inputs */
       rewrite_io_ranged(ctx);
-      rewrite_components(ctx->num_inputs, ctx->inputs,
-                         get_stage_input_name_prefix(ctx, ctx->prog_type),
-                         ctx->key->fs.coord_replace, true);
-      rewrite_components(ctx->num_outputs, ctx->outputs,
-                         get_stage_output_name_prefix(ctx->prog_type), 0, true);
    }
 }
 
+static int
+compare_shader_io(const void *vlhs, const void *vrhs)
+{
+   struct vrend_shader_io *lhs = (struct vrend_shader_io *)vlhs;
+   struct vrend_shader_io *rhs = (struct vrend_shader_io *)vrhs;
+
+   if (lhs->name < rhs->name)
+      return -1;
+   if (lhs->name > rhs->name)
+      return 1;
+   return lhs->sid - rhs->sid;
+}
+
+static void
+add_missing_semantic_inputs(struct vrend_shader_io *inputs, int *num_inputs,
+                            int *next_location, uint64_t sids_missing,
+                            const char *prefix, char *type_prefix,
+                            enum tgsi_semantic name,
+                            const struct vrend_shader_key *key)
+{
+
+   while (sids_missing) {
+      int sid = u_bit_scan64(&sids_missing);
+      struct vrend_shader_io *io = &inputs[*num_inputs];
+      io->sid = sid;
+      io->last = io->first = *next_location;
+      io->name = name;
+      io->type = VEC_FLOAT;
+      uint32_t sids_added = 1 << sid;
+
+
+      for (uint32_t j = 0; j < key->in_arrays.num_arrays; j++) {
+         const struct vrend_shader_io_array *array = &key->in_arrays.layout[j];
+         if (array->name == name &&
+             array->sid <= sid &&
+             array->sid + array->size >= sid) {
+            io->last = io->first + array->size;
+            io->sid = array->sid;
+            sids_added = ((1u << array->size) - 1) << sid;
+            break;
+         }
+      }
+
+      (*next_location) += io->last - io->first + 1;
+
+      sids_missing &= ~sids_added;
+
+      snprintf(io->glsl_name, 128, "%s%s%d", prefix, type_prefix, sid);
+      (*num_inputs)++;
+   }
+}
+
+static int
+add_missing_inputs(const struct dump_ctx *ctx, struct vrend_shader_io *inputs,
+                   int num_inputs)
+{
+   uint64_t generics_declared = 0;
+   uint64_t patches_declared = 0;
+   uint8_t texcoord_declared = 0;
+
+   int next_location = 0;
+   for (int i = 0; i < num_inputs; ++i) {
+      int offset = 0;
+      for (int k = inputs[i].first; k <= inputs[i].last; ++k, ++offset) {
+         int sid = inputs[i].sid + offset;
+         switch (inputs[i].name) {
+         case TGSI_SEMANTIC_GENERIC:
+            generics_declared |= 1ull << sid;
+            break;
+         case TGSI_SEMANTIC_PATCH:
+            patches_declared |= 1ull << sid;
+            break;
+         case TGSI_SEMANTIC_TEXCOORD:
+            texcoord_declared |= 1ull << sid;
+            break;
+         default:
+            ;
+         }
+      }
+      if (next_location < inputs[i].last)
+         next_location = inputs[i].last;
+   }
+   ++next_location;
+
+   uint64_t generics_missing = ctx->key->in_generic_expected_mask & ~generics_declared;
+   uint64_t patches_missing = ctx->key->in_patch_expected_mask & ~patches_declared;
+   uint64_t texcoord_missing = ctx->key->in_texcoord_expected_mask & ~texcoord_declared;
+
+   const char *prefix = get_stage_input_name_prefix(ctx, ctx->prog_type);
+   add_missing_semantic_inputs(inputs, &num_inputs, &next_location,
+                               generics_missing, prefix, "_g",
+                               TGSI_SEMANTIC_GENERIC, ctx->key);
+   add_missing_semantic_inputs(inputs, &num_inputs, &next_location,
+                               texcoord_missing, prefix, "_t",
+                               TGSI_SEMANTIC_TEXCOORD, ctx->key);
+   add_missing_semantic_inputs(inputs, &num_inputs, &next_location,
+                               patches_missing, "patch", "",
+                               TGSI_SEMANTIC_PATCH, ctx->key);
+
+   qsort(inputs, num_inputs, sizeof(struct vrend_shader_io),
+         compare_shader_io);
+   return num_inputs;
+}
 
 static boolean
 iter_instruction(struct tgsi_iterate_context *iter,
@@ -5164,6 +5338,8 @@
       ctx->prog_type = iter->processor.Processor;
 
    if (instno == 0) {
+      if (ctx->prog_type != TGSI_PROCESSOR_VERTEX)
+         ctx->num_inputs = add_missing_inputs(ctx, ctx->inputs, ctx->num_inputs);
       handle_io_arrays(ctx);
 
       /* Vertex shader inputs are not send as arrays, but the access may still be
@@ -5361,7 +5537,8 @@
       emit_arit_op2("+");
       break;
    case TGSI_OPCODE_UADD:
-      emit_buff(&ctx->glsl_strbufs, "%s = %s(%s(ivec4((uvec4(%s) + uvec4(%s))))%s);\n", dsts[0], get_string(dinfo.dstconv), get_string(dinfo.dtypeprefix), srcs[0], srcs[1], writemask);
+      emit_buff(&ctx->glsl_strbufs, "%s = %s(%s(uvec4(%s) + uvec4(%s))%s);\n", dsts[0],
+            get_string(dinfo.dstconv), get_string(dinfo.dtypeprefix), srcs[0], srcs[1], writemask);
       break;
    case TGSI_OPCODE_SUB:
       emit_arit_op2("-");
@@ -5422,9 +5599,11 @@
    case TGSI_OPCODE_TXF:
    case TGSI_OPCODE_TG4:
    case TGSI_OPCODE_TXP:
-   case TGSI_OPCODE_LODQ:
       translate_tex(ctx, inst, &sinfo, &dinfo, srcs, dsts[0], writemask);
       break;
+   case TGSI_OPCODE_LODQ:
+      emit_lodq(ctx, inst, &sinfo, &dinfo, srcs, dsts[0], writemask);
+      break;
    case TGSI_OPCODE_TXQ:
       emit_txq(ctx, inst, sinfo.sreg_index, srcs, dsts[0], writemask);
       break;
@@ -5483,6 +5662,12 @@
    case TGSI_OPCODE_SLT:
       emit_compare("lessThan");
       break;
+   case TGSI_OPCODE_SLE:
+      emit_compare("lessThanEqual");
+      break;
+   case TGSI_OPCODE_SGT:
+      emit_compare("greaterThan");
+      break;
    case TGSI_OPCODE_ISLT:
    case TGSI_OPCODE_USLT:
    case TGSI_OPCODE_FSLT:
@@ -5693,8 +5878,10 @@
             return false;
          srcs[1] = ctx->src_bufs[1].buf;
       }
-      translate_store(ctx, &ctx->glsl_strbufs, ctx->ssbo_memory_qualifier,
-                      inst, &sinfo, srcs, dsts[0]);
+      /* Don't try to write to dest with a negative index. */
+      if (dinfo.dest_index >= 0)
+         translate_store(ctx, &ctx->glsl_strbufs, ctx->ssbo_memory_qualifier, ctx->images,
+                         inst, &sinfo, srcs, &dinfo, dsts[0]);
       break;
    case TGSI_OPCODE_LOAD:
       if (ctx->cfg->use_gles) {
@@ -5702,8 +5889,12 @@
             return false;
          srcs[1] = ctx->src_bufs[1].buf;
       }
-      translate_load(ctx, &ctx->glsl_strbufs, ctx->ssbo_memory_qualifier, ctx->images,
-                     inst, &sinfo, &dinfo, srcs, dsts[0], writemask);
+      /* Replace an obvious out-of-bounds load with loading zero. */
+      if (sinfo.sreg_index < 0 ||
+          !translate_load(ctx, &ctx->glsl_strbufs, ctx->ssbo_memory_qualifier, ctx->images,
+                          inst, &sinfo, &dinfo, srcs, dsts[0], writemask)) {
+         emit_buff(&ctx->glsl_strbufs, "%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n", dsts[0], writemask);
+      }
       break;
    case TGSI_OPCODE_ATOMUADD:
    case TGSI_OPCODE_ATOMXCHG:
@@ -5807,6 +5998,9 @@
       if (ctx->shader_req_bits & SHADER_REQ_NV_IMAGE_FORMATS)
          emit_ext(glsl_strbufs, "NV_image_formats", "require");
 
+      if (ctx->shader_req_bits & SHADER_REQ_SEPERATE_SHADER_OBJECTS)
+         emit_ext(glsl_strbufs, "EXT_separate_shader_objects", "require");
+
       if ((ctx->prog_type == TGSI_PROCESSOR_TESS_CTRL ||
            ctx->prog_type == TGSI_PROCESSOR_TESS_EVAL)) {
          if (ctx->cfg->glsl_version < 320)
@@ -5846,9 +6040,15 @@
 
       }
 
+      if (ctx->shader_req_bits & SHADER_REQ_TEXTURE_SHADOW_LOD)
+         emit_ext(glsl_strbufs, "EXT_texture_shadow_lod", "require");
+
       if (ctx->shader_req_bits & SHADER_REQ_LODQ)
          emit_ext(glsl_strbufs, "EXT_texture_query_lod", "require");
 
+      if (ctx->shader_req_bits & SHADER_REQ_SHADER_NOPERSPECTIVE_INTERPOLATION)
+         emit_ext(glsl_strbufs, "NV_shader_noperspective_interpolation", "require");
+
       emit_hdr(glsl_strbufs, "precision highp float;\n");
       emit_hdr(glsl_strbufs, "precision highp int;\n");
    } else {
@@ -5875,6 +6075,9 @@
       if (ctx->shader_req_bits & SHADER_REQ_SEPERATE_SHADER_OBJECTS)
          emit_ext(glsl_strbufs, "ARB_separate_shader_objects", "require");
 
+      if (ctx->shader_req_bits & SHADER_REQ_EXPLICIT_ATTRIB_LOCATION)
+         emit_ext(glsl_strbufs, "ARB_explicit_attrib_location", "require");
+
       if (ctx->shader_req_bits & SHADER_REQ_ARRAYS_OF_ARRAYS)
          emit_ext(glsl_strbufs, "ARB_arrays_of_arrays", "require");
 
@@ -5967,7 +6170,7 @@
 {
    switch (interpolate) {
    case TGSI_INTERPOLATE_LINEAR:
-      if (!cfg->use_gles)
+      if (cfg->has_nopersective)
          return "noperspective ";
       else
          return "";
@@ -6166,6 +6369,7 @@
    const char *sname, *stc, *formatstr;
    enum tgsi_return_type itype;
    const char *volatile_str = image->vflag ? "volatile " : "";
+   const char *coherent_str = image->coherent ? "coherent " : "";
    const char *precision = ctx->cfg->use_gles ? "highp " : "";
    const char *access = "";
    formatstr = get_internalformat_string(image->decl.Format, &itype);
@@ -6202,11 +6406,11 @@
    }
 
    if (range)
-      emit_hdrf(glsl_strbufs, "%s%suniform %s%cimage%s %simg%d[%d];\n",
-               access, volatile_str, precision, ptc, stc, sname, i, range);
+      emit_hdrf(glsl_strbufs, "%s%s%suniform %s%cimage%s %simg%d[%d];\n",
+               access, volatile_str, coherent_str, precision, ptc, stc, sname, i, range);
    else
-      emit_hdrf(glsl_strbufs, "%s%suniform %s%cimage%s %simg%d;\n",
-               access, volatile_str, precision, ptc, stc, sname, i);
+      emit_hdrf(glsl_strbufs, "%s%s%suniform %s%cimage%s %simg%d;\n",
+               access, volatile_str, coherent_str, precision, ptc, stc, sname, i);
 }
 
 static int emit_ios_common(const struct dump_ctx *ctx,
@@ -6227,6 +6431,9 @@
       }
    }
 
+   if (ctx->require_dummy_value)
+      emit_hdr(glsl_strbufs, "vec4 dummy_value = vec4(0.0, 0.0, 0.0, 0.0);\n");
+
    if (ctx->write_mul_utemp) {
       emit_hdr(glsl_strbufs, "uvec4 mul_utemp;\n");
       emit_hdr(glsl_strbufs, "uvec4 umul_temp;\n");
@@ -6408,11 +6615,6 @@
          snprintf(array_handle, sizeof(array_handle), "[%d]", size);
 
       assert(size < 256 && size >= 0);
-      if (size < ctx->key->input.num_indirect_generic) {
-         VREND_DEBUG(dbg_shader, NULL, "WARNING: shader key indicates less indirect inputs"
-                                       " (%d) then are actually used (%d)\n",
-                     ctx->key->input.num_indirect_generic, size);
-      }
 
       if (prefer_generic_io_block(ctx, io_in)) {
 
@@ -6444,26 +6646,26 @@
                  const struct vrend_shader_io *io, const char *inout,
                  const char *postfix)
 {
-   const char *atype[3][4] =  {
-      {"float", " vec2", " vec3", " vec4"},
-      {"  int", "ivec2", "ivec3", "ivec4"},
-      {" uint", "uvec2", "uvec3", "uvec4"},
+   const char *atype[3] =  {
+      " vec4", "ivec4", "uvec4"
    };
-   const char **type = atype[io->type];
-   const char *t = type[3];
+
+   const char *t = atype[io->type];
 
    char layout[128] = "";
 
    if (io->overlapping_array)
       return;
 
-   if (io->usage_mask != 0xf && io->name == TGSI_SEMANTIC_GENERIC)
-      t = type[io->num_components - 1];
+   if (ctx->separable_program && io->name == TGSI_SEMANTIC_GENERIC &&
+       !(ctx->prog_type == TGSI_PROCESSOR_FRAGMENT && strcmp(inout, "in") != 0)) {
+      snprintf(layout, sizeof(layout), "layout(location = %d) ", 31 - io->sid);
+   }
 
    if (io->first == io->last) {
       emit_hdr(glsl_strbufs, layout);
       /* ugly leave spaces to patch interp in later */
-      emit_hdrf(glsl_strbufs, "%s%s\n%s  %s %s %s%s;\n",
+      emit_hdrf(glsl_strbufs, "%s%s %s  %s %s %s%s;\n",
                 io->precise ? "precise" : "",
                 io->invariant ? "invariant" : "",
                 prefix,
@@ -6489,6 +6691,7 @@
       }
 
    } else {
+      int array_size = io->last - io->first + 1;
       if (prefer_generic_io_block(ctx, iot)) {
          const char *stage_prefix = iot == io_in ? get_stage_input_name_prefix(ctx, ctx->prog_type):
                                                    get_stage_output_name_prefix(ctx->prog_type);
@@ -6507,7 +6710,7 @@
                    prefix,
                    t,
                    io->glsl_name,
-                   io->last - io->first +1,
+                   array_size,
                    blockvarame);
       } else {
          emit_hdr(glsl_strbufs, layout);
@@ -6519,8 +6722,24 @@
                    t,
                    io->glsl_name,
                    postfix,
-                   io->last - io->first +1);
+                   array_size);
 
+         uint64_t mask = ((1ull << array_size) - 1) << io->sid;
+         if (io->name == TGSI_SEMANTIC_GENERIC) {
+            assert(io->sid + array_size < 64);
+            if (iot == io_in) {
+               generic_ios->match.inputs_emitted_mask |= mask;
+            } else {
+               generic_ios->match.outputs_emitted_mask |= mask;
+            }
+         } else if (io->name == TGSI_SEMANTIC_TEXCOORD) {
+            assert(io->sid + array_size < 8);
+            if (iot == io_in) {
+               texcoord_ios->match.inputs_emitted_mask |= mask;
+            } else {
+               texcoord_ios->match.outputs_emitted_mask |= mask;
+            }
+         }
       }
    }
 }
@@ -6625,22 +6844,28 @@
       *force_color_two_side = 1;
 }
 
-static void
+static uint64_t
 emit_ios_patch(struct vrend_glsl_strbufs *glsl_strbufs,
                const char *prefix, const struct vrend_shader_io *io,
-               const char *inout, int size)
+               const char *inout, int size, bool emit_location)
 {
-   const char type[4][6] = {"float", " vec2", " vec3", " vec4"};
-   const char *t = " vec4";
+   uint64_t emitted_patches = 0;
 
-   if (io->usage_mask != 0xf)
-      t = type[io->num_components - 1];
+   /* We start these locations from 32 and proceed downwards, to avoid
+    * conflicting with generic IO locations. */
+   if (emit_location)
+      emit_hdrf(glsl_strbufs, "layout(location = %d) ", io->sid);
 
-   if (io->last == io->first)
-      emit_hdrf(glsl_strbufs, "%s %s %s %s;\n", prefix, inout, t, io->glsl_name);
-   else
-      emit_hdrf(glsl_strbufs, "%s %s %s %s[%d];\n", prefix, inout, t,
+   if (io->last == io->first) {
+      emit_hdrf(glsl_strbufs, "%s %s vec4 %s;\n", prefix, inout, io->glsl_name);
+      emitted_patches |= 1ul << io->sid;
+   } else {
+      emit_hdrf(glsl_strbufs, "%s %s vec4 %s[%d];\n", prefix, inout,
                 io->glsl_name, size);
+      uint64_t mask = (1ul << size) - 1;
+      emitted_patches |= mask << io->sid;
+   }
+   return emitted_patches;
 }
 
 static bool
@@ -6751,7 +6976,7 @@
 
    const char *psize_buf = ctx->has_pointsize_output ? "out float gl_PointSize;\n" : "";
 
-   if (!ctx->is_last_vertex_stage && ctx->key->output.use_pervertex) {
+   if (!ctx->is_last_vertex_stage && ctx->key->use_pervertex_in) {
       emit_hdrf(glsl_strbufs, "out gl_PerVertex {\n vec4 gl_Position;\n %s%s%s};\n", clip_buf, cull_buf, psize_buf);
    }
 }
@@ -6780,14 +7005,14 @@
    uint32_t i;
 
    if (fs_emit_layout(ctx)) {
-      bool upper_left = !(ctx->fs_coord_origin ^ ctx->key->fs.invert_origin);
-      char comma = (upper_left && ctx->fs_pixel_center) ? ',' : ' ';
+      bool upper_left = ctx->fs_lower_left_origin == ctx->key->fs.lower_left_origin;
+      char comma = (upper_left && ctx->fs_integer_pixel_center) ? ',' : ' ';
 
       if (!ctx->cfg->use_gles)
          emit_hdrf(glsl_strbufs, "layout(%s%c%s) in vec4 gl_FragCoord;\n",
                    upper_left ? "origin_upper_left" : "",
                    comma,
-                   ctx->fs_pixel_center ? "pixel_center_integer" : "");
+                   ctx->fs_integer_pixel_center ? "pixel_center_integer" : "");
    }
    if (ctx->early_depth_stencil) {
       emit_hdr(glsl_strbufs, "layout(early_fragment_tests) in;\n");
@@ -6959,7 +7184,7 @@
    if (ctx->num_out_clip_dist && !num_clip_cull)
       clip_dist = ctx->num_out_clip_dist;
 
-   if (ctx->key->output.use_pervertex) {
+   if (ctx->key->use_pervertex_in) {
       char clip_var[64] = "", cull_var[64] = "";
       if (cull_dist)
          snprintf(cull_var, 64, "float gl_CullDistance[%d];\n", cull_dist);
@@ -7063,6 +7288,7 @@
                          struct vrend_glsl_strbufs *glsl_strbufs,
                          struct vrend_generic_ios *generic_ios,
                          struct vrend_texcoord_ios *texcoord_ios,
+                         uint64_t *emitted_out_patches_mask,
                          bool *has_pervertex)
 {
    uint32_t i;
@@ -7071,26 +7297,31 @@
 
    for (i = 0; i < ctx->num_inputs; i++) {
       if (!ctx->inputs[i].glsl_predefined_no_emit) {
-         if (ctx->inputs[i].name == TGSI_SEMANTIC_PATCH)
-            emit_ios_patch(glsl_strbufs, "",  &ctx->inputs[i], "in", ctx->inputs[i].last - ctx->inputs[i].first + 1);
-         else
+         if (ctx->inputs[i].name == TGSI_SEMANTIC_PATCH) {
+            emit_ios_patch(glsl_strbufs, "",  &ctx->inputs[i], "in",
+                           ctx->inputs[i].last - ctx->inputs[i].first + 1,
+                           ctx->separable_program);
+         } else
             emit_ios_generic(ctx, glsl_strbufs, generic_ios, texcoord_ios, io_in, "", &ctx->inputs[i], "in", "[]");
       }
    }
 
+   uint64_t emitted_patches = 0;
+
    emit_hdrf(glsl_strbufs, "layout(vertices = %d) out;\n", ctx->tcs_vertices_out);
 
-   emit_ios_indirect_generics_output(ctx, glsl_strbufs, "[]");
-
    if (ctx->patch_ios.output_range.used)
-      emit_ios_patch(glsl_strbufs, "patch", &ctx->patch_ios.output_range.io, "out",
-                     ctx->patch_ios.output_range.io.last - ctx->patch_ios.output_range.io.first + 1);
+      emitted_patches |= emit_ios_patch(glsl_strbufs, "patch", &ctx->patch_ios.output_range.io, "out",
+                                        ctx->patch_ios.output_range.io.last - ctx->patch_ios.output_range.io.first + 1,
+                                        ctx->separable_program);
 
    for (i = 0; i < ctx->num_outputs; i++) {
       if (!ctx->outputs[i].glsl_predefined_no_emit) {
          if (ctx->outputs[i].name == TGSI_SEMANTIC_PATCH) {
-            emit_ios_patch(glsl_strbufs, "patch", &ctx->outputs[i], "out",
-                           ctx->outputs[i].last - ctx->outputs[i].first + 1);
+
+            emitted_patches |= emit_ios_patch(glsl_strbufs, "patch", &ctx->outputs[i], "out",
+                                              ctx->outputs[i].last - ctx->outputs[i].first + 1,
+                                              ctx->separable_program);
          } else
             emit_ios_generic(ctx, glsl_strbufs, generic_ios, texcoord_ios, io_out, "", &ctx->outputs[i], "out", "[]");
       } else if (ctx->outputs[i].invariant || ctx->outputs[i].precise) {
@@ -7103,6 +7334,8 @@
 
    emit_ios_per_vertex_in(ctx, glsl_strbufs, has_pervertex);
    emit_ios_per_vertex_out(ctx, glsl_strbufs, " gl_out[]");
+
+   *emitted_out_patches_mask = emitted_patches;
 }
 
 static void emit_ios_tes(const struct dump_ctx *ctx,
@@ -7118,7 +7351,9 @@
 
    if (ctx->patch_ios.input_range.used)
       emit_ios_patch(glsl_strbufs, "patch", &ctx->patch_ios.input_range.io, "in",
-                     ctx->patch_ios.input_range.io.last - ctx->patch_ios.input_range.io.first + 1);
+                     ctx->patch_ios.input_range.io.last -
+                        ctx->patch_ios.input_range.io.first + 1,
+                     ctx->separable_program);
 
    if (generic_ios->input_range.used)
       emit_ios_indirect_generics_input(ctx, glsl_strbufs, "[]");
@@ -7127,7 +7362,8 @@
       if (!ctx->inputs[i].glsl_predefined_no_emit) {
          if (ctx->inputs[i].name == TGSI_SEMANTIC_PATCH)
             emit_ios_patch(glsl_strbufs, "patch", &ctx->inputs[i], "in",
-                           ctx->inputs[i].last - ctx->inputs[i].first + 1);
+                           ctx->inputs[i].last - ctx->inputs[i].first + 1,
+                           ctx->separable_program);
          else
             emit_ios_generic(ctx, glsl_strbufs, generic_ios, texcoord_ios, io_in, "", &ctx->inputs[i], "in", "[]");
       }
@@ -7200,17 +7436,22 @@
       int i = u_bit_scan64(&mask);
       emit_interp_info(glsl_strbufs, ctx->cfg, &ctx->key->fs_info,
                        semantic->name, i, ctx->key->flatshade);
+
+      if (semantic->name == TGSI_SEMANTIC_GENERIC && ctx->separable_program)
+          emit_hdrf(glsl_strbufs, "layout(location=%d) ", i);
+
       emit_hdrf(glsl_strbufs, "out vec4 %s_%c%d%s;\n",
                 get_stage_output_name_prefix(ctx->prog_type),
                 semantic->prefix, i,
                 ctx->prog_type == TGSI_PROCESSOR_TESS_CTRL ? "[]" : "");
-         }
+   }
 }
 
 static int emit_ios(const struct dump_ctx *ctx,
                     struct vrend_glsl_strbufs *glsl_strbufs,
                     struct vrend_generic_ios *generic_ios,
                     struct vrend_texcoord_ios *texcoord_ios,
+                    uint64_t *patches_emitted_mask,
                     uint8_t front_back_color_emitted_flags[],
                     uint32_t *num_interps,
                     bool *has_pervertex,
@@ -7237,7 +7478,7 @@
       emit_ios_geom(ctx, glsl_strbufs, generic_ios, texcoord_ios, front_back_color_emitted_flags, num_interps, has_pervertex, force_color_two_side);
       break;
    case TGSI_PROCESSOR_TESS_CTRL:
-      emit_ios_tcs(ctx, glsl_strbufs, generic_ios, texcoord_ios, has_pervertex);
+      emit_ios_tcs(ctx, glsl_strbufs, generic_ios, texcoord_ios, patches_emitted_mask, has_pervertex);
       break;
    case TGSI_PROCESSOR_TESS_EVAL:
       emit_ios_tes(ctx, glsl_strbufs, generic_ios, texcoord_ios, front_back_color_emitted_flags, num_interps, has_pervertex, force_color_two_side);
@@ -7261,8 +7502,8 @@
    glsl_ver_required = emit_ios_common(ctx, glsl_strbufs, shadow_samp_mask);
 
    if (ctx->prog_type == TGSI_PROCESSOR_FRAGMENT &&
-       ctx->key->pstipple_tex == true) {
-      emit_hdr(glsl_strbufs, "float stip_temp;\n");
+       ctx->key->pstipple_enabled) {
+      emit_hdr(glsl_strbufs, "uint stip_temp;\n");
    }
 
    return glsl_ver_required;
@@ -7339,6 +7580,7 @@
 {
    sinfo->num_ucp = ctx->is_last_vertex_stage ? VIRGL_NUM_CLIP_PLANES : 0;
    sinfo->fs_info.has_sample_input = ctx->has_sample_input;
+   sinfo->fs_info.has_noperspective = ctx->has_noperspective;
    sinfo->fs_info.num_interps = ctx->num_interps;
    sinfo->fs_info.glsl_ver = ctx->glsl_ver_required;
    bool has_prop = (ctx->num_clip_dist_prop + ctx->num_cull_dist_prop) > 0;
@@ -7352,7 +7594,7 @@
 
 static void fill_sinfo(const struct dump_ctx *ctx, struct vrend_shader_info *sinfo)
 {
-   sinfo->in.use_pervertex = ctx->has_pervertex;
+   sinfo->use_pervertex_in = ctx->has_pervertex;
    sinfo->samplers_used_mask = ctx->samplers_used;
    sinfo->images_used_mask = ctx->images_used_mask;
    sinfo->num_consts = ctx->num_consts;
@@ -7364,19 +7606,12 @@
 
    sinfo->ubo_indirect = !!(ctx->info.dimension_indirect_files & (1 << TGSI_FILE_CONSTANT));
 
-   if (ctx->generic_ios.input_range.used)
-      sinfo->in.num_indirect_generic = ctx->generic_ios.input_range.io.last -
-         ctx->generic_ios.input_range.io.first + 1;
-   if (ctx->patch_ios.input_range.used)
-      sinfo->in.num_indirect_patch = ctx->patch_ios.input_range.io.last -
-         ctx->patch_ios.input_range.io.first + 1;
+   sinfo->has_output_arrays = ctx->has_output_arrays;
+   sinfo->has_input_arrays = ctx->has_input_arrays;
 
-   if (ctx->generic_ios.output_range.used)
-      sinfo->out.num_indirect_generic = ctx->generic_ios.output_range.io.last -
-         ctx->generic_ios.output_range.io.first + 1;
-   if (ctx->patch_ios.output_range.used)
-      sinfo->out.num_indirect_patch = ctx->patch_ios.output_range.io.last -
-         ctx->patch_ios.output_range.io.first + 1;
+   sinfo->out_generic_emitted_mask = ctx->generic_ios.match.outputs_emitted_mask;
+   sinfo->out_texcoord_emitted_mask = ctx->texcoord_ios.match.outputs_emitted_mask;
+   sinfo->out_patch_emitted_mask = ctx->patches_emitted_mask;
 
    sinfo->num_inputs = ctx->num_inputs;
    sinfo->num_outputs = ctx->num_outputs;
@@ -7399,18 +7634,7 @@
     * to the next shader stage. mesa/tgsi doesn't provide this information for
     * TCS, TES, and GEOM shaders.
     */
-   sinfo->out.guest_sent_io_arrays = ctx->guest_sent_io_arrays;
-   sinfo->out.num_generic_and_patch = 0;
    for(unsigned i = 0; i < ctx->num_outputs; i++) {
-      if ((ctx->outputs[i].name == TGSI_SEMANTIC_GENERIC || ctx->outputs[i].name == TGSI_SEMANTIC_PATCH) &&
-          !ctx->outputs[i].overlapping_array) {
-         sinfo->generic_outputs_layout[sinfo->out.num_generic_and_patch].name = ctx->outputs[i].name;
-         sinfo->generic_outputs_layout[sinfo->out.num_generic_and_patch].sid = ctx->outputs[i].sid;
-         sinfo->generic_outputs_layout[sinfo->out.num_generic_and_patch].location = 0;
-         sinfo->generic_outputs_layout[sinfo->out.num_generic_and_patch].array_id = ctx->outputs[i].array_id;
-         sinfo->out.num_generic_and_patch++;
-      }
-
       if (ctx->prog_type == TGSI_PROCESSOR_FRAGMENT) {
          if (ctx->outputs[i].name == TGSI_SEMANTIC_COLOR)
             sinfo->fs_output_layout[i] = ctx->outputs[i].sid;
@@ -7429,8 +7653,8 @@
       free(sinfo->image_arrays);
    sinfo->image_arrays = ctx->image_arrays;
    sinfo->num_image_arrays = ctx->num_image_arrays;
-   sinfo->in.generic_emitted_mask = ctx->generic_ios.match.inputs_emitted_mask;
-   sinfo->in.texcoord_emitted_mask = ctx->texcoord_ios.match.inputs_emitted_mask;
+   sinfo->in_generic_emitted_mask = ctx->generic_ios.match.inputs_emitted_mask;
+   sinfo->in_texcoord_emitted_mask = ctx->texcoord_ios.match.inputs_emitted_mask;
 
    for (unsigned i = 0; i < ctx->num_outputs; ++i) {
       if (ctx->outputs[i].invariant) {
@@ -7441,6 +7665,22 @@
       }
    }
    sinfo->gles_use_tex_query_level = ctx->gles_use_tex_query_level;
+
+   if (ctx->guest_sent_io_arrays) {
+      sinfo->output_arrays.num_arrays = 0;
+      for (unsigned i = 0; i < ctx->num_outputs; ++i) {
+         const struct vrend_shader_io *io = &ctx->outputs[i];
+         if (io->array_id  > 0) {
+            struct vrend_shader_io_array *array =
+                  &sinfo->output_arrays.layout[sinfo->output_arrays.num_arrays];
+            array->sid = io->sid;
+            array->size = io->last - io->first;
+            array->name = io->name;
+            array->array_id = io->array_id;
+            ++sinfo->output_arrays.num_arrays;
+         }
+      }
+   }
 }
 
 static bool allocate_strbuffers(struct vrend_glsl_strbufs* glsl_strbufs)
@@ -7473,18 +7713,14 @@
    if (!mask)
       return;
 
-   if (mask != BIT(UNIFORM_PSTIPPLE_SAMPLER)) {
-      strbuf_append(block, "layout (std140) uniform VirglBlock {\n");
-      strbuf_append(block, "\tvec4 clipp[8];\n");
-      strbuf_append(block, "\tfloat winsys_adjust_y;\n");
-      strbuf_append(block, "\tfloat alpha_ref_val;\n");
-      strbuf_append(block, "\tbool clip_plane_enabled;\n");
-      strbuf_append(block, "};\n");
-   }
+   strbuf_append(block, "layout (std140) uniform VirglBlock {\n");
+   strbuf_append(block, "\tvec4 clipp[8];\n");
+   strbuf_appendf(block, "\tuint stipple_pattern[%d];\n", VREND_POLYGON_STIPPLE_SIZE);
+   strbuf_append(block, "\tfloat winsys_adjust_y;\n");
+   strbuf_append(block, "\tfloat alpha_ref_val;\n");
+   strbuf_append(block, "\tbool clip_plane_enabled;\n");
+   strbuf_append(block, "};\n");
 
-   if (mask & BIT(UNIFORM_PSTIPPLE_SAMPLER)) {
-      strbuf_append(block, "uniform sampler2D pstipple_sampler;\n");
-   }
 }
 
 static int compare_sid(const void *lhs, const void *rhs)
@@ -7498,6 +7734,102 @@
    return l->sid - r->sid;
 }
 
+struct sso_scan_ctx {
+   struct tgsi_iterate_context iter;
+   const struct vrend_shader_cfg *cfg;
+   uint8_t max_generic_in_sid;
+   uint8_t max_patch_in_sid;
+   uint8_t max_generic_out_sid;
+   uint8_t max_patch_out_sid;
+   bool separable_program;
+   bool unsupported_io;
+};
+
+static boolean
+iter_prop_for_separable(struct tgsi_iterate_context *iter,
+          struct tgsi_full_property *prop)
+{
+   struct sso_scan_ctx *ctx = (struct sso_scan_ctx *) iter;
+
+   if (prop->Property.PropertyName == TGSI_PROPERTY_SEPARABLE_PROGRAM)
+      ctx->separable_program = prop->u[0].Data != 0;
+   return true;
+}
+
+static boolean
+iter_decl_for_overlap(struct tgsi_iterate_context *iter,
+                      struct tgsi_full_declaration *decl)
+{
+   struct sso_scan_ctx *ctx = (struct sso_scan_ctx *) iter;
+
+   /* VS inputs and FS outputs are of no interest
+    * when it comes to IO matching */
+   if (decl->Declaration.File == TGSI_FILE_INPUT &&
+       iter->processor.Processor == TGSI_PROCESSOR_VERTEX)
+      return true;
+
+   if (decl->Declaration.File == TGSI_FILE_OUTPUT &&
+       iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT)
+      return true;
+
+   switch (decl->Semantic.Name) {
+   case TGSI_SEMANTIC_PATCH:
+      if (decl->Declaration.File == TGSI_FILE_INPUT) {
+         if (ctx->max_patch_in_sid < decl->Semantic.Index)
+            ctx->max_patch_in_sid = decl->Semantic.Index;
+      } else {
+         if (ctx->max_patch_out_sid < decl->Semantic.Index)
+            ctx->max_patch_out_sid = decl->Semantic.Index;
+      }
+      break;
+   case TGSI_SEMANTIC_GENERIC:
+      if (decl->Declaration.File == TGSI_FILE_INPUT) {
+         if (ctx->max_generic_in_sid < decl->Semantic.Index)
+            ctx->max_generic_in_sid = decl->Semantic.Index;
+      } else {
+         if (ctx->max_generic_out_sid < decl->Semantic.Index)
+            ctx->max_generic_out_sid = decl->Semantic.Index;
+      }
+      break;
+   case TGSI_SEMANTIC_COLOR:
+   case TGSI_SEMANTIC_CLIPVERTEX:
+   case TGSI_SEMANTIC_BCOLOR:
+   case TGSI_SEMANTIC_TEXCOORD:
+   case TGSI_SEMANTIC_FOG:
+      /* These are semantics that need to be matched by name and since we can't
+       * guarantee that they exist in all the stages of separable shaders
+       * we can't emit the shader as SSO */
+      ctx->unsupported_io = true;
+      break;
+   default:
+      ;
+   }
+   return true;
+}
+
+
+bool vrend_shader_query_separable_program(const struct tgsi_token *tokens,
+                                          const struct vrend_shader_cfg *cfg)
+{
+   struct sso_scan_ctx ctx = {0};
+   ctx.cfg = cfg;
+   ctx.iter.iterate_property = iter_prop_for_separable;
+   ctx.iter.iterate_declaration = iter_decl_for_overlap;
+   tgsi_iterate_shader(tokens, &ctx.iter);
+
+   /* Since we have to match by location, and have to handle generics and patches
+    * at in the limited range of 32 locations, we have to make sure that the
+    * the generics range and the patch range don't overlap. In addition, to
+    * work around that radeonsi doesn't support patch locations above 30 we have
+    * to check that limit too. */
+   bool supports_separable = !ctx.unsupported_io &&
+                             (ctx.max_generic_in_sid + ctx.max_patch_in_sid < MAX_VARYING) &&
+                             (ctx.max_generic_out_sid + ctx.max_patch_out_sid < MAX_VARYING) &&
+                             (ctx.max_patch_in_sid < ctx.cfg->max_shader_patch_varyings) &&
+                             (ctx.max_patch_out_sid < ctx.cfg->max_shader_patch_varyings);
+   return ctx.separable_program && supports_separable;
+}
+
 bool vrend_convert_shader(const struct vrend_context *rctx,
                           const struct vrend_shader_cfg *cfg,
                           const struct tgsi_token *tokens,
@@ -7511,6 +7843,7 @@
    boolean bret;
 
    memset(&ctx, 0, sizeof(struct dump_ctx));
+   ctx.cfg = cfg;
 
    /* First pass to deal with edge cases. */
    ctx.iter.iterate_declaration = iter_decls;
@@ -7525,7 +7858,6 @@
          (ctx.iter.processor.Processor == TGSI_PROCESSOR_VERTEX &&  !key->gs_present && !key->tes_present);
 
    ctx.num_inputs = 0;
-
    ctx.iter.prolog = prolog;
    ctx.iter.iterate_instruction = iter_instruction;
    ctx.iter.iterate_declaration = iter_declaration;
@@ -7543,9 +7875,9 @@
    ctx.ssbo_atomic_array_base = 0xffffffff;
    ctx.has_sample_input = false;
    ctx.req_local_mem = req_local_mem;
-   ctx.guest_sent_io_arrays = key->input.guest_sent_io_arrays;
-   ctx.generic_ios.match.outputs_expected_mask = key->output.generic_emitted_mask;
-   ctx.texcoord_ios.match.outputs_expected_mask = key->output.texcoord_emitted_mask;
+   ctx.guest_sent_io_arrays = false;
+   ctx.generic_ios.match.outputs_expected_mask = key->out_generic_expected_mask;
+   ctx.texcoord_ios.match.outputs_expected_mask = key->out_texcoord_expected_mask;
 
    tgsi_scan_shader(tokens, &ctx.info);
    /* if we are in core profile mode we should use GLSL 1.40 */
@@ -7578,6 +7910,18 @@
    if (bret == false)
       goto fail;
 
+   /* If we need a sysvalue UBO then we require GLSL 1.40 */
+   if (ctx.glsl_strbufs.required_sysval_uniform_decls)
+      ctx.glsl_ver_required = require_glsl_ver(&ctx, 140);
+
+   if (!ctx.cfg->use_gles &&
+      ( key->in_arrays.num_arrays > 0 ) &&
+       (ctx.prog_type == TGSI_PROCESSOR_GEOMETRY ||
+        ctx.prog_type == TGSI_PROCESSOR_TESS_CTRL ||
+        ctx.prog_type == TGSI_PROCESSOR_TESS_EVAL)) {
+      ctx.shader_req_bits |= SHADER_REQ_ARRAYS_OF_ARRAYS;
+   }
+
    for (size_t i = 0; i < ARRAY_SIZE(ctx.src_bufs); ++i)
       strbuf_free(ctx.src_bufs + i);
 
@@ -7595,9 +7939,15 @@
       ctx.shader_req_bits |= SHADER_REQ_GPU_SHADER5;
    }
 
+   if (fs_info->num_interps && fs_info->has_noperspective &&
+       cfg->use_gles) {
+      ctx.shader_req_bits |= SHADER_REQ_SHADER_NOPERSPECTIVE_INTERPOLATION;
+   }
+
    emit_header(&ctx, &ctx.glsl_strbufs);
    ctx.glsl_ver_required = emit_ios(&ctx, &ctx.glsl_strbufs, &ctx.generic_ios,
-                                    &ctx.texcoord_ios, ctx.front_back_color_emitted_flags,
+                                    &ctx.texcoord_ios, &ctx.patches_emitted_mask,
+                                    ctx.front_back_color_emitted_flags,
                                     &ctx.num_interps, &ctx.has_pervertex,
                                     &ctx.force_color_two_side,
                                     &ctx.shadow_samp_mask);
@@ -7773,7 +8123,8 @@
 
    emit_header(&ctx, &ctx.glsl_strbufs);
    ctx.glsl_ver_required = emit_ios(&ctx, &ctx.glsl_strbufs, &ctx.generic_ios,
-                                    &ctx.texcoord_ios, ctx.front_back_color_emitted_flags,
+                                    &ctx.texcoord_ios, &ctx.patches_emitted_mask,
+                                    ctx.front_back_color_emitted_flags,
                                     &ctx.num_interps, &ctx.has_pervertex,
                                     &ctx.force_color_two_side,
                                     &ctx.shadow_samp_mask);
@@ -7843,13 +8194,8 @@
 {
 
 
-   if (io->first == io->last) {
-      if (io->overlapping_array)
-         strbuf_appendf(result, "%s%s[%d]", io->overlapping_array->glsl_name,
-                        array_or_varname, io->array_offset);
-      else
-         strbuf_appendf(result, "%s%s", io->glsl_name, array_or_varname);
-
+   if (io->first == io->last && !io->overlapping_array) {
+      strbuf_appendf(result, "%s%s", io->glsl_name, array_or_varname);
    } else {
       const struct vrend_shader_io *base = io->overlapping_array ? io->overlapping_array : io;
       const int offset = src->Register.Index - io->first + io->array_offset;
diff --git a/src/vrend_shader.h b/src/vrend_shader.h
index 13fd03f..849acd9 100644
--- a/src/vrend_shader.h
+++ b/src/vrend_shader.h
@@ -32,6 +32,8 @@
 
 #define VIRGL_NUM_CLIP_PLANES 8
 
+#define VREND_POLYGON_STIPPLE_SIZE 32
+
 #define VREND_SHADER_SAMPLER_VIEWS_MASK_LENGTH \
    ((PIPE_MAX_SHADER_SAMPLER_VIEWS + 63) / 64)
 
@@ -81,31 +83,47 @@
    int num_interps;
    int glsl_ver;
    bool has_sample_input;
+   bool has_noperspective;
    struct vrend_interp_info interpinfo[PIPE_MAX_SHADER_INPUTS];
 };
 
 struct vrend_shader_info_out {
-   uint64_t num_indirect_generic : 8;
-   uint64_t num_indirect_patch : 8;
-   uint64_t num_generic_and_patch : 8;
-   uint64_t guest_sent_io_arrays : 1;
+   uint8_t num_generic_and_patch;
+   uint8_t num_indirect_generic;
+   uint8_t num_indirect_patch;
+   bool guest_sent_io_arrays;
 };
 
 struct vrend_shader_info_in {
    uint64_t generic_emitted_mask;
    uint64_t texcoord_emitted_mask;
-   uint32_t num_indirect_generic : 8;
-   uint32_t num_indirect_patch : 8;
-   uint32_t use_pervertex : 1;
+   bool indirect_generic_or_patch : 1;
+   bool use_pervertex : 1;
 };
 
+struct vrend_shader_io_array {
+   enum tgsi_semantic name : 6;
+   uint32_t sid : 6;
+   uint32_t size : 6;
+   uint32_t array_id : 6;
+   uint32_t padding : 8;
+};
+
+struct vrend_shader_io_array_info {
+   uint32_t num_arrays;
+   struct vrend_shader_io_array layout[16];
+};
 
 struct vrend_shader_info {
    uint32_t invariant_outputs[4];
-   struct vrend_shader_info_out out;
-   struct vrend_shader_info_in in;
+   uint64_t in_generic_emitted_mask;
+   uint64_t in_texcoord_emitted_mask;
 
-   struct vrend_layout_info generic_outputs_layout[64];
+   uint64_t out_generic_emitted_mask;
+   uint64_t out_patch_emitted_mask;
+
+   struct vrend_shader_io_array_info output_arrays;
+
    struct vrend_array *sampler_arrays;
    struct vrend_array *image_arrays;
    char **so_names;
@@ -132,10 +150,14 @@
    int num_sampler_arrays;
    int num_image_arrays;
 
+   uint8_t out_texcoord_emitted_mask;
    uint8_t ubo_indirect : 1;
    uint8_t tes_point_mode : 1;
    uint8_t gles_use_tex_query_level : 1;
    uint8_t separable_program : 1;
+   uint8_t has_input_arrays : 1;
+   uint8_t has_output_arrays : 1;
+   uint8_t use_pervertex_in : 1;
 };
 
 struct vrend_variable_shader_info {
@@ -149,12 +171,17 @@
 };
 
 struct vrend_shader_key {
+   uint64_t out_generic_expected_mask;
+   uint64_t out_texcoord_expected_mask;
+
+   uint64_t in_generic_expected_mask;
+   uint64_t in_texcoord_expected_mask;
+   uint64_t in_patch_expected_mask;
+
    uint32_t force_invariant_inputs[4];
 
    struct vrend_fs_shader_info fs_info;
-   struct vrend_shader_info_out input;
-   struct vrend_shader_info_in output;
-   struct vrend_layout_info prev_stage_generic_and_patch_outputs_layout[64];
+   struct vrend_shader_io_array_info in_arrays;
 
    union {
       struct {
@@ -168,7 +195,7 @@
          uint32_t logicop_func : 4;
          uint32_t logicop_enabled : 1;
          uint32_t prim_is_points : 1;
-         uint32_t invert_origin : 1;
+         uint32_t lower_left_origin : 1;
          uint32_t available_color_in_bits : 4;
       } fs;
 
@@ -193,19 +220,22 @@
    uint8_t num_in_clip : 4;
    uint8_t num_out_cull : 4;
    uint8_t num_out_clip : 4;
-   uint8_t pstipple_tex : 1;
+   uint8_t pstipple_enabled : 1;
    uint8_t add_alpha_test : 1;
    uint8_t color_two_side : 1;
    uint8_t gs_present : 1;
    uint8_t tcs_present : 1;
    uint8_t tes_present : 1;
    uint8_t flatshade : 1;
-
+   uint8_t require_input_arrays : 1;
+   uint8_t require_output_arrays : 1;
+   uint8_t use_pervertex_in : 1;
 };
 
 struct vrend_shader_cfg {
    uint32_t glsl_version : 12;
    uint32_t max_draw_buffers : 4;
+   uint32_t max_shader_patch_varyings : 6;
    uint32_t use_gles : 1;
    uint32_t use_core_profile : 1;
    uint32_t use_explicit_locations : 1;
@@ -217,6 +247,8 @@
    uint32_t has_dual_src_blend : 1;
    uint32_t has_fbfetch_coherent : 1;
    uint32_t has_cull_distance : 1;
+   uint32_t has_nopersective : 1;
+   uint32_t has_texture_shadow_lod : 1;
 };
 
 struct vrend_context;
@@ -251,6 +283,9 @@
 
 bool vrend_shader_needs_alpha_func(const struct vrend_shader_key *key);
 
+bool vrend_shader_query_separable_program(const struct tgsi_token *tokens,
+                                          const struct vrend_shader_cfg *cfg);
+
 static inline bool vrend_shader_sampler_views_mask_get(
    const uint64_t mask[static VREND_SHADER_SAMPLER_VIEWS_MASK_LENGTH],
    int index)
diff --git a/src/vrend_strbuf.h b/src/vrend_strbuf.h
index da5cb47..8568d01 100644
--- a/src/vrend_strbuf.h
+++ b/src/vrend_strbuf.h
@@ -148,11 +148,14 @@
 
    int len = vsnprintf(sb->buf + sb->size, sb->alloc_size - sb->size, fmt, ap);
    if (len >= (int)(sb->alloc_size - sb->size)) {
-      if (!strbuf_grow(sb, len))
-        return;
+      if (!strbuf_grow(sb, len)) {
+         goto end;
+      }
       vsnprintf(sb->buf + sb->size, sb->alloc_size - sb->size, fmt, cp);
    }
    sb->size += len;
+end:
+   va_end(ap);
 }
 
 __attribute__((format(printf, 2, 3)))
@@ -172,10 +175,12 @@
    int len = vsnprintf(sb->buf, sb->alloc_size, fmt, ap);
    if (len >= (int)(sb->alloc_size)) {
       if (!strbuf_grow(sb, len))
-        return;
+        goto end;
       vsnprintf(sb->buf, sb->alloc_size, fmt, cp);
    }
    sb->size = len;
+end:
+   va_end(ap);
 }
 
 __attribute__((format(printf, 2, 3)))
diff --git a/src/vrend_video.c b/src/vrend_video.c
new file mode 100644
index 0000000..38da8ff
--- /dev/null
+++ b/src/vrend_video.c
@@ -0,0 +1,771 @@
+/**************************************************************************
+ *
+ * Copyright (C) 2022 Kylin Software Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * @file
+ * The video implementation of the vrend renderer.
+ *
+ * It is based on the general virgl video submodule and handles data transfer
+ * and synchronization between host and guest.
+ *
+ * The relationship between vaSurface and video buffer objects:
+ *
+ *           GUEST (Mesa)           |       HOST (Virglrenderer)
+ *                                  |
+ *         +------------+           |          +------------+
+ *         | vaSurface  |           |          | vaSurface  | <------+
+ *         +------------+           |          +------------+        |
+ *               |                  |                                |
+ *  +---------------------------+   |   +-------------------------+  |
+ *  |    virgl_video_buffer     |   |   |    vrend_video_buffer   |  |
+ *  | +-----------------------+ |   |   |  +-------------------+  |  |
+ *  | |    vl_video_buffer    | |   |   |  | vrend_resource(s) |  |  |
+ *  | | +-------------------+ | |<--+-->|  +-------------------+  |  |
+ *  | | | virgl_resource(s) | | |   |   |  +--------------------+ |  |
+ *  | | +-------------------+ | |   |   |  | virgl_video_buffer |-+--+
+ *  | +-----------------------+ |   |   |  +--------------------+ |
+ *  +---------------------------+   |   +-------------------------+
+ *
+ * The relationship between vaContext and video codec objects:
+ *
+ *           GUEST (Mesa)         |         HOST (Virglrenderer)
+ *                                |
+ *         +------------+         |           +------------+
+ *         | vaContext  |         |           | vaContext  | <-------+
+ *         +------------+         |           +------------+         |
+ *               |                |                                  |
+ *  +------------------------+    |    +--------------------------+  |
+ *  |    virgl_video_codec   | <--+--> |    vrend_video_codec     |  |
+ *  +------------------------+    |    |  +--------------------+  |  |
+ *                                |    |  | virgl_video_codec  | -+--+
+ *                                |    |  +--------------------+  |
+ *                                |    +--------------------------+
+ *
+ * @author Feng Jiang <jiangfeng@kylinos.cn>
+ */
+
+
+#include <sys/param.h>
+
+#include "virgl_video.h"
+#include "virgl_video_hw.h"
+
+#include "vrend_debug.h"
+#include "vrend_winsys.h"
+#include "vrend_renderer.h"
+#include "vrend_video.h"
+
+struct vrend_context;
+
+struct vrend_video_context {
+    struct vrend_context *ctx;
+    struct list_head codecs;
+    struct list_head buffers;
+};
+
+struct vrend_video_codec {
+    struct virgl_video_codec *codec;
+    uint32_t handle;
+    struct vrend_resource *feed_res;    /* encoding feedback */
+    struct vrend_resource *dest_res;    /* encoding coded buffer */
+    struct vrend_video_context *ctx;
+    struct list_head head;
+};
+
+struct vrend_video_plane {
+    uint32_t res_handle;
+    GLuint texture;         /* texture for temporary use */
+    GLuint framebuffer;     /* framebuffer for temporary use */
+    EGLImageKHR egl_image;  /* egl image for temporary use */
+};
+
+struct vrend_video_buffer {
+    struct virgl_video_buffer *buffer;
+
+    uint32_t handle;
+    struct vrend_video_context *ctx;
+    struct list_head head;
+
+    uint32_t num_planes;
+    struct vrend_video_plane planes[3];
+};
+
+static struct vrend_video_codec *vrend_video_codec(
+        struct virgl_video_codec *codec)
+{
+    return virgl_video_codec_opaque_data(codec);
+}
+
+static struct vrend_video_buffer *vrend_video_buffer(
+        struct virgl_video_buffer *buffer)
+{
+    return virgl_video_buffer_opaque_data(buffer);
+}
+
+static struct vrend_video_codec *get_video_codec(
+                                        struct vrend_video_context *ctx,
+                                        uint32_t cdc_handle)
+{
+    struct vrend_video_codec *cdc;
+
+    LIST_FOR_EACH_ENTRY(cdc, &ctx->codecs, head) {
+        if (cdc->handle == cdc_handle)
+            return cdc;
+    }
+
+    return NULL;
+}
+
+static struct vrend_video_buffer *get_video_buffer(
+                                        struct vrend_video_context *ctx,
+                                        uint32_t buf_handle)
+{
+    struct vrend_video_buffer *buf;
+
+    LIST_FOR_EACH_ENTRY(buf, &ctx->buffers, head) {
+        if (buf->handle == buf_handle)
+            return buf;
+    }
+
+    return NULL;
+}
+
+
+static int sync_dmabuf_to_video_buffer(struct vrend_video_buffer *buf,
+                                       const struct virgl_video_dma_buf *dmabuf)
+{
+    if (!(dmabuf->flags & VIRGL_VIDEO_DMABUF_READ_ONLY)) {
+        vrend_printf("%s: dmabuf is not readable\n", __func__);
+        return -1;
+    }
+
+    for (unsigned i = 0; i < dmabuf->num_planes && i < buf->num_planes; i++) {
+        struct vrend_video_plane *plane = &buf->planes[i];
+        struct vrend_resource *res;
+
+        res = vrend_renderer_ctx_res_lookup(buf->ctx->ctx, plane->res_handle);
+        if (!res) {
+            vrend_printf("%s: res %d not found\n", __func__, plane->res_handle);
+            continue;
+        }
+
+        /* dmabuf -> eglimage */
+        if (EGL_NO_IMAGE_KHR == plane->egl_image) {
+            EGLint img_attrs[16] = {
+                EGL_LINUX_DRM_FOURCC_EXT,       dmabuf->planes[i].drm_format,
+                EGL_WIDTH,                      dmabuf->width / (i + 1),
+                EGL_HEIGHT,                     dmabuf->height / (i + 1),
+                EGL_DMA_BUF_PLANE0_FD_EXT,      dmabuf->planes[i].fd,
+                EGL_DMA_BUF_PLANE0_OFFSET_EXT,  dmabuf->planes[i].offset,
+                EGL_DMA_BUF_PLANE0_PITCH_EXT,   dmabuf->planes[i].pitch,
+                EGL_NONE
+            };
+
+            plane->egl_image = eglCreateImageKHR(eglGetCurrentDisplay(),
+                    EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, img_attrs);
+        }
+
+        if (EGL_NO_IMAGE_KHR == plane->egl_image) {
+            vrend_printf("%s: create egl image failed\n", __func__);
+            continue;
+        }
+
+        /* eglimage -> texture */
+        glBindTexture(GL_TEXTURE_2D, plane->texture);
+        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
+                                    (GLeglImageOES)(plane->egl_image));
+
+        /* texture -> framebuffer */
+        glBindFramebuffer(GL_READ_FRAMEBUFFER, plane->framebuffer);
+        glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                               GL_TEXTURE_2D, plane->texture, 0);
+
+        /* framebuffer -> vrend_video_buffer.planes[i] */
+        glBindTexture(GL_TEXTURE_2D, res->id);
+        glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
+                            res->base.width0, res->base.height0);
+    }
+
+    glBindTexture(GL_TEXTURE_2D, 0);
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+    return 0;
+}
+
+static int sync_video_buffer_to_dmabuf(struct vrend_video_buffer *buf,
+                                       const struct virgl_video_dma_buf *dmabuf)
+{
+    if (!(dmabuf->flags & VIRGL_VIDEO_DMABUF_WRITE_ONLY)) {
+        vrend_printf("%s: dmabuf is not writable\n", __func__);
+        return -1;
+    }
+
+    for (unsigned i = 0; i < dmabuf->num_planes && i < buf->num_planes; i++) {
+        struct vrend_video_plane *plane = &buf->planes[i];
+        struct vrend_resource *res;
+
+        res = vrend_renderer_ctx_res_lookup(buf->ctx->ctx, plane->res_handle);
+        if (!res) {
+            vrend_printf("%s: res %d not found\n", __func__, plane->res_handle);
+            continue;
+        }
+
+        /* dmabuf -> eglimage */
+        if (EGL_NO_IMAGE_KHR == plane->egl_image) {
+            EGLint img_attrs[16] = {
+                EGL_LINUX_DRM_FOURCC_EXT,       dmabuf->planes[i].drm_format,
+                EGL_WIDTH,                      dmabuf->width / (i + 1),
+                EGL_HEIGHT,                     dmabuf->height / (i + 1),
+                EGL_DMA_BUF_PLANE0_FD_EXT,      dmabuf->planes[i].fd,
+                EGL_DMA_BUF_PLANE0_OFFSET_EXT,  dmabuf->planes[i].offset,
+                EGL_DMA_BUF_PLANE0_PITCH_EXT,   dmabuf->planes[i].pitch,
+                EGL_NONE
+            };
+
+            plane->egl_image = eglCreateImageKHR(eglGetCurrentDisplay(),
+                    EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, img_attrs);
+        }
+
+        if (EGL_NO_IMAGE_KHR == plane->egl_image) {
+            vrend_printf("%s: create egl image failed\n", __func__);
+            continue;
+        }
+
+        /* eglimage -> texture */
+        glBindTexture(GL_TEXTURE_2D, plane->texture);
+        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
+                                    (GLeglImageOES)(plane->egl_image));
+
+        /* vrend_video_buffer.planes[i] -> framebuffer */
+        glBindFramebuffer(GL_READ_FRAMEBUFFER, plane->framebuffer);
+        glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                               GL_TEXTURE_2D, res->id, 0);
+
+        /* framebuffer -> texture */
+        glBindTexture(GL_TEXTURE_2D, plane->texture);
+        glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
+                            res->base.width0, res->base.height0);
+
+    }
+
+    glBindTexture(GL_TEXTURE_2D, 0);
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+    return 0;
+}
+
+
+static void vrend_video_decode_completed(
+                                struct virgl_video_codec *codec,
+                                const struct virgl_video_dma_buf *dmabuf)
+{
+    struct vrend_video_buffer *buf = vrend_video_buffer(dmabuf->buf);
+
+    (void)codec;
+
+    sync_dmabuf_to_video_buffer(buf, dmabuf);
+}
+
+
+static void vrend_video_enocde_upload_picture(
+                                struct virgl_video_codec *codec,
+                                const struct virgl_video_dma_buf *dmabuf)
+{
+    struct vrend_video_buffer *buf = vrend_video_buffer(dmabuf->buf);
+
+    (void)codec;
+
+    sync_video_buffer_to_dmabuf(buf, dmabuf);
+}
+
+static void vrend_video_encode_completed(
+                                struct virgl_video_codec *codec,
+                                const struct virgl_video_dma_buf *src_buf,
+                                const struct virgl_video_dma_buf *ref_buf,
+                                unsigned num_coded_bufs,
+                                const void * const *coded_bufs,
+                                const unsigned *coded_sizes)
+{
+    void *buf;
+    unsigned i, size, data_size;
+    struct virgl_video_encode_feedback feedback;
+    struct vrend_video_codec *cdc = vrend_video_codec(codec);
+
+    (void)src_buf;
+    (void)ref_buf;
+
+    if (!cdc->dest_res || !cdc->feed_res)
+        return;
+
+    memset(&feedback, 0, sizeof(feedback));
+
+    /* sync coded data to guest */
+    if (has_bit(cdc->dest_res->storage_bits, VREND_STORAGE_GL_BUFFER)) {
+        glBindBufferARB(cdc->dest_res->target, cdc->dest_res->id);
+        buf = glMapBufferRange(cdc->dest_res->target, 0,
+                               cdc->dest_res->base.width0, GL_MAP_WRITE_BIT);
+        for (i = 0, data_size = 0; i < num_coded_bufs &&
+                    data_size < cdc->dest_res->base.width0; i++) {
+            size = MIN(cdc->dest_res->base.width0 - data_size, coded_sizes[i]);
+            memcpy((uint8_t *)buf + data_size, coded_bufs[i], size);
+            vrend_write_to_iovec(cdc->dest_res->iov, cdc->dest_res->num_iovs,
+                                 data_size, coded_bufs[i], size);
+            data_size += size;
+        }
+        glUnmapBuffer(cdc->dest_res->target);
+        glBindBufferARB(cdc->dest_res->target, 0);
+        feedback.stat = VIRGL_VIDEO_ENCODE_STAT_SUCCESS;
+        feedback.coded_size = data_size;
+    } else {
+        vrend_printf("unexcepted coded res type\n");
+        feedback.stat = VIRGL_VIDEO_ENCODE_STAT_FAILURE;
+        feedback.coded_size = 0;
+    }
+
+    /* send feedback */
+    vrend_write_to_iovec(cdc->feed_res->iov, cdc->feed_res->num_iovs,
+                         0, (char *)(&feedback),
+                         MIN(cdc->feed_res->base.width0, sizeof(feedback)));
+
+    cdc->dest_res = NULL;
+    cdc->feed_res = NULL;
+}
+
+static struct virgl_video_callbacks video_callbacks = {
+    .decode_completed           = vrend_video_decode_completed,
+    .encode_upload_picture      = vrend_video_enocde_upload_picture,
+    .encode_completed           = vrend_video_encode_completed,
+};
+
+int vrend_video_init(int drm_fd)
+{
+    if (drm_fd < 0)
+        return -1;
+
+    return virgl_video_init(drm_fd, &video_callbacks, 0);
+}
+
+void vrend_video_fini(void)
+{
+    virgl_video_destroy();
+}
+
+int vrend_video_fill_caps(union virgl_caps *caps)
+{
+    return virgl_video_fill_caps(caps);
+}
+
+int vrend_video_create_codec(struct vrend_video_context *ctx,
+                             uint32_t handle,
+                             uint32_t profile,
+                             uint32_t entrypoint,
+                             uint32_t chroma_format,
+                             uint32_t level,
+                             uint32_t width,
+                             uint32_t height,
+                             uint32_t max_ref,
+                             uint32_t flags)
+{
+    struct vrend_video_codec *cdc = get_video_codec(ctx, handle);
+    struct virgl_video_create_codec_args args;
+
+    if (cdc)
+        return 0;
+
+    if (profile <= PIPE_VIDEO_PROFILE_UNKNOWN ||
+        profile >= PIPE_VIDEO_PROFILE_MAX)
+        return -1;
+
+    if (entrypoint <= PIPE_VIDEO_ENTRYPOINT_UNKNOWN ||
+        entrypoint > PIPE_VIDEO_ENTRYPOINT_ENCODE)
+        return -1;
+
+    if (chroma_format >= PIPE_VIDEO_CHROMA_FORMAT_NONE)
+        return -1;
+
+    if (!width || !height)
+        return -1;
+
+    cdc = (struct vrend_video_codec *)calloc(1, sizeof(*cdc));
+    if (!cdc)
+        return -1;
+
+    args.profile = profile;
+    args.entrypoint = entrypoint;
+    args.chroma_format = chroma_format;
+    args.level = level;
+    args.width = width;
+    args.height = height;
+    args.max_references = max_ref;
+    args.flags = flags;
+    args.opaque = cdc;
+    cdc->codec = virgl_video_create_codec(&args);
+    if (!cdc->codec) {
+        free(cdc);
+        return -1;
+    }
+
+    cdc->handle = handle;
+    cdc->ctx = ctx;
+    list_add(&cdc->head, &ctx->codecs);
+
+    return 0;
+}
+
+static void destroy_video_codec(struct vrend_video_codec *cdc)
+{
+    if (cdc) {
+        list_del(&cdc->head);
+        virgl_video_destroy_codec(cdc->codec);
+        free(cdc);
+    }
+}
+
+void vrend_video_destroy_codec(struct vrend_video_context *ctx,
+                               uint32_t handle)
+{
+    struct vrend_video_codec *cdc = get_video_codec(ctx, handle);
+
+    destroy_video_codec(cdc);
+}
+
+int vrend_video_create_buffer(struct vrend_video_context *ctx,
+                              uint32_t handle,
+                              uint32_t format,
+                              uint32_t width,
+                              uint32_t height,
+                              uint32_t *res_handles,
+                              unsigned int num_res)
+{
+    unsigned i;
+    struct vrend_video_plane *plane;
+    struct vrend_video_buffer *buf = get_video_buffer(ctx, handle);
+    struct virgl_video_create_buffer_args args;
+
+    if (buf)
+        return 0;
+
+    if (format <= PIPE_FORMAT_NONE || format >= PIPE_FORMAT_COUNT)
+        return -1;
+
+    if (!width || !height || !res_handles || !num_res)
+        return -1;
+
+    buf = (struct vrend_video_buffer *)calloc(1, sizeof(*buf));
+    if (!buf)
+        return -1;
+
+    args.format = format;
+    args.width = width;
+    args.height = height;
+    args.interlaced = 0;
+    args.opaque = buf;
+    buf->buffer = virgl_video_create_buffer(&args);
+    if (!buf->buffer) {
+        free(buf);
+        return -1;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(buf->planes); i++)
+        buf->planes[i].egl_image = EGL_NO_IMAGE_KHR;
+
+    for (i = 0, buf->num_planes = 0;
+         i < num_res && buf->num_planes < ARRAY_SIZE(buf->planes); i++) {
+
+        if (!res_handles[i])
+            continue;
+
+        plane = &buf->planes[buf->num_planes++];
+        plane->res_handle = res_handles[i];
+        glGenFramebuffers(1, &plane->framebuffer);
+        glGenTextures(1, &plane->texture);
+        glBindTexture(GL_TEXTURE_2D, plane->texture);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        glBindTexture(GL_TEXTURE_2D, 0);
+    }
+
+    buf->handle = handle;
+    buf->ctx = ctx;
+    list_add(&buf->head, &ctx->buffers);
+
+    return 0;
+}
+
+static void destroy_video_buffer(struct vrend_video_buffer *buf)
+{
+    unsigned i;
+    struct vrend_video_plane *plane;
+
+    if (!buf)
+        return;
+
+    list_del(&buf->head);
+
+    for (i = 0; i < buf->num_planes; i++) {
+        plane = &buf->planes[i];
+
+        glDeleteTextures(1, &plane->texture);
+        glDeleteFramebuffers(1, &plane->framebuffer);
+        if (plane->egl_image == EGL_NO_IMAGE_KHR)
+            eglDestroyImageKHR(eglGetCurrentDisplay(), plane->egl_image);
+    }
+
+    virgl_video_destroy_buffer(buf->buffer);
+
+    free(buf);
+}
+
+void vrend_video_destroy_buffer(struct vrend_video_context *ctx,
+                                uint32_t handle)
+{
+    struct vrend_video_buffer *buf = get_video_buffer(ctx, handle);
+
+    destroy_video_buffer(buf);
+}
+
+struct vrend_video_context *vrend_video_create_context(struct vrend_context *ctx)
+{
+    struct vrend_video_context *vctx;
+
+    vctx = (struct vrend_video_context *)calloc(1, sizeof(*vctx));
+    if (vctx) {
+        vctx->ctx = ctx;
+        list_inithead(&vctx->codecs);
+        list_inithead(&vctx->buffers);
+    }
+
+    return vctx;
+}
+
+void vrend_video_destroy_context(struct vrend_video_context *ctx)
+{
+   struct vrend_video_codec *vcdc, *vcdc_tmp;
+   struct vrend_video_buffer *vbuf, *vbuf_tmp;
+
+   LIST_FOR_EACH_ENTRY_SAFE(vcdc, vcdc_tmp, &ctx->codecs, head)
+      destroy_video_codec(vcdc);
+
+   LIST_FOR_EACH_ENTRY_SAFE(vbuf, vbuf_tmp, &ctx->buffers, head)
+      destroy_video_buffer(vbuf);
+
+   free(ctx);
+}
+
+int vrend_video_begin_frame(struct vrend_video_context *ctx,
+                            uint32_t cdc_handle,
+                            uint32_t tgt_handle)
+{
+    struct vrend_video_codec *cdc = get_video_codec(ctx, cdc_handle);
+    struct vrend_video_buffer *tgt = get_video_buffer(ctx, tgt_handle);
+
+    if (!cdc || !tgt)
+        return -1;
+
+    return virgl_video_begin_frame(cdc->codec, tgt->buffer);
+}
+
+static void modify_h264_picture_desc(struct vrend_video_codec *cdc,
+                                     struct vrend_video_buffer *tgt,
+                                     struct virgl_h264_picture_desc *desc)
+{
+    unsigned i;
+    struct vrend_video_buffer *vbuf;
+
+    (void)tgt;
+
+    for (i = 0; i < ARRAY_SIZE(desc->buffer_id); i++) {
+        vbuf = get_video_buffer(cdc->ctx, desc->buffer_id[i]);
+        desc->buffer_id[i] = virgl_video_buffer_id(vbuf ? vbuf->buffer : NULL);
+    }
+}
+
+static void modify_h265_picture_desc(struct vrend_video_codec *cdc,
+                                     struct vrend_video_buffer *tgt,
+                                     struct virgl_h265_picture_desc *desc)
+{
+    unsigned i;
+    struct vrend_video_buffer *vbuf;
+
+    (void)tgt;
+
+    for (i = 0; i < ARRAY_SIZE(desc->ref); i++) {
+        vbuf = get_video_buffer(cdc->ctx, desc->ref[i]);
+        desc->ref[i] = virgl_video_buffer_id(vbuf ? vbuf->buffer : NULL);
+    }
+}
+
+static void modify_picture_desc(struct vrend_video_codec *cdc,
+                                struct vrend_video_buffer *tgt,
+                                union virgl_picture_desc *desc)
+{
+    switch(virgl_video_codec_profile(cdc->codec)) {
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE:
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED:
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10:
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH422:
+    case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH444:
+        modify_h264_picture_desc(cdc, tgt, &desc->h264);
+        break;
+    case PIPE_VIDEO_PROFILE_HEVC_MAIN:
+    case PIPE_VIDEO_PROFILE_HEVC_MAIN_10:
+    case PIPE_VIDEO_PROFILE_HEVC_MAIN_STILL:
+    case PIPE_VIDEO_PROFILE_HEVC_MAIN_12:
+    case PIPE_VIDEO_PROFILE_HEVC_MAIN_444:
+        modify_h265_picture_desc(cdc, tgt, &desc->h265);
+        break;
+    default:
+        break;
+    }
+}
+
+int vrend_video_decode_bitstream(struct vrend_video_context *ctx,
+                                 uint32_t cdc_handle,
+                                 uint32_t tgt_handle,
+                                 uint32_t desc_handle,
+                                 unsigned num_buffers,
+                                 const uint32_t *buffer_handles,
+                                 const uint32_t *buffer_sizes)
+{
+    int err = -1;
+    unsigned i, num_bs, *bs_sizes = NULL;
+    void **bs_buffers = NULL;
+    struct vrend_resource *res;
+    struct vrend_video_codec  *cdc = get_video_codec(ctx, cdc_handle);
+    struct vrend_video_buffer *tgt = get_video_buffer(ctx, tgt_handle);
+    union virgl_picture_desc desc;
+
+    if (!cdc || !tgt)
+        return -1;
+
+    bs_buffers = calloc(num_buffers, sizeof(void *));
+    if (!bs_buffers) {
+        vrend_printf("%s: alloc bs_buffers failed\n", __func__);
+        return -1;
+    }
+
+    bs_sizes = calloc(num_buffers, sizeof(unsigned));
+    if (!bs_sizes) {
+        vrend_printf("%s: alloc bs_sizes failed\n", __func__);
+        goto err;
+    }
+
+    for (i = 0, num_bs = 0; i < num_buffers; i++) {
+        res = vrend_renderer_ctx_res_lookup(ctx->ctx, buffer_handles[i]);
+        if (!res || !res->ptr) {
+            vrend_printf("%s: bs res %d invalid or not found",
+                         __func__, buffer_handles[i]);
+            continue;
+        }
+
+        vrend_read_from_iovec(res->iov, res->num_iovs, 0,
+                              res->ptr, buffer_sizes[i]);
+        bs_buffers[num_bs] = res->ptr;
+        bs_sizes[num_bs] = buffer_sizes[i];
+        num_bs++;
+    }
+
+    res = vrend_renderer_ctx_res_lookup(ctx->ctx, desc_handle);
+    if (!res) {
+        vrend_printf("%s: desc res %d not found\n", __func__, desc_handle);
+        goto err;
+    }
+    memset(&desc, 0, sizeof(desc));
+    vrend_read_from_iovec(res->iov, res->num_iovs, 0, (char *)(&desc),
+                          MIN(res->base.width0, sizeof(desc)));
+    modify_picture_desc(cdc, tgt, &desc);
+
+    err = virgl_video_decode_bitstream(cdc->codec, tgt->buffer, &desc,
+                           num_bs, (const void * const *)bs_buffers, bs_sizes);
+
+err:
+    free(bs_buffers);
+    free(bs_sizes);
+
+    return err;
+}
+
+int vrend_video_encode_bitstream(struct vrend_video_context *ctx,
+                                 uint32_t cdc_handle,
+                                 uint32_t src_handle,
+                                 uint32_t dest_handle,
+                                 uint32_t desc_handle,
+                                 uint32_t feed_handle)
+{
+    union virgl_picture_desc desc;
+    struct vrend_resource *dest_res, *desc_res, *feed_res;
+    struct vrend_video_codec  *cdc = get_video_codec(ctx, cdc_handle);
+    struct vrend_video_buffer *src = get_video_buffer(ctx, src_handle);
+
+    if (!cdc || !src)
+        return -1;
+
+    /* Feedback resource */
+    feed_res = vrend_renderer_ctx_res_lookup(ctx->ctx, feed_handle);
+    if (!feed_res) {
+        vrend_printf("%s: feedback res %d not found\n", __func__, feed_handle);
+        return -1;
+    }
+
+    /* Picture descriptor resource */
+    desc_res = vrend_renderer_ctx_res_lookup(ctx->ctx, desc_handle);
+    if (!desc_res) {
+        vrend_printf("%s: desc res %d not found\n", __func__, desc_handle);
+        return -1;
+    }
+    memset(&desc, 0, sizeof(desc));
+    vrend_read_from_iovec(desc_res->iov, desc_res->num_iovs, 0, (char *)(&desc),
+                          MIN(desc_res->base.width0, sizeof(desc)));
+
+    /* Destination buffer resource. */
+    dest_res = vrend_renderer_ctx_res_lookup(ctx->ctx, dest_handle);
+    if (!dest_res) {
+        vrend_printf("%s: dest res %d not found\n", __func__, dest_handle);
+        return -1;
+    }
+
+    cdc->feed_res = feed_res;
+    cdc->dest_res = dest_res;
+
+    return virgl_video_encode_bitstream(cdc->codec, src->buffer, &desc);
+}
+
+int vrend_video_end_frame(struct vrend_video_context *ctx,
+                          uint32_t cdc_handle,
+                          uint32_t tgt_handle)
+{
+    struct vrend_video_codec *cdc = get_video_codec(ctx, cdc_handle);
+    struct vrend_video_buffer *tgt = get_video_buffer(ctx, tgt_handle);
+
+    if (!cdc || !tgt)
+        return -1;
+
+    return virgl_video_end_frame(cdc->codec, tgt->buffer);
+}
+
diff --git a/src/vrend_video.h b/src/vrend_video.h
new file mode 100644
index 0000000..7b61db1
--- /dev/null
+++ b/src/vrend_video.h
@@ -0,0 +1,95 @@
+/**************************************************************************
+ *
+ * Copyright (C) 2022 Kylin Software Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * @file
+ * The video interface of the vrend renderer.
+ *
+ * These interfaces are mainly called by the vrend deocode submodule
+ * to process the corresponding virgl context video command.
+ *
+ * @author Feng Jiang <jiangfeng@kylinos.cn>
+ */
+
+#ifndef VREND_VIDEO_H
+#define VREND_VIDEO_H
+
+#include <virgl_hw.h>
+
+#define VREND_VIDEO_BUFFER_PLANE_NUM  3
+
+struct vrend_video_context;
+
+int vrend_video_init(int drm_fd);
+void vrend_video_fini(void);
+
+int vrend_video_fill_caps(union virgl_caps *caps);
+
+struct vrend_video_context *vrend_video_create_context(struct vrend_context *ctx);
+void vrend_video_destroy_context(struct vrend_video_context *ctx);
+
+int vrend_video_create_codec(struct vrend_video_context *ctx,
+                             uint32_t handle,
+                             uint32_t profile,
+                             uint32_t entrypoint,
+                             uint32_t chroma_format,
+                             uint32_t level,
+                             uint32_t width,
+                             uint32_t height,
+                             uint32_t max_ref,
+                             uint32_t flags);
+void vrend_video_destroy_codec(struct vrend_video_context *ctx,
+                               uint32_t handle);
+
+int vrend_video_create_buffer(struct vrend_video_context *ctx,
+                              uint32_t handle,
+                              uint32_t format,
+                              uint32_t width,
+                              uint32_t height,
+                              uint32_t *res_handles,
+                              unsigned int num_res);
+void vrend_video_destroy_buffer(struct vrend_video_context *ctx,
+                                uint32_t handle);
+
+int vrend_video_begin_frame(struct vrend_video_context *ctx,
+                            uint32_t cdc_handle,
+                            uint32_t tgt_handle);
+int vrend_video_decode_bitstream(struct vrend_video_context *ctx,
+                                 uint32_t cdc_handle,
+                                 uint32_t tgt_handle,
+                                 uint32_t desc_handle,
+                                 unsigned num_buffers,
+                                 const uint32_t *buffer_handles,
+                                 const uint32_t *buffer_sizes);
+int vrend_video_encode_bitstream(struct vrend_video_context *ctx,
+                                 uint32_t cdc_handle,
+                                 uint32_t src_handle,
+                                 uint32_t dest_handle,
+                                 uint32_t desc_handle,
+                                 uint32_t feed_handle);
+int vrend_video_end_frame(struct vrend_video_context *ctx,
+                          uint32_t cdc_handle,
+                          uint32_t tgt_handle);
+
+#endif /* VREND_VIDEO_H */
diff --git a/src/vrend_winsys.c b/src/vrend_winsys.c
index 9371e81..6a73b7f 100644
--- a/src/vrend_winsys.c
+++ b/src/vrend_winsys.c
@@ -166,15 +166,24 @@
 
 int vrend_winsys_make_context_current(virgl_renderer_gl_context ctx)
 {
+   int ret = -1;
 #ifdef HAVE_EPOXY_EGL_H
-   if (use_context == CONTEXT_EGL)
-      return virgl_egl_make_context_current(egl, ctx);
+   if (use_context == CONTEXT_EGL) {
+      ret = virgl_egl_make_context_current(egl, ctx);
+      if (ret)
+         vrend_printf("%s: Error switching context: %s\n",
+                      __func__, virgl_egl_error_string(eglGetError()));
+   }
 #endif
 #ifdef HAVE_EPOXY_GLX_H
-   if (use_context == CONTEXT_GLX)
-      return virgl_glx_make_context_current(glx_info, ctx);
+   if (use_context == CONTEXT_GLX) {
+      ret = virgl_glx_make_context_current(glx_info, ctx);
+      if (ret)
+         vrend_printf("%s: Error switching context\n", __func__);
+   }
 #endif
-   return -1;
+   assert(!ret && "Failed to switch GL context");
+   return ret;
 }
 
 int vrend_winsys_has_gl_colorspace(void)
@@ -186,7 +195,8 @@
 #endif
    return use_context == CONTEXT_NONE ||
          use_context == CONTEXT_GLX ||
-         (use_context == CONTEXT_EGL && egl_colorspace);
+         (use_context == CONTEXT_EGL && egl_colorspace) ||
+         (use_context == CONTEXT_EGL_EXTERNAL && egl_colorspace);
 }
 
 int vrend_winsys_get_fourcc_for_texture(uint32_t tex_id, uint32_t format, int *fourcc)
diff --git a/src/vrend_winsys_egl.c b/src/vrend_winsys_egl.c
index 1982a76..4b38d5e 100644
--- a/src/vrend_winsys_egl.c
+++ b/src/vrend_winsys_egl.c
@@ -33,7 +33,9 @@
 #define EGL_EGLEXT_PROTOTYPES
 #include <errno.h>
 #include <fcntl.h>
+#include <poll.h>
 #include <stdbool.h>
+#include <unistd.h>
 #include <xf86drm.h>
 
 #include "util/u_memory.h"
@@ -428,6 +430,9 @@
       return NULL;
    }
 
+   gbm = virgl_gbm_init(-1);
+   egl->gbm = gbm;
+
    return egl;
 }
 
@@ -457,7 +462,7 @@
    EGLContext egl_ctx = (EGLContext)virglctx;
 
    return eglMakeCurrent(egl->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
-                         egl_ctx);
+                         egl_ctx) ? 0 : -1;
 }
 
 virgl_renderer_gl_context virgl_egl_get_current_context(UNUSED struct virgl_egl *egl)
@@ -731,13 +736,38 @@
    eglDestroySyncKHR(egl->egl_display, fence);
 }
 
-bool virgl_egl_client_wait_fence(struct virgl_egl *egl, EGLSyncKHR fence, uint64_t timeout)
+bool virgl_egl_client_wait_fence(struct virgl_egl *egl, EGLSyncKHR fence, bool blocking)
 {
-   EGLint ret = eglClientWaitSyncKHR(egl->egl_display, fence, 0, timeout);
-   if (ret == EGL_FALSE) {
-      vrend_printf("wait sync failed\n");
+   /* attempt to poll the native fence fd instead of eglClientWaitSyncKHR() to
+    * avoid Mesa's eglapi global-display-lock synchronizing vrend's sync_thread.
+    */
+   int fd = -1;
+   if (!virgl_egl_export_fence(egl, fence, &fd)) {
+      EGLint egl_result = eglClientWaitSyncKHR(egl->egl_display, fence, 0,
+                                               blocking ? EGL_FOREVER_KHR : 0);
+      if (egl_result == EGL_FALSE)
+         vrend_printf("wait sync failed\n");
+      return egl_result != EGL_TIMEOUT_EXPIRED_KHR;
    }
-   return ret != EGL_TIMEOUT_EXPIRED_KHR;
+   assert(fd >= 0);
+
+   int ret;
+   struct pollfd pfd = {
+      .fd = fd,
+      .events = POLLIN,
+   };
+   do {
+      ret = poll(&pfd, 1, blocking ? -1 : 0);
+      if (ret > 0 && (pfd.revents & (POLLERR | POLLNVAL))) {
+         ret = -1;
+         break;
+      }
+   } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
+   close(fd);
+
+   if (ret < 0)
+      vrend_printf("wait sync failed\n");
+   return ret != 0;
 }
 
 bool virgl_egl_export_signaled_fence(struct virgl_egl *egl, int *out_fd) {
@@ -753,3 +783,27 @@
 {
    return egl->different_gpu;
 }
+
+const char *virgl_egl_error_string(EGLint error)
+{
+    switch (error) {
+#define CASE_STR( value ) case value: return #value;
+    CASE_STR( EGL_SUCCESS             )
+    CASE_STR( EGL_NOT_INITIALIZED     )
+    CASE_STR( EGL_BAD_ACCESS          )
+    CASE_STR( EGL_BAD_ALLOC           )
+    CASE_STR( EGL_BAD_ATTRIBUTE       )
+    CASE_STR( EGL_BAD_CONTEXT         )
+    CASE_STR( EGL_BAD_CONFIG          )
+    CASE_STR( EGL_BAD_CURRENT_SURFACE )
+    CASE_STR( EGL_BAD_DISPLAY         )
+    CASE_STR( EGL_BAD_SURFACE         )
+    CASE_STR( EGL_BAD_MATCH           )
+    CASE_STR( EGL_BAD_PARAMETER       )
+    CASE_STR( EGL_BAD_NATIVE_PIXMAP   )
+    CASE_STR( EGL_BAD_NATIVE_WINDOW   )
+    CASE_STR( EGL_CONTEXT_LOST        )
+#undef CASE_STR
+    default: return "Unknown error";
+    }
+}
diff --git a/src/vrend_winsys_egl.h b/src/vrend_winsys_egl.h
index 0ef3e4e..132e215 100644
--- a/src/vrend_winsys_egl.h
+++ b/src/vrend_winsys_egl.h
@@ -75,8 +75,9 @@
 bool virgl_egl_supports_fences(struct virgl_egl *egl);
 EGLSyncKHR virgl_egl_fence_create(struct virgl_egl *egl);
 void virgl_egl_fence_destroy(struct virgl_egl *egl, EGLSyncKHR fence);
-bool virgl_egl_client_wait_fence(struct virgl_egl *egl, EGLSyncKHR fence, uint64_t timeout);
+bool virgl_egl_client_wait_fence(struct virgl_egl *egl, EGLSyncKHR fence, bool blocking);
 bool virgl_egl_export_signaled_fence(struct virgl_egl *egl, int *out_fd);
 bool virgl_egl_export_fence(struct virgl_egl *egl, EGLSyncKHR fence, int *out_fd);
 bool virgl_egl_different_gpu(struct virgl_egl *egl);
+const char *virgl_egl_error_string(EGLint error);
 #endif
diff --git a/src/vrend_winsys_glx.c b/src/vrend_winsys_glx.c
index 5b907ad..6670374 100644
--- a/src/vrend_winsys_glx.c
+++ b/src/vrend_winsys_glx.c
@@ -100,7 +100,7 @@
 
 int virgl_glx_make_context_current(struct virgl_glx *d, virgl_renderer_gl_context virglctx)
 {
-   return glXMakeContextCurrent(d->display, d->pbuffer, d->pbuffer, virglctx);
+   return glXMakeContextCurrent(d->display, d->pbuffer, d->pbuffer, virglctx) ? 0 : -1;
 }
 
 uint32_t virgl_glx_query_video_memory(struct virgl_glx *d)
@@ -113,4 +113,4 @@
    }
 
    return video_memory;
-}
\ No newline at end of file
+}
diff --git a/tests/fuzzer/meson.build b/tests/fuzzer/meson.build
index 5ea892c..596f89b 100644
--- a/tests/fuzzer/meson.build
+++ b/tests/fuzzer/meson.build
@@ -32,16 +32,6 @@
    dependencies : [libvirglrenderer_dep, gallium_dep, epoxy_dep]
 )
 
-if with_venus
-   virgl_venus_fuzzer = executable(
-      'virgl_venus_fuzzer',
-      'virgl_venus_fuzzer.c',
-      c_args : [ '-fsanitize=fuzzer' ],
-      link_args : [ '-fsanitize=fuzzer' ],
-      dependencies : [libvirglrenderer_dep]
-   )
-endif
-
 if with_drm
    virgl_drm_fuzzer = executable(
       'virgl_drm_fuzzer',
diff --git a/tests/fuzzer/virgl_drm_fuzzer.c b/tests/fuzzer/virgl_drm_fuzzer.c
index 5627094..2a38a4a 100644
--- a/tests/fuzzer/virgl_drm_fuzzer.c
+++ b/tests/fuzzer/virgl_drm_fuzzer.c
@@ -34,7 +34,7 @@
 static void
 fuzz_write_context_fence(UNUSED void *cookie,
                          UNUSED uint32_t ctx_id,
-                         UNUSED uint64_t queue_id,
+                         UNUSED uint32_t ring_idx,
                          UNUSED uint64_t fence_id)
 {
 
diff --git a/tests/fuzzer/virgl_venus_fuzzer.c b/tests/fuzzer/virgl_venus_fuzzer.c
deleted file mode 100644
index 49cfb4e..0000000
--- a/tests/fuzzer/virgl_venus_fuzzer.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2021 Google LLC
- * SPDX-License-Identifier: MIT
- */
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include "util/macros.h"
-#include "virglrenderer.h"
-#include "virglrenderer_hw.h"
-
-int
-LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
-
-struct fuzz_renderer {
-   bool initialized;
-};
-
-static void
-fuzz_atexit_callback(void)
-{
-   virgl_renderer_cleanup(NULL);
-}
-
-static void
-fuzz_debug_callback(UNUSED const char *fmt, UNUSED va_list ap)
-{
-   /* no logging */
-}
-
-static struct fuzz_renderer *
-fuzz_renderer_get(void)
-{
-   static struct fuzz_renderer renderer;
-   if (renderer.initialized)
-      return &renderer;
-
-   int ret =
-      virgl_renderer_init(NULL, VIRGL_RENDERER_VENUS | VIRGL_RENDERER_NO_VIRGL, NULL);
-   if (ret)
-      abort();
-
-   virgl_set_debug_callback(fuzz_debug_callback);
-
-   atexit(fuzz_atexit_callback);
-
-   renderer.initialized = true;
-   return &renderer;
-}
-
-static uint32_t
-fuzz_context_create(UNUSED struct fuzz_renderer *renderer)
-{
-   const uint32_t ctx_id = 1;
-   const char name[] = "virgl_venus_fuzzer";
-   int ret = virgl_renderer_context_create_with_flags(ctx_id, VIRGL_RENDERER_CAPSET_VENUS,
-                                                      sizeof(name), name);
-   if (ret)
-      abort();
-
-   return ctx_id;
-}
-
-static void
-fuzz_context_destroy(UNUSED struct fuzz_renderer *renderer, uint32_t ctx_id)
-{
-   virgl_renderer_context_destroy(ctx_id);
-}
-
-static void
-fuzz_context_submit(UNUSED struct fuzz_renderer *renderer,
-                    uint32_t ctx_id,
-                    const uint8_t *data,
-                    size_t size)
-{
-   virgl_renderer_submit_cmd((void *)data, ctx_id, size / 4);
-}
-
-int
-LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
-{
-   struct fuzz_renderer *renderer = fuzz_renderer_get();
-
-   const uint32_t ctx_id = fuzz_context_create(renderer);
-   fuzz_context_submit(renderer, ctx_id, data, size);
-   fuzz_context_destroy(renderer, ctx_id);
-
-   return 0;
-}
diff --git a/vtest/vtest_fuzzer.c b/vtest/vtest_fuzzer.c
index 89b12b2..7505f14 100644
--- a/vtest/vtest_fuzzer.c
+++ b/vtest/vtest_fuzzer.c
@@ -152,7 +152,7 @@
    int out_fd = open("/dev/null", O_WRONLY);
 
    struct vtest_buffer buffer;
-   buffer.buffer = data;
+   buffer.buffer = (char *)data;
    buffer.size = size;
    struct vtest_input input;
    input.data.buffer = &buffer;
diff --git a/vtest/vtest_protocol.h b/vtest/vtest_protocol.h
index f31b8e4..c48be14 100644
--- a/vtest/vtest_protocol.h
+++ b/vtest/vtest_protocol.h
@@ -153,7 +153,7 @@
 #ifdef VIRGL_RENDERER_UNSTABLE_APIS
 
 enum vcmd_param  {
-   VCMD_PARAM_MAX_SYNC_QUEUE_COUNT      = 1,
+   VCMD_PARAM_MAX_TIMELINE_COUNT = 1,
 };
 #define VCMD_GET_PARAM_SIZE 1
 #define VCMD_GET_PARAM_PARAM 0
@@ -217,7 +217,7 @@
 /* resp poll'able fd */
 
 enum vcmd_submit_cmd2_flag {
-   VCMD_SUBMIT_CMD2_FLAG_SYNC_QUEUE = 1 << 0,
+   VCMD_SUBMIT_CMD2_FLAG_RING_IDX = 1 << 0,
 };
 
 struct vcmd_submit_cmd2_batch {
@@ -230,9 +230,8 @@
    uint32_t sync_offset;
    uint32_t sync_count;
 
-   /* ignored unless VCMD_SUBMIT_CMD2_FLAG_SYNC_QUEUE is set */
-   uint32_t sync_queue_index;
-   uint64_t sync_queue_id;
+   /* ignored unless VCMD_SUBMIT_CMD2_FLAG_RING_IDX is set */
+   uint32_t ring_idx;
 };
 #define VCMD_SUBMIT_CMD2_BATCH_COUNT 0
 #define VCMD_SUBMIT_CMD2_BATCH_FLAGS(n)            (1 + 8 * (n) + 0)
@@ -240,9 +239,7 @@
 #define VCMD_SUBMIT_CMD2_BATCH_CMD_SIZE(n)         (1 + 8 * (n) + 2)
 #define VCMD_SUBMIT_CMD2_BATCH_SYNC_OFFSET(n)      (1 + 8 * (n) + 3)
 #define VCMD_SUBMIT_CMD2_BATCH_SYNC_COUNT(n)       (1 + 8 * (n) + 4)
-#define VCMD_SUBMIT_CMD2_BATCH_SYNC_QUEUE_INDEX(n) (1 + 8 * (n) + 5)
-#define VCMD_SUBMIT_CMD2_BATCH_SYNC_QUEUE_ID_LO(n) (1 + 8 * (n) + 6)
-#define VCMD_SUBMIT_CMD2_BATCH_SYNC_QUEUE_ID_HI(n) (1 + 8 * (n) + 7)
+#define VCMD_SUBMIT_CMD2_BATCH_RING_IDX(n)         (1 + 8 * (n) + 5)
 
 #endif /* VIRGL_RENDERER_UNSTABLE_APIS */
 
diff --git a/vtest/vtest_renderer.c b/vtest/vtest_renderer.c
index c44c78d..dc9ba19 100644
--- a/vtest/vtest_renderer.c
+++ b/vtest/vtest_renderer.c
@@ -56,7 +56,7 @@
 #include "util/u_pointer.h"
 #include "util/u_hash_table.h"
 
-#define VTEST_MAX_SYNC_QUEUE_COUNT 64
+#define VTEST_MAX_TIMELINE_COUNT 64
 
 struct vtest_resource {
    struct list_head head;
@@ -76,14 +76,14 @@
    uint64_t value;
 };
 
-struct vtest_sync_queue {
+struct vtest_timeline {
    struct list_head submits;
 };
 
-struct vtest_sync_queue_submit {
+struct vtest_timeline_submit {
    struct list_head head;
 
-   struct vtest_sync_queue *sync_queue;
+   struct vtest_timeline *timeline;
 
    uint32_t count;
    struct vtest_sync **syncs;
@@ -122,7 +122,7 @@
    struct util_hash_table *resource_table;
    struct util_hash_table *sync_table;
 
-   struct vtest_sync_queue sync_queues[VTEST_MAX_SYNC_QUEUE_COUNT];
+   struct vtest_timeline timelines[VTEST_MAX_TIMELINE_COUNT];
 
    struct list_head sync_waits;
 };
@@ -165,16 +165,16 @@
    renderer->implicit_fence_completed = fence_id_in;
 }
 
-static void vtest_signal_sync_queue(struct vtest_sync_queue *queue,
-                                    struct vtest_sync_queue_submit *to_submit);
+static void vtest_signal_timeline(struct vtest_timeline *timeline,
+                                  struct vtest_timeline_submit *to_submit);
 
 static void vtest_write_context_fence(UNUSED void *cookie,
                                       UNUSED uint32_t ctx_id,
-                                      UNUSED uint64_t queue_id,
+                                      UNUSED uint32_t ring_idx,
                                       uint64_t fence_id)
 {
-   struct vtest_sync_queue_submit *submit = (void*)(uintptr_t)fence_id;
-   vtest_signal_sync_queue(submit->sync_queue, submit);
+   struct vtest_timeline_submit *submit = (void*)(uintptr_t)fence_id;
+   vtest_signal_timeline(submit->timeline, submit);
 }
 
 static int vtest_get_drm_fd(void *cookie)
@@ -279,7 +279,7 @@
    list_add(&sync->head, &renderer.free_syncs);
 }
 
-static void vtest_free_sync_queue_submit(struct vtest_sync_queue_submit *submit)
+static void vtest_free_timeline_submit(struct vtest_timeline_submit *submit)
 {
    uint32_t i;
    for (i = 0; i < submit->count; i++)
@@ -299,23 +299,17 @@
    free(wait);
 }
 
-static unsigned
-u32_hash_func(void *key)
+static uint32_t
+u32_hash_func(const void *key)
 {
    intptr_t ip = pointer_to_intptr(key);
-   return (unsigned)(ip & 0xffffffff);
+   return (uint32_t)(ip & 0xffffffff);
 }
 
-static int
-u32_compare_func(void *key1, void *key2)
+static bool
+u32_equal_func(const void *key1, const void *key2)
 {
-   if (key1 < key2) {
-      return -1;
-   } else if (key1 > key2) {
-      return 1;
-   } else {
-      return 0;
-   }
+   return key1 == key2;
 }
 
 static void
@@ -523,7 +517,7 @@
       }
 
       ctx->resource_table = util_hash_table_create(u32_hash_func,
-                                                   u32_compare_func,
+                                                   u32_equal_func,
                                                    resource_destroy_func);
       if (!ctx->resource_table) {
          free(ctx);
@@ -531,7 +525,7 @@
       }
 
       ctx->sync_table = util_hash_table_create(u32_hash_func,
-                                               u32_compare_func,
+                                               u32_equal_func,
                                                sync_destroy_func);
       if (!ctx->sync_table) {
          util_hash_table_destroy(ctx->resource_table);
@@ -539,9 +533,9 @@
          return NULL;
       }
 
-      for (i = 0; i < VTEST_MAX_SYNC_QUEUE_COUNT; i++) {
-         struct vtest_sync_queue *queue = &ctx->sync_queues[i];
-         list_inithead(&queue->submits);
+      for (i = 0; i < VTEST_MAX_TIMELINE_COUNT; i++) {
+         struct vtest_timeline *timeline = &ctx->timelines[i];
+         list_inithead(&timeline->submits);
       }
 
       list_inithead(&ctx->sync_waits);
@@ -651,13 +645,13 @@
    }
    list_del(&ctx->head);
 
-   for (i = 0; i < VTEST_MAX_SYNC_QUEUE_COUNT; i++) {
-      struct vtest_sync_queue *queue = &ctx->sync_queues[i];
-      struct vtest_sync_queue_submit *submit, *submit_tmp;
+   for (i = 0; i < VTEST_MAX_TIMELINE_COUNT; i++) {
+      struct vtest_timeline *timeline = &ctx->timelines[i];
+      struct vtest_timeline_submit *submit, *submit_tmp;
 
-      LIST_FOR_EACH_ENTRY_SAFE(submit, submit_tmp, &queue->submits, head)
-         vtest_free_sync_queue_submit(submit);
-      list_inithead(&queue->submits);
+      LIST_FOR_EACH_ENTRY_SAFE(submit, submit_tmp, &timeline->submits, head)
+         vtest_free_timeline_submit(submit);
+      list_inithead(&timeline->submits);
    }
 
    LIST_FOR_EACH_ENTRY_SAFE(wait, wait_tmp, &ctx->sync_waits, head) {
@@ -783,12 +777,12 @@
    resp_buf[VTEST_CMD_ID] = VCMD_GET_PARAM;
    resp = &resp_buf[VTEST_CMD_DATA_START];
    switch (param) {
-   case VCMD_PARAM_MAX_SYNC_QUEUE_COUNT:
+   case VCMD_PARAM_MAX_TIMELINE_COUNT:
       resp[0] = true;
       /* TODO until we have a timerfd */
 #ifdef HAVE_EVENTFD_H
       if (!getenv("VIRGL_DISABLE_MT"))
-         resp[1] = VTEST_MAX_SYNC_QUEUE_COUNT;
+         resp[1] = VTEST_MAX_TIMELINE_COUNT;
       else
          resp[1] = 0;
 #else
@@ -909,7 +903,7 @@
       goto end;
    }
 
-   vtest_block_write(ctx->out_fd, caps_buf, max_size);
+   ret = vtest_block_write(ctx->out_fd, caps_buf, max_size);
    if (ret < 0) {
       goto end;
    }
@@ -943,7 +937,7 @@
       goto end;
    }
 
-   vtest_block_write(ctx->out_fd, caps_buf, max_size);
+   ret = vtest_block_write(ctx->out_fd, caps_buf, max_size);
    if (ret < 0) {
       goto end;
    }
@@ -1181,6 +1175,7 @@
       fd = -1;
       break;
    default:
+      vtest_unref_resource(res);
       return -EINVAL;
    }
 
@@ -1677,6 +1672,20 @@
    return ns + ns_per_ms * offset_ms;
 }
 
+static inline void write_ready(int fd)
+{
+#ifdef __GNUC__
+#  pragma GCC diagnostic push
+#  pragma GCC diagnostic ignored "-Wunused-result"
+#endif
+   static const uint64_t val = 1;
+   write(fd, &val, sizeof(val));
+#ifdef __GNUC__
+#  pragma GCC diagnostic pop
+#endif
+}
+
+
 /* TODO this is slow */
 static void vtest_signal_sync(struct vtest_sync *sync, uint64_t value)
 {
@@ -1720,22 +1729,20 @@
          }
 
          if (is_ready) {
-            const uint64_t val = 1;
-
             list_del(&wait->head);
-            write(wait->fd, &val, sizeof(val));
+            write_ready(wait->fd);
             vtest_free_sync_wait(wait);
          }
       }
    }
 }
 
-static void vtest_signal_sync_queue(struct vtest_sync_queue *queue,
-                                    struct vtest_sync_queue_submit *to_submit)
+static void vtest_signal_timeline(struct vtest_timeline *timeline,
+                                  struct vtest_timeline_submit *to_submit)
 {
-   struct vtest_sync_queue_submit *submit, *tmp;
+   struct vtest_timeline_submit *submit, *tmp;
 
-   LIST_FOR_EACH_ENTRY_SAFE(submit, tmp, &queue->submits, head) {
+   LIST_FOR_EACH_ENTRY_SAFE(submit, tmp, &timeline->submits, head) {
       uint32_t i;
 
       list_del(&submit->head);
@@ -1971,18 +1978,15 @@
          sync_wait_buf + 2, sync_count);
    free(sync_wait_buf);
 
-   if (ret) {
-      free(wait);
+   if (ret)
       return ret;
-   }
 
    is_ready = !wait->count;
    if ((wait->flags & VCMD_SYNC_WAIT_FLAG_ANY) && wait->count < sync_count)
       is_ready = true;
 
    if (is_ready) {
-      const uint64_t val = 1;
-      write(wait->fd, &val, sizeof(val));
+      write_ready(wait->fd);
    }
 
    resp_buf[VTEST_CMD_LEN] = 0;
@@ -2004,7 +2008,7 @@
                                    const uint32_t *cmds,
                                    const uint32_t *syncs)
 {
-   struct vtest_sync_queue_submit *submit = NULL;
+   struct vtest_timeline_submit *submit = NULL;
    uint32_t i;
    int ret;
 
@@ -2015,7 +2019,7 @@
    if (!batch->sync_count)
       return 0;
 
-   if (batch->flags & VCMD_SUBMIT_CMD2_FLAG_SYNC_QUEUE) {
+   if (batch->flags & VCMD_SUBMIT_CMD2_FLAG_RING_IDX) {
       submit = malloc(sizeof(*submit) +
                       sizeof(*submit->syncs) * batch->sync_count +
                       sizeof(*submit->values) * batch->sync_count);
@@ -2049,25 +2053,25 @@
    if (i < batch->sync_count) {
       if (submit) {
          submit->count = i;
-         vtest_free_sync_queue_submit(submit);
+         vtest_free_timeline_submit(submit);
       }
       return -EEXIST;
    }
 
    if (submit) {
-      struct vtest_sync_queue *queue = &ctx->sync_queues[batch->sync_queue_index];
+      struct vtest_timeline *timeline = &ctx->timelines[batch->ring_idx];
 
-      submit->sync_queue = queue;
+      submit->timeline = timeline;
       ret = virgl_renderer_context_create_fence(ctx->ctx_id,
                                                 VIRGL_RENDERER_FENCE_FLAG_MERGEABLE,
-                                                batch->sync_queue_id,
+                                                batch->ring_idx,
                                                 (uintptr_t)submit);
       if (ret) {
-         vtest_free_sync_queue_submit(submit);
+         vtest_free_timeline_submit(submit);
          return ret;
       }
 
-      list_addtail(&submit->head, &queue->submits);
+      list_addtail(&submit->head, &timeline->submits);
    }
 
    return 0;
@@ -2095,7 +2099,7 @@
    }
 
    batch_count = submit_cmd2_buf[VCMD_SUBMIT_CMD2_BATCH_COUNT];
-   if (VCMD_SUBMIT_CMD2_BATCH_COUNT + 8 * batch_count > length_dw) {
+   if (VCMD_SUBMIT_CMD2_BATCH_COUNT + 6 * batch_count > length_dw) {
       free(submit_cmd2_buf);
       return -EINVAL;
    }
@@ -2107,16 +2111,14 @@
          .cmd_size = submit_cmd2_buf[VCMD_SUBMIT_CMD2_BATCH_CMD_SIZE(i)],
          .sync_offset = submit_cmd2_buf[VCMD_SUBMIT_CMD2_BATCH_SYNC_OFFSET(i)],
          .sync_count = submit_cmd2_buf[VCMD_SUBMIT_CMD2_BATCH_SYNC_COUNT(i)],
-         .sync_queue_index = submit_cmd2_buf[VCMD_SUBMIT_CMD2_BATCH_SYNC_QUEUE_INDEX(i)],
-         .sync_queue_id = submit_cmd2_buf[VCMD_SUBMIT_CMD2_BATCH_SYNC_QUEUE_ID_LO(i)] |
-                          (uint64_t)submit_cmd2_buf[VCMD_SUBMIT_CMD2_BATCH_SYNC_QUEUE_ID_HI(i)] << 32,
+         .ring_idx = submit_cmd2_buf[VCMD_SUBMIT_CMD2_BATCH_RING_IDX(i)],
       };
       const uint32_t *cmds = &submit_cmd2_buf[batch.cmd_offset];
       const uint32_t *syncs = &submit_cmd2_buf[batch.sync_offset];
 
       if (batch.cmd_offset + batch.cmd_size > length_dw ||
           batch.sync_offset + batch.sync_count * 3 > length_dw ||
-          batch.sync_queue_index >= VTEST_MAX_SYNC_QUEUE_COUNT) {
+          batch.ring_idx >= VTEST_MAX_TIMELINE_COUNT) {
          free(submit_cmd2_buf);
          return -EINVAL;
       }
diff --git a/vtest/vtest_server.c b/vtest/vtest_server.c
index bb9ceec..a6339aa 100644
--- a/vtest/vtest_server.c
+++ b/vtest/vtest_server.c
@@ -165,6 +165,7 @@
 #define OPT_RENDERNODE 'r'
 #define OPT_VENUS 'v'
 #define OPT_RENDER_SERVER 'n'
+#define OPT_SOCKET_PATH 'p'
 
 static void vtest_server_parse_args(int argc, char **argv)
 {
@@ -180,6 +181,7 @@
       {"rendernode",          required_argument, NULL, OPT_RENDERNODE},
       {"venus",               no_argument, NULL, OPT_VENUS},
       {"render-server",       no_argument, NULL, OPT_RENDER_SERVER},
+      {"socket-path",         optional_argument, NULL, OPT_SOCKET_PATH},
       {0, 0, 0, 0}
    };
 
@@ -225,10 +227,13 @@
          server.render_server = true;
          break;
 #endif
+      case OPT_SOCKET_PATH:
+         server.socket_name = optarg;
+         break;
       default:
          printf("Usage: %s [--no-fork] [--no-loop-or-fork] [--multi-clients] "
                 "[--use-glx] [--use-egl-surfaceless] [--use-gles] "
-                "[--rendernode <dev>]"
+                "[--rendernode <dev>] [--socket-path <path>] "
 #ifdef ENABLE_VENUS
                 " [--venus]"
 #endif