From 3f13df4d019cfcbef3f9909e3b993896d3c934e6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 11:22:22 +0200 Subject: Adding upstream version 2.4.114. Signed-off-by: Daniel Baumann --- .editorconfig | 23 + .gitignore | 1 + .gitlab-ci.yml | 265 ++ Android.common.mk | 22 + Android.mk | 74 + CONTRIBUTING.rst | 105 + CleanSpec.mk | 4 + Makefile.sources | 45 + README.rst | 51 + RELEASING | 40 + amdgpu/.editorconfig | 13 + amdgpu/Android.mk | 19 + amdgpu/Makefile.sources | 14 + amdgpu/amdgpu-symbols.txt | 77 + amdgpu/amdgpu.h | 1876 +++++++++++ amdgpu/amdgpu_asic_id.c | 161 + amdgpu/amdgpu_bo.c | 791 +++++ amdgpu/amdgpu_cs.c | 972 ++++++ amdgpu/amdgpu_device.c | 316 ++ amdgpu/amdgpu_gpu_info.c | 348 +++ amdgpu/amdgpu_internal.h | 176 ++ amdgpu/amdgpu_vamgr.c | 298 ++ amdgpu/amdgpu_vm.c | 50 + amdgpu/handle_table.c | 72 + amdgpu/handle_table.h | 41 + amdgpu/libdrm_amdgpu.pc.in | 11 + amdgpu/meson.build | 70 + android/gralloc_handle.h | 111 + core-symbols.txt | 209 ++ data/Android.mk | 10 + data/amdgpu.ids | 487 +++ data/meson.build | 27 + etnaviv/Android.mk | 14 + etnaviv/Makefile.sources | 13 + etnaviv/etnaviv-symbols.txt | 36 + etnaviv/etnaviv_bo.c | 340 ++ etnaviv/etnaviv_bo_cache.c | 204 ++ etnaviv/etnaviv_cmd_stream.c | 279 ++ etnaviv/etnaviv_device.c | 115 + etnaviv/etnaviv_drm.h | 300 ++ etnaviv/etnaviv_drmif.h | 214 ++ etnaviv/etnaviv_gpu.c | 155 + etnaviv/etnaviv_perfmon.c | 185 ++ etnaviv/etnaviv_pipe.c | 79 + etnaviv/etnaviv_priv.h | 208 ++ etnaviv/libdrm_etnaviv.pc.in | 11 + etnaviv/meson.build | 66 + exynos/exynos-symbols.txt | 23 + exynos/exynos_drm.c | 444 +++ exynos/exynos_drm.h | 172 ++ exynos/exynos_drmif.h | 120 + exynos/exynos_fimg2d.c | 1010 ++++++ exynos/exynos_fimg2d.h | 333 ++ exynos/fimg2d_reg.h | 127 + exynos/libdrm_exynos.pc.in | 11 + exynos/meson.build | 61 + freedreno/Android.mk | 14 + freedreno/Makefile.sources | 25 + freedreno/freedreno-symbols.txt | 45 + freedreno/freedreno_bo.c | 359 +++ freedreno/freedreno_bo_cache.c | 220 ++ freedreno/freedreno_device.c | 145 + freedreno/freedreno_drmif.h | 140 + freedreno/freedreno_pipe.c | 102 + freedreno/freedreno_priv.h | 258 ++ freedreno/freedreno_ringbuffer.c | 182 ++ freedreno/freedreno_ringbuffer.h | 142 + freedreno/kgsl/README | 26 + freedreno/kgsl/kgsl_bo.c | 311 ++ freedreno/kgsl/kgsl_device.c | 63 + freedreno/kgsl/kgsl_drm.h | 192 ++ freedreno/kgsl/kgsl_pipe.c | 282 ++ freedreno/kgsl/kgsl_priv.h | 120 + freedreno/kgsl/kgsl_ringbuffer.c | 235 ++ freedreno/kgsl/msm_kgsl.h | 519 ++++ freedreno/libdrm_freedreno.pc.in | 11 + freedreno/meson.build | 82 + freedreno/msm/msm_bo.c | 170 + freedreno/msm/msm_device.c | 63 + freedreno/msm/msm_pipe.c | 212 ++ freedreno/msm/msm_priv.h | 141 + freedreno/msm/msm_ringbuffer.c | 723 +++++ gen_table_fourcc.py | 84 + include/drm/README | 128 + include/drm/amdgpu_drm.h | 1161 +++++++ include/drm/drm.h | 1183 +++++++ include/drm/drm_fourcc.h | 1459 +++++++++ include/drm/drm_mode.h | 1129 +++++++ include/drm/drm_sarea.h | 92 + include/drm/i915_drm.h | 3724 ++++++++++++++++++++++ include/drm/mach64_drm.h | 256 ++ include/drm/mga_drm.h | 427 +++ include/drm/msm_drm.h | 308 ++ include/drm/nouveau_drm.h | 256 ++ include/drm/qxl_drm.h | 158 + include/drm/r128_drm.h | 336 ++ include/drm/radeon_drm.h | 1079 +++++++ include/drm/savage_drm.h | 220 ++ include/drm/sis_drm.h | 77 + include/drm/tegra_drm.h | 1060 +++++++ include/drm/vc4_drm.h | 442 +++ include/drm/via_drm.h | 283 ++ include/drm/virtgpu_drm.h | 182 ++ include/drm/vmwgfx_drm.h | 1128 +++++++ intel/.gitignore | 1 + intel/Android.mk | 38 + intel/Makefile.sources | 17 + intel/i915_pciids.h | 750 +++++ intel/intel-symbols.txt | 83 + intel/intel_aub.h | 153 + intel/intel_bufmgr.c | 382 +++ intel/intel_bufmgr.h | 341 ++ intel/intel_bufmgr_fake.c | 1626 ++++++++++ intel/intel_bufmgr_gem.c | 3748 ++++++++++++++++++++++ intel/intel_bufmgr_priv.h | 325 ++ intel/intel_chipset.c | 98 + intel/intel_chipset.h | 350 +++ intel/intel_debug.h | 44 + intel/intel_decode.c | 3983 ++++++++++++++++++++++++ intel/libdrm_intel.pc.in | 11 + intel/meson.build | 109 + intel/mm.c | 260 ++ intel/mm.h | 80 + intel/test_decode.c | 195 ++ intel/tests/.gitignore | 1 + intel/tests/gen4-3d.batch | Bin 0 -> 1952 bytes intel/tests/gen4-3d.batch-ref.txt | 488 +++ intel/tests/gen4-3d.batch.sh | 1 + intel/tests/gen5-3d.batch | Bin 0 -> 2048 bytes intel/tests/gen5-3d.batch-ref.txt | 512 +++ intel/tests/gen5-3d.batch.sh | 1 + intel/tests/gen6-3d.batch | Bin 0 -> 3960 bytes intel/tests/gen6-3d.batch-ref.txt | 990 ++++++ intel/tests/gen6-3d.batch.sh | 1 + intel/tests/gen7-2d-copy.batch | Bin 0 -> 56 bytes intel/tests/gen7-2d-copy.batch-ref.txt | 14 + intel/tests/gen7-2d-copy.batch.sh | 1 + intel/tests/gen7-3d.batch | Bin 0 -> 848 bytes intel/tests/gen7-3d.batch-ref.txt | 212 ++ intel/tests/gen7-3d.batch.sh | 1 + intel/tests/gm45-3d.batch | Bin 0 -> 1952 bytes intel/tests/gm45-3d.batch-ref.txt | 488 +++ intel/tests/gm45-3d.batch.sh | 1 + intel/tests/test-batch.sh | 20 + intel/uthash.h | 1074 +++++++ libdrm.pc.in | 10 + libdrm_lists.h | 118 + libdrm_macros.h | 87 + libsync.h | 148 + man/drm-kms.7.rst | 229 ++ man/drm-memory.7.rst | 313 ++ man/drm.7.rst | 91 + man/drmAvailable.3.rst | 41 + man/drmHandleEvent.3.rst | 62 + man/drmModeGetResources.3.rst | 92 + man/meson.build | 40 + meson.build | 395 +++ meson_options.txt | 117 + nouveau/Android.mk | 14 + nouveau/Makefile.sources | 9 + nouveau/abi16.c | 359 +++ nouveau/bufctx.c | 160 + nouveau/libdrm_nouveau.pc.in | 11 + nouveau/meson.build | 65 + nouveau/nouveau-symbols.txt | 42 + nouveau/nouveau.c | 887 ++++++ nouveau/nouveau.h | 280 ++ nouveau/nvif/cl0080.h | 45 + nouveau/nvif/cl9097.h | 44 + nouveau/nvif/class.h | 141 + nouveau/nvif/if0002.h | 38 + nouveau/nvif/if0003.h | 33 + nouveau/nvif/ioctl.h | 132 + nouveau/nvif/unpack.h | 28 + nouveau/private.h | 127 + nouveau/pushbuf.c | 800 +++++ omap/Android.mk | 13 + omap/libdrm_omap.pc.in | 11 + omap/meson.build | 61 + omap/omap-symbols.txt | 18 + omap/omap_drm.c | 468 +++ omap/omap_drm.h | 135 + omap/omap_drmif.h | 65 + radeon/Android.mk | 14 + radeon/Makefile.sources | 21 + radeon/bof.c | 477 +++ radeon/bof.h | 90 + radeon/libdrm_radeon.pc.in | 11 + radeon/meson.build | 70 + radeon/r600_pci_ids.h | 487 +++ radeon/radeon-symbols.txt | 44 + radeon/radeon_bo.c | 142 + radeon/radeon_bo.h | 73 + radeon/radeon_bo_gem.c | 399 +++ radeon/radeon_bo_gem.h | 48 + radeon/radeon_bo_int.h | 45 + radeon/radeon_cs.c | 95 + radeon/radeon_cs.h | 141 + radeon/radeon_cs_gem.c | 556 ++++ radeon/radeon_cs_gem.h | 41 + radeon/radeon_cs_int.h | 67 + radeon/radeon_cs_space.c | 248 ++ radeon/radeon_surface.c | 2566 +++++++++++++++ radeon/radeon_surface.h | 149 + symbols-check.py | 130 + tegra/.gitignore | 1 + tegra/channel.c | 195 ++ tegra/job.c | 187 ++ tegra/libdrm_tegra.pc.in | 11 + tegra/meson.build | 64 + tegra/private.h | 118 + tegra/pushbuf.c | 184 ++ tegra/syncpt.c | 101 + tegra/tegra-symbols.txt | 32 + tegra/tegra.c | 354 +++ tegra/tegra.h | 127 + tests/Android.mk | 1 + tests/amdgpu/.editorconfig | 1 + tests/amdgpu/amdgpu_stress.c | 418 +++ tests/amdgpu/amdgpu_test.c | 830 +++++ tests/amdgpu/amdgpu_test.h | 546 ++++ tests/amdgpu/basic_tests.c | 2556 +++++++++++++++ tests/amdgpu/bo_tests.c | 317 ++ tests/amdgpu/cp_dma_tests.c | 533 ++++ tests/amdgpu/cs_tests.c | 471 +++ tests/amdgpu/deadlock_tests.c | 696 +++++ tests/amdgpu/decode_messages.h | 881 ++++++ tests/amdgpu/frame.h | 1949 ++++++++++++ tests/amdgpu/hotunplug_tests.c | 443 +++ tests/amdgpu/jpeg_tests.c | 579 ++++ tests/amdgpu/meson.build | 46 + tests/amdgpu/ras_tests.c | 1003 ++++++ tests/amdgpu/security_tests.c | 486 +++ tests/amdgpu/shader_code.h | 153 + tests/amdgpu/shader_code_gfx10.h | 202 ++ tests/amdgpu/shader_code_gfx11.h | 320 ++ tests/amdgpu/shader_code_gfx9.h | 204 ++ tests/amdgpu/shader_code_hang.h | 104 + tests/amdgpu/shader_test_util.c | 2156 +++++++++++++ tests/amdgpu/syncobj_tests.c | 314 ++ tests/amdgpu/uvd_enc_tests.c | 491 +++ tests/amdgpu/uve_ib.h | 527 ++++ tests/amdgpu/vce_ib.h | 335 ++ tests/amdgpu/vce_tests.c | 764 +++++ tests/amdgpu/vcn_tests.c | 1635 ++++++++++ tests/amdgpu/vm_tests.c | 270 ++ tests/drmdevice.c | 164 + tests/drmsl.c | 184 ++ tests/etnaviv/cmdstream.xml.h | 242 ++ tests/etnaviv/etnaviv_2d_test.c | 290 ++ tests/etnaviv/etnaviv_bo_cache_test.c | 117 + tests/etnaviv/etnaviv_cmd_stream_test.c | 123 + tests/etnaviv/meson.build | 45 + tests/etnaviv/state.xml.h | 375 +++ tests/etnaviv/state_2d.xml.h | 1497 +++++++++ tests/etnaviv/write_bmp.c | 149 + tests/etnaviv/write_bmp.h | 34 + tests/exynos/exynos_fimg2d_event.c | 333 ++ tests/exynos/exynos_fimg2d_perf.c | 327 ++ tests/exynos/exynos_fimg2d_test.c | 903 ++++++ tests/exynos/meson.build | 51 + tests/hash.c | 217 ++ tests/meson.build | 74 + tests/modeprint/meson.build | 29 + tests/modeprint/modeprint.c | 418 +++ tests/modetest/Android.mk | 14 + tests/modetest/Makefile.sources | 6 + tests/modetest/buffers.c | 340 ++ tests/modetest/buffers.h | 40 + tests/modetest/cursor.c | 206 ++ tests/modetest/cursor.h | 33 + tests/modetest/meson.build | 29 + tests/modetest/modetest.c | 2285 ++++++++++++++ tests/nouveau/.gitignore | 1 + tests/nouveau/meson.build | 30 + tests/nouveau/threaded.c | 156 + tests/proptest/Android.mk | 14 + tests/proptest/Makefile.sources | 2 + tests/proptest/meson.build | 28 + tests/proptest/proptest.c | 325 ++ tests/radeon/meson.build | 27 + tests/radeon/radeon_ttm.c | 77 + tests/radeon/rbo.c | 171 + tests/radeon/rbo.h | 50 + tests/tegra/.gitignore | 2 + tests/tegra/drm-test-tegra.c | 147 + tests/tegra/drm-test-tegra.h | 55 + tests/tegra/drm-test.c | 248 ++ tests/tegra/drm-test.h | 72 + tests/tegra/gr2d-fill.c | 146 + tests/tegra/host1x.h | 34 + tests/tegra/meson.build | 111 + tests/tegra/openclose.c | 67 + tests/tegra/syncpt-timeout.c | 163 + tests/tegra/syncpt-wait.c | 151 + tests/tegra/vic-blit.c | 333 ++ tests/tegra/vic-clear.c | 173 ++ tests/tegra/vic-flip.c | 333 ++ tests/tegra/vic.c | 184 ++ tests/tegra/vic.h | 181 ++ tests/tegra/vic30.c | 458 +++ tests/tegra/vic30.h | 439 +++ tests/tegra/vic40.c | 338 ++ tests/tegra/vic40.h | 285 ++ tests/tegra/vic41.c | 342 ++ tests/tegra/vic41.h | 372 +++ tests/tegra/vic42.c | 342 ++ tests/tegra/vic42.h | 597 ++++ tests/ttmtest/AUTHORS | 1 + tests/ttmtest/ChangeLog | 23 + tests/ttmtest/Makefile.am | 1 + tests/ttmtest/NEWS | 0 tests/ttmtest/README | 0 tests/ttmtest/configure.ac | 33 + tests/ttmtest/reconf | 2 + tests/ttmtest/src/Makefile.am | 8 + tests/ttmtest/src/ttmtest.c | 430 +++ tests/ttmtest/src/xf86dri.c | 603 ++++ tests/ttmtest/src/xf86dri.h | 116 + tests/ttmtest/src/xf86dristr.h | 390 +++ tests/util/Android.mk | 38 + tests/util/Makefile.sources | 8 + tests/util/common.h | 33 + tests/util/format.c | 123 + tests/util/format.h | 65 + tests/util/kms.c | 163 + tests/util/kms.h | 34 + tests/util/meson.build | 28 + tests/util/pattern.c | 1282 ++++++++ tests/util/pattern.h | 46 + tests/vbltest/meson.build | 28 + tests/vbltest/vbltest.c | 186 ++ util_double_list.h | 143 + util_math.h | 34 + vc4/Makefile.sources | 3 + vc4/libdrm_vc4.pc.in | 9 + vc4/meson.build | 28 + vc4/vc4_packet.h | 397 +++ vc4/vc4_qpu_defines.h | 274 ++ xf86atomic.h | 114 + xf86drm.c | 5148 +++++++++++++++++++++++++++++++ xf86drm.h | 969 ++++++ xf86drmHash.c | 242 ++ xf86drmHash.h | 47 + xf86drmMode.c | 1874 +++++++++++ xf86drmMode.h | 536 ++++ xf86drmRandom.c | 138 + xf86drmRandom.h | 35 + xf86drmSL.c | 319 ++ 349 files changed, 108830 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 .gitlab-ci.yml create mode 100644 Android.common.mk create mode 100644 Android.mk create mode 100644 CONTRIBUTING.rst create mode 100644 CleanSpec.mk create mode 100644 Makefile.sources create mode 100644 README.rst create mode 100644 RELEASING create mode 100644 amdgpu/.editorconfig create mode 100644 amdgpu/Android.mk create mode 100644 amdgpu/Makefile.sources create mode 100644 amdgpu/amdgpu-symbols.txt create mode 100644 amdgpu/amdgpu.h create mode 100644 amdgpu/amdgpu_asic_id.c create mode 100644 amdgpu/amdgpu_bo.c create mode 100644 amdgpu/amdgpu_cs.c create mode 100644 amdgpu/amdgpu_device.c create mode 100644 amdgpu/amdgpu_gpu_info.c create mode 100644 amdgpu/amdgpu_internal.h create mode 100644 amdgpu/amdgpu_vamgr.c create mode 100644 amdgpu/amdgpu_vm.c create mode 100644 amdgpu/handle_table.c create mode 100644 amdgpu/handle_table.h create mode 100644 amdgpu/libdrm_amdgpu.pc.in create mode 100644 amdgpu/meson.build create mode 100644 android/gralloc_handle.h create mode 100644 core-symbols.txt create mode 100644 data/Android.mk create mode 100644 data/amdgpu.ids create mode 100644 data/meson.build create mode 100644 etnaviv/Android.mk create mode 100644 etnaviv/Makefile.sources create mode 100644 etnaviv/etnaviv-symbols.txt create mode 100644 etnaviv/etnaviv_bo.c create mode 100644 etnaviv/etnaviv_bo_cache.c create mode 100644 etnaviv/etnaviv_cmd_stream.c create mode 100644 etnaviv/etnaviv_device.c create mode 100644 etnaviv/etnaviv_drm.h create mode 100644 etnaviv/etnaviv_drmif.h create mode 100644 etnaviv/etnaviv_gpu.c create mode 100644 etnaviv/etnaviv_perfmon.c create mode 100644 etnaviv/etnaviv_pipe.c create mode 100644 etnaviv/etnaviv_priv.h create mode 100644 etnaviv/libdrm_etnaviv.pc.in create mode 100644 etnaviv/meson.build create mode 100644 exynos/exynos-symbols.txt create mode 100644 exynos/exynos_drm.c create mode 100644 exynos/exynos_drm.h create mode 100644 exynos/exynos_drmif.h create mode 100644 exynos/exynos_fimg2d.c create mode 100644 exynos/exynos_fimg2d.h create mode 100644 exynos/fimg2d_reg.h create mode 100644 exynos/libdrm_exynos.pc.in create mode 100644 exynos/meson.build create mode 100644 freedreno/Android.mk create mode 100644 freedreno/Makefile.sources create mode 100644 freedreno/freedreno-symbols.txt create mode 100644 freedreno/freedreno_bo.c create mode 100644 freedreno/freedreno_bo_cache.c create mode 100644 freedreno/freedreno_device.c create mode 100644 freedreno/freedreno_drmif.h create mode 100644 freedreno/freedreno_pipe.c create mode 100644 freedreno/freedreno_priv.h create mode 100644 freedreno/freedreno_ringbuffer.c create mode 100644 freedreno/freedreno_ringbuffer.h create mode 100644 freedreno/kgsl/README create mode 100644 freedreno/kgsl/kgsl_bo.c create mode 100644 freedreno/kgsl/kgsl_device.c create mode 100644 freedreno/kgsl/kgsl_drm.h create mode 100644 freedreno/kgsl/kgsl_pipe.c create mode 100644 freedreno/kgsl/kgsl_priv.h create mode 100644 freedreno/kgsl/kgsl_ringbuffer.c create mode 100644 freedreno/kgsl/msm_kgsl.h create mode 100644 freedreno/libdrm_freedreno.pc.in create mode 100644 freedreno/meson.build create mode 100644 freedreno/msm/msm_bo.c create mode 100644 freedreno/msm/msm_device.c create mode 100644 freedreno/msm/msm_pipe.c create mode 100644 freedreno/msm/msm_priv.h create mode 100644 freedreno/msm/msm_ringbuffer.c create mode 100644 gen_table_fourcc.py create mode 100644 include/drm/README create mode 100644 include/drm/amdgpu_drm.h create mode 100644 include/drm/drm.h create mode 100644 include/drm/drm_fourcc.h create mode 100644 include/drm/drm_mode.h create mode 100644 include/drm/drm_sarea.h create mode 100644 include/drm/i915_drm.h create mode 100644 include/drm/mach64_drm.h create mode 100644 include/drm/mga_drm.h create mode 100644 include/drm/msm_drm.h create mode 100644 include/drm/nouveau_drm.h create mode 100644 include/drm/qxl_drm.h create mode 100644 include/drm/r128_drm.h create mode 100644 include/drm/radeon_drm.h create mode 100644 include/drm/savage_drm.h create mode 100644 include/drm/sis_drm.h create mode 100644 include/drm/tegra_drm.h create mode 100644 include/drm/vc4_drm.h create mode 100644 include/drm/via_drm.h create mode 100644 include/drm/virtgpu_drm.h create mode 100644 include/drm/vmwgfx_drm.h create mode 100644 intel/.gitignore create mode 100644 intel/Android.mk create mode 100644 intel/Makefile.sources create mode 100644 intel/i915_pciids.h create mode 100644 intel/intel-symbols.txt create mode 100644 intel/intel_aub.h create mode 100644 intel/intel_bufmgr.c create mode 100644 intel/intel_bufmgr.h create mode 100644 intel/intel_bufmgr_fake.c create mode 100644 intel/intel_bufmgr_gem.c create mode 100644 intel/intel_bufmgr_priv.h create mode 100644 intel/intel_chipset.c create mode 100644 intel/intel_chipset.h create mode 100644 intel/intel_debug.h create mode 100644 intel/intel_decode.c create mode 100644 intel/libdrm_intel.pc.in create mode 100644 intel/meson.build create mode 100644 intel/mm.c create mode 100644 intel/mm.h create mode 100644 intel/test_decode.c create mode 100644 intel/tests/.gitignore create mode 100644 intel/tests/gen4-3d.batch create mode 100644 intel/tests/gen4-3d.batch-ref.txt create mode 120000 intel/tests/gen4-3d.batch.sh create mode 100644 intel/tests/gen5-3d.batch create mode 100644 intel/tests/gen5-3d.batch-ref.txt create mode 120000 intel/tests/gen5-3d.batch.sh create mode 100644 intel/tests/gen6-3d.batch create mode 100644 intel/tests/gen6-3d.batch-ref.txt create mode 120000 intel/tests/gen6-3d.batch.sh create mode 100644 intel/tests/gen7-2d-copy.batch create mode 100644 intel/tests/gen7-2d-copy.batch-ref.txt create mode 120000 intel/tests/gen7-2d-copy.batch.sh create mode 100644 intel/tests/gen7-3d.batch create mode 100644 intel/tests/gen7-3d.batch-ref.txt create mode 120000 intel/tests/gen7-3d.batch.sh create mode 100644 intel/tests/gm45-3d.batch create mode 100644 intel/tests/gm45-3d.batch-ref.txt create mode 120000 intel/tests/gm45-3d.batch.sh create mode 100755 intel/tests/test-batch.sh create mode 100644 intel/uthash.h create mode 100644 libdrm.pc.in create mode 100644 libdrm_lists.h create mode 100644 libdrm_macros.h create mode 100644 libsync.h create mode 100644 man/drm-kms.7.rst create mode 100644 man/drm-memory.7.rst create mode 100644 man/drm.7.rst create mode 100644 man/drmAvailable.3.rst create mode 100644 man/drmHandleEvent.3.rst create mode 100644 man/drmModeGetResources.3.rst create mode 100644 man/meson.build create mode 100644 meson.build create mode 100644 meson_options.txt create mode 100644 nouveau/Android.mk create mode 100644 nouveau/Makefile.sources create mode 100644 nouveau/abi16.c create mode 100644 nouveau/bufctx.c create mode 100644 nouveau/libdrm_nouveau.pc.in create mode 100644 nouveau/meson.build create mode 100644 nouveau/nouveau-symbols.txt create mode 100644 nouveau/nouveau.c create mode 100644 nouveau/nouveau.h create mode 100644 nouveau/nvif/cl0080.h create mode 100644 nouveau/nvif/cl9097.h create mode 100644 nouveau/nvif/class.h create mode 100644 nouveau/nvif/if0002.h create mode 100644 nouveau/nvif/if0003.h create mode 100644 nouveau/nvif/ioctl.h create mode 100644 nouveau/nvif/unpack.h create mode 100644 nouveau/private.h create mode 100644 nouveau/pushbuf.c create mode 100644 omap/Android.mk create mode 100644 omap/libdrm_omap.pc.in create mode 100644 omap/meson.build create mode 100644 omap/omap-symbols.txt create mode 100644 omap/omap_drm.c create mode 100644 omap/omap_drm.h create mode 100644 omap/omap_drmif.h create mode 100644 radeon/Android.mk create mode 100644 radeon/Makefile.sources create mode 100644 radeon/bof.c create mode 100644 radeon/bof.h create mode 100644 radeon/libdrm_radeon.pc.in create mode 100644 radeon/meson.build create mode 100644 radeon/r600_pci_ids.h create mode 100644 radeon/radeon-symbols.txt create mode 100644 radeon/radeon_bo.c create mode 100644 radeon/radeon_bo.h create mode 100644 radeon/radeon_bo_gem.c create mode 100644 radeon/radeon_bo_gem.h create mode 100644 radeon/radeon_bo_int.h create mode 100644 radeon/radeon_cs.c create mode 100644 radeon/radeon_cs.h create mode 100644 radeon/radeon_cs_gem.c create mode 100644 radeon/radeon_cs_gem.h create mode 100644 radeon/radeon_cs_int.h create mode 100644 radeon/radeon_cs_space.c create mode 100644 radeon/radeon_surface.c create mode 100644 radeon/radeon_surface.h create mode 100644 symbols-check.py create mode 100644 tegra/.gitignore create mode 100644 tegra/channel.c create mode 100644 tegra/job.c create mode 100644 tegra/libdrm_tegra.pc.in create mode 100644 tegra/meson.build create mode 100644 tegra/private.h create mode 100644 tegra/pushbuf.c create mode 100644 tegra/syncpt.c create mode 100644 tegra/tegra-symbols.txt create mode 100644 tegra/tegra.c create mode 100644 tegra/tegra.h create mode 100644 tests/Android.mk create mode 120000 tests/amdgpu/.editorconfig create mode 100644 tests/amdgpu/amdgpu_stress.c create mode 100644 tests/amdgpu/amdgpu_test.c create mode 100644 tests/amdgpu/amdgpu_test.h create mode 100644 tests/amdgpu/basic_tests.c create mode 100644 tests/amdgpu/bo_tests.c create mode 100644 tests/amdgpu/cp_dma_tests.c create mode 100644 tests/amdgpu/cs_tests.c create mode 100644 tests/amdgpu/deadlock_tests.c create mode 100644 tests/amdgpu/decode_messages.h create mode 100644 tests/amdgpu/frame.h create mode 100644 tests/amdgpu/hotunplug_tests.c create mode 100644 tests/amdgpu/jpeg_tests.c create mode 100644 tests/amdgpu/meson.build create mode 100644 tests/amdgpu/ras_tests.c create mode 100644 tests/amdgpu/security_tests.c create mode 100644 tests/amdgpu/shader_code.h create mode 100644 tests/amdgpu/shader_code_gfx10.h create mode 100644 tests/amdgpu/shader_code_gfx11.h create mode 100644 tests/amdgpu/shader_code_gfx9.h create mode 100644 tests/amdgpu/shader_code_hang.h create mode 100644 tests/amdgpu/shader_test_util.c create mode 100644 tests/amdgpu/syncobj_tests.c create mode 100644 tests/amdgpu/uvd_enc_tests.c create mode 100644 tests/amdgpu/uve_ib.h create mode 100644 tests/amdgpu/vce_ib.h create mode 100644 tests/amdgpu/vce_tests.c create mode 100644 tests/amdgpu/vcn_tests.c create mode 100644 tests/amdgpu/vm_tests.c create mode 100644 tests/drmdevice.c create mode 100644 tests/drmsl.c create mode 100644 tests/etnaviv/cmdstream.xml.h create mode 100644 tests/etnaviv/etnaviv_2d_test.c create mode 100644 tests/etnaviv/etnaviv_bo_cache_test.c create mode 100644 tests/etnaviv/etnaviv_cmd_stream_test.c create mode 100644 tests/etnaviv/meson.build create mode 100644 tests/etnaviv/state.xml.h create mode 100644 tests/etnaviv/state_2d.xml.h create mode 100644 tests/etnaviv/write_bmp.c create mode 100644 tests/etnaviv/write_bmp.h create mode 100644 tests/exynos/exynos_fimg2d_event.c create mode 100644 tests/exynos/exynos_fimg2d_perf.c create mode 100644 tests/exynos/exynos_fimg2d_test.c create mode 100644 tests/exynos/meson.build create mode 100644 tests/hash.c create mode 100644 tests/meson.build create mode 100644 tests/modeprint/meson.build create mode 100644 tests/modeprint/modeprint.c create mode 100644 tests/modetest/Android.mk create mode 100644 tests/modetest/Makefile.sources create mode 100644 tests/modetest/buffers.c create mode 100644 tests/modetest/buffers.h create mode 100644 tests/modetest/cursor.c create mode 100644 tests/modetest/cursor.h create mode 100644 tests/modetest/meson.build create mode 100644 tests/modetest/modetest.c create mode 100644 tests/nouveau/.gitignore create mode 100644 tests/nouveau/meson.build create mode 100644 tests/nouveau/threaded.c create mode 100644 tests/proptest/Android.mk create mode 100644 tests/proptest/Makefile.sources create mode 100644 tests/proptest/meson.build create mode 100644 tests/proptest/proptest.c create mode 100644 tests/radeon/meson.build create mode 100644 tests/radeon/radeon_ttm.c create mode 100644 tests/radeon/rbo.c create mode 100644 tests/radeon/rbo.h create mode 100644 tests/tegra/.gitignore create mode 100644 tests/tegra/drm-test-tegra.c create mode 100644 tests/tegra/drm-test-tegra.h create mode 100644 tests/tegra/drm-test.c create mode 100644 tests/tegra/drm-test.h create mode 100644 tests/tegra/gr2d-fill.c create mode 100644 tests/tegra/host1x.h create mode 100644 tests/tegra/meson.build create mode 100644 tests/tegra/openclose.c create mode 100644 tests/tegra/syncpt-timeout.c create mode 100644 tests/tegra/syncpt-wait.c create mode 100644 tests/tegra/vic-blit.c create mode 100644 tests/tegra/vic-clear.c create mode 100644 tests/tegra/vic-flip.c create mode 100644 tests/tegra/vic.c create mode 100644 tests/tegra/vic.h create mode 100644 tests/tegra/vic30.c create mode 100644 tests/tegra/vic30.h create mode 100644 tests/tegra/vic40.c create mode 100644 tests/tegra/vic40.h create mode 100644 tests/tegra/vic41.c create mode 100644 tests/tegra/vic41.h create mode 100644 tests/tegra/vic42.c create mode 100644 tests/tegra/vic42.h create mode 100644 tests/ttmtest/AUTHORS create mode 100644 tests/ttmtest/ChangeLog create mode 100644 tests/ttmtest/Makefile.am create mode 100644 tests/ttmtest/NEWS create mode 100644 tests/ttmtest/README create mode 100644 tests/ttmtest/configure.ac create mode 100755 tests/ttmtest/reconf create mode 100644 tests/ttmtest/src/Makefile.am create mode 100644 tests/ttmtest/src/ttmtest.c create mode 100644 tests/ttmtest/src/xf86dri.c create mode 100644 tests/ttmtest/src/xf86dri.h create mode 100644 tests/ttmtest/src/xf86dristr.h create mode 100644 tests/util/Android.mk create mode 100644 tests/util/Makefile.sources create mode 100644 tests/util/common.h create mode 100644 tests/util/format.c create mode 100644 tests/util/format.h create mode 100644 tests/util/kms.c create mode 100644 tests/util/kms.h create mode 100644 tests/util/meson.build create mode 100644 tests/util/pattern.c create mode 100644 tests/util/pattern.h create mode 100644 tests/vbltest/meson.build create mode 100644 tests/vbltest/vbltest.c create mode 100644 util_double_list.h create mode 100644 util_math.h create mode 100644 vc4/Makefile.sources create mode 100644 vc4/libdrm_vc4.pc.in create mode 100644 vc4/meson.build create mode 100644 vc4/vc4_packet.h create mode 100644 vc4/vc4_qpu_defines.h create mode 100644 xf86atomic.h create mode 100644 xf86drm.c create mode 100644 xf86drm.h create mode 100644 xf86drmHash.c create mode 100644 xf86drmHash.h create mode 100644 xf86drmMode.c create mode 100644 xf86drmMode.h create mode 100644 xf86drmRandom.c create mode 100644 xf86drmRandom.h create mode 100644 xf86drmSL.c diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..29b4f39 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,23 @@ +# To use this config with your editor, follow the instructions at: +# http://editorconfig.org + +root = true + +[*] +charset = utf-8 +insert_final_newline = true + +[*.{c,h}] +indent_style = space +indent_size = 4 + +[{Makefile.*,*.mk}] +indent_style = tab + +[*.m4] +indent_style = space +indent_size = 2 + +[{meson.build,meson_options.txt}] +indent_style = space +indent_size = 2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0ec9e7f --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/build* diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..4a3ed21 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,265 @@ +# This is the tag of the docker image used for the build jobs. If the +# image doesn't exist yet, the containers stage generates it. +# +# In order to generate a new image, one should generally change the tag. +# While removing the image from the registry would also work, that's not +# recommended except for ephemeral images during development: Replacing +# an image after a significant amount of time might pull in newer +# versions of gcc/clang or other packages, which might break the build +# with older commits using the same tag. +# +# After merging a change resulting in generating a new image to the +# main repository, it's recommended to remove the image from the source +# repository's container registry, so that the image from the main +# repository's registry will be used there as well. +.templates_sha: &template_sha 567700e483aabed992d0a4fea84994a0472deff6 # see https://docs.gitlab.com/ee/ci/yaml/#includefile + +include: + - project: 'freedesktop/ci-templates' + ref: *template_sha + file: + - '/templates/debian.yml' + - '/templates/freebsd.yml' + - '/templates/ci-fairy.yml' + +variables: + FDO_UPSTREAM_REPO: mesa/drm + FDO_REPO_SUFFIX: "$BUILD_OS/$BUILD_ARCH" + +stages: + - "Base container" + - "Build" + +.ci-rules: + rules: + - when: on_success + +# CONTAINERS + +.os-debian: + variables: + BUILD_OS: debian + FDO_DISTRIBUTION_VERSION: buster + FDO_DISTRIBUTION_PACKAGES: 'build-essential docbook-xsl libatomic-ops-dev libcairo2-dev libcunit1-dev libpciaccess-dev meson ninja-build pkg-config python3 python3-pip python3-wheel python3-setuptools python3-docutils valgrind' + FDO_DISTRIBUTION_EXEC: 'pip3 install meson==0.53.0' + # bump this tag every time you change something which requires rebuilding the + # base image + FDO_DISTRIBUTION_TAG: "2022-08-22.0" + +.debian-x86_64: + extends: + - .os-debian + variables: + BUILD_ARCH: "x86-64" + +.debian-aarch64: + extends: + - .os-debian + variables: + BUILD_ARCH: "aarch64" + +.debian-armv7: + extends: + - .os-debian + variables: + BUILD_ARCH: "armv7" + +.os-freebsd: + variables: + BUILD_OS: freebsd + FDO_DISTRIBUTION_VERSION: "13.0" + FDO_DISTRIBUTION_PACKAGES: 'meson ninja pkgconf libpciaccess libpthread-stubs py39-docutils cairo' + # bump this tag every time you change something which requires rebuilding the + # base image + FDO_DISTRIBUTION_TAG: "2022-08-22.0" + +.freebsd-x86_64: + extends: + - .os-freebsd + variables: + BUILD_ARCH: "x86_64" + +# Build our base container image, which contains the core distribution, the +# toolchain, and all our build dependencies. This will be reused in the build +# stage. +x86_64-debian-container_prep: + extends: + - .ci-rules + - .debian-x86_64 + - .fdo.container-build@debian + stage: "Base container" + variables: + GIT_STRATEGY: none + +aarch64-debian-container_prep: + extends: + - .ci-rules + - .debian-aarch64 + - .fdo.container-build@debian + tags: + - aarch64 + stage: "Base container" + variables: + GIT_STRATEGY: none + +armv7-debian-container_prep: + extends: + - .ci-rules + - .debian-armv7 + - .fdo.container-build@debian + tags: + - aarch64 + stage: "Base container" + variables: + GIT_STRATEGY: none + FDO_BASE_IMAGE: "arm32v7/debian:$FDO_DISTRIBUTION_VERSION" + +x86_64-freebsd-container_prep: + extends: + - .ci-rules + - .freebsd-x86_64 + - .fdo.qemu-build@freebsd@x86_64 + stage: "Base container" + variables: + GIT_STRATEGY: none + +# Core build environment. +.build-env: + variables: + MESON_BUILD_TYPE: "-Dbuildtype=debug -Doptimization=0 -Db_sanitize=address,undefined" + +# OS/architecture-specific variants +.build-env-debian-x86_64: + extends: + - .fdo.suffixed-image@debian + - .debian-x86_64 + - .build-env + needs: + - job: x86_64-debian-container_prep + artifacts: false + +.build-env-debian-aarch64: + extends: + - .fdo.suffixed-image@debian + - .debian-aarch64 + - .build-env + variables: + # At least with the versions we have, the LSan runtime makes fork unusably + # slow on AArch64, which is bad news since the test suite decides to fork + # for every single subtest. For now, in order to get AArch64 builds and + # tests into CI, just assume that we're not going to leak any more on + # AArch64 than we would on ARMv7 or x86-64. + ASAN_OPTIONS: "detect_leaks=0" + tags: + - aarch64 + needs: + - job: aarch64-debian-container_prep + artifacts: false + +.build-env-debian-armv7: + extends: + - .fdo.suffixed-image@debian + - .debian-armv7 + - .build-env + tags: + - aarch64 + needs: + - job: armv7-debian-container_prep + artifacts: false + +.build-env-freebsd-x86_64: + variables: + # Compiling with ASan+UBSan appears to trigger an infinite loop in the + # compiler shipped with FreeBSD 13.0, so we only use UBSan here. + # Additionally, sanitizers can't be used with b_lundef on FreeBSD. + MESON_BUILD_TYPE: "-Dbuildtype=debug -Db_sanitize=undefined -Db_lundef=false" + extends: + - .fdo.suffixed-image@freebsd + - .freebsd-x86_64 + - .build-env + needs: + - job: x86_64-freebsd-container_prep + artifacts: false + +# BUILD + +.do-build: + extends: + - .ci-rules + stage: "Build" + variables: + GIT_DEPTH: 10 + script: + - meson build + --auto-features=enabled + -D udev=true + - ninja -C build + - ninja -C build test + - DESTDIR=$PWD/install ninja -C build install + artifacts: + when: on_failure + paths: + - build/meson-logs/* + +.do-build-qemu: + extends: + - .ci-rules + stage: "Build" + script: + # Start the VM and copy our workspace to the VM + - /app/vmctl start + - scp -r $PWD "vm:" + # The `set +e is needed to ensure that we always copy the meson logs back to + # the workspace to see details about the failed tests. + - | + set +e + /app/vmctl exec "pkg info; cd $CI_PROJECT_NAME ; meson build --auto-features=enabled -D etnaviv=disabled -D nouveau=disabled -D valgrind=disabled && ninja -C build" + set -ex + scp -r vm:$CI_PROJECT_NAME/build/meson-logs . + /app/vmctl exec "ninja -C $CI_PROJECT_NAME/build install" + mkdir -p $PREFIX && scp -r vm:$PREFIX/ $PREFIX/ + # Finally, shut down the VM. + - /app/vmctl stop + artifacts: + when: on_failure + paths: + - build/meson-logs/* + +# Full build and test. +x86_64-debian-build: + extends: + - .build-env-debian-x86_64 + - .do-build + +aarch64-debian-build: + extends: + - .build-env-debian-aarch64 + - .do-build + +armv7-debian-build: + extends: + - .build-env-debian-armv7 + - .do-build + +# Daily build +meson-arch-daily: + rules: + - if: '$SCHEDULE == "arch-daily"' + when: on_success + - when: never + image: archlinux/archlinux:base-devel + before_script: + - pacman -Syu --noconfirm --needed + cairo + cunit + libatomic_ops + libpciaccess + meson + valgrind + python-docutils + extends: .do-build + +x86_64-freebsd-build: + extends: + - .build-env-freebsd-x86_64 + - .do-build-qemu diff --git a/Android.common.mk b/Android.common.mk new file mode 100644 index 0000000..37c2b23 --- /dev/null +++ b/Android.common.mk @@ -0,0 +1,22 @@ +# XXX: Consider moving these to config.h analogous to autoconf. +LOCAL_CFLAGS += \ + -DMAJOR_IN_SYSMACROS=1 \ + -DHAVE_ALLOCA_H=0 \ + -DHAVE_SYS_SELECT_H=0 \ + -DHAVE_SYS_SYSCTL_H=0 \ + -DHAVE_VISIBILITY=1 \ + -fvisibility=hidden \ + -DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1 + +LOCAL_CFLAGS += \ + -Wno-error \ + -Wno-unused-parameter \ + -Wno-missing-field-initializers \ + -Wno-pointer-arith \ + -Wno-enum-conversion + +# Quiet down the build system and remove any .h files from the sources +LOCAL_SRC_FILES := $(patsubst %.h, , $(LOCAL_SRC_FILES)) +LOCAL_EXPORT_C_INCLUDE_DIRS += $(LOCAL_PATH) + +LOCAL_PROPRIETARY_MODULE := true diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..0ab6f0f --- /dev/null +++ b/Android.mk @@ -0,0 +1,74 @@ +# +# Copyright © 2011-2012 Intel Corporation +# +# 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 (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 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. +# + +LIBDRM_ANDROID_MAJOR_VERSION := $(word 1, $(subst ., , $(PLATFORM_VERSION))) +ifneq ($(filter 2 4, $(LIBDRM_ANDROID_MAJOR_VERSION)),) +$(error "Android 4.4 and earlier not supported") +endif + +LIBDRM_COMMON_MK := $(call my-dir)/Android.common.mk + +LOCAL_PATH := $(call my-dir) +LIBDRM_TOP := $(LOCAL_PATH) + +include $(CLEAR_VARS) + +# Import variables LIBDRM_{,H,INCLUDE_H,INCLUDE_ANDROID_H,INCLUDE_VMWGFX_H}_FILES +include $(LOCAL_PATH)/Makefile.sources + +#static library for the device (recovery) +include $(CLEAR_VARS) +LOCAL_MODULE := libdrm + +LOCAL_SRC_FILES := $(LIBDRM_FILES) +LOCAL_EXPORT_C_INCLUDE_DIRS := \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/include/drm \ + $(LOCAL_PATH)/android + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/include/drm + +include $(LIBDRM_COMMON_MK) +include $(BUILD_STATIC_LIBRARY) + +# Shared library for the device +include $(CLEAR_VARS) +LOCAL_MODULE := libdrm + +LOCAL_SRC_FILES := $(LIBDRM_FILES) +LOCAL_EXPORT_C_INCLUDE_DIRS := \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/include/drm \ + $(LOCAL_PATH)/android + +LOCAL_SHARED_LIBRARIES := \ + libcutils + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/include/drm + +include $(LIBDRM_COMMON_MK) +include $(BUILD_SHARED_LIBRARY) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst new file mode 100644 index 0000000..96f1e4f --- /dev/null +++ b/CONTRIBUTING.rst @@ -0,0 +1,105 @@ +Contributing to libdrm +====================== + +Submitting Patches +------------------ + +Patches should be sent to dri-devel@lists.freedesktop.org, using git +send-email. For patches only touching driver specific code one of the driver +mailing lists (like amd-gfx@lists.freedesktop.org) is also appropriate. See git +documentation for help: + +http://git-scm.com/documentation + +Since dri-devel is a very busy mailing list please use --subject-prefix="PATCH +libdrm" to make it easier to find libdrm patches. This is best done by running + + git config --local format.subjectprefix "PATCH libdrm" + +The first line of a commit message should contain a prefix indicating what part +is affected by the patch followed by one sentence that describes the change. For +examples: + + amdgpu: Use uint32_t i in amdgpu_find_bo_by_cpu_mapping + +The body of the commit message should describe what the patch changes and why, +and also note any particular side effects. For a recommended reading on +writing commit messages, see: + +http://who-t.blogspot.de/2009/12/on-commit-messages.html + +Your patches should also include a Signed-off-by line with your name and email +address. If you're not the patch's original author, you should also gather +S-o-b's by them (and/or whomever gave the patch to you.) The significance of +this is that it certifies that you created the patch, that it was created under +an appropriate open source license, or provided to you under those terms. This +lets us indicate a chain of responsibility for the copyright status of the code. +For more details: + +https://developercertificate.org/ + +We won't reject patches that lack S-o-b, but it is strongly recommended. + +Review and Merging +------------------ + +Patches should have at least one positive review (Reviewed-by: tag) or +indication of approval (Acked-by: tag) before merging. For any code shared +between drivers this is mandatory. + +Please note that kernel/userspace API header files have special rules, see +include/drm/README. + +Coding style in the project loosely follows the CodingStyle of the linux kernel: + +https://www.kernel.org/doc/html/latest/process/coding-style.html?highlight=coding%20style + +Commit Rights +------------- + +Commit rights will be granted to anyone who requests them and fulfills the +below criteria: + +- Submitted a few (5-10 as a rule of thumb) non-trivial (not just simple + spelling fixes and whitespace adjustment) patches that have been merged + already. Since libdrm is just a glue library between the kernel and userspace + drivers, merged patches to those components also count towards the commit + criteria. + +- Are actively participating on discussions about their work (on the mailing + list or IRC). This should not be interpreted as a requirement to review other + peoples patches but just make sure that patch submission isn't one-way + communication. Cross-review is still highly encouraged. + +- Will be regularly contributing further patches. This includes regular + contributors to other parts of the open source graphics stack who only + do the oddball rare patch within libdrm itself. + +- Agrees to use their commit rights in accordance with the documented merge + criteria, tools, and processes. + +To apply for commit rights ("Developer" role in gitlab) send a mail to +dri-devel@lists.freedesktop.org and please ping the maintainers if your request +is stuck. + +Committers are encouraged to request their commit rights get removed when they +no longer contribute to the project. Commit rights will be reinstated when they +come back to the project. + +Maintainers and committers should encourage contributors to request commit +rights, as especially junior contributors tend to underestimate their skills. + +Code of Conduct +--------------- + +Please be aware the fd.o Code of Conduct also applies to libdrm: + +https://www.freedesktop.org/wiki/CodeOfConduct/ + +See the gitlab project owners for contact details of the libdrm maintainers. + +Abuse of commit rights, like engaging in commit fights or willfully pushing +patches that violate the documented merge criteria, will also be handled through +the Code of Conduct enforcement process. + +Happy hacking! diff --git a/CleanSpec.mk b/CleanSpec.mk new file mode 100644 index 0000000..28a11db --- /dev/null +++ b/CleanSpec.mk @@ -0,0 +1,4 @@ +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/include/libdrm) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/include/freedreno) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdrm_*intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libdrm_*intermediates) diff --git a/Makefile.sources b/Makefile.sources new file mode 100644 index 0000000..55290fe --- /dev/null +++ b/Makefile.sources @@ -0,0 +1,45 @@ +LIBDRM_FILES := \ + xf86drm.c \ + xf86drmHash.c \ + xf86drmHash.h \ + xf86drmRandom.c \ + xf86drmRandom.h \ + xf86drmSL.c \ + xf86drmMode.c \ + xf86atomic.h \ + libdrm_macros.h \ + libdrm_lists.h \ + util_double_list.h \ + util_math.h + +LIBDRM_H_FILES := \ + libsync.h \ + xf86drm.h \ + xf86drmMode.h + +LIBDRM_INCLUDE_H_FILES := \ + include/drm/drm.h \ + include/drm/drm_fourcc.h \ + include/drm/drm_mode.h \ + include/drm/drm_sarea.h \ + include/drm/i915_drm.h \ + include/drm/mach64_drm.h \ + include/drm/mga_drm.h \ + include/drm/msm_drm.h \ + include/drm/nouveau_drm.h \ + include/drm/qxl_drm.h \ + include/drm/r128_drm.h \ + include/drm/radeon_drm.h \ + include/drm/amdgpu_drm.h \ + include/drm/savage_drm.h \ + include/drm/sis_drm.h \ + include/drm/tegra_drm.h \ + include/drm/vc4_drm.h \ + include/drm/via_drm.h \ + include/drm/virtgpu_drm.h + +LIBDRM_INCLUDE_ANDROID_H_FILES := \ + android/gralloc_handle.h + +LIBDRM_INCLUDE_VMWGFX_H_FILES := \ + include/drm/vmwgfx_drm.h diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..7460803 --- /dev/null +++ b/README.rst @@ -0,0 +1,51 @@ +libdrm - userspace library for drm +---------------------------------- + +This is libdrm, a userspace library for accessing the DRM, direct rendering +manager, on Linux, BSD and other operating systems that support the ioctl +interface. +The library provides wrapper functions for the ioctls to avoid exposing the +kernel interface directly, and for chipsets with drm memory manager, support +for tracking relocations and buffers. +New functionality in the kernel DRM drivers typically requires a new libdrm, +but a new libdrm will always work with an older kernel. + +libdrm is a low-level library, typically used by graphics drivers such as +the Mesa drivers, the X drivers, libva and similar projects. + +Syncing with the Linux kernel headers +------------------------------------- + +The library should be regularly updated to match the recent changes in the +`include/uapi/drm/`. + +libdrm maintains a human-readable version for the token format modifier, with +the simpler ones being extracted automatically from `drm_fourcc.h` header file +with the help of a python script. This might not always possible, as some of +the vendors require decoding/extracting them programmatically. For that +reason one can enhance the current vendor functions to include/provide the +newly added token formats, or, in case there's no such decoding +function, to add one that performs the tasks of extracting them. + +For simpler format modifier tokens there's a script (gen_table_fourcc.py) that +creates a static table, by going over `drm_fourcc.h` header file. The script +could be further modified if it can't handle new (simpler) token format +modifiers instead of the generated static table. + +Compiling +--------- + +To set up meson: + + meson builddir/ + +By default this will install into /usr/local, you can change your prefix +with --prefix=/usr (or `meson configure builddir/ -Dprefix=/usr` after +the initial meson setup). + +Then use ninja to build and install: + + ninja -C builddir/ install + +If you are installing into a system location you will need to run install +separately, and as root. diff --git a/RELEASING b/RELEASING new file mode 100644 index 0000000..838ba2b --- /dev/null +++ b/RELEASING @@ -0,0 +1,40 @@ +The release criteria for libdrm is essentially "if you need a release, +make one". There is no designated release engineer or maintainer. +Anybody is free to make a release if there's a certain feature or bug +fix they need in a released version of libdrm. + +When new ioctl definitions are merged into drm-next, we will add +support to libdrm, at which point we typically create a new release. +However, this is up to whoever is driving the feature in question. + +Follow these steps to release a new version of libdrm: + + 1) Bump the version number in meson.build. We seem to have settled for + 2.4.x as the versioning scheme for libdrm, so just bump the micro + version. + + 2) Run `ninja -C builddir/ dist` to generate the tarballs. + Make sure that the version number of the tarball name in + builddir/meson-dist/ matches the number you bumped to. Move that + tarball to the libdrm repo root for the release script to pick up. + + 3) Push the updated main branch with the bumped version number: + + git push origin main + + assuming the remote for the upstream libdrm repo is called origin. + + 4) Use the release.sh script from the xorg/util/modular repo to + upload the tarballs to the freedesktop.org download area and + create an announce email template. The script takes one argument: + the path to the libdrm checkout. So, if a checkout of modular is + at the same level than the libdrm repo: + + ./modular/release.sh libdrm + + This copies the two tarballs to freedesktop.org and creates + libdrm-2.4.16.announce which has a detailed summary of the + changes, links to the tarballs, MD5 and SHA1 sums and pre-filled + out email headers. Fill out the blank between the email headers + and the list of changes with a brief message of what changed or + what prompted this release. Send out the email and you're done! diff --git a/amdgpu/.editorconfig b/amdgpu/.editorconfig new file mode 100644 index 0000000..426273f --- /dev/null +++ b/amdgpu/.editorconfig @@ -0,0 +1,13 @@ +# To use this config with your editor, follow the instructions at: +# http://editorconfig.org + +[*] +charset = utf-8 +indent_style = tab +indent_size = 8 +tab_width = 8 +insert_final_newline = true + +[meson.build] +indent_style = space +indent_size = 2 diff --git a/amdgpu/Android.mk b/amdgpu/Android.mk new file mode 100644 index 0000000..1f028d0 --- /dev/null +++ b/amdgpu/Android.mk @@ -0,0 +1,19 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +# Import variables LIBDRM_AMDGPU_FILES, LIBDRM_AMDGPU_H_FILES +include $(LOCAL_PATH)/Makefile.sources + +LOCAL_MODULE := libdrm_amdgpu + +LOCAL_SHARED_LIBRARIES := libdrm + +LOCAL_SRC_FILES := $(LIBDRM_AMDGPU_FILES) + +LOCAL_CFLAGS := \ + -DAMDGPU_ASIC_ID_TABLE=\"/vendor/etc/hwdata/amdgpu.ids\" + +LOCAL_REQUIRED_MODULES := amdgpu.ids + +include $(LIBDRM_COMMON_MK) +include $(BUILD_SHARED_LIBRARY) diff --git a/amdgpu/Makefile.sources b/amdgpu/Makefile.sources new file mode 100644 index 0000000..d6df324 --- /dev/null +++ b/amdgpu/Makefile.sources @@ -0,0 +1,14 @@ +LIBDRM_AMDGPU_FILES := \ + amdgpu_asic_id.c \ + amdgpu_bo.c \ + amdgpu_cs.c \ + amdgpu_device.c \ + amdgpu_gpu_info.c \ + amdgpu_internal.h \ + amdgpu_vamgr.c \ + amdgpu_vm.c \ + handle_table.c \ + handle_table.h + +LIBDRM_AMDGPU_H_FILES := \ + amdgpu.h diff --git a/amdgpu/amdgpu-symbols.txt b/amdgpu/amdgpu-symbols.txt new file mode 100644 index 0000000..d41d9c2 --- /dev/null +++ b/amdgpu/amdgpu-symbols.txt @@ -0,0 +1,77 @@ +amdgpu_bo_alloc +amdgpu_bo_cpu_map +amdgpu_bo_cpu_unmap +amdgpu_bo_export +amdgpu_bo_free +amdgpu_bo_import +amdgpu_bo_inc_ref +amdgpu_bo_list_create_raw +amdgpu_bo_list_destroy_raw +amdgpu_bo_list_create +amdgpu_bo_list_destroy +amdgpu_bo_list_update +amdgpu_bo_query_info +amdgpu_bo_set_metadata +amdgpu_bo_va_op +amdgpu_bo_va_op_raw +amdgpu_bo_wait_for_idle +amdgpu_create_bo_from_user_mem +amdgpu_cs_chunk_fence_info_to_data +amdgpu_cs_chunk_fence_to_dep +amdgpu_cs_create_semaphore +amdgpu_cs_create_syncobj +amdgpu_cs_create_syncobj2 +amdgpu_cs_ctx_create +amdgpu_cs_ctx_create2 +amdgpu_cs_ctx_free +amdgpu_cs_ctx_override_priority +amdgpu_cs_ctx_stable_pstate +amdgpu_cs_destroy_semaphore +amdgpu_cs_destroy_syncobj +amdgpu_cs_export_syncobj +amdgpu_cs_fence_to_handle +amdgpu_cs_import_syncobj +amdgpu_cs_query_fence_status +amdgpu_cs_query_reset_state +amdgpu_cs_query_reset_state2 +amdgpu_query_sw_info +amdgpu_cs_signal_semaphore +amdgpu_cs_submit +amdgpu_cs_submit_raw +amdgpu_cs_submit_raw2 +amdgpu_cs_syncobj_export_sync_file +amdgpu_cs_syncobj_export_sync_file2 +amdgpu_cs_syncobj_import_sync_file +amdgpu_cs_syncobj_import_sync_file2 +amdgpu_cs_syncobj_query +amdgpu_cs_syncobj_query2 +amdgpu_cs_syncobj_reset +amdgpu_cs_syncobj_signal +amdgpu_cs_syncobj_timeline_signal +amdgpu_cs_syncobj_timeline_wait +amdgpu_cs_syncobj_transfer +amdgpu_cs_syncobj_wait +amdgpu_cs_wait_fences +amdgpu_cs_wait_semaphore +amdgpu_device_deinitialize +amdgpu_device_get_fd +amdgpu_device_initialize +amdgpu_find_bo_by_cpu_mapping +amdgpu_get_marketing_name +amdgpu_query_buffer_size_alignment +amdgpu_query_crtc_from_id +amdgpu_query_firmware_version +amdgpu_query_gds_info +amdgpu_query_gpu_info +amdgpu_query_heap_info +amdgpu_query_hw_ip_count +amdgpu_query_hw_ip_info +amdgpu_query_info +amdgpu_query_sensor_info +amdgpu_query_video_caps_info +amdgpu_read_mm_registers +amdgpu_va_range_alloc +amdgpu_va_range_free +amdgpu_va_range_query +amdgpu_vm_reserve_vmid +amdgpu_vm_unreserve_vmid diff --git a/amdgpu/amdgpu.h b/amdgpu/amdgpu.h new file mode 100644 index 0000000..5ef2524 --- /dev/null +++ b/amdgpu/amdgpu.h @@ -0,0 +1,1876 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 amdgpu.h + * + * Declare public libdrm_amdgpu API + * + * This file define API exposed by libdrm_amdgpu library. + * User wanted to use libdrm_amdgpu functionality must include + * this file. + * + */ +#ifndef _AMDGPU_H_ +#define _AMDGPU_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct drm_amdgpu_info_hw_ip; +struct drm_amdgpu_bo_list_entry; + +/*--------------------------------------------------------------------------*/ +/* --------------------------- Defines ------------------------------------ */ +/*--------------------------------------------------------------------------*/ + +/** + * Define max. number of Command Buffers (IB) which could be sent to the single + * hardware IP to accommodate CE/DE requirements + * + * \sa amdgpu_cs_ib_info +*/ +#define AMDGPU_CS_MAX_IBS_PER_SUBMIT 4 + +/** + * Special timeout value meaning that the timeout is infinite. + */ +#define AMDGPU_TIMEOUT_INFINITE 0xffffffffffffffffull + +/** + * Used in amdgpu_cs_query_fence_status(), meaning that the given timeout + * is absolute. + */ +#define AMDGPU_QUERY_FENCE_TIMEOUT_IS_ABSOLUTE (1 << 0) + +/*--------------------------------------------------------------------------*/ +/* ----------------------------- Enums ------------------------------------ */ +/*--------------------------------------------------------------------------*/ + +/** + * Enum describing possible handle types + * + * \sa amdgpu_bo_import, amdgpu_bo_export + * +*/ +enum amdgpu_bo_handle_type { + /** GEM flink name (needs DRM authentication, used by DRI2) */ + amdgpu_bo_handle_type_gem_flink_name = 0, + + /** KMS handle which is used by all driver ioctls */ + amdgpu_bo_handle_type_kms = 1, + + /** DMA-buf fd handle */ + amdgpu_bo_handle_type_dma_buf_fd = 2, + + /** Deprecated in favour of and same behaviour as + * amdgpu_bo_handle_type_kms, use that instead of this + */ + amdgpu_bo_handle_type_kms_noimport = 3, +}; + +/** Define known types of GPU VM VA ranges */ +enum amdgpu_gpu_va_range +{ + /** Allocate from "normal"/general range */ + amdgpu_gpu_va_range_general = 0 +}; + +enum amdgpu_sw_info { + amdgpu_sw_info_address32_hi = 0, +}; + +/*--------------------------------------------------------------------------*/ +/* -------------------------- Datatypes ----------------------------------- */ +/*--------------------------------------------------------------------------*/ + +/** + * Define opaque pointer to context associated with fd. + * This context will be returned as the result of + * "initialize" function and should be pass as the first + * parameter to any API call + */ +typedef struct amdgpu_device *amdgpu_device_handle; + +/** + * Define GPU Context type as pointer to opaque structure + * Example of GPU Context is the "rendering" context associated + * with OpenGL context (glCreateContext) + */ +typedef struct amdgpu_context *amdgpu_context_handle; + +/** + * Define handle for amdgpu resources: buffer, GDS, etc. + */ +typedef struct amdgpu_bo *amdgpu_bo_handle; + +/** + * Define handle for list of BOs + */ +typedef struct amdgpu_bo_list *amdgpu_bo_list_handle; + +/** + * Define handle to be used to work with VA allocated ranges + */ +typedef struct amdgpu_va *amdgpu_va_handle; + +/** + * Define handle for semaphore + */ +typedef struct amdgpu_semaphore *amdgpu_semaphore_handle; + +/*--------------------------------------------------------------------------*/ +/* -------------------------- Structures ---------------------------------- */ +/*--------------------------------------------------------------------------*/ + +/** + * Structure describing memory allocation request + * + * \sa amdgpu_bo_alloc() + * +*/ +struct amdgpu_bo_alloc_request { + /** Allocation request. It must be aligned correctly. */ + uint64_t alloc_size; + + /** + * It may be required to have some specific alignment requirements + * for physical back-up storage (e.g. for displayable surface). + * If 0 there is no special alignment requirement + */ + uint64_t phys_alignment; + + /** + * UMD should specify where to allocate memory and how it + * will be accessed by the CPU. + */ + uint32_t preferred_heap; + + /** Additional flags passed on allocation */ + uint64_t flags; +}; + +/** + * Special UMD specific information associated with buffer. + * + * It may be need to pass some buffer charactersitic as part + * of buffer sharing. Such information are defined UMD and + * opaque for libdrm_amdgpu as well for kernel driver. + * + * \sa amdgpu_bo_set_metadata(), amdgpu_bo_query_info, + * amdgpu_bo_import(), amdgpu_bo_export + * +*/ +struct amdgpu_bo_metadata { + /** Special flag associated with surface */ + uint64_t flags; + + /** + * ASIC-specific tiling information (also used by DCE). + * The encoding is defined by the AMDGPU_TILING_* definitions. + */ + uint64_t tiling_info; + + /** Size of metadata associated with the buffer, in bytes. */ + uint32_t size_metadata; + + /** UMD specific metadata. Opaque for kernel */ + uint32_t umd_metadata[64]; +}; + +/** + * Structure describing allocated buffer. Client may need + * to query such information as part of 'sharing' buffers mechanism + * + * \sa amdgpu_bo_set_metadata(), amdgpu_bo_query_info(), + * amdgpu_bo_import(), amdgpu_bo_export() +*/ +struct amdgpu_bo_info { + /** Allocated memory size */ + uint64_t alloc_size; + + /** + * It may be required to have some specific alignment requirements + * for physical back-up storage. + */ + uint64_t phys_alignment; + + /** Heap where to allocate memory. */ + uint32_t preferred_heap; + + /** Additional allocation flags. */ + uint64_t alloc_flags; + + /** Metadata associated with buffer if any. */ + struct amdgpu_bo_metadata metadata; +}; + +/** + * Structure with information about "imported" buffer + * + * \sa amdgpu_bo_import() + * + */ +struct amdgpu_bo_import_result { + /** Handle of memory/buffer to use */ + amdgpu_bo_handle buf_handle; + + /** Buffer size */ + uint64_t alloc_size; +}; + +/** + * + * Structure to describe GDS partitioning information. + * \note OA and GWS resources are asscoiated with GDS partition + * + * \sa amdgpu_gpu_resource_query_gds_info + * +*/ +struct amdgpu_gds_resource_info { + uint32_t gds_gfx_partition_size; + uint32_t compute_partition_size; + uint32_t gds_total_size; + uint32_t gws_per_gfx_partition; + uint32_t gws_per_compute_partition; + uint32_t oa_per_gfx_partition; + uint32_t oa_per_compute_partition; +}; + +/** + * Structure describing CS fence + * + * \sa amdgpu_cs_query_fence_status(), amdgpu_cs_request, amdgpu_cs_submit() + * +*/ +struct amdgpu_cs_fence { + + /** In which context IB was sent to execution */ + amdgpu_context_handle context; + + /** To which HW IP type the fence belongs */ + uint32_t ip_type; + + /** IP instance index if there are several IPs of the same type. */ + uint32_t ip_instance; + + /** Ring index of the HW IP */ + uint32_t ring; + + /** Specify fence for which we need to check submission status.*/ + uint64_t fence; +}; + +/** + * Structure describing IB + * + * \sa amdgpu_cs_request, amdgpu_cs_submit() + * +*/ +struct amdgpu_cs_ib_info { + /** Special flags */ + uint64_t flags; + + /** Virtual MC address of the command buffer */ + uint64_t ib_mc_address; + + /** + * Size of Command Buffer to be submitted. + * - The size is in units of dwords (4 bytes). + * - Could be 0 + */ + uint32_t size; +}; + +/** + * Structure describing fence information + * + * \sa amdgpu_cs_request, amdgpu_cs_query_fence, + * amdgpu_cs_submit(), amdgpu_cs_query_fence_status() +*/ +struct amdgpu_cs_fence_info { + /** buffer object for the fence */ + amdgpu_bo_handle handle; + + /** fence offset in the unit of sizeof(uint64_t) */ + uint64_t offset; +}; + +/** + * Structure describing submission request + * + * \note We could have several IBs as packet. e.g. CE, CE, DE case for gfx + * + * \sa amdgpu_cs_submit() +*/ +struct amdgpu_cs_request { + /** Specify flags with additional information */ + uint64_t flags; + + /** Specify HW IP block type to which to send the IB. */ + unsigned ip_type; + + /** IP instance index if there are several IPs of the same type. */ + unsigned ip_instance; + + /** + * Specify ring index of the IP. We could have several rings + * in the same IP. E.g. 0 for SDMA0 and 1 for SDMA1. + */ + uint32_t ring; + + /** + * List handle with resources used by this request. + */ + amdgpu_bo_list_handle resources; + + /** + * Number of dependencies this Command submission needs to + * wait for before starting execution. + */ + uint32_t number_of_dependencies; + + /** + * Array of dependencies which need to be met before + * execution can start. + */ + struct amdgpu_cs_fence *dependencies; + + /** Number of IBs to submit in the field ibs. */ + uint32_t number_of_ibs; + + /** + * IBs to submit. Those IBs will be submit together as single entity + */ + struct amdgpu_cs_ib_info *ibs; + + /** + * The returned sequence number for the command submission + */ + uint64_t seq_no; + + /** + * The fence information + */ + struct amdgpu_cs_fence_info fence_info; +}; + +/** + * Structure which provide information about GPU VM MC Address space + * alignments requirements + * + * \sa amdgpu_query_buffer_size_alignment + */ +struct amdgpu_buffer_size_alignments { + /** Size alignment requirement for allocation in + * local memory */ + uint64_t size_local; + + /** + * Size alignment requirement for allocation in remote memory + */ + uint64_t size_remote; +}; + +/** + * Structure which provide information about heap + * + * \sa amdgpu_query_heap_info() + * + */ +struct amdgpu_heap_info { + /** Theoretical max. available memory in the given heap */ + uint64_t heap_size; + + /** + * Number of bytes allocated in the heap. This includes all processes + * and private allocations in the kernel. It changes when new buffers + * are allocated, freed, and moved. It cannot be larger than + * heap_size. + */ + uint64_t heap_usage; + + /** + * Theoretical possible max. size of buffer which + * could be allocated in the given heap + */ + uint64_t max_allocation; +}; + +/** + * Describe GPU h/w info needed for UMD correct initialization + * + * \sa amdgpu_query_gpu_info() +*/ +struct amdgpu_gpu_info { + /** Asic id */ + uint32_t asic_id; + /** Chip revision */ + uint32_t chip_rev; + /** Chip external revision */ + uint32_t chip_external_rev; + /** Family ID */ + uint32_t family_id; + /** Special flags */ + uint64_t ids_flags; + /** max engine clock*/ + uint64_t max_engine_clk; + /** max memory clock */ + uint64_t max_memory_clk; + /** number of shader engines */ + uint32_t num_shader_engines; + /** number of shader arrays per engine */ + uint32_t num_shader_arrays_per_engine; + /** Number of available good shader pipes */ + uint32_t avail_quad_shader_pipes; + /** Max. number of shader pipes.(including good and bad pipes */ + uint32_t max_quad_shader_pipes; + /** Number of parameter cache entries per shader quad pipe */ + uint32_t cache_entries_per_quad_pipe; + /** Number of available graphics context */ + uint32_t num_hw_gfx_contexts; + /** Number of render backend pipes */ + uint32_t rb_pipes; + /** Enabled render backend pipe mask */ + uint32_t enabled_rb_pipes_mask; + /** Frequency of GPU Counter */ + uint32_t gpu_counter_freq; + /** CC_RB_BACKEND_DISABLE.BACKEND_DISABLE per SE */ + uint32_t backend_disable[4]; + /** Value of MC_ARB_RAMCFG register*/ + uint32_t mc_arb_ramcfg; + /** Value of GB_ADDR_CONFIG */ + uint32_t gb_addr_cfg; + /** Values of the GB_TILE_MODE0..31 registers */ + uint32_t gb_tile_mode[32]; + /** Values of GB_MACROTILE_MODE0..15 registers */ + uint32_t gb_macro_tile_mode[16]; + /** Value of PA_SC_RASTER_CONFIG register per SE */ + uint32_t pa_sc_raster_cfg[4]; + /** Value of PA_SC_RASTER_CONFIG_1 register per SE */ + uint32_t pa_sc_raster_cfg1[4]; + /* CU info */ + uint32_t cu_active_number; + uint32_t cu_ao_mask; + uint32_t cu_bitmap[4][4]; + /* video memory type info*/ + uint32_t vram_type; + /* video memory bit width*/ + uint32_t vram_bit_width; + /** constant engine ram size*/ + uint32_t ce_ram_size; + /* vce harvesting instance */ + uint32_t vce_harvest_config; + /* PCI revision ID */ + uint32_t pci_rev_id; +}; + + +/*--------------------------------------------------------------------------*/ +/*------------------------- Functions --------------------------------------*/ +/*--------------------------------------------------------------------------*/ + +/* + * Initialization / Cleanup + * +*/ + +/** + * + * \param fd - \c [in] File descriptor for AMD GPU device + * received previously as the result of + * e.g. drmOpen() call. + * For legacy fd type, the DRI2/DRI3 + * authentication should be done before + * calling this function. + * \param major_version - \c [out] Major version of library. It is assumed + * that adding new functionality will cause + * increase in major version + * \param minor_version - \c [out] Minor version of library + * \param device_handle - \c [out] Pointer to opaque context which should + * be passed as the first parameter on each + * API call + * + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + * + * \sa amdgpu_device_deinitialize() +*/ +int amdgpu_device_initialize(int fd, + uint32_t *major_version, + uint32_t *minor_version, + amdgpu_device_handle *device_handle); + +/** + * + * When access to such library does not needed any more the special + * function must be call giving opportunity to clean up any + * resources if needed. + * + * \param device_handle - \c [in] Context associated with file + * descriptor for AMD GPU device + * received previously as the + * result e.g. of drmOpen() call. + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + * \sa amdgpu_device_initialize() + * +*/ +int amdgpu_device_deinitialize(amdgpu_device_handle device_handle); + +/** + * + * /param device_handle - \c [in] Device handle. + * See #amdgpu_device_initialize() + * + * \return Returns the drm fd used for operations on this + * device. This is still owned by the library and hence + * should not be closed. Guaranteed to be valid until + * #amdgpu_device_deinitialize gets called. + * +*/ +int amdgpu_device_get_fd(amdgpu_device_handle device_handle); + +/* + * Memory Management + * +*/ + +/** + * Allocate memory to be used by UMD for GPU related operations + * + * \param dev - \c [in] Device handle. + * See #amdgpu_device_initialize() + * \param alloc_buffer - \c [in] Pointer to the structure describing an + * allocation request + * \param buf_handle - \c [out] Allocated buffer handle + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + * \sa amdgpu_bo_free() +*/ +int amdgpu_bo_alloc(amdgpu_device_handle dev, + struct amdgpu_bo_alloc_request *alloc_buffer, + amdgpu_bo_handle *buf_handle); + +/** + * Associate opaque data with buffer to be queried by another UMD + * + * \param dev - \c [in] Device handle. See #amdgpu_device_initialize() + * \param buf_handle - \c [in] Buffer handle + * \param info - \c [in] Metadata to associated with buffer + * + * \return 0 on success\n + * <0 - Negative POSIX Error code +*/ +int amdgpu_bo_set_metadata(amdgpu_bo_handle buf_handle, + struct amdgpu_bo_metadata *info); + +/** + * Query buffer information including metadata previusly associated with + * buffer. + * + * \param dev - \c [in] Device handle. + * See #amdgpu_device_initialize() + * \param buf_handle - \c [in] Buffer handle + * \param info - \c [out] Structure describing buffer + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + * \sa amdgpu_bo_set_metadata(), amdgpu_bo_alloc() +*/ +int amdgpu_bo_query_info(amdgpu_bo_handle buf_handle, + struct amdgpu_bo_info *info); + +/** + * Allow others to get access to buffer + * + * \param dev - \c [in] Device handle. + * See #amdgpu_device_initialize() + * \param buf_handle - \c [in] Buffer handle + * \param type - \c [in] Type of handle requested + * \param shared_handle - \c [out] Special "shared" handle + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + * \sa amdgpu_bo_import() + * +*/ +int amdgpu_bo_export(amdgpu_bo_handle buf_handle, + enum amdgpu_bo_handle_type type, + uint32_t *shared_handle); + +/** + * Request access to "shared" buffer + * + * \param dev - \c [in] Device handle. + * See #amdgpu_device_initialize() + * \param type - \c [in] Type of handle requested + * \param shared_handle - \c [in] Shared handle received as result "import" + * operation + * \param output - \c [out] Pointer to structure with information + * about imported buffer + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + * \note Buffer must be "imported" only using new "fd" (different from + * one used by "exporter"). + * + * \sa amdgpu_bo_export() + * +*/ +int amdgpu_bo_import(amdgpu_device_handle dev, + enum amdgpu_bo_handle_type type, + uint32_t shared_handle, + struct amdgpu_bo_import_result *output); + +/** + * Request GPU access to user allocated memory e.g. via "malloc" + * + * \param dev - [in] Device handle. See #amdgpu_device_initialize() + * \param cpu - [in] CPU address of user allocated memory which we + * want to map to GPU address space (make GPU accessible) + * (This address must be correctly aligned). + * \param size - [in] Size of allocation (must be correctly aligned) + * \param buf_handle - [out] Buffer handle for the userptr memory + * resource on submission and be used in other operations. + * + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + * \note + * This call doesn't guarantee that such memory will be persistently + * "locked" / make non-pageable. The purpose of this call is to provide + * opportunity for GPU get access to this resource during submission. + * + * The maximum amount of memory which could be mapped in this call depends + * if overcommit is disabled or not. If overcommit is disabled than the max. + * amount of memory to be pinned will be limited by left "free" size in total + * amount of memory which could be locked simultaneously ("GART" size). + * + * Supported (theoretical) max. size of mapping is restricted only by + * "GART" size. + * + * It is responsibility of caller to correctly specify access rights + * on VA assignment. +*/ +int amdgpu_create_bo_from_user_mem(amdgpu_device_handle dev, + void *cpu, uint64_t size, + amdgpu_bo_handle *buf_handle); + +/** + * Validate if the user memory comes from BO + * + * \param dev - [in] Device handle. See #amdgpu_device_initialize() + * \param cpu - [in] CPU address of user allocated memory which we + * want to map to GPU address space (make GPU accessible) + * (This address must be correctly aligned). + * \param size - [in] Size of allocation (must be correctly aligned) + * \param buf_handle - [out] Buffer handle for the userptr memory + * if the user memory is not from BO, the buf_handle will be NULL. + * \param offset_in_bo - [out] offset in this BO for this user memory + * + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_find_bo_by_cpu_mapping(amdgpu_device_handle dev, + void *cpu, + uint64_t size, + amdgpu_bo_handle *buf_handle, + uint64_t *offset_in_bo); + +/** + * Free previously allocated memory + * + * \param dev - \c [in] Device handle. See #amdgpu_device_initialize() + * \param buf_handle - \c [in] Buffer handle to free + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + * \note In the case of memory shared between different applications all + * resources will be “physically” freed only all such applications + * will be terminated + * \note If is UMD responsibility to ‘free’ buffer only when there is no + * more GPU access + * + * \sa amdgpu_bo_set_metadata(), amdgpu_bo_alloc() + * +*/ +int amdgpu_bo_free(amdgpu_bo_handle buf_handle); + +/** + * Increase the reference count of a buffer object + * + * \param bo - \c [in] Buffer object handle to increase the reference count + * + * \sa amdgpu_bo_alloc(), amdgpu_bo_free() + * +*/ +void amdgpu_bo_inc_ref(amdgpu_bo_handle bo); + +/** + * Request CPU access to GPU accessible memory + * + * \param buf_handle - \c [in] Buffer handle + * \param cpu - \c [out] CPU address to be used for access + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + * \sa amdgpu_bo_cpu_unmap() + * +*/ +int amdgpu_bo_cpu_map(amdgpu_bo_handle buf_handle, void **cpu); + +/** + * Release CPU access to GPU memory + * + * \param buf_handle - \c [in] Buffer handle + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + * \sa amdgpu_bo_cpu_map() + * +*/ +int amdgpu_bo_cpu_unmap(amdgpu_bo_handle buf_handle); + +/** + * Wait until a buffer is not used by the device. + * + * \param dev - \c [in] Device handle. See #amdgpu_device_initialize() + * \param buf_handle - \c [in] Buffer handle. + * \param timeout_ns - Timeout in nanoseconds. + * \param buffer_busy - 0 if buffer is idle, all GPU access was completed + * and no GPU access is scheduled. + * 1 GPU access is in fly or scheduled + * + * \return 0 - on success + * <0 - Negative POSIX Error code + */ +int amdgpu_bo_wait_for_idle(amdgpu_bo_handle buf_handle, + uint64_t timeout_ns, + bool *buffer_busy); + +/** + * Creates a BO list handle for command submission. + * + * \param dev - \c [in] Device handle. + * See #amdgpu_device_initialize() + * \param number_of_buffers - \c [in] Number of BOs in the list + * \param buffers - \c [in] List of BO handles + * \param result - \c [out] Created BO list handle + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + * \sa amdgpu_bo_list_destroy_raw(), amdgpu_cs_submit_raw2() +*/ +int amdgpu_bo_list_create_raw(amdgpu_device_handle dev, + uint32_t number_of_buffers, + struct drm_amdgpu_bo_list_entry *buffers, + uint32_t *result); + +/** + * Destroys a BO list handle. + * + * \param bo_list - \c [in] BO list handle. + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + * \sa amdgpu_bo_list_create_raw(), amdgpu_cs_submit_raw2() +*/ +int amdgpu_bo_list_destroy_raw(amdgpu_device_handle dev, uint32_t bo_list); + +/** + * Creates a BO list handle for command submission. + * + * \param dev - \c [in] Device handle. + * See #amdgpu_device_initialize() + * \param number_of_resources - \c [in] Number of BOs in the list + * \param resources - \c [in] List of BO handles + * \param resource_prios - \c [in] Optional priority for each handle + * \param result - \c [out] Created BO list handle + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + * \sa amdgpu_bo_list_destroy() +*/ +int amdgpu_bo_list_create(amdgpu_device_handle dev, + uint32_t number_of_resources, + amdgpu_bo_handle *resources, + uint8_t *resource_prios, + amdgpu_bo_list_handle *result); + +/** + * Destroys a BO list handle. + * + * \param handle - \c [in] BO list handle. + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + * \sa amdgpu_bo_list_create() +*/ +int amdgpu_bo_list_destroy(amdgpu_bo_list_handle handle); + +/** + * Update resources for existing BO list + * + * \param handle - \c [in] BO list handle + * \param number_of_resources - \c [in] Number of BOs in the list + * \param resources - \c [in] List of BO handles + * \param resource_prios - \c [in] Optional priority for each handle + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + * \sa amdgpu_bo_list_update() +*/ +int amdgpu_bo_list_update(amdgpu_bo_list_handle handle, + uint32_t number_of_resources, + amdgpu_bo_handle *resources, + uint8_t *resource_prios); + +/* + * GPU Execution context + * +*/ + +/** + * Create GPU execution Context + * + * For the purpose of GPU Scheduler and GPU Robustness extensions it is + * necessary to have information/identify rendering/compute contexts. + * It also may be needed to associate some specific requirements with such + * contexts. Kernel driver will guarantee that submission from the same + * context will always be executed in order (first come, first serve). + * + * + * \param dev - \c [in] Device handle. See #amdgpu_device_initialize() + * \param priority - \c [in] Context creation flags. See AMDGPU_CTX_PRIORITY_* + * \param context - \c [out] GPU Context handle + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + * \sa amdgpu_cs_ctx_free() + * +*/ +int amdgpu_cs_ctx_create2(amdgpu_device_handle dev, + uint32_t priority, + amdgpu_context_handle *context); +/** + * Create GPU execution Context + * + * Refer to amdgpu_cs_ctx_create2 for full documentation. This call + * is missing the priority parameter. + * + * \sa amdgpu_cs_ctx_create2() + * +*/ +int amdgpu_cs_ctx_create(amdgpu_device_handle dev, + amdgpu_context_handle *context); + +/** + * + * Destroy GPU execution context when not needed any more + * + * \param context - \c [in] GPU Context handle + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + * \sa amdgpu_cs_ctx_create() + * +*/ +int amdgpu_cs_ctx_free(amdgpu_context_handle context); + +/** + * Override the submission priority for the given context using a master fd. + * + * \param dev - \c [in] device handle + * \param context - \c [in] context handle for context id + * \param master_fd - \c [in] The master fd to authorize the override. + * \param priority - \c [in] The priority to assign to the context. + * + * \return 0 on success or a a negative Posix error code on failure. + */ +int amdgpu_cs_ctx_override_priority(amdgpu_device_handle dev, + amdgpu_context_handle context, + int master_fd, + unsigned priority); + +/** + * Set or query the stable power state for GPU profiling. + * + * \param dev - \c [in] device handle + * \param op - \c [in] AMDGPU_CTX_OP_{GET,SET}_STABLE_PSTATE + * \param flags - \c [in] AMDGPU_CTX_STABLE_PSTATE_* + * \param out_flags - \c [out] output current stable pstate + * + * \return 0 on success otherwise POSIX Error code. + */ +int amdgpu_cs_ctx_stable_pstate(amdgpu_context_handle context, + uint32_t op, + uint32_t flags, + uint32_t *out_flags); + +/** + * Query reset state for the specific GPU Context + * + * \param context - \c [in] GPU Context handle + * \param state - \c [out] One of AMDGPU_CTX_*_RESET + * \param hangs - \c [out] Number of hangs caused by the context. + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + * \sa amdgpu_cs_ctx_create() + * +*/ +int amdgpu_cs_query_reset_state(amdgpu_context_handle context, + uint32_t *state, uint32_t *hangs); + +/** + * Query reset state for the specific GPU Context. + * + * \param context - \c [in] GPU Context handle + * \param flags - \c [out] A combination of AMDGPU_CTX_QUERY2_FLAGS_* + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + * \sa amdgpu_cs_ctx_create() + * +*/ +int amdgpu_cs_query_reset_state2(amdgpu_context_handle context, + uint64_t *flags); + +/* + * Command Buffers Management + * +*/ + +/** + * Send request to submit command buffers to hardware. + * + * Kernel driver could use GPU Scheduler to make decision when physically + * sent this request to the hardware. Accordingly this request could be put + * in queue and sent for execution later. The only guarantee is that request + * from the same GPU context to the same ip:ip_instance:ring will be executed in + * order. + * + * The caller can specify the user fence buffer/location with the fence_info in the + * cs_request.The sequence number is returned via the 'seq_no' parameter + * in ibs_request structure. + * + * + * \param dev - \c [in] Device handle. + * See #amdgpu_device_initialize() + * \param context - \c [in] GPU Context + * \param flags - \c [in] Global submission flags + * \param ibs_request - \c [in/out] Pointer to submission requests. + * We could submit to the several + * engines/rings simulteniously as + * 'atomic' operation + * \param number_of_requests - \c [in] Number of submission requests + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + * \note It is required to pass correct resource list with buffer handles + * which will be accessible by command buffers from submission + * This will allow kernel driver to correctly implement "paging". + * Failure to do so will have unpredictable results. + * + * \sa amdgpu_command_buffer_alloc(), amdgpu_command_buffer_free(), + * amdgpu_cs_query_fence_status() + * +*/ +int amdgpu_cs_submit(amdgpu_context_handle context, + uint64_t flags, + struct amdgpu_cs_request *ibs_request, + uint32_t number_of_requests); + +/** + * Query status of Command Buffer Submission + * + * \param fence - \c [in] Structure describing fence to query + * \param timeout_ns - \c [in] Timeout value to wait + * \param flags - \c [in] Flags for the query + * \param expired - \c [out] If fence expired or not.\n + * 0 – if fence is not expired\n + * !0 - otherwise + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + * \note If UMD wants only to check operation status and returned immediately + * then timeout value as 0 must be passed. In this case success will be + * returned in the case if submission was completed or timeout error + * code. + * + * \sa amdgpu_cs_submit() +*/ +int amdgpu_cs_query_fence_status(struct amdgpu_cs_fence *fence, + uint64_t timeout_ns, + uint64_t flags, + uint32_t *expired); + +/** + * Wait for multiple fences + * + * \param fences - \c [in] The fence array to wait + * \param fence_count - \c [in] The fence count + * \param wait_all - \c [in] If true, wait all fences to be signaled, + * otherwise, wait at least one fence + * \param timeout_ns - \c [in] The timeout to wait, in nanoseconds + * \param status - \c [out] '1' for signaled, '0' for timeout + * \param first - \c [out] the index of the first signaled fence from @fences + * + * \return 0 on success + * <0 - Negative POSIX Error code + * + * \note Currently it supports only one amdgpu_device. All fences come from + * the same amdgpu_device with the same fd. +*/ +int amdgpu_cs_wait_fences(struct amdgpu_cs_fence *fences, + uint32_t fence_count, + bool wait_all, + uint64_t timeout_ns, + uint32_t *status, uint32_t *first); + +/* + * Query / Info API + * +*/ + +/** + * Query allocation size alignments + * + * UMD should query information about GPU VM MC size alignments requirements + * to be able correctly choose required allocation size and implement + * internal optimization if needed. + * + * \param dev - \c [in] Device handle. See #amdgpu_device_initialize() + * \param info - \c [out] Pointer to structure to get size alignment + * requirements + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_query_buffer_size_alignment(amdgpu_device_handle dev, + struct amdgpu_buffer_size_alignments + *info); + +/** + * Query firmware versions + * + * \param dev - \c [in] Device handle. See #amdgpu_device_initialize() + * \param fw_type - \c [in] AMDGPU_INFO_FW_* + * \param ip_instance - \c [in] Index of the IP block of the same type. + * \param index - \c [in] Index of the engine. (for SDMA and MEC) + * \param version - \c [out] Pointer to to the "version" return value + * \param feature - \c [out] Pointer to to the "feature" return value + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_query_firmware_version(amdgpu_device_handle dev, unsigned fw_type, + unsigned ip_instance, unsigned index, + uint32_t *version, uint32_t *feature); + +/** + * Query the number of HW IP instances of a certain type. + * + * \param dev - \c [in] Device handle. See #amdgpu_device_initialize() + * \param type - \c [in] Hardware IP block type = AMDGPU_HW_IP_* + * \param count - \c [out] Pointer to structure to get information + * + * \return 0 on success\n + * <0 - Negative POSIX Error code +*/ +int amdgpu_query_hw_ip_count(amdgpu_device_handle dev, unsigned type, + uint32_t *count); + +/** + * Query engine information + * + * This query allows UMD to query information different engines and their + * capabilities. + * + * \param dev - \c [in] Device handle. See #amdgpu_device_initialize() + * \param type - \c [in] Hardware IP block type = AMDGPU_HW_IP_* + * \param ip_instance - \c [in] Index of the IP block of the same type. + * \param info - \c [out] Pointer to structure to get information + * + * \return 0 on success\n + * <0 - Negative POSIX Error code +*/ +int amdgpu_query_hw_ip_info(amdgpu_device_handle dev, unsigned type, + unsigned ip_instance, + struct drm_amdgpu_info_hw_ip *info); + +/** + * Query heap information + * + * This query allows UMD to query potentially available memory resources and + * adjust their logic if necessary. + * + * \param dev - \c [in] Device handle. See #amdgpu_device_initialize() + * \param heap - \c [in] Heap type + * \param info - \c [in] Pointer to structure to get needed information + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_query_heap_info(amdgpu_device_handle dev, uint32_t heap, + uint32_t flags, struct amdgpu_heap_info *info); + +/** + * Get the CRTC ID from the mode object ID + * + * \param dev - \c [in] Device handle. See #amdgpu_device_initialize() + * \param id - \c [in] Mode object ID + * \param result - \c [in] Pointer to the CRTC ID + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_query_crtc_from_id(amdgpu_device_handle dev, unsigned id, + int32_t *result); + +/** + * Query GPU H/w Info + * + * Query hardware specific information + * + * \param dev - \c [in] Device handle. See #amdgpu_device_initialize() + * \param heap - \c [in] Heap type + * \param info - \c [in] Pointer to structure to get needed information + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_query_gpu_info(amdgpu_device_handle dev, + struct amdgpu_gpu_info *info); + +/** + * Query hardware or driver information. + * + * The return size is query-specific and depends on the "info_id" parameter. + * No more than "size" bytes is returned. + * + * \param dev - \c [in] Device handle. See #amdgpu_device_initialize() + * \param info_id - \c [in] AMDGPU_INFO_* + * \param size - \c [in] Size of the returned value. + * \param value - \c [out] Pointer to the return value. + * + * \return 0 on success\n + * <0 - Negative POSIX error code + * +*/ +int amdgpu_query_info(amdgpu_device_handle dev, unsigned info_id, + unsigned size, void *value); + +/** + * Query hardware or driver information. + * + * The return size is query-specific and depends on the "info_id" parameter. + * No more than "size" bytes is returned. + * + * \param dev - \c [in] Device handle. See #amdgpu_device_initialize() + * \param info - \c [in] amdgpu_sw_info_* + * \param value - \c [out] Pointer to the return value. + * + * \return 0 on success\n + * <0 - Negative POSIX error code + * +*/ +int amdgpu_query_sw_info(amdgpu_device_handle dev, enum amdgpu_sw_info info, + void *value); + +/** + * Query information about GDS + * + * \param dev - \c [in] Device handle. See #amdgpu_device_initialize() + * \param gds_info - \c [out] Pointer to structure to get GDS information + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_query_gds_info(amdgpu_device_handle dev, + struct amdgpu_gds_resource_info *gds_info); + +/** + * Query information about sensor. + * + * The return size is query-specific and depends on the "sensor_type" + * parameter. No more than "size" bytes is returned. + * + * \param dev - \c [in] Device handle. See #amdgpu_device_initialize() + * \param sensor_type - \c [in] AMDGPU_INFO_SENSOR_* + * \param size - \c [in] Size of the returned value. + * \param value - \c [out] Pointer to the return value. + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_query_sensor_info(amdgpu_device_handle dev, unsigned sensor_type, + unsigned size, void *value); + +/** + * Query information about video capabilities + * + * The return sizeof(struct drm_amdgpu_info_video_caps) + * + * \param dev - \c [in] Device handle. See #amdgpu_device_initialize() + * \param caps_type - \c [in] AMDGPU_INFO_VIDEO_CAPS_DECODE(ENCODE) + * \param size - \c [in] Size of the returned value. + * \param value - \c [out] Pointer to the return value. + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_query_video_caps_info(amdgpu_device_handle dev, unsigned cap_type, + unsigned size, void *value); + +/** + * Read a set of consecutive memory-mapped registers. + * Not all registers are allowed to be read by userspace. + * + * \param dev - \c [in] Device handle. See #amdgpu_device_initialize( + * \param dword_offset - \c [in] Register offset in dwords + * \param count - \c [in] The number of registers to read starting + * from the offset + * \param instance - \c [in] GRBM_GFX_INDEX selector. It may have other + * uses. Set it to 0xffffffff if unsure. + * \param flags - \c [in] Flags with additional information. + * \param values - \c [out] The pointer to return values. + * + * \return 0 on success\n + * <0 - Negative POSIX error code + * +*/ +int amdgpu_read_mm_registers(amdgpu_device_handle dev, unsigned dword_offset, + unsigned count, uint32_t instance, uint32_t flags, + uint32_t *values); + +/** + * Flag to request VA address range in the 32bit address space +*/ +#define AMDGPU_VA_RANGE_32_BIT 0x1 +#define AMDGPU_VA_RANGE_HIGH 0x2 +#define AMDGPU_VA_RANGE_REPLAYABLE 0x4 + +/** + * Allocate virtual address range + * + * \param dev - [in] Device handle. See #amdgpu_device_initialize() + * \param va_range_type - \c [in] Type of MC va range from which to allocate + * \param size - \c [in] Size of range. Size must be correctly* aligned. + * It is client responsibility to correctly aligned size based on the future + * usage of allocated range. + * \param va_base_alignment - \c [in] Overwrite base address alignment + * requirement for GPU VM MC virtual + * address assignment. Must be multiple of size alignments received as + * 'amdgpu_buffer_size_alignments'. + * If 0 use the default one. + * \param va_base_required - \c [in] Specified required va base address. + * If 0 then library choose available one. + * If !0 value will be passed and those value already "in use" then + * corresponding error status will be returned. + * \param va_base_allocated - \c [out] On return: Allocated VA base to be used + * by client. + * \param va_range_handle - \c [out] On return: Handle assigned to allocation + * \param flags - \c [in] flags for special VA range + * + * \return 0 on success\n + * >0 - AMD specific error code\n + * <0 - Negative POSIX Error code + * + * \notes \n + * It is client responsibility to correctly handle VA assignments and usage. + * Neither kernel driver nor libdrm_amdpgu are able to prevent and + * detect wrong va assignment. + * + * It is client responsibility to correctly handle multi-GPU cases and to pass + * the corresponding arrays of all devices handles where corresponding VA will + * be used. + * +*/ +int amdgpu_va_range_alloc(amdgpu_device_handle dev, + enum amdgpu_gpu_va_range va_range_type, + uint64_t size, + uint64_t va_base_alignment, + uint64_t va_base_required, + uint64_t *va_base_allocated, + amdgpu_va_handle *va_range_handle, + uint64_t flags); + +/** + * Free previously allocated virtual address range + * + * + * \param va_range_handle - \c [in] Handle assigned to VA allocation + * + * \return 0 on success\n + * >0 - AMD specific error code\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_va_range_free(amdgpu_va_handle va_range_handle); + +/** +* Query virtual address range +* +* UMD can query GPU VM range supported by each device +* to initialize its own VAM accordingly. +* +* \param dev - [in] Device handle. See #amdgpu_device_initialize() +* \param type - \c [in] Type of virtual address range +* \param offset - \c [out] Start offset of virtual address range +* \param size - \c [out] Size of virtual address range +* +* \return 0 on success\n +* <0 - Negative POSIX Error code +* +*/ + +int amdgpu_va_range_query(amdgpu_device_handle dev, + enum amdgpu_gpu_va_range type, + uint64_t *start, + uint64_t *end); + +/** + * VA mapping/unmapping for the buffer object + * + * \param bo - \c [in] BO handle + * \param offset - \c [in] Start offset to map + * \param size - \c [in] Size to map + * \param addr - \c [in] Start virtual address. + * \param flags - \c [in] Supported flags for mapping/unmapping + * \param ops - \c [in] AMDGPU_VA_OP_MAP or AMDGPU_VA_OP_UNMAP + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ + +int amdgpu_bo_va_op(amdgpu_bo_handle bo, + uint64_t offset, + uint64_t size, + uint64_t addr, + uint64_t flags, + uint32_t ops); + +/** + * VA mapping/unmapping for a buffer object or PRT region. + * + * This is not a simple drop-in extension for amdgpu_bo_va_op; instead, all + * parameters are treated "raw", i.e. size is not automatically aligned, and + * all flags must be specified explicitly. + * + * \param dev - \c [in] device handle + * \param bo - \c [in] BO handle (may be NULL) + * \param offset - \c [in] Start offset to map + * \param size - \c [in] Size to map + * \param addr - \c [in] Start virtual address. + * \param flags - \c [in] Supported flags for mapping/unmapping + * \param ops - \c [in] AMDGPU_VA_OP_MAP or AMDGPU_VA_OP_UNMAP + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ + +int amdgpu_bo_va_op_raw(amdgpu_device_handle dev, + amdgpu_bo_handle bo, + uint64_t offset, + uint64_t size, + uint64_t addr, + uint64_t flags, + uint32_t ops); + +/** + * create semaphore + * + * \param sem - \c [out] semaphore handle + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_cs_create_semaphore(amdgpu_semaphore_handle *sem); + +/** + * signal semaphore + * + * \param context - \c [in] GPU Context + * \param ip_type - \c [in] Hardware IP block type = AMDGPU_HW_IP_* + * \param ip_instance - \c [in] Index of the IP block of the same type + * \param ring - \c [in] Specify ring index of the IP + * \param sem - \c [in] semaphore handle + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_cs_signal_semaphore(amdgpu_context_handle ctx, + uint32_t ip_type, + uint32_t ip_instance, + uint32_t ring, + amdgpu_semaphore_handle sem); + +/** + * wait semaphore + * + * \param context - \c [in] GPU Context + * \param ip_type - \c [in] Hardware IP block type = AMDGPU_HW_IP_* + * \param ip_instance - \c [in] Index of the IP block of the same type + * \param ring - \c [in] Specify ring index of the IP + * \param sem - \c [in] semaphore handle + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_cs_wait_semaphore(amdgpu_context_handle ctx, + uint32_t ip_type, + uint32_t ip_instance, + uint32_t ring, + amdgpu_semaphore_handle sem); + +/** + * destroy semaphore + * + * \param sem - \c [in] semaphore handle + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_cs_destroy_semaphore(amdgpu_semaphore_handle sem); + +/** + * Get the ASIC marketing name + * + * \param dev - \c [in] Device handle. See #amdgpu_device_initialize() + * + * \return the constant string of the marketing name + * "NULL" means the ASIC is not found +*/ +const char *amdgpu_get_marketing_name(amdgpu_device_handle dev); + +/** + * Create kernel sync object + * + * \param dev - \c [in] device handle + * \param flags - \c [in] flags that affect creation + * \param syncobj - \c [out] sync object handle + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_cs_create_syncobj2(amdgpu_device_handle dev, + uint32_t flags, + uint32_t *syncobj); + +/** + * Create kernel sync object + * + * \param dev - \c [in] device handle + * \param syncobj - \c [out] sync object handle + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_cs_create_syncobj(amdgpu_device_handle dev, + uint32_t *syncobj); +/** + * Destroy kernel sync object + * + * \param dev - \c [in] device handle + * \param syncobj - \c [in] sync object handle + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_cs_destroy_syncobj(amdgpu_device_handle dev, + uint32_t syncobj); + +/** + * Reset kernel sync objects to unsignalled state. + * + * \param dev - \c [in] device handle + * \param syncobjs - \c [in] array of sync object handles + * \param syncobj_count - \c [in] number of handles in syncobjs + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_cs_syncobj_reset(amdgpu_device_handle dev, + const uint32_t *syncobjs, uint32_t syncobj_count); + +/** + * Signal kernel sync objects. + * + * \param dev - \c [in] device handle + * \param syncobjs - \c [in] array of sync object handles + * \param syncobj_count - \c [in] number of handles in syncobjs + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_cs_syncobj_signal(amdgpu_device_handle dev, + const uint32_t *syncobjs, uint32_t syncobj_count); + +/** + * Signal kernel timeline sync objects. + * + * \param dev - \c [in] device handle + * \param syncobjs - \c [in] array of sync object handles + * \param points - \c [in] array of timeline points + * \param syncobj_count - \c [in] number of handles in syncobjs + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_cs_syncobj_timeline_signal(amdgpu_device_handle dev, + const uint32_t *syncobjs, + uint64_t *points, + uint32_t syncobj_count); + +/** + * Wait for one or all sync objects to signal. + * + * \param dev - \c [in] self-explanatory + * \param handles - \c [in] array of sync object handles + * \param num_handles - \c [in] self-explanatory + * \param timeout_nsec - \c [in] self-explanatory + * \param flags - \c [in] a bitmask of DRM_SYNCOBJ_WAIT_FLAGS_* + * \param first_signaled - \c [in] self-explanatory + * + * \return 0 on success\n + * -ETIME - Timeout + * <0 - Negative POSIX Error code + * + */ +int amdgpu_cs_syncobj_wait(amdgpu_device_handle dev, + uint32_t *handles, unsigned num_handles, + int64_t timeout_nsec, unsigned flags, + uint32_t *first_signaled); + +/** + * Wait for one or all sync objects on their points to signal. + * + * \param dev - \c [in] self-explanatory + * \param handles - \c [in] array of sync object handles + * \param points - \c [in] array of sync points to wait + * \param num_handles - \c [in] self-explanatory + * \param timeout_nsec - \c [in] self-explanatory + * \param flags - \c [in] a bitmask of DRM_SYNCOBJ_WAIT_FLAGS_* + * \param first_signaled - \c [in] self-explanatory + * + * \return 0 on success\n + * -ETIME - Timeout + * <0 - Negative POSIX Error code + * + */ +int amdgpu_cs_syncobj_timeline_wait(amdgpu_device_handle dev, + uint32_t *handles, uint64_t *points, + unsigned num_handles, + int64_t timeout_nsec, unsigned flags, + uint32_t *first_signaled); +/** + * Query sync objects payloads. + * + * \param dev - \c [in] self-explanatory + * \param handles - \c [in] array of sync object handles + * \param points - \c [out] array of sync points returned, which presents + * syncobj payload. + * \param num_handles - \c [in] self-explanatory + * + * \return 0 on success\n + * -ETIME - Timeout + * <0 - Negative POSIX Error code + * + */ +int amdgpu_cs_syncobj_query(amdgpu_device_handle dev, + uint32_t *handles, uint64_t *points, + unsigned num_handles); +/** + * Query sync objects last signaled or submitted point. + * + * \param dev - \c [in] self-explanatory + * \param handles - \c [in] array of sync object handles + * \param points - \c [out] array of sync points returned, which presents + * syncobj payload. + * \param num_handles - \c [in] self-explanatory + * \param flags - \c [in] a bitmask of DRM_SYNCOBJ_QUERY_FLAGS_* + * + * \return 0 on success\n + * -ETIME - Timeout + * <0 - Negative POSIX Error code + * + */ +int amdgpu_cs_syncobj_query2(amdgpu_device_handle dev, + uint32_t *handles, uint64_t *points, + unsigned num_handles, uint32_t flags); + +/** + * Export kernel sync object to shareable fd. + * + * \param dev - \c [in] device handle + * \param syncobj - \c [in] sync object handle + * \param shared_fd - \c [out] shared file descriptor. + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_cs_export_syncobj(amdgpu_device_handle dev, + uint32_t syncobj, + int *shared_fd); +/** + * Import kernel sync object from shareable fd. + * + * \param dev - \c [in] device handle + * \param shared_fd - \c [in] shared file descriptor. + * \param syncobj - \c [out] sync object handle + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * +*/ +int amdgpu_cs_import_syncobj(amdgpu_device_handle dev, + int shared_fd, + uint32_t *syncobj); + +/** + * Export kernel sync object to a sync_file. + * + * \param dev - \c [in] device handle + * \param syncobj - \c [in] sync object handle + * \param sync_file_fd - \c [out] sync_file file descriptor. + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + */ +int amdgpu_cs_syncobj_export_sync_file(amdgpu_device_handle dev, + uint32_t syncobj, + int *sync_file_fd); + +/** + * Import kernel sync object from a sync_file. + * + * \param dev - \c [in] device handle + * \param syncobj - \c [in] sync object handle + * \param sync_file_fd - \c [in] sync_file file descriptor. + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + */ +int amdgpu_cs_syncobj_import_sync_file(amdgpu_device_handle dev, + uint32_t syncobj, + int sync_file_fd); +/** + * Export kernel timeline sync object to a sync_file. + * + * \param dev - \c [in] device handle + * \param syncobj - \c [in] sync object handle + * \param point - \c [in] timeline point + * \param flags - \c [in] flags + * \param sync_file_fd - \c [out] sync_file file descriptor. + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + */ +int amdgpu_cs_syncobj_export_sync_file2(amdgpu_device_handle dev, + uint32_t syncobj, + uint64_t point, + uint32_t flags, + int *sync_file_fd); + +/** + * Import kernel timeline sync object from a sync_file. + * + * \param dev - \c [in] device handle + * \param syncobj - \c [in] sync object handle + * \param point - \c [in] timeline point + * \param sync_file_fd - \c [in] sync_file file descriptor. + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + */ +int amdgpu_cs_syncobj_import_sync_file2(amdgpu_device_handle dev, + uint32_t syncobj, + uint64_t point, + int sync_file_fd); + +/** + * transfer between syncbojs. + * + * \param dev - \c [in] device handle + * \param dst_handle - \c [in] sync object handle + * \param dst_point - \c [in] timeline point, 0 presents dst is binary + * \param src_handle - \c [in] sync object handle + * \param src_point - \c [in] timeline point, 0 presents src is binary + * \param flags - \c [in] flags + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + */ +int amdgpu_cs_syncobj_transfer(amdgpu_device_handle dev, + uint32_t dst_handle, + uint64_t dst_point, + uint32_t src_handle, + uint64_t src_point, + uint32_t flags); + +/** + * Export an amdgpu fence as a handle (syncobj or fd). + * + * \param what AMDGPU_FENCE_TO_HANDLE_GET_{SYNCOBJ, FD} + * \param out_handle returned handle + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + */ +int amdgpu_cs_fence_to_handle(amdgpu_device_handle dev, + struct amdgpu_cs_fence *fence, + uint32_t what, + uint32_t *out_handle); + +/** + * Submit raw command submission to kernel + * + * \param dev - \c [in] device handle + * \param context - \c [in] context handle for context id + * \param bo_list_handle - \c [in] request bo list handle (0 for none) + * \param num_chunks - \c [in] number of CS chunks to submit + * \param chunks - \c [in] array of CS chunks + * \param seq_no - \c [out] output sequence number for submission. + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + */ +struct drm_amdgpu_cs_chunk; +struct drm_amdgpu_cs_chunk_dep; +struct drm_amdgpu_cs_chunk_data; + +int amdgpu_cs_submit_raw(amdgpu_device_handle dev, + amdgpu_context_handle context, + amdgpu_bo_list_handle bo_list_handle, + int num_chunks, + struct drm_amdgpu_cs_chunk *chunks, + uint64_t *seq_no); + +/** + * Submit raw command submission to the kernel with a raw BO list handle. + * + * \param dev - \c [in] device handle + * \param context - \c [in] context handle for context id + * \param bo_list_handle - \c [in] raw bo list handle (0 for none) + * \param num_chunks - \c [in] number of CS chunks to submit + * \param chunks - \c [in] array of CS chunks + * \param seq_no - \c [out] output sequence number for submission. + * + * \return 0 on success\n + * <0 - Negative POSIX Error code + * + * \sa amdgpu_bo_list_create_raw(), amdgpu_bo_list_destroy_raw() + */ +int amdgpu_cs_submit_raw2(amdgpu_device_handle dev, + amdgpu_context_handle context, + uint32_t bo_list_handle, + int num_chunks, + struct drm_amdgpu_cs_chunk *chunks, + uint64_t *seq_no); + +void amdgpu_cs_chunk_fence_to_dep(struct amdgpu_cs_fence *fence, + struct drm_amdgpu_cs_chunk_dep *dep); +void amdgpu_cs_chunk_fence_info_to_data(struct amdgpu_cs_fence_info *fence_info, + struct drm_amdgpu_cs_chunk_data *data); + +/** + * Reserve VMID + * \param context - \c [in] GPU Context + * \param flags - \c [in] TBD + * + * \return 0 on success otherwise POSIX Error code +*/ +int amdgpu_vm_reserve_vmid(amdgpu_device_handle dev, uint32_t flags); + +/** + * Free reserved VMID + * \param context - \c [in] GPU Context + * \param flags - \c [in] TBD + * + * \return 0 on success otherwise POSIX Error code +*/ +int amdgpu_vm_unreserve_vmid(amdgpu_device_handle dev, uint32_t flags); + +#ifdef __cplusplus +} +#endif +#endif /* #ifdef _AMDGPU_H_ */ diff --git a/amdgpu/amdgpu_asic_id.c b/amdgpu/amdgpu_asic_id.c new file mode 100644 index 0000000..a5007ff --- /dev/null +++ b/amdgpu/amdgpu_asic_id.c @@ -0,0 +1,161 @@ +/* + * Copyright © 2017 Advanced Micro Devices, Inc. + * 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, 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "xf86drm.h" +#include "amdgpu_drm.h" +#include "amdgpu_internal.h" + +static int parse_one_line(struct amdgpu_device *dev, const char *line) +{ + char *buf, *saveptr; + char *s_did; + uint32_t did; + char *s_rid; + uint32_t rid; + char *s_name; + char *endptr; + int r = -EINVAL; + + /* ignore empty line and commented line */ + if (strlen(line) == 0 || line[0] == '#') + return -EAGAIN; + + buf = strdup(line); + if (!buf) + return -ENOMEM; + + /* device id */ + s_did = strtok_r(buf, ",", &saveptr); + if (!s_did) + goto out; + + did = strtol(s_did, &endptr, 16); + if (*endptr) + goto out; + + if (did != dev->info.asic_id) { + r = -EAGAIN; + goto out; + } + + /* revision id */ + s_rid = strtok_r(NULL, ",", &saveptr); + if (!s_rid) + goto out; + + rid = strtol(s_rid, &endptr, 16); + if (*endptr) + goto out; + + if (rid != dev->info.pci_rev_id) { + r = -EAGAIN; + goto out; + } + + /* marketing name */ + s_name = strtok_r(NULL, ",", &saveptr); + if (!s_name) + goto out; + + /* trim leading whitespaces or tabs */ + while (isblank(*s_name)) + s_name++; + if (strlen(s_name) == 0) + goto out; + + dev->marketing_name = strdup(s_name); + if (dev->marketing_name) + r = 0; + else + r = -ENOMEM; + +out: + free(buf); + + return r; +} + +void amdgpu_parse_asic_ids(struct amdgpu_device *dev) +{ + FILE *fp; + char *line = NULL; + size_t len = 0; + ssize_t n; + int line_num = 1; + int r = 0; + + fp = fopen(AMDGPU_ASIC_ID_TABLE, "r"); + if (!fp) { + fprintf(stderr, "%s: %s\n", AMDGPU_ASIC_ID_TABLE, + strerror(errno)); + return; + } + + /* 1st valid line is file version */ + while ((n = getline(&line, &len, fp)) != -1) { + /* trim trailing newline */ + if (line[n - 1] == '\n') + line[n - 1] = '\0'; + + /* ignore empty line and commented line */ + if (strlen(line) == 0 || line[0] == '#') { + line_num++; + continue; + } + + drmMsg("%s version: %s\n", AMDGPU_ASIC_ID_TABLE, line); + break; + } + + while ((n = getline(&line, &len, fp)) != -1) { + /* trim trailing newline */ + if (line[n - 1] == '\n') + line[n - 1] = '\0'; + + r = parse_one_line(dev, line); + if (r != -EAGAIN) + break; + + line_num++; + } + + if (r == -EINVAL) { + fprintf(stderr, "Invalid format: %s: line %d: %s\n", + AMDGPU_ASIC_ID_TABLE, line_num, line); + } else if (r && r != -EAGAIN) { + fprintf(stderr, "%s: Cannot parse ASIC IDs: %s\n", + __func__, strerror(-r)); + } + + free(line); + fclose(fp); +} diff --git a/amdgpu/amdgpu_bo.c b/amdgpu/amdgpu_bo.c new file mode 100644 index 0000000..f4e0435 --- /dev/null +++ b/amdgpu/amdgpu_bo.c @@ -0,0 +1,791 @@ +/* + * Copyright © 2014 Advanced Micro Devices, Inc. + * 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, 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libdrm_macros.h" +#include "xf86drm.h" +#include "amdgpu_drm.h" +#include "amdgpu_internal.h" +#include "util_math.h" + +static int amdgpu_bo_create(amdgpu_device_handle dev, + uint64_t size, + uint32_t handle, + amdgpu_bo_handle *buf_handle) +{ + struct amdgpu_bo *bo; + int r; + + bo = calloc(1, sizeof(struct amdgpu_bo)); + if (!bo) + return -ENOMEM; + + r = handle_table_insert(&dev->bo_handles, handle, bo); + if (r) { + free(bo); + return r; + } + + atomic_set(&bo->refcount, 1); + bo->dev = dev; + bo->alloc_size = size; + bo->handle = handle; + pthread_mutex_init(&bo->cpu_access_mutex, NULL); + + *buf_handle = bo; + return 0; +} + +drm_public int amdgpu_bo_alloc(amdgpu_device_handle dev, + struct amdgpu_bo_alloc_request *alloc_buffer, + amdgpu_bo_handle *buf_handle) +{ + union drm_amdgpu_gem_create args; + int r; + + memset(&args, 0, sizeof(args)); + args.in.bo_size = alloc_buffer->alloc_size; + args.in.alignment = alloc_buffer->phys_alignment; + + /* Set the placement. */ + args.in.domains = alloc_buffer->preferred_heap; + args.in.domain_flags = alloc_buffer->flags; + + /* Allocate the buffer with the preferred heap. */ + r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_GEM_CREATE, + &args, sizeof(args)); + if (r) + goto out; + + pthread_mutex_lock(&dev->bo_table_mutex); + r = amdgpu_bo_create(dev, alloc_buffer->alloc_size, args.out.handle, + buf_handle); + pthread_mutex_unlock(&dev->bo_table_mutex); + if (r) { + drmCloseBufferHandle(dev->fd, args.out.handle); + } + +out: + return r; +} + +drm_public int amdgpu_bo_set_metadata(amdgpu_bo_handle bo, + struct amdgpu_bo_metadata *info) +{ + struct drm_amdgpu_gem_metadata args = {}; + + args.handle = bo->handle; + args.op = AMDGPU_GEM_METADATA_OP_SET_METADATA; + args.data.flags = info->flags; + args.data.tiling_info = info->tiling_info; + + if (info->size_metadata > sizeof(args.data.data)) + return -EINVAL; + + if (info->size_metadata) { + args.data.data_size_bytes = info->size_metadata; + memcpy(args.data.data, info->umd_metadata, info->size_metadata); + } + + return drmCommandWriteRead(bo->dev->fd, + DRM_AMDGPU_GEM_METADATA, + &args, sizeof(args)); +} + +drm_public int amdgpu_bo_query_info(amdgpu_bo_handle bo, + struct amdgpu_bo_info *info) +{ + struct drm_amdgpu_gem_metadata metadata = {}; + struct drm_amdgpu_gem_create_in bo_info = {}; + struct drm_amdgpu_gem_op gem_op = {}; + int r; + + /* Validate the BO passed in */ + if (!bo->handle) + return -EINVAL; + + /* Query metadata. */ + metadata.handle = bo->handle; + metadata.op = AMDGPU_GEM_METADATA_OP_GET_METADATA; + + r = drmCommandWriteRead(bo->dev->fd, DRM_AMDGPU_GEM_METADATA, + &metadata, sizeof(metadata)); + if (r) + return r; + + if (metadata.data.data_size_bytes > + sizeof(info->metadata.umd_metadata)) + return -EINVAL; + + /* Query buffer info. */ + gem_op.handle = bo->handle; + gem_op.op = AMDGPU_GEM_OP_GET_GEM_CREATE_INFO; + gem_op.value = (uintptr_t)&bo_info; + + r = drmCommandWriteRead(bo->dev->fd, DRM_AMDGPU_GEM_OP, + &gem_op, sizeof(gem_op)); + if (r) + return r; + + memset(info, 0, sizeof(*info)); + info->alloc_size = bo_info.bo_size; + info->phys_alignment = bo_info.alignment; + info->preferred_heap = bo_info.domains; + info->alloc_flags = bo_info.domain_flags; + info->metadata.flags = metadata.data.flags; + info->metadata.tiling_info = metadata.data.tiling_info; + + info->metadata.size_metadata = metadata.data.data_size_bytes; + if (metadata.data.data_size_bytes > 0) + memcpy(info->metadata.umd_metadata, metadata.data.data, + metadata.data.data_size_bytes); + + return 0; +} + +static int amdgpu_bo_export_flink(amdgpu_bo_handle bo) +{ + struct drm_gem_flink flink; + int fd, dma_fd; + uint32_t handle; + int r; + + fd = bo->dev->fd; + handle = bo->handle; + if (bo->flink_name) + return 0; + + + if (bo->dev->flink_fd != bo->dev->fd) { + r = drmPrimeHandleToFD(bo->dev->fd, bo->handle, DRM_CLOEXEC, + &dma_fd); + if (!r) { + r = drmPrimeFDToHandle(bo->dev->flink_fd, dma_fd, &handle); + close(dma_fd); + } + if (r) + return r; + fd = bo->dev->flink_fd; + } + memset(&flink, 0, sizeof(flink)); + flink.handle = handle; + + r = drmIoctl(fd, DRM_IOCTL_GEM_FLINK, &flink); + if (r) + return r; + + bo->flink_name = flink.name; + + if (bo->dev->flink_fd != bo->dev->fd) + drmCloseBufferHandle(bo->dev->flink_fd, handle); + + pthread_mutex_lock(&bo->dev->bo_table_mutex); + r = handle_table_insert(&bo->dev->bo_flink_names, bo->flink_name, bo); + pthread_mutex_unlock(&bo->dev->bo_table_mutex); + + return r; +} + +drm_public int amdgpu_bo_export(amdgpu_bo_handle bo, + enum amdgpu_bo_handle_type type, + uint32_t *shared_handle) +{ + int r; + + switch (type) { + case amdgpu_bo_handle_type_gem_flink_name: + r = amdgpu_bo_export_flink(bo); + if (r) + return r; + + *shared_handle = bo->flink_name; + return 0; + + case amdgpu_bo_handle_type_kms: + case amdgpu_bo_handle_type_kms_noimport: + *shared_handle = bo->handle; + return 0; + + case amdgpu_bo_handle_type_dma_buf_fd: + return drmPrimeHandleToFD(bo->dev->fd, bo->handle, + DRM_CLOEXEC | DRM_RDWR, + (int*)shared_handle); + } + return -EINVAL; +} + +drm_public int amdgpu_bo_import(amdgpu_device_handle dev, + enum amdgpu_bo_handle_type type, + uint32_t shared_handle, + struct amdgpu_bo_import_result *output) +{ + struct drm_gem_open open_arg = {}; + struct amdgpu_bo *bo = NULL; + uint32_t handle = 0, flink_name = 0; + uint64_t alloc_size = 0; + int r = 0; + int dma_fd; + uint64_t dma_buf_size = 0; + + /* We must maintain a list of pairs , so that we always + * return the same amdgpu_bo instance for the same handle. */ + pthread_mutex_lock(&dev->bo_table_mutex); + + /* Convert a DMA buf handle to a KMS handle now. */ + if (type == amdgpu_bo_handle_type_dma_buf_fd) { + off_t size; + + /* Get a KMS handle. */ + r = drmPrimeFDToHandle(dev->fd, shared_handle, &handle); + if (r) + goto unlock; + + /* Query the buffer size. */ + size = lseek(shared_handle, 0, SEEK_END); + if (size == (off_t)-1) { + r = -errno; + goto free_bo_handle; + } + lseek(shared_handle, 0, SEEK_SET); + + dma_buf_size = size; + shared_handle = handle; + } + + /* If we have already created a buffer with this handle, find it. */ + switch (type) { + case amdgpu_bo_handle_type_gem_flink_name: + bo = handle_table_lookup(&dev->bo_flink_names, shared_handle); + break; + + case amdgpu_bo_handle_type_dma_buf_fd: + bo = handle_table_lookup(&dev->bo_handles, shared_handle); + break; + + case amdgpu_bo_handle_type_kms: + case amdgpu_bo_handle_type_kms_noimport: + /* Importing a KMS handle in not allowed. */ + r = -EPERM; + goto unlock; + + default: + r = -EINVAL; + goto unlock; + } + + if (bo) { + /* The buffer already exists, just bump the refcount. */ + atomic_inc(&bo->refcount); + pthread_mutex_unlock(&dev->bo_table_mutex); + + output->buf_handle = bo; + output->alloc_size = bo->alloc_size; + return 0; + } + + /* Open the handle. */ + switch (type) { + case amdgpu_bo_handle_type_gem_flink_name: + open_arg.name = shared_handle; + r = drmIoctl(dev->flink_fd, DRM_IOCTL_GEM_OPEN, &open_arg); + if (r) + goto unlock; + + flink_name = shared_handle; + handle = open_arg.handle; + alloc_size = open_arg.size; + if (dev->flink_fd != dev->fd) { + r = drmPrimeHandleToFD(dev->flink_fd, handle, + DRM_CLOEXEC, &dma_fd); + if (r) + goto free_bo_handle; + r = drmPrimeFDToHandle(dev->fd, dma_fd, &handle); + close(dma_fd); + if (r) + goto free_bo_handle; + r = drmCloseBufferHandle(dev->flink_fd, + open_arg.handle); + if (r) + goto free_bo_handle; + } + open_arg.handle = 0; + break; + + case amdgpu_bo_handle_type_dma_buf_fd: + handle = shared_handle; + alloc_size = dma_buf_size; + break; + + case amdgpu_bo_handle_type_kms: + case amdgpu_bo_handle_type_kms_noimport: + assert(0); /* unreachable */ + } + + /* Initialize it. */ + r = amdgpu_bo_create(dev, alloc_size, handle, &bo); + if (r) + goto free_bo_handle; + + if (flink_name) { + bo->flink_name = flink_name; + r = handle_table_insert(&dev->bo_flink_names, flink_name, + bo); + if (r) + goto free_bo_handle; + + } + + output->buf_handle = bo; + output->alloc_size = bo->alloc_size; + pthread_mutex_unlock(&dev->bo_table_mutex); + return 0; + +free_bo_handle: + if (flink_name && open_arg.handle) + drmCloseBufferHandle(dev->flink_fd, open_arg.handle); + + if (bo) + amdgpu_bo_free(bo); + else + drmCloseBufferHandle(dev->fd, handle); +unlock: + pthread_mutex_unlock(&dev->bo_table_mutex); + return r; +} + +drm_public int amdgpu_bo_free(amdgpu_bo_handle buf_handle) +{ + struct amdgpu_device *dev; + struct amdgpu_bo *bo = buf_handle; + + assert(bo != NULL); + dev = bo->dev; + pthread_mutex_lock(&dev->bo_table_mutex); + + if (update_references(&bo->refcount, NULL)) { + /* Remove the buffer from the hash tables. */ + handle_table_remove(&dev->bo_handles, bo->handle); + + if (bo->flink_name) + handle_table_remove(&dev->bo_flink_names, + bo->flink_name); + + /* Release CPU access. */ + if (bo->cpu_map_count > 0) { + bo->cpu_map_count = 1; + amdgpu_bo_cpu_unmap(bo); + } + + drmCloseBufferHandle(dev->fd, bo->handle); + pthread_mutex_destroy(&bo->cpu_access_mutex); + free(bo); + } + + pthread_mutex_unlock(&dev->bo_table_mutex); + + return 0; +} + +drm_public void amdgpu_bo_inc_ref(amdgpu_bo_handle bo) +{ + atomic_inc(&bo->refcount); +} + +drm_public int amdgpu_bo_cpu_map(amdgpu_bo_handle bo, void **cpu) +{ + union drm_amdgpu_gem_mmap args; + void *ptr; + int r; + + pthread_mutex_lock(&bo->cpu_access_mutex); + + if (bo->cpu_ptr) { + /* already mapped */ + assert(bo->cpu_map_count > 0); + bo->cpu_map_count++; + *cpu = bo->cpu_ptr; + pthread_mutex_unlock(&bo->cpu_access_mutex); + return 0; + } + + assert(bo->cpu_map_count == 0); + + memset(&args, 0, sizeof(args)); + + /* Query the buffer address (args.addr_ptr). + * The kernel driver ignores the offset and size parameters. */ + args.in.handle = bo->handle; + + r = drmCommandWriteRead(bo->dev->fd, DRM_AMDGPU_GEM_MMAP, &args, + sizeof(args)); + if (r) { + pthread_mutex_unlock(&bo->cpu_access_mutex); + return r; + } + + /* Map the buffer. */ + ptr = drm_mmap(NULL, bo->alloc_size, PROT_READ | PROT_WRITE, MAP_SHARED, + bo->dev->fd, args.out.addr_ptr); + if (ptr == MAP_FAILED) { + pthread_mutex_unlock(&bo->cpu_access_mutex); + return -errno; + } + + bo->cpu_ptr = ptr; + bo->cpu_map_count = 1; + pthread_mutex_unlock(&bo->cpu_access_mutex); + + *cpu = ptr; + return 0; +} + +drm_public int amdgpu_bo_cpu_unmap(amdgpu_bo_handle bo) +{ + int r; + + pthread_mutex_lock(&bo->cpu_access_mutex); + assert(bo->cpu_map_count >= 0); + + if (bo->cpu_map_count == 0) { + /* not mapped */ + pthread_mutex_unlock(&bo->cpu_access_mutex); + return -EINVAL; + } + + bo->cpu_map_count--; + if (bo->cpu_map_count > 0) { + /* mapped multiple times */ + pthread_mutex_unlock(&bo->cpu_access_mutex); + return 0; + } + + r = drm_munmap(bo->cpu_ptr, bo->alloc_size) == 0 ? 0 : -errno; + bo->cpu_ptr = NULL; + pthread_mutex_unlock(&bo->cpu_access_mutex); + return r; +} + +drm_public int amdgpu_query_buffer_size_alignment(amdgpu_device_handle dev, + struct amdgpu_buffer_size_alignments *info) +{ + info->size_local = dev->dev_info.pte_fragment_size; + info->size_remote = dev->dev_info.gart_page_size; + return 0; +} + +drm_public int amdgpu_bo_wait_for_idle(amdgpu_bo_handle bo, + uint64_t timeout_ns, + bool *busy) +{ + union drm_amdgpu_gem_wait_idle args; + int r; + + memset(&args, 0, sizeof(args)); + args.in.handle = bo->handle; + args.in.timeout = amdgpu_cs_calculate_timeout(timeout_ns); + + r = drmCommandWriteRead(bo->dev->fd, DRM_AMDGPU_GEM_WAIT_IDLE, + &args, sizeof(args)); + + if (r == 0) { + *busy = args.out.status; + return 0; + } else { + fprintf(stderr, "amdgpu: GEM_WAIT_IDLE failed with %i\n", r); + return r; + } +} + +drm_public int amdgpu_find_bo_by_cpu_mapping(amdgpu_device_handle dev, + void *cpu, + uint64_t size, + amdgpu_bo_handle *buf_handle, + uint64_t *offset_in_bo) +{ + struct amdgpu_bo *bo = NULL; + uint32_t i; + int r = 0; + + if (cpu == NULL || size == 0) + return -EINVAL; + + /* + * Workaround for a buggy application which tries to import previously + * exposed CPU pointers. If we find a real world use case we should + * improve that by asking the kernel for the right handle. + */ + pthread_mutex_lock(&dev->bo_table_mutex); + for (i = 0; i < dev->bo_handles.max_key; i++) { + bo = handle_table_lookup(&dev->bo_handles, i); + if (!bo || !bo->cpu_ptr || size > bo->alloc_size) + continue; + if (cpu >= bo->cpu_ptr && + cpu < (void*)((uintptr_t)bo->cpu_ptr + bo->alloc_size)) + break; + } + + if (i < dev->bo_handles.max_key) { + atomic_inc(&bo->refcount); + *buf_handle = bo; + *offset_in_bo = (uintptr_t)cpu - (uintptr_t)bo->cpu_ptr; + } else { + *buf_handle = NULL; + *offset_in_bo = 0; + r = -ENXIO; + } + pthread_mutex_unlock(&dev->bo_table_mutex); + + return r; +} + +drm_public int amdgpu_create_bo_from_user_mem(amdgpu_device_handle dev, + void *cpu, + uint64_t size, + amdgpu_bo_handle *buf_handle) +{ + int r; + struct drm_amdgpu_gem_userptr args; + + args.addr = (uintptr_t)cpu; + args.flags = AMDGPU_GEM_USERPTR_ANONONLY | AMDGPU_GEM_USERPTR_REGISTER | + AMDGPU_GEM_USERPTR_VALIDATE; + args.size = size; + r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_GEM_USERPTR, + &args, sizeof(args)); + if (r) + goto out; + + pthread_mutex_lock(&dev->bo_table_mutex); + r = amdgpu_bo_create(dev, size, args.handle, buf_handle); + pthread_mutex_unlock(&dev->bo_table_mutex); + if (r) { + drmCloseBufferHandle(dev->fd, args.handle); + } + +out: + return r; +} + +drm_public int amdgpu_bo_list_create_raw(amdgpu_device_handle dev, + uint32_t number_of_buffers, + struct drm_amdgpu_bo_list_entry *buffers, + uint32_t *result) +{ + union drm_amdgpu_bo_list args; + int r; + + memset(&args, 0, sizeof(args)); + args.in.operation = AMDGPU_BO_LIST_OP_CREATE; + args.in.bo_number = number_of_buffers; + args.in.bo_info_size = sizeof(struct drm_amdgpu_bo_list_entry); + args.in.bo_info_ptr = (uint64_t)(uintptr_t)buffers; + + r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_BO_LIST, + &args, sizeof(args)); + if (!r) + *result = args.out.list_handle; + return r; +} + +drm_public int amdgpu_bo_list_destroy_raw(amdgpu_device_handle dev, + uint32_t bo_list) +{ + union drm_amdgpu_bo_list args; + + memset(&args, 0, sizeof(args)); + args.in.operation = AMDGPU_BO_LIST_OP_DESTROY; + args.in.list_handle = bo_list; + + return drmCommandWriteRead(dev->fd, DRM_AMDGPU_BO_LIST, + &args, sizeof(args)); +} + +drm_public int amdgpu_bo_list_create(amdgpu_device_handle dev, + uint32_t number_of_resources, + amdgpu_bo_handle *resources, + uint8_t *resource_prios, + amdgpu_bo_list_handle *result) +{ + struct drm_amdgpu_bo_list_entry *list; + union drm_amdgpu_bo_list args; + unsigned i; + int r; + + if (!number_of_resources) + return -EINVAL; + + /* overflow check for multiplication */ + if (number_of_resources > UINT32_MAX / sizeof(struct drm_amdgpu_bo_list_entry)) + return -EINVAL; + + list = malloc(number_of_resources * sizeof(struct drm_amdgpu_bo_list_entry)); + if (!list) + return -ENOMEM; + + *result = malloc(sizeof(struct amdgpu_bo_list)); + if (!*result) { + free(list); + return -ENOMEM; + } + + memset(&args, 0, sizeof(args)); + args.in.operation = AMDGPU_BO_LIST_OP_CREATE; + args.in.bo_number = number_of_resources; + args.in.bo_info_size = sizeof(struct drm_amdgpu_bo_list_entry); + args.in.bo_info_ptr = (uint64_t)(uintptr_t)list; + + for (i = 0; i < number_of_resources; i++) { + list[i].bo_handle = resources[i]->handle; + if (resource_prios) + list[i].bo_priority = resource_prios[i]; + else + list[i].bo_priority = 0; + } + + r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_BO_LIST, + &args, sizeof(args)); + free(list); + if (r) { + free(*result); + return r; + } + + (*result)->dev = dev; + (*result)->handle = args.out.list_handle; + return 0; +} + +drm_public int amdgpu_bo_list_destroy(amdgpu_bo_list_handle list) +{ + union drm_amdgpu_bo_list args; + int r; + + memset(&args, 0, sizeof(args)); + args.in.operation = AMDGPU_BO_LIST_OP_DESTROY; + args.in.list_handle = list->handle; + + r = drmCommandWriteRead(list->dev->fd, DRM_AMDGPU_BO_LIST, + &args, sizeof(args)); + + if (!r) + free(list); + + return r; +} + +drm_public int amdgpu_bo_list_update(amdgpu_bo_list_handle handle, + uint32_t number_of_resources, + amdgpu_bo_handle *resources, + uint8_t *resource_prios) +{ + struct drm_amdgpu_bo_list_entry *list; + union drm_amdgpu_bo_list args; + unsigned i; + int r; + + if (!number_of_resources) + return -EINVAL; + + /* overflow check for multiplication */ + if (number_of_resources > UINT32_MAX / sizeof(struct drm_amdgpu_bo_list_entry)) + return -EINVAL; + + list = malloc(number_of_resources * sizeof(struct drm_amdgpu_bo_list_entry)); + if (!list) + return -ENOMEM; + + args.in.operation = AMDGPU_BO_LIST_OP_UPDATE; + args.in.list_handle = handle->handle; + args.in.bo_number = number_of_resources; + args.in.bo_info_size = sizeof(struct drm_amdgpu_bo_list_entry); + args.in.bo_info_ptr = (uintptr_t)list; + + for (i = 0; i < number_of_resources; i++) { + list[i].bo_handle = resources[i]->handle; + if (resource_prios) + list[i].bo_priority = resource_prios[i]; + else + list[i].bo_priority = 0; + } + + r = drmCommandWriteRead(handle->dev->fd, DRM_AMDGPU_BO_LIST, + &args, sizeof(args)); + free(list); + return r; +} + +drm_public int amdgpu_bo_va_op(amdgpu_bo_handle bo, + uint64_t offset, + uint64_t size, + uint64_t addr, + uint64_t flags, + uint32_t ops) +{ + amdgpu_device_handle dev = bo->dev; + + size = ALIGN(size, getpagesize()); + + return amdgpu_bo_va_op_raw(dev, bo, offset, size, addr, + AMDGPU_VM_PAGE_READABLE | + AMDGPU_VM_PAGE_WRITEABLE | + AMDGPU_VM_PAGE_EXECUTABLE, ops); +} + +drm_public int amdgpu_bo_va_op_raw(amdgpu_device_handle dev, + amdgpu_bo_handle bo, + uint64_t offset, + uint64_t size, + uint64_t addr, + uint64_t flags, + uint32_t ops) +{ + struct drm_amdgpu_gem_va va; + int r; + + if (ops != AMDGPU_VA_OP_MAP && ops != AMDGPU_VA_OP_UNMAP && + ops != AMDGPU_VA_OP_REPLACE && ops != AMDGPU_VA_OP_CLEAR) + return -EINVAL; + + memset(&va, 0, sizeof(va)); + va.handle = bo ? bo->handle : 0; + va.operation = ops; + va.flags = flags; + va.va_address = addr; + va.offset_in_bo = offset; + va.map_size = size; + + r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_GEM_VA, &va, sizeof(va)); + + return r; +} diff --git a/amdgpu/amdgpu_cs.c b/amdgpu/amdgpu_cs.c new file mode 100644 index 0000000..638fd7d --- /dev/null +++ b/amdgpu/amdgpu_cs.c @@ -0,0 +1,972 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#if HAVE_ALLOCA_H +# include +#endif + +#include "xf86drm.h" +#include "amdgpu_drm.h" +#include "amdgpu_internal.h" + +static int amdgpu_cs_unreference_sem(amdgpu_semaphore_handle sem); +static int amdgpu_cs_reset_sem(amdgpu_semaphore_handle sem); + +/** + * Create command submission context + * + * \param dev - \c [in] Device handle. See #amdgpu_device_initialize() + * \param priority - \c [in] Context creation flags. See AMDGPU_CTX_PRIORITY_* + * \param context - \c [out] GPU Context handle + * + * \return 0 on success otherwise POSIX Error code +*/ +drm_public int amdgpu_cs_ctx_create2(amdgpu_device_handle dev, + uint32_t priority, + amdgpu_context_handle *context) +{ + struct amdgpu_context *gpu_context; + union drm_amdgpu_ctx args; + int i, j, k; + int r; + + if (!dev || !context) + return -EINVAL; + + gpu_context = calloc(1, sizeof(struct amdgpu_context)); + if (!gpu_context) + return -ENOMEM; + + gpu_context->dev = dev; + + r = pthread_mutex_init(&gpu_context->sequence_mutex, NULL); + if (r) + goto error; + + /* Create the context */ + memset(&args, 0, sizeof(args)); + args.in.op = AMDGPU_CTX_OP_ALLOC_CTX; + args.in.priority = priority; + + r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_CTX, &args, sizeof(args)); + if (r) + goto error; + + gpu_context->id = args.out.alloc.ctx_id; + for (i = 0; i < AMDGPU_HW_IP_NUM; i++) + for (j = 0; j < AMDGPU_HW_IP_INSTANCE_MAX_COUNT; j++) + for (k = 0; k < AMDGPU_CS_MAX_RINGS; k++) + list_inithead(&gpu_context->sem_list[i][j][k]); + *context = (amdgpu_context_handle)gpu_context; + + return 0; + +error: + pthread_mutex_destroy(&gpu_context->sequence_mutex); + free(gpu_context); + return r; +} + +drm_public int amdgpu_cs_ctx_create(amdgpu_device_handle dev, + amdgpu_context_handle *context) +{ + return amdgpu_cs_ctx_create2(dev, AMDGPU_CTX_PRIORITY_NORMAL, context); +} + +/** + * Release command submission context + * + * \param dev - \c [in] amdgpu device handle + * \param context - \c [in] amdgpu context handle + * + * \return 0 on success otherwise POSIX Error code +*/ +drm_public int amdgpu_cs_ctx_free(amdgpu_context_handle context) +{ + union drm_amdgpu_ctx args; + int i, j, k; + int r; + + if (!context) + return -EINVAL; + + pthread_mutex_destroy(&context->sequence_mutex); + + /* now deal with kernel side */ + memset(&args, 0, sizeof(args)); + args.in.op = AMDGPU_CTX_OP_FREE_CTX; + args.in.ctx_id = context->id; + r = drmCommandWriteRead(context->dev->fd, DRM_AMDGPU_CTX, + &args, sizeof(args)); + for (i = 0; i < AMDGPU_HW_IP_NUM; i++) { + for (j = 0; j < AMDGPU_HW_IP_INSTANCE_MAX_COUNT; j++) { + for (k = 0; k < AMDGPU_CS_MAX_RINGS; k++) { + amdgpu_semaphore_handle sem; + LIST_FOR_EACH_ENTRY(sem, &context->sem_list[i][j][k], list) { + list_del(&sem->list); + amdgpu_cs_reset_sem(sem); + amdgpu_cs_unreference_sem(sem); + } + } + } + } + free(context); + + return r; +} + +drm_public int amdgpu_cs_ctx_override_priority(amdgpu_device_handle dev, + amdgpu_context_handle context, + int master_fd, + unsigned priority) +{ + union drm_amdgpu_sched args; + int r; + + if (!dev || !context || master_fd < 0) + return -EINVAL; + + memset(&args, 0, sizeof(args)); + + args.in.op = AMDGPU_SCHED_OP_CONTEXT_PRIORITY_OVERRIDE; + args.in.fd = dev->fd; + args.in.priority = priority; + args.in.ctx_id = context->id; + + r = drmCommandWrite(master_fd, DRM_AMDGPU_SCHED, &args, sizeof(args)); + if (r) + return r; + + return 0; +} + +drm_public int amdgpu_cs_ctx_stable_pstate(amdgpu_context_handle context, + uint32_t op, + uint32_t flags, + uint32_t *out_flags) +{ + union drm_amdgpu_ctx args; + int r; + + if (!context) + return -EINVAL; + + memset(&args, 0, sizeof(args)); + args.in.op = op; + args.in.ctx_id = context->id; + args.in.flags = flags; + r = drmCommandWriteRead(context->dev->fd, DRM_AMDGPU_CTX, + &args, sizeof(args)); + if (!r && out_flags) + *out_flags = args.out.pstate.flags; + return r; +} + +drm_public int amdgpu_cs_query_reset_state(amdgpu_context_handle context, + uint32_t *state, uint32_t *hangs) +{ + union drm_amdgpu_ctx args; + int r; + + if (!context) + return -EINVAL; + + memset(&args, 0, sizeof(args)); + args.in.op = AMDGPU_CTX_OP_QUERY_STATE; + args.in.ctx_id = context->id; + r = drmCommandWriteRead(context->dev->fd, DRM_AMDGPU_CTX, + &args, sizeof(args)); + if (!r) { + *state = args.out.state.reset_status; + *hangs = args.out.state.hangs; + } + return r; +} + +drm_public int amdgpu_cs_query_reset_state2(amdgpu_context_handle context, + uint64_t *flags) +{ + union drm_amdgpu_ctx args; + int r; + + if (!context) + return -EINVAL; + + memset(&args, 0, sizeof(args)); + args.in.op = AMDGPU_CTX_OP_QUERY_STATE2; + args.in.ctx_id = context->id; + r = drmCommandWriteRead(context->dev->fd, DRM_AMDGPU_CTX, + &args, sizeof(args)); + if (!r) + *flags = args.out.state.flags; + return r; +} + +/** + * Submit command to kernel DRM + * \param dev - \c [in] Device handle + * \param context - \c [in] GPU Context + * \param ibs_request - \c [in] Pointer to submission requests + * \param fence - \c [out] return fence for this submission + * + * \return 0 on success otherwise POSIX Error code + * \sa amdgpu_cs_submit() +*/ +static int amdgpu_cs_submit_one(amdgpu_context_handle context, + struct amdgpu_cs_request *ibs_request) +{ + struct drm_amdgpu_cs_chunk *chunks; + struct drm_amdgpu_cs_chunk_data *chunk_data; + struct drm_amdgpu_cs_chunk_dep *dependencies = NULL; + struct drm_amdgpu_cs_chunk_dep *sem_dependencies = NULL; + amdgpu_device_handle dev = context->dev; + struct list_head *sem_list; + amdgpu_semaphore_handle sem, tmp; + uint32_t i, size, num_chunks, bo_list_handle = 0, sem_count = 0; + uint64_t seq_no; + bool user_fence; + int r = 0; + + if (ibs_request->ip_type >= AMDGPU_HW_IP_NUM) + return -EINVAL; + if (ibs_request->ring >= AMDGPU_CS_MAX_RINGS) + return -EINVAL; + if (ibs_request->number_of_ibs == 0) { + ibs_request->seq_no = AMDGPU_NULL_SUBMIT_SEQ; + return 0; + } + user_fence = (ibs_request->fence_info.handle != NULL); + + size = ibs_request->number_of_ibs + (user_fence ? 2 : 1) + 1; + + chunks = alloca(sizeof(struct drm_amdgpu_cs_chunk) * size); + + size = ibs_request->number_of_ibs + (user_fence ? 1 : 0); + + chunk_data = alloca(sizeof(struct drm_amdgpu_cs_chunk_data) * size); + + if (ibs_request->resources) + bo_list_handle = ibs_request->resources->handle; + num_chunks = ibs_request->number_of_ibs; + /* IB chunks */ + for (i = 0; i < ibs_request->number_of_ibs; i++) { + struct amdgpu_cs_ib_info *ib; + chunks[i].chunk_id = AMDGPU_CHUNK_ID_IB; + chunks[i].length_dw = sizeof(struct drm_amdgpu_cs_chunk_ib) / 4; + chunks[i].chunk_data = (uint64_t)(uintptr_t)&chunk_data[i]; + + ib = &ibs_request->ibs[i]; + + chunk_data[i].ib_data._pad = 0; + chunk_data[i].ib_data.va_start = ib->ib_mc_address; + chunk_data[i].ib_data.ib_bytes = ib->size * 4; + chunk_data[i].ib_data.ip_type = ibs_request->ip_type; + chunk_data[i].ib_data.ip_instance = ibs_request->ip_instance; + chunk_data[i].ib_data.ring = ibs_request->ring; + chunk_data[i].ib_data.flags = ib->flags; + } + + pthread_mutex_lock(&context->sequence_mutex); + + if (user_fence) { + i = num_chunks++; + + /* fence chunk */ + chunks[i].chunk_id = AMDGPU_CHUNK_ID_FENCE; + chunks[i].length_dw = sizeof(struct drm_amdgpu_cs_chunk_fence) / 4; + chunks[i].chunk_data = (uint64_t)(uintptr_t)&chunk_data[i]; + + /* fence bo handle */ + chunk_data[i].fence_data.handle = ibs_request->fence_info.handle->handle; + /* offset */ + chunk_data[i].fence_data.offset = + ibs_request->fence_info.offset * sizeof(uint64_t); + } + + if (ibs_request->number_of_dependencies) { + dependencies = alloca(sizeof(struct drm_amdgpu_cs_chunk_dep) * + ibs_request->number_of_dependencies); + if (!dependencies) { + r = -ENOMEM; + goto error_unlock; + } + + for (i = 0; i < ibs_request->number_of_dependencies; ++i) { + struct amdgpu_cs_fence *info = &ibs_request->dependencies[i]; + struct drm_amdgpu_cs_chunk_dep *dep = &dependencies[i]; + dep->ip_type = info->ip_type; + dep->ip_instance = info->ip_instance; + dep->ring = info->ring; + dep->ctx_id = info->context->id; + dep->handle = info->fence; + } + + i = num_chunks++; + + /* dependencies chunk */ + chunks[i].chunk_id = AMDGPU_CHUNK_ID_DEPENDENCIES; + chunks[i].length_dw = sizeof(struct drm_amdgpu_cs_chunk_dep) / 4 + * ibs_request->number_of_dependencies; + chunks[i].chunk_data = (uint64_t)(uintptr_t)dependencies; + } + + sem_list = &context->sem_list[ibs_request->ip_type][ibs_request->ip_instance][ibs_request->ring]; + LIST_FOR_EACH_ENTRY(sem, sem_list, list) + sem_count++; + if (sem_count) { + sem_dependencies = alloca(sizeof(struct drm_amdgpu_cs_chunk_dep) * sem_count); + if (!sem_dependencies) { + r = -ENOMEM; + goto error_unlock; + } + sem_count = 0; + LIST_FOR_EACH_ENTRY_SAFE(sem, tmp, sem_list, list) { + struct amdgpu_cs_fence *info = &sem->signal_fence; + struct drm_amdgpu_cs_chunk_dep *dep = &sem_dependencies[sem_count++]; + dep->ip_type = info->ip_type; + dep->ip_instance = info->ip_instance; + dep->ring = info->ring; + dep->ctx_id = info->context->id; + dep->handle = info->fence; + + list_del(&sem->list); + amdgpu_cs_reset_sem(sem); + amdgpu_cs_unreference_sem(sem); + } + i = num_chunks++; + + /* dependencies chunk */ + chunks[i].chunk_id = AMDGPU_CHUNK_ID_DEPENDENCIES; + chunks[i].length_dw = sizeof(struct drm_amdgpu_cs_chunk_dep) / 4 * sem_count; + chunks[i].chunk_data = (uint64_t)(uintptr_t)sem_dependencies; + } + + r = amdgpu_cs_submit_raw2(dev, context, bo_list_handle, num_chunks, + chunks, &seq_no); + if (r) + goto error_unlock; + + ibs_request->seq_no = seq_no; + context->last_seq[ibs_request->ip_type][ibs_request->ip_instance][ibs_request->ring] = ibs_request->seq_no; +error_unlock: + pthread_mutex_unlock(&context->sequence_mutex); + return r; +} + +drm_public int amdgpu_cs_submit(amdgpu_context_handle context, + uint64_t flags, + struct amdgpu_cs_request *ibs_request, + uint32_t number_of_requests) +{ + uint32_t i; + int r; + + if (!context || !ibs_request) + return -EINVAL; + + r = 0; + for (i = 0; i < number_of_requests; i++) { + r = amdgpu_cs_submit_one(context, ibs_request); + if (r) + break; + ibs_request++; + } + + return r; +} + +/** + * Calculate absolute timeout. + * + * \param timeout - \c [in] timeout in nanoseconds. + * + * \return absolute timeout in nanoseconds +*/ +drm_private uint64_t amdgpu_cs_calculate_timeout(uint64_t timeout) +{ + int r; + + if (timeout != AMDGPU_TIMEOUT_INFINITE) { + struct timespec current; + uint64_t current_ns; + r = clock_gettime(CLOCK_MONOTONIC, ¤t); + if (r) { + fprintf(stderr, "clock_gettime() returned error (%d)!", errno); + return AMDGPU_TIMEOUT_INFINITE; + } + + current_ns = ((uint64_t)current.tv_sec) * 1000000000ull; + current_ns += current.tv_nsec; + timeout += current_ns; + if (timeout < current_ns) + timeout = AMDGPU_TIMEOUT_INFINITE; + } + return timeout; +} + +static int amdgpu_ioctl_wait_cs(amdgpu_context_handle context, + unsigned ip, + unsigned ip_instance, + uint32_t ring, + uint64_t handle, + uint64_t timeout_ns, + uint64_t flags, + bool *busy) +{ + amdgpu_device_handle dev = context->dev; + union drm_amdgpu_wait_cs args; + int r; + + memset(&args, 0, sizeof(args)); + args.in.handle = handle; + args.in.ip_type = ip; + args.in.ip_instance = ip_instance; + args.in.ring = ring; + args.in.ctx_id = context->id; + + if (flags & AMDGPU_QUERY_FENCE_TIMEOUT_IS_ABSOLUTE) + args.in.timeout = timeout_ns; + else + args.in.timeout = amdgpu_cs_calculate_timeout(timeout_ns); + + r = drmIoctl(dev->fd, DRM_IOCTL_AMDGPU_WAIT_CS, &args); + if (r) + return -errno; + + *busy = args.out.status; + return 0; +} + +drm_public int amdgpu_cs_query_fence_status(struct amdgpu_cs_fence *fence, + uint64_t timeout_ns, + uint64_t flags, + uint32_t *expired) +{ + bool busy = true; + int r; + + if (!fence || !expired || !fence->context) + return -EINVAL; + if (fence->ip_type >= AMDGPU_HW_IP_NUM) + return -EINVAL; + if (fence->ring >= AMDGPU_CS_MAX_RINGS) + return -EINVAL; + if (fence->fence == AMDGPU_NULL_SUBMIT_SEQ) { + *expired = true; + return 0; + } + + *expired = false; + + r = amdgpu_ioctl_wait_cs(fence->context, fence->ip_type, + fence->ip_instance, fence->ring, + fence->fence, timeout_ns, flags, &busy); + + if (!r && !busy) + *expired = true; + + return r; +} + +static int amdgpu_ioctl_wait_fences(struct amdgpu_cs_fence *fences, + uint32_t fence_count, + bool wait_all, + uint64_t timeout_ns, + uint32_t *status, + uint32_t *first) +{ + struct drm_amdgpu_fence *drm_fences; + amdgpu_device_handle dev = fences[0].context->dev; + union drm_amdgpu_wait_fences args; + int r; + uint32_t i; + + drm_fences = alloca(sizeof(struct drm_amdgpu_fence) * fence_count); + for (i = 0; i < fence_count; i++) { + drm_fences[i].ctx_id = fences[i].context->id; + drm_fences[i].ip_type = fences[i].ip_type; + drm_fences[i].ip_instance = fences[i].ip_instance; + drm_fences[i].ring = fences[i].ring; + drm_fences[i].seq_no = fences[i].fence; + } + + memset(&args, 0, sizeof(args)); + args.in.fences = (uint64_t)(uintptr_t)drm_fences; + args.in.fence_count = fence_count; + args.in.wait_all = wait_all; + args.in.timeout_ns = amdgpu_cs_calculate_timeout(timeout_ns); + + r = drmIoctl(dev->fd, DRM_IOCTL_AMDGPU_WAIT_FENCES, &args); + if (r) + return -errno; + + *status = args.out.status; + + if (first) + *first = args.out.first_signaled; + + return 0; +} + +drm_public int amdgpu_cs_wait_fences(struct amdgpu_cs_fence *fences, + uint32_t fence_count, + bool wait_all, + uint64_t timeout_ns, + uint32_t *status, + uint32_t *first) +{ + uint32_t i; + + /* Sanity check */ + if (!fences || !status || !fence_count) + return -EINVAL; + + for (i = 0; i < fence_count; i++) { + if (NULL == fences[i].context) + return -EINVAL; + if (fences[i].ip_type >= AMDGPU_HW_IP_NUM) + return -EINVAL; + if (fences[i].ring >= AMDGPU_CS_MAX_RINGS) + return -EINVAL; + } + + *status = 0; + + return amdgpu_ioctl_wait_fences(fences, fence_count, wait_all, + timeout_ns, status, first); +} + +drm_public int amdgpu_cs_create_semaphore(amdgpu_semaphore_handle *sem) +{ + struct amdgpu_semaphore *gpu_semaphore; + + if (!sem) + return -EINVAL; + + gpu_semaphore = calloc(1, sizeof(struct amdgpu_semaphore)); + if (!gpu_semaphore) + return -ENOMEM; + + atomic_set(&gpu_semaphore->refcount, 1); + *sem = gpu_semaphore; + + return 0; +} + +drm_public int amdgpu_cs_signal_semaphore(amdgpu_context_handle ctx, + uint32_t ip_type, + uint32_t ip_instance, + uint32_t ring, + amdgpu_semaphore_handle sem) +{ + if (!ctx || !sem) + return -EINVAL; + if (ip_type >= AMDGPU_HW_IP_NUM) + return -EINVAL; + if (ring >= AMDGPU_CS_MAX_RINGS) + return -EINVAL; + /* sem has been signaled */ + if (sem->signal_fence.context) + return -EINVAL; + pthread_mutex_lock(&ctx->sequence_mutex); + sem->signal_fence.context = ctx; + sem->signal_fence.ip_type = ip_type; + sem->signal_fence.ip_instance = ip_instance; + sem->signal_fence.ring = ring; + sem->signal_fence.fence = ctx->last_seq[ip_type][ip_instance][ring]; + update_references(NULL, &sem->refcount); + pthread_mutex_unlock(&ctx->sequence_mutex); + return 0; +} + +drm_public int amdgpu_cs_wait_semaphore(amdgpu_context_handle ctx, + uint32_t ip_type, + uint32_t ip_instance, + uint32_t ring, + amdgpu_semaphore_handle sem) +{ + if (!ctx || !sem) + return -EINVAL; + if (ip_type >= AMDGPU_HW_IP_NUM) + return -EINVAL; + if (ring >= AMDGPU_CS_MAX_RINGS) + return -EINVAL; + /* must signal first */ + if (!sem->signal_fence.context) + return -EINVAL; + + pthread_mutex_lock(&ctx->sequence_mutex); + list_add(&sem->list, &ctx->sem_list[ip_type][ip_instance][ring]); + pthread_mutex_unlock(&ctx->sequence_mutex); + return 0; +} + +static int amdgpu_cs_reset_sem(amdgpu_semaphore_handle sem) +{ + if (!sem || !sem->signal_fence.context) + return -EINVAL; + + sem->signal_fence.context = NULL; + sem->signal_fence.ip_type = 0; + sem->signal_fence.ip_instance = 0; + sem->signal_fence.ring = 0; + sem->signal_fence.fence = 0; + + return 0; +} + +static int amdgpu_cs_unreference_sem(amdgpu_semaphore_handle sem) +{ + if (!sem) + return -EINVAL; + + if (update_references(&sem->refcount, NULL)) + free(sem); + return 0; +} + +drm_public int amdgpu_cs_destroy_semaphore(amdgpu_semaphore_handle sem) +{ + return amdgpu_cs_unreference_sem(sem); +} + +drm_public int amdgpu_cs_create_syncobj2(amdgpu_device_handle dev, + uint32_t flags, + uint32_t *handle) +{ + if (NULL == dev) + return -EINVAL; + + return drmSyncobjCreate(dev->fd, flags, handle); +} + +drm_public int amdgpu_cs_create_syncobj(amdgpu_device_handle dev, + uint32_t *handle) +{ + if (NULL == dev) + return -EINVAL; + + return drmSyncobjCreate(dev->fd, 0, handle); +} + +drm_public int amdgpu_cs_destroy_syncobj(amdgpu_device_handle dev, + uint32_t handle) +{ + if (NULL == dev) + return -EINVAL; + + return drmSyncobjDestroy(dev->fd, handle); +} + +drm_public int amdgpu_cs_syncobj_reset(amdgpu_device_handle dev, + const uint32_t *syncobjs, + uint32_t syncobj_count) +{ + if (NULL == dev) + return -EINVAL; + + return drmSyncobjReset(dev->fd, syncobjs, syncobj_count); +} + +drm_public int amdgpu_cs_syncobj_signal(amdgpu_device_handle dev, + const uint32_t *syncobjs, + uint32_t syncobj_count) +{ + if (NULL == dev) + return -EINVAL; + + return drmSyncobjSignal(dev->fd, syncobjs, syncobj_count); +} + +drm_public int amdgpu_cs_syncobj_timeline_signal(amdgpu_device_handle dev, + const uint32_t *syncobjs, + uint64_t *points, + uint32_t syncobj_count) +{ + if (NULL == dev) + return -EINVAL; + + return drmSyncobjTimelineSignal(dev->fd, syncobjs, + points, syncobj_count); +} + +drm_public int amdgpu_cs_syncobj_wait(amdgpu_device_handle dev, + uint32_t *handles, unsigned num_handles, + int64_t timeout_nsec, unsigned flags, + uint32_t *first_signaled) +{ + if (NULL == dev) + return -EINVAL; + + return drmSyncobjWait(dev->fd, handles, num_handles, timeout_nsec, + flags, first_signaled); +} + +drm_public int amdgpu_cs_syncobj_timeline_wait(amdgpu_device_handle dev, + uint32_t *handles, uint64_t *points, + unsigned num_handles, + int64_t timeout_nsec, unsigned flags, + uint32_t *first_signaled) +{ + if (NULL == dev) + return -EINVAL; + + return drmSyncobjTimelineWait(dev->fd, handles, points, num_handles, + timeout_nsec, flags, first_signaled); +} + +drm_public int amdgpu_cs_syncobj_query(amdgpu_device_handle dev, + uint32_t *handles, uint64_t *points, + unsigned num_handles) +{ + if (NULL == dev) + return -EINVAL; + + return drmSyncobjQuery(dev->fd, handles, points, num_handles); +} + +drm_public int amdgpu_cs_syncobj_query2(amdgpu_device_handle dev, + uint32_t *handles, uint64_t *points, + unsigned num_handles, uint32_t flags) +{ + if (!dev) + return -EINVAL; + + return drmSyncobjQuery2(dev->fd, handles, points, num_handles, flags); +} + +drm_public int amdgpu_cs_export_syncobj(amdgpu_device_handle dev, + uint32_t handle, + int *shared_fd) +{ + if (NULL == dev) + return -EINVAL; + + return drmSyncobjHandleToFD(dev->fd, handle, shared_fd); +} + +drm_public int amdgpu_cs_import_syncobj(amdgpu_device_handle dev, + int shared_fd, + uint32_t *handle) +{ + if (NULL == dev) + return -EINVAL; + + return drmSyncobjFDToHandle(dev->fd, shared_fd, handle); +} + +drm_public int amdgpu_cs_syncobj_export_sync_file(amdgpu_device_handle dev, + uint32_t syncobj, + int *sync_file_fd) +{ + if (NULL == dev) + return -EINVAL; + + return drmSyncobjExportSyncFile(dev->fd, syncobj, sync_file_fd); +} + +drm_public int amdgpu_cs_syncobj_import_sync_file(amdgpu_device_handle dev, + uint32_t syncobj, + int sync_file_fd) +{ + if (NULL == dev) + return -EINVAL; + + return drmSyncobjImportSyncFile(dev->fd, syncobj, sync_file_fd); +} + +drm_public int amdgpu_cs_syncobj_export_sync_file2(amdgpu_device_handle dev, + uint32_t syncobj, + uint64_t point, + uint32_t flags, + int *sync_file_fd) +{ + uint32_t binary_handle; + int ret; + + if (NULL == dev) + return -EINVAL; + + if (!point) + return drmSyncobjExportSyncFile(dev->fd, syncobj, sync_file_fd); + + ret = drmSyncobjCreate(dev->fd, 0, &binary_handle); + if (ret) + return ret; + + ret = drmSyncobjTransfer(dev->fd, binary_handle, 0, + syncobj, point, flags); + if (ret) + goto out; + ret = drmSyncobjExportSyncFile(dev->fd, binary_handle, sync_file_fd); +out: + drmSyncobjDestroy(dev->fd, binary_handle); + return ret; +} + +drm_public int amdgpu_cs_syncobj_import_sync_file2(amdgpu_device_handle dev, + uint32_t syncobj, + uint64_t point, + int sync_file_fd) +{ + uint32_t binary_handle; + int ret; + + if (NULL == dev) + return -EINVAL; + + if (!point) + return drmSyncobjImportSyncFile(dev->fd, syncobj, sync_file_fd); + + ret = drmSyncobjCreate(dev->fd, 0, &binary_handle); + if (ret) + return ret; + ret = drmSyncobjImportSyncFile(dev->fd, binary_handle, sync_file_fd); + if (ret) + goto out; + ret = drmSyncobjTransfer(dev->fd, syncobj, point, + binary_handle, 0, 0); +out: + drmSyncobjDestroy(dev->fd, binary_handle); + return ret; +} + +drm_public int amdgpu_cs_syncobj_transfer(amdgpu_device_handle dev, + uint32_t dst_handle, + uint64_t dst_point, + uint32_t src_handle, + uint64_t src_point, + uint32_t flags) +{ + if (NULL == dev) + return -EINVAL; + + return drmSyncobjTransfer(dev->fd, + dst_handle, dst_point, + src_handle, src_point, + flags); +} + +drm_public int amdgpu_cs_submit_raw(amdgpu_device_handle dev, + amdgpu_context_handle context, + amdgpu_bo_list_handle bo_list_handle, + int num_chunks, + struct drm_amdgpu_cs_chunk *chunks, + uint64_t *seq_no) +{ + union drm_amdgpu_cs cs; + uint64_t *chunk_array; + int i, r; + if (num_chunks == 0) + return -EINVAL; + + memset(&cs, 0, sizeof(cs)); + chunk_array = alloca(sizeof(uint64_t) * num_chunks); + for (i = 0; i < num_chunks; i++) + chunk_array[i] = (uint64_t)(uintptr_t)&chunks[i]; + cs.in.chunks = (uint64_t)(uintptr_t)chunk_array; + cs.in.ctx_id = context->id; + cs.in.bo_list_handle = bo_list_handle ? bo_list_handle->handle : 0; + cs.in.num_chunks = num_chunks; + r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_CS, + &cs, sizeof(cs)); + if (r) + return r; + + if (seq_no) + *seq_no = cs.out.handle; + return 0; +} + +drm_public int amdgpu_cs_submit_raw2(amdgpu_device_handle dev, + amdgpu_context_handle context, + uint32_t bo_list_handle, + int num_chunks, + struct drm_amdgpu_cs_chunk *chunks, + uint64_t *seq_no) +{ + union drm_amdgpu_cs cs; + uint64_t *chunk_array; + int i, r; + + memset(&cs, 0, sizeof(cs)); + chunk_array = alloca(sizeof(uint64_t) * num_chunks); + for (i = 0; i < num_chunks; i++) + chunk_array[i] = (uint64_t)(uintptr_t)&chunks[i]; + cs.in.chunks = (uint64_t)(uintptr_t)chunk_array; + cs.in.ctx_id = context->id; + cs.in.bo_list_handle = bo_list_handle; + cs.in.num_chunks = num_chunks; + r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_CS, + &cs, sizeof(cs)); + if (!r && seq_no) + *seq_no = cs.out.handle; + return r; +} + +drm_public void amdgpu_cs_chunk_fence_info_to_data(struct amdgpu_cs_fence_info *fence_info, + struct drm_amdgpu_cs_chunk_data *data) +{ + data->fence_data.handle = fence_info->handle->handle; + data->fence_data.offset = fence_info->offset * sizeof(uint64_t); +} + +drm_public void amdgpu_cs_chunk_fence_to_dep(struct amdgpu_cs_fence *fence, + struct drm_amdgpu_cs_chunk_dep *dep) +{ + dep->ip_type = fence->ip_type; + dep->ip_instance = fence->ip_instance; + dep->ring = fence->ring; + dep->ctx_id = fence->context->id; + dep->handle = fence->fence; +} + +drm_public int amdgpu_cs_fence_to_handle(amdgpu_device_handle dev, + struct amdgpu_cs_fence *fence, + uint32_t what, + uint32_t *out_handle) +{ + union drm_amdgpu_fence_to_handle fth; + int r; + + memset(&fth, 0, sizeof(fth)); + fth.in.fence.ctx_id = fence->context->id; + fth.in.fence.ip_type = fence->ip_type; + fth.in.fence.ip_instance = fence->ip_instance; + fth.in.fence.ring = fence->ring; + fth.in.fence.seq_no = fence->fence; + fth.in.what = what; + + r = drmCommandWriteRead(dev->fd, DRM_AMDGPU_FENCE_TO_HANDLE, + &fth, sizeof(fth)); + if (r == 0) + *out_handle = fth.out.handle; + return r; +} diff --git a/amdgpu/amdgpu_device.c b/amdgpu/amdgpu_device.c new file mode 100644 index 0000000..aeb5e3c --- /dev/null +++ b/amdgpu/amdgpu_device.c @@ -0,0 +1,316 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 amdgpu_device.c + * + * Implementation of functions for AMD GPU device + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "xf86drm.h" +#include "amdgpu_drm.h" +#include "amdgpu_internal.h" +#include "util_math.h" + +#define PTR_TO_UINT(x) ((unsigned)((intptr_t)(x))) + +static pthread_mutex_t dev_mutex = PTHREAD_MUTEX_INITIALIZER; +static amdgpu_device_handle dev_list; + +static int fd_compare(int fd1, int fd2) +{ + char *name1 = drmGetPrimaryDeviceNameFromFd(fd1); + char *name2 = drmGetPrimaryDeviceNameFromFd(fd2); + int result; + + if (name1 == NULL || name2 == NULL) { + free(name1); + free(name2); + return 0; + } + + result = strcmp(name1, name2); + free(name1); + free(name2); + + return result; +} + +/** +* Get the authenticated form fd, +* +* \param fd - \c [in] File descriptor for AMD GPU device +* \param auth - \c [out] Pointer to output the fd is authenticated or not +* A render node fd, output auth = 0 +* A legacy fd, get the authenticated for compatibility root +* +* \return 0 on success\n +* >0 - AMD specific error code\n +* <0 - Negative POSIX Error code +*/ +static int amdgpu_get_auth(int fd, int *auth) +{ + int r = 0; + drm_client_t client = {}; + + if (drmGetNodeTypeFromFd(fd) == DRM_NODE_RENDER) + *auth = 0; + else { + client.idx = 0; + r = drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client); + if (!r) + *auth = client.auth; + } + return r; +} + +static void amdgpu_device_free_internal(amdgpu_device_handle dev) +{ + amdgpu_device_handle *node = &dev_list; + + pthread_mutex_lock(&dev_mutex); + while (*node != dev && (*node)->next) + node = &(*node)->next; + *node = (*node)->next; + pthread_mutex_unlock(&dev_mutex); + + close(dev->fd); + if ((dev->flink_fd >= 0) && (dev->fd != dev->flink_fd)) + close(dev->flink_fd); + + amdgpu_vamgr_deinit(&dev->vamgr_32); + amdgpu_vamgr_deinit(&dev->vamgr); + amdgpu_vamgr_deinit(&dev->vamgr_high_32); + amdgpu_vamgr_deinit(&dev->vamgr_high); + handle_table_fini(&dev->bo_handles); + handle_table_fini(&dev->bo_flink_names); + pthread_mutex_destroy(&dev->bo_table_mutex); + free(dev->marketing_name); + free(dev); +} + +/** + * Assignment between two amdgpu_device pointers with reference counting. + * + * Usage: + * struct amdgpu_device *dst = ... , *src = ...; + * + * dst = src; + * // No reference counting. Only use this when you need to move + * // a reference from one pointer to another. + * + * amdgpu_device_reference(&dst, src); + * // Reference counters are updated. dst is decremented and src is + * // incremented. dst is freed if its reference counter is 0. + */ +static void amdgpu_device_reference(struct amdgpu_device **dst, + struct amdgpu_device *src) +{ + if (update_references(&(*dst)->refcount, &src->refcount)) + amdgpu_device_free_internal(*dst); + *dst = src; +} + +drm_public int amdgpu_device_initialize(int fd, + uint32_t *major_version, + uint32_t *minor_version, + amdgpu_device_handle *device_handle) +{ + struct amdgpu_device *dev; + drmVersionPtr version; + int r; + int flag_auth = 0; + int flag_authexist=0; + uint32_t accel_working = 0; + uint64_t start, max; + + *device_handle = NULL; + + pthread_mutex_lock(&dev_mutex); + r = amdgpu_get_auth(fd, &flag_auth); + if (r) { + fprintf(stderr, "%s: amdgpu_get_auth (1) failed (%i)\n", + __func__, r); + pthread_mutex_unlock(&dev_mutex); + return r; + } + + for (dev = dev_list; dev; dev = dev->next) + if (fd_compare(dev->fd, fd) == 0) + break; + + if (dev) { + r = amdgpu_get_auth(dev->fd, &flag_authexist); + if (r) { + fprintf(stderr, "%s: amdgpu_get_auth (2) failed (%i)\n", + __func__, r); + pthread_mutex_unlock(&dev_mutex); + return r; + } + if ((flag_auth) && (!flag_authexist)) { + dev->flink_fd = fcntl(fd, F_DUPFD_CLOEXEC, 0); + } + *major_version = dev->major_version; + *minor_version = dev->minor_version; + amdgpu_device_reference(device_handle, dev); + pthread_mutex_unlock(&dev_mutex); + return 0; + } + + dev = calloc(1, sizeof(struct amdgpu_device)); + if (!dev) { + fprintf(stderr, "%s: calloc failed\n", __func__); + pthread_mutex_unlock(&dev_mutex); + return -ENOMEM; + } + + dev->fd = -1; + dev->flink_fd = -1; + + atomic_set(&dev->refcount, 1); + + version = drmGetVersion(fd); + if (version->version_major != 3) { + fprintf(stderr, "%s: DRM version is %d.%d.%d but this driver is " + "only compatible with 3.x.x.\n", + __func__, + version->version_major, + version->version_minor, + version->version_patchlevel); + drmFreeVersion(version); + r = -EBADF; + goto cleanup; + } + + dev->fd = fcntl(fd, F_DUPFD_CLOEXEC, 0); + dev->flink_fd = dev->fd; + dev->major_version = version->version_major; + dev->minor_version = version->version_minor; + drmFreeVersion(version); + + pthread_mutex_init(&dev->bo_table_mutex, NULL); + + /* Check if acceleration is working. */ + r = amdgpu_query_info(dev, AMDGPU_INFO_ACCEL_WORKING, 4, &accel_working); + if (r) { + fprintf(stderr, "%s: amdgpu_query_info(ACCEL_WORKING) failed (%i)\n", + __func__, r); + goto cleanup; + } + if (!accel_working) { + fprintf(stderr, "%s: AMDGPU_INFO_ACCEL_WORKING = 0\n", __func__); + r = -EBADF; + goto cleanup; + } + + r = amdgpu_query_gpu_info_init(dev); + if (r) { + fprintf(stderr, "%s: amdgpu_query_gpu_info_init failed\n", __func__); + goto cleanup; + } + + start = dev->dev_info.virtual_address_offset; + max = MIN2(dev->dev_info.virtual_address_max, 0x100000000ULL); + amdgpu_vamgr_init(&dev->vamgr_32, start, max, + dev->dev_info.virtual_address_alignment); + + start = max; + max = MAX2(dev->dev_info.virtual_address_max, 0x100000000ULL); + amdgpu_vamgr_init(&dev->vamgr, start, max, + dev->dev_info.virtual_address_alignment); + + start = dev->dev_info.high_va_offset; + max = MIN2(dev->dev_info.high_va_max, (start & ~0xffffffffULL) + + 0x100000000ULL); + amdgpu_vamgr_init(&dev->vamgr_high_32, start, max, + dev->dev_info.virtual_address_alignment); + + start = max; + max = MAX2(dev->dev_info.high_va_max, (start & ~0xffffffffULL) + + 0x100000000ULL); + amdgpu_vamgr_init(&dev->vamgr_high, start, max, + dev->dev_info.virtual_address_alignment); + + amdgpu_parse_asic_ids(dev); + + *major_version = dev->major_version; + *minor_version = dev->minor_version; + *device_handle = dev; + dev->next = dev_list; + dev_list = dev; + pthread_mutex_unlock(&dev_mutex); + + return 0; + +cleanup: + if (dev->fd >= 0) + close(dev->fd); + free(dev); + pthread_mutex_unlock(&dev_mutex); + return r; +} + +drm_public int amdgpu_device_deinitialize(amdgpu_device_handle dev) +{ + amdgpu_device_reference(&dev, NULL); + return 0; +} + +drm_public int amdgpu_device_get_fd(amdgpu_device_handle device_handle) +{ + return device_handle->fd; +} + +drm_public const char *amdgpu_get_marketing_name(amdgpu_device_handle dev) +{ + if (dev->marketing_name) + return dev->marketing_name; + else + return "AMD Radeon Graphics"; +} + +drm_public int amdgpu_query_sw_info(amdgpu_device_handle dev, + enum amdgpu_sw_info info, + void *value) +{ + uint32_t *val32 = (uint32_t*)value; + + switch (info) { + case amdgpu_sw_info_address32_hi: + if (dev->vamgr_high_32.va_max) + *val32 = (dev->vamgr_high_32.va_max - 1) >> 32; + else + *val32 = (dev->vamgr_32.va_max - 1) >> 32; + return 0; + } + return -EINVAL; +} diff --git a/amdgpu/amdgpu_gpu_info.c b/amdgpu/amdgpu_gpu_info.c new file mode 100644 index 0000000..9f8695c --- /dev/null +++ b/amdgpu/amdgpu_gpu_info.c @@ -0,0 +1,348 @@ +/* + * Copyright © 2014 Advanced Micro Devices, Inc. + * 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, 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + */ + +#include +#include + +#include "amdgpu.h" +#include "amdgpu_drm.h" +#include "amdgpu_internal.h" +#include "xf86drm.h" + +drm_public int amdgpu_query_info(amdgpu_device_handle dev, unsigned info_id, + unsigned size, void *value) +{ + struct drm_amdgpu_info request; + + memset(&request, 0, sizeof(request)); + request.return_pointer = (uintptr_t)value; + request.return_size = size; + request.query = info_id; + + return drmCommandWrite(dev->fd, DRM_AMDGPU_INFO, &request, + sizeof(struct drm_amdgpu_info)); +} + +drm_public int amdgpu_query_crtc_from_id(amdgpu_device_handle dev, unsigned id, + int32_t *result) +{ + struct drm_amdgpu_info request; + + memset(&request, 0, sizeof(request)); + request.return_pointer = (uintptr_t)result; + request.return_size = sizeof(*result); + request.query = AMDGPU_INFO_CRTC_FROM_ID; + request.mode_crtc.id = id; + + return drmCommandWrite(dev->fd, DRM_AMDGPU_INFO, &request, + sizeof(struct drm_amdgpu_info)); +} + +drm_public int amdgpu_read_mm_registers(amdgpu_device_handle dev, + unsigned dword_offset, unsigned count, uint32_t instance, + uint32_t flags, uint32_t *values) +{ + struct drm_amdgpu_info request; + + memset(&request, 0, sizeof(request)); + request.return_pointer = (uintptr_t)values; + request.return_size = count * sizeof(uint32_t); + request.query = AMDGPU_INFO_READ_MMR_REG; + request.read_mmr_reg.dword_offset = dword_offset; + request.read_mmr_reg.count = count; + request.read_mmr_reg.instance = instance; + request.read_mmr_reg.flags = flags; + + return drmCommandWrite(dev->fd, DRM_AMDGPU_INFO, &request, + sizeof(struct drm_amdgpu_info)); +} + +drm_public int amdgpu_query_hw_ip_count(amdgpu_device_handle dev, + unsigned type, + uint32_t *count) +{ + struct drm_amdgpu_info request; + + memset(&request, 0, sizeof(request)); + request.return_pointer = (uintptr_t)count; + request.return_size = sizeof(*count); + request.query = AMDGPU_INFO_HW_IP_COUNT; + request.query_hw_ip.type = type; + + return drmCommandWrite(dev->fd, DRM_AMDGPU_INFO, &request, + sizeof(struct drm_amdgpu_info)); +} + +drm_public int amdgpu_query_hw_ip_info(amdgpu_device_handle dev, unsigned type, + unsigned ip_instance, + struct drm_amdgpu_info_hw_ip *info) +{ + struct drm_amdgpu_info request; + + memset(&request, 0, sizeof(request)); + request.return_pointer = (uintptr_t)info; + request.return_size = sizeof(*info); + request.query = AMDGPU_INFO_HW_IP_INFO; + request.query_hw_ip.type = type; + request.query_hw_ip.ip_instance = ip_instance; + + return drmCommandWrite(dev->fd, DRM_AMDGPU_INFO, &request, + sizeof(struct drm_amdgpu_info)); +} + +drm_public int amdgpu_query_firmware_version(amdgpu_device_handle dev, + unsigned fw_type, unsigned ip_instance, unsigned index, + uint32_t *version, uint32_t *feature) +{ + struct drm_amdgpu_info request; + struct drm_amdgpu_info_firmware firmware = {}; + int r; + + memset(&request, 0, sizeof(request)); + request.return_pointer = (uintptr_t)&firmware; + request.return_size = sizeof(firmware); + request.query = AMDGPU_INFO_FW_VERSION; + request.query_fw.fw_type = fw_type; + request.query_fw.ip_instance = ip_instance; + request.query_fw.index = index; + + r = drmCommandWrite(dev->fd, DRM_AMDGPU_INFO, &request, + sizeof(struct drm_amdgpu_info)); + if (r) + return r; + + *version = firmware.ver; + *feature = firmware.feature; + return 0; +} + +drm_private int amdgpu_query_gpu_info_init(amdgpu_device_handle dev) +{ + int r, i; + + r = amdgpu_query_info(dev, AMDGPU_INFO_DEV_INFO, sizeof(dev->dev_info), + &dev->dev_info); + if (r) + return r; + + dev->info.asic_id = dev->dev_info.device_id; + dev->info.chip_rev = dev->dev_info.chip_rev; + dev->info.chip_external_rev = dev->dev_info.external_rev; + dev->info.family_id = dev->dev_info.family; + dev->info.max_engine_clk = dev->dev_info.max_engine_clock; + dev->info.max_memory_clk = dev->dev_info.max_memory_clock; + dev->info.gpu_counter_freq = dev->dev_info.gpu_counter_freq; + dev->info.enabled_rb_pipes_mask = dev->dev_info.enabled_rb_pipes_mask; + dev->info.rb_pipes = dev->dev_info.num_rb_pipes; + dev->info.ids_flags = dev->dev_info.ids_flags; + dev->info.num_hw_gfx_contexts = dev->dev_info.num_hw_gfx_contexts; + dev->info.num_shader_engines = dev->dev_info.num_shader_engines; + dev->info.num_shader_arrays_per_engine = + dev->dev_info.num_shader_arrays_per_engine; + dev->info.vram_type = dev->dev_info.vram_type; + dev->info.vram_bit_width = dev->dev_info.vram_bit_width; + dev->info.ce_ram_size = dev->dev_info.ce_ram_size; + dev->info.vce_harvest_config = dev->dev_info.vce_harvest_config; + dev->info.pci_rev_id = dev->dev_info.pci_rev; + + if (dev->info.family_id < AMDGPU_FAMILY_AI) { + for (i = 0; i < (int)dev->info.num_shader_engines; i++) { + unsigned instance = (i << AMDGPU_INFO_MMR_SE_INDEX_SHIFT) | + (AMDGPU_INFO_MMR_SH_INDEX_MASK << + AMDGPU_INFO_MMR_SH_INDEX_SHIFT); + + r = amdgpu_read_mm_registers(dev, 0x263d, 1, instance, 0, + &dev->info.backend_disable[i]); + if (r) + return r; + /* extract bitfield CC_RB_BACKEND_DISABLE.BACKEND_DISABLE */ + dev->info.backend_disable[i] = + (dev->info.backend_disable[i] >> 16) & 0xff; + + r = amdgpu_read_mm_registers(dev, 0xa0d4, 1, instance, 0, + &dev->info.pa_sc_raster_cfg[i]); + if (r) + return r; + + if (dev->info.family_id >= AMDGPU_FAMILY_CI) { + r = amdgpu_read_mm_registers(dev, 0xa0d5, 1, instance, 0, + &dev->info.pa_sc_raster_cfg1[i]); + if (r) + return r; + } + } + } + + r = amdgpu_read_mm_registers(dev, 0x263e, 1, 0xffffffff, 0, + &dev->info.gb_addr_cfg); + if (r) + return r; + + if (dev->info.family_id < AMDGPU_FAMILY_AI) { + r = amdgpu_read_mm_registers(dev, 0x2644, 32, 0xffffffff, 0, + dev->info.gb_tile_mode); + if (r) + return r; + + if (dev->info.family_id >= AMDGPU_FAMILY_CI) { + r = amdgpu_read_mm_registers(dev, 0x2664, 16, 0xffffffff, 0, + dev->info.gb_macro_tile_mode); + if (r) + return r; + } + + r = amdgpu_read_mm_registers(dev, 0x9d8, 1, 0xffffffff, 0, + &dev->info.mc_arb_ramcfg); + if (r) + return r; + } + + dev->info.cu_active_number = dev->dev_info.cu_active_number; + dev->info.cu_ao_mask = dev->dev_info.cu_ao_mask; + memcpy(&dev->info.cu_bitmap[0][0], &dev->dev_info.cu_bitmap[0][0], sizeof(dev->info.cu_bitmap)); + + /* TODO: info->max_quad_shader_pipes is not set */ + /* TODO: info->avail_quad_shader_pipes is not set */ + /* TODO: info->cache_entries_per_quad_pipe is not set */ + return 0; +} + +drm_public int amdgpu_query_gpu_info(amdgpu_device_handle dev, + struct amdgpu_gpu_info *info) +{ + if (!dev || !info) + return -EINVAL; + + /* Get ASIC info*/ + *info = dev->info; + + return 0; +} + +drm_public int amdgpu_query_heap_info(amdgpu_device_handle dev, + uint32_t heap, + uint32_t flags, + struct amdgpu_heap_info *info) +{ + struct drm_amdgpu_info_vram_gtt vram_gtt_info = {}; + int r; + + r = amdgpu_query_info(dev, AMDGPU_INFO_VRAM_GTT, + sizeof(vram_gtt_info), &vram_gtt_info); + if (r) + return r; + + /* Get heap information */ + switch (heap) { + case AMDGPU_GEM_DOMAIN_VRAM: + /* query visible only vram heap */ + if (flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) + info->heap_size = vram_gtt_info.vram_cpu_accessible_size; + else /* query total vram heap */ + info->heap_size = vram_gtt_info.vram_size; + + info->max_allocation = vram_gtt_info.vram_cpu_accessible_size; + + if (flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) + r = amdgpu_query_info(dev, AMDGPU_INFO_VIS_VRAM_USAGE, + sizeof(info->heap_usage), + &info->heap_usage); + else + r = amdgpu_query_info(dev, AMDGPU_INFO_VRAM_USAGE, + sizeof(info->heap_usage), + &info->heap_usage); + if (r) + return r; + break; + case AMDGPU_GEM_DOMAIN_GTT: + info->heap_size = vram_gtt_info.gtt_size; + info->max_allocation = vram_gtt_info.vram_cpu_accessible_size; + + r = amdgpu_query_info(dev, AMDGPU_INFO_GTT_USAGE, + sizeof(info->heap_usage), + &info->heap_usage); + if (r) + return r; + break; + default: + return -EINVAL; + } + + return 0; +} + +drm_public int amdgpu_query_gds_info(amdgpu_device_handle dev, + struct amdgpu_gds_resource_info *gds_info) +{ + struct drm_amdgpu_info_gds gds_config = {}; + int r; + + if (!gds_info) + return -EINVAL; + + r = amdgpu_query_info(dev, AMDGPU_INFO_GDS_CONFIG, + sizeof(gds_config), &gds_config); + if (r) + return r; + + gds_info->gds_gfx_partition_size = gds_config.gds_gfx_partition_size; + gds_info->compute_partition_size = gds_config.compute_partition_size; + gds_info->gds_total_size = gds_config.gds_total_size; + gds_info->gws_per_gfx_partition = gds_config.gws_per_gfx_partition; + gds_info->gws_per_compute_partition = gds_config.gws_per_compute_partition; + gds_info->oa_per_gfx_partition = gds_config.oa_per_gfx_partition; + gds_info->oa_per_compute_partition = gds_config.oa_per_compute_partition; + + return 0; +} + +drm_public int amdgpu_query_sensor_info(amdgpu_device_handle dev, unsigned sensor_type, + unsigned size, void *value) +{ + struct drm_amdgpu_info request; + + memset(&request, 0, sizeof(request)); + request.return_pointer = (uintptr_t)value; + request.return_size = size; + request.query = AMDGPU_INFO_SENSOR; + request.sensor_info.type = sensor_type; + + return drmCommandWrite(dev->fd, DRM_AMDGPU_INFO, &request, + sizeof(struct drm_amdgpu_info)); +} + +drm_public int amdgpu_query_video_caps_info(amdgpu_device_handle dev, unsigned cap_type, + unsigned size, void *value) +{ + struct drm_amdgpu_info request; + + memset(&request, 0, sizeof(request)); + request.return_pointer = (uintptr_t)value; + request.return_size = size; + request.query = AMDGPU_INFO_VIDEO_CAPS; + request.sensor_info.type = cap_type; + + return drmCommandWrite(dev->fd, DRM_AMDGPU_INFO, &request, + sizeof(struct drm_amdgpu_info)); +} diff --git a/amdgpu/amdgpu_internal.h b/amdgpu/amdgpu_internal.h new file mode 100644 index 0000000..37a7c9d --- /dev/null +++ b/amdgpu/amdgpu_internal.h @@ -0,0 +1,176 @@ +/* + * Copyright © 2014 Advanced Micro Devices, Inc. + * 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, 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 _AMDGPU_INTERNAL_H_ +#define _AMDGPU_INTERNAL_H_ + +#include +#include + +#include "libdrm_macros.h" +#include "xf86atomic.h" +#include "amdgpu.h" +#include "util_double_list.h" +#include "handle_table.h" + +#define AMDGPU_CS_MAX_RINGS 8 +/* do not use below macro if b is not power of 2 aligned value */ +#define __round_mask(x, y) ((__typeof__(x))((y)-1)) +#define ROUND_UP(x, y) ((((x)-1) | __round_mask(x, y))+1) +#define ROUND_DOWN(x, y) ((x) & ~__round_mask(x, y)) + +#define AMDGPU_INVALID_VA_ADDRESS 0xffffffffffffffff +#define AMDGPU_NULL_SUBMIT_SEQ 0 + +struct amdgpu_bo_va_hole { + struct list_head list; + uint64_t offset; + uint64_t size; +}; + +struct amdgpu_bo_va_mgr { + uint64_t va_max; + struct list_head va_holes; + pthread_mutex_t bo_va_mutex; + uint32_t va_alignment; +}; + +struct amdgpu_va { + amdgpu_device_handle dev; + uint64_t address; + uint64_t size; + enum amdgpu_gpu_va_range range; + struct amdgpu_bo_va_mgr *vamgr; +}; + +struct amdgpu_device { + atomic_t refcount; + struct amdgpu_device *next; + int fd; + int flink_fd; + unsigned major_version; + unsigned minor_version; + + char *marketing_name; + /** List of buffer handles. Protected by bo_table_mutex. */ + struct handle_table bo_handles; + /** List of buffer GEM flink names. Protected by bo_table_mutex. */ + struct handle_table bo_flink_names; + /** This protects all hash tables. */ + pthread_mutex_t bo_table_mutex; + struct drm_amdgpu_info_device dev_info; + struct amdgpu_gpu_info info; + /** The VA manager for the lower virtual address space */ + struct amdgpu_bo_va_mgr vamgr; + /** The VA manager for the 32bit address space */ + struct amdgpu_bo_va_mgr vamgr_32; + /** The VA manager for the high virtual address space */ + struct amdgpu_bo_va_mgr vamgr_high; + /** The VA manager for the 32bit high address space */ + struct amdgpu_bo_va_mgr vamgr_high_32; +}; + +struct amdgpu_bo { + atomic_t refcount; + struct amdgpu_device *dev; + + uint64_t alloc_size; + + uint32_t handle; + uint32_t flink_name; + + pthread_mutex_t cpu_access_mutex; + void *cpu_ptr; + int64_t cpu_map_count; +}; + +struct amdgpu_bo_list { + struct amdgpu_device *dev; + + uint32_t handle; +}; + +struct amdgpu_context { + struct amdgpu_device *dev; + /** Mutex for accessing fences and to maintain command submissions + in good sequence. */ + pthread_mutex_t sequence_mutex; + /* context id*/ + uint32_t id; + uint64_t last_seq[AMDGPU_HW_IP_NUM][AMDGPU_HW_IP_INSTANCE_MAX_COUNT][AMDGPU_CS_MAX_RINGS]; + struct list_head sem_list[AMDGPU_HW_IP_NUM][AMDGPU_HW_IP_INSTANCE_MAX_COUNT][AMDGPU_CS_MAX_RINGS]; +}; + +/** + * Structure describing sw semaphore based on scheduler + * + */ +struct amdgpu_semaphore { + atomic_t refcount; + struct list_head list; + struct amdgpu_cs_fence signal_fence; +}; + +/** + * Functions. + */ + +drm_private void amdgpu_vamgr_init(struct amdgpu_bo_va_mgr *mgr, uint64_t start, + uint64_t max, uint64_t alignment); + +drm_private void amdgpu_vamgr_deinit(struct amdgpu_bo_va_mgr *mgr); + +drm_private void amdgpu_parse_asic_ids(struct amdgpu_device *dev); + +drm_private int amdgpu_query_gpu_info_init(amdgpu_device_handle dev); + +drm_private uint64_t amdgpu_cs_calculate_timeout(uint64_t timeout); + +/** + * Inline functions. + */ + +/** + * Increment src and decrement dst as if we were updating references + * for an assignment between 2 pointers of some objects. + * + * \return true if dst is 0 + */ +static inline bool update_references(atomic_t *dst, atomic_t *src) +{ + if (dst != src) { + /* bump src first */ + if (src) { + assert(atomic_read(src) > 0); + atomic_inc(src); + } + if (dst) { + assert(atomic_read(dst) > 0); + return atomic_dec_and_test(dst); + } + } + return false; +} + +#endif diff --git a/amdgpu/amdgpu_vamgr.c b/amdgpu/amdgpu_vamgr.c new file mode 100644 index 0000000..077a9fc --- /dev/null +++ b/amdgpu/amdgpu_vamgr.c @@ -0,0 +1,298 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + */ + +#include +#include +#include +#include "amdgpu.h" +#include "amdgpu_drm.h" +#include "amdgpu_internal.h" +#include "util_math.h" + +drm_public int amdgpu_va_range_query(amdgpu_device_handle dev, + enum amdgpu_gpu_va_range type, + uint64_t *start, uint64_t *end) +{ + if (type != amdgpu_gpu_va_range_general) + return -EINVAL; + + *start = dev->dev_info.virtual_address_offset; + *end = dev->dev_info.virtual_address_max; + return 0; +} + +drm_private void amdgpu_vamgr_init(struct amdgpu_bo_va_mgr *mgr, uint64_t start, + uint64_t max, uint64_t alignment) +{ + struct amdgpu_bo_va_hole *n; + + mgr->va_max = max; + mgr->va_alignment = alignment; + + list_inithead(&mgr->va_holes); + pthread_mutex_init(&mgr->bo_va_mutex, NULL); + pthread_mutex_lock(&mgr->bo_va_mutex); + n = calloc(1, sizeof(struct amdgpu_bo_va_hole)); + n->size = mgr->va_max - start; + n->offset = start; + list_add(&n->list, &mgr->va_holes); + pthread_mutex_unlock(&mgr->bo_va_mutex); +} + +drm_private void amdgpu_vamgr_deinit(struct amdgpu_bo_va_mgr *mgr) +{ + struct amdgpu_bo_va_hole *hole, *tmp; + LIST_FOR_EACH_ENTRY_SAFE(hole, tmp, &mgr->va_holes, list) { + list_del(&hole->list); + free(hole); + } + pthread_mutex_destroy(&mgr->bo_va_mutex); +} + +static drm_private int +amdgpu_vamgr_subtract_hole(struct amdgpu_bo_va_hole *hole, uint64_t start_va, + uint64_t end_va) +{ + if (start_va > hole->offset && end_va - hole->offset < hole->size) { + struct amdgpu_bo_va_hole *n = calloc(1, sizeof(struct amdgpu_bo_va_hole)); + if (!n) + return -ENOMEM; + + n->size = start_va - hole->offset; + n->offset = hole->offset; + list_add(&n->list, &hole->list); + + hole->size -= (end_va - hole->offset); + hole->offset = end_va; + } else if (start_va > hole->offset) { + hole->size = start_va - hole->offset; + } else if (end_va - hole->offset < hole->size) { + hole->size -= (end_va - hole->offset); + hole->offset = end_va; + } else { + list_del(&hole->list); + free(hole); + } + + return 0; +} + +static drm_private int +amdgpu_vamgr_find_va(struct amdgpu_bo_va_mgr *mgr, uint64_t size, + uint64_t alignment, uint64_t base_required, + bool search_from_top, uint64_t *va_out) +{ + struct amdgpu_bo_va_hole *hole, *n; + uint64_t offset = 0; + int ret; + + + alignment = MAX2(alignment, mgr->va_alignment); + size = ALIGN(size, mgr->va_alignment); + + if (base_required % alignment) + return -EINVAL; + + pthread_mutex_lock(&mgr->bo_va_mutex); + if (!search_from_top) { + LIST_FOR_EACH_ENTRY_SAFE_REV(hole, n, &mgr->va_holes, list) { + if (base_required) { + if (hole->offset > base_required || + (hole->offset + hole->size) < (base_required + size)) + continue; + offset = base_required; + } else { + uint64_t waste = hole->offset % alignment; + waste = waste ? alignment - waste : 0; + offset = hole->offset + waste; + if (offset >= (hole->offset + hole->size) || + size > (hole->offset + hole->size) - offset) { + continue; + } + } + ret = amdgpu_vamgr_subtract_hole(hole, offset, offset + size); + pthread_mutex_unlock(&mgr->bo_va_mutex); + *va_out = offset; + return ret; + } + } else { + LIST_FOR_EACH_ENTRY_SAFE(hole, n, &mgr->va_holes, list) { + if (base_required) { + if (hole->offset > base_required || + (hole->offset + hole->size) < (base_required + size)) + continue; + offset = base_required; + } else { + if (size > hole->size) + continue; + + offset = hole->offset + hole->size - size; + offset -= offset % alignment; + if (offset < hole->offset) { + continue; + } + } + + ret = amdgpu_vamgr_subtract_hole(hole, offset, offset + size); + pthread_mutex_unlock(&mgr->bo_va_mutex); + *va_out = offset; + return ret; + } + } + + pthread_mutex_unlock(&mgr->bo_va_mutex); + return -ENOMEM; +} + +static drm_private void +amdgpu_vamgr_free_va(struct amdgpu_bo_va_mgr *mgr, uint64_t va, uint64_t size) +{ + struct amdgpu_bo_va_hole *hole, *next; + + if (va == AMDGPU_INVALID_VA_ADDRESS) + return; + + size = ALIGN(size, mgr->va_alignment); + + pthread_mutex_lock(&mgr->bo_va_mutex); + hole = container_of(&mgr->va_holes, hole, list); + LIST_FOR_EACH_ENTRY(next, &mgr->va_holes, list) { + if (next->offset < va) + break; + hole = next; + } + + if (&hole->list != &mgr->va_holes) { + /* Grow upper hole if it's adjacent */ + if (hole->offset == (va + size)) { + hole->offset = va; + hole->size += size; + /* Merge lower hole if it's adjacent */ + if (next != hole && + &next->list != &mgr->va_holes && + (next->offset + next->size) == va) { + next->size += hole->size; + list_del(&hole->list); + free(hole); + } + goto out; + } + } + + /* Grow lower hole if it's adjacent */ + if (next != hole && &next->list != &mgr->va_holes && + (next->offset + next->size) == va) { + next->size += size; + goto out; + } + + /* FIXME on allocation failure we just lose virtual address space + * maybe print a warning + */ + next = calloc(1, sizeof(struct amdgpu_bo_va_hole)); + if (next) { + next->size = size; + next->offset = va; + list_add(&next->list, &hole->list); + } + +out: + pthread_mutex_unlock(&mgr->bo_va_mutex); +} + +drm_public int amdgpu_va_range_alloc(amdgpu_device_handle dev, + enum amdgpu_gpu_va_range va_range_type, + uint64_t size, + uint64_t va_base_alignment, + uint64_t va_base_required, + uint64_t *va_base_allocated, + amdgpu_va_handle *va_range_handle, + uint64_t flags) +{ + struct amdgpu_bo_va_mgr *vamgr; + bool search_from_top = !!(flags & AMDGPU_VA_RANGE_REPLAYABLE); + int ret; + + /* Clear the flag when the high VA manager is not initialized */ + if (flags & AMDGPU_VA_RANGE_HIGH && !dev->vamgr_high_32.va_max) + flags &= ~AMDGPU_VA_RANGE_HIGH; + + if (flags & AMDGPU_VA_RANGE_HIGH) { + if (flags & AMDGPU_VA_RANGE_32_BIT) + vamgr = &dev->vamgr_high_32; + else + vamgr = &dev->vamgr_high; + } else { + if (flags & AMDGPU_VA_RANGE_32_BIT) + vamgr = &dev->vamgr_32; + else + vamgr = &dev->vamgr; + } + + va_base_alignment = MAX2(va_base_alignment, vamgr->va_alignment); + size = ALIGN(size, vamgr->va_alignment); + + ret = amdgpu_vamgr_find_va(vamgr, size, + va_base_alignment, va_base_required, + search_from_top, va_base_allocated); + + if (!(flags & AMDGPU_VA_RANGE_32_BIT) && ret) { + /* fallback to 32bit address */ + if (flags & AMDGPU_VA_RANGE_HIGH) + vamgr = &dev->vamgr_high_32; + else + vamgr = &dev->vamgr_32; + ret = amdgpu_vamgr_find_va(vamgr, size, + va_base_alignment, va_base_required, + search_from_top, va_base_allocated); + } + + if (!ret) { + struct amdgpu_va* va; + va = calloc(1, sizeof(struct amdgpu_va)); + if(!va){ + amdgpu_vamgr_free_va(vamgr, *va_base_allocated, size); + return -ENOMEM; + } + va->dev = dev; + va->address = *va_base_allocated; + va->size = size; + va->range = va_range_type; + va->vamgr = vamgr; + *va_range_handle = va; + } + + return ret; +} + +drm_public int amdgpu_va_range_free(amdgpu_va_handle va_range_handle) +{ + if(!va_range_handle || !va_range_handle->address) + return 0; + + amdgpu_vamgr_free_va(va_range_handle->vamgr, + va_range_handle->address, + va_range_handle->size); + free(va_range_handle); + return 0; +} diff --git a/amdgpu/amdgpu_vm.c b/amdgpu/amdgpu_vm.c new file mode 100644 index 0000000..7e6e28f --- /dev/null +++ b/amdgpu/amdgpu_vm.c @@ -0,0 +1,50 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + */ + +#include "amdgpu.h" +#include "amdgpu_drm.h" +#include "xf86drm.h" +#include "amdgpu_internal.h" + +drm_public int amdgpu_vm_reserve_vmid(amdgpu_device_handle dev, uint32_t flags) +{ + union drm_amdgpu_vm vm; + + vm.in.op = AMDGPU_VM_OP_RESERVE_VMID; + vm.in.flags = flags; + + return drmCommandWriteRead(dev->fd, DRM_AMDGPU_VM, + &vm, sizeof(vm)); +} + +drm_public int amdgpu_vm_unreserve_vmid(amdgpu_device_handle dev, + uint32_t flags) +{ + union drm_amdgpu_vm vm; + + vm.in.op = AMDGPU_VM_OP_UNRESERVE_VMID; + vm.in.flags = flags; + + return drmCommandWriteRead(dev->fd, DRM_AMDGPU_VM, + &vm, sizeof(vm)); +} diff --git a/amdgpu/handle_table.c b/amdgpu/handle_table.c new file mode 100644 index 0000000..4fdd29d --- /dev/null +++ b/amdgpu/handle_table.c @@ -0,0 +1,72 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + */ + +#include +#include +#include +#include +#include "handle_table.h" +#include "util_math.h" + +drm_private int handle_table_insert(struct handle_table *table, uint32_t key, + void *value) +{ + if (key >= table->max_key) { + uint32_t alignment = sysconf(_SC_PAGESIZE) / sizeof(void*); + uint32_t max_key = ALIGN(key + 1, alignment); + void **values; + + values = realloc(table->values, max_key * sizeof(void *)); + if (!values) + return -ENOMEM; + + memset(values + table->max_key, 0, (max_key - table->max_key) * + sizeof(void *)); + + table->max_key = max_key; + table->values = values; + } + table->values[key] = value; + return 0; +} + +drm_private void handle_table_remove(struct handle_table *table, uint32_t key) +{ + if (key < table->max_key) + table->values[key] = NULL; +} + +drm_private void *handle_table_lookup(struct handle_table *table, uint32_t key) +{ + if (key < table->max_key) + return table->values[key]; + else + return NULL; +} + +drm_private void handle_table_fini(struct handle_table *table) +{ + free(table->values); + table->max_key = 0; + table->values = NULL; +} diff --git a/amdgpu/handle_table.h b/amdgpu/handle_table.h new file mode 100644 index 0000000..461193f --- /dev/null +++ b/amdgpu/handle_table.h @@ -0,0 +1,41 @@ +/* + * Copyright 2018 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 _HANDLE_TABLE_H_ +#define _HANDLE_TABLE_H_ + +#include +#include "libdrm_macros.h" + +struct handle_table { + uint32_t max_key; + void **values; +}; + +drm_private int handle_table_insert(struct handle_table *table, uint32_t key, + void *value); +drm_private void handle_table_remove(struct handle_table *table, uint32_t key); +drm_private void *handle_table_lookup(struct handle_table *table, uint32_t key); +drm_private void handle_table_fini(struct handle_table *table); + +#endif /* _HANDLE_TABLE_H_ */ diff --git a/amdgpu/libdrm_amdgpu.pc.in b/amdgpu/libdrm_amdgpu.pc.in new file mode 100644 index 0000000..f1c552a --- /dev/null +++ b/amdgpu/libdrm_amdgpu.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libdrm_amdgpu +Description: Userspace interface to kernel DRM services for amdgpu +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -ldrm_amdgpu +Cflags: -I${includedir} -I${includedir}/libdrm +Requires.private: libdrm diff --git a/amdgpu/meson.build b/amdgpu/meson.build new file mode 100644 index 0000000..a1cca5a --- /dev/null +++ b/amdgpu/meson.build @@ -0,0 +1,70 @@ +# Copyright © 2017-2018 Intel Corporation + +# 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. + + +datadir_amdgpu = join_paths(get_option('prefix'), get_option('datadir'), 'libdrm') + +libdrm_amdgpu = library( + 'drm_amdgpu', + [ + files( + 'amdgpu_asic_id.c', 'amdgpu_bo.c', 'amdgpu_cs.c', 'amdgpu_device.c', + 'amdgpu_gpu_info.c', 'amdgpu_vamgr.c', 'amdgpu_vm.c', 'handle_table.c', + ), + config_file, + ], + c_args : [ + libdrm_c_args, + '-DAMDGPU_ASIC_ID_TABLE="@0@"'.format(join_paths(datadir_amdgpu, 'amdgpu.ids')), + ], + include_directories : [inc_root, inc_drm], + link_with : libdrm, + dependencies : [dep_pthread_stubs, dep_atomic_ops, dep_rt], + version : '1.0.0', + install : true, +) + +install_headers('amdgpu.h', subdir : 'libdrm') + +pkg.generate( + libdrm_amdgpu, + name : 'libdrm_amdgpu', + subdirs : ['.', 'libdrm'], + description : 'Userspace interface to kernel DRM services for amdgpu', +) + +ext_libdrm_amdgpu = declare_dependency( + link_with : [libdrm, libdrm_amdgpu], + include_directories : [inc_drm, include_directories('.')], +) + +if meson.version().version_compare('>= 0.54.0') + meson.override_dependency('libdrm_amdgpu', ext_libdrm_amdgpu) +endif + +test( + 'amdgpu-symbols-check', + symbols_check, + args : [ + '--lib', libdrm_amdgpu, + '--symbols-file', files('amdgpu-symbols.txt'), + '--nm', prog_nm.path(), + ], +) diff --git a/android/gralloc_handle.h b/android/gralloc_handle.h new file mode 100644 index 0000000..d3d975e --- /dev/null +++ b/android/gralloc_handle.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2010-2011 Chia-I Wu + * Copyright (C) 2010-2011 LunarG Inc. + * Copyright (C) 2016 Linaro, Ltd., Rob Herring + * Copyright (C) 2018 Collabora, Robert Foss + * + * 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. + */ + +#ifndef __ANDROID_GRALLOC_HANDLE_H__ +#define __ANDROID_GRALLOC_HANDLE_H__ + +#include +#include + +/* support users of drm_gralloc/gbm_gralloc */ +#define gralloc_gbm_handle_t gralloc_handle_t +#define gralloc_drm_handle_t gralloc_handle_t + +struct gralloc_handle_t { + native_handle_t base; + + /* dma-buf file descriptor + * Must be located first since, native_handle_t is allocated + * using native_handle_create(), which allocates space for + * sizeof(native_handle_t) + sizeof(int) * (numFds + numInts) + * numFds = GRALLOC_HANDLE_NUM_FDS + * numInts = GRALLOC_HANDLE_NUM_INTS + * Where numFds represents the number of FDs and + * numInts represents the space needed for the + * remainder of this struct. + * And the FDs are expected to be found first following + * native_handle_t. + */ + int prime_fd; + + /* api variables */ + uint32_t magic; /* differentiate between allocator impls */ + uint32_t version; /* api version */ + + uint32_t width; /* width of buffer in pixels */ + uint32_t height; /* height of buffer in pixels */ + uint32_t format; /* pixel format (Android) */ + uint32_t usage; /* android libhardware usage flags */ + + uint32_t stride; /* the stride in bytes */ + int data_owner; /* owner of data (for validation) */ + uint64_t modifier __attribute__((aligned(8))); /* buffer modifiers */ + + union { + void *data; /* pointer to struct gralloc_gbm_bo_t */ + uint64_t reserved; + } __attribute__((aligned(8))); +}; + +#define GRALLOC_HANDLE_VERSION 4 +#define GRALLOC_HANDLE_MAGIC 0x60585350 +#define GRALLOC_HANDLE_NUM_FDS 1 +#define GRALLOC_HANDLE_NUM_INTS ( \ + ((sizeof(struct gralloc_handle_t) - sizeof(native_handle_t))/sizeof(int)) \ + - GRALLOC_HANDLE_NUM_FDS) + +static inline struct gralloc_handle_t *gralloc_handle(buffer_handle_t handle) +{ + return (struct gralloc_handle_t *)handle; +} + +/** + * Create a buffer handle. + */ +static inline native_handle_t *gralloc_handle_create(int32_t width, + int32_t height, + int32_t hal_format, + int32_t usage) +{ + struct gralloc_handle_t *handle; + native_handle_t *nhandle = native_handle_create(GRALLOC_HANDLE_NUM_FDS, + GRALLOC_HANDLE_NUM_INTS); + + if (!nhandle) + return NULL; + + handle = gralloc_handle(nhandle); + handle->magic = GRALLOC_HANDLE_MAGIC; + handle->version = GRALLOC_HANDLE_VERSION; + handle->width = width; + handle->height = height; + handle->format = hal_format; + handle->usage = usage; + handle->prime_fd = -1; + + return nhandle; +} + +#endif diff --git a/core-symbols.txt b/core-symbols.txt new file mode 100644 index 0000000..9f8a323 --- /dev/null +++ b/core-symbols.txt @@ -0,0 +1,209 @@ +drmAddBufs +drmAddContextPrivateMapping +drmAddContextTag +drmAddMap +drmAgpAcquire +drmAgpAlloc +drmAgpBase +drmAgpBind +drmAgpDeviceId +drmAgpEnable +drmAgpFree +drmAgpGetMode +drmAgpMemoryAvail +drmAgpMemoryUsed +drmAgpRelease +drmAgpSize +drmAgpUnbind +drmAgpVendorId +drmAgpVersionMajor +drmAgpVersionMinor +drmAuthMagic +drmAvailable +drmCheckModesettingSupported +drmClose +drmCloseBufferHandle +drmCloseOnce +drmCommandNone +drmCommandRead +drmCommandWrite +drmCommandWriteRead +drmCreateContext +drmCreateDrawable +drmCrtcGetSequence +drmCrtcQueueSequence +drmCtlInstHandler +drmCtlUninstHandler +drmDelContextTag +drmDestroyContext +drmDestroyDrawable +drmDevicesEqual +drmDMA +drmDropMaster +drmError +drmFinish +drmFree +drmFreeBufs +drmFreeBusid +drmFreeDevice +drmFreeDevices +drmFreeReservedContextList +drmFreeVersion +drmGetBufInfo +drmGetBusid +drmGetCap +drmGetClient +drmGetContextFlags +drmGetContextPrivateMapping +drmGetContextTag +drmGetDevice +drmGetDevice2 +drmGetDeviceFromDevId +drmGetDeviceNameFromFd +drmGetDeviceNameFromFd2 +drmGetDevices +drmGetDevices2 +drmGetEntry +drmGetHashTable +drmGetInterruptFromBusID +drmGetLibVersion +drmGetLock +drmGetMagic +drmGetMap +drmGetNodeTypeFromFd +drmGetPrimaryDeviceNameFromFd +drmGetRenderDeviceNameFromFd +drmGetReservedContextList +drmGetStats +drmGetVersion +drmHandleEvent +drmHashCreate +drmHashDelete +drmHashDestroy +drmHashFirst +drmHashInsert +drmHashLookup +drmHashNext +drmIoctl +drmIsKMS +drmIsMaster +drmMalloc +drmMap +drmMapBufs +drmMarkBufs +drmModeAddFB +drmModeAddFB2 +drmModeAddFB2WithModifiers +drmModeAtomicAddProperty +drmModeAtomicAlloc +drmModeAtomicCommit +drmModeAtomicDuplicate +drmModeAtomicFree +drmModeAtomicGetCursor +drmModeAtomicMerge +drmModeAtomicSetCursor +drmModeAttachMode +drmModeConnectorGetPossibleCrtcs +drmModeConnectorSetProperty +drmModeCreateDumbBuffer +drmModeCreateLease +drmModeCreatePropertyBlob +drmModeCrtcGetGamma +drmModeCrtcSetGamma +drmModeDestroyDumbBuffer +drmModeDestroyPropertyBlob +drmModeDetachMode +drmModeDirtyFB +drmModeFormatModifierBlobIterNext +drmModeFreeConnector +drmModeFreeCrtc +drmModeFreeEncoder +drmModeFreeFB +drmModeFreeFB2 +drmModeFreeModeInfo +drmModeFreeObjectProperties +drmModeFreePlane +drmModeFreePlaneResources +drmModeFreeProperty +drmModeFreePropertyBlob +drmModeFreeResources +drmModeGetConnector +drmModeGetConnectorCurrent +drmModeGetConnectorTypeName +drmModeGetCrtc +drmModeGetEncoder +drmModeGetFB +drmModeGetFB2 +drmModeGetLease +drmModeGetPlane +drmModeGetPlaneResources +drmModeGetProperty +drmModeGetPropertyBlob +drmModeGetResources +drmModeListLessees +drmModeMapDumbBuffer +drmModeMoveCursor +drmModeObjectGetProperties +drmModeObjectSetProperty +drmModePageFlip +drmModePageFlipTarget +drmModeRevokeLease +drmModeRmFB +drmModeSetCrtc +drmModeSetCursor +drmModeSetCursor2 +drmModeSetPlane +drmMsg +drmOpen +drmOpenControl +drmOpenOnce +drmOpenOnceWithType +drmOpenRender +drmOpenWithType +drmPrimeFDToHandle +drmPrimeHandleToFD +drmRandom +drmRandomCreate +drmRandomDestroy +drmRandomDouble +drmRmMap +drmScatterGatherAlloc +drmScatterGatherFree +drmSetBusid +drmSetClientCap +drmSetContextFlags +drmSetInterfaceVersion +drmSetMaster +drmSetServerInfo +drmSLCreate +drmSLDelete +drmSLDestroy +drmSLDump +drmSLFirst +drmSLInsert +drmSLLookup +drmSLLookupNeighbors +drmSLNext +drmSwitchToContext +drmSyncobjCreate +drmSyncobjDestroy +drmSyncobjExportSyncFile +drmSyncobjFDToHandle +drmSyncobjHandleToFD +drmSyncobjImportSyncFile +drmSyncobjQuery +drmSyncobjQuery2 +drmSyncobjReset +drmSyncobjSignal +drmSyncobjTimelineSignal +drmSyncobjTimelineWait +drmSyncobjTransfer +drmSyncobjWait +drmUnlock +drmUnmap +drmUnmapBufs +drmUpdateDrawableInfo +drmWaitVBlank +drmGetFormatModifierName +drmGetFormatModifierVendor +drmGetFormatName diff --git a/data/Android.mk b/data/Android.mk new file mode 100644 index 0000000..62013f0 --- /dev/null +++ b/data/Android.mk @@ -0,0 +1,10 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := amdgpu.ids +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := ETC +LOCAL_PROPRIETARY_MODULE := true +LOCAL_MODULE_RELATIVE_PATH := hwdata +LOCAL_SRC_FILES := $(LOCAL_MODULE) +include $(BUILD_PREBUILT) diff --git a/data/amdgpu.ids b/data/amdgpu.ids new file mode 100644 index 0000000..abf3d69 --- /dev/null +++ b/data/amdgpu.ids @@ -0,0 +1,487 @@ +# List of AMDGPU IDs +# +# Syntax: +# device_id, revision_id, product_name <-- single tab after comma + +1.0.0 +1309, 00, AMD Radeon R7 Graphics +130A, 00, AMD Radeon R6 Graphics +130B, 00, AMD Radeon R4 Graphics +130C, 00, AMD Radeon R7 Graphics +130D, 00, AMD Radeon R6 Graphics +130E, 00, AMD Radeon R5 Graphics +130F, 00, AMD Radeon R7 Graphics +130F, D4, AMD Radeon R7 Graphics +130F, D5, AMD Radeon R7 Graphics +130F, D6, AMD Radeon R7 Graphics +130F, D7, AMD Radeon R7 Graphics +1313, 00, AMD Radeon R7 Graphics +1313, D4, AMD Radeon R7 Graphics +1313, D5, AMD Radeon R7 Graphics +1313, D6, AMD Radeon R7 Graphics +1315, 00, AMD Radeon R5 Graphics +1315, D4, AMD Radeon R5 Graphics +1315, D5, AMD Radeon R5 Graphics +1315, D6, AMD Radeon R5 Graphics +1315, D7, AMD Radeon R5 Graphics +1316, 00, AMD Radeon R5 Graphics +1318, 00, AMD Radeon R5 Graphics +131B, 00, AMD Radeon R4 Graphics +131C, 00, AMD Radeon R7 Graphics +131D, 00, AMD Radeon R6 Graphics +15D8, 00, AMD Radeon RX Vega 8 Graphics WS +15D8, 91, AMD Radeon Vega 3 Graphics +15D8, 91, AMD Ryzen Embedded R1606G with Radeon Vega Gfx +15D8, 92, AMD Radeon Vega 3 Graphics +15D8, 92, AMD Ryzen Embedded R1505G with Radeon Vega Gfx +15D8, 93, AMD Radeon Vega 1 Graphics +15D8, A1, AMD Radeon Vega 10 Graphics +15D8, A2, AMD Radeon Vega 8 Graphics +15D8, A3, AMD Radeon Vega 6 Graphics +15D8, A4, AMD Radeon Vega 3 Graphics +15D8, B1, AMD Radeon Vega 10 Graphics +15D8, B2, AMD Radeon Vega 8 Graphics +15D8, B3, AMD Radeon Vega 6 Graphics +15D8, B4, AMD Radeon Vega 3 Graphics +15D8, C1, AMD Radeon Vega 10 Graphics +15D8, C2, AMD Radeon Vega 8 Graphics +15D8, C3, AMD Radeon Vega 6 Graphics +15D8, C4, AMD Radeon Vega 3 Graphics +15D8, C5, AMD Radeon Vega 3 Graphics +15D8, C8, AMD Radeon Vega 11 Graphics +15D8, C9, AMD Radeon Vega 8 Graphics +15D8, CA, AMD Radeon Vega 11 Graphics +15D8, CB, AMD Radeon Vega 8 Graphics +15D8, CC, AMD Radeon Vega 3 Graphics +15D8, CE, AMD Radeon Vega 3 Graphics +15D8, CF, AMD Ryzen Embedded R1305G with Radeon Vega Gfx +15D8, D1, AMD Radeon Vega 10 Graphics +15D8, D2, AMD Radeon Vega 8 Graphics +15D8, D3, AMD Radeon Vega 6 Graphics +15D8, D4, AMD Radeon Vega 3 Graphics +15D8, D8, AMD Radeon Vega 11 Graphics +15D8, D9, AMD Radeon Vega 8 Graphics +15D8, DA, AMD Radeon Vega 11 Graphics +15D8, DB, AMD Radeon Vega 3 Graphics +15D8, DB, AMD Radeon Vega 8 Graphics +15D8, DC, AMD Radeon Vega 3 Graphics +15D8, DD, AMD Radeon Vega 3 Graphics +15D8, DE, AMD Radeon Vega 3 Graphics +15D8, DF, AMD Radeon Vega 3 Graphics +15D8, E3, AMD Radeon Vega 3 Graphics +15D8, E4, AMD Ryzen Embedded R1102G with Radeon Vega Gfx +15DD, 81, AMD Ryzen Embedded V1807B with Radeon Vega Gfx +15DD, 82, AMD Ryzen Embedded V1756B with Radeon Vega Gfx +15DD, 83, AMD Ryzen Embedded V1605B with Radeon Vega Gfx +15DD, 84, AMD Radeon Vega 6 Graphics +15DD, 85, AMD Ryzen Embedded V1202B with Radeon Vega Gfx +15DD, 86, AMD Radeon Vega 11 Graphics +15DD, 88, AMD Radeon Vega 8 Graphics +15DD, C1, AMD Radeon Vega 11 Graphics +15DD, C2, AMD Radeon Vega 8 Graphics +15DD, C3, AMD Radeon Vega 3 / 10 Graphics +15DD, C4, AMD Radeon Vega 8 Graphics +15DD, C5, AMD Radeon Vega 3 Graphics +15DD, C6, AMD Radeon Vega 11 Graphics +15DD, C8, AMD Radeon Vega 8 Graphics +15DD, C9, AMD Radeon Vega 11 Graphics +15DD, CA, AMD Radeon Vega 8 Graphics +15DD, CB, AMD Radeon Vega 3 Graphics +15DD, CC, AMD Radeon Vega 6 Graphics +15DD, CE, AMD Radeon Vega 3 Graphics +15DD, CF, AMD Radeon Vega 3 Graphics +15DD, D0, AMD Radeon Vega 10 Graphics +15DD, D1, AMD Radeon Vega 8 Graphics +15DD, D3, AMD Radeon Vega 11 Graphics +15DD, D5, AMD Radeon Vega 8 Graphics +15DD, D6, AMD Radeon Vega 11 Graphics +15DD, D7, AMD Radeon Vega 8 Graphics +15DD, D8, AMD Radeon Vega 3 Graphics +15DD, D9, AMD Radeon Vega 6 Graphics +15DD, E1, AMD Radeon Vega 3 Graphics +15DD, E2, AMD Radeon Vega 3 Graphics +163F, AE, AMD Custom GPU 0405 +6600, 00, AMD Radeon HD 8600 / 8700M +6600, 81, AMD Radeon R7 M370 +6601, 00, AMD Radeon HD 8500M / 8700M +6604, 00, AMD Radeon R7 M265 Series +6604, 81, AMD Radeon R7 M350 +6605, 00, AMD Radeon R7 M260 Series +6605, 81, AMD Radeon R7 M340 +6606, 00, AMD Radeon HD 8790M +6607, 00, AMD Radeon R5 M240 +6608, 00, AMD FirePro W2100 +6610, 00, AMD Radeon R7 200 Series +6610, 81, AMD Radeon R7 350 +6610, 83, AMD Radeon R5 340 +6610, 87, AMD Radeon R7 200 Series +6611, 00, AMD Radeon R7 200 Series +6611, 87, AMD Radeon R7 200 Series +6613, 00, AMD Radeon R7 200 Series +6617, 00, AMD Radeon R7 240 Series +6617, 87, AMD Radeon R7 200 Series +6617, C7, AMD Radeon R7 240 Series +6640, 00, AMD Radeon HD 8950 +6640, 80, AMD Radeon R9 M380 +6646, 00, AMD Radeon R9 M280X +6646, 80, AMD Radeon R9 M385 +6646, 80, AMD Radeon R9 M470X +6647, 00, AMD Radeon R9 M200X Series +6647, 80, AMD Radeon R9 M380 +6649, 00, AMD FirePro W5100 +6658, 00, AMD Radeon R7 200 Series +665C, 00, AMD Radeon HD 7700 Series +665D, 00, AMD Radeon R7 200 Series +665F, 81, AMD Radeon R7 360 Series +6660, 00, AMD Radeon HD 8600M Series +6660, 81, AMD Radeon R5 M335 +6660, 83, AMD Radeon R5 M330 +6663, 00, AMD Radeon HD 8500M Series +6663, 83, AMD Radeon R5 M320 +6664, 00, AMD Radeon R5 M200 Series +6665, 00, AMD Radeon R5 M230 Series +6665, 83, AMD Radeon R5 M320 +6665, C3, AMD Radeon R5 M435 +6666, 00, AMD Radeon R5 M200 Series +6667, 00, AMD Radeon R5 M200 Series +666F, 00, AMD Radeon HD 8500M +66A1, 02, AMD Instinct MI60 / MI50 +66A1, 06, AMD Radeon Pro VII +66AF, C1, AMD Radeon VII +6780, 00, AMD FirePro W9000 +6784, 00, ATI FirePro V (FireGL V) Graphics Adapter +6788, 00, ATI FirePro V (FireGL V) Graphics Adapter +678A, 00, AMD FirePro W8000 +6798, 00, AMD Radeon R9 200 / HD 7900 Series +6799, 00, AMD Radeon HD 7900 Series +679A, 00, AMD Radeon HD 7900 Series +679B, 00, AMD Radeon HD 7900 Series +679E, 00, AMD Radeon HD 7800 Series +67A0, 00, AMD Radeon FirePro W9100 +67A1, 00, AMD Radeon FirePro W8100 +67B0, 00, AMD Radeon R9 200 Series +67B0, 80, AMD Radeon R9 390 Series +67B1, 00, AMD Radeon R9 200 Series +67B1, 80, AMD Radeon R9 390 Series +67B9, 00, AMD Radeon R9 200 Series +67C0, 00, AMD Radeon Pro WX 7100 Graphics +67C0, 80, AMD Radeon E9550 +67C2, 01, AMD Radeon Pro V7350x2 +67C2, 02, AMD Radeon Pro V7300X +67C4, 00, AMD Radeon Pro WX 7100 Graphics +67C4, 80, AMD Radeon E9560 / E9565 Graphics +67C7, 00, AMD Radeon Pro WX 5100 Graphics +67C7, 80, AMD Radeon E9390 Graphics +67D0, 01, AMD Radeon Pro V7350x2 +67D0, 02, AMD Radeon Pro V7300X +67DF, C0, AMD Radeon Pro 580X +67DF, C1, AMD Radeon RX 580 Series +67DF, C2, AMD Radeon RX 570 Series +67DF, C3, AMD Radeon RX 580 Series +67DF, C4, AMD Radeon RX 480 Graphics +67DF, C5, AMD Radeon RX 470 Graphics +67DF, C6, AMD Radeon RX 570 Series +67DF, C7, AMD Radeon RX 480 Graphics +67DF, CF, AMD Radeon RX 470 Graphics +67DF, D7, AMD Radeon RX 470 Graphics +67DF, E0, AMD Radeon RX 470 Series +67DF, E1, AMD Radeon RX 590 Series +67DF, E3, AMD Radeon RX Series +67DF, E7, AMD Radeon RX 580 Series +67DF, EB, AMD Radeon Pro 580X +67DF, EF, AMD Radeon RX 570 Series +67DF, F7, AMD Radeon RX P30PH +67DF, FF, AMD Radeon RX 470 Series +67E0, 00, AMD Radeon Pro WX Series +67E3, 00, AMD Radeon Pro WX 4100 +67E8, 00, AMD Radeon Pro WX Series +67E8, 01, AMD Radeon Pro WX Series +67E8, 80, AMD Radeon E9260 Graphics +67EB, 00, AMD Radeon Pro V5300X +67EF, C0, AMD Radeon RX Graphics +67EF, C1, AMD Radeon RX 460 Graphics +67EF, C2, AMD Radeon Pro Series +67EF, C3, AMD Radeon RX Series +67EF, C5, AMD Radeon RX 460 Graphics +67EF, C7, AMD Radeon RX Graphics +67EF, CF, AMD Radeon RX 460 Graphics +67EF, E0, AMD Radeon RX 560 Series +67EF, E1, AMD Radeon RX Series +67EF, E2, AMD Radeon RX 560X +67EF, E3, AMD Radeon RX Series +67EF, E5, AMD Radeon RX 560 Series +67EF, E7, AMD Radeon RX 560 Series +67EF, EF, AMD Radeon 550 Series +67EF, FF, AMD Radeon RX 460 Graphics +67FF, C0, AMD Radeon Pro 465 +67FF, C1, AMD Radeon RX 560 Series +67FF, CF, AMD Radeon RX 560 Series +67FF, EF, AMD Radeon RX 560 Series +67FF, FF, AMD Radeon RX 550 Series +6800, 00, AMD Radeon HD 7970M +6801, 00, AMD Radeon HD 8970M +6806, 00, AMD Radeon R9 M290X +6808, 00, AMD FirePro W7000 +6808, 00, ATI FirePro V (FireGL V) Graphics Adapter +6809, 00, ATI FirePro W5000 +6810, 00, AMD Radeon R9 200 Series +6810, 81, AMD Radeon R9 370 Series +6811, 00, AMD Radeon R9 200 Series +6811, 81, AMD Radeon R7 370 Series +6818, 00, AMD Radeon HD 7800 Series +6819, 00, AMD Radeon HD 7800 Series +6820, 00, AMD Radeon R9 M275X +6820, 81, AMD Radeon R9 M375 +6820, 83, AMD Radeon R9 M375X +6821, 00, AMD Radeon R9 M200X Series +6821, 83, AMD Radeon R9 M370X +6821, 87, AMD Radeon R7 M380 +6822, 00, AMD Radeon E8860 +6823, 00, AMD Radeon R9 M200X Series +6825, 00, AMD Radeon HD 7800M Series +6826, 00, AMD Radeon HD 7700M Series +6827, 00, AMD Radeon HD 7800M Series +6828, 00, AMD FirePro W600 +682B, 00, AMD Radeon HD 8800M Series +682B, 87, AMD Radeon R9 M360 +682C, 00, AMD FirePro W4100 +682D, 00, AMD Radeon HD 7700M Series +682F, 00, AMD Radeon HD 7700M Series +6830, 00, AMD Radeon 7800M Series +6831, 00, AMD Radeon 7700M Series +6835, 00, AMD Radeon R7 Series / HD 9000 Series +6837, 00, AMD Radeon HD 7700 Series +683D, 00, AMD Radeon HD 7700 Series +683F, 00, AMD Radeon HD 7700 Series +684C, 00, ATI FirePro V (FireGL V) Graphics Adapter +6860, 00, AMD Radeon Instinct MI25 +6860, 01, AMD Radeon Instinct MI25 +6860, 02, AMD Radeon Instinct MI25 +6860, 03, AMD Radeon Pro V340 +6860, 04, AMD Radeon Instinct MI25x2 +6860, 07, AMD Radeon Pro V320 +6861, 00, AMD Radeon Pro WX 9100 +6862, 00, AMD Radeon Pro SSG +6863, 00, AMD Radeon Vega Frontier Edition +6864, 03, AMD Radeon Pro V340 +6864, 04, AMD Radeon Instinct MI25x2 +6864, 05, AMD Radeon Pro V340 +6868, 00, AMD Radeon Pro WX 8200 +686C, 00, AMD Radeon Instinct MI25 MxGPU +686C, 01, AMD Radeon Instinct MI25 MxGPU +686C, 02, AMD Radeon Instinct MI25 MxGPU +686C, 03, AMD Radeon Pro V340 MxGPU +686C, 04, AMD Radeon Instinct MI25x2 MxGPU +686C, 05, AMD Radeon Pro V340L MxGPU +686C, 06, AMD Radeon Instinct MI25 MxGPU +687F, 01, AMD Radeon RX Vega +687F, C0, AMD Radeon RX Vega +687F, C1, AMD Radeon RX Vega +687F, C3, AMD Radeon RX Vega +687F, C7, AMD Radeon RX Vega +6900, 00, AMD Radeon R7 M260 +6900, 81, AMD Radeon R7 M360 +6900, 83, AMD Radeon R7 M340 +6900, C1, AMD Radeon R5 M465 Series +6900, C3, AMD Radeon R5 M445 Series +6900, D1, AMD Radeon 530 Series +6900, D3, AMD Radeon 530 Series +6901, 00, AMD Radeon R5 M255 +6902, 00, AMD Radeon Series +6907, 00, AMD Radeon R5 M255 +6907, 87, AMD Radeon R5 M315 +6920, 00, AMD Radeon R9 M395X +6920, 01, AMD Radeon R9 M390X +6921, 00, AMD Radeon R9 M390X +6929, 00, AMD FirePro S7150 +6929, 01, AMD FirePro S7100X +692B, 00, AMD FirePro W7100 +6938, 00, AMD Radeon R9 200 Series +6938, F0, AMD Radeon R9 200 Series +6938, F1, AMD Radeon R9 380 Series +6939, 00, AMD Radeon R9 200 Series +6939, F0, AMD Radeon R9 200 Series +6939, F1, AMD Radeon R9 380 Series +694C, C0, AMD Radeon RX Vega M GH Graphics +694E, C0, AMD Radeon RX Vega M GL Graphics +6980, 00, AMD Radeon Pro WX 3100 +6981, 00, AMD Radeon Pro WX 3200 Series +6981, 01, AMD Radeon Pro WX 3200 Series +6981, 10, AMD Radeon Pro WX 3200 Series +6985, 00, AMD Radeon Pro WX 3100 +6986, 00, AMD Radeon Pro WX 2100 +6987, 80, AMD Embedded Radeon E9171 +6987, C0, AMD Radeon 550X Series +6987, C1, AMD Radeon RX 640 +6987, C3, AMD Radeon 540X Series +6987, C7, AMD Radeon 540 +6995, 00, AMD Radeon Pro WX 2100 +6997, 00, AMD Radeon Pro WX 2100 +699F, 81, AMD Embedded Radeon E9170 Series +699F, C0, AMD Radeon 500 Series +699F, C1, AMD Radeon 540 Series +699F, C3, AMD Radeon 500 Series +699F, C7, AMD Radeon RX 550 / 550 Series +699F, C9, AMD Radeon 540 +6FDF, E7, AMD Radeon RX 590 GME +6FDF, EF, AMD Radeon RX 580 2048SP +7300, C1, AMD FirePro S9300 x2 +7300, C8, AMD Radeon R9 Fury Series +7300, C9, AMD Radeon Pro Duo +7300, CA, AMD Radeon R9 Fury Series +7300, CB, AMD Radeon R9 Fury Series +7312, 00, AMD Radeon Pro W5700 +731E, C6, AMD Radeon RX 5700XTB +731E, C7, AMD Radeon RX 5700B +731F, C0, AMD Radeon RX 5700 XT 50th Anniversary +731F, C1, AMD Radeon RX 5700 XT +731F, C2, AMD Radeon RX 5600M +731F, C3, AMD Radeon RX 5700M +731F, C4, AMD Radeon RX 5700 +731F, C5, AMD Radeon RX 5700 XT +731F, CA, AMD Radeon RX 5600 XT +731F, CB, AMD Radeon RX 5600 OEM +7340, C1, AMD Radeon RX 5500M +7340, C3, AMD Radeon RX 5300M +7340, C5, AMD Radeon RX 5500 XT +7340, C7, AMD Radeon RX 5500 +7340, C9, AMD Radeon RX 5500XTB +7340, CF, AMD Radeon RX 5300 +7341, 00, AMD Radeon Pro W5500 +7347, 00, AMD Radeon Pro W5500M +7360, 41, AMD Radeon Pro 5600M +7360, C3, AMD Radeon Pro V520 +738C, 01, AMD Instinct MI100 +73A3, 00, AMD Radeon Pro W6800 +73A5, C0, AMD Radeon RX 6950 XT +73AF, C0, AMD Radeon RX 6900 XT +73BF, C0, AMD Radeon RX 6900 XT +73BF, C1, AMD Radeon RX 6800 XT +73BF, C3, AMD Radeon RX 6800 +73DF, C0, AMD Radeon RX 6750 XT +73DF, C1, AMD Radeon RX 6700 XT +73DF, C2, AMD Radeon RX 6800M +73DF, C3, AMD Radeon RX 6800M +73DF, C5, AMD Radeon RX 6700 XT +73DF, CF, AMD Radeon RX 6700M +73DF, D7, AMD TDC-235 +73E1, 00, AMD Radeon Pro W6600M +73E3, 00, AMD Radeon Pro W6600 +73EF, C0, AMD Radeon RX 6800S +73EF, C1, AMD Radeon RX 6650 XT +73EF, C2, AMD Radeon RX 6700S +73EF, C3, AMD Radeon RX 6650M +73EF, C4, AMD Radeon RX 6650M XT +73FF, C1, AMD Radeon RX 6600 XT +73FF, C3, AMD Radeon RX 6600M +73FF, C7, AMD Radeon RX 6600 +73FF, CB, AMD Radeon RX 6600S +7408, 00, AMD Instinct MI250X +740C, 01, AMD Instinct MI250X / MI250 +740F, 02, AMD Instinct MI210 +7421, 00, AMD Radeon Pro W6500M +7422, 00, AMD Radeon Pro W6400 +7423, 00, AMD Radeon Pro W6300M +7423, 01, AMD Radeon Pro W6300 +7424, 00, AMD Radeon RX 6300 +743F, C1, AMD Radeon RX 6500 XT +743F, C3, AMD Radeon RX 6500 +743F, C3, AMD Radeon RX 6500M +743F, C7, AMD Radeon RX 6400 +743F, CF, AMD Radeon RX 6300M +9830, 00, AMD Radeon HD 8400 / R3 Series +9831, 00, AMD Radeon HD 8400E +9832, 00, AMD Radeon HD 8330 +9833, 00, AMD Radeon HD 8330E +9834, 00, AMD Radeon HD 8210 +9835, 00, AMD Radeon HD 8210E +9836, 00, AMD Radeon HD 8200 / R3 Series +9837, 00, AMD Radeon HD 8280E +9838, 00, AMD Radeon HD 8200 / R3 series +9839, 00, AMD Radeon HD 8180 +983D, 00, AMD Radeon HD 8250 +9850, 00, AMD Radeon R3 Graphics +9850, 03, AMD Radeon R3 Graphics +9850, 40, AMD Radeon R2 Graphics +9850, 45, AMD Radeon R3 Graphics +9851, 00, AMD Radeon R4 Graphics +9851, 01, AMD Radeon R5E Graphics +9851, 05, AMD Radeon R5 Graphics +9851, 06, AMD Radeon R5E Graphics +9851, 40, AMD Radeon R4 Graphics +9851, 45, AMD Radeon R5 Graphics +9852, 00, AMD Radeon R2 Graphics +9852, 40, AMD Radeon E1 Graphics +9853, 00, AMD Radeon R2 Graphics +9853, 01, AMD Radeon R4E Graphics +9853, 03, AMD Radeon R2 Graphics +9853, 05, AMD Radeon R1E Graphics +9853, 06, AMD Radeon R1E Graphics +9853, 07, AMD Radeon R1E Graphics +9853, 08, AMD Radeon R1E Graphics +9853, 40, AMD Radeon R2 Graphics +9854, 00, AMD Radeon R3 Graphics +9854, 01, AMD Radeon R3E Graphics +9854, 02, AMD Radeon R3 Graphics +9854, 05, AMD Radeon R2 Graphics +9854, 06, AMD Radeon R4 Graphics +9854, 07, AMD Radeon R3 Graphics +9855, 02, AMD Radeon R6 Graphics +9855, 05, AMD Radeon R4 Graphics +9856, 00, AMD Radeon R2 Graphics +9856, 01, AMD Radeon R2E Graphics +9856, 02, AMD Radeon R2 Graphics +9856, 05, AMD Radeon R1E Graphics +9856, 06, AMD Radeon R2 Graphics +9856, 07, AMD Radeon R1E Graphics +9856, 08, AMD Radeon R1E Graphics +9856, 13, AMD Radeon R1E Graphics +9874, 81, AMD Radeon R6 Graphics +9874, 84, AMD Radeon R7 Graphics +9874, 85, AMD Radeon R6 Graphics +9874, 87, AMD Radeon R5 Graphics +9874, 88, AMD Radeon R7E Graphics +9874, 89, AMD Radeon R6E Graphics +9874, C4, AMD Radeon R7 Graphics +9874, C5, AMD Radeon R6 Graphics +9874, C6, AMD Radeon R6 Graphics +9874, C7, AMD Radeon R5 Graphics +9874, C8, AMD Radeon R7 Graphics +9874, C9, AMD Radeon R7 Graphics +9874, CA, AMD Radeon R5 Graphics +9874, CB, AMD Radeon R5 Graphics +9874, CC, AMD Radeon R7 Graphics +9874, CD, AMD Radeon R7 Graphics +9874, CE, AMD Radeon R5 Graphics +9874, E1, AMD Radeon R7 Graphics +9874, E2, AMD Radeon R7 Graphics +9874, E3, AMD Radeon R7 Graphics +9874, E4, AMD Radeon R7 Graphics +9874, E5, AMD Radeon R5 Graphics +9874, E6, AMD Radeon R5 Graphics +98E4, 80, AMD Radeon R5E Graphics +98E4, 81, AMD Radeon R4E Graphics +98E4, 83, AMD Radeon R2E Graphics +98E4, 84, AMD Radeon R2E Graphics +98E4, 86, AMD Radeon R1E Graphics +98E4, C0, AMD Radeon R4 Graphics +98E4, C1, AMD Radeon R5 Graphics +98E4, C2, AMD Radeon R4 Graphics +98E4, C4, AMD Radeon R5 Graphics +98E4, C6, AMD Radeon R5 Graphics +98E4, C8, AMD Radeon R4 Graphics +98E4, C9, AMD Radeon R4 Graphics +98E4, CA, AMD Radeon R5 Graphics +98E4, D0, AMD Radeon R2 Graphics +98E4, D1, AMD Radeon R2 Graphics +98E4, D2, AMD Radeon R2 Graphics +98E4, D4, AMD Radeon R2 Graphics +98E4, D9, AMD Radeon R5 Graphics +98E4, DA, AMD Radeon R5 Graphics +98E4, DB, AMD Radeon R3 Graphics +98E4, E1, AMD Radeon R3 Graphics +98E4, E2, AMD Radeon R3 Graphics +98E4, E9, AMD Radeon R4 Graphics +98E4, EA, AMD Radeon R4 Graphics +98E4, EB, AMD Radeon R3 Graphics +98E4, EB, AMD Radeon R4 Graphics diff --git a/data/meson.build b/data/meson.build new file mode 100644 index 0000000..9c26b66 --- /dev/null +++ b/data/meson.build @@ -0,0 +1,27 @@ +# Copyright © 2017-2018 Intel Corporation + +# 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. + +if with_amdgpu + install_data( + 'amdgpu.ids', + install_mode : 'rw-r--r--', + install_dir : datadir_amdgpu, + ) +endif diff --git a/etnaviv/Android.mk b/etnaviv/Android.mk new file mode 100644 index 0000000..390f9a9 --- /dev/null +++ b/etnaviv/Android.mk @@ -0,0 +1,14 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +# Import variables LIBDRM_ETNAVIV_FILES, LIBDRM_ETNAVIV_H_FILES +include $(LOCAL_PATH)/Makefile.sources + +LOCAL_MODULE := libdrm_etnaviv + +LOCAL_SHARED_LIBRARIES := libdrm + +LOCAL_SRC_FILES := $(LIBDRM_ETNAVIV_FILES) + +include $(LIBDRM_COMMON_MK) +include $(BUILD_SHARED_LIBRARY) diff --git a/etnaviv/Makefile.sources b/etnaviv/Makefile.sources new file mode 100644 index 0000000..0eb7378 --- /dev/null +++ b/etnaviv/Makefile.sources @@ -0,0 +1,13 @@ +LIBDRM_ETNAVIV_FILES := \ + etnaviv_device.c \ + etnaviv_gpu.c \ + etnaviv_bo.c \ + etnaviv_bo_cache.c \ + etnaviv_perfmon.c \ + etnaviv_pipe.c \ + etnaviv_cmd_stream.c \ + etnaviv_drm.h \ + etnaviv_priv.h + +LIBDRM_ETNAVIV_H_FILES := \ + etnaviv_drmif.h diff --git a/etnaviv/etnaviv-symbols.txt b/etnaviv/etnaviv-symbols.txt new file mode 100644 index 0000000..f48cece --- /dev/null +++ b/etnaviv/etnaviv-symbols.txt @@ -0,0 +1,36 @@ +etna_device_new +etna_device_new_dup +etna_device_ref +etna_device_del +etna_device_fd +etna_gpu_new +etna_gpu_del +etna_gpu_get_param +etna_pipe_new +etna_pipe_del +etna_pipe_wait +etna_pipe_wait_ns +etna_bo_new +etna_bo_from_name +etna_bo_from_dmabuf +etna_bo_ref +etna_bo_del +etna_bo_get_name +etna_bo_handle +etna_bo_dmabuf +etna_bo_size +etna_bo_map +etna_bo_cpu_prep +etna_bo_cpu_fini +etna_cmd_stream_new +etna_cmd_stream_del +etna_cmd_stream_timestamp +etna_cmd_stream_flush +etna_cmd_stream_flush2 +etna_cmd_stream_finish +etna_cmd_stream_perf +etna_cmd_stream_reloc +etna_perfmon_create +etna_perfmon_del +etna_perfmon_get_dom_by_name +etna_perfmon_get_sig_by_name diff --git a/etnaviv/etnaviv_bo.c b/etnaviv/etnaviv_bo.c new file mode 100644 index 0000000..27123e6 --- /dev/null +++ b/etnaviv/etnaviv_bo.c @@ -0,0 +1,340 @@ +/* + * Copyright (C) 2014 Etnaviv Project + * + * 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 (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 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. + * + * Authors: + * Christian Gmeiner + */ + +#include "etnaviv_priv.h" +#include "etnaviv_drmif.h" + +drm_private pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER; +drm_private void bo_del(struct etna_bo *bo); + +/* set buffer name, and add to table, call w/ table_lock held: */ +static void set_name(struct etna_bo *bo, uint32_t name) +{ + bo->name = name; + /* add ourself into the name table: */ + drmHashInsert(bo->dev->name_table, name, bo); +} + +/* Called under table_lock */ +drm_private void bo_del(struct etna_bo *bo) +{ + if (bo->map) + drm_munmap(bo->map, bo->size); + + if (bo->name) + drmHashDelete(bo->dev->name_table, bo->name); + + if (bo->handle) { + drmHashDelete(bo->dev->handle_table, bo->handle); + drmCloseBufferHandle(bo->dev->fd, bo->handle); + } + + free(bo); +} + +/* lookup a buffer from it's handle, call w/ table_lock held: */ +static struct etna_bo *lookup_bo(void *tbl, uint32_t handle) +{ + struct etna_bo *bo = NULL; + + if (!drmHashLookup(tbl, handle, (void **)&bo)) { + /* found, incr refcnt and return: */ + bo = etna_bo_ref(bo); + + /* don't break the bucket if this bo was found in one */ + list_delinit(&bo->list); + } + + return bo; +} + +/* allocate a new buffer object, call w/ table_lock held */ +static struct etna_bo *bo_from_handle(struct etna_device *dev, + uint32_t size, uint32_t handle, uint32_t flags) +{ + struct etna_bo *bo = calloc(sizeof(*bo), 1); + + if (!bo) { + drmCloseBufferHandle(dev->fd, handle); + return NULL; + } + + bo->dev = etna_device_ref(dev); + bo->size = size; + bo->handle = handle; + bo->flags = flags; + atomic_set(&bo->refcnt, 1); + list_inithead(&bo->list); + /* add ourselves to the handle table: */ + drmHashInsert(dev->handle_table, handle, bo); + + return bo; +} + +/* allocate a new (un-tiled) buffer object */ +drm_public struct etna_bo *etna_bo_new(struct etna_device *dev, uint32_t size, + uint32_t flags) +{ + struct etna_bo *bo; + int ret; + struct drm_etnaviv_gem_new req = { + .flags = flags, + }; + + bo = etna_bo_cache_alloc(&dev->bo_cache, &size, flags); + if (bo) + return bo; + + req.size = size; + ret = drmCommandWriteRead(dev->fd, DRM_ETNAVIV_GEM_NEW, + &req, sizeof(req)); + if (ret) + return NULL; + + pthread_mutex_lock(&table_lock); + bo = bo_from_handle(dev, size, req.handle, flags); + bo->reuse = 1; + pthread_mutex_unlock(&table_lock); + + return bo; +} + +drm_public struct etna_bo *etna_bo_ref(struct etna_bo *bo) +{ + atomic_inc(&bo->refcnt); + + return bo; +} + +/* get buffer info */ +static int get_buffer_info(struct etna_bo *bo) +{ + int ret; + struct drm_etnaviv_gem_info req = { + .handle = bo->handle, + }; + + ret = drmCommandWriteRead(bo->dev->fd, DRM_ETNAVIV_GEM_INFO, + &req, sizeof(req)); + if (ret) { + return ret; + } + + /* really all we need for now is mmap offset */ + bo->offset = req.offset; + + return 0; +} + +/* import a buffer object from DRI2 name */ +drm_public struct etna_bo *etna_bo_from_name(struct etna_device *dev, + uint32_t name) +{ + struct etna_bo *bo; + struct drm_gem_open req = { + .name = name, + }; + + pthread_mutex_lock(&table_lock); + + /* check name table first, to see if bo is already open: */ + bo = lookup_bo(dev->name_table, name); + if (bo) + goto out_unlock; + + if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) { + ERROR_MSG("gem-open failed: %s", strerror(errno)); + goto out_unlock; + } + + bo = lookup_bo(dev->handle_table, req.handle); + if (bo) + goto out_unlock; + + bo = bo_from_handle(dev, req.size, req.handle, 0); + if (bo) + set_name(bo, name); + +out_unlock: + pthread_mutex_unlock(&table_lock); + + return bo; +} + +/* import a buffer from dmabuf fd, does not take ownership of the + * fd so caller should close() the fd when it is otherwise done + * with it (even if it is still using the 'struct etna_bo *') + */ +drm_public struct etna_bo *etna_bo_from_dmabuf(struct etna_device *dev, int fd) +{ + struct etna_bo *bo; + int ret, size; + uint32_t handle; + + /* take the lock before calling drmPrimeFDToHandle to avoid + * racing against etna_bo_del, which might invalidate the + * returned handle. + */ + pthread_mutex_lock(&table_lock); + + ret = drmPrimeFDToHandle(dev->fd, fd, &handle); + if (ret) { + pthread_mutex_unlock(&table_lock); + return NULL; + } + + bo = lookup_bo(dev->handle_table, handle); + if (bo) + goto out_unlock; + + /* lseek() to get bo size */ + size = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_CUR); + + bo = bo_from_handle(dev, size, handle, 0); + +out_unlock: + pthread_mutex_unlock(&table_lock); + + return bo; +} + +/* destroy a buffer object */ +drm_public void etna_bo_del(struct etna_bo *bo) +{ + struct etna_device *dev = bo->dev; + + if (!bo) + return; + + if (!atomic_dec_and_test(&bo->refcnt)) + return; + + pthread_mutex_lock(&table_lock); + + if (bo->reuse && (etna_bo_cache_free(&dev->bo_cache, bo) == 0)) + goto out; + + bo_del(bo); + etna_device_del_locked(dev); +out: + pthread_mutex_unlock(&table_lock); +} + +/* get the global flink/DRI2 buffer name */ +drm_public int etna_bo_get_name(struct etna_bo *bo, uint32_t *name) +{ + if (!bo->name) { + struct drm_gem_flink req = { + .handle = bo->handle, + }; + int ret; + + ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req); + if (ret) { + return ret; + } + + pthread_mutex_lock(&table_lock); + set_name(bo, req.name); + pthread_mutex_unlock(&table_lock); + bo->reuse = 0; + } + + *name = bo->name; + + return 0; +} + +drm_public uint32_t etna_bo_handle(struct etna_bo *bo) +{ + return bo->handle; +} + +/* caller owns the dmabuf fd that is returned and is responsible + * to close() it when done + */ +drm_public int etna_bo_dmabuf(struct etna_bo *bo) +{ + int ret, prime_fd; + + ret = drmPrimeHandleToFD(bo->dev->fd, bo->handle, DRM_CLOEXEC, + &prime_fd); + if (ret) { + ERROR_MSG("failed to get dmabuf fd: %d", ret); + return ret; + } + + bo->reuse = 0; + + return prime_fd; +} + +drm_public uint32_t etna_bo_size(struct etna_bo *bo) +{ + return bo->size; +} + +drm_public void *etna_bo_map(struct etna_bo *bo) +{ + if (!bo->map) { + if (!bo->offset) { + get_buffer_info(bo); + } + + bo->map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, + MAP_SHARED, bo->dev->fd, bo->offset); + if (bo->map == MAP_FAILED) { + ERROR_MSG("mmap failed: %s", strerror(errno)); + bo->map = NULL; + } + } + + return bo->map; +} + +drm_public int etna_bo_cpu_prep(struct etna_bo *bo, uint32_t op) +{ + struct drm_etnaviv_gem_cpu_prep req = { + .handle = bo->handle, + .op = op, + }; + + get_abs_timeout(&req.timeout, 5000000000); + + return drmCommandWrite(bo->dev->fd, DRM_ETNAVIV_GEM_CPU_PREP, + &req, sizeof(req)); +} + +drm_public void etna_bo_cpu_fini(struct etna_bo *bo) +{ + struct drm_etnaviv_gem_cpu_fini req = { + .handle = bo->handle, + }; + + drmCommandWrite(bo->dev->fd, DRM_ETNAVIV_GEM_CPU_FINI, + &req, sizeof(req)); +} diff --git a/etnaviv/etnaviv_bo_cache.c b/etnaviv/etnaviv_bo_cache.c new file mode 100644 index 0000000..c81de26 --- /dev/null +++ b/etnaviv/etnaviv_bo_cache.c @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2016 Etnaviv Project + * + * 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 (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 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. + * + * Authors: + * Christian Gmeiner + */ + +#include "etnaviv_priv.h" +#include "etnaviv_drmif.h" + +drm_private void bo_del(struct etna_bo *bo); +drm_private extern pthread_mutex_t table_lock; + +static void add_bucket(struct etna_bo_cache *cache, int size) +{ + unsigned i = cache->num_buckets; + + assert(i < ARRAY_SIZE(cache->cache_bucket)); + + list_inithead(&cache->cache_bucket[i].list); + cache->cache_bucket[i].size = size; + cache->num_buckets++; +} + +drm_private void etna_bo_cache_init(struct etna_bo_cache *cache) +{ + unsigned long size, cache_max_size = 64 * 1024 * 1024; + + /* OK, so power of two buckets was too wasteful of memory. + * Give 3 other sizes between each power of two, to hopefully + * cover things accurately enough. (The alternative is + * probably to just go for exact matching of sizes, and assume + * that for things like composited window resize the tiled + * width/height alignment and rounding of sizes to pages will + * get us useful cache hit rates anyway) + */ + add_bucket(cache, 4096); + add_bucket(cache, 4096 * 2); + add_bucket(cache, 4096 * 3); + + /* Initialize the linked lists for BO reuse cache. */ + for (size = 4 * 4096; size <= cache_max_size; size *= 2) { + add_bucket(cache, size); + add_bucket(cache, size + size * 1 / 4); + add_bucket(cache, size + size * 2 / 4); + add_bucket(cache, size + size * 3 / 4); + } +} + +/* Frees older cached buffers. Called under table_lock */ +drm_private void etna_bo_cache_cleanup(struct etna_bo_cache *cache, time_t time) +{ + unsigned i; + + if (cache->time == time) + return; + + for (i = 0; i < cache->num_buckets; i++) { + struct etna_bo_bucket *bucket = &cache->cache_bucket[i]; + struct etna_bo *bo; + + while (!LIST_IS_EMPTY(&bucket->list)) { + bo = LIST_ENTRY(struct etna_bo, bucket->list.next, list); + + /* keep things in cache for at least 1 second: */ + if (time && ((time - bo->free_time) <= 1)) + break; + + list_del(&bo->list); + bo_del(bo); + } + } + + cache->time = time; +} + +static struct etna_bo_bucket *get_bucket(struct etna_bo_cache *cache, uint32_t size) +{ + unsigned i; + + /* hmm, this is what intel does, but I suppose we could calculate our + * way to the correct bucket size rather than looping.. + */ + for (i = 0; i < cache->num_buckets; i++) { + struct etna_bo_bucket *bucket = &cache->cache_bucket[i]; + if (bucket->size >= size) { + return bucket; + } + } + + return NULL; +} + +static int is_idle(struct etna_bo *bo) +{ + return etna_bo_cpu_prep(bo, + DRM_ETNA_PREP_READ | + DRM_ETNA_PREP_WRITE | + DRM_ETNA_PREP_NOSYNC) == 0; +} + +static struct etna_bo *find_in_bucket(struct etna_bo_bucket *bucket, uint32_t flags) +{ + struct etna_bo *bo = NULL, *tmp; + + pthread_mutex_lock(&table_lock); + + if (LIST_IS_EMPTY(&bucket->list)) + goto out_unlock; + + LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bucket->list, list) { + /* skip BOs with different flags */ + if (bo->flags != flags) + continue; + + /* check if the first BO with matching flags is idle */ + if (is_idle(bo)) { + list_delinit(&bo->list); + goto out_unlock; + } + + /* If the oldest BO is still busy, don't try younger ones */ + break; + } + + /* There was no matching buffer found */ + bo = NULL; + +out_unlock: + pthread_mutex_unlock(&table_lock); + + return bo; +} + +/* allocate a new (un-tiled) buffer object + * + * NOTE: size is potentially rounded up to bucket size + */ +drm_private struct etna_bo *etna_bo_cache_alloc(struct etna_bo_cache *cache, uint32_t *size, + uint32_t flags) +{ + struct etna_bo *bo; + struct etna_bo_bucket *bucket; + + *size = ALIGN(*size, 4096); + bucket = get_bucket(cache, *size); + + /* see if we can be green and recycle: */ + if (bucket) { + *size = bucket->size; + bo = find_in_bucket(bucket, flags); + if (bo) { + atomic_set(&bo->refcnt, 1); + etna_device_ref(bo->dev); + return bo; + } + } + + return NULL; +} + +drm_private int etna_bo_cache_free(struct etna_bo_cache *cache, struct etna_bo *bo) +{ + struct etna_bo_bucket *bucket = get_bucket(cache, bo->size); + + /* see if we can be green and recycle: */ + if (bucket) { + struct timespec time; + + clock_gettime(CLOCK_MONOTONIC, &time); + + bo->free_time = time.tv_sec; + list_addtail(&bo->list, &bucket->list); + etna_bo_cache_cleanup(cache, time.tv_sec); + + /* bo's in the bucket cache don't have a ref and + * don't hold a ref to the dev: + */ + etna_device_del_locked(bo->dev); + + return 0; + } + + return -1; +} diff --git a/etnaviv/etnaviv_cmd_stream.c b/etnaviv/etnaviv_cmd_stream.c new file mode 100644 index 0000000..261777b --- /dev/null +++ b/etnaviv/etnaviv_cmd_stream.c @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2014-2015 Etnaviv Project + * + * 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 (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 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. + * + * Authors: + * Christian Gmeiner + */ + +#include + +#include "etnaviv_drmif.h" +#include "etnaviv_priv.h" + +static pthread_mutex_t idx_lock = PTHREAD_MUTEX_INITIALIZER; + +static void *grow(void *ptr, uint32_t nr, uint32_t *max, uint32_t sz) +{ + if ((nr + 1) > *max) { + if ((*max * 2) < (nr + 1)) + *max = nr + 5; + else + *max = *max * 2; + ptr = realloc(ptr, *max * sz); + } + + return ptr; +} + +#define APPEND(x, name) ({ \ + (x)->name = grow((x)->name, (x)->nr_ ## name, &(x)->max_ ## name, sizeof((x)->name[0])); \ + (x)->nr_ ## name ++; \ +}) + +static inline struct etna_cmd_stream_priv * +etna_cmd_stream_priv(struct etna_cmd_stream *stream) +{ + return (struct etna_cmd_stream_priv *)stream; +} + +drm_public struct etna_cmd_stream *etna_cmd_stream_new(struct etna_pipe *pipe, + uint32_t size, + void (*reset_notify)(struct etna_cmd_stream *stream, void *priv), + void *priv) +{ + struct etna_cmd_stream_priv *stream = NULL; + + if (size == 0) { + ERROR_MSG("invalid size of 0"); + goto fail; + } + + stream = calloc(1, sizeof(*stream)); + if (!stream) { + ERROR_MSG("allocation failed"); + goto fail; + } + + /* allocate even number of 32-bit words */ + size = ALIGN(size, 2); + + stream->base.buffer = malloc(size * sizeof(uint32_t)); + if (!stream->base.buffer) { + ERROR_MSG("allocation failed"); + goto fail; + } + + stream->base.size = size; + stream->pipe = pipe; + stream->reset_notify = reset_notify; + stream->reset_notify_priv = priv; + + return &stream->base; + +fail: + if (stream) + etna_cmd_stream_del(&stream->base); + + return NULL; +} + +drm_public void etna_cmd_stream_del(struct etna_cmd_stream *stream) +{ + struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream); + + free(stream->buffer); + free(priv->submit.relocs); + free(priv->submit.pmrs); + free(priv); +} + +static void reset_buffer(struct etna_cmd_stream *stream) +{ + struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream); + + stream->offset = 0; + priv->submit.nr_bos = 0; + priv->submit.nr_relocs = 0; + priv->submit.nr_pmrs = 0; + priv->nr_bos = 0; + + if (priv->reset_notify) + priv->reset_notify(stream, priv->reset_notify_priv); +} + +drm_public uint32_t etna_cmd_stream_timestamp(struct etna_cmd_stream *stream) +{ + return etna_cmd_stream_priv(stream)->last_timestamp; +} + +static uint32_t append_bo(struct etna_cmd_stream *stream, struct etna_bo *bo) +{ + struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream); + uint32_t idx; + + idx = APPEND(&priv->submit, bos); + idx = APPEND(priv, bos); + + priv->submit.bos[idx].flags = 0; + priv->submit.bos[idx].handle = bo->handle; + + priv->bos[idx] = etna_bo_ref(bo); + + return idx; +} + +/* add (if needed) bo, return idx: */ +static uint32_t bo2idx(struct etna_cmd_stream *stream, struct etna_bo *bo, + uint32_t flags) +{ + struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream); + uint32_t idx; + + pthread_mutex_lock(&idx_lock); + + if (bo->current_stream == stream) { + idx = bo->idx; + } else { + /* slow-path: */ + for (idx = 0; idx < priv->nr_bos; idx++) + if (priv->bos[idx] == bo) + break; + if (idx == priv->nr_bos) { + /* not found */ + idx = append_bo(stream, bo); + } + bo->current_stream = stream; + bo->idx = idx; + } + pthread_mutex_unlock(&idx_lock); + + if (flags & ETNA_RELOC_READ) + priv->submit.bos[idx].flags |= ETNA_SUBMIT_BO_READ; + if (flags & ETNA_RELOC_WRITE) + priv->submit.bos[idx].flags |= ETNA_SUBMIT_BO_WRITE; + + return idx; +} + +static void flush(struct etna_cmd_stream *stream, int in_fence_fd, + int *out_fence_fd) +{ + struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream); + int ret, id = priv->pipe->id; + struct etna_gpu *gpu = priv->pipe->gpu; + + struct drm_etnaviv_gem_submit req = { + .pipe = gpu->core, + .exec_state = id, + .bos = VOID2U64(priv->submit.bos), + .nr_bos = priv->submit.nr_bos, + .relocs = VOID2U64(priv->submit.relocs), + .nr_relocs = priv->submit.nr_relocs, + .pmrs = VOID2U64(priv->submit.pmrs), + .nr_pmrs = priv->submit.nr_pmrs, + .stream = VOID2U64(stream->buffer), + .stream_size = stream->offset * 4, /* in bytes */ + }; + + if (in_fence_fd != -1) { + req.flags |= ETNA_SUBMIT_FENCE_FD_IN | ETNA_SUBMIT_NO_IMPLICIT; + req.fence_fd = in_fence_fd; + } + + if (out_fence_fd) + req.flags |= ETNA_SUBMIT_FENCE_FD_OUT; + + ret = drmCommandWriteRead(gpu->dev->fd, DRM_ETNAVIV_GEM_SUBMIT, + &req, sizeof(req)); + + if (ret) + ERROR_MSG("submit failed: %d (%s)", ret, strerror(errno)); + else + priv->last_timestamp = req.fence; + + for (uint32_t i = 0; i < priv->nr_bos; i++) { + struct etna_bo *bo = priv->bos[i]; + + bo->current_stream = NULL; + etna_bo_del(bo); + } + + if (out_fence_fd) + *out_fence_fd = req.fence_fd; +} + +drm_public void etna_cmd_stream_flush(struct etna_cmd_stream *stream) +{ + flush(stream, -1, NULL); + reset_buffer(stream); +} + +drm_public void etna_cmd_stream_flush2(struct etna_cmd_stream *stream, + int in_fence_fd, + int *out_fence_fd) +{ + flush(stream, in_fence_fd, out_fence_fd); + reset_buffer(stream); +} + +drm_public void etna_cmd_stream_finish(struct etna_cmd_stream *stream) +{ + struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream); + + flush(stream, -1, NULL); + etna_pipe_wait(priv->pipe, priv->last_timestamp, 5000); + reset_buffer(stream); +} + +drm_public void etna_cmd_stream_reloc(struct etna_cmd_stream *stream, + const struct etna_reloc *r) +{ + struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream); + struct drm_etnaviv_gem_submit_reloc *reloc; + uint32_t idx = APPEND(&priv->submit, relocs); + uint32_t addr = 0; + + reloc = &priv->submit.relocs[idx]; + + reloc->reloc_idx = bo2idx(stream, r->bo, r->flags); + reloc->reloc_offset = r->offset; + reloc->submit_offset = stream->offset * 4; /* in bytes */ + reloc->flags = 0; + + etna_cmd_stream_emit(stream, addr); +} + +drm_public void etna_cmd_stream_perf(struct etna_cmd_stream *stream, const struct etna_perf *p) +{ + struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream); + struct drm_etnaviv_gem_submit_pmr *pmr; + uint32_t idx = APPEND(&priv->submit, pmrs); + + pmr = &priv->submit.pmrs[idx]; + + pmr->flags = p->flags; + pmr->sequence = p->sequence; + pmr->read_offset = p->offset; + pmr->read_idx = bo2idx(stream, p->bo, ETNA_SUBMIT_BO_READ | ETNA_SUBMIT_BO_WRITE); + pmr->domain = p->signal->domain->id; + pmr->signal = p->signal->signal; +} diff --git a/etnaviv/etnaviv_device.c b/etnaviv/etnaviv_device.c new file mode 100644 index 0000000..699df25 --- /dev/null +++ b/etnaviv/etnaviv_device.c @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2014 Etnaviv Project + * + * 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 (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 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. + * + * Authors: + * Christian Gmeiner + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "etnaviv_priv.h" +#include "etnaviv_drmif.h" + +static pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER; + +drm_public struct etna_device *etna_device_new(int fd) +{ + struct etna_device *dev = calloc(sizeof(*dev), 1); + + if (!dev) + return NULL; + + atomic_set(&dev->refcnt, 1); + dev->fd = fd; + dev->handle_table = drmHashCreate(); + dev->name_table = drmHashCreate(); + etna_bo_cache_init(&dev->bo_cache); + + return dev; +} + +/* like etna_device_new() but creates it's own private dup() of the fd + * which is close()d when the device is finalized. */ +drm_public struct etna_device *etna_device_new_dup(int fd) +{ + int dup_fd = dup(fd); + struct etna_device *dev = etna_device_new(dup_fd); + + if (dev) + dev->closefd = 1; + else + close(dup_fd); + + return dev; +} + +drm_public struct etna_device *etna_device_ref(struct etna_device *dev) +{ + atomic_inc(&dev->refcnt); + + return dev; +} + +static void etna_device_del_impl(struct etna_device *dev) +{ + etna_bo_cache_cleanup(&dev->bo_cache, 0); + drmHashDestroy(dev->handle_table); + drmHashDestroy(dev->name_table); + + if (dev->closefd) + close(dev->fd); + + free(dev); +} + +drm_private void etna_device_del_locked(struct etna_device *dev) +{ + if (!atomic_dec_and_test(&dev->refcnt)) + return; + + etna_device_del_impl(dev); +} + +drm_public void etna_device_del(struct etna_device *dev) +{ + if (!atomic_dec_and_test(&dev->refcnt)) + return; + + pthread_mutex_lock(&table_lock); + etna_device_del_impl(dev); + pthread_mutex_unlock(&table_lock); +} + +drm_public int etna_device_fd(struct etna_device *dev) +{ + return dev->fd; +} diff --git a/etnaviv/etnaviv_drm.h b/etnaviv/etnaviv_drm.h new file mode 100644 index 0000000..af024d9 --- /dev/null +++ b/etnaviv/etnaviv_drm.h @@ -0,0 +1,300 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (C) 2015 Etnaviv Project + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#ifndef __ETNAVIV_DRM_H__ +#define __ETNAVIV_DRM_H__ + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Please note that modifications to all structs defined here are + * subject to backwards-compatibility constraints: + * 1) Do not use pointers, use __u64 instead for 32 bit / 64 bit + * user/kernel compatibility + * 2) Keep fields aligned to their size + * 3) Because of how drm_ioctl() works, we can add new fields at + * the end of an ioctl if some care is taken: drm_ioctl() will + * zero out the new fields at the tail of the ioctl, so a zero + * value should have a backwards compatible meaning. And for + * output params, userspace won't see the newly added output + * fields.. so that has to be somehow ok. + */ + +/* timeouts are specified in clock-monotonic absolute times (to simplify + * restarting interrupted ioctls). The following struct is logically the + * same as 'struct timespec' but 32/64b ABI safe. + */ +struct drm_etnaviv_timespec { + __s64 tv_sec; /* seconds */ + __s64 tv_nsec; /* nanoseconds */ +}; + +#define ETNAVIV_PARAM_GPU_MODEL 0x01 +#define ETNAVIV_PARAM_GPU_REVISION 0x02 +#define ETNAVIV_PARAM_GPU_FEATURES_0 0x03 +#define ETNAVIV_PARAM_GPU_FEATURES_1 0x04 +#define ETNAVIV_PARAM_GPU_FEATURES_2 0x05 +#define ETNAVIV_PARAM_GPU_FEATURES_3 0x06 +#define ETNAVIV_PARAM_GPU_FEATURES_4 0x07 +#define ETNAVIV_PARAM_GPU_FEATURES_5 0x08 +#define ETNAVIV_PARAM_GPU_FEATURES_6 0x09 +#define ETNAVIV_PARAM_GPU_FEATURES_7 0x0a +#define ETNAVIV_PARAM_GPU_FEATURES_8 0x0b +#define ETNAVIV_PARAM_GPU_FEATURES_9 0x0c +#define ETNAVIV_PARAM_GPU_FEATURES_10 0x0d +#define ETNAVIV_PARAM_GPU_FEATURES_11 0x0e +#define ETNAVIV_PARAM_GPU_FEATURES_12 0x0f + +#define ETNAVIV_PARAM_GPU_STREAM_COUNT 0x10 +#define ETNAVIV_PARAM_GPU_REGISTER_MAX 0x11 +#define ETNAVIV_PARAM_GPU_THREAD_COUNT 0x12 +#define ETNAVIV_PARAM_GPU_VERTEX_CACHE_SIZE 0x13 +#define ETNAVIV_PARAM_GPU_SHADER_CORE_COUNT 0x14 +#define ETNAVIV_PARAM_GPU_PIXEL_PIPES 0x15 +#define ETNAVIV_PARAM_GPU_VERTEX_OUTPUT_BUFFER_SIZE 0x16 +#define ETNAVIV_PARAM_GPU_BUFFER_SIZE 0x17 +#define ETNAVIV_PARAM_GPU_INSTRUCTION_COUNT 0x18 +#define ETNAVIV_PARAM_GPU_NUM_CONSTANTS 0x19 +#define ETNAVIV_PARAM_GPU_NUM_VARYINGS 0x1a +#define ETNAVIV_PARAM_SOFTPIN_START_ADDR 0x1b +#define ETNAVIV_PARAM_GPU_PRODUCT_ID 0x1c +#define ETNAVIV_PARAM_GPU_CUSTOMER_ID 0x1d +#define ETNAVIV_PARAM_GPU_ECO_ID 0x1e + +#define ETNA_MAX_PIPES 4 + +struct drm_etnaviv_param { + __u32 pipe; /* in */ + __u32 param; /* in, ETNAVIV_PARAM_x */ + __u64 value; /* out (get_param) or in (set_param) */ +}; + +/* + * GEM buffers: + */ + +#define ETNA_BO_CACHE_MASK 0x000f0000 +/* cache modes */ +#define ETNA_BO_CACHED 0x00010000 +#define ETNA_BO_WC 0x00020000 +#define ETNA_BO_UNCACHED 0x00040000 +/* map flags */ +#define ETNA_BO_FORCE_MMU 0x00100000 + +struct drm_etnaviv_gem_new { + __u64 size; /* in */ + __u32 flags; /* in, mask of ETNA_BO_x */ + __u32 handle; /* out */ +}; + +struct drm_etnaviv_gem_info { + __u32 handle; /* in */ + __u32 pad; + __u64 offset; /* out, offset to pass to mmap() */ +}; + +#define ETNA_PREP_READ 0x01 +#define ETNA_PREP_WRITE 0x02 +#define ETNA_PREP_NOSYNC 0x04 + +struct drm_etnaviv_gem_cpu_prep { + __u32 handle; /* in */ + __u32 op; /* in, mask of ETNA_PREP_x */ + struct drm_etnaviv_timespec timeout; /* in */ +}; + +struct drm_etnaviv_gem_cpu_fini { + __u32 handle; /* in */ + __u32 flags; /* in, placeholder for now, no defined values */ +}; + +/* + * Cmdstream Submission: + */ + +/* The value written into the cmdstream is logically: + * relocbuf->gpuaddr + reloc_offset + * + * NOTE that reloc's must be sorted by order of increasing submit_offset, + * otherwise EINVAL. + */ +struct drm_etnaviv_gem_submit_reloc { + __u32 submit_offset; /* in, offset from submit_bo */ + __u32 reloc_idx; /* in, index of reloc_bo buffer */ + __u64 reloc_offset; /* in, offset from start of reloc_bo */ + __u32 flags; /* in, placeholder for now, no defined values */ +}; + +/* Each buffer referenced elsewhere in the cmdstream submit (ie. the + * cmdstream buffer(s) themselves or reloc entries) has one (and only + * one) entry in the submit->bos[] table. + * + * As a optimization, the current buffer (gpu virtual address) can be + * passed back through the 'presumed' field. If on a subsequent reloc, + * userspace passes back a 'presumed' address that is still valid, + * then patching the cmdstream for this entry is skipped. This can + * avoid kernel needing to map/access the cmdstream bo in the common + * case. + * If the submit is a softpin submit (ETNA_SUBMIT_SOFTPIN) the 'presumed' + * field is interpreted as the fixed location to map the bo into the gpu + * virtual address space. If the kernel is unable to map the buffer at + * this location the submit will fail. This means userspace is responsible + * for the whole gpu virtual address management. + */ +#define ETNA_SUBMIT_BO_READ 0x0001 +#define ETNA_SUBMIT_BO_WRITE 0x0002 +struct drm_etnaviv_gem_submit_bo { + __u32 flags; /* in, mask of ETNA_SUBMIT_BO_x */ + __u32 handle; /* in, GEM handle */ + __u64 presumed; /* in/out, presumed buffer address */ +}; + +/* performance monitor request (pmr) */ +#define ETNA_PM_PROCESS_PRE 0x0001 +#define ETNA_PM_PROCESS_POST 0x0002 +struct drm_etnaviv_gem_submit_pmr { + __u32 flags; /* in, when to process request (ETNA_PM_PROCESS_x) */ + __u8 domain; /* in, pm domain */ + __u8 pad; + __u16 signal; /* in, pm signal */ + __u32 sequence; /* in, sequence number */ + __u32 read_offset; /* in, offset from read_bo */ + __u32 read_idx; /* in, index of read_bo buffer */ +}; + +/* Each cmdstream submit consists of a table of buffers involved, and + * one or more cmdstream buffers. This allows for conditional execution + * (context-restore), and IB buffers needed for per tile/bin draw cmds. + */ +#define ETNA_SUBMIT_NO_IMPLICIT 0x0001 +#define ETNA_SUBMIT_FENCE_FD_IN 0x0002 +#define ETNA_SUBMIT_FENCE_FD_OUT 0x0004 +#define ETNA_SUBMIT_SOFTPIN 0x0008 +#define ETNA_SUBMIT_FLAGS (ETNA_SUBMIT_NO_IMPLICIT | \ + ETNA_SUBMIT_FENCE_FD_IN | \ + ETNA_SUBMIT_FENCE_FD_OUT| \ + ETNA_SUBMIT_SOFTPIN) +#define ETNA_PIPE_3D 0x00 +#define ETNA_PIPE_2D 0x01 +#define ETNA_PIPE_VG 0x02 +struct drm_etnaviv_gem_submit { + __u32 fence; /* out */ + __u32 pipe; /* in */ + __u32 exec_state; /* in, initial execution state (ETNA_PIPE_x) */ + __u32 nr_bos; /* in, number of submit_bo's */ + __u32 nr_relocs; /* in, number of submit_reloc's */ + __u32 stream_size; /* in, cmdstream size */ + __u64 bos; /* in, ptr to array of submit_bo's */ + __u64 relocs; /* in, ptr to array of submit_reloc's */ + __u64 stream; /* in, ptr to cmdstream */ + __u32 flags; /* in, mask of ETNA_SUBMIT_x */ + __s32 fence_fd; /* in/out, fence fd (see ETNA_SUBMIT_FENCE_FD_x) */ + __u64 pmrs; /* in, ptr to array of submit_pmr's */ + __u32 nr_pmrs; /* in, number of submit_pmr's */ + __u32 pad; +}; + +/* The normal way to synchronize with the GPU is just to CPU_PREP on + * a buffer if you need to access it from the CPU (other cmdstream + * submission from same or other contexts, PAGE_FLIP ioctl, etc, all + * handle the required synchronization under the hood). This ioctl + * mainly just exists as a way to implement the gallium pipe_fence + * APIs without requiring a dummy bo to synchronize on. + */ +#define ETNA_WAIT_NONBLOCK 0x01 +struct drm_etnaviv_wait_fence { + __u32 pipe; /* in */ + __u32 fence; /* in */ + __u32 flags; /* in, mask of ETNA_WAIT_x */ + __u32 pad; + struct drm_etnaviv_timespec timeout; /* in */ +}; + +#define ETNA_USERPTR_READ 0x01 +#define ETNA_USERPTR_WRITE 0x02 +struct drm_etnaviv_gem_userptr { + __u64 user_ptr; /* in, page aligned user pointer */ + __u64 user_size; /* in, page aligned user size */ + __u32 flags; /* in, flags */ + __u32 handle; /* out, non-zero handle */ +}; + +struct drm_etnaviv_gem_wait { + __u32 pipe; /* in */ + __u32 handle; /* in, bo to be waited for */ + __u32 flags; /* in, mask of ETNA_WAIT_x */ + __u32 pad; + struct drm_etnaviv_timespec timeout; /* in */ +}; + +/* + * Performance Monitor (PM): + */ + +struct drm_etnaviv_pm_domain { + __u32 pipe; /* in */ + __u8 iter; /* in/out, select pm domain at index iter */ + __u8 id; /* out, id of domain */ + __u16 nr_signals; /* out, how many signals does this domain provide */ + char name[64]; /* out, name of domain */ +}; + +struct drm_etnaviv_pm_signal { + __u32 pipe; /* in */ + __u8 domain; /* in, pm domain index */ + __u8 pad; + __u16 iter; /* in/out, select pm source at index iter */ + __u16 id; /* out, id of signal */ + char name[64]; /* out, name of domain */ +}; + +#define DRM_ETNAVIV_GET_PARAM 0x00 +/* placeholder: +#define DRM_ETNAVIV_SET_PARAM 0x01 + */ +#define DRM_ETNAVIV_GEM_NEW 0x02 +#define DRM_ETNAVIV_GEM_INFO 0x03 +#define DRM_ETNAVIV_GEM_CPU_PREP 0x04 +#define DRM_ETNAVIV_GEM_CPU_FINI 0x05 +#define DRM_ETNAVIV_GEM_SUBMIT 0x06 +#define DRM_ETNAVIV_WAIT_FENCE 0x07 +#define DRM_ETNAVIV_GEM_USERPTR 0x08 +#define DRM_ETNAVIV_GEM_WAIT 0x09 +#define DRM_ETNAVIV_PM_QUERY_DOM 0x0a +#define DRM_ETNAVIV_PM_QUERY_SIG 0x0b +#define DRM_ETNAVIV_NUM_IOCTLS 0x0c + +#define DRM_IOCTL_ETNAVIV_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GET_PARAM, struct drm_etnaviv_param) +#define DRM_IOCTL_ETNAVIV_GEM_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_NEW, struct drm_etnaviv_gem_new) +#define DRM_IOCTL_ETNAVIV_GEM_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_INFO, struct drm_etnaviv_gem_info) +#define DRM_IOCTL_ETNAVIV_GEM_CPU_PREP DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_CPU_PREP, struct drm_etnaviv_gem_cpu_prep) +#define DRM_IOCTL_ETNAVIV_GEM_CPU_FINI DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_CPU_FINI, struct drm_etnaviv_gem_cpu_fini) +#define DRM_IOCTL_ETNAVIV_GEM_SUBMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_SUBMIT, struct drm_etnaviv_gem_submit) +#define DRM_IOCTL_ETNAVIV_WAIT_FENCE DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_WAIT_FENCE, struct drm_etnaviv_wait_fence) +#define DRM_IOCTL_ETNAVIV_GEM_USERPTR DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_USERPTR, struct drm_etnaviv_gem_userptr) +#define DRM_IOCTL_ETNAVIV_GEM_WAIT DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_WAIT, struct drm_etnaviv_gem_wait) +#define DRM_IOCTL_ETNAVIV_PM_QUERY_DOM DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_PM_QUERY_DOM, struct drm_etnaviv_pm_domain) +#define DRM_IOCTL_ETNAVIV_PM_QUERY_SIG DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_PM_QUERY_SIG, struct drm_etnaviv_pm_signal) + +#if defined(__cplusplus) +} +#endif + +#endif /* __ETNAVIV_DRM_H__ */ diff --git a/etnaviv/etnaviv_drmif.h b/etnaviv/etnaviv_drmif.h new file mode 100644 index 0000000..80aedc1 --- /dev/null +++ b/etnaviv/etnaviv_drmif.h @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2014-2015 Etnaviv Project + * + * 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 (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 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. + * + * Authors: + * Christian Gmeiner + */ + +#ifndef ETNAVIV_DRMIF_H_ +#define ETNAVIV_DRMIF_H_ + +#include +#include + +struct etna_bo; +struct etna_pipe; +struct etna_gpu; +struct etna_device; +struct etna_cmd_stream; +struct etna_perfmon; +struct etna_perfmon_domain; +struct etna_perfmon_signal; + +enum etna_pipe_id { + ETNA_PIPE_3D = 0, + ETNA_PIPE_2D = 1, + ETNA_PIPE_VG = 2, + ETNA_PIPE_MAX +}; + +enum etna_param_id { + ETNA_GPU_MODEL = 0x1, + ETNA_GPU_REVISION = 0x2, + ETNA_GPU_FEATURES_0 = 0x3, + ETNA_GPU_FEATURES_1 = 0x4, + ETNA_GPU_FEATURES_2 = 0x5, + ETNA_GPU_FEATURES_3 = 0x6, + ETNA_GPU_FEATURES_4 = 0x7, + ETNA_GPU_FEATURES_5 = 0x8, + ETNA_GPU_FEATURES_6 = 0x9, + + ETNA_GPU_STREAM_COUNT = 0x10, + ETNA_GPU_REGISTER_MAX = 0x11, + ETNA_GPU_THREAD_COUNT = 0x12, + ETNA_GPU_VERTEX_CACHE_SIZE = 0x13, + ETNA_GPU_SHADER_CORE_COUNT = 0x14, + ETNA_GPU_PIXEL_PIPES = 0x15, + ETNA_GPU_VERTEX_OUTPUT_BUFFER_SIZE = 0x16, + ETNA_GPU_BUFFER_SIZE = 0x17, + ETNA_GPU_INSTRUCTION_COUNT = 0x18, + ETNA_GPU_NUM_CONSTANTS = 0x19, + ETNA_GPU_NUM_VARYINGS = 0x1a +}; + +/* bo flags: */ +#define DRM_ETNA_GEM_CACHE_CACHED 0x00010000 +#define DRM_ETNA_GEM_CACHE_WC 0x00020000 +#define DRM_ETNA_GEM_CACHE_UNCACHED 0x00040000 +#define DRM_ETNA_GEM_CACHE_MASK 0x000f0000 +/* map flags */ +#define DRM_ETNA_GEM_FORCE_MMU 0x00100000 + +/* bo access flags: (keep aligned to ETNA_PREP_x) */ +#define DRM_ETNA_PREP_READ 0x01 +#define DRM_ETNA_PREP_WRITE 0x02 +#define DRM_ETNA_PREP_NOSYNC 0x04 + +/* device functions: + */ + +struct etna_device *etna_device_new(int fd); +struct etna_device *etna_device_new_dup(int fd); +struct etna_device *etna_device_ref(struct etna_device *dev); +void etna_device_del(struct etna_device *dev); +int etna_device_fd(struct etna_device *dev); + +/* gpu functions: + */ + +struct etna_gpu *etna_gpu_new(struct etna_device *dev, unsigned int core); +void etna_gpu_del(struct etna_gpu *gpu); +int etna_gpu_get_param(struct etna_gpu *gpu, enum etna_param_id param, + uint64_t *value); + + +/* pipe functions: + */ + +struct etna_pipe *etna_pipe_new(struct etna_gpu *gpu, enum etna_pipe_id id); +void etna_pipe_del(struct etna_pipe *pipe); +int etna_pipe_wait(struct etna_pipe *pipe, uint32_t timestamp, uint32_t ms); +int etna_pipe_wait_ns(struct etna_pipe *pipe, uint32_t timestamp, uint64_t ns); + + +/* buffer-object functions: + */ + +struct etna_bo *etna_bo_new(struct etna_device *dev, + uint32_t size, uint32_t flags); +struct etna_bo *etna_bo_from_name(struct etna_device *dev, uint32_t name); +struct etna_bo *etna_bo_from_dmabuf(struct etna_device *dev, int fd); +struct etna_bo *etna_bo_ref(struct etna_bo *bo); +void etna_bo_del(struct etna_bo *bo); +int etna_bo_get_name(struct etna_bo *bo, uint32_t *name); +uint32_t etna_bo_handle(struct etna_bo *bo); +int etna_bo_dmabuf(struct etna_bo *bo); +uint32_t etna_bo_size(struct etna_bo *bo); +void * etna_bo_map(struct etna_bo *bo); +int etna_bo_cpu_prep(struct etna_bo *bo, uint32_t op); +void etna_bo_cpu_fini(struct etna_bo *bo); + + +/* cmd stream functions: + */ + +struct etna_cmd_stream { + uint32_t *buffer; + uint32_t offset; /* in 32-bit words */ + uint32_t size; /* in 32-bit words */ +}; + +struct etna_cmd_stream *etna_cmd_stream_new(struct etna_pipe *pipe, uint32_t size, + void (*reset_notify)(struct etna_cmd_stream *stream, void *priv), + void *priv); +void etna_cmd_stream_del(struct etna_cmd_stream *stream); +uint32_t etna_cmd_stream_timestamp(struct etna_cmd_stream *stream); +void etna_cmd_stream_flush(struct etna_cmd_stream *stream); +void etna_cmd_stream_flush2(struct etna_cmd_stream *stream, int in_fence_fd, + int *out_fence_fd); +void etna_cmd_stream_finish(struct etna_cmd_stream *stream); + +static inline uint32_t etna_cmd_stream_avail(struct etna_cmd_stream *stream) +{ + static const uint32_t END_CLEARANCE = 2; /* LINK op code */ + + return stream->size - stream->offset - END_CLEARANCE; +} + +static inline void etna_cmd_stream_reserve(struct etna_cmd_stream *stream, size_t n) +{ + if (etna_cmd_stream_avail(stream) < n) + etna_cmd_stream_flush(stream); +} + +static inline void etna_cmd_stream_emit(struct etna_cmd_stream *stream, uint32_t data) +{ + stream->buffer[stream->offset++] = data; +} + +static inline uint32_t etna_cmd_stream_get(struct etna_cmd_stream *stream, uint32_t offset) +{ + return stream->buffer[offset]; +} + +static inline void etna_cmd_stream_set(struct etna_cmd_stream *stream, uint32_t offset, + uint32_t data) +{ + stream->buffer[offset] = data; +} + +static inline uint32_t etna_cmd_stream_offset(struct etna_cmd_stream *stream) +{ + return stream->offset; +} + +struct etna_reloc { + struct etna_bo *bo; +#define ETNA_RELOC_READ 0x0001 +#define ETNA_RELOC_WRITE 0x0002 + uint32_t flags; + uint32_t offset; +}; + +void etna_cmd_stream_reloc(struct etna_cmd_stream *stream, const struct etna_reloc *r); + +/* performance monitoring functions: + */ + +struct etna_perfmon *etna_perfmon_create(struct etna_pipe *pipe); +void etna_perfmon_del(struct etna_perfmon *perfmon); +struct etna_perfmon_domain *etna_perfmon_get_dom_by_name(struct etna_perfmon *pm, const char *name); +struct etna_perfmon_signal *etna_perfmon_get_sig_by_name(struct etna_perfmon_domain *dom, const char *name); + +struct etna_perf { +#define ETNA_PM_PROCESS_PRE 0x0001 +#define ETNA_PM_PROCESS_POST 0x0002 + uint32_t flags; + uint32_t sequence; + struct etna_perfmon_signal *signal; + struct etna_bo *bo; + uint32_t offset; +}; + +void etna_cmd_stream_perf(struct etna_cmd_stream *stream, const struct etna_perf *p); + +#endif /* ETNAVIV_DRMIF_H_ */ diff --git a/etnaviv/etnaviv_gpu.c b/etnaviv/etnaviv_gpu.c new file mode 100644 index 0000000..dc4c126 --- /dev/null +++ b/etnaviv/etnaviv_gpu.c @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2015 Etnaviv Project + * + * 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 (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 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. + * + * Authors: + * Christian Gmeiner + */ + +#include "etnaviv_priv.h" +#include "etnaviv_drmif.h" + +static uint64_t get_param(struct etna_device *dev, uint32_t core, uint32_t param) +{ + struct drm_etnaviv_param req = { + .pipe = core, + .param = param, + }; + int ret; + + ret = drmCommandWriteRead(dev->fd, DRM_ETNAVIV_GET_PARAM, &req, sizeof(req)); + if (ret) { + ERROR_MSG("get-param (%x) failed! %d (%s)", param, ret, strerror(errno)); + return 0; + } + + return req.value; +} + +drm_public struct etna_gpu *etna_gpu_new(struct etna_device *dev, unsigned int core) +{ + struct etna_gpu *gpu; + + gpu = calloc(1, sizeof(*gpu)); + if (!gpu) { + ERROR_MSG("allocation failed"); + goto fail; + } + + gpu->dev = dev; + gpu->core = core; + + gpu->model = get_param(dev, core, ETNAVIV_PARAM_GPU_MODEL); + gpu->revision = get_param(dev, core, ETNAVIV_PARAM_GPU_REVISION); + + if (!gpu->model) + goto fail; + + INFO_MSG(" GPU model: 0x%x (rev %x)", gpu->model, gpu->revision); + + return gpu; +fail: + if (gpu) + etna_gpu_del(gpu); + + return NULL; +} + +drm_public void etna_gpu_del(struct etna_gpu *gpu) +{ + free(gpu); +} + +drm_public int etna_gpu_get_param(struct etna_gpu *gpu, enum etna_param_id param, + uint64_t *value) +{ + struct etna_device *dev = gpu->dev; + unsigned int core = gpu->core; + + switch(param) { + case ETNA_GPU_MODEL: + *value = gpu->model; + return 0; + case ETNA_GPU_REVISION: + *value = gpu->revision; + return 0; + case ETNA_GPU_FEATURES_0: + *value = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_0); + return 0; + case ETNA_GPU_FEATURES_1: + *value = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_1); + return 0; + case ETNA_GPU_FEATURES_2: + *value = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_2); + return 0; + case ETNA_GPU_FEATURES_3: + *value = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_3); + return 0; + case ETNA_GPU_FEATURES_4: + *value = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_4); + return 0; + case ETNA_GPU_FEATURES_5: + *value = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_5); + return 0; + case ETNA_GPU_FEATURES_6: + *value = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_6); + return 0; + case ETNA_GPU_STREAM_COUNT: + *value = get_param(dev, core, ETNA_GPU_STREAM_COUNT); + return 0; + case ETNA_GPU_REGISTER_MAX: + *value = get_param(dev, core, ETNA_GPU_REGISTER_MAX); + return 0; + case ETNA_GPU_THREAD_COUNT: + *value = get_param(dev, core, ETNA_GPU_THREAD_COUNT); + return 0; + case ETNA_GPU_VERTEX_CACHE_SIZE: + *value = get_param(dev, core, ETNA_GPU_VERTEX_CACHE_SIZE); + return 0; + case ETNA_GPU_SHADER_CORE_COUNT: + *value = get_param(dev, core, ETNA_GPU_SHADER_CORE_COUNT); + return 0; + case ETNA_GPU_PIXEL_PIPES: + *value = get_param(dev, core, ETNA_GPU_PIXEL_PIPES); + return 0; + case ETNA_GPU_VERTEX_OUTPUT_BUFFER_SIZE: + *value = get_param(dev, core, ETNA_GPU_VERTEX_OUTPUT_BUFFER_SIZE); + return 0; + case ETNA_GPU_BUFFER_SIZE: + *value = get_param(dev, core, ETNA_GPU_BUFFER_SIZE); + return 0; + case ETNA_GPU_INSTRUCTION_COUNT: + *value = get_param(dev, core, ETNA_GPU_INSTRUCTION_COUNT); + return 0; + case ETNA_GPU_NUM_CONSTANTS: + *value = get_param(dev, core, ETNA_GPU_NUM_CONSTANTS); + return 0; + case ETNA_GPU_NUM_VARYINGS: + *value = get_param(dev, core, ETNA_GPU_NUM_VARYINGS); + return 0; + + default: + ERROR_MSG("invalid param id: %d", param); + return -1; + } + + return 0; +} diff --git a/etnaviv/etnaviv_perfmon.c b/etnaviv/etnaviv_perfmon.c new file mode 100644 index 0000000..f6576b8 --- /dev/null +++ b/etnaviv/etnaviv_perfmon.c @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2017 Etnaviv Project + * Copyright (C) 2017 Zodiac Inflight Innovations + * + * 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 (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 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. + * + * Authors: + * Christian Gmeiner + */ + +#include "etnaviv_priv.h" + +static int etna_perfmon_query_signals(struct etna_perfmon *pm, struct etna_perfmon_domain *dom) +{ + struct etna_device *dev = pm->pipe->gpu->dev; + struct drm_etnaviv_pm_signal req = { + .pipe = pm->pipe->id, + .domain = dom->id + }; + + do { + struct etna_perfmon_signal *sig; + int ret; + + ret = drmCommandWriteRead(dev->fd, DRM_ETNAVIV_PM_QUERY_SIG, &req, sizeof(req)); + if (ret) + break; + + sig = calloc(1, sizeof(*sig)); + if (!sig) + return -ENOMEM; + + INFO_MSG("perfmon signal:"); + INFO_MSG("id = %d", req.id); + INFO_MSG("name = %s", req.name); + + sig->domain = dom; + sig->signal = req.id; + strncpy(sig->name, req.name, sizeof(sig->name)); + list_addtail(&sig->head, &dom->signals); + } while (req.iter != 0xffff); + + return 0; +} + +static int etna_perfmon_query_domains(struct etna_perfmon *pm) +{ + struct etna_device *dev = pm->pipe->gpu->dev; + struct drm_etnaviv_pm_domain req = { + .pipe = pm->pipe->id + }; + + do { + struct etna_perfmon_domain *dom; + int ret; + + ret = drmCommandWriteRead(dev->fd, DRM_ETNAVIV_PM_QUERY_DOM, &req, sizeof(req)); + if (ret) + break; + + dom = calloc(1, sizeof(*dom)); + if (!dom) + return -ENOMEM; + + list_inithead(&dom->signals); + dom->id = req.id; + strncpy(dom->name, req.name, sizeof(dom->name)); + list_addtail(&dom->head, &pm->domains); + + INFO_MSG("perfmon domain:"); + INFO_MSG("id = %d", req.id); + INFO_MSG("name = %s", req.name); + INFO_MSG("nr_signals = %d", req.nr_signals); + + /* Query all available signals for this domain. */ + if (req.nr_signals > 0) { + ret = etna_perfmon_query_signals(pm, dom); + if (ret) + return ret; + } + } while (req.iter != 0xff); + + return 0; +} + +static void etna_perfmon_free_signals(struct etna_perfmon_domain *dom) +{ + struct etna_perfmon_signal *sig, *next; + + LIST_FOR_EACH_ENTRY_SAFE(sig, next, &dom->signals, head) { + list_del(&sig->head); + free(sig); + } +} + +static void etna_perfmon_free_domains(struct etna_perfmon *pm) +{ + struct etna_perfmon_domain *dom, *next; + + LIST_FOR_EACH_ENTRY_SAFE(dom, next, &pm->domains, head) { + etna_perfmon_free_signals(dom); + list_del(&dom->head); + free(dom); + } +} + +drm_public struct etna_perfmon *etna_perfmon_create(struct etna_pipe *pipe) +{ + struct etna_perfmon *pm; + int ret; + + pm = calloc(1, sizeof(*pm)); + if (!pm) { + ERROR_MSG("allocation failed"); + return NULL; + } + + list_inithead(&pm->domains); + pm->pipe = pipe; + + /* query all available domains and sources for this device */ + ret = etna_perfmon_query_domains(pm); + if (ret) + goto fail; + + return pm; + +fail: + etna_perfmon_del(pm); + return NULL; +} + +drm_public void etna_perfmon_del(struct etna_perfmon *pm) +{ + if (!pm) + return; + + etna_perfmon_free_domains(pm); + free(pm); +} + +drm_public struct etna_perfmon_domain *etna_perfmon_get_dom_by_name(struct etna_perfmon *pm, const char *name) +{ + struct etna_perfmon_domain *dom; + + if (pm) { + LIST_FOR_EACH_ENTRY(dom, &pm->domains, head) { + if (!strcmp(dom->name, name)) + return dom; + } + } + + return NULL; +} + +drm_public struct etna_perfmon_signal *etna_perfmon_get_sig_by_name(struct etna_perfmon_domain *dom, const char *name) +{ + struct etna_perfmon_signal *signal; + + if (dom) { + LIST_FOR_EACH_ENTRY(signal, &dom->signals, head) { + if (!strcmp(signal->name, name)) + return signal; + } + } + + return NULL; +} diff --git a/etnaviv/etnaviv_pipe.c b/etnaviv/etnaviv_pipe.c new file mode 100644 index 0000000..4120a36 --- /dev/null +++ b/etnaviv/etnaviv_pipe.c @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2014-2015 Etnaviv Project + * + * 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 (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 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. + * + * Authors: + * Christian Gmeiner + */ + +#include "etnaviv_priv.h" + +drm_public int etna_pipe_wait(struct etna_pipe *pipe, uint32_t timestamp, uint32_t ms) +{ + return etna_pipe_wait_ns(pipe, timestamp, ms * 1000000); +} + +drm_public int etna_pipe_wait_ns(struct etna_pipe *pipe, uint32_t timestamp, uint64_t ns) +{ + struct etna_device *dev = pipe->gpu->dev; + int ret; + + struct drm_etnaviv_wait_fence req = { + .pipe = pipe->gpu->core, + .fence = timestamp, + }; + + if (ns == 0) + req.flags |= ETNA_WAIT_NONBLOCK; + + get_abs_timeout(&req.timeout, ns); + + ret = drmCommandWrite(dev->fd, DRM_ETNAVIV_WAIT_FENCE, &req, sizeof(req)); + if (ret) { + ERROR_MSG("wait-fence failed! %d (%s)", ret, strerror(errno)); + return ret; + } + + return 0; +} + +drm_public void etna_pipe_del(struct etna_pipe *pipe) +{ + free(pipe); +} + +drm_public struct etna_pipe *etna_pipe_new(struct etna_gpu *gpu, enum etna_pipe_id id) +{ + struct etna_pipe *pipe; + + pipe = calloc(1, sizeof(*pipe)); + if (!pipe) { + ERROR_MSG("allocation failed"); + goto fail; + } + + pipe->id = id; + pipe->gpu = gpu; + + return pipe; +fail: + return NULL; +} diff --git a/etnaviv/etnaviv_priv.h b/etnaviv/etnaviv_priv.h new file mode 100644 index 0000000..eef7f49 --- /dev/null +++ b/etnaviv/etnaviv_priv.h @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2014-2015 Etnaviv Project + * + * 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 (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 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. + * + * Authors: + * Christian Gmeiner + */ + +#ifndef ETNAVIV_PRIV_H_ +#define ETNAVIV_PRIV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libdrm_macros.h" +#include "xf86drm.h" +#include "xf86atomic.h" + +#include "util_double_list.h" + +#include "etnaviv_drmif.h" +#include "etnaviv_drm.h" + +struct etna_bo_bucket { + uint32_t size; + struct list_head list; +}; + +struct etna_bo_cache { + struct etna_bo_bucket cache_bucket[14 * 4]; + unsigned num_buckets; + time_t time; +}; + +struct etna_device { + int fd; + atomic_t refcnt; + + /* tables to keep track of bo's, to avoid "evil-twin" etna_bo objects: + * + * handle_table: maps handle to etna_bo + * name_table: maps flink name to etna_bo + * + * We end up needing two tables, because DRM_IOCTL_GEM_OPEN always + * returns a new handle. So we need to figure out if the bo is already + * open in the process first, before calling gem-open. + */ + void *handle_table, *name_table; + + struct etna_bo_cache bo_cache; + + int closefd; /* call close(fd) upon destruction */ +}; + +drm_private void etna_bo_cache_init(struct etna_bo_cache *cache); +drm_private void etna_bo_cache_cleanup(struct etna_bo_cache *cache, time_t time); +drm_private struct etna_bo *etna_bo_cache_alloc(struct etna_bo_cache *cache, + uint32_t *size, uint32_t flags); +drm_private int etna_bo_cache_free(struct etna_bo_cache *cache, struct etna_bo *bo); + +/* for where @table_lock is already held: */ +drm_private void etna_device_del_locked(struct etna_device *dev); + +/* a GEM buffer object allocated from the DRM device */ +struct etna_bo { + struct etna_device *dev; + void *map; /* userspace mmap'ing (if there is one) */ + uint32_t size; + uint32_t handle; + uint32_t flags; + uint32_t name; /* flink global handle (DRI2 name) */ + uint64_t offset; /* offset to mmap() */ + atomic_t refcnt; + + /* in the common case, a bo won't be referenced by more than a single + * command stream. So to avoid looping over all the bo's in the + * reloc table to find the idx of a bo that might already be in the + * table, we cache the idx in the bo. But in order to detect the + * slow-path where bo is ref'd in multiple streams, we also must track + * the current_stream for which the idx is valid. See bo2idx(). + */ + struct etna_cmd_stream *current_stream; + uint32_t idx; + + int reuse; + struct list_head list; /* bucket-list entry */ + time_t free_time; /* time when added to bucket-list */ +}; + +struct etna_gpu { + struct etna_device *dev; + uint32_t core; + uint32_t model; + uint32_t revision; +}; + +struct etna_pipe { + enum etna_pipe_id id; + struct etna_gpu *gpu; +}; + +struct etna_cmd_stream_priv { + struct etna_cmd_stream base; + struct etna_pipe *pipe; + + uint32_t last_timestamp; + + /* submit ioctl related tables: */ + struct { + /* bo's table: */ + struct drm_etnaviv_gem_submit_bo *bos; + uint32_t nr_bos, max_bos; + + /* reloc's table: */ + struct drm_etnaviv_gem_submit_reloc *relocs; + uint32_t nr_relocs, max_relocs; + + /* perf's table: */ + struct drm_etnaviv_gem_submit_pmr *pmrs; + uint32_t nr_pmrs, max_pmrs; + } submit; + + /* should have matching entries in submit.bos: */ + struct etna_bo **bos; + uint32_t nr_bos, max_bos; + + /* notify callback if buffer reset happened */ + void (*reset_notify)(struct etna_cmd_stream *stream, void *priv); + void *reset_notify_priv; +}; + +struct etna_perfmon { + struct list_head domains; + struct etna_pipe *pipe; +}; + +struct etna_perfmon_domain +{ + struct list_head head; + struct list_head signals; + uint8_t id; + char name[64]; +}; + +struct etna_perfmon_signal +{ + struct list_head head; + struct etna_perfmon_domain *domain; + uint8_t signal; + char name[64]; +}; + +#define ALIGN(v,a) (((v) + (a) - 1) & ~((a) - 1)) +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +#define enable_debug 1 /* TODO make dynamic */ + +#define INFO_MSG(fmt, ...) \ + do { drmMsg("[I] "fmt " (%s:%d)\n", \ + ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) +#define DEBUG_MSG(fmt, ...) \ + do if (enable_debug) { drmMsg("[D] "fmt " (%s:%d)\n", \ + ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) +#define WARN_MSG(fmt, ...) \ + do { drmMsg("[W] "fmt " (%s:%d)\n", \ + ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) +#define ERROR_MSG(fmt, ...) \ + do { drmMsg("[E] " fmt " (%s:%d)\n", \ + ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) + +#define VOID2U64(x) ((uint64_t)(unsigned long)(x)) + +static inline void get_abs_timeout(struct drm_etnaviv_timespec *tv, uint64_t ns) +{ + struct timespec t; + uint32_t s = ns / 1000000000; + clock_gettime(CLOCK_MONOTONIC, &t); + tv->tv_sec = t.tv_sec + s; + tv->tv_nsec = t.tv_nsec + ns - (s * 1000000000); +} + +#endif /* ETNAVIV_PRIV_H_ */ diff --git a/etnaviv/libdrm_etnaviv.pc.in b/etnaviv/libdrm_etnaviv.pc.in new file mode 100644 index 0000000..13fed01 --- /dev/null +++ b/etnaviv/libdrm_etnaviv.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libdrm_etnaviv +Description: Userspace interface to etnaviv kernel DRM services +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -ldrm_etnaviv +Cflags: -I${includedir} -I${includedir}/libdrm +Requires.private: libdrm diff --git a/etnaviv/meson.build b/etnaviv/meson.build new file mode 100644 index 0000000..591f20f --- /dev/null +++ b/etnaviv/meson.build @@ -0,0 +1,66 @@ +# Copyright © 2017-2018 Intel Corporation + +# 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. + + +libdrm_etnaviv = library( + 'drm_etnaviv', + [ + files( + 'etnaviv_device.c', 'etnaviv_gpu.c', 'etnaviv_bo.c', 'etnaviv_bo_cache.c', + 'etnaviv_perfmon.c', 'etnaviv_pipe.c', 'etnaviv_cmd_stream.c', + ), + config_file + ], + include_directories : [inc_root, inc_drm], + link_with : libdrm, + c_args : libdrm_c_args, + gnu_symbol_visibility : 'hidden', + dependencies : [dep_pthread_stubs, dep_rt, dep_atomic_ops], + version : '1.0.0', + install : true, +) + +install_headers('etnaviv_drmif.h', subdir : 'libdrm') + +pkg.generate( + libdrm_etnaviv, + name : 'libdrm_etnaviv', + subdirs : ['.', 'libdrm'], + description : 'Userspace interface to Tegra kernel DRM services', +) + +ext_libdrm_etnaviv = declare_dependency( + link_with : [libdrm, libdrm_etnaviv], + include_directories : [inc_drm, include_directories('.')], +) + +if meson.version().version_compare('>= 0.54.0') + meson.override_dependency('libdrm_etnaviv', ext_libdrm_etnaviv) +endif + +test( + 'etnaviv-symbols-check', + symbols_check, + args : [ + '--lib', libdrm_etnaviv, + '--symbols-file', files('etnaviv-symbols.txt'), + '--nm', prog_nm.path(), + ], +) diff --git a/exynos/exynos-symbols.txt b/exynos/exynos-symbols.txt new file mode 100644 index 0000000..c674841 --- /dev/null +++ b/exynos/exynos-symbols.txt @@ -0,0 +1,23 @@ +exynos_bo_create +exynos_bo_destroy +exynos_bo_from_name +exynos_bo_get_info +exynos_bo_get_name +exynos_bo_handle +exynos_bo_map +exynos_device_create +exynos_device_destroy +exynos_prime_fd_to_handle +exynos_prime_handle_to_fd +exynos_vidi_connection +exynos_handle_event +g2d_blend +g2d_copy +g2d_copy_with_scale +g2d_exec +g2d_config_event +g2d_fini +g2d_init +g2d_move +g2d_scale_and_blend +g2d_solid_fill diff --git a/exynos/exynos_drm.c b/exynos/exynos_drm.c new file mode 100644 index 0000000..3e322a1 --- /dev/null +++ b/exynos/exynos_drm.c @@ -0,0 +1,444 @@ +/* + * Copyright (C) 2012 Samsung Electronics 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 (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 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. + * + * Authors: + * Inki Dae + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "libdrm_macros.h" +#include "exynos_drm.h" +#include "exynos_drmif.h" + +#define U642VOID(x) ((void *)(unsigned long)(x)) + +/* + * Create exynos drm device object. + * + * @fd: file descriptor to exynos drm driver opened. + * + * if true, return the device object else NULL. + */ +drm_public struct exynos_device * exynos_device_create(int fd) +{ + struct exynos_device *dev; + + dev = calloc(sizeof(*dev), 1); + if (!dev) { + fprintf(stderr, "failed to create device[%s].\n", + strerror(errno)); + return NULL; + } + + dev->fd = fd; + + return dev; +} + +/* + * Destroy exynos drm device object + * + * @dev: exynos drm device object. + */ +drm_public void exynos_device_destroy(struct exynos_device *dev) +{ + free(dev); +} + +/* + * Create a exynos buffer object to exynos drm device. + * + * @dev: exynos drm device object. + * @size: user-desired size. + * flags: user-desired memory type. + * user can set one or more types among several types to memory + * allocation and cache attribute types. and as default, + * EXYNOS_BO_NONCONTIG and EXYNOS-BO_NONCACHABLE types would + * be used. + * + * if true, return a exynos buffer object else NULL. + */ +drm_public struct exynos_bo * exynos_bo_create(struct exynos_device *dev, + size_t size, uint32_t flags) +{ + struct exynos_bo *bo; + struct drm_exynos_gem_create req = { + .size = size, + .flags = flags, + }; + + if (size == 0) { + fprintf(stderr, "invalid size.\n"); + goto fail; + } + + bo = calloc(sizeof(*bo), 1); + if (!bo) { + fprintf(stderr, "failed to create bo[%s].\n", + strerror(errno)); + goto err_free_bo; + } + + bo->dev = dev; + + if (drmIoctl(dev->fd, DRM_IOCTL_EXYNOS_GEM_CREATE, &req)){ + fprintf(stderr, "failed to create gem object[%s].\n", + strerror(errno)); + goto err_free_bo; + } + + bo->handle = req.handle; + bo->size = size; + bo->flags = flags; + + return bo; + +err_free_bo: + free(bo); +fail: + return NULL; +} + +/* + * Get information to gem region allocated. + * + * @dev: exynos drm device object. + * @handle: gem handle to request gem info. + * @size: size to gem object and returned by kernel side. + * @flags: gem flags to gem object and returned by kernel side. + * + * with this function call, you can get flags and size to gem handle + * through bo object. + * + * if true, return 0 else negative. + */ +drm_public int exynos_bo_get_info(struct exynos_device *dev, uint32_t handle, + size_t *size, uint32_t *flags) +{ + int ret; + struct drm_exynos_gem_info req = { + .handle = handle, + }; + + ret = drmIoctl(dev->fd, DRM_IOCTL_EXYNOS_GEM_GET, &req); + if (ret < 0) { + fprintf(stderr, "failed to get gem object information[%s].\n", + strerror(errno)); + return ret; + } + + *size = req.size; + *flags = req.flags; + + return 0; +} + +/* + * Destroy a exynos buffer object. + * + * @bo: a exynos buffer object to be destroyed. + */ +drm_public void exynos_bo_destroy(struct exynos_bo *bo) +{ + if (!bo) + return; + + if (bo->vaddr) + munmap(bo->vaddr, bo->size); + + if (bo->handle) { + drmCloseBufferHandle(bo->dev->fd, bo->handle); + } + + free(bo); +} + + +/* + * Get a exynos buffer object from a gem global object name. + * + * @dev: a exynos device object. + * @name: a gem global object name exported by another process. + * + * this interface is used to get a exynos buffer object from a gem + * global object name sent by another process for buffer sharing. + * + * if true, return a exynos buffer object else NULL. + * + */ +drm_public struct exynos_bo * +exynos_bo_from_name(struct exynos_device *dev, uint32_t name) +{ + struct exynos_bo *bo; + struct drm_gem_open req = { + .name = name, + }; + + bo = calloc(sizeof(*bo), 1); + if (!bo) { + fprintf(stderr, "failed to allocate bo[%s].\n", + strerror(errno)); + return NULL; + } + + if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) { + fprintf(stderr, "failed to open gem object[%s].\n", + strerror(errno)); + goto err_free_bo; + } + + bo->dev = dev; + bo->name = name; + bo->handle = req.handle; + + return bo; + +err_free_bo: + free(bo); + return NULL; +} + +/* + * Get a gem global object name from a gem object handle. + * + * @bo: a exynos buffer object including gem handle. + * @name: a gem global object name to be got by kernel driver. + * + * this interface is used to get a gem global object name from a gem object + * handle to a buffer that wants to share it with another process. + * + * if true, return 0 else negative. + */ +drm_public int exynos_bo_get_name(struct exynos_bo *bo, uint32_t *name) +{ + if (!bo->name) { + struct drm_gem_flink req = { + .handle = bo->handle, + }; + int ret; + + ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req); + if (ret) { + fprintf(stderr, "failed to get gem global name[%s].\n", + strerror(errno)); + return ret; + } + + bo->name = req.name; + } + + *name = bo->name; + + return 0; +} + +drm_public uint32_t exynos_bo_handle(struct exynos_bo *bo) +{ + return bo->handle; +} + +/* + * Mmap a buffer to user space. + * + * @bo: a exynos buffer object including a gem object handle to be mmapped + * to user space. + * + * if true, user pointer mmapped else NULL. + */ +drm_public void *exynos_bo_map(struct exynos_bo *bo) +{ + if (!bo->vaddr) { + struct exynos_device *dev = bo->dev; + struct drm_mode_map_dumb arg; + void *map = NULL; + int ret; + + memset(&arg, 0, sizeof(arg)); + arg.handle = bo->handle; + + ret = drmIoctl(dev->fd, DRM_IOCTL_MODE_MAP_DUMB, &arg); + if (ret) { + fprintf(stderr, "failed to map dumb buffer[%s].\n", + strerror(errno)); + return NULL; + } + + map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, + dev->fd, arg.offset); + + if (map != MAP_FAILED) + bo->vaddr = map; + } + + return bo->vaddr; +} + +/* + * Export gem object to dmabuf as file descriptor. + * + * @dev: exynos device object + * @handle: gem handle to export as file descriptor of dmabuf + * @fd: file descriptor returned from kernel + * + * @return: 0 on success, -1 on error, and errno will be set + */ +drm_public int +exynos_prime_handle_to_fd(struct exynos_device *dev, uint32_t handle, int *fd) +{ + return drmPrimeHandleToFD(dev->fd, handle, 0, fd); +} + +/* + * Import file descriptor into gem handle. + * + * @dev: exynos device object + * @fd: file descriptor of dmabuf to import + * @handle: gem handle returned from kernel + * + * @return: 0 on success, -1 on error, and errno will be set + */ +drm_public int +exynos_prime_fd_to_handle(struct exynos_device *dev, int fd, uint32_t *handle) +{ + return drmPrimeFDToHandle(dev->fd, fd, handle); +} + + + +/* + * Request Wireless Display connection or disconnection. + * + * @dev: a exynos device object. + * @connect: indicate whether connectoin or disconnection request. + * @ext: indicate whether edid data includes extensions data or not. + * @edid: a pointer to edid data from Wireless Display device. + * + * this interface is used to request Virtual Display driver connection or + * disconnection. for this, user should get a edid data from the Wireless + * Display device and then send that data to kernel driver with connection + * request + * + * if true, return 0 else negative. + */ +drm_public int +exynos_vidi_connection(struct exynos_device *dev, uint32_t connect, + uint32_t ext, void *edid) +{ + struct drm_exynos_vidi_connection req = { + .connection = connect, + .extensions = ext, + .edid = (uint64_t)(uintptr_t)edid, + }; + int ret; + + ret = drmIoctl(dev->fd, DRM_IOCTL_EXYNOS_VIDI_CONNECTION, &req); + if (ret) { + fprintf(stderr, "failed to request vidi connection[%s].\n", + strerror(errno)); + return ret; + } + + return 0; +} + +static void +exynos_handle_vendor(int fd, struct drm_event *e, void *ctx) +{ + struct drm_exynos_g2d_event *g2d; + struct exynos_event_context *ectx = ctx; + + switch (e->type) { + case DRM_EXYNOS_G2D_EVENT: + if (ectx->version < 1 || ectx->g2d_event_handler == NULL) + break; + g2d = (struct drm_exynos_g2d_event *)e; + ectx->g2d_event_handler(fd, g2d->cmdlist_no, g2d->tv_sec, + g2d->tv_usec, U642VOID(g2d->user_data)); + break; + + default: + break; + } +} + +drm_public int +exynos_handle_event(struct exynos_device *dev, struct exynos_event_context *ctx) +{ + char buffer[1024]; + int len, i; + struct drm_event *e; + struct drm_event_vblank *vblank; + drmEventContextPtr evctx = &ctx->base; + + /* The DRM read semantics guarantees that we always get only + * complete events. */ + len = read(dev->fd, buffer, sizeof buffer); + if (len == 0) + return 0; + if (len < (int)sizeof *e) + return -1; + + i = 0; + while (i < len) { + e = (struct drm_event *)(buffer + i); + switch (e->type) { + case DRM_EVENT_VBLANK: + if (evctx->version < 1 || + evctx->vblank_handler == NULL) + break; + vblank = (struct drm_event_vblank *) e; + evctx->vblank_handler(dev->fd, + vblank->sequence, + vblank->tv_sec, + vblank->tv_usec, + U642VOID (vblank->user_data)); + break; + case DRM_EVENT_FLIP_COMPLETE: + if (evctx->version < 2 || + evctx->page_flip_handler == NULL) + break; + vblank = (struct drm_event_vblank *) e; + evctx->page_flip_handler(dev->fd, + vblank->sequence, + vblank->tv_sec, + vblank->tv_usec, + U642VOID (vblank->user_data)); + break; + default: + exynos_handle_vendor(dev->fd, e, evctx); + break; + } + i += e->length; + } + + return 0; +} diff --git a/exynos/exynos_drm.h b/exynos/exynos_drm.h new file mode 100644 index 0000000..50181c4 --- /dev/null +++ b/exynos/exynos_drm.h @@ -0,0 +1,172 @@ +/* exynos_drm.h + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * Authors: + * Inki Dae + * Joonyoung Shim + * Seung-Woo Kim + * + * 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS 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 _EXYNOS_DRM_H_ +#define _EXYNOS_DRM_H_ + +#include "drm.h" + +/** + * User-desired buffer creation information structure. + * + * @size: user-desired memory allocation size. + * - this size value would be page-aligned internally. + * @flags: user request for setting memory type or cache attributes. + * @handle: returned a handle to created gem object. + * - this handle will be set by gem module of kernel side. + */ +struct drm_exynos_gem_create { + uint64_t size; + unsigned int flags; + unsigned int handle; +}; + +/** + * A structure to gem information. + * + * @handle: a handle to gem object created. + * @flags: flag value including memory type and cache attribute and + * this value would be set by driver. + * @size: size to memory region allocated by gem and this size would + * be set by driver. + */ +struct drm_exynos_gem_info { + unsigned int handle; + unsigned int flags; + uint64_t size; +}; + +/** + * A structure for user connection request of virtual display. + * + * @connection: indicate whether doing connection or not by user. + * @extensions: if this value is 1 then the vidi driver would need additional + * 128bytes edid data. + * @edid: the edid data pointer from user side. + */ +struct drm_exynos_vidi_connection { + unsigned int connection; + unsigned int extensions; + uint64_t edid; +}; + +/* memory type definitions. */ +enum e_drm_exynos_gem_mem_type { + /* Physically Continuous memory and used as default. */ + EXYNOS_BO_CONTIG = 0 << 0, + /* Physically Non-Continuous memory. */ + EXYNOS_BO_NONCONTIG = 1 << 0, + /* non-cachable mapping and used as default. */ + EXYNOS_BO_NONCACHABLE = 0 << 1, + /* cachable mapping. */ + EXYNOS_BO_CACHABLE = 1 << 1, + /* write-combine mapping. */ + EXYNOS_BO_WC = 1 << 2, + EXYNOS_BO_MASK = EXYNOS_BO_NONCONTIG | EXYNOS_BO_CACHABLE | + EXYNOS_BO_WC +}; + +struct drm_exynos_g2d_get_ver { + __u32 major; + __u32 minor; +}; + +struct drm_exynos_g2d_cmd { + __u32 offset; + __u32 data; +}; + +enum drm_exynos_g2d_buf_type { + G2D_BUF_USERPTR = 1 << 31, +}; + +enum drm_exynos_g2d_event_type { + G2D_EVENT_NOT, + G2D_EVENT_NONSTOP, + G2D_EVENT_STOP, /* not yet */ +}; + +struct drm_exynos_g2d_userptr { + unsigned long userptr; + unsigned long size; +}; + +struct drm_exynos_g2d_set_cmdlist { + __u64 cmd; + __u64 cmd_buf; + __u32 cmd_nr; + __u32 cmd_buf_nr; + + /* for g2d event */ + __u64 event_type; + __u64 user_data; +}; + +struct drm_exynos_g2d_exec { + __u64 async; +}; + +#define DRM_EXYNOS_GEM_CREATE 0x00 +/* Reserved 0x04 ~ 0x05 for exynos specific gem ioctl */ +#define DRM_EXYNOS_GEM_GET 0x04 +#define DRM_EXYNOS_VIDI_CONNECTION 0x07 + +/* G2D */ +#define DRM_EXYNOS_G2D_GET_VER 0x20 +#define DRM_EXYNOS_G2D_SET_CMDLIST 0x21 +#define DRM_EXYNOS_G2D_EXEC 0x22 + +#define DRM_IOCTL_EXYNOS_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create) + +#define DRM_IOCTL_EXYNOS_GEM_GET DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_GEM_GET, struct drm_exynos_gem_info) + +#define DRM_IOCTL_EXYNOS_VIDI_CONNECTION DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_VIDI_CONNECTION, struct drm_exynos_vidi_connection) + +#define DRM_IOCTL_EXYNOS_G2D_GET_VER DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_G2D_GET_VER, struct drm_exynos_g2d_get_ver) +#define DRM_IOCTL_EXYNOS_G2D_SET_CMDLIST DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_G2D_SET_CMDLIST, struct drm_exynos_g2d_set_cmdlist) +#define DRM_IOCTL_EXYNOS_G2D_EXEC DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_G2D_EXEC, struct drm_exynos_g2d_exec) + +/* EXYNOS specific events */ +#define DRM_EXYNOS_G2D_EVENT 0x80000000 + +struct drm_exynos_g2d_event { + struct drm_event base; + __u64 user_data; + __u32 tv_sec; + __u32 tv_usec; + __u32 cmdlist_no; + __u32 reserved; +}; + +#endif diff --git a/exynos/exynos_drmif.h b/exynos/exynos_drmif.h new file mode 100644 index 0000000..bcf8595 --- /dev/null +++ b/exynos/exynos_drmif.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2012 Samsung Electronics 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 (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 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. + * + * Authors: + * Inki Dae + */ + +#ifndef EXYNOS_DRMIF_H_ +#define EXYNOS_DRMIF_H_ + +#include +#include +#include "exynos_drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +struct exynos_device { + int fd; +}; + +/* + * Exynos Buffer Object structure. + * + * @dev: exynos device object allocated. + * @handle: a gem handle to gem object created. + * @flags: indicate memory allocation and cache attribute types. + * @size: size to the buffer created. + * @vaddr: user space address to a gem buffer mmapped. + * @name: a gem global handle from flink request. + */ +struct exynos_bo { + struct exynos_device *dev; + uint32_t handle; + uint32_t flags; + size_t size; + void *vaddr; + uint32_t name; +}; + +#define EXYNOS_EVENT_CONTEXT_VERSION 1 + +/* + * Exynos Event Context structure. + * + * @base: base context (for core events). + * @version: version info similar to the one in 'drmEventContext'. + * @g2d_event_handler: handler for G2D events. + */ +struct exynos_event_context { + drmEventContext base; + + int version; + + void (*g2d_event_handler)(int fd, unsigned int cmdlist_no, + unsigned int tv_sec, unsigned int tv_usec, + void *user_data); +}; + +/* + * device related functions: + */ +struct exynos_device * exynos_device_create(int fd); +void exynos_device_destroy(struct exynos_device *dev); + +/* + * buffer-object related functions: + */ +struct exynos_bo * exynos_bo_create(struct exynos_device *dev, + size_t size, uint32_t flags); +int exynos_bo_get_info(struct exynos_device *dev, uint32_t handle, + size_t *size, uint32_t *flags); +void exynos_bo_destroy(struct exynos_bo *bo); +struct exynos_bo * exynos_bo_from_name(struct exynos_device *dev, uint32_t name); +int exynos_bo_get_name(struct exynos_bo *bo, uint32_t *name); +uint32_t exynos_bo_handle(struct exynos_bo *bo); +void * exynos_bo_map(struct exynos_bo *bo); +int exynos_prime_handle_to_fd(struct exynos_device *dev, uint32_t handle, + int *fd); +int exynos_prime_fd_to_handle(struct exynos_device *dev, int fd, + uint32_t *handle); + +/* + * Virtual Display related functions: + */ +int exynos_vidi_connection(struct exynos_device *dev, uint32_t connect, + uint32_t ext, void *edid); + +/* + * event handling related functions: + */ +int exynos_handle_event(struct exynos_device *dev, + struct exynos_event_context *ctx); + + +#if defined(__cplusplus) +} +#endif + +#endif /* EXYNOS_DRMIF_H_ */ diff --git a/exynos/exynos_fimg2d.c b/exynos/exynos_fimg2d.c new file mode 100644 index 0000000..ac6fa68 --- /dev/null +++ b/exynos/exynos_fimg2d.c @@ -0,0 +1,1010 @@ +/* + * Copyright (C) 2013 Samsung Electronics Co.Ltd + * Authors: + * Inki Dae + * + * 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS 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. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "libdrm_macros.h" +#include "exynos_drm.h" +#include "fimg2d_reg.h" +#include "exynos_fimg2d.h" + +#define SET_BF(val, sc, si, scsa, scda, dc, di, dcsa, dcda) \ + val.data.src_coeff = sc; \ + val.data.inv_src_color_coeff = si; \ + val.data.src_coeff_src_a = scsa; \ + val.data.src_coeff_dst_a = scda; \ + val.data.dst_coeff = dc; \ + val.data.inv_dst_color_coeff = di; \ + val.data.dst_coeff_src_a = dcsa; \ + val.data.dst_coeff_dst_a = dcda; + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +#define MSG_PREFIX "exynos/fimg2d: " + +#define G2D_MAX_CMD_NR 64 +#define G2D_MAX_GEM_CMD_NR 64 +#define G2D_MAX_CMD_LIST_NR 64 + +struct g2d_context { + int fd; + unsigned int major; + unsigned int minor; + struct drm_exynos_g2d_cmd cmd[G2D_MAX_CMD_NR]; + struct drm_exynos_g2d_cmd cmd_buf[G2D_MAX_GEM_CMD_NR]; + unsigned int cmd_nr; + unsigned int cmd_buf_nr; + unsigned int cmdlist_nr; + void *event_userdata; +}; + +enum g2d_base_addr_reg { + g2d_dst = 0, + g2d_src +}; + +enum e_g2d_dir_mode { + G2D_DIR_MODE_POSITIVE = 0, + G2D_DIR_MODE_NEGATIVE = 1 +}; + +union g2d_direction_val { + unsigned int val[2]; + struct { + /* SRC_MSK_DIRECT_REG [0:1] (source) */ + enum e_g2d_dir_mode src_x_direction:1; + enum e_g2d_dir_mode src_y_direction:1; + + /* SRC_MSK_DIRECT_REG [2:3] */ + unsigned int reversed1:2; + + /* SRC_MSK_DIRECT_REG [4:5] (mask) */ + enum e_g2d_dir_mode mask_x_direction:1; + enum e_g2d_dir_mode mask_y_direction:1; + + /* SRC_MSK_DIRECT_REG [6:31] */ + unsigned int padding1:26; + + /* DST_PAT_DIRECT_REG [0:1] (destination) */ + enum e_g2d_dir_mode dst_x_direction:1; + enum e_g2d_dir_mode dst_y_direction:1; + + /* DST_PAT_DIRECT_REG [2:3] */ + unsigned int reversed2:2; + + /* DST_PAT_DIRECT_REG [4:5] (pattern) */ + enum e_g2d_dir_mode pat_x_direction:1; + enum e_g2d_dir_mode pat_y_direction:1; + + /* DST_PAT_DIRECT_REG [6:31] */ + unsigned int padding2:26; + } data; +}; + +static unsigned int g2d_get_scaling(unsigned int src, unsigned int dst) +{ + /* + * The G2D hw scaling factor is a normalized inverse of the scaling factor. + * For example: When source width is 100 and destination width is 200 + * (scaling of 2x), then the hw factor is NC * 100 / 200. + * The normalization factor (NC) is 2^16 = 0x10000. + */ + + return ((src << 16) / dst); +} + +static unsigned int g2d_get_blend_op(enum e_g2d_op op) +{ + union g2d_blend_func_val val; + + val.val = 0; + + /* + * The switch statement is missing the default branch since + * we assume that the caller checks the blending operation + * via g2d_validate_blending_op() first. + */ + switch (op) { + case G2D_OP_CLEAR: + case G2D_OP_DISJOINT_CLEAR: + case G2D_OP_CONJOINT_CLEAR: + SET_BF(val, G2D_COEFF_MODE_ZERO, 0, 0, 0, G2D_COEFF_MODE_ZERO, + 0, 0, 0); + break; + case G2D_OP_SRC: + case G2D_OP_DISJOINT_SRC: + case G2D_OP_CONJOINT_SRC: + SET_BF(val, G2D_COEFF_MODE_ONE, 0, 0, 0, G2D_COEFF_MODE_ZERO, + 0, 0, 0); + break; + case G2D_OP_DST: + case G2D_OP_DISJOINT_DST: + case G2D_OP_CONJOINT_DST: + SET_BF(val, G2D_COEFF_MODE_ZERO, 0, 0, 0, G2D_COEFF_MODE_ONE, + 0, 0, 0); + break; + case G2D_OP_OVER: + SET_BF(val, G2D_COEFF_MODE_ONE, 0, 0, 0, + G2D_COEFF_MODE_SRC_ALPHA, 1, 0, 0); + break; + case G2D_OP_INTERPOLATE: + SET_BF(val, G2D_COEFF_MODE_SRC_ALPHA, 0, 0, 0, + G2D_COEFF_MODE_SRC_ALPHA, 1, 0, 0); + break; + } + + return val.val; +} + +/* + * g2d_check_space - check if command buffers have enough space left. + * + * @ctx: a pointer to g2d_context structure. + * @num_cmds: number of (regular) commands. + * @num_gem_cmds: number of GEM commands. + */ +static unsigned int g2d_check_space(const struct g2d_context *ctx, + unsigned int num_cmds, unsigned int num_gem_cmds) +{ + if (ctx->cmd_nr + num_cmds >= G2D_MAX_CMD_NR || + ctx->cmd_buf_nr + num_gem_cmds >= G2D_MAX_GEM_CMD_NR) + return 1; + else + return 0; +} + +/* + * g2d_validate_select_mode - validate select mode. + * + * @mode: the mode to validate + * + * Returns zero for an invalid mode and one otherwise. + */ +static int g2d_validate_select_mode( + enum e_g2d_select_mode mode) +{ + switch (mode) { + case G2D_SELECT_MODE_NORMAL: + case G2D_SELECT_MODE_FGCOLOR: + case G2D_SELECT_MODE_BGCOLOR: + return 1; + } + + return 0; +} + +/* + * g2d_validate_blending_op - validate blending operation. + * + * @operation: the operation to validate + * + * Returns zero for an invalid mode and one otherwise. + */ +static int g2d_validate_blending_op( + enum e_g2d_op operation) +{ + switch (operation) { + case G2D_OP_CLEAR: + case G2D_OP_SRC: + case G2D_OP_DST: + case G2D_OP_OVER: + case G2D_OP_INTERPOLATE: + case G2D_OP_DISJOINT_CLEAR: + case G2D_OP_DISJOINT_SRC: + case G2D_OP_DISJOINT_DST: + case G2D_OP_CONJOINT_CLEAR: + case G2D_OP_CONJOINT_SRC: + case G2D_OP_CONJOINT_DST: + return 1; + } + + return 0; +} + +/* + * g2d_add_cmd - set given command and value to user side command buffer. + * + * @ctx: a pointer to g2d_context structure. + * @cmd: command data. + * @value: value data. + * + * The caller has to make sure that the commands buffers have enough space + * left to hold the command. Use g2d_check_space() to ensure this. + */ +static void g2d_add_cmd(struct g2d_context *ctx, unsigned long cmd, + unsigned long value) +{ + switch (cmd & ~(G2D_BUF_USERPTR)) { + case SRC_BASE_ADDR_REG: + case SRC_PLANE2_BASE_ADDR_REG: + case DST_BASE_ADDR_REG: + case DST_PLANE2_BASE_ADDR_REG: + case PAT_BASE_ADDR_REG: + case MASK_BASE_ADDR_REG: + assert(ctx->cmd_buf_nr < G2D_MAX_GEM_CMD_NR); + + ctx->cmd_buf[ctx->cmd_buf_nr].offset = cmd; + ctx->cmd_buf[ctx->cmd_buf_nr].data = value; + ctx->cmd_buf_nr++; + break; + default: + assert(ctx->cmd_nr < G2D_MAX_CMD_NR); + + ctx->cmd[ctx->cmd_nr].offset = cmd; + ctx->cmd[ctx->cmd_nr].data = value; + ctx->cmd_nr++; + break; + } +} + +/* + * g2d_add_base_addr - helper function to set dst/src base address register. + * + * @ctx: a pointer to g2d_context structure. + * @img: a pointer to the dst/src g2d_image structure. + * @reg: the register that should be set. + */ +static void g2d_add_base_addr(struct g2d_context *ctx, struct g2d_image *img, + enum g2d_base_addr_reg reg) +{ + const unsigned long cmd = (reg == g2d_dst) ? + DST_BASE_ADDR_REG : SRC_BASE_ADDR_REG; + + if (img->buf_type == G2D_IMGBUF_USERPTR) + g2d_add_cmd(ctx, cmd | G2D_BUF_USERPTR, + (unsigned long)&img->user_ptr[0]); + else + g2d_add_cmd(ctx, cmd, img->bo[0]); +} + +/* + * g2d_set_direction - setup direction register (useful for overlapping blits). + * + * @ctx: a pointer to g2d_context structure. + * @dir: a pointer to the g2d_direction_val structure. + */ +static void g2d_set_direction(struct g2d_context *ctx, + const union g2d_direction_val *dir) +{ + g2d_add_cmd(ctx, SRC_MASK_DIRECT_REG, dir->val[0]); + g2d_add_cmd(ctx, DST_PAT_DIRECT_REG, dir->val[1]); +} + +/* + * g2d_flush - submit all commands and values in user side command buffer + * to command queue aware of fimg2d dma. + * + * @ctx: a pointer to g2d_context structure. + * + * This function should be called after all commands and values to user + * side command buffer are set. It submits that buffer to the kernel side driver. + */ +static int g2d_flush(struct g2d_context *ctx) +{ + int ret; + struct drm_exynos_g2d_set_cmdlist cmdlist = {0}; + + if (ctx->cmd_nr == 0 && ctx->cmd_buf_nr == 0) + return 0; + + if (ctx->cmdlist_nr >= G2D_MAX_CMD_LIST_NR) { + fprintf(stderr, MSG_PREFIX "command list overflow.\n"); + return -EINVAL; + } + + cmdlist.cmd = (uint64_t)(uintptr_t)&ctx->cmd[0]; + cmdlist.cmd_buf = (uint64_t)(uintptr_t)&ctx->cmd_buf[0]; + cmdlist.cmd_nr = ctx->cmd_nr; + cmdlist.cmd_buf_nr = ctx->cmd_buf_nr; + + if (ctx->event_userdata) { + cmdlist.event_type = G2D_EVENT_NONSTOP; + cmdlist.user_data = (uint64_t)(uintptr_t)(ctx->event_userdata); + ctx->event_userdata = NULL; + } else { + cmdlist.event_type = G2D_EVENT_NOT; + cmdlist.user_data = 0; + } + + ctx->cmd_nr = 0; + ctx->cmd_buf_nr = 0; + + ret = drmIoctl(ctx->fd, DRM_IOCTL_EXYNOS_G2D_SET_CMDLIST, &cmdlist); + if (ret < 0) { + fprintf(stderr, MSG_PREFIX "failed to set cmdlist.\n"); + return ret; + } + + ctx->cmdlist_nr++; + + return ret; +} + +/** + * g2d_init - create a new g2d context and get hardware version. + * + * fd: a file descriptor to an opened drm device. + */ +drm_public struct g2d_context *g2d_init(int fd) +{ + struct drm_exynos_g2d_get_ver ver; + struct g2d_context *ctx; + int ret; + + ctx = calloc(1, sizeof(*ctx)); + if (!ctx) { + fprintf(stderr, MSG_PREFIX "failed to allocate context.\n"); + return NULL; + } + + ctx->fd = fd; + + ret = drmIoctl(fd, DRM_IOCTL_EXYNOS_G2D_GET_VER, &ver); + if (ret < 0) { + fprintf(stderr, MSG_PREFIX "failed to get version.\n"); + free(ctx); + return NULL; + } + + ctx->major = ver.major; + ctx->minor = ver.minor; + + printf(MSG_PREFIX "G2D version (%d.%d).\n", ctx->major, ctx->minor); + return ctx; +} + +drm_public void g2d_fini(struct g2d_context *ctx) +{ + free(ctx); +} + +/** + * g2d_config_event - setup userdata configuration for a g2d event. + * The next invocation of a g2d call (e.g. g2d_solid_fill) is + * then going to flag the command buffer as 'nonstop'. + * Completion of the command buffer execution can then be + * determined by using drmHandleEvent on the DRM fd. + * The userdata is 'consumed' in the process. + * + * @ctx: a pointer to g2d_context structure. + * @userdata: a pointer to the user data + */ +drm_public void g2d_config_event(struct g2d_context *ctx, void *userdata) +{ + ctx->event_userdata = userdata; +} + +/** + * g2d_exec - start the dma to process all commands summited by g2d_flush(). + * + * @ctx: a pointer to g2d_context structure. + */ +drm_public int g2d_exec(struct g2d_context *ctx) +{ + struct drm_exynos_g2d_exec exec; + int ret; + + if (ctx->cmdlist_nr == 0) + return -EINVAL; + + exec.async = 0; + + ret = drmIoctl(ctx->fd, DRM_IOCTL_EXYNOS_G2D_EXEC, &exec); + if (ret < 0) { + fprintf(stderr, MSG_PREFIX "failed to execute.\n"); + return ret; + } + + ctx->cmdlist_nr = 0; + + return ret; +} + +/** + * g2d_solid_fill - fill given buffer with given color data. + * + * @ctx: a pointer to g2d_context structure. + * @img: a pointer to g2d_image structure including image and buffer + * information. + * @x: x start position to buffer filled with given color data. + * @y: y start position to buffer filled with given color data. + * @w: width value to buffer filled with given color data. + * @h: height value to buffer filled with given color data. + */ +drm_public int +g2d_solid_fill(struct g2d_context *ctx, struct g2d_image *img, + unsigned int x, unsigned int y, unsigned int w, + unsigned int h) +{ + union g2d_bitblt_cmd_val bitblt; + union g2d_point_val pt; + + if (g2d_check_space(ctx, 7, 1)) + return -ENOSPC; + + g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_NORMAL); + g2d_add_cmd(ctx, DST_COLOR_MODE_REG, img->color_mode); + g2d_add_base_addr(ctx, img, g2d_dst); + g2d_add_cmd(ctx, DST_STRIDE_REG, img->stride); + + if (x + w > img->width) + w = img->width - x; + if (y + h > img->height) + h = img->height - y; + + pt.data.x = x; + pt.data.y = y; + g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); + + pt.data.x = x + w; + pt.data.y = y + h; + g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); + + g2d_add_cmd(ctx, SF_COLOR_REG, img->color); + + bitblt.val = 0; + bitblt.data.fast_solid_color_fill_en = 1; + g2d_add_cmd(ctx, BITBLT_COMMAND_REG, bitblt.val); + + return g2d_flush(ctx); +} + +/** + * g2d_copy - copy contents in source buffer to destination buffer. + * + * @ctx: a pointer to g2d_context structure. + * @src: a pointer to g2d_image structure including image and buffer + * information to source. + * @dst: a pointer to g2d_image structure including image and buffer + * information to destination. + * @src_x: x start position to source buffer. + * @src_y: y start position to source buffer. + * @dst_x: x start position to destination buffer. + * @dst_y: y start position to destination buffer. + * @w: width value to source and destination buffers. + * @h: height value to source and destination buffers. + */ +drm_public int +g2d_copy(struct g2d_context *ctx, struct g2d_image *src, + struct g2d_image *dst, unsigned int src_x, unsigned int src_y, + unsigned int dst_x, unsigned dst_y, unsigned int w, + unsigned int h) +{ + union g2d_rop4_val rop4; + union g2d_point_val pt; + unsigned int src_w, src_h, dst_w, dst_h; + + src_w = w; + src_h = h; + if (src_x + src->width > w) + src_w = src->width - src_x; + if (src_y + src->height > h) + src_h = src->height - src_y; + + dst_w = w; + dst_h = w; + if (dst_x + dst->width > w) + dst_w = dst->width - dst_x; + if (dst_y + dst->height > h) + dst_h = dst->height - dst_y; + + w = MIN(src_w, dst_w); + h = MIN(src_h, dst_h); + + if (w <= 0 || h <= 0) { + fprintf(stderr, MSG_PREFIX "invalid width or height.\n"); + return -EINVAL; + } + + if (g2d_check_space(ctx, 11, 2)) + return -ENOSPC; + + g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); + g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode); + g2d_add_base_addr(ctx, dst, g2d_dst); + g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride); + + g2d_add_cmd(ctx, SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL); + g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode); + g2d_add_base_addr(ctx, src, g2d_src); + g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride); + + pt.data.x = src_x; + pt.data.y = src_y; + g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val); + pt.data.x = src_x + w; + pt.data.y = src_y + h; + g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val); + + pt.data.x = dst_x; + pt.data.y = dst_y; + g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); + pt.data.x = dst_x + w; + pt.data.y = dst_y + h; + g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); + + rop4.val = 0; + rop4.data.unmasked_rop3 = G2D_ROP3_SRC; + g2d_add_cmd(ctx, ROP4_REG, rop4.val); + + return g2d_flush(ctx); +} + +/** + * g2d_move - copy content inside single buffer. + * Similar to libc's memmove() this copies a rectangular + * region of the provided buffer to another location, while + * properly handling the situation where source and + * destination rectangle overlap. + * + * @ctx: a pointer to g2d_context structure. + * @img: a pointer to g2d_image structure providing + * buffer information. + * @src_x: x position of source rectangle. + * @src_y: y position of source rectangle. + * @dst_x: x position of destination rectangle. + * @dst_y: y position of destination rectangle. + * @w: width of rectangle to move. + * @h: height of rectangle to move. + */ +drm_public int +g2d_move(struct g2d_context *ctx, struct g2d_image *img, + unsigned int src_x, unsigned int src_y, + unsigned int dst_x, unsigned dst_y, unsigned int w, + unsigned int h) +{ + union g2d_rop4_val rop4; + union g2d_point_val pt; + union g2d_direction_val dir; + unsigned int src_w, src_h, dst_w, dst_h; + + src_w = w; + src_h = h; + if (src_x + img->width > w) + src_w = img->width - src_x; + if (src_y + img->height > h) + src_h = img->height - src_y; + + dst_w = w; + dst_h = w; + if (dst_x + img->width > w) + dst_w = img->width - dst_x; + if (dst_y + img->height > h) + dst_h = img->height - dst_y; + + w = MIN(src_w, dst_w); + h = MIN(src_h, dst_h); + + if (w == 0 || h == 0) { + fprintf(stderr, MSG_PREFIX "invalid width or height.\n"); + return -EINVAL; + } + + if (g2d_check_space(ctx, 13, 2)) + return -ENOSPC; + + g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); + g2d_add_cmd(ctx, SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL); + + g2d_add_cmd(ctx, DST_COLOR_MODE_REG, img->color_mode); + g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, img->color_mode); + + g2d_add_base_addr(ctx, img, g2d_dst); + g2d_add_base_addr(ctx, img, g2d_src); + + g2d_add_cmd(ctx, DST_STRIDE_REG, img->stride); + g2d_add_cmd(ctx, SRC_STRIDE_REG, img->stride); + + dir.val[0] = dir.val[1] = 0; + + if (dst_x >= src_x) + dir.data.src_x_direction = dir.data.dst_x_direction = 1; + if (dst_y >= src_y) + dir.data.src_y_direction = dir.data.dst_y_direction = 1; + + g2d_set_direction(ctx, &dir); + + pt.data.x = src_x; + pt.data.y = src_y; + g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val); + pt.data.x = src_x + w; + pt.data.y = src_y + h; + g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val); + + pt.data.x = dst_x; + pt.data.y = dst_y; + g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); + pt.data.x = dst_x + w; + pt.data.y = dst_y + h; + g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); + + rop4.val = 0; + rop4.data.unmasked_rop3 = G2D_ROP3_SRC; + g2d_add_cmd(ctx, ROP4_REG, rop4.val); + + return g2d_flush(ctx); +} + +/** + * g2d_copy_with_scale - copy contents in source buffer to destination buffer + * scaling up or down properly. + * + * @ctx: a pointer to g2d_context structure. + * @src: a pointer to g2d_image structure including image and buffer + * information to source. + * @dst: a pointer to g2d_image structure including image and buffer + * information to destination. + * @src_x: x start position to source buffer. + * @src_y: y start position to source buffer. + * @src_w: width value to source buffer. + * @src_h: height value to source buffer. + * @dst_x: x start position to destination buffer. + * @dst_y: y start position to destination buffer. + * @dst_w: width value to destination buffer. + * @dst_h: height value to destination buffer. + * @negative: indicate that it uses color negative to source and + * destination buffers. + */ +drm_public int +g2d_copy_with_scale(struct g2d_context *ctx, struct g2d_image *src, + struct g2d_image *dst, unsigned int src_x, + unsigned int src_y, unsigned int src_w, + unsigned int src_h, unsigned int dst_x, + unsigned int dst_y, unsigned int dst_w, + unsigned int dst_h, unsigned int negative) +{ + union g2d_rop4_val rop4; + union g2d_point_val pt; + unsigned int scale, repeat_pad; + unsigned int scale_x, scale_y; + + /* Sanitize this parameter to facilitate space computation below. */ + if (negative) + negative = 1; + + if (src_w == dst_w && src_h == dst_h) + scale = 0; + else { + scale = 1; + scale_x = g2d_get_scaling(src_w, dst_w); + scale_y = g2d_get_scaling(src_h, dst_h); + } + + repeat_pad = src->repeat_mode == G2D_REPEAT_MODE_PAD ? 1 : 0; + + if (src_x + src_w > src->width) + src_w = src->width - src_x; + if (src_y + src_h > src->height) + src_h = src->height - src_y; + + if (dst_x + dst_w > dst->width) + dst_w = dst->width - dst_x; + if (dst_y + dst_h > dst->height) + dst_h = dst->height - dst_y; + + if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0) { + fprintf(stderr, MSG_PREFIX "invalid width or height.\n"); + return -EINVAL; + } + + if (g2d_check_space(ctx, 12 + scale * 3 + negative + repeat_pad, 2)) + return -ENOSPC; + + g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); + g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode); + g2d_add_base_addr(ctx, dst, g2d_dst); + g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride); + + g2d_add_cmd(ctx, SRC_SELECT_REG, G2D_SELECT_MODE_NORMAL); + g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode); + + g2d_add_cmd(ctx, SRC_REPEAT_MODE_REG, src->repeat_mode); + if (repeat_pad) + g2d_add_cmd(ctx, SRC_PAD_VALUE_REG, dst->color); + + g2d_add_base_addr(ctx, src, g2d_src); + g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride); + + rop4.val = 0; + rop4.data.unmasked_rop3 = G2D_ROP3_SRC; + + if (negative) { + g2d_add_cmd(ctx, BG_COLOR_REG, 0x00FFFFFF); + rop4.data.unmasked_rop3 ^= G2D_ROP3_DST; + } + + g2d_add_cmd(ctx, ROP4_REG, rop4.val); + + if (scale) { + g2d_add_cmd(ctx, SRC_SCALE_CTRL_REG, G2D_SCALE_MODE_BILINEAR); + g2d_add_cmd(ctx, SRC_XSCALE_REG, scale_x); + g2d_add_cmd(ctx, SRC_YSCALE_REG, scale_y); + } + + pt.data.x = src_x; + pt.data.y = src_y; + g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val); + pt.data.x = src_x + src_w; + pt.data.y = src_y + src_h; + g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val); + + pt.data.x = dst_x; + pt.data.y = dst_y; + g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); + pt.data.x = dst_x + dst_w; + pt.data.y = dst_y + dst_h; + g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); + + return g2d_flush(ctx); +} + +/** + * g2d_blend - blend image data in source and destination buffers. + * + * @ctx: a pointer to g2d_context structure. + * @src: a pointer to g2d_image structure including image and buffer + * information to source. + * @dst: a pointer to g2d_image structure including image and buffer + * information to destination. + * @src_x: x start position to source buffer. + * @src_y: y start position to source buffer. + * @dst_x: x start position to destination buffer. + * @dst_y: y start position to destination buffer. + * @w: width value to source and destination buffer. + * @h: height value to source and destination buffer. + * @op: blend operation type. + */ +drm_public int +g2d_blend(struct g2d_context *ctx, struct g2d_image *src, + struct g2d_image *dst, unsigned int src_x, + unsigned int src_y, unsigned int dst_x, unsigned int dst_y, + unsigned int w, unsigned int h, enum e_g2d_op op) +{ + union g2d_point_val pt; + union g2d_bitblt_cmd_val bitblt; + union g2d_blend_func_val blend; + unsigned int gem_space; + unsigned int src_w, src_h, dst_w, dst_h; + + src_w = w; + src_h = h; + if (src_x + w > src->width) + src_w = src->width - src_x; + if (src_y + h > src->height) + src_h = src->height - src_y; + + dst_w = w; + dst_h = h; + if (dst_x + w > dst->width) + dst_w = dst->width - dst_x; + if (dst_y + h > dst->height) + dst_h = dst->height - dst_y; + + w = MIN(src_w, dst_w); + h = MIN(src_h, dst_h); + + if (w <= 0 || h <= 0) { + fprintf(stderr, MSG_PREFIX "invalid width or height.\n"); + return -EINVAL; + } + + if (!g2d_validate_select_mode(src->select_mode)) { + fprintf(stderr , MSG_PREFIX "invalid select mode for source.\n"); + return -EINVAL; + } + + if (!g2d_validate_blending_op(op)) { + fprintf(stderr , MSG_PREFIX "unsupported blending operation.\n"); + return -EINVAL; + } + + gem_space = src->select_mode == G2D_SELECT_MODE_NORMAL ? 2 : 1; + + if (g2d_check_space(ctx, 12, gem_space)) + return -ENOSPC; + + bitblt.val = 0; + blend.val = 0; + + if (op == G2D_OP_SRC || op == G2D_OP_CLEAR) + g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); + else + g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_NORMAL); + + g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode); + g2d_add_base_addr(ctx, dst, g2d_dst); + g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride); + + g2d_add_cmd(ctx, SRC_SELECT_REG, src->select_mode); + g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode); + + switch (src->select_mode) { + case G2D_SELECT_MODE_NORMAL: + g2d_add_base_addr(ctx, src, g2d_src); + g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride); + break; + case G2D_SELECT_MODE_FGCOLOR: + g2d_add_cmd(ctx, FG_COLOR_REG, src->color); + break; + case G2D_SELECT_MODE_BGCOLOR: + g2d_add_cmd(ctx, BG_COLOR_REG, src->color); + break; + } + + bitblt.data.alpha_blend_mode = G2D_ALPHA_BLEND_MODE_ENABLE; + blend.val = g2d_get_blend_op(op); + g2d_add_cmd(ctx, BITBLT_COMMAND_REG, bitblt.val); + g2d_add_cmd(ctx, BLEND_FUNCTION_REG, blend.val); + + pt.data.x = src_x; + pt.data.y = src_y; + g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val); + pt.data.x = src_x + w; + pt.data.y = src_y + h; + g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val); + + pt.data.x = dst_x; + pt.data.y = dst_y; + g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); + pt.data.x = dst_x + w; + pt.data.y = dst_y + h; + g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); + + return g2d_flush(ctx); +} + +/** + * g2d_scale_and_blend - apply scaling to source buffer and then blend to destination buffer + * + * @ctx: a pointer to g2d_context structure. + * @src: a pointer to g2d_image structure including image and buffer + * information to source. + * @dst: a pointer to g2d_image structure including image and buffer + * information to destination. + * @src_x: x start position to source buffer. + * @src_y: y start position to source buffer. + * @src_w: width value to source buffer. + * @src_h: height value to source buffer. + * @dst_x: x start position to destination buffer. + * @dst_y: y start position to destination buffer. + * @dst_w: width value to destination buffer. + * @dst_h: height value to destination buffer. + * @op: blend operation type. + */ +drm_public int +g2d_scale_and_blend(struct g2d_context *ctx, struct g2d_image *src, + struct g2d_image *dst, unsigned int src_x, unsigned int src_y, + unsigned int src_w, unsigned int src_h, unsigned int dst_x, + unsigned int dst_y, unsigned int dst_w, unsigned int dst_h, + enum e_g2d_op op) +{ + union g2d_point_val pt; + union g2d_bitblt_cmd_val bitblt; + union g2d_blend_func_val blend; + unsigned int scale, gem_space; + unsigned int scale_x, scale_y; + + if (src_w == dst_w && src_h == dst_h) + scale = 0; + else { + scale = 1; + scale_x = g2d_get_scaling(src_w, dst_w); + scale_y = g2d_get_scaling(src_h, dst_h); + } + + if (src_x + src_w > src->width) + src_w = src->width - src_x; + if (src_y + src_h > src->height) + src_h = src->height - src_y; + + if (dst_x + dst_w > dst->width) + dst_w = dst->width - dst_x; + if (dst_y + dst_h > dst->height) + dst_h = dst->height - dst_y; + + if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0) { + fprintf(stderr, MSG_PREFIX "invalid width or height.\n"); + return -EINVAL; + } + + if (!g2d_validate_select_mode(src->select_mode)) { + fprintf(stderr , MSG_PREFIX "invalid select mode for source.\n"); + return -EINVAL; + } + + if (!g2d_validate_blending_op(op)) { + fprintf(stderr , MSG_PREFIX "unsupported blending operation.\n"); + return -EINVAL; + } + + gem_space = src->select_mode == G2D_SELECT_MODE_NORMAL ? 2 : 1; + + if (g2d_check_space(ctx, 12 + scale * 3, gem_space)) + return -ENOSPC; + + bitblt.val = 0; + blend.val = 0; + + if (op == G2D_OP_SRC || op == G2D_OP_CLEAR) + g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_BGCOLOR); + else + g2d_add_cmd(ctx, DST_SELECT_REG, G2D_SELECT_MODE_NORMAL); + + g2d_add_cmd(ctx, DST_COLOR_MODE_REG, dst->color_mode); + g2d_add_base_addr(ctx, dst, g2d_dst); + g2d_add_cmd(ctx, DST_STRIDE_REG, dst->stride); + + g2d_add_cmd(ctx, SRC_SELECT_REG, src->select_mode); + g2d_add_cmd(ctx, SRC_COLOR_MODE_REG, src->color_mode); + + switch (src->select_mode) { + case G2D_SELECT_MODE_NORMAL: + g2d_add_base_addr(ctx, src, g2d_src); + g2d_add_cmd(ctx, SRC_STRIDE_REG, src->stride); + break; + case G2D_SELECT_MODE_FGCOLOR: + g2d_add_cmd(ctx, FG_COLOR_REG, src->color); + break; + case G2D_SELECT_MODE_BGCOLOR: + g2d_add_cmd(ctx, BG_COLOR_REG, src->color); + break; + } + + if (scale) { + g2d_add_cmd(ctx, SRC_SCALE_CTRL_REG, G2D_SCALE_MODE_BILINEAR); + g2d_add_cmd(ctx, SRC_XSCALE_REG, scale_x); + g2d_add_cmd(ctx, SRC_YSCALE_REG, scale_y); + } + + bitblt.data.alpha_blend_mode = G2D_ALPHA_BLEND_MODE_ENABLE; + blend.val = g2d_get_blend_op(op); + g2d_add_cmd(ctx, BITBLT_COMMAND_REG, bitblt.val); + g2d_add_cmd(ctx, BLEND_FUNCTION_REG, blend.val); + + pt.data.x = src_x; + pt.data.y = src_y; + g2d_add_cmd(ctx, SRC_LEFT_TOP_REG, pt.val); + pt.data.x = src_x + src_w; + pt.data.y = src_y + src_h; + g2d_add_cmd(ctx, SRC_RIGHT_BOTTOM_REG, pt.val); + + pt.data.x = dst_x; + pt.data.y = dst_y; + g2d_add_cmd(ctx, DST_LEFT_TOP_REG, pt.val); + pt.data.x = dst_x + dst_w; + pt.data.y = dst_y + dst_h; + g2d_add_cmd(ctx, DST_RIGHT_BOTTOM_REG, pt.val); + + return g2d_flush(ctx); +} diff --git a/exynos/exynos_fimg2d.h b/exynos/exynos_fimg2d.h new file mode 100644 index 0000000..a4dfbe7 --- /dev/null +++ b/exynos/exynos_fimg2d.h @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2013 Samsung Electronics Co.Ltd + * Authors: + * Inki Dae + * + * 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS 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 _FIMG2D_H_ +#define _FIMG2D_H_ + +#define G2D_PLANE_MAX_NR 2 + +enum e_g2d_color_mode { + /* COLOR FORMAT */ + G2D_COLOR_FMT_XRGB8888, + G2D_COLOR_FMT_ARGB8888, + G2D_COLOR_FMT_RGB565, + G2D_COLOR_FMT_XRGB1555, + G2D_COLOR_FMT_ARGB1555, + G2D_COLOR_FMT_XRGB4444, + G2D_COLOR_FMT_ARGB4444, + G2D_COLOR_FMT_PRGB888, + G2D_COLOR_FMT_YCbCr444, + G2D_COLOR_FMT_YCbCr422, + G2D_COLOR_FMT_YCbCr420, + /* alpha 8bit */ + G2D_COLOR_FMT_A8, + /* Luminance 8bit: gray color */ + G2D_COLOR_FMT_L8, + /* alpha 1bit */ + G2D_COLOR_FMT_A1, + /* alpha 4bit */ + G2D_COLOR_FMT_A4, + G2D_COLOR_FMT_MASK, /* VER4.1 */ + + /* COLOR ORDER */ + G2D_ORDER_AXRGB = (0 << 4), /* VER4.1 */ + G2D_ORDER_RGBAX = (1 << 4), /* VER4.1 */ + G2D_ORDER_AXBGR = (2 << 4), /* VER4.1 */ + G2D_ORDER_BGRAX = (3 << 4), /* VER4.1 */ + G2D_ORDER_MASK = (3 << 4), /* VER4.1 */ + + /* Number of YCbCr plane */ + G2D_YCbCr_1PLANE = (0 << 8), /* VER4.1 */ + G2D_YCbCr_2PLANE = (1 << 8), /* VER4.1 */ + G2D_YCbCr_PLANE_MASK = (3 << 8), /* VER4.1 */ + + /* Order in YCbCr */ + G2D_YCbCr_ORDER_CrY1CbY0 = (0 << 12), /* VER4.1 */ + G2D_YCbCr_ORDER_CbY1CrY0 = (1 << 12), /* VER4.1 */ + G2D_YCbCr_ORDER_Y1CrY0Cb = (2 << 12), /* VER4.1 */ + G2D_YCbCr_ORDER_Y1CbY0Cr = (3 << 12), /* VER4.1 */ + G2D_YCbCr_ORDER_CrCb = G2D_YCbCr_ORDER_CrY1CbY0, /* VER4.1 */ + G2D_YCbCr_ORDER_CbCr = G2D_YCbCr_ORDER_CbY1CrY0, /* VER4.1 */ + G2D_YCbCr_ORDER_MASK = (3 < 12), /* VER4.1 */ + + /* CSC */ + G2D_CSC_601 = (0 << 16), /* VER4.1 */ + G2D_CSC_709 = (1 << 16), /* VER4.1 */ + G2D_CSC_MASK = (1 << 16), /* VER4.1 */ + + /* Valid value range of YCbCr */ + G2D_YCbCr_RANGE_NARROW = (0 << 17), /* VER4.1 */ + G2D_YCbCr_RANGE_WIDE = (1 << 17), /* VER4.1 */ + G2D_YCbCr_RANGE_MASK = (1 << 17), /* VER4.1 */ + + G2D_COLOR_MODE_MASK = 0xFFFFFFFF, +}; + +enum e_g2d_select_mode { + G2D_SELECT_MODE_NORMAL = (0 << 0), + G2D_SELECT_MODE_FGCOLOR = (1 << 0), + G2D_SELECT_MODE_BGCOLOR = (2 << 0), +}; + +enum e_g2d_repeat_mode { + G2D_REPEAT_MODE_REPEAT, + G2D_REPEAT_MODE_PAD, + G2D_REPEAT_MODE_REFLECT, + G2D_REPEAT_MODE_CLAMP, + G2D_REPEAT_MODE_NONE, +}; + +enum e_g2d_scale_mode { + G2D_SCALE_MODE_NONE = 0, + G2D_SCALE_MODE_NEAREST, + G2D_SCALE_MODE_BILINEAR, + G2D_SCALE_MODE_MAX, +}; + +enum e_g2d_buf_type { + G2D_IMGBUF_COLOR, + G2D_IMGBUF_GEM, + G2D_IMGBUF_USERPTR, +}; + +enum e_g2d_rop3_type { + G2D_ROP3_DST = 0xAA, + G2D_ROP3_SRC = 0xCC, + G2D_ROP3_3RD = 0xF0, + G2D_ROP3_MASK = 0xFF, +}; + +enum e_g2d_select_alpha_src { + G2D_SELECT_SRC_FOR_ALPHA_BLEND, /* VER4.1 */ + G2D_SELECT_ROP_FOR_ALPHA_BLEND, /* VER4.1 */ +}; + +enum e_g2d_transparent_mode { + G2D_TRANSPARENT_MODE_OPAQUE, + G2D_TRANSPARENT_MODE_TRANSPARENT, + G2D_TRANSPARENT_MODE_BLUESCREEN, + G2D_TRANSPARENT_MODE_MAX, +}; + +enum e_g2d_color_key_mode { + G2D_COLORKEY_MODE_DISABLE = 0, + G2D_COLORKEY_MODE_SRC_RGBA = (1<<0), + G2D_COLORKEY_MODE_DST_RGBA = (1<<1), + G2D_COLORKEY_MODE_SRC_YCbCr = (1<<2), /* VER4.1 */ + G2D_COLORKEY_MODE_DST_YCbCr = (1<<3), /* VER4.1 */ + G2D_COLORKEY_MODE_MASK = 15, +}; + +enum e_g2d_alpha_blend_mode { + G2D_ALPHA_BLEND_MODE_DISABLE, + G2D_ALPHA_BLEND_MODE_ENABLE, + G2D_ALPHA_BLEND_MODE_FADING, /* VER3.0 */ + G2D_ALPHA_BLEND_MODE_MAX, +}; + +enum e_g2d_op { + G2D_OP_CLEAR = 0x00, + G2D_OP_SRC = 0x01, + G2D_OP_DST = 0x02, + G2D_OP_OVER = 0x03, + G2D_OP_INTERPOLATE = 0x04, + G2D_OP_DISJOINT_CLEAR = 0x10, + G2D_OP_DISJOINT_SRC = 0x11, + G2D_OP_DISJOINT_DST = 0x12, + G2D_OP_CONJOINT_CLEAR = 0x20, + G2D_OP_CONJOINT_SRC = 0x21, + G2D_OP_CONJOINT_DST = 0x22, +}; + +/* + * The G2D_COEFF_MODE_DST_{COLOR,ALPHA} modes both use the ALPHA_REG(0x618) + * register. The registers fields are as follows: + * bits 31:8 = color value (RGB order) + * bits 7:0 = alpha value + */ +enum e_g2d_coeff_mode { + G2D_COEFF_MODE_ONE, + G2D_COEFF_MODE_ZERO, + G2D_COEFF_MODE_SRC_ALPHA, + G2D_COEFF_MODE_SRC_COLOR, + G2D_COEFF_MODE_DST_ALPHA, + G2D_COEFF_MODE_DST_COLOR, + /* Global Alpha : Set by ALPHA_REG(0x618) */ + G2D_COEFF_MODE_GB_ALPHA, + /* Global Color and Alpha : Set by ALPHA_REG(0x618) */ + G2D_COEFF_MODE_GB_COLOR, + /* (1-SRC alpha)/DST Alpha */ + G2D_COEFF_MODE_DISJOINT_S, + /* (1-DST alpha)/SRC Alpha */ + G2D_COEFF_MODE_DISJOINT_D, + /* SRC alpha/DST alpha */ + G2D_COEFF_MODE_CONJOINT_S, + /* DST alpha/SRC alpha */ + G2D_COEFF_MODE_CONJOINT_D, + /* DST alpha/SRC alpha */ + G2D_COEFF_MODE_MASK +}; + +enum e_g2d_acoeff_mode { + G2D_ACOEFF_MODE_A, /* alpha */ + G2D_ACOEFF_MODE_APGA, /* alpha + global alpha */ + G2D_ACOEFF_MODE_AMGA, /* alpha * global alpha */ + G2D_ACOEFF_MODE_MASK +}; + +union g2d_point_val { + unsigned int val; + struct { + /* + * Coordinate of Source Image + * Range: 0 ~ 8000 (Requirement: SrcLeftX < SrcRightX) + * In YCbCr 422 and YCbCr 420 format with even number. + */ + unsigned int x:16; + /* + * Y Coordinate of Source Image + * Range: 0 ~ 8000 (Requirement: SrcTopY < SrcBottomY) + * In YCbCr 420 format with even number. + */ + unsigned int y:16; + } data; +}; + +union g2d_rop4_val { + unsigned int val; + struct { + enum e_g2d_rop3_type unmasked_rop3:8; + enum e_g2d_rop3_type masked_rop3:8; + unsigned int reserved:16; + } data; +}; + +union g2d_bitblt_cmd_val { + unsigned int val; + struct { + /* [0:3] */ + unsigned int mask_rop4_en:1; + unsigned int masking_en:1; + enum e_g2d_select_alpha_src rop4_alpha_en:1; + unsigned int dither_en:1; + /* [4:7] */ + unsigned int resolved1:4; + /* [8:11] */ + unsigned int cw_en:4; + /* [12:15] */ + enum e_g2d_transparent_mode transparent_mode:4; + /* [16:19] */ + enum e_g2d_color_key_mode color_key_mode:4; + /* [20:23] */ + enum e_g2d_alpha_blend_mode alpha_blend_mode:4; + /* [24:27] */ + unsigned int src_pre_multiply:1; + unsigned int pat_pre_multiply:1; + unsigned int dst_pre_multiply:1; + unsigned int dst_depre_multiply:1; + /* [28:31] */ + unsigned int fast_solid_color_fill_en:1; + unsigned int reserved:3; + } data; +}; + +union g2d_blend_func_val { + unsigned int val; + struct { + /* [0:15] */ + enum e_g2d_coeff_mode src_coeff:4; + enum e_g2d_acoeff_mode src_coeff_src_a:2; + enum e_g2d_acoeff_mode src_coeff_dst_a:2; + enum e_g2d_coeff_mode dst_coeff:4; + enum e_g2d_acoeff_mode dst_coeff_src_a:2; + enum e_g2d_acoeff_mode dst_coeff_dst_a:2; + /* [16:19] */ + unsigned int inv_src_color_coeff:1; + unsigned int resoled1:1; + unsigned int inv_dst_color_coeff:1; + unsigned int resoled2:1; + /* [20:23] */ + unsigned int lighten_en:1; + unsigned int darken_en:1; + unsigned int win_ce_src_over_en:2; + /* [24:31] */ + unsigned int reserved:8; + } data; +}; + +struct g2d_image { + enum e_g2d_select_mode select_mode; + enum e_g2d_color_mode color_mode; + enum e_g2d_repeat_mode repeat_mode; + enum e_g2d_scale_mode scale_mode; + unsigned int xscale; + unsigned int yscale; + unsigned char rotate_90; + unsigned char x_dir; + unsigned char y_dir; + unsigned char component_alpha; + unsigned int width; + unsigned int height; + unsigned int stride; + unsigned int need_free; + unsigned int color; + enum e_g2d_buf_type buf_type; + unsigned int bo[G2D_PLANE_MAX_NR]; + struct drm_exynos_g2d_userptr user_ptr[G2D_PLANE_MAX_NR]; + void *mapped_ptr[G2D_PLANE_MAX_NR]; +}; + +struct g2d_context; + +struct g2d_context *g2d_init(int fd); +void g2d_fini(struct g2d_context *ctx); +void g2d_config_event(struct g2d_context *ctx, void *userdata); +int g2d_exec(struct g2d_context *ctx); +int g2d_solid_fill(struct g2d_context *ctx, struct g2d_image *img, + unsigned int x, unsigned int y, unsigned int w, + unsigned int h); +int g2d_copy(struct g2d_context *ctx, struct g2d_image *src, + struct g2d_image *dst, unsigned int src_x, + unsigned int src_y, unsigned int dst_x, unsigned int dst_y, + unsigned int w, unsigned int h); +int g2d_move(struct g2d_context *ctx, struct g2d_image *img, + unsigned int src_x, unsigned int src_y, unsigned int dst_x, + unsigned dst_y, unsigned int w, unsigned int h); +int g2d_copy_with_scale(struct g2d_context *ctx, struct g2d_image *src, + struct g2d_image *dst, unsigned int src_x, + unsigned int src_y, unsigned int src_w, + unsigned int src_h, unsigned int dst_x, + unsigned int dst_y, unsigned int dst_w, + unsigned int dst_h, unsigned int negative); +int g2d_blend(struct g2d_context *ctx, struct g2d_image *src, + struct g2d_image *dst, unsigned int src_x, + unsigned int src_y, unsigned int dst_x, unsigned int dst_y, + unsigned int w, unsigned int h, enum e_g2d_op op); +int g2d_scale_and_blend(struct g2d_context *ctx, struct g2d_image *src, + struct g2d_image *dst, unsigned int src_x, unsigned int src_y, + unsigned int src_w, unsigned int src_h, unsigned int dst_x, + unsigned int dst_y, unsigned int dst_w, unsigned int dst_h, + enum e_g2d_op op); +#endif /* _FIMG2D_H_ */ diff --git a/exynos/fimg2d_reg.h b/exynos/fimg2d_reg.h new file mode 100644 index 0000000..d42296d --- /dev/null +++ b/exynos/fimg2d_reg.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2013 Samsung Electronics Co.Ltd + * Authors: + * Inki Dae + * + * 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS 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 _FIMG2D_REG_H_ +#define _FIMG2D_REG_H_ + +#define SOFT_RESET_REG (0x0000) +#define INTEN_REG (0x0004) +#define INTC_PEND_REG (0x000C) +#define FIFO_STAT_REG (0x0010) +#define AXI_MODE_REG (0x001C) +#define DMA_SFR_BASE_ADDR_REG (0x0080) +#define DMA_COMMAND_REG (0x0084) +#define DMA_EXE_LIST_NUM_REG (0x0088) +#define DMA_STATUS_REG (0x008C) +#define DMA_HOLD_CMD_REG (0x0090) + +/* COMMAND REGISTER */ +#define BITBLT_START_REG (0x0100) +#define BITBLT_COMMAND_REG (0x0104) +#define BLEND_FUNCTION_REG (0x0108) /* VER4.1 */ +#define ROUND_MODE_REG (0x010C) /* VER4.1 */ + +/* PARAMETER SETTING REGISTER */ +#define ROTATE_REG (0x0200) +#define SRC_MASK_DIRECT_REG (0x0204) +#define DST_PAT_DIRECT_REG (0x0208) + +/* SOURCE */ +#define SRC_SELECT_REG (0x0300) +#define SRC_BASE_ADDR_REG (0x0304) +#define SRC_STRIDE_REG (0x0308) +#define SRC_COLOR_MODE_REG (0x030c) +#define SRC_LEFT_TOP_REG (0x0310) +#define SRC_RIGHT_BOTTOM_REG (0x0314) +#define SRC_PLANE2_BASE_ADDR_REG (0x0318) /* VER4.1 */ +#define SRC_REPEAT_MODE_REG (0x031C) +#define SRC_PAD_VALUE_REG (0x0320) +#define SRC_A8_RGB_EXT_REG (0x0324) +#define SRC_SCALE_CTRL_REG (0x0328) +#define SRC_XSCALE_REG (0x032C) +#define SRC_YSCALE_REG (0x0330) + +/* DESTINATION */ +#define DST_SELECT_REG (0x0400) +#define DST_BASE_ADDR_REG (0x0404) +#define DST_STRIDE_REG (0x0408) +#define DST_COLOR_MODE_REG (0x040C) +#define DST_LEFT_TOP_REG (0x0410) +#define DST_RIGHT_BOTTOM_REG (0x0414) +#define DST_PLANE2_BASE_ADDR_REG (0x0418) /* VER4.1 */ +#define DST_A8_RGB_EXT_REG (0x041C) + +/* PATTERN */ +#define PAT_BASE_ADDR_REG (0x0500) +#define PAT_SIZE_REG (0x0504) +#define PAT_COLOR_MODE_REG (0x0508) +#define PAT_OFFSET_REG (0x050C) +#define PAT_STRIDE_REG (0x0510) + +/* MASK */ +#define MASK_BASE_ADDR_REG (0x0520) +#define MASK_STRIDE_REG (0x0524) +#define MASK_LEFT_TOP_REG (0x0528) /* VER4.1 */ +#define MASK_RIGHT_BOTTOM_REG (0x052C) /* VER4.1 */ +#define MASK_MODE_REG (0x0530) /* VER4.1 */ +#define MASK_REPEAT_MODE_REG (0x0534) +#define MASK_PAD_VALUE_REG (0x0538) +#define MASK_SCALE_CTRL_REG (0x053C) +#define MASK_XSCALE_REG (0x0540) +#define MASK_YSCALE_REG (0x0544) + +/* CLIPPING WINDOW */ +#define CW_LT_REG (0x0600) +#define CW_RB_REG (0x0604) + +/* ROP & ALPHA SETTING */ +#define THIRD_OPERAND_REG (0x0610) +#define ROP4_REG (0x0614) +#define ALPHA_REG (0x0618) + +/* COLOR SETTING */ +#define FG_COLOR_REG (0x0700) +#define BG_COLOR_REG (0x0704) +#define BS_COLOR_REG (0x0708) +#define SF_COLOR_REG (0x070C) /* VER4.1 */ + +/* COLOR KEY */ +#define SRC_COLORKEY_CTRL_REG (0x0710) +#define SRC_COLORKEY_DR_MIN_REG (0x0714) +#define SRC_COLORKEY_DR_MAX_REG (0x0718) +#define DST_COLORKEY_CTRL_REG (0x071C) +#define DST_COLORKEY_DR_MIN_REG (0x0720) +#define DST_COLORKEY_DR_MAX_REG (0x0724) +/* YCbCr src Color Key */ +#define YCbCr_SRC_COLORKEY_CTRL_REG (0x0728) /* VER4.1 */ +#define YCbCr_SRC_COLORKEY_DR_MIN_REG (0x072C) /* VER4.1 */ +#define YCbCr_SRC_COLORKEY_DR_MAX_REG (0x0730) /* VER4.1 */ +/*Y CbCr dst Color Key */ +#define YCbCr_DST_COLORKEY_CTRL_REG (0x0734) /* VER4.1 */ +#define YCbCr_DST_COLORKEY_DR_MIN_REG (0x0738) /* VER4.1 */ +#define YCbCr_DST_COLORKEY_DR_MAX_REG (0x073C) /* VER4.1 */ + +#endif + diff --git a/exynos/libdrm_exynos.pc.in b/exynos/libdrm_exynos.pc.in new file mode 100644 index 0000000..ff1c432 --- /dev/null +++ b/exynos/libdrm_exynos.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libdrm_exynos +Description: Userspace interface to exynos kernel DRM services +Version: 0.7 +Libs: -L${libdir} -ldrm_exynos +Cflags: -I${includedir} -I${includedir}/libdrm -I${includedir}/exynos +Requires.private: libdrm diff --git a/exynos/meson.build b/exynos/meson.build new file mode 100644 index 0000000..2f02ae7 --- /dev/null +++ b/exynos/meson.build @@ -0,0 +1,61 @@ +# Copyright © 2017-2018 Intel Corporation + +# 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. + +libdrm_exynos = library( + 'drm_exynos', + [files('exynos_drm.c', 'exynos_fimg2d.c'), config_file], + c_args : libdrm_c_args, + gnu_symbol_visibility : 'hidden', + include_directories : [inc_root, inc_drm], + link_with : libdrm, + dependencies : [dep_pthread_stubs], + version : '1.0.0', + install : true, +) + +install_headers('exynos_drmif.h', subdir : 'libdrm') +install_headers('exynos_drm.h', 'exynos_fimg2d.h', subdir : 'exynos') + +ext_libdrm_exynos = declare_dependency( + link_with : [libdrm, libdrm_exynos], + include_directories : [inc_drm, include_directories('.')], +) + +if meson.version().version_compare('>= 0.54.0') + meson.override_dependency('libdrm_exynos', ext_libdrm_exynos) +endif + +pkg.generate( + libdrm_exynos, + name : 'libdrm_exynos', + subdirs : ['.', 'libdrm', 'exynos'], + version : '0.7', + description : 'Userspace interface to exynos kernel DRM services', +) + +test( + 'exynos-symbols-check', + symbols_check, + args : [ + '--lib', libdrm_exynos, + '--symbols-file', files('exynos-symbols.txt'), + '--nm', prog_nm.path(), + ], +) diff --git a/freedreno/Android.mk b/freedreno/Android.mk new file mode 100644 index 0000000..2b582ae --- /dev/null +++ b/freedreno/Android.mk @@ -0,0 +1,14 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +# Import variables LIBDRM_FREEDRENO_FILES, LIBDRM_FREEDRENO_H_FILES +include $(LOCAL_PATH)/Makefile.sources + +LOCAL_MODULE := libdrm_freedreno + +LOCAL_SHARED_LIBRARIES := libdrm + +LOCAL_SRC_FILES := $(LIBDRM_FREEDRENO_FILES) + +include $(LIBDRM_COMMON_MK) +include $(BUILD_SHARED_LIBRARY) diff --git a/freedreno/Makefile.sources b/freedreno/Makefile.sources new file mode 100644 index 0000000..ca89511 --- /dev/null +++ b/freedreno/Makefile.sources @@ -0,0 +1,25 @@ +LIBDRM_FREEDRENO_FILES := \ + freedreno_device.c \ + freedreno_pipe.c \ + freedreno_priv.h \ + freedreno_ringbuffer.c \ + freedreno_bo.c \ + freedreno_bo_cache.c \ + msm/msm_bo.c \ + msm/msm_device.c \ + msm/msm_pipe.c \ + msm/msm_priv.h \ + msm/msm_ringbuffer.c + +LIBDRM_FREEDRENO_KGSL_FILES := \ + kgsl/kgsl_bo.c \ + kgsl/kgsl_device.c \ + kgsl/kgsl_drm.h \ + kgsl/kgsl_pipe.c \ + kgsl/kgsl_priv.h \ + kgsl/kgsl_ringbuffer.c \ + kgsl/msm_kgsl.h + +LIBDRM_FREEDRENO_H_FILES := \ + freedreno_drmif.h \ + freedreno_ringbuffer.h diff --git a/freedreno/freedreno-symbols.txt b/freedreno/freedreno-symbols.txt new file mode 100644 index 0000000..471ca99 --- /dev/null +++ b/freedreno/freedreno-symbols.txt @@ -0,0 +1,45 @@ +fd_bo_cpu_fini +fd_bo_cpu_prep +fd_bo_del +fd_bo_dmabuf +fd_bo_from_dmabuf +fd_bo_from_fbdev +fd_bo_from_handle +fd_bo_from_name +fd_bo_get_iova +fd_bo_get_name +fd_bo_handle +fd_bo_map +fd_bo_new +fd_bo_put_iova +fd_bo_ref +fd_bo_size +fd_device_del +fd_device_fd +fd_device_new +fd_device_new_dup +fd_device_ref +fd_device_version +fd_pipe_del +fd_pipe_get_param +fd_pipe_new +fd_pipe_new2 +fd_pipe_ref +fd_pipe_wait +fd_pipe_wait_timeout +fd_ringbuffer_cmd_count +fd_ringbuffer_del +fd_ringbuffer_emit_reloc_ring_full +fd_ringbuffer_flush +fd_ringbuffer_grow +fd_ringbuffer_new +fd_ringbuffer_new_flags +fd_ringbuffer_new_object +fd_ringbuffer_ref +fd_ringbuffer_reloc +fd_ringbuffer_reloc2 +fd_ringbuffer_reset +fd_ringbuffer_set_parent +fd_ringbuffer_size +fd_ringbuffer_timestamp +fd_ringbuffer_flush2 diff --git a/freedreno/freedreno_bo.c b/freedreno/freedreno_bo.c new file mode 100644 index 0000000..3cdc973 --- /dev/null +++ b/freedreno/freedreno_bo.c @@ -0,0 +1,359 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2012 Rob Clark + * + * 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 (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 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. + * + * Authors: + * Rob Clark + */ + +#include "freedreno_drmif.h" +#include "freedreno_priv.h" + +drm_private pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER; +drm_private void bo_del(struct fd_bo *bo); + +/* set buffer name, and add to table, call w/ table_lock held: */ +static void set_name(struct fd_bo *bo, uint32_t name) +{ + bo->name = name; + /* add ourself into the handle table: */ + drmHashInsert(bo->dev->name_table, name, bo); +} + +/* lookup a buffer, call w/ table_lock held: */ +static struct fd_bo * lookup_bo(void *tbl, uint32_t key) +{ + struct fd_bo *bo = NULL; + if (!drmHashLookup(tbl, key, (void **)&bo)) { + /* found, incr refcnt and return: */ + bo = fd_bo_ref(bo); + + /* don't break the bucket if this bo was found in one */ + list_delinit(&bo->list); + } + return bo; +} + +/* allocate a new buffer object, call w/ table_lock held */ +static struct fd_bo * bo_from_handle(struct fd_device *dev, + uint32_t size, uint32_t handle) +{ + struct fd_bo *bo; + + bo = dev->funcs->bo_from_handle(dev, size, handle); + if (!bo) { + drmCloseBufferHandle(dev->fd, handle); + return NULL; + } + bo->dev = fd_device_ref(dev); + bo->size = size; + bo->handle = handle; + atomic_set(&bo->refcnt, 1); + list_inithead(&bo->list); + /* add ourself into the handle table: */ + drmHashInsert(dev->handle_table, handle, bo); + return bo; +} + +static struct fd_bo * +bo_new(struct fd_device *dev, uint32_t size, uint32_t flags, + struct fd_bo_cache *cache) +{ + struct fd_bo *bo = NULL; + uint32_t handle; + int ret; + + bo = fd_bo_cache_alloc(cache, &size, flags); + if (bo) + return bo; + + ret = dev->funcs->bo_new_handle(dev, size, flags, &handle); + if (ret) + return NULL; + + pthread_mutex_lock(&table_lock); + bo = bo_from_handle(dev, size, handle); + pthread_mutex_unlock(&table_lock); + + VG_BO_ALLOC(bo); + + return bo; +} + +drm_public struct fd_bo * +fd_bo_new(struct fd_device *dev, uint32_t size, uint32_t flags) +{ + struct fd_bo *bo = bo_new(dev, size, flags, &dev->bo_cache); + if (bo) + bo->bo_reuse = BO_CACHE; + return bo; +} + +/* internal function to allocate bo's that use the ringbuffer cache + * instead of the normal bo_cache. The purpose is, because cmdstream + * bo's get vmap'd on the kernel side, and that is expensive, we want + * to re-use cmdstream bo's for cmdstream and not unrelated purposes. + */ +drm_private struct fd_bo * +fd_bo_new_ring(struct fd_device *dev, uint32_t size, uint32_t flags) +{ + struct fd_bo *bo = bo_new(dev, size, flags, &dev->ring_cache); + if (bo) + bo->bo_reuse = RING_CACHE; + return bo; +} + +drm_public struct fd_bo * +fd_bo_from_handle(struct fd_device *dev, uint32_t handle, uint32_t size) +{ + struct fd_bo *bo = NULL; + + pthread_mutex_lock(&table_lock); + + bo = lookup_bo(dev->handle_table, handle); + if (bo) + goto out_unlock; + + bo = bo_from_handle(dev, size, handle); + + VG_BO_ALLOC(bo); + +out_unlock: + pthread_mutex_unlock(&table_lock); + + return bo; +} + +drm_public struct fd_bo * +fd_bo_from_dmabuf(struct fd_device *dev, int fd) +{ + int ret, size; + uint32_t handle; + struct fd_bo *bo; + + pthread_mutex_lock(&table_lock); + ret = drmPrimeFDToHandle(dev->fd, fd, &handle); + if (ret) { + pthread_mutex_unlock(&table_lock); + return NULL; + } + + bo = lookup_bo(dev->handle_table, handle); + if (bo) + goto out_unlock; + + /* lseek() to get bo size */ + size = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_CUR); + + bo = bo_from_handle(dev, size, handle); + + VG_BO_ALLOC(bo); + +out_unlock: + pthread_mutex_unlock(&table_lock); + + return bo; +} + +drm_public struct fd_bo * fd_bo_from_name(struct fd_device *dev, uint32_t name) +{ + struct drm_gem_open req = { + .name = name, + }; + struct fd_bo *bo; + + pthread_mutex_lock(&table_lock); + + /* check name table first, to see if bo is already open: */ + bo = lookup_bo(dev->name_table, name); + if (bo) + goto out_unlock; + + if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) { + ERROR_MSG("gem-open failed: %s", strerror(errno)); + goto out_unlock; + } + + bo = lookup_bo(dev->handle_table, req.handle); + if (bo) + goto out_unlock; + + bo = bo_from_handle(dev, req.size, req.handle); + if (bo) { + set_name(bo, name); + VG_BO_ALLOC(bo); + } + +out_unlock: + pthread_mutex_unlock(&table_lock); + + return bo; +} + +drm_public uint64_t fd_bo_get_iova(struct fd_bo *bo) +{ + return bo->funcs->iova(bo); +} + +drm_public void fd_bo_put_iova(struct fd_bo *bo) +{ + /* currently a no-op */ +} + +drm_public struct fd_bo * fd_bo_ref(struct fd_bo *bo) +{ + atomic_inc(&bo->refcnt); + return bo; +} + +drm_public void fd_bo_del(struct fd_bo *bo) +{ + struct fd_device *dev = bo->dev; + + if (!atomic_dec_and_test(&bo->refcnt)) + return; + + pthread_mutex_lock(&table_lock); + + if ((bo->bo_reuse == BO_CACHE) && (fd_bo_cache_free(&dev->bo_cache, bo) == 0)) + goto out; + if ((bo->bo_reuse == RING_CACHE) && (fd_bo_cache_free(&dev->ring_cache, bo) == 0)) + goto out; + + bo_del(bo); + fd_device_del_locked(dev); +out: + pthread_mutex_unlock(&table_lock); +} + +/* Called under table_lock */ +drm_private void bo_del(struct fd_bo *bo) +{ + VG_BO_FREE(bo); + + if (bo->map) + drm_munmap(bo->map, bo->size); + + /* TODO probably bo's in bucket list get removed from + * handle table?? + */ + + if (bo->handle) { + drmHashDelete(bo->dev->handle_table, bo->handle); + if (bo->name) + drmHashDelete(bo->dev->name_table, bo->name); + drmCloseBufferHandle(bo->dev->fd, bo->handle); + } + + bo->funcs->destroy(bo); +} + +drm_public int fd_bo_get_name(struct fd_bo *bo, uint32_t *name) +{ + if (!bo->name) { + struct drm_gem_flink req = { + .handle = bo->handle, + }; + int ret; + + ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req); + if (ret) { + return ret; + } + + pthread_mutex_lock(&table_lock); + set_name(bo, req.name); + pthread_mutex_unlock(&table_lock); + bo->bo_reuse = NO_CACHE; + } + + *name = bo->name; + + return 0; +} + +drm_public uint32_t fd_bo_handle(struct fd_bo *bo) +{ + return bo->handle; +} + +drm_public int fd_bo_dmabuf(struct fd_bo *bo) +{ + int ret, prime_fd; + + ret = drmPrimeHandleToFD(bo->dev->fd, bo->handle, DRM_CLOEXEC, + &prime_fd); + if (ret) { + ERROR_MSG("failed to get dmabuf fd: %d", ret); + return ret; + } + + bo->bo_reuse = NO_CACHE; + + return prime_fd; +} + +drm_public uint32_t fd_bo_size(struct fd_bo *bo) +{ + return bo->size; +} + +drm_public void * fd_bo_map(struct fd_bo *bo) +{ + if (!bo->map) { + uint64_t offset; + int ret; + + ret = bo->funcs->offset(bo, &offset); + if (ret) { + return NULL; + } + + bo->map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, + bo->dev->fd, offset); + if (bo->map == MAP_FAILED) { + ERROR_MSG("mmap failed: %s", strerror(errno)); + bo->map = NULL; + } + } + return bo->map; +} + +/* a bit odd to take the pipe as an arg, but it's a, umm, quirk of kgsl.. */ +drm_public int fd_bo_cpu_prep(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op) +{ + return bo->funcs->cpu_prep(bo, pipe, op); +} + +drm_public void fd_bo_cpu_fini(struct fd_bo *bo) +{ + bo->funcs->cpu_fini(bo); +} + +#if !HAVE_FREEDRENO_KGSL +drm_public struct fd_bo * fd_bo_from_fbdev(struct fd_pipe *pipe, int fbfd, uint32_t size) +{ + return NULL; +} +#endif diff --git a/freedreno/freedreno_bo_cache.c b/freedreno/freedreno_bo_cache.c new file mode 100644 index 0000000..bb0605a --- /dev/null +++ b/freedreno/freedreno_bo_cache.c @@ -0,0 +1,220 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2016 Rob Clark + * + * 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 (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 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. + * + * Authors: + * Rob Clark + */ + +#include "freedreno_drmif.h" +#include "freedreno_priv.h" + +drm_private void bo_del(struct fd_bo *bo); +drm_private extern pthread_mutex_t table_lock; + +static void +add_bucket(struct fd_bo_cache *cache, int size) +{ + unsigned int i = cache->num_buckets; + + assert(i < ARRAY_SIZE(cache->cache_bucket)); + + list_inithead(&cache->cache_bucket[i].list); + cache->cache_bucket[i].size = size; + cache->num_buckets++; +} + +/** + * @coarse: if true, only power-of-two bucket sizes, otherwise + * fill in for a bit smoother size curve.. + */ +drm_private void +fd_bo_cache_init(struct fd_bo_cache *cache, int coarse) +{ + unsigned long size, cache_max_size = 64 * 1024 * 1024; + + /* OK, so power of two buckets was too wasteful of memory. + * Give 3 other sizes between each power of two, to hopefully + * cover things accurately enough. (The alternative is + * probably to just go for exact matching of sizes, and assume + * that for things like composited window resize the tiled + * width/height alignment and rounding of sizes to pages will + * get us useful cache hit rates anyway) + */ + add_bucket(cache, 4096); + add_bucket(cache, 4096 * 2); + if (!coarse) + add_bucket(cache, 4096 * 3); + + /* Initialize the linked lists for BO reuse cache. */ + for (size = 4 * 4096; size <= cache_max_size; size *= 2) { + add_bucket(cache, size); + if (!coarse) { + add_bucket(cache, size + size * 1 / 4); + add_bucket(cache, size + size * 2 / 4); + add_bucket(cache, size + size * 3 / 4); + } + } +} + +/* Frees older cached buffers. Called under table_lock */ +drm_private void +fd_bo_cache_cleanup(struct fd_bo_cache *cache, time_t time) +{ + int i; + + if (cache->time == time) + return; + + for (i = 0; i < cache->num_buckets; i++) { + struct fd_bo_bucket *bucket = &cache->cache_bucket[i]; + struct fd_bo *bo; + + while (!LIST_IS_EMPTY(&bucket->list)) { + bo = LIST_ENTRY(struct fd_bo, bucket->list.next, list); + + /* keep things in cache for at least 1 second: */ + if (time && ((time - bo->free_time) <= 1)) + break; + + VG_BO_OBTAIN(bo); + list_del(&bo->list); + bo_del(bo); + } + } + + cache->time = time; +} + +static struct fd_bo_bucket * get_bucket(struct fd_bo_cache *cache, uint32_t size) +{ + int i; + + /* hmm, this is what intel does, but I suppose we could calculate our + * way to the correct bucket size rather than looping.. + */ + for (i = 0; i < cache->num_buckets; i++) { + struct fd_bo_bucket *bucket = &cache->cache_bucket[i]; + if (bucket->size >= size) { + return bucket; + } + } + + return NULL; +} + +static int is_idle(struct fd_bo *bo) +{ + return fd_bo_cpu_prep(bo, NULL, + DRM_FREEDRENO_PREP_READ | + DRM_FREEDRENO_PREP_WRITE | + DRM_FREEDRENO_PREP_NOSYNC) == 0; +} + +static struct fd_bo *find_in_bucket(struct fd_bo_bucket *bucket, uint32_t flags) +{ + struct fd_bo *bo = NULL; + + /* TODO .. if we had an ALLOC_FOR_RENDER flag like intel, we could + * skip the busy check.. if it is only going to be a render target + * then we probably don't need to stall.. + * + * NOTE that intel takes ALLOC_FOR_RENDER bo's from the list tail + * (MRU, since likely to be in GPU cache), rather than head (LRU).. + */ + pthread_mutex_lock(&table_lock); + if (!LIST_IS_EMPTY(&bucket->list)) { + bo = LIST_ENTRY(struct fd_bo, bucket->list.next, list); + /* TODO check for compatible flags? */ + if (is_idle(bo)) { + list_del(&bo->list); + } else { + bo = NULL; + } + } + pthread_mutex_unlock(&table_lock); + + return bo; +} + +/* NOTE: size is potentially rounded up to bucket size: */ +drm_private struct fd_bo * +fd_bo_cache_alloc(struct fd_bo_cache *cache, uint32_t *size, uint32_t flags) +{ + struct fd_bo *bo = NULL; + struct fd_bo_bucket *bucket; + + *size = ALIGN(*size, 4096); + bucket = get_bucket(cache, *size); + + /* see if we can be green and recycle: */ +retry: + if (bucket) { + *size = bucket->size; + bo = find_in_bucket(bucket, flags); + if (bo) { + VG_BO_OBTAIN(bo); + if (bo->funcs->madvise(bo, TRUE) <= 0) { + /* we've lost the backing pages, delete and try again: */ + pthread_mutex_lock(&table_lock); + bo_del(bo); + pthread_mutex_unlock(&table_lock); + goto retry; + } + atomic_set(&bo->refcnt, 1); + fd_device_ref(bo->dev); + return bo; + } + } + + return NULL; +} + +drm_private int +fd_bo_cache_free(struct fd_bo_cache *cache, struct fd_bo *bo) +{ + struct fd_bo_bucket *bucket = get_bucket(cache, bo->size); + + /* see if we can be green and recycle: */ + if (bucket) { + struct timespec time; + + bo->funcs->madvise(bo, FALSE); + + clock_gettime(CLOCK_MONOTONIC, &time); + + bo->free_time = time.tv_sec; + VG_BO_RELEASE(bo); + list_addtail(&bo->list, &bucket->list); + fd_bo_cache_cleanup(cache, time.tv_sec); + + /* bo's in the bucket cache don't have a ref and + * don't hold a ref to the dev: + */ + fd_device_del_locked(bo->dev); + + return 0; + } + + return -1; +} diff --git a/freedreno/freedreno_device.c b/freedreno/freedreno_device.c new file mode 100644 index 0000000..ac23430 --- /dev/null +++ b/freedreno/freedreno_device.c @@ -0,0 +1,145 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2012 Rob Clark + * + * 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 (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 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. + * + * Authors: + * Rob Clark + */ + +#include +#include +#include + +#include "freedreno_drmif.h" +#include "freedreno_priv.h" + +static pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER; + +struct fd_device * kgsl_device_new(int fd); +struct fd_device * msm_device_new(int fd); + +drm_public struct fd_device * fd_device_new(int fd) +{ + struct fd_device *dev; + drmVersionPtr version; + + /* figure out if we are kgsl or msm drm driver: */ + version = drmGetVersion(fd); + if (!version) { + ERROR_MSG("cannot get version: %s", strerror(errno)); + return NULL; + } + + if (!strcmp(version->name, "msm")) { + DEBUG_MSG("msm DRM device"); + if (version->version_major != 1) { + ERROR_MSG("unsupported version: %u.%u.%u", version->version_major, + version->version_minor, version->version_patchlevel); + dev = NULL; + goto out; + } + + dev = msm_device_new(fd); + dev->version = version->version_minor; +#if HAVE_FREEDRENO_KGSL + } else if (!strcmp(version->name, "kgsl")) { + DEBUG_MSG("kgsl DRM device"); + dev = kgsl_device_new(fd); +#endif + } else { + ERROR_MSG("unknown device: %s", version->name); + dev = NULL; + } + +out: + drmFreeVersion(version); + + if (!dev) + return NULL; + + atomic_set(&dev->refcnt, 1); + dev->fd = fd; + dev->handle_table = drmHashCreate(); + dev->name_table = drmHashCreate(); + fd_bo_cache_init(&dev->bo_cache, FALSE); + fd_bo_cache_init(&dev->ring_cache, TRUE); + + return dev; +} + +/* like fd_device_new() but creates it's own private dup() of the fd + * which is close()d when the device is finalized. + */ +drm_public struct fd_device * fd_device_new_dup(int fd) +{ + int dup_fd = dup(fd); + struct fd_device *dev = fd_device_new(dup_fd); + if (dev) + dev->closefd = 1; + else + close(dup_fd); + return dev; +} + +drm_public struct fd_device * fd_device_ref(struct fd_device *dev) +{ + atomic_inc(&dev->refcnt); + return dev; +} + +static void fd_device_del_impl(struct fd_device *dev) +{ + int close_fd = dev->closefd ? dev->fd : -1; + fd_bo_cache_cleanup(&dev->bo_cache, 0); + drmHashDestroy(dev->handle_table); + drmHashDestroy(dev->name_table); + dev->funcs->destroy(dev); + if (close_fd >= 0) + close(close_fd); +} + +drm_private void fd_device_del_locked(struct fd_device *dev) +{ + if (!atomic_dec_and_test(&dev->refcnt)) + return; + fd_device_del_impl(dev); +} + +drm_public void fd_device_del(struct fd_device *dev) +{ + if (!atomic_dec_and_test(&dev->refcnt)) + return; + pthread_mutex_lock(&table_lock); + fd_device_del_impl(dev); + pthread_mutex_unlock(&table_lock); +} + +drm_public int fd_device_fd(struct fd_device *dev) +{ + return dev->fd; +} + +drm_public enum fd_version fd_device_version(struct fd_device *dev) +{ + return dev->version; +} diff --git a/freedreno/freedreno_drmif.h b/freedreno/freedreno_drmif.h new file mode 100644 index 0000000..c95c21b --- /dev/null +++ b/freedreno/freedreno_drmif.h @@ -0,0 +1,140 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2012 Rob Clark + * + * 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 (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 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. + * + * Authors: + * Rob Clark + */ + +#ifndef FREEDRENO_DRMIF_H_ +#define FREEDRENO_DRMIF_H_ + +#include +#include + +#if defined(__GNUC__) +# define drm_deprecated __attribute__((__deprecated__)) +#else +# define drm_deprecated +#endif + +/* an empty marker for things that will be deprecated in the future: */ +#define will_be_deprecated + +struct fd_bo; +struct fd_pipe; +struct fd_device; + +enum fd_pipe_id { + FD_PIPE_3D = 1, + FD_PIPE_2D = 2, + /* some devices have two 2d blocks.. not really sure how to + * use that yet, so just ignoring the 2nd 2d pipe for now + */ + FD_PIPE_MAX +}; + +enum fd_param_id { + FD_DEVICE_ID, + FD_GMEM_SIZE, + FD_GPU_ID, + FD_CHIP_ID, + FD_MAX_FREQ, + FD_TIMESTAMP, + FD_NR_RINGS, /* # of rings == # of distinct priority levels */ +}; + +/* bo flags: */ +#define DRM_FREEDRENO_GEM_TYPE_SMI 0x00000001 +#define DRM_FREEDRENO_GEM_TYPE_KMEM 0x00000002 +#define DRM_FREEDRENO_GEM_TYPE_MEM_MASK 0x0000000f +#define DRM_FREEDRENO_GEM_CACHE_NONE 0x00000000 +#define DRM_FREEDRENO_GEM_CACHE_WCOMBINE 0x00100000 +#define DRM_FREEDRENO_GEM_CACHE_WTHROUGH 0x00200000 +#define DRM_FREEDRENO_GEM_CACHE_WBACK 0x00400000 +#define DRM_FREEDRENO_GEM_CACHE_WBACKWA 0x00800000 +#define DRM_FREEDRENO_GEM_CACHE_MASK 0x00f00000 +#define DRM_FREEDRENO_GEM_GPUREADONLY 0x01000000 + +/* bo access flags: (keep aligned to MSM_PREP_x) */ +#define DRM_FREEDRENO_PREP_READ 0x01 +#define DRM_FREEDRENO_PREP_WRITE 0x02 +#define DRM_FREEDRENO_PREP_NOSYNC 0x04 + +/* device functions: + */ + +struct fd_device * fd_device_new(int fd); +struct fd_device * fd_device_new_dup(int fd); +struct fd_device * fd_device_ref(struct fd_device *dev); +void fd_device_del(struct fd_device *dev); +int fd_device_fd(struct fd_device *dev); + +enum fd_version { + FD_VERSION_MADVISE = 1, /* kernel supports madvise */ + FD_VERSION_UNLIMITED_CMDS = 1, /* submits w/ >4 cmd buffers (growable ringbuffer) */ + FD_VERSION_FENCE_FD = 2, /* submit command supports in/out fences */ + FD_VERSION_SUBMIT_QUEUES = 3, /* submit queues and multiple priority levels */ + FD_VERSION_BO_IOVA = 3, /* supports fd_bo_get/put_iova() */ +}; +enum fd_version fd_device_version(struct fd_device *dev); + +/* pipe functions: + */ + +struct fd_pipe * fd_pipe_new(struct fd_device *dev, enum fd_pipe_id id); +struct fd_pipe * fd_pipe_new2(struct fd_device *dev, enum fd_pipe_id id, uint32_t prio); +struct fd_pipe * fd_pipe_ref(struct fd_pipe *pipe); +void fd_pipe_del(struct fd_pipe *pipe); +int fd_pipe_get_param(struct fd_pipe *pipe, enum fd_param_id param, + uint64_t *value); +int fd_pipe_wait(struct fd_pipe *pipe, uint32_t timestamp); +/* timeout in nanosec */ +int fd_pipe_wait_timeout(struct fd_pipe *pipe, uint32_t timestamp, + uint64_t timeout); + + +/* buffer-object functions: + */ + +struct fd_bo * fd_bo_new(struct fd_device *dev, + uint32_t size, uint32_t flags); +struct fd_bo * fd_bo_from_fbdev(struct fd_pipe *pipe, + int fbfd, uint32_t size); +struct fd_bo *fd_bo_from_handle(struct fd_device *dev, + uint32_t handle, uint32_t size); +struct fd_bo * fd_bo_from_name(struct fd_device *dev, uint32_t name); +struct fd_bo * fd_bo_from_dmabuf(struct fd_device *dev, int fd); +uint64_t fd_bo_get_iova(struct fd_bo *bo); +void fd_bo_put_iova(struct fd_bo *bo); +struct fd_bo * fd_bo_ref(struct fd_bo *bo); +void fd_bo_del(struct fd_bo *bo); +int fd_bo_get_name(struct fd_bo *bo, uint32_t *name); +uint32_t fd_bo_handle(struct fd_bo *bo); +int fd_bo_dmabuf(struct fd_bo *bo); +uint32_t fd_bo_size(struct fd_bo *bo); +void * fd_bo_map(struct fd_bo *bo); +int fd_bo_cpu_prep(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op); +void fd_bo_cpu_fini(struct fd_bo *bo); + +#endif /* FREEDRENO_DRMIF_H_ */ diff --git a/freedreno/freedreno_pipe.c b/freedreno/freedreno_pipe.c new file mode 100644 index 0000000..e82e644 --- /dev/null +++ b/freedreno/freedreno_pipe.c @@ -0,0 +1,102 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2012 Rob Clark + * + * 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 (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 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. + * + * Authors: + * Rob Clark + */ + +#include "freedreno_drmif.h" +#include "freedreno_priv.h" + +/** + * priority of zero is highest priority, and higher numeric values are + * lower priorities + */ +drm_public struct fd_pipe * +fd_pipe_new2(struct fd_device *dev, enum fd_pipe_id id, uint32_t prio) +{ + struct fd_pipe *pipe; + uint64_t val; + + if (id > FD_PIPE_MAX) { + ERROR_MSG("invalid pipe id: %d", id); + return NULL; + } + + if ((prio != 1) && (fd_device_version(dev) < FD_VERSION_SUBMIT_QUEUES)) { + ERROR_MSG("invalid priority!"); + return NULL; + } + + pipe = dev->funcs->pipe_new(dev, id, prio); + if (!pipe) { + ERROR_MSG("allocation failed"); + return NULL; + } + + pipe->dev = dev; + pipe->id = id; + atomic_set(&pipe->refcnt, 1); + + fd_pipe_get_param(pipe, FD_GPU_ID, &val); + pipe->gpu_id = val; + + return pipe; +} + +drm_public struct fd_pipe * +fd_pipe_new(struct fd_device *dev, enum fd_pipe_id id) +{ + return fd_pipe_new2(dev, id, 1); +} + +drm_public struct fd_pipe * fd_pipe_ref(struct fd_pipe *pipe) +{ + atomic_inc(&pipe->refcnt); + return pipe; +} + +drm_public void fd_pipe_del(struct fd_pipe *pipe) +{ + if (!atomic_dec_and_test(&pipe->refcnt)) + return; + pipe->funcs->destroy(pipe); +} + +drm_public int fd_pipe_get_param(struct fd_pipe *pipe, + enum fd_param_id param, uint64_t *value) +{ + return pipe->funcs->get_param(pipe, param, value); +} + +drm_public int fd_pipe_wait(struct fd_pipe *pipe, uint32_t timestamp) +{ + return fd_pipe_wait_timeout(pipe, timestamp, ~0); +} + +drm_public int fd_pipe_wait_timeout(struct fd_pipe *pipe, uint32_t timestamp, + uint64_t timeout) +{ + return pipe->funcs->wait(pipe, timestamp, timeout); +} diff --git a/freedreno/freedreno_priv.h b/freedreno/freedreno_priv.h new file mode 100644 index 0000000..b8eac4b --- /dev/null +++ b/freedreno/freedreno_priv.h @@ -0,0 +1,258 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2012 Rob Clark + * + * 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 (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 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. + * + * Authors: + * Rob Clark + */ + +#ifndef FREEDRENO_PRIV_H_ +#define FREEDRENO_PRIV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libdrm_macros.h" +#include "xf86drm.h" +#include "xf86atomic.h" + +#include "util_double_list.h" +#include "util_math.h" + +#include "freedreno_drmif.h" +#include "freedreno_ringbuffer.h" +#include "drm.h" + +#ifndef TRUE +# define TRUE 1 +#endif +#ifndef FALSE +# define FALSE 0 +#endif + +struct fd_device_funcs { + int (*bo_new_handle)(struct fd_device *dev, uint32_t size, + uint32_t flags, uint32_t *handle); + struct fd_bo * (*bo_from_handle)(struct fd_device *dev, + uint32_t size, uint32_t handle); + struct fd_pipe * (*pipe_new)(struct fd_device *dev, enum fd_pipe_id id, + unsigned prio); + void (*destroy)(struct fd_device *dev); +}; + +struct fd_bo_bucket { + uint32_t size; + struct list_head list; +}; + +struct fd_bo_cache { + struct fd_bo_bucket cache_bucket[14 * 4]; + int num_buckets; + time_t time; +}; + +struct fd_device { + int fd; + enum fd_version version; + atomic_t refcnt; + + /* tables to keep track of bo's, to avoid "evil-twin" fd_bo objects: + * + * handle_table: maps handle to fd_bo + * name_table: maps flink name to fd_bo + * + * We end up needing two tables, because DRM_IOCTL_GEM_OPEN always + * returns a new handle. So we need to figure out if the bo is already + * open in the process first, before calling gem-open. + */ + void *handle_table, *name_table; + + const struct fd_device_funcs *funcs; + + struct fd_bo_cache bo_cache; + struct fd_bo_cache ring_cache; + + int closefd; /* call close(fd) upon destruction */ + + /* just for valgrind: */ + int bo_size; +}; + +drm_private void fd_bo_cache_init(struct fd_bo_cache *cache, int coarse); +drm_private void fd_bo_cache_cleanup(struct fd_bo_cache *cache, time_t time); +drm_private struct fd_bo * fd_bo_cache_alloc(struct fd_bo_cache *cache, + uint32_t *size, uint32_t flags); +drm_private int fd_bo_cache_free(struct fd_bo_cache *cache, struct fd_bo *bo); + +/* for where @table_lock is already held: */ +drm_private void fd_device_del_locked(struct fd_device *dev); + +struct fd_pipe_funcs { + struct fd_ringbuffer * (*ringbuffer_new)(struct fd_pipe *pipe, uint32_t size, + enum fd_ringbuffer_flags flags); + int (*get_param)(struct fd_pipe *pipe, enum fd_param_id param, uint64_t *value); + int (*wait)(struct fd_pipe *pipe, uint32_t timestamp, uint64_t timeout); + void (*destroy)(struct fd_pipe *pipe); +}; + +struct fd_pipe { + struct fd_device *dev; + enum fd_pipe_id id; + uint32_t gpu_id; + atomic_t refcnt; + const struct fd_pipe_funcs *funcs; +}; + +struct fd_ringbuffer_funcs { + void * (*hostptr)(struct fd_ringbuffer *ring); + int (*flush)(struct fd_ringbuffer *ring, uint32_t *last_start, + int in_fence_fd, int *out_fence_fd); + void (*grow)(struct fd_ringbuffer *ring, uint32_t size); + void (*reset)(struct fd_ringbuffer *ring); + void (*emit_reloc)(struct fd_ringbuffer *ring, + const struct fd_reloc *reloc); + uint32_t (*emit_reloc_ring)(struct fd_ringbuffer *ring, + struct fd_ringbuffer *target, uint32_t cmd_idx); + uint32_t (*cmd_count)(struct fd_ringbuffer *ring); + void (*destroy)(struct fd_ringbuffer *ring); +}; + +struct fd_bo_funcs { + int (*offset)(struct fd_bo *bo, uint64_t *offset); + int (*cpu_prep)(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op); + void (*cpu_fini)(struct fd_bo *bo); + int (*madvise)(struct fd_bo *bo, int willneed); + uint64_t (*iova)(struct fd_bo *bo); + void (*destroy)(struct fd_bo *bo); +}; + +struct fd_bo { + struct fd_device *dev; + uint32_t size; + uint32_t handle; + uint32_t name; + void *map; + atomic_t refcnt; + const struct fd_bo_funcs *funcs; + + enum { + NO_CACHE = 0, + BO_CACHE = 1, + RING_CACHE = 2, + } bo_reuse; + + struct list_head list; /* bucket-list entry */ + time_t free_time; /* time when added to bucket-list */ +}; + +drm_private struct fd_bo *fd_bo_new_ring(struct fd_device *dev, + uint32_t size, uint32_t flags); + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +#define enable_debug 0 /* TODO make dynamic */ + +#define INFO_MSG(fmt, ...) \ + do { drmMsg("[I] "fmt " (%s:%d)\n", \ + ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) +#define DEBUG_MSG(fmt, ...) \ + do if (enable_debug) { drmMsg("[D] "fmt " (%s:%d)\n", \ + ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) +#define WARN_MSG(fmt, ...) \ + do { drmMsg("[W] "fmt " (%s:%d)\n", \ + ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) +#define ERROR_MSG(fmt, ...) \ + do { drmMsg("[E] " fmt " (%s:%d)\n", \ + ##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0) + +#define U642VOID(x) ((void *)(unsigned long)(x)) +#define VOID2U64(x) ((uint64_t)(unsigned long)(x)) + +static inline uint32_t +offset_bytes(void *end, void *start) +{ + return ((char *)end) - ((char *)start); +} + +#if HAVE_VALGRIND +# include + +/* + * For tracking the backing memory (if valgrind enabled, we force a mmap + * for the purposes of tracking) + */ +static inline void VG_BO_ALLOC(struct fd_bo *bo) +{ + if (bo && RUNNING_ON_VALGRIND) { + VALGRIND_MALLOCLIKE_BLOCK(fd_bo_map(bo), bo->size, 0, 1); + } +} + +static inline void VG_BO_FREE(struct fd_bo *bo) +{ + VALGRIND_FREELIKE_BLOCK(bo->map, 0); +} + +/* + * For tracking bo structs that are in the buffer-cache, so that valgrind + * doesn't attribute ownership to the first one to allocate the recycled + * bo. + * + * Note that the list_head in fd_bo is used to track the buffers in cache + * so disable error reporting on the range while they are in cache so + * valgrind doesn't squawk about list traversal. + * + */ +static inline void VG_BO_RELEASE(struct fd_bo *bo) +{ + if (RUNNING_ON_VALGRIND) { + VALGRIND_DISABLE_ADDR_ERROR_REPORTING_IN_RANGE(bo, bo->dev->bo_size); + VALGRIND_MAKE_MEM_NOACCESS(bo, bo->dev->bo_size); + VALGRIND_FREELIKE_BLOCK(bo->map, 0); + } +} +static inline void VG_BO_OBTAIN(struct fd_bo *bo) +{ + if (RUNNING_ON_VALGRIND) { + VALGRIND_MAKE_MEM_DEFINED(bo, bo->dev->bo_size); + VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(bo, bo->dev->bo_size); + VALGRIND_MALLOCLIKE_BLOCK(bo->map, bo->size, 0, 1); + } +} +#else +static inline void VG_BO_ALLOC(struct fd_bo *bo) {} +static inline void VG_BO_FREE(struct fd_bo *bo) {} +static inline void VG_BO_RELEASE(struct fd_bo *bo) {} +static inline void VG_BO_OBTAIN(struct fd_bo *bo) {} +#endif + + +#endif /* FREEDRENO_PRIV_H_ */ diff --git a/freedreno/freedreno_ringbuffer.c b/freedreno/freedreno_ringbuffer.c new file mode 100644 index 0000000..8f0093a --- /dev/null +++ b/freedreno/freedreno_ringbuffer.c @@ -0,0 +1,182 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2012 Rob Clark + * + * 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 (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 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. + * + * Authors: + * Rob Clark + */ + +#include + +#include "freedreno_drmif.h" +#include "freedreno_priv.h" +#include "freedreno_ringbuffer.h" + +drm_public struct fd_ringbuffer * +fd_ringbuffer_new_flags(struct fd_pipe *pipe, uint32_t size, + enum fd_ringbuffer_flags flags) +{ + struct fd_ringbuffer *ring; + + /* we can't really support "growable" rb's in general for + * stateobj's since we need a single gpu addr (ie. can't + * do the trick of a chain of IB packets): + */ + if (flags & FD_RINGBUFFER_OBJECT) + assert(size); + + ring = pipe->funcs->ringbuffer_new(pipe, size, flags); + if (!ring) + return NULL; + + ring->flags = flags; + ring->pipe = pipe; + ring->start = ring->funcs->hostptr(ring); + ring->end = &(ring->start[ring->size/4]); + + ring->cur = ring->last_start = ring->start; + + return ring; +} + +drm_public struct fd_ringbuffer * +fd_ringbuffer_new(struct fd_pipe *pipe, uint32_t size) +{ + return fd_ringbuffer_new_flags(pipe, size, 0); +} + +drm_public struct fd_ringbuffer * +fd_ringbuffer_new_object(struct fd_pipe *pipe, uint32_t size) +{ + return fd_ringbuffer_new_flags(pipe, size, FD_RINGBUFFER_OBJECT); +} + +drm_public void fd_ringbuffer_del(struct fd_ringbuffer *ring) +{ + if (!atomic_dec_and_test(&ring->refcnt)) + return; + + fd_ringbuffer_reset(ring); + ring->funcs->destroy(ring); +} + +drm_public struct fd_ringbuffer * +fd_ringbuffer_ref(struct fd_ringbuffer *ring) +{ + STATIC_ASSERT(sizeof(ring->refcnt) <= sizeof(ring->__pad)); + atomic_inc(&ring->refcnt); + return ring; +} + +/* ringbuffers which are IB targets should set the toplevel rb (ie. + * the IB source) as it's parent before emitting reloc's, to ensure + * the bookkeeping works out properly. + */ +drm_public void fd_ringbuffer_set_parent(struct fd_ringbuffer *ring, + struct fd_ringbuffer *parent) +{ + /* state objects should not be parented! */ + assert(!(ring->flags & FD_RINGBUFFER_OBJECT)); + ring->parent = parent; +} + +drm_public void fd_ringbuffer_reset(struct fd_ringbuffer *ring) +{ + uint32_t *start = ring->start; + if (ring->pipe->id == FD_PIPE_2D) + start = &ring->start[0x140]; + ring->cur = ring->last_start = start; + if (ring->funcs->reset) + ring->funcs->reset(ring); +} + +drm_public int fd_ringbuffer_flush(struct fd_ringbuffer *ring) +{ + return ring->funcs->flush(ring, ring->last_start, -1, NULL); +} + +drm_public int fd_ringbuffer_flush2(struct fd_ringbuffer *ring, int in_fence_fd, + int *out_fence_fd) +{ + return ring->funcs->flush(ring, ring->last_start, in_fence_fd, out_fence_fd); +} + +drm_public void fd_ringbuffer_grow(struct fd_ringbuffer *ring, uint32_t ndwords) +{ + assert(ring->funcs->grow); /* unsupported on kgsl */ + + /* there is an upper bound on IB size, which appears to be 0x100000 */ + if (ring->size < 0x100000) + ring->size *= 2; + + ring->funcs->grow(ring, ring->size); + + ring->start = ring->funcs->hostptr(ring); + ring->end = &(ring->start[ring->size/4]); + + ring->cur = ring->last_start = ring->start; +} + +drm_public uint32_t fd_ringbuffer_timestamp(struct fd_ringbuffer *ring) +{ + return ring->last_timestamp; +} + +drm_public void fd_ringbuffer_reloc(struct fd_ringbuffer *ring, + const struct fd_reloc *reloc) +{ + assert(ring->pipe->gpu_id < 500); + ring->funcs->emit_reloc(ring, reloc); +} + +drm_public void fd_ringbuffer_reloc2(struct fd_ringbuffer *ring, + const struct fd_reloc *reloc) +{ + ring->funcs->emit_reloc(ring, reloc); +} + +drm_public uint32_t fd_ringbuffer_cmd_count(struct fd_ringbuffer *ring) +{ + if (!ring->funcs->cmd_count) + return 1; + return ring->funcs->cmd_count(ring); +} + +drm_public uint32_t +fd_ringbuffer_emit_reloc_ring_full(struct fd_ringbuffer *ring, + struct fd_ringbuffer *target, uint32_t cmd_idx) +{ + return ring->funcs->emit_reloc_ring(ring, target, cmd_idx); +} + +drm_public uint32_t +fd_ringbuffer_size(struct fd_ringbuffer *ring) +{ + /* only really needed for stateobj ringbuffers, and won't really + * do what you expect for growable rb's.. so lets just restrict + * this to stateobj's for now: + */ + assert(ring->flags & FD_RINGBUFFER_OBJECT); + return offset_bytes(ring->cur, ring->start); +} + diff --git a/freedreno/freedreno_ringbuffer.h b/freedreno/freedreno_ringbuffer.h new file mode 100644 index 0000000..bc41a31 --- /dev/null +++ b/freedreno/freedreno_ringbuffer.h @@ -0,0 +1,142 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2012 Rob Clark + * + * 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 (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 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. + * + * Authors: + * Rob Clark + */ + +#ifndef FREEDRENO_RINGBUFFER_H_ +#define FREEDRENO_RINGBUFFER_H_ + +#include + +/* the ringbuffer object is not opaque so that OUT_RING() type stuff + * can be inlined. Note that users should not make assumptions about + * the size of this struct. + */ + +struct fd_ringbuffer_funcs; + +enum fd_ringbuffer_flags { + + /* Ringbuffer is a "state object", which is potentially reused + * many times, rather than being used in one-shot mode linked + * to a parent ringbuffer. + */ + FD_RINGBUFFER_OBJECT = 0x1, + + /* Hint that the stateobj will be used for streaming state + * that is used once or a few times and then discarded. + * + * For sub-allocation, non streaming stateobj's should be + * sub-allocated from a page size buffer, so one long lived + * state obj doesn't prevent other pages from being freed. + * (Ie. it would be no worse than allocating a page sized + * bo for each small non-streaming stateobj). + * + * But streaming stateobj's could be sub-allocated from a + * larger buffer to reduce the alloc/del overhead. + */ + FD_RINGBUFFER_STREAMING = 0x2, +}; + +struct fd_ringbuffer { + int size; + uint32_t *cur, *end, *start, *last_start; + struct fd_pipe *pipe; + const struct fd_ringbuffer_funcs *funcs; + uint32_t last_timestamp; + struct fd_ringbuffer *parent; + + /* for users of fd_ringbuffer to store their own private per- + * ringbuffer data + */ + void *user; + + enum fd_ringbuffer_flags flags; + + /* This is a bit gross, but we can't use atomic_t in exported + * headers. OTOH, we don't need the refcnt to be publicly + * visible. The only reason that this struct is exported is + * because fd_ringbuffer_emit needs to be something that can + * be inlined for performance reasons. + */ + union { +#ifdef HAS_ATOMIC_OPS + atomic_t refcnt; +#endif + uint64_t __pad; + }; +}; + +struct fd_ringbuffer * fd_ringbuffer_new(struct fd_pipe *pipe, + uint32_t size); +will_be_deprecated +struct fd_ringbuffer * fd_ringbuffer_new_object(struct fd_pipe *pipe, + uint32_t size); +struct fd_ringbuffer * fd_ringbuffer_new_flags(struct fd_pipe *pipe, + uint32_t size, enum fd_ringbuffer_flags flags); + +struct fd_ringbuffer *fd_ringbuffer_ref(struct fd_ringbuffer *ring); +void fd_ringbuffer_del(struct fd_ringbuffer *ring); +void fd_ringbuffer_set_parent(struct fd_ringbuffer *ring, + struct fd_ringbuffer *parent); +will_be_deprecated +void fd_ringbuffer_reset(struct fd_ringbuffer *ring); +int fd_ringbuffer_flush(struct fd_ringbuffer *ring); +/* in_fence_fd: -1 for no in-fence, else fence fd + * out_fence_fd: NULL for no output-fence requested, else ptr to return out-fence + */ +int fd_ringbuffer_flush2(struct fd_ringbuffer *ring, int in_fence_fd, + int *out_fence_fd); +void fd_ringbuffer_grow(struct fd_ringbuffer *ring, uint32_t ndwords); +uint32_t fd_ringbuffer_timestamp(struct fd_ringbuffer *ring); + +static inline void fd_ringbuffer_emit(struct fd_ringbuffer *ring, + uint32_t data) +{ + (*ring->cur++) = data; +} + +struct fd_reloc { + struct fd_bo *bo; +#define FD_RELOC_READ 0x0001 +#define FD_RELOC_WRITE 0x0002 + uint32_t flags; + uint32_t offset; + uint32_t or; + int32_t shift; + uint32_t orhi; /* used for a5xx+ */ +}; + +/* NOTE: relocs are 2 dwords on a5xx+ */ + +void fd_ringbuffer_reloc2(struct fd_ringbuffer *ring, const struct fd_reloc *reloc); +will_be_deprecated void fd_ringbuffer_reloc(struct fd_ringbuffer *ring, const struct fd_reloc *reloc); +uint32_t fd_ringbuffer_cmd_count(struct fd_ringbuffer *ring); +uint32_t fd_ringbuffer_emit_reloc_ring_full(struct fd_ringbuffer *ring, + struct fd_ringbuffer *target, uint32_t cmd_idx); +uint32_t fd_ringbuffer_size(struct fd_ringbuffer *ring); + +#endif /* FREEDRENO_RINGBUFFER_H_ */ diff --git a/freedreno/kgsl/README b/freedreno/kgsl/README new file mode 100644 index 0000000..c46ba08 --- /dev/null +++ b/freedreno/kgsl/README @@ -0,0 +1,26 @@ +This is a historical description of what is now the kgsl backend +in libdrm freedreno (before the upstream drm/msm driver). Note +that the kgsl backend requires the "kgsl-drm" shim driver, which +usually is in disrepair (QCOM does not build it for android), and +due to random differences between different downstream android +kernel branches it may or may not work. So YMMV. + +Original README: +---------------- + +Note that current msm kernel driver is a bit strange. It provides a +DRM interface for GEM, which is basically sufficient to have DRI2 +working. But it does not provide KMS. And interface to 2d and 3d +cores is via different other devices (/dev/kgsl-*). This is not +quite how I'd write a DRM driver, but at this stage it is useful for +xf86-video-freedreno and fdre (and eventual gallium driver) to be +able to work on existing kernel driver from QCOM, to allow to +capture cmdstream dumps from the binary blob drivers without having +to reboot. So libdrm_freedreno attempts to hide most of the crazy. +The intention is that when there is a proper kernel driver, it will +be mostly just changes in libdrm_freedreno to adapt the gallium +driver and xf86-video-freedreno (ignoring the fbdev->KMS changes). + +So don't look at freedreno as an example of how to write a libdrm +module or a DRM driver.. it is just an attempt to paper over a non- +standard kernel driver architecture. diff --git a/freedreno/kgsl/kgsl_bo.c b/freedreno/kgsl/kgsl_bo.c new file mode 100644 index 0000000..7a6af2f --- /dev/null +++ b/freedreno/kgsl/kgsl_bo.c @@ -0,0 +1,311 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2013 Rob Clark + * + * 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 (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 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. + * + * Authors: + * Rob Clark + */ + +#include "kgsl_priv.h" + +#include + +static int set_memtype(struct fd_device *dev, uint32_t handle, uint32_t flags) +{ + struct drm_kgsl_gem_memtype req = { + .handle = handle, + .type = flags & DRM_FREEDRENO_GEM_TYPE_MEM_MASK, + }; + + return drmCommandWrite(dev->fd, DRM_KGSL_GEM_SETMEMTYPE, + &req, sizeof(req)); +} + +static int bo_alloc(struct kgsl_bo *kgsl_bo) +{ + struct fd_bo *bo = &kgsl_bo->base; + if (!kgsl_bo->offset) { + struct drm_kgsl_gem_alloc req = { + .handle = bo->handle, + }; + int ret; + + /* if the buffer is already backed by pages then this + * doesn't actually do anything (other than giving us + * the offset) + */ + ret = drmCommandWriteRead(bo->dev->fd, DRM_KGSL_GEM_ALLOC, + &req, sizeof(req)); + if (ret) { + ERROR_MSG("alloc failed: %s", strerror(errno)); + return ret; + } + + kgsl_bo->offset = req.offset; + } + + return 0; +} + +static int kgsl_bo_offset(struct fd_bo *bo, uint64_t *offset) +{ + struct kgsl_bo *kgsl_bo = to_kgsl_bo(bo); + int ret = bo_alloc(kgsl_bo); + if (ret) + return ret; + *offset = kgsl_bo->offset; + return 0; +} + +static int kgsl_bo_cpu_prep(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op) +{ + uint32_t timestamp = kgsl_bo_get_timestamp(to_kgsl_bo(bo)); + + if (op & DRM_FREEDRENO_PREP_NOSYNC) { + uint32_t current; + int ret; + + /* special case for is_idle().. we can't really handle that + * properly in kgsl (perhaps we need a way to just disable + * the bo-cache for kgsl?) + */ + if (!pipe) + return -EBUSY; + + ret = kgsl_pipe_timestamp(to_kgsl_pipe(pipe), ¤t); + if (ret) + return ret; + + if (timestamp > current) + return -EBUSY; + + return 0; + } + + if (timestamp) + fd_pipe_wait(pipe, timestamp); + + return 0; +} + +static void kgsl_bo_cpu_fini(struct fd_bo *bo) +{ +} + +static int kgsl_bo_madvise(struct fd_bo *bo, int willneed) +{ + return willneed; /* not supported by kgsl */ +} + +static void kgsl_bo_destroy(struct fd_bo *bo) +{ + struct kgsl_bo *kgsl_bo = to_kgsl_bo(bo); + free(kgsl_bo); + +} + +static const struct fd_bo_funcs funcs = { + .offset = kgsl_bo_offset, + .cpu_prep = kgsl_bo_cpu_prep, + .cpu_fini = kgsl_bo_cpu_fini, + .madvise = kgsl_bo_madvise, + .destroy = kgsl_bo_destroy, +}; + +/* allocate a buffer handle: */ +drm_private int kgsl_bo_new_handle(struct fd_device *dev, + uint32_t size, uint32_t flags, uint32_t *handle) +{ + struct drm_kgsl_gem_create req = { + .size = size, + }; + int ret; + + ret = drmCommandWriteRead(dev->fd, DRM_KGSL_GEM_CREATE, + &req, sizeof(req)); + if (ret) + return ret; + + // TODO make flags match msm driver, since kgsl is legacy.. + // translate flags in kgsl.. + + set_memtype(dev, req.handle, flags); + + *handle = req.handle; + + return 0; +} + +/* allocate a new buffer object */ +drm_private struct fd_bo * kgsl_bo_from_handle(struct fd_device *dev, + uint32_t size, uint32_t handle) +{ + struct kgsl_bo *kgsl_bo; + struct fd_bo *bo; + unsigned i; + + kgsl_bo = calloc(1, sizeof(*kgsl_bo)); + if (!kgsl_bo) + return NULL; + + bo = &kgsl_bo->base; + bo->funcs = &funcs; + + for (i = 0; i < ARRAY_SIZE(kgsl_bo->list); i++) + list_inithead(&kgsl_bo->list[i]); + + return bo; +} + +drm_public struct fd_bo * +fd_bo_from_fbdev(struct fd_pipe *pipe, int fbfd, uint32_t size) +{ + struct fd_bo *bo; + + if (!is_kgsl_pipe(pipe)) + return NULL; + + bo = fd_bo_new(pipe->dev, 1, 0); + + /* this is fugly, but works around a bug in the kernel.. + * priv->memdesc.size never gets set, so getbufinfo ioctl + * thinks the buffer hasn't be allocate and fails + */ + if (bo) { + void *fbmem = drm_mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_SHARED, fbfd, 0); + struct kgsl_map_user_mem req = { + .memtype = KGSL_USER_MEM_TYPE_ADDR, + .len = size, + .offset = 0, + .hostptr = (unsigned long)fbmem, + }; + struct kgsl_bo *kgsl_bo = to_kgsl_bo(bo); + int ret; + + ret = ioctl(to_kgsl_pipe(pipe)->fd, IOCTL_KGSL_MAP_USER_MEM, &req); + if (ret) { + ERROR_MSG("mapping user mem failed: %s", + strerror(errno)); + goto fail; + } + kgsl_bo->gpuaddr = req.gpuaddr; + bo->map = fbmem; + } + + return bo; +fail: + if (bo) + fd_bo_del(bo); + return NULL; +} + +drm_private uint32_t kgsl_bo_gpuaddr(struct kgsl_bo *kgsl_bo, uint32_t offset) +{ + struct fd_bo *bo = &kgsl_bo->base; + if (!kgsl_bo->gpuaddr) { + struct drm_kgsl_gem_bufinfo req = { + .handle = bo->handle, + }; + int ret; + + ret = bo_alloc(kgsl_bo); + if (ret) { + return ret; + } + + ret = drmCommandWriteRead(bo->dev->fd, DRM_KGSL_GEM_GET_BUFINFO, + &req, sizeof(req)); + if (ret) { + ERROR_MSG("get bufinfo failed: %s", strerror(errno)); + return 0; + } + + kgsl_bo->gpuaddr = req.gpuaddr[0]; + } + return kgsl_bo->gpuaddr + offset; +} + +/* + * Super-cheezy way to synchronization between mesa and ddx.. the + * SET_ACTIVE ioctl gives us a way to stash a 32b # w/ a GEM bo, and + * GET_BUFINFO gives us a way to retrieve it. We use this to stash + * the timestamp of the last ISSUEIBCMDS on the buffer. + * + * To avoid an obscene amount of syscalls, we: + * 1) Only set the timestamp for buffers w/ an flink name, ie. + * only buffers shared across processes. This is enough to + * catch the DRI2 buffers. + * 2) Only set the timestamp for buffers submitted to the 3d ring + * and only check the timestamps on buffers submitted to the + * 2d ring. This should be enough to handle synchronizing of + * presentation blit. We could do synchronization in the other + * direction too, but that would be problematic if we are using + * the 3d ring from DDX, since client side wouldn't know this. + * + * The waiting on timestamp happens before flush, and setting of + * timestamp happens after flush. It is transparent to the user + * of libdrm_freedreno as all the tracking of buffers happens via + * _emit_reloc().. + */ + +drm_private void kgsl_bo_set_timestamp(struct kgsl_bo *kgsl_bo, + uint32_t timestamp) +{ + struct fd_bo *bo = &kgsl_bo->base; + if (bo->name) { + struct drm_kgsl_gem_active req = { + .handle = bo->handle, + .active = timestamp, + }; + int ret; + + ret = drmCommandWrite(bo->dev->fd, DRM_KGSL_GEM_SET_ACTIVE, + &req, sizeof(req)); + if (ret) { + ERROR_MSG("set active failed: %s", strerror(errno)); + } + } +} + +drm_private uint32_t kgsl_bo_get_timestamp(struct kgsl_bo *kgsl_bo) +{ + struct fd_bo *bo = &kgsl_bo->base; + uint32_t timestamp = 0; + if (bo->name) { + struct drm_kgsl_gem_bufinfo req = { + .handle = bo->handle, + }; + int ret; + + ret = drmCommandWriteRead(bo->dev->fd, DRM_KGSL_GEM_GET_BUFINFO, + &req, sizeof(req)); + if (ret) { + ERROR_MSG("get bufinfo failed: %s", strerror(errno)); + return 0; + } + + timestamp = req.active; + } + return timestamp; +} diff --git a/freedreno/kgsl/kgsl_device.c b/freedreno/kgsl/kgsl_device.c new file mode 100644 index 0000000..914f341 --- /dev/null +++ b/freedreno/kgsl/kgsl_device.c @@ -0,0 +1,63 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2013 Rob Clark + * + * 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 (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 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. + * + * Authors: + * Rob Clark + */ + +#include +#include +#include + +#include "kgsl_priv.h" + +static void kgsl_device_destroy(struct fd_device *dev) +{ + struct kgsl_device *kgsl_dev = to_kgsl_device(dev); + free(kgsl_dev); +} + +static const struct fd_device_funcs funcs = { + .bo_new_handle = kgsl_bo_new_handle, + .bo_from_handle = kgsl_bo_from_handle, + .pipe_new = kgsl_pipe_new, + .destroy = kgsl_device_destroy, +}; + +drm_private struct fd_device * kgsl_device_new(int fd) +{ + struct kgsl_device *kgsl_dev; + struct fd_device *dev; + + kgsl_dev = calloc(1, sizeof(*kgsl_dev)); + if (!kgsl_dev) + return NULL; + + dev = &kgsl_dev->base; + dev->funcs = &funcs; + + dev->bo_size = sizeof(struct kgsl_bo); + + return dev; +} diff --git a/freedreno/kgsl/kgsl_drm.h b/freedreno/kgsl/kgsl_drm.h new file mode 100644 index 0000000..281978e --- /dev/null +++ b/freedreno/kgsl/kgsl_drm.h @@ -0,0 +1,192 @@ +#ifndef _KGSL_DRM_H_ +#define _KGSL_DRM_H_ + +#include "drm.h" + +#define DRM_KGSL_GEM_CREATE 0x00 +#define DRM_KGSL_GEM_PREP 0x01 +#define DRM_KGSL_GEM_SETMEMTYPE 0x02 +#define DRM_KGSL_GEM_GETMEMTYPE 0x03 +#define DRM_KGSL_GEM_MMAP 0x04 +#define DRM_KGSL_GEM_ALLOC 0x05 +#define DRM_KGSL_GEM_BIND_GPU 0x06 +#define DRM_KGSL_GEM_UNBIND_GPU 0x07 + +#define DRM_KGSL_GEM_GET_BUFINFO 0x08 +#define DRM_KGSL_GEM_SET_BUFCOUNT 0x09 +#define DRM_KGSL_GEM_SET_ACTIVE 0x0A +#define DRM_KGSL_GEM_LOCK_HANDLE 0x0B +#define DRM_KGSL_GEM_UNLOCK_HANDLE 0x0C +#define DRM_KGSL_GEM_UNLOCK_ON_TS 0x0D +#define DRM_KGSL_GEM_CREATE_FD 0x0E + +#define DRM_IOCTL_KGSL_GEM_CREATE \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_CREATE, struct drm_kgsl_gem_create) + +#define DRM_IOCTL_KGSL_GEM_PREP \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_PREP, struct drm_kgsl_gem_prep) + +#define DRM_IOCTL_KGSL_GEM_SETMEMTYPE \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_SETMEMTYPE, \ +struct drm_kgsl_gem_memtype) + +#define DRM_IOCTL_KGSL_GEM_GETMEMTYPE \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_GETMEMTYPE, \ +struct drm_kgsl_gem_memtype) + +#define DRM_IOCTL_KGSL_GEM_MMAP \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_MMAP, struct drm_kgsl_gem_mmap) + +#define DRM_IOCTL_KGSL_GEM_ALLOC \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_ALLOC, struct drm_kgsl_gem_alloc) + +#define DRM_IOCTL_KGSL_GEM_BIND_GPU \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_BIND_GPU, struct drm_kgsl_gem_bind_gpu) + +#define DRM_IOCTL_KGSL_GEM_UNBIND_GPU \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_UNBIND_GPU, \ +struct drm_kgsl_gem_bind_gpu) + +#define DRM_IOCTL_KGSL_GEM_GET_BUFINFO \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_GET_BUFINFO, \ + struct drm_kgsl_gem_bufinfo) + +#define DRM_IOCTL_KGSL_GEM_SET_BUFCOUNT \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_SET_BUFCOUNT, \ + struct drm_kgsl_gem_bufcount) + +#define DRM_IOCTL_KGSL_GEM_SET_ACTIVE \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_SET_ACTIVE, \ + struct drm_kgsl_gem_active) + +#define DRM_IOCTL_KGSL_GEM_LOCK_HANDLE \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_LOCK_HANDLE, \ +struct drm_kgsl_gem_lock_handles) + +#define DRM_IOCTL_KGSL_GEM_UNLOCK_HANDLE \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_UNLOCK_HANDLE, \ +struct drm_kgsl_gem_unlock_handles) + +#define DRM_IOCTL_KGSL_GEM_UNLOCK_ON_TS \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_UNLOCK_ON_TS, \ +struct drm_kgsl_gem_unlock_on_ts) + +#define DRM_IOCTL_KGSL_GEM_CREATE_FD \ +DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_CREATE_FD, \ +struct drm_kgsl_gem_create_fd) + +/* Maximum number of sub buffers per GEM object */ +#define DRM_KGSL_GEM_MAX_BUFFERS 2 + +/* Memory types - these define the source and caching policies + of the GEM memory chunk */ + +/* Legacy definitions left for compatibility */ + +#define DRM_KGSL_GEM_TYPE_EBI 0 +#define DRM_KGSL_GEM_TYPE_SMI 1 +#define DRM_KGSL_GEM_TYPE_KMEM 2 +#define DRM_KGSL_GEM_TYPE_KMEM_NOCACHE 3 +#define DRM_KGSL_GEM_TYPE_MEM_MASK 0xF + +/* Contiguous memory (PMEM) */ +#define DRM_KGSL_GEM_TYPE_PMEM 0x000100 + +/* PMEM memory types */ +#define DRM_KGSL_GEM_PMEM_EBI 0x001000 +#define DRM_KGSL_GEM_PMEM_SMI 0x002000 + +/* Standard paged memory */ +#define DRM_KGSL_GEM_TYPE_MEM 0x010000 + +/* Caching controls */ +#define DRM_KGSL_GEM_CACHE_NONE 0x000000 +#define DRM_KGSL_GEM_CACHE_WCOMBINE 0x100000 +#define DRM_KGSL_GEM_CACHE_WTHROUGH 0x200000 +#define DRM_KGSL_GEM_CACHE_WBACK 0x400000 +#define DRM_KGSL_GEM_CACHE_WBACKWA 0x800000 +#define DRM_KGSL_GEM_CACHE_MASK 0xF00000 + +/* FD based objects */ +#define DRM_KGSL_GEM_TYPE_FD_FBMEM 0x1000000 +#define DRM_KGSL_GEM_TYPE_FD_MASK 0xF000000 + +/* Timestamp types */ +#define DRM_KGSL_GEM_TS_3D 0x00000430 +#define DRM_KGSL_GEM_TS_2D 0x00000180 + + +struct drm_kgsl_gem_create { + uint32_t size; + uint32_t handle; +}; + +struct drm_kgsl_gem_prep { + uint32_t handle; + uint32_t phys; + uint64_t offset; +}; + +struct drm_kgsl_gem_memtype { + uint32_t handle; + uint32_t type; +}; + +struct drm_kgsl_gem_mmap { + uint32_t handle; + uint32_t size; + uint32_t hostptr; + uint64_t offset; +}; + +struct drm_kgsl_gem_alloc { + uint32_t handle; + uint64_t offset; +}; + +struct drm_kgsl_gem_bind_gpu { + uint32_t handle; + uint32_t gpuptr; +}; + +struct drm_kgsl_gem_bufinfo { + uint32_t handle; + uint32_t count; + uint32_t active; + uint32_t offset[DRM_KGSL_GEM_MAX_BUFFERS]; + uint32_t gpuaddr[DRM_KGSL_GEM_MAX_BUFFERS]; +}; + +struct drm_kgsl_gem_bufcount { + uint32_t handle; + uint32_t bufcount; +}; + +struct drm_kgsl_gem_active { + uint32_t handle; + uint32_t active; +}; + +struct drm_kgsl_gem_lock_handles { + uint32_t num_handles; + uint32_t *handle_list; + uint32_t pid; + uint32_t lock_id; /* Returned lock id used for unlocking */ +}; + +struct drm_kgsl_gem_unlock_handles { + uint32_t lock_id; +}; + +struct drm_kgsl_gem_unlock_on_ts { + uint32_t lock_id; + uint32_t timestamp; /* This field is a hw generated ts */ + uint32_t type; /* Which pipe to check for ts generation */ +}; + +struct drm_kgsl_gem_create_fd { + uint32_t fd; + uint32_t handle; +}; + +#endif diff --git a/freedreno/kgsl/kgsl_pipe.c b/freedreno/kgsl/kgsl_pipe.c new file mode 100644 index 0000000..0a8b658 --- /dev/null +++ b/freedreno/kgsl/kgsl_pipe.c @@ -0,0 +1,282 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2013 Rob Clark + * + * 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 (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 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. + * + * Authors: + * Rob Clark + */ + +#include "kgsl_priv.h" + + +static int kgsl_pipe_get_param(struct fd_pipe *pipe, + enum fd_param_id param, uint64_t *value) +{ + struct kgsl_pipe *kgsl_pipe = to_kgsl_pipe(pipe); + switch (param) { + case FD_DEVICE_ID: + *value = kgsl_pipe->devinfo.device_id; + return 0; + case FD_GPU_ID: + *value = kgsl_pipe->devinfo.gpu_id; + return 0; + case FD_GMEM_SIZE: + *value = kgsl_pipe->devinfo.gmem_sizebytes; + return 0; + case FD_CHIP_ID: + *value = kgsl_pipe->devinfo.chip_id; + return 0; + case FD_MAX_FREQ: + case FD_TIMESTAMP: + case FD_NR_RINGS: + /* unsupported on kgsl */ + return -1; + default: + ERROR_MSG("invalid param id: %d", param); + return -1; + } +} + +static int kgsl_pipe_wait(struct fd_pipe *pipe, uint32_t timestamp, + uint64_t timeout) +{ + struct kgsl_pipe *kgsl_pipe = to_kgsl_pipe(pipe); + struct kgsl_device_waittimestamp req = { + .timestamp = timestamp, + .timeout = 5000, + }; + int ret; + + do { + ret = ioctl(kgsl_pipe->fd, IOCTL_KGSL_DEVICE_WAITTIMESTAMP, &req); + } while ((ret == -1) && ((errno == EINTR) || (errno == EAGAIN))); + if (ret) + ERROR_MSG("waittimestamp failed! %d (%s)", ret, strerror(errno)); + else + kgsl_pipe_process_pending(kgsl_pipe, timestamp); + return ret; +} + +drm_private int kgsl_pipe_timestamp(struct kgsl_pipe *kgsl_pipe, + uint32_t *timestamp) +{ + struct kgsl_cmdstream_readtimestamp req = { + .type = KGSL_TIMESTAMP_RETIRED + }; + int ret = ioctl(kgsl_pipe->fd, IOCTL_KGSL_CMDSTREAM_READTIMESTAMP, &req); + if (ret) { + ERROR_MSG("readtimestamp failed! %d (%s)", + ret, strerror(errno)); + return ret; + } + *timestamp = req.timestamp; + return 0; +} + +static void kgsl_pipe_destroy(struct fd_pipe *pipe) +{ + struct kgsl_pipe *kgsl_pipe = to_kgsl_pipe(pipe); + struct kgsl_drawctxt_destroy req = { + .drawctxt_id = kgsl_pipe->drawctxt_id, + }; + + if (kgsl_pipe->drawctxt_id) + ioctl(kgsl_pipe->fd, IOCTL_KGSL_DRAWCTXT_DESTROY, &req); + + if (kgsl_pipe->fd >= 0) + close(kgsl_pipe->fd); + + free(kgsl_pipe); +} + +static const struct fd_pipe_funcs funcs = { + .ringbuffer_new = kgsl_ringbuffer_new, + .get_param = kgsl_pipe_get_param, + .wait = kgsl_pipe_wait, + .destroy = kgsl_pipe_destroy, +}; + +drm_private int is_kgsl_pipe(struct fd_pipe *pipe) +{ + return pipe->funcs == &funcs; +} + +/* add buffer to submit list when it is referenced in cmdstream: */ +drm_private void kgsl_pipe_add_submit(struct kgsl_pipe *kgsl_pipe, + struct kgsl_bo *kgsl_bo) +{ + struct fd_pipe *pipe = &kgsl_pipe->base; + struct fd_bo *bo = &kgsl_bo->base; + struct list_head *list = &kgsl_bo->list[pipe->id]; + if (LIST_IS_EMPTY(list)) { + fd_bo_ref(bo); + } else { + list_del(list); + } + list_addtail(list, &kgsl_pipe->submit_list); +} + +/* prepare buffers on submit list before flush: */ +drm_private void kgsl_pipe_pre_submit(struct kgsl_pipe *kgsl_pipe) +{ + struct fd_pipe *pipe = &kgsl_pipe->base; + struct kgsl_bo *kgsl_bo = NULL; + + if (!kgsl_pipe->p3d) + kgsl_pipe->p3d = fd_pipe_new(pipe->dev, FD_PIPE_3D); + + LIST_FOR_EACH_ENTRY(kgsl_bo, &kgsl_pipe->submit_list, list[pipe->id]) { + uint32_t timestamp = kgsl_bo_get_timestamp(kgsl_bo); + if (timestamp) + fd_pipe_wait(kgsl_pipe->p3d, timestamp); + } +} + +/* process buffers on submit list after flush: */ +drm_private void kgsl_pipe_post_submit(struct kgsl_pipe *kgsl_pipe, + uint32_t timestamp) +{ + struct fd_pipe *pipe = &kgsl_pipe->base; + struct kgsl_bo *kgsl_bo = NULL, *tmp; + + LIST_FOR_EACH_ENTRY_SAFE(kgsl_bo, tmp, &kgsl_pipe->submit_list, list[pipe->id]) { + struct list_head *list = &kgsl_bo->list[pipe->id]; + list_del(list); + kgsl_bo->timestamp[pipe->id] = timestamp; + list_addtail(list, &kgsl_pipe->pending_list); + + kgsl_bo_set_timestamp(kgsl_bo, timestamp); + } + + if (!kgsl_pipe_timestamp(kgsl_pipe, ×tamp)) + kgsl_pipe_process_pending(kgsl_pipe, timestamp); +} + +drm_private void kgsl_pipe_process_pending(struct kgsl_pipe *kgsl_pipe, + uint32_t timestamp) +{ + struct fd_pipe *pipe = &kgsl_pipe->base; + struct kgsl_bo *kgsl_bo = NULL, *tmp; + + LIST_FOR_EACH_ENTRY_SAFE(kgsl_bo, tmp, &kgsl_pipe->pending_list, list[pipe->id]) { + struct list_head *list = &kgsl_bo->list[pipe->id]; + if (kgsl_bo->timestamp[pipe->id] > timestamp) + return; + list_delinit(list); + kgsl_bo->timestamp[pipe->id] = 0; + fd_bo_del(&kgsl_bo->base); + } +} + +static int getprop(int fd, enum kgsl_property_type type, + void *value, int sizebytes) +{ + struct kgsl_device_getproperty req = { + .type = type, + .value = value, + .sizebytes = sizebytes, + }; + return ioctl(fd, IOCTL_KGSL_DEVICE_GETPROPERTY, &req); +} + +#define GETPROP(fd, prop, x) do { \ + if (getprop((fd), KGSL_PROP_##prop, &(x), sizeof(x))) { \ + ERROR_MSG("failed to get property: " #prop); \ + goto fail; \ + } } while (0) + + +drm_private struct fd_pipe * kgsl_pipe_new(struct fd_device *dev, + enum fd_pipe_id id, uint32_t prio) +{ + static const char *paths[] = { + [FD_PIPE_3D] = "/dev/kgsl-3d0", + [FD_PIPE_2D] = "/dev/kgsl-2d0", + }; + struct kgsl_drawctxt_create req = { + .flags = 0x2000, /* ??? */ + }; + struct kgsl_pipe *kgsl_pipe = NULL; + struct fd_pipe *pipe = NULL; + int ret, fd; + + fd = open(paths[id], O_RDWR); + if (fd < 0) { + ERROR_MSG("could not open %s device: %d (%s)", + paths[id], fd, strerror(errno)); + goto fail; + } + + ret = ioctl(fd, IOCTL_KGSL_DRAWCTXT_CREATE, &req); + if (ret) { + ERROR_MSG("failed to allocate context: %d (%s)", + ret, strerror(errno)); + goto fail; + } + + kgsl_pipe = calloc(1, sizeof(*kgsl_pipe)); + if (!kgsl_pipe) { + ERROR_MSG("allocation failed"); + goto fail; + } + + pipe = &kgsl_pipe->base; + pipe->funcs = &funcs; + + kgsl_pipe->fd = fd; + kgsl_pipe->drawctxt_id = req.drawctxt_id; + + list_inithead(&kgsl_pipe->submit_list); + list_inithead(&kgsl_pipe->pending_list); + + GETPROP(fd, VERSION, kgsl_pipe->version); + GETPROP(fd, DEVICE_INFO, kgsl_pipe->devinfo); + + if (kgsl_pipe->devinfo.gpu_id >= 500) { + ERROR_MSG("64b unsupported with kgsl"); + goto fail; + } + + INFO_MSG("Pipe Info:"); + INFO_MSG(" Device: %s", paths[id]); + INFO_MSG(" Chip-id: %d.%d.%d.%d", + (kgsl_pipe->devinfo.chip_id >> 24) & 0xff, + (kgsl_pipe->devinfo.chip_id >> 16) & 0xff, + (kgsl_pipe->devinfo.chip_id >> 8) & 0xff, + (kgsl_pipe->devinfo.chip_id >> 0) & 0xff); + INFO_MSG(" Device-id: %d", kgsl_pipe->devinfo.device_id); + INFO_MSG(" GPU-id: %d", kgsl_pipe->devinfo.gpu_id); + INFO_MSG(" MMU enabled: %d", kgsl_pipe->devinfo.mmu_enabled); + INFO_MSG(" GMEM Base addr: 0x%08x", kgsl_pipe->devinfo.gmem_gpubaseaddr); + INFO_MSG(" GMEM size: 0x%08x", kgsl_pipe->devinfo.gmem_sizebytes); + INFO_MSG(" Driver version: %d.%d", + kgsl_pipe->version.drv_major, kgsl_pipe->version.drv_minor); + INFO_MSG(" Device version: %d.%d", + kgsl_pipe->version.dev_major, kgsl_pipe->version.dev_minor); + + return pipe; +fail: + if (pipe) + fd_pipe_del(pipe); + return NULL; +} diff --git a/freedreno/kgsl/kgsl_priv.h b/freedreno/kgsl/kgsl_priv.h new file mode 100644 index 0000000..a6bf2d4 --- /dev/null +++ b/freedreno/kgsl/kgsl_priv.h @@ -0,0 +1,120 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2013 Rob Clark + * + * 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 (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 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. + * + * Authors: + * Rob Clark + */ + +#ifndef KGSL_PRIV_H_ +#define KGSL_PRIV_H_ + +#include "freedreno_priv.h" +#include "msm_kgsl.h" +#include "kgsl_drm.h" + +struct kgsl_device { + struct fd_device base; +}; + +static inline struct kgsl_device * to_kgsl_device(struct fd_device *x) +{ + return (struct kgsl_device *)x; +} + +struct kgsl_pipe { + struct fd_pipe base; + + int fd; + uint32_t drawctxt_id; + + /* device properties: */ + struct kgsl_version version; + struct kgsl_devinfo devinfo; + + /* list of bo's that are referenced in ringbuffer but not + * submitted yet: + */ + struct list_head submit_list; + + /* list of bo's that have been submitted but timestamp has + * not passed yet (so still ref'd in active cmdstream) + */ + struct list_head pending_list; + + /* if we are the 2d pipe, and want to wait on a timestamp + * from 3d, we need to also internally open the 3d pipe: + */ + struct fd_pipe *p3d; +}; + +static inline struct kgsl_pipe * to_kgsl_pipe(struct fd_pipe *x) +{ + return (struct kgsl_pipe *)x; +} + +drm_private int is_kgsl_pipe(struct fd_pipe *pipe); + +struct kgsl_bo { + struct fd_bo base; + uint64_t offset; + uint32_t gpuaddr; + /* timestamp (per pipe) for bo's in a pipe's pending_list: */ + uint32_t timestamp[FD_PIPE_MAX]; + /* list-node for pipe's submit_list or pending_list */ + struct list_head list[FD_PIPE_MAX]; +}; + +static inline struct kgsl_bo * to_kgsl_bo(struct fd_bo *x) +{ + return (struct kgsl_bo *)x; +} + + +drm_private struct fd_device * kgsl_device_new(int fd); + +drm_private int kgsl_pipe_timestamp(struct kgsl_pipe *kgsl_pipe, + uint32_t *timestamp); +drm_private void kgsl_pipe_add_submit(struct kgsl_pipe *pipe, + struct kgsl_bo *bo); +drm_private void kgsl_pipe_pre_submit(struct kgsl_pipe *pipe); +drm_private void kgsl_pipe_post_submit(struct kgsl_pipe *pipe, + uint32_t timestamp); +drm_private void kgsl_pipe_process_pending(struct kgsl_pipe *pipe, + uint32_t timestamp); +drm_private struct fd_pipe * kgsl_pipe_new(struct fd_device *dev, + enum fd_pipe_id id, uint32_t prio); + +drm_private struct fd_ringbuffer * kgsl_ringbuffer_new(struct fd_pipe *pipe, + uint32_t size, enum fd_ringbuffer_flags flags); + +drm_private int kgsl_bo_new_handle(struct fd_device *dev, + uint32_t size, uint32_t flags, uint32_t *handle); +drm_private struct fd_bo * kgsl_bo_from_handle(struct fd_device *dev, + uint32_t size, uint32_t handle); + +drm_private uint32_t kgsl_bo_gpuaddr(struct kgsl_bo *bo, uint32_t offset); +drm_private void kgsl_bo_set_timestamp(struct kgsl_bo *bo, uint32_t timestamp); +drm_private uint32_t kgsl_bo_get_timestamp(struct kgsl_bo *bo); + +#endif /* KGSL_PRIV_H_ */ diff --git a/freedreno/kgsl/kgsl_ringbuffer.c b/freedreno/kgsl/kgsl_ringbuffer.c new file mode 100644 index 0000000..9abf0ad --- /dev/null +++ b/freedreno/kgsl/kgsl_ringbuffer.c @@ -0,0 +1,235 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2013 Rob Clark + * + * 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 (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 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. + * + * Authors: + * Rob Clark + */ + +#include + +#include "xf86atomic.h" +#include "freedreno_ringbuffer.h" +#include "kgsl_priv.h" + + +/* because kgsl tries to validate the gpuaddr on kernel side in ISSUEIBCMDS, + * we can't use normal gem bo's for ringbuffer.. someday the kernel part + * needs to be reworked into a single sane drm driver :-/ + */ +struct kgsl_rb_bo { + struct kgsl_pipe *pipe; + void *hostptr; + uint32_t gpuaddr; + uint32_t size; +}; + +struct kgsl_ringbuffer { + struct fd_ringbuffer base; + struct kgsl_rb_bo *bo; +}; + +static inline struct kgsl_ringbuffer * to_kgsl_ringbuffer(struct fd_ringbuffer *x) +{ + return (struct kgsl_ringbuffer *)x; +} + +static void kgsl_rb_bo_del(struct kgsl_rb_bo *bo) +{ + struct kgsl_sharedmem_free req = { + .gpuaddr = bo->gpuaddr, + }; + int ret; + + drm_munmap(bo->hostptr, bo->size); + + ret = ioctl(bo->pipe->fd, IOCTL_KGSL_SHAREDMEM_FREE, &req); + if (ret) { + ERROR_MSG("sharedmem free failed: %s", strerror(errno)); + } + + free(bo); +} + +static struct kgsl_rb_bo * kgsl_rb_bo_new(struct kgsl_pipe *pipe, uint32_t size) +{ + struct kgsl_rb_bo *bo; + struct kgsl_gpumem_alloc req = { + .size = ALIGN(size, 4096), + .flags = KGSL_MEMFLAGS_GPUREADONLY, + }; + int ret; + + bo = calloc(1, sizeof(*bo)); + if (!bo) { + ERROR_MSG("allocation failed"); + return NULL; + } + ret = ioctl(pipe->fd, IOCTL_KGSL_GPUMEM_ALLOC, &req); + if (ret) { + ERROR_MSG("gpumem allocation failed: %s", strerror(errno)); + goto fail; + } + + bo->pipe = pipe; + bo->gpuaddr = req.gpuaddr; + bo->size = size; + bo->hostptr = drm_mmap(NULL, size, PROT_WRITE|PROT_READ, + MAP_SHARED, pipe->fd, req.gpuaddr); + + return bo; +fail: + if (bo) + kgsl_rb_bo_del(bo); + return NULL; +} + +static void * kgsl_ringbuffer_hostptr(struct fd_ringbuffer *ring) +{ + struct kgsl_ringbuffer *kgsl_ring = to_kgsl_ringbuffer(ring); + return kgsl_ring->bo->hostptr; +} + +static int kgsl_ringbuffer_flush(struct fd_ringbuffer *ring, uint32_t *last_start, + int in_fence_fd, int *out_fence_fd) +{ + struct kgsl_ringbuffer *kgsl_ring = to_kgsl_ringbuffer(ring); + struct kgsl_pipe *kgsl_pipe = to_kgsl_pipe(ring->pipe); + uint32_t offset = (uint8_t *)last_start - (uint8_t *)ring->start; + struct kgsl_ibdesc ibdesc = { + .gpuaddr = kgsl_ring->bo->gpuaddr + offset, + .hostptr = last_start, + .sizedwords = ring->cur - last_start, + }; + struct kgsl_ringbuffer_issueibcmds req = { + .drawctxt_id = kgsl_pipe->drawctxt_id, + .ibdesc_addr = (unsigned long)&ibdesc, + .numibs = 1, + .flags = KGSL_CONTEXT_SUBMIT_IB_LIST, + }; + int ret; + + assert(in_fence_fd == -1); + assert(out_fence_fd == NULL); + + kgsl_pipe_pre_submit(kgsl_pipe); + + /* z180_cmdstream_issueibcmds() is made of fail: */ + if (ring->pipe->id == FD_PIPE_2D) { + /* fix up size field in last cmd packet */ + uint32_t last_size = (uint32_t)(ring->cur - last_start); + /* 5 is length of first packet, 2 for the two 7f000000's */ + last_start[2] = last_size - (5 + 2); + ibdesc.gpuaddr = kgsl_ring->bo->gpuaddr; + ibdesc.hostptr = kgsl_ring->bo->hostptr; + ibdesc.sizedwords = 0x145; + req.timestamp = (uintptr_t)kgsl_ring->bo->hostptr; + } + + do { + ret = ioctl(kgsl_pipe->fd, IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS, &req); + } while ((ret == -1) && ((errno == EINTR) || (errno == EAGAIN))); + if (ret) + ERROR_MSG("issueibcmds failed! %d (%s)", ret, strerror(errno)); + + ring->last_timestamp = req.timestamp; + ring->last_start = ring->cur; + + kgsl_pipe_post_submit(kgsl_pipe, req.timestamp); + + return ret; +} + +static void kgsl_ringbuffer_emit_reloc(struct fd_ringbuffer *ring, + const struct fd_reloc *r) +{ + struct kgsl_bo *kgsl_bo = to_kgsl_bo(r->bo); + uint32_t addr = kgsl_bo_gpuaddr(kgsl_bo, r->offset); + assert(addr); + if (r->shift < 0) + addr >>= -r->shift; + else + addr <<= r->shift; + (*ring->cur++) = addr | r->or; + kgsl_pipe_add_submit(to_kgsl_pipe(ring->pipe), kgsl_bo); +} + +static uint32_t kgsl_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring, + struct fd_ringbuffer *target, uint32_t cmd_idx) +{ + struct kgsl_ringbuffer *target_ring = to_kgsl_ringbuffer(target); + assert(cmd_idx == 0); + (*ring->cur++) = target_ring->bo->gpuaddr; + return offset_bytes(target->cur, target->start); +} + +static void kgsl_ringbuffer_destroy(struct fd_ringbuffer *ring) +{ + struct kgsl_ringbuffer *kgsl_ring = to_kgsl_ringbuffer(ring); + if (ring->last_timestamp) + fd_pipe_wait(ring->pipe, ring->last_timestamp); + if (kgsl_ring->bo) + kgsl_rb_bo_del(kgsl_ring->bo); + free(kgsl_ring); +} + +static const struct fd_ringbuffer_funcs funcs = { + .hostptr = kgsl_ringbuffer_hostptr, + .flush = kgsl_ringbuffer_flush, + .emit_reloc = kgsl_ringbuffer_emit_reloc, + .emit_reloc_ring = kgsl_ringbuffer_emit_reloc_ring, + .destroy = kgsl_ringbuffer_destroy, +}; + +drm_private struct fd_ringbuffer * kgsl_ringbuffer_new(struct fd_pipe *pipe, + uint32_t size, enum fd_ringbuffer_flags flags) +{ + struct kgsl_ringbuffer *kgsl_ring; + struct fd_ringbuffer *ring = NULL; + + assert(!flags); + + kgsl_ring = calloc(1, sizeof(*kgsl_ring)); + if (!kgsl_ring) { + ERROR_MSG("allocation failed"); + goto fail; + } + + ring = &kgsl_ring->base; + atomic_set(&ring->refcnt, 1); + + ring->funcs = &funcs; + ring->size = size; + + kgsl_ring->bo = kgsl_rb_bo_new(to_kgsl_pipe(pipe), size); + if (!kgsl_ring->bo) { + ERROR_MSG("ringbuffer allocation failed"); + goto fail; + } + + return ring; +fail: + if (ring) + fd_ringbuffer_del(ring); + return NULL; +} diff --git a/freedreno/kgsl/msm_kgsl.h b/freedreno/kgsl/msm_kgsl.h new file mode 100644 index 0000000..5b36eeb --- /dev/null +++ b/freedreno/kgsl/msm_kgsl.h @@ -0,0 +1,519 @@ +#ifndef _MSM_KGSL_H +#define _MSM_KGSL_H + +#define KGSL_VERSION_MAJOR 3 +#define KGSL_VERSION_MINOR 11 + +/*context flags */ +#define KGSL_CONTEXT_SAVE_GMEM 0x00000001 +#define KGSL_CONTEXT_NO_GMEM_ALLOC 0x00000002 +#define KGSL_CONTEXT_SUBMIT_IB_LIST 0x00000004 +#define KGSL_CONTEXT_CTX_SWITCH 0x00000008 +#define KGSL_CONTEXT_PREAMBLE 0x00000010 +#define KGSL_CONTEXT_TRASH_STATE 0x00000020 +#define KGSL_CONTEXT_PER_CONTEXT_TS 0x00000040 + +#define KGSL_CONTEXT_INVALID 0xffffffff + +/* Memory allocayion flags */ +#define KGSL_MEMFLAGS_GPUREADONLY 0x01000000 + +/* generic flag values */ +#define KGSL_FLAGS_NORMALMODE 0x00000000 +#define KGSL_FLAGS_SAFEMODE 0x00000001 +#define KGSL_FLAGS_INITIALIZED0 0x00000002 +#define KGSL_FLAGS_INITIALIZED 0x00000004 +#define KGSL_FLAGS_STARTED 0x00000008 +#define KGSL_FLAGS_ACTIVE 0x00000010 +#define KGSL_FLAGS_RESERVED0 0x00000020 +#define KGSL_FLAGS_RESERVED1 0x00000040 +#define KGSL_FLAGS_RESERVED2 0x00000080 +#define KGSL_FLAGS_SOFT_RESET 0x00000100 +#define KGSL_FLAGS_PER_CONTEXT_TIMESTAMPS 0x00000200 + +/* Clock flags to show which clocks should be controlled by a given platform */ +#define KGSL_CLK_SRC 0x00000001 +#define KGSL_CLK_CORE 0x00000002 +#define KGSL_CLK_IFACE 0x00000004 +#define KGSL_CLK_MEM 0x00000008 +#define KGSL_CLK_MEM_IFACE 0x00000010 +#define KGSL_CLK_AXI 0x00000020 + +/* + * Reset status values for context + */ +enum kgsl_ctx_reset_stat { + KGSL_CTX_STAT_NO_ERROR = 0x00000000, + KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT = 0x00000001, + KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT = 0x00000002, + KGSL_CTX_STAT_UNKNOWN_CONTEXT_RESET_EXT = 0x00000003 +}; + +#define KGSL_MAX_PWRLEVELS 5 + +#define KGSL_CONVERT_TO_MBPS(val) \ + (val*1000*1000U) + +/* device id */ +enum kgsl_deviceid { + KGSL_DEVICE_3D0 = 0x00000000, + KGSL_DEVICE_2D0 = 0x00000001, + KGSL_DEVICE_2D1 = 0x00000002, + KGSL_DEVICE_MAX = 0x00000003 +}; + +enum kgsl_user_mem_type { + KGSL_USER_MEM_TYPE_PMEM = 0x00000000, + KGSL_USER_MEM_TYPE_ASHMEM = 0x00000001, + KGSL_USER_MEM_TYPE_ADDR = 0x00000002, + KGSL_USER_MEM_TYPE_ION = 0x00000003, + KGSL_USER_MEM_TYPE_MAX = 0x00000004, +}; + +struct kgsl_devinfo { + + unsigned int device_id; + /* chip revision id + * coreid:8 majorrev:8 minorrev:8 patch:8 + */ + unsigned int chip_id; + unsigned int mmu_enabled; + unsigned int gmem_gpubaseaddr; + /* + * This field contains the adreno revision + * number 200, 205, 220, etc... + */ + unsigned int gpu_id; + unsigned int gmem_sizebytes; +}; + +/* this structure defines the region of memory that can be mmap()ed from this + driver. The timestamp fields are volatile because they are written by the + GPU +*/ +struct kgsl_devmemstore { + volatile unsigned int soptimestamp; + unsigned int sbz; + volatile unsigned int eoptimestamp; + unsigned int sbz2; + volatile unsigned int ts_cmp_enable; + unsigned int sbz3; + volatile unsigned int ref_wait_ts; + unsigned int sbz4; + unsigned int current_context; + unsigned int sbz5; +}; + +#define KGSL_MEMSTORE_OFFSET(ctxt_id, field) \ + ((ctxt_id)*sizeof(struct kgsl_devmemstore) + \ + offsetof(struct kgsl_devmemstore, field)) + +/* timestamp id*/ +enum kgsl_timestamp_type { + KGSL_TIMESTAMP_CONSUMED = 0x00000001, /* start-of-pipeline timestamp */ + KGSL_TIMESTAMP_RETIRED = 0x00000002, /* end-of-pipeline timestamp*/ + KGSL_TIMESTAMP_QUEUED = 0x00000003, +}; + +/* property types - used with kgsl_device_getproperty */ +enum kgsl_property_type { + KGSL_PROP_DEVICE_INFO = 0x00000001, + KGSL_PROP_DEVICE_SHADOW = 0x00000002, + KGSL_PROP_DEVICE_POWER = 0x00000003, + KGSL_PROP_SHMEM = 0x00000004, + KGSL_PROP_SHMEM_APERTURES = 0x00000005, + KGSL_PROP_MMU_ENABLE = 0x00000006, + KGSL_PROP_INTERRUPT_WAITS = 0x00000007, + KGSL_PROP_VERSION = 0x00000008, + KGSL_PROP_GPU_RESET_STAT = 0x00000009, + KGSL_PROP_PWRCTRL = 0x0000000E, +}; + +struct kgsl_shadowprop { + unsigned int gpuaddr; + unsigned int size; + unsigned int flags; /* contains KGSL_FLAGS_ values */ +}; + +struct kgsl_pwrlevel { + unsigned int gpu_freq; + unsigned int bus_freq; + unsigned int io_fraction; +}; + +struct kgsl_version { + unsigned int drv_major; + unsigned int drv_minor; + unsigned int dev_major; + unsigned int dev_minor; +}; + +#ifdef __KERNEL__ + +#define KGSL_3D0_REG_MEMORY "kgsl_3d0_reg_memory" +#define KGSL_3D0_IRQ "kgsl_3d0_irq" +#define KGSL_2D0_REG_MEMORY "kgsl_2d0_reg_memory" +#define KGSL_2D0_IRQ "kgsl_2d0_irq" +#define KGSL_2D1_REG_MEMORY "kgsl_2d1_reg_memory" +#define KGSL_2D1_IRQ "kgsl_2d1_irq" + +enum kgsl_iommu_context_id { + KGSL_IOMMU_CONTEXT_USER = 0, + KGSL_IOMMU_CONTEXT_PRIV = 1, +}; + +struct kgsl_iommu_ctx { + const char *iommu_ctx_name; + enum kgsl_iommu_context_id ctx_id; +}; + +struct kgsl_device_iommu_data { + const struct kgsl_iommu_ctx *iommu_ctxs; + int iommu_ctx_count; + unsigned int physstart; + unsigned int physend; +}; + +struct kgsl_device_platform_data { + struct kgsl_pwrlevel pwrlevel[KGSL_MAX_PWRLEVELS]; + int init_level; + int num_levels; + int (*set_grp_async)(void); + unsigned int idle_timeout; + bool strtstp_sleepwake; + unsigned int nap_allowed; + unsigned int clk_map; + unsigned int idle_needed; + struct msm_bus_scale_pdata *bus_scale_table; + struct kgsl_device_iommu_data *iommu_data; + int iommu_count; + struct msm_dcvs_core_info *core_info; +}; + +#endif + +/* structure holds list of ibs */ +struct kgsl_ibdesc { + unsigned int gpuaddr; + void *hostptr; + unsigned int sizedwords; + unsigned int ctrl; +}; + +/* ioctls */ +#define KGSL_IOC_TYPE 0x09 + +/* get misc info about the GPU + type should be a value from enum kgsl_property_type + value points to a structure that varies based on type + sizebytes is sizeof() that structure + for KGSL_PROP_DEVICE_INFO, use struct kgsl_devinfo + this structure contaings hardware versioning info. + for KGSL_PROP_DEVICE_SHADOW, use struct kgsl_shadowprop + this is used to find mmap() offset and sizes for mapping + struct kgsl_memstore into userspace. +*/ +struct kgsl_device_getproperty { + unsigned int type; + void *value; + unsigned int sizebytes; +}; + +#define IOCTL_KGSL_DEVICE_GETPROPERTY \ + _IOWR(KGSL_IOC_TYPE, 0x2, struct kgsl_device_getproperty) + +/* IOCTL_KGSL_DEVICE_READ (0x3) - removed 03/2012 + */ + +/* block until the GPU has executed past a given timestamp + * timeout is in milliseconds. + */ +struct kgsl_device_waittimestamp { + unsigned int timestamp; + unsigned int timeout; +}; + +#define IOCTL_KGSL_DEVICE_WAITTIMESTAMP \ + _IOW(KGSL_IOC_TYPE, 0x6, struct kgsl_device_waittimestamp) + +struct kgsl_device_waittimestamp_ctxtid { + unsigned int context_id; + unsigned int timestamp; + unsigned int timeout; +}; + +#define IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID \ + _IOW(KGSL_IOC_TYPE, 0x7, struct kgsl_device_waittimestamp_ctxtid) + +/* issue indirect commands to the GPU. + * drawctxt_id must have been created with IOCTL_KGSL_DRAWCTXT_CREATE + * ibaddr and sizedwords must specify a subset of a buffer created + * with IOCTL_KGSL_SHAREDMEM_FROM_PMEM + * flags may be a mask of KGSL_CONTEXT_ values + * timestamp is a returned counter value which can be passed to + * other ioctls to determine when the commands have been executed by + * the GPU. + */ +struct kgsl_ringbuffer_issueibcmds { + unsigned int drawctxt_id; + unsigned int ibdesc_addr; + unsigned int numibs; + unsigned int timestamp; /*output param */ + unsigned int flags; +}; + +#define IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS \ + _IOWR(KGSL_IOC_TYPE, 0x10, struct kgsl_ringbuffer_issueibcmds) + +/* read the most recently executed timestamp value + * type should be a value from enum kgsl_timestamp_type + */ +struct kgsl_cmdstream_readtimestamp { + unsigned int type; + unsigned int timestamp; /*output param */ +}; + +#define IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_OLD \ + _IOR(KGSL_IOC_TYPE, 0x11, struct kgsl_cmdstream_readtimestamp) + +#define IOCTL_KGSL_CMDSTREAM_READTIMESTAMP \ + _IOWR(KGSL_IOC_TYPE, 0x11, struct kgsl_cmdstream_readtimestamp) + +/* free memory when the GPU reaches a given timestamp. + * gpuaddr specify a memory region created by a + * IOCTL_KGSL_SHAREDMEM_FROM_PMEM call + * type should be a value from enum kgsl_timestamp_type + */ +struct kgsl_cmdstream_freememontimestamp { + unsigned int gpuaddr; + unsigned int type; + unsigned int timestamp; +}; + +#define IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP \ + _IOW(KGSL_IOC_TYPE, 0x12, struct kgsl_cmdstream_freememontimestamp) + +/* Previous versions of this header had incorrectly defined + IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP as a read-only ioctl instead + of a write only ioctl. To ensure binary compatibility, the following + #define will be used to intercept the incorrect ioctl +*/ + +#define IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_OLD \ + _IOR(KGSL_IOC_TYPE, 0x12, struct kgsl_cmdstream_freememontimestamp) + +/* create a draw context, which is used to preserve GPU state. + * The flags field may contain a mask KGSL_CONTEXT_* values + */ +struct kgsl_drawctxt_create { + unsigned int flags; + unsigned int drawctxt_id; /*output param */ +}; + +#define IOCTL_KGSL_DRAWCTXT_CREATE \ + _IOWR(KGSL_IOC_TYPE, 0x13, struct kgsl_drawctxt_create) + +/* destroy a draw context */ +struct kgsl_drawctxt_destroy { + unsigned int drawctxt_id; +}; + +#define IOCTL_KGSL_DRAWCTXT_DESTROY \ + _IOW(KGSL_IOC_TYPE, 0x14, struct kgsl_drawctxt_destroy) + +/* add a block of pmem, fb, ashmem or user allocated address + * into the GPU address space */ +struct kgsl_map_user_mem { + int fd; + unsigned int gpuaddr; /*output param */ + unsigned int len; + unsigned int offset; + unsigned int hostptr; /*input param */ + enum kgsl_user_mem_type memtype; + unsigned int reserved; /* May be required to add + params for another mem type */ +}; + +#define IOCTL_KGSL_MAP_USER_MEM \ + _IOWR(KGSL_IOC_TYPE, 0x15, struct kgsl_map_user_mem) + +struct kgsl_cmdstream_readtimestamp_ctxtid { + unsigned int context_id; + unsigned int type; + unsigned int timestamp; /*output param */ +}; + +#define IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_CTXTID \ + _IOWR(KGSL_IOC_TYPE, 0x16, struct kgsl_cmdstream_readtimestamp_ctxtid) + +struct kgsl_cmdstream_freememontimestamp_ctxtid { + unsigned int context_id; + unsigned int gpuaddr; + unsigned int type; + unsigned int timestamp; +}; + +#define IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_CTXTID \ + _IOW(KGSL_IOC_TYPE, 0x17, \ + struct kgsl_cmdstream_freememontimestamp_ctxtid) + +/* add a block of pmem or fb into the GPU address space */ +struct kgsl_sharedmem_from_pmem { + int pmem_fd; + unsigned int gpuaddr; /*output param */ + unsigned int len; + unsigned int offset; +}; + +#define IOCTL_KGSL_SHAREDMEM_FROM_PMEM \ + _IOWR(KGSL_IOC_TYPE, 0x20, struct kgsl_sharedmem_from_pmem) + +/* remove memory from the GPU's address space */ +struct kgsl_sharedmem_free { + unsigned int gpuaddr; +}; + +#define IOCTL_KGSL_SHAREDMEM_FREE \ + _IOW(KGSL_IOC_TYPE, 0x21, struct kgsl_sharedmem_free) + +struct kgsl_cff_user_event { + unsigned char cff_opcode; + unsigned int op1; + unsigned int op2; + unsigned int op3; + unsigned int op4; + unsigned int op5; + unsigned int __pad[2]; +}; + +#define IOCTL_KGSL_CFF_USER_EVENT \ + _IOW(KGSL_IOC_TYPE, 0x31, struct kgsl_cff_user_event) + +struct kgsl_gmem_desc { + unsigned int x; + unsigned int y; + unsigned int width; + unsigned int height; + unsigned int pitch; +}; + +struct kgsl_buffer_desc { + void *hostptr; + unsigned int gpuaddr; + int size; + unsigned int format; + unsigned int pitch; + unsigned int enabled; +}; + +struct kgsl_bind_gmem_shadow { + unsigned int drawctxt_id; + struct kgsl_gmem_desc gmem_desc; + unsigned int shadow_x; + unsigned int shadow_y; + struct kgsl_buffer_desc shadow_buffer; + unsigned int buffer_id; +}; + +#define IOCTL_KGSL_DRAWCTXT_BIND_GMEM_SHADOW \ + _IOW(KGSL_IOC_TYPE, 0x22, struct kgsl_bind_gmem_shadow) + +/* add a block of memory into the GPU address space */ +struct kgsl_sharedmem_from_vmalloc { + unsigned int gpuaddr; /*output param */ + unsigned int hostptr; + unsigned int flags; +}; + +#define IOCTL_KGSL_SHAREDMEM_FROM_VMALLOC \ + _IOWR(KGSL_IOC_TYPE, 0x23, struct kgsl_sharedmem_from_vmalloc) + +#define IOCTL_KGSL_SHAREDMEM_FLUSH_CACHE \ + _IOW(KGSL_IOC_TYPE, 0x24, struct kgsl_sharedmem_free) + +struct kgsl_drawctxt_set_bin_base_offset { + unsigned int drawctxt_id; + unsigned int offset; +}; + +#define IOCTL_KGSL_DRAWCTXT_SET_BIN_BASE_OFFSET \ + _IOW(KGSL_IOC_TYPE, 0x25, struct kgsl_drawctxt_set_bin_base_offset) + +enum kgsl_cmdwindow_type { + KGSL_CMDWINDOW_MIN = 0x00000000, + KGSL_CMDWINDOW_2D = 0x00000000, + KGSL_CMDWINDOW_3D = 0x00000001, /* legacy */ + KGSL_CMDWINDOW_MMU = 0x00000002, + KGSL_CMDWINDOW_ARBITER = 0x000000FF, + KGSL_CMDWINDOW_MAX = 0x000000FF, +}; + +/* write to the command window */ +struct kgsl_cmdwindow_write { + enum kgsl_cmdwindow_type target; + unsigned int addr; + unsigned int data; +}; + +#define IOCTL_KGSL_CMDWINDOW_WRITE \ + _IOW(KGSL_IOC_TYPE, 0x2e, struct kgsl_cmdwindow_write) + +struct kgsl_gpumem_alloc { + unsigned long gpuaddr; + size_t size; + unsigned int flags; +}; + +#define IOCTL_KGSL_GPUMEM_ALLOC \ + _IOWR(KGSL_IOC_TYPE, 0x2f, struct kgsl_gpumem_alloc) + +struct kgsl_cff_syncmem { + unsigned int gpuaddr; + unsigned int len; + unsigned int __pad[2]; /* For future binary compatibility */ +}; + +#define IOCTL_KGSL_CFF_SYNCMEM \ + _IOW(KGSL_IOC_TYPE, 0x30, struct kgsl_cff_syncmem) + +/* + * A timestamp event allows the user space to register an action following an + * expired timestamp. + */ + +struct kgsl_timestamp_event { + int type; /* Type of event (see list below) */ + unsigned int timestamp; /* Timestamp to trigger event on */ + unsigned int context_id; /* Context for the timestamp */ + void *priv; /* Pointer to the event specific blob */ + size_t len; /* Size of the event specific blob */ +}; + +#define IOCTL_KGSL_TIMESTAMP_EVENT \ + _IOW(KGSL_IOC_TYPE, 0x31, struct kgsl_timestamp_event) + +/* A genlock timestamp event releases an existing lock on timestamp expire */ + +#define KGSL_TIMESTAMP_EVENT_GENLOCK 1 + +struct kgsl_timestamp_event_genlock { + int handle; /* Handle of the genlock lock to release */ +}; + +/* + * Set a property within the kernel. Uses the same structure as + * IOCTL_KGSL_GETPROPERTY + */ + +#define IOCTL_KGSL_SETPROPERTY \ + _IOW(KGSL_IOC_TYPE, 0x32, struct kgsl_device_getproperty) + +#ifdef __KERNEL__ +#ifdef CONFIG_MSM_KGSL_DRM +int kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start, + unsigned long *len); +#else +#define kgsl_gem_obj_addr(...) 0 +#endif +#endif +#endif /* _MSM_KGSL_H */ diff --git a/freedreno/libdrm_freedreno.pc.in b/freedreno/libdrm_freedreno.pc.in new file mode 100644 index 0000000..b736b65 --- /dev/null +++ b/freedreno/libdrm_freedreno.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libdrm_freedreno +Description: Userspace interface to freedreno kernel DRM services +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -ldrm_freedreno +Cflags: -I${includedir} -I${includedir}/libdrm -I${includedir}/freedreno +Requires.private: libdrm diff --git a/freedreno/meson.build b/freedreno/meson.build new file mode 100644 index 0000000..de9ee14 --- /dev/null +++ b/freedreno/meson.build @@ -0,0 +1,82 @@ +# Copyright © 2017-2018 Intel Corporation + +# 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. + +files_freedreno = files( + 'freedreno_device.c', + 'freedreno_pipe.c', + 'freedreno_ringbuffer.c', + 'freedreno_bo.c', + 'freedreno_bo_cache.c', + 'msm/msm_bo.c', + 'msm/msm_device.c', + 'msm/msm_pipe.c', + 'msm/msm_ringbuffer.c', +) + +if with_freedreno_kgsl + files_freedreno += files( + 'kgsl/kgsl_bo.c', + 'kgsl/kgsl_device.c', + 'kgsl/kgsl_pipe.c', + 'kgsl/kgsl_ringbuffer.c', + ) +endif + +libdrm_freedreno = library( + 'drm_freedreno', + [files_freedreno, config_file], + c_args : libdrm_c_args, + include_directories : [inc_root, inc_drm], + dependencies : [dep_valgrind, dep_pthread_stubs, dep_rt, dep_atomic_ops], + link_with : libdrm, + version : '1.0.0', + install : true, +) + +ext_libdrm_freedreno = declare_dependency( + link_with : [libdrm, libdrm_freedreno], + include_directories : [inc_drm, include_directories('.')], +) + +if meson.version().version_compare('>= 0.54.0') + meson.override_dependency('libdrm_freedreno', ext_libdrm_freedreno) +endif + +install_headers( + 'freedreno_drmif.h', 'freedreno_ringbuffer.h', + subdir : 'freedreno' +) + +pkg.generate( + libdrm_freedreno, + name : 'libdrm_freedreno', + subdirs : ['.', 'libdrm', 'freedreno'], + description : 'Userspace interface to freedreno kernel DRM services', +) + +test( + 'freedreno-symbols-check', + symbols_check, + args : [ + '--lib', libdrm_freedreno, + '--symbols-file', files('freedreno-symbols.txt'), + '--nm', prog_nm.path(), + ], +) diff --git a/freedreno/msm/msm_bo.c b/freedreno/msm/msm_bo.c new file mode 100644 index 0000000..8b3d0bc --- /dev/null +++ b/freedreno/msm/msm_bo.c @@ -0,0 +1,170 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2013 Rob Clark + * + * 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 (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 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. + * + * Authors: + * Rob Clark + */ + +#include "msm_priv.h" + +static int bo_allocate(struct msm_bo *msm_bo) +{ + struct fd_bo *bo = &msm_bo->base; + if (!msm_bo->offset) { + struct drm_msm_gem_info req = { + .handle = bo->handle, + }; + int ret; + + /* if the buffer is already backed by pages then this + * doesn't actually do anything (other than giving us + * the offset) + */ + ret = drmCommandWriteRead(bo->dev->fd, DRM_MSM_GEM_INFO, + &req, sizeof(req)); + if (ret) { + ERROR_MSG("alloc failed: %s", strerror(errno)); + return ret; + } + + msm_bo->offset = req.offset; + } + + return 0; +} + +static int msm_bo_offset(struct fd_bo *bo, uint64_t *offset) +{ + struct msm_bo *msm_bo = to_msm_bo(bo); + int ret = bo_allocate(msm_bo); + if (ret) + return ret; + *offset = msm_bo->offset; + return 0; +} + +static int msm_bo_cpu_prep(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op) +{ + struct drm_msm_gem_cpu_prep req = { + .handle = bo->handle, + .op = op, + }; + + get_abs_timeout(&req.timeout, 5000000000); + + return drmCommandWrite(bo->dev->fd, DRM_MSM_GEM_CPU_PREP, &req, sizeof(req)); +} + +static void msm_bo_cpu_fini(struct fd_bo *bo) +{ + struct drm_msm_gem_cpu_fini req = { + .handle = bo->handle, + }; + + drmCommandWrite(bo->dev->fd, DRM_MSM_GEM_CPU_FINI, &req, sizeof(req)); +} + +static int msm_bo_madvise(struct fd_bo *bo, int willneed) +{ + struct drm_msm_gem_madvise req = { + .handle = bo->handle, + .madv = willneed ? MSM_MADV_WILLNEED : MSM_MADV_DONTNEED, + }; + int ret; + + /* older kernels do not support this: */ + if (bo->dev->version < FD_VERSION_MADVISE) + return willneed; + + ret = drmCommandWriteRead(bo->dev->fd, DRM_MSM_GEM_MADVISE, &req, sizeof(req)); + if (ret) + return ret; + + return req.retained; +} + +static uint64_t msm_bo_iova(struct fd_bo *bo) +{ + struct drm_msm_gem_info req = { + .handle = bo->handle, + .flags = MSM_INFO_IOVA, + }; + + drmCommandWriteRead(bo->dev->fd, DRM_MSM_GEM_INFO, &req, sizeof(req)); + + return req.offset; +} + +static void msm_bo_destroy(struct fd_bo *bo) +{ + struct msm_bo *msm_bo = to_msm_bo(bo); + free(msm_bo); + +} + +static const struct fd_bo_funcs funcs = { + .offset = msm_bo_offset, + .cpu_prep = msm_bo_cpu_prep, + .cpu_fini = msm_bo_cpu_fini, + .madvise = msm_bo_madvise, + .iova = msm_bo_iova, + .destroy = msm_bo_destroy, +}; + +/* allocate a buffer handle: */ +drm_private int msm_bo_new_handle(struct fd_device *dev, + uint32_t size, uint32_t flags, uint32_t *handle) +{ + struct drm_msm_gem_new req = { + .size = size, + .flags = MSM_BO_WC, // TODO figure out proper flags.. + }; + int ret; + + ret = drmCommandWriteRead(dev->fd, DRM_MSM_GEM_NEW, + &req, sizeof(req)); + if (ret) + return ret; + + *handle = req.handle; + + return 0; +} + +/* allocate a new buffer object */ +drm_private struct fd_bo * msm_bo_from_handle(struct fd_device *dev, + uint32_t size, uint32_t handle) +{ + struct msm_bo *msm_bo; + struct fd_bo *bo; + + msm_bo = calloc(1, sizeof(*msm_bo)); + if (!msm_bo) + return NULL; + + bo = &msm_bo->base; + bo->funcs = &funcs; + + return bo; +} diff --git a/freedreno/msm/msm_device.c b/freedreno/msm/msm_device.c new file mode 100644 index 0000000..58b0746 --- /dev/null +++ b/freedreno/msm/msm_device.c @@ -0,0 +1,63 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2013 Rob Clark + * + * 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 (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 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. + * + * Authors: + * Rob Clark + */ + +#include +#include +#include + +#include "msm_priv.h" + +static void msm_device_destroy(struct fd_device *dev) +{ + struct msm_device *msm_dev = to_msm_device(dev); + free(msm_dev); +} + +static const struct fd_device_funcs funcs = { + .bo_new_handle = msm_bo_new_handle, + .bo_from_handle = msm_bo_from_handle, + .pipe_new = msm_pipe_new, + .destroy = msm_device_destroy, +}; + +drm_private struct fd_device * msm_device_new(int fd) +{ + struct msm_device *msm_dev; + struct fd_device *dev; + + msm_dev = calloc(1, sizeof(*msm_dev)); + if (!msm_dev) + return NULL; + + dev = &msm_dev->base; + dev->funcs = &funcs; + + dev->bo_size = sizeof(struct msm_bo); + + return dev; +} diff --git a/freedreno/msm/msm_pipe.c b/freedreno/msm/msm_pipe.c new file mode 100644 index 0000000..e070b31 --- /dev/null +++ b/freedreno/msm/msm_pipe.c @@ -0,0 +1,212 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2013 Rob Clark + * + * 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 (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 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. + * + * Authors: + * Rob Clark + */ + +#include "msm_priv.h" + +static int query_param(struct fd_pipe *pipe, uint32_t param, + uint64_t *value) +{ + struct msm_pipe *msm_pipe = to_msm_pipe(pipe); + struct drm_msm_param req = { + .pipe = msm_pipe->pipe, + .param = param, + }; + int ret; + + ret = drmCommandWriteRead(pipe->dev->fd, DRM_MSM_GET_PARAM, + &req, sizeof(req)); + if (ret) + return ret; + + *value = req.value; + + return 0; +} + +static int msm_pipe_get_param(struct fd_pipe *pipe, + enum fd_param_id param, uint64_t *value) +{ + struct msm_pipe *msm_pipe = to_msm_pipe(pipe); + switch(param) { + case FD_DEVICE_ID: // XXX probably get rid of this.. + case FD_GPU_ID: + *value = msm_pipe->gpu_id; + return 0; + case FD_GMEM_SIZE: + *value = msm_pipe->gmem; + return 0; + case FD_CHIP_ID: + *value = msm_pipe->chip_id; + return 0; + case FD_MAX_FREQ: + return query_param(pipe, MSM_PARAM_MAX_FREQ, value); + case FD_TIMESTAMP: + return query_param(pipe, MSM_PARAM_TIMESTAMP, value); + case FD_NR_RINGS: + return query_param(pipe, MSM_PARAM_NR_RINGS, value); + default: + ERROR_MSG("invalid param id: %d", param); + return -1; + } +} + +static int msm_pipe_wait(struct fd_pipe *pipe, uint32_t timestamp, + uint64_t timeout) +{ + struct fd_device *dev = pipe->dev; + struct drm_msm_wait_fence req = { + .fence = timestamp, + .queueid = to_msm_pipe(pipe)->queue_id, + }; + int ret; + + get_abs_timeout(&req.timeout, timeout); + + ret = drmCommandWrite(dev->fd, DRM_MSM_WAIT_FENCE, &req, sizeof(req)); + if (ret) { + ERROR_MSG("wait-fence failed! %d (%s)", ret, strerror(errno)); + return ret; + } + + return 0; +} + +static int open_submitqueue(struct fd_pipe *pipe, uint32_t prio) +{ + struct drm_msm_submitqueue req = { + .flags = 0, + .prio = prio, + }; + uint64_t nr_rings = 1; + int ret; + + if (fd_device_version(pipe->dev) < FD_VERSION_SUBMIT_QUEUES) { + to_msm_pipe(pipe)->queue_id = 0; + return 0; + } + + msm_pipe_get_param(pipe, FD_NR_RINGS, &nr_rings); + + req.prio = MIN2(req.prio, MAX2(nr_rings, 1) - 1); + + ret = drmCommandWriteRead(pipe->dev->fd, DRM_MSM_SUBMITQUEUE_NEW, + &req, sizeof(req)); + if (ret) { + ERROR_MSG("could not create submitqueue! %d (%s)", ret, strerror(errno)); + return ret; + } + + to_msm_pipe(pipe)->queue_id = req.id; + return 0; +} + +static void close_submitqueue(struct fd_pipe *pipe, uint32_t queue_id) +{ + if (fd_device_version(pipe->dev) < FD_VERSION_SUBMIT_QUEUES) + return; + + drmCommandWrite(pipe->dev->fd, DRM_MSM_SUBMITQUEUE_CLOSE, + &queue_id, sizeof(queue_id)); +} + +static void msm_pipe_destroy(struct fd_pipe *pipe) +{ + struct msm_pipe *msm_pipe = to_msm_pipe(pipe); + close_submitqueue(pipe, msm_pipe->queue_id); + + if (msm_pipe->suballoc_ring) { + fd_ringbuffer_del(msm_pipe->suballoc_ring); + msm_pipe->suballoc_ring = NULL; + } + + free(msm_pipe); +} + +static const struct fd_pipe_funcs funcs = { + .ringbuffer_new = msm_ringbuffer_new, + .get_param = msm_pipe_get_param, + .wait = msm_pipe_wait, + .destroy = msm_pipe_destroy, +}; + +static uint64_t get_param(struct fd_pipe *pipe, uint32_t param) +{ + uint64_t value; + int ret = query_param(pipe, param, &value); + if (ret) { + ERROR_MSG("get-param failed! %d (%s)", ret, strerror(errno)); + return 0; + } + return value; +} + +drm_private struct fd_pipe * msm_pipe_new(struct fd_device *dev, + enum fd_pipe_id id, uint32_t prio) +{ + static const uint32_t pipe_id[] = { + [FD_PIPE_3D] = MSM_PIPE_3D0, + [FD_PIPE_2D] = MSM_PIPE_2D0, + }; + struct msm_pipe *msm_pipe = NULL; + struct fd_pipe *pipe = NULL; + + msm_pipe = calloc(1, sizeof(*msm_pipe)); + if (!msm_pipe) { + ERROR_MSG("allocation failed"); + goto fail; + } + + pipe = &msm_pipe->base; + pipe->funcs = &funcs; + + /* initialize before get_param(): */ + pipe->dev = dev; + msm_pipe->pipe = pipe_id[id]; + + /* these params should be supported since the first version of drm/msm: */ + msm_pipe->gpu_id = get_param(pipe, MSM_PARAM_GPU_ID); + msm_pipe->gmem = get_param(pipe, MSM_PARAM_GMEM_SIZE); + msm_pipe->chip_id = get_param(pipe, MSM_PARAM_CHIP_ID); + + if (! msm_pipe->gpu_id) + goto fail; + + INFO_MSG("Pipe Info:"); + INFO_MSG(" GPU-id: %d", msm_pipe->gpu_id); + INFO_MSG(" Chip-id: 0x%08x", msm_pipe->chip_id); + INFO_MSG(" GMEM size: 0x%08x", msm_pipe->gmem); + + if (open_submitqueue(pipe, prio)) + goto fail; + + return pipe; +fail: + if (pipe) + fd_pipe_del(pipe); + return NULL; +} diff --git a/freedreno/msm/msm_priv.h b/freedreno/msm/msm_priv.h new file mode 100644 index 0000000..cc951fb --- /dev/null +++ b/freedreno/msm/msm_priv.h @@ -0,0 +1,141 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2013 Rob Clark + * + * 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 (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 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. + * + * Authors: + * Rob Clark + */ + +#ifndef MSM_PRIV_H_ +#define MSM_PRIV_H_ + +#include "freedreno_priv.h" + +#ifndef __user +# define __user +#endif + +#include "msm_drm.h" + +struct msm_device { + struct fd_device base; + struct fd_bo_cache ring_cache; + unsigned ring_cnt; +}; + +static inline struct msm_device * to_msm_device(struct fd_device *x) +{ + return (struct msm_device *)x; +} + +drm_private struct fd_device * msm_device_new(int fd); + +struct msm_pipe { + struct fd_pipe base; + uint32_t pipe; + uint32_t gpu_id; + uint32_t gmem; + uint32_t chip_id; + uint32_t queue_id; + + /* Allow for sub-allocation of stateobj ring buffers (ie. sharing + * the same underlying bo).. + * + * This takes advantage of each context having it's own fd_pipe, + * so we don't have to worry about access from multiple threads. + * + * We also rely on previous stateobj having been fully constructed + * so we can reclaim extra space at it's end. + */ + struct fd_ringbuffer *suballoc_ring; +}; + +static inline struct msm_pipe * to_msm_pipe(struct fd_pipe *x) +{ + return (struct msm_pipe *)x; +} + +drm_private struct fd_pipe * msm_pipe_new(struct fd_device *dev, + enum fd_pipe_id id, uint32_t prio); + +drm_private struct fd_ringbuffer * msm_ringbuffer_new(struct fd_pipe *pipe, + uint32_t size, enum fd_ringbuffer_flags flags); + +struct msm_bo { + struct fd_bo base; + uint64_t offset; + uint64_t presumed; + /* to avoid excess hashtable lookups, cache the ring this bo was + * last emitted on (since that will probably also be the next ring + * it is emitted on) + */ + unsigned current_ring_seqno; + uint32_t idx; +}; + +static inline struct msm_bo * to_msm_bo(struct fd_bo *x) +{ + return (struct msm_bo *)x; +} + +drm_private int msm_bo_new_handle(struct fd_device *dev, + uint32_t size, uint32_t flags, uint32_t *handle); +drm_private struct fd_bo * msm_bo_from_handle(struct fd_device *dev, + uint32_t size, uint32_t handle); + +static inline void get_abs_timeout(struct drm_msm_timespec *tv, uint64_t ns) +{ + struct timespec t; + uint32_t s = ns / 1000000000; + clock_gettime(CLOCK_MONOTONIC, &t); + tv->tv_sec = t.tv_sec + s; + tv->tv_nsec = t.tv_nsec + ns - (s * 1000000000); +} + +/* + * Stupid/simple growable array implementation: + */ + +static inline void * +grow(void *ptr, uint32_t nr, uint32_t *max, uint32_t sz) +{ + if ((nr + 1) > *max) { + if ((*max * 2) < (nr + 1)) + *max = nr + 5; + else + *max = *max * 2; + ptr = realloc(ptr, *max * sz); + } + return ptr; +} + +#define DECLARE_ARRAY(type, name) \ + unsigned nr_ ## name, max_ ## name; \ + type * name; + +#define APPEND(x, name) ({ \ + (x)->name = grow((x)->name, (x)->nr_ ## name, &(x)->max_ ## name, sizeof((x)->name[0])); \ + (x)->nr_ ## name ++; \ +}) + +#endif /* MSM_PRIV_H_ */ diff --git a/freedreno/msm/msm_ringbuffer.c b/freedreno/msm/msm_ringbuffer.c new file mode 100644 index 0000000..7b9df4a --- /dev/null +++ b/freedreno/msm/msm_ringbuffer.c @@ -0,0 +1,723 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2013 Rob Clark + * + * 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 (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 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. + * + * Authors: + * Rob Clark + */ + +#include +#include + +#include "xf86atomic.h" +#include "freedreno_ringbuffer.h" +#include "msm_priv.h" + +/* represents a single cmd buffer in the submit ioctl. Each cmd buffer has + * a backing bo, and a reloc table. + */ +struct msm_cmd { + struct list_head list; + + struct fd_ringbuffer *ring; + struct fd_bo *ring_bo; + + /* reloc's table: */ + DECLARE_ARRAY(struct drm_msm_gem_submit_reloc, relocs); + + uint32_t size; + + /* has cmd already been added to parent rb's submit.cmds table? */ + int is_appended_to_submit; +}; + +struct msm_ringbuffer { + struct fd_ringbuffer base; + + /* submit ioctl related tables: + * Note that bos and cmds are tracked by the parent ringbuffer, since + * that is global to the submit ioctl call. The reloc's table is tracked + * per cmd-buffer. + */ + struct { + /* bo's table: */ + DECLARE_ARRAY(struct drm_msm_gem_submit_bo, bos); + + /* cmd's table: */ + DECLARE_ARRAY(struct drm_msm_gem_submit_cmd, cmds); + } submit; + + /* should have matching entries in submit.bos: */ + /* Note, only in parent ringbuffer */ + DECLARE_ARRAY(struct fd_bo *, bos); + + /* should have matching entries in submit.cmds: */ + DECLARE_ARRAY(struct msm_cmd *, cmds); + + /* List of physical cmdstream buffers (msm_cmd) associated with this + * logical fd_ringbuffer. + * + * Note that this is different from msm_ringbuffer::cmds (which + * shadows msm_ringbuffer::submit::cmds for tracking submit ioctl + * related stuff, and *only* is tracked in the parent ringbuffer. + * And only has "completed" cmd buffers (ie. we already know the + * size) added via get_cmd(). + */ + struct list_head cmd_list; + + int is_growable; + unsigned cmd_count; + + unsigned offset; /* for sub-allocated stateobj rb's */ + + unsigned seqno; + + /* maps fd_bo to idx: */ + void *bo_table; + + /* maps msm_cmd to drm_msm_gem_submit_cmd in parent rb. Each rb has a + * list of msm_cmd's which correspond to each chunk of cmdstream in + * a 'growable' rb. For each of those we need to create one + * drm_msm_gem_submit_cmd in the parent rb which collects the state + * for the submit ioctl. Because we can have multiple IB's to the same + * target rb (for example, or same stateobj emit multiple times), and + * because in theory we can have multiple different rb's that have a + * reference to a given target, we need a hashtable to track this per + * rb. + */ + void *cmd_table; +}; + +static inline struct msm_ringbuffer * to_msm_ringbuffer(struct fd_ringbuffer *x) +{ + return (struct msm_ringbuffer *)x; +} + +#define INIT_SIZE 0x1000 + +static pthread_mutex_t idx_lock = PTHREAD_MUTEX_INITIALIZER; + +static struct msm_cmd *current_cmd(struct fd_ringbuffer *ring) +{ + struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); + assert(!LIST_IS_EMPTY(&msm_ring->cmd_list)); + return LIST_LAST_ENTRY(&msm_ring->cmd_list, struct msm_cmd, list); +} + +static void ring_cmd_del(struct msm_cmd *cmd) +{ + fd_bo_del(cmd->ring_bo); + list_del(&cmd->list); + to_msm_ringbuffer(cmd->ring)->cmd_count--; + free(cmd->relocs); + free(cmd); +} + +static struct msm_cmd * ring_cmd_new(struct fd_ringbuffer *ring, uint32_t size, + enum fd_ringbuffer_flags flags) +{ + struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); + struct msm_cmd *cmd = calloc(1, sizeof(*cmd)); + + if (!cmd) + return NULL; + + cmd->ring = ring; + + /* TODO separate suballoc buffer for small non-streaming state, using + * smaller page-sized backing bo's. + */ + if (flags & FD_RINGBUFFER_STREAMING) { + struct msm_pipe *msm_pipe = to_msm_pipe(ring->pipe); + unsigned suballoc_offset = 0; + struct fd_bo *suballoc_bo = NULL; + + if (msm_pipe->suballoc_ring) { + struct msm_ringbuffer *suballoc_ring = to_msm_ringbuffer(msm_pipe->suballoc_ring); + + assert(msm_pipe->suballoc_ring->flags & FD_RINGBUFFER_OBJECT); + assert(suballoc_ring->cmd_count == 1); + + suballoc_bo = current_cmd(msm_pipe->suballoc_ring)->ring_bo; + + suballoc_offset = fd_ringbuffer_size(msm_pipe->suballoc_ring) + + suballoc_ring->offset; + + suballoc_offset = ALIGN(suballoc_offset, 0x10); + + if ((size + suballoc_offset) > suballoc_bo->size) { + suballoc_bo = NULL; + } + } + + if (!suballoc_bo) { + cmd->ring_bo = fd_bo_new_ring(ring->pipe->dev, 0x8000, 0); + msm_ring->offset = 0; + } else { + cmd->ring_bo = fd_bo_ref(suballoc_bo); + msm_ring->offset = suballoc_offset; + } + + if (msm_pipe->suballoc_ring) + fd_ringbuffer_del(msm_pipe->suballoc_ring); + + msm_pipe->suballoc_ring = fd_ringbuffer_ref(ring); + } else { + cmd->ring_bo = fd_bo_new_ring(ring->pipe->dev, size, 0); + } + if (!cmd->ring_bo) + goto fail; + + list_addtail(&cmd->list, &msm_ring->cmd_list); + msm_ring->cmd_count++; + + return cmd; + +fail: + ring_cmd_del(cmd); + return NULL; +} + +static uint32_t append_bo(struct fd_ringbuffer *ring, struct fd_bo *bo) +{ + struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); + uint32_t idx; + + idx = APPEND(&msm_ring->submit, bos); + idx = APPEND(msm_ring, bos); + + msm_ring->submit.bos[idx].flags = 0; + msm_ring->submit.bos[idx].handle = bo->handle; + msm_ring->submit.bos[idx].presumed = to_msm_bo(bo)->presumed; + + msm_ring->bos[idx] = fd_bo_ref(bo); + + return idx; +} + +/* add (if needed) bo, return idx: */ +static uint32_t bo2idx(struct fd_ringbuffer *ring, struct fd_bo *bo, uint32_t flags) +{ + struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); + struct msm_bo *msm_bo = to_msm_bo(bo); + uint32_t idx; + pthread_mutex_lock(&idx_lock); + if (msm_bo->current_ring_seqno == msm_ring->seqno) { + idx = msm_bo->idx; + } else { + void *val; + + if (!msm_ring->bo_table) + msm_ring->bo_table = drmHashCreate(); + + if (!drmHashLookup(msm_ring->bo_table, bo->handle, &val)) { + /* found */ + idx = (uint32_t)(uintptr_t)val; + } else { + idx = append_bo(ring, bo); + val = (void *)(uintptr_t)idx; + drmHashInsert(msm_ring->bo_table, bo->handle, val); + } + msm_bo->current_ring_seqno = msm_ring->seqno; + msm_bo->idx = idx; + } + pthread_mutex_unlock(&idx_lock); + if (flags & FD_RELOC_READ) + msm_ring->submit.bos[idx].flags |= MSM_SUBMIT_BO_READ; + if (flags & FD_RELOC_WRITE) + msm_ring->submit.bos[idx].flags |= MSM_SUBMIT_BO_WRITE; + return idx; +} + +/* Ensure that submit has corresponding entry in cmds table for the + * target cmdstream buffer: + * + * Returns TRUE if new cmd added (else FALSE if it was already in + * the cmds table) + */ +static int get_cmd(struct fd_ringbuffer *ring, struct msm_cmd *target_cmd, + uint32_t submit_offset, uint32_t size, uint32_t type) +{ + struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); + struct drm_msm_gem_submit_cmd *cmd; + uint32_t i; + void *val; + + if (!msm_ring->cmd_table) + msm_ring->cmd_table = drmHashCreate(); + + /* figure out if we already have a cmd buf.. short-circuit hash + * lookup if: + * - target cmd has never been added to submit.cmds + * - target cmd is not a streaming stateobj (which unlike longer + * lived CSO stateobj, is not expected to be reused with multiple + * submits) + */ + if (target_cmd->is_appended_to_submit && + !(target_cmd->ring->flags & FD_RINGBUFFER_STREAMING) && + !drmHashLookup(msm_ring->cmd_table, (unsigned long)target_cmd, &val)) { + i = VOID2U64(val); + cmd = &msm_ring->submit.cmds[i]; + + assert(cmd->submit_offset == submit_offset); + assert(cmd->size == size); + assert(cmd->type == type); + assert(msm_ring->submit.bos[cmd->submit_idx].handle == + target_cmd->ring_bo->handle); + + return FALSE; + } + + /* create cmd buf if not: */ + i = APPEND(&msm_ring->submit, cmds); + APPEND(msm_ring, cmds); + msm_ring->cmds[i] = target_cmd; + cmd = &msm_ring->submit.cmds[i]; + cmd->type = type; + cmd->submit_idx = bo2idx(ring, target_cmd->ring_bo, FD_RELOC_READ); + cmd->submit_offset = submit_offset; + cmd->size = size; + cmd->pad = 0; + + target_cmd->is_appended_to_submit = TRUE; + + if (!(target_cmd->ring->flags & FD_RINGBUFFER_STREAMING)) { + drmHashInsert(msm_ring->cmd_table, (unsigned long)target_cmd, + U642VOID(i)); + } + + target_cmd->size = size; + + return TRUE; +} + +static void * msm_ringbuffer_hostptr(struct fd_ringbuffer *ring) +{ + struct msm_cmd *cmd = current_cmd(ring); + uint8_t *base = fd_bo_map(cmd->ring_bo); + return base + to_msm_ringbuffer(ring)->offset; +} + +static void delete_cmds(struct msm_ringbuffer *msm_ring) +{ + struct msm_cmd *cmd, *tmp; + + LIST_FOR_EACH_ENTRY_SAFE(cmd, tmp, &msm_ring->cmd_list, list) { + ring_cmd_del(cmd); + } +} + +static void flush_reset(struct fd_ringbuffer *ring) +{ + struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); + unsigned i; + + for (i = 0; i < msm_ring->nr_bos; i++) { + struct msm_bo *msm_bo = to_msm_bo(msm_ring->bos[i]); + if (!msm_bo) + continue; + msm_bo->current_ring_seqno = 0; + fd_bo_del(&msm_bo->base); + } + + for (i = 0; i < msm_ring->nr_cmds; i++) { + struct msm_cmd *msm_cmd = msm_ring->cmds[i]; + + if (msm_cmd->ring == ring) + continue; + + if (msm_cmd->ring->flags & FD_RINGBUFFER_OBJECT) + fd_ringbuffer_del(msm_cmd->ring); + } + + msm_ring->submit.nr_cmds = 0; + msm_ring->submit.nr_bos = 0; + msm_ring->nr_cmds = 0; + msm_ring->nr_bos = 0; + + if (msm_ring->bo_table) { + drmHashDestroy(msm_ring->bo_table); + msm_ring->bo_table = NULL; + } + + if (msm_ring->cmd_table) { + drmHashDestroy(msm_ring->cmd_table); + msm_ring->cmd_table = NULL; + } + + if (msm_ring->is_growable) { + delete_cmds(msm_ring); + } else { + /* in old mode, just reset the # of relocs: */ + current_cmd(ring)->nr_relocs = 0; + } +} + +static void finalize_current_cmd(struct fd_ringbuffer *ring, uint32_t *last_start) +{ + uint32_t submit_offset, size, type; + struct fd_ringbuffer *parent; + + if (ring->parent) { + parent = ring->parent; + type = MSM_SUBMIT_CMD_IB_TARGET_BUF; + } else { + parent = ring; + type = MSM_SUBMIT_CMD_BUF; + } + + submit_offset = offset_bytes(last_start, ring->start); + size = offset_bytes(ring->cur, last_start); + + get_cmd(parent, current_cmd(ring), submit_offset, size, type); +} + +static void dump_submit(struct msm_ringbuffer *msm_ring) +{ + uint32_t i, j; + + for (i = 0; i < msm_ring->submit.nr_bos; i++) { + struct drm_msm_gem_submit_bo *bo = &msm_ring->submit.bos[i]; + ERROR_MSG(" bos[%d]: handle=%u, flags=%x", i, bo->handle, bo->flags); + } + for (i = 0; i < msm_ring->submit.nr_cmds; i++) { + struct drm_msm_gem_submit_cmd *cmd = &msm_ring->submit.cmds[i]; + struct drm_msm_gem_submit_reloc *relocs = U642VOID(cmd->relocs); + ERROR_MSG(" cmd[%d]: type=%u, submit_idx=%u, submit_offset=%u, size=%u", + i, cmd->type, cmd->submit_idx, cmd->submit_offset, cmd->size); + for (j = 0; j < cmd->nr_relocs; j++) { + struct drm_msm_gem_submit_reloc *r = &relocs[j]; + ERROR_MSG(" reloc[%d]: submit_offset=%u, or=%08x, shift=%d, reloc_idx=%u" + ", reloc_offset=%"PRIu64, j, r->submit_offset, r->or, r->shift, + r->reloc_idx, r->reloc_offset); + } + } +} + +static struct drm_msm_gem_submit_reloc * +handle_stateobj_relocs(struct fd_ringbuffer *parent, struct fd_ringbuffer *stateobj, + struct drm_msm_gem_submit_reloc *orig_relocs, unsigned nr_relocs) +{ + struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(stateobj); + struct drm_msm_gem_submit_reloc *relocs = malloc(nr_relocs * sizeof(*relocs)); + unsigned i; + + for (i = 0; i < nr_relocs; i++) { + unsigned idx = orig_relocs[i].reloc_idx; + struct fd_bo *bo = msm_ring->bos[idx]; + unsigned flags = 0; + + if (msm_ring->submit.bos[idx].flags & MSM_SUBMIT_BO_READ) + flags |= FD_RELOC_READ; + if (msm_ring->submit.bos[idx].flags & MSM_SUBMIT_BO_WRITE) + flags |= FD_RELOC_WRITE; + + relocs[i] = orig_relocs[i]; + relocs[i].reloc_idx = bo2idx(parent, bo, flags); + } + + /* stateobj rb's could have reloc's to other stateobj rb's which didn't + * get propagated to the parent rb at _emit_reloc_ring() time (because + * the parent wasn't known then), so fix that up now: + */ + for (i = 0; i < msm_ring->nr_cmds; i++) { + struct msm_cmd *msm_cmd = msm_ring->cmds[i]; + struct drm_msm_gem_submit_cmd *cmd = &msm_ring->submit.cmds[i]; + + if (msm_ring->cmds[i]->ring == stateobj) + continue; + + assert(msm_cmd->ring->flags & FD_RINGBUFFER_OBJECT); + + if (get_cmd(parent, msm_cmd, cmd->submit_offset, cmd->size, cmd->type)) { + fd_ringbuffer_ref(msm_cmd->ring); + } + } + + return relocs; +} + +static int msm_ringbuffer_flush(struct fd_ringbuffer *ring, uint32_t *last_start, + int in_fence_fd, int *out_fence_fd) +{ + struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); + struct msm_pipe *msm_pipe = to_msm_pipe(ring->pipe); + struct drm_msm_gem_submit req = { + .flags = msm_pipe->pipe, + .queueid = msm_pipe->queue_id, + }; + uint32_t i; + int ret; + + assert(!ring->parent); + + if (in_fence_fd != -1) { + req.flags |= MSM_SUBMIT_FENCE_FD_IN | MSM_SUBMIT_NO_IMPLICIT; + req.fence_fd = in_fence_fd; + } + + if (out_fence_fd) { + req.flags |= MSM_SUBMIT_FENCE_FD_OUT; + } + + finalize_current_cmd(ring, last_start); + + /* for each of the cmd's fix up their reloc's: */ + for (i = 0; i < msm_ring->submit.nr_cmds; i++) { + struct msm_cmd *msm_cmd = msm_ring->cmds[i]; + struct drm_msm_gem_submit_reloc *relocs = msm_cmd->relocs; + struct drm_msm_gem_submit_cmd *cmd; + unsigned nr_relocs = msm_cmd->nr_relocs; + + /* for reusable stateobjs, the reloc table has reloc_idx that + * points into it's own private bos table, rather than the global + * bos table used for the submit, so we need to add the stateobj's + * bos to the global table and construct new relocs table with + * corresponding reloc_idx + */ + if (msm_cmd->ring->flags & FD_RINGBUFFER_OBJECT) { + relocs = handle_stateobj_relocs(ring, msm_cmd->ring, + relocs, nr_relocs); + } + + cmd = &msm_ring->submit.cmds[i]; + cmd->relocs = VOID2U64(relocs); + cmd->nr_relocs = nr_relocs; + } + + /* needs to be after get_cmd() as that could create bos/cmds table: */ + req.bos = VOID2U64(msm_ring->submit.bos), + req.nr_bos = msm_ring->submit.nr_bos; + req.cmds = VOID2U64(msm_ring->submit.cmds), + req.nr_cmds = msm_ring->submit.nr_cmds; + + DEBUG_MSG("nr_cmds=%u, nr_bos=%u", req.nr_cmds, req.nr_bos); + + ret = drmCommandWriteRead(ring->pipe->dev->fd, DRM_MSM_GEM_SUBMIT, + &req, sizeof(req)); + if (ret) { + ERROR_MSG("submit failed: %d (%s)", ret, strerror(errno)); + dump_submit(msm_ring); + } else if (!ret) { + /* update timestamp on all rings associated with submit: */ + for (i = 0; i < msm_ring->submit.nr_cmds; i++) { + struct msm_cmd *msm_cmd = msm_ring->cmds[i]; + msm_cmd->ring->last_timestamp = req.fence; + } + + if (out_fence_fd) { + *out_fence_fd = req.fence_fd; + } + } + + /* free dynamically constructed stateobj relocs tables: */ + for (i = 0; i < msm_ring->submit.nr_cmds; i++) { + struct drm_msm_gem_submit_cmd *cmd = &msm_ring->submit.cmds[i]; + struct msm_cmd *msm_cmd = msm_ring->cmds[i]; + if (msm_cmd->ring->flags & FD_RINGBUFFER_OBJECT) { + free(U642VOID(cmd->relocs)); + } + } + + flush_reset(ring); + + return ret; +} + +static void msm_ringbuffer_grow(struct fd_ringbuffer *ring, uint32_t size) +{ + assert(to_msm_ringbuffer(ring)->is_growable); + finalize_current_cmd(ring, ring->last_start); + ring_cmd_new(ring, size, 0); +} + +static void msm_ringbuffer_reset(struct fd_ringbuffer *ring) +{ + flush_reset(ring); +} + +static void msm_ringbuffer_emit_reloc(struct fd_ringbuffer *ring, + const struct fd_reloc *r) +{ + struct fd_ringbuffer *parent = ring->parent ? ring->parent : ring; + struct msm_bo *msm_bo = to_msm_bo(r->bo); + struct drm_msm_gem_submit_reloc *reloc; + struct msm_cmd *cmd = current_cmd(ring); + uint32_t idx = APPEND(cmd, relocs); + uint32_t addr; + + reloc = &cmd->relocs[idx]; + + reloc->reloc_idx = bo2idx(parent, r->bo, r->flags); + reloc->reloc_offset = r->offset; + reloc->or = r->or; + reloc->shift = r->shift; + reloc->submit_offset = offset_bytes(ring->cur, ring->start) + + to_msm_ringbuffer(ring)->offset; + + addr = msm_bo->presumed; + if (reloc->shift < 0) + addr >>= -reloc->shift; + else + addr <<= reloc->shift; + (*ring->cur++) = addr | r->or; + + if (ring->pipe->gpu_id >= 500) { + struct drm_msm_gem_submit_reloc *reloc_hi; + + /* NOTE: grab reloc_idx *before* APPEND() since that could + * realloc() meaning that 'reloc' ptr is no longer valid: + */ + uint32_t reloc_idx = reloc->reloc_idx; + + idx = APPEND(cmd, relocs); + + reloc_hi = &cmd->relocs[idx]; + + reloc_hi->reloc_idx = reloc_idx; + reloc_hi->reloc_offset = r->offset; + reloc_hi->or = r->orhi; + reloc_hi->shift = r->shift - 32; + reloc_hi->submit_offset = offset_bytes(ring->cur, ring->start) + + to_msm_ringbuffer(ring)->offset; + + addr = msm_bo->presumed >> 32; + if (reloc_hi->shift < 0) + addr >>= -reloc_hi->shift; + else + addr <<= reloc_hi->shift; + (*ring->cur++) = addr | r->orhi; + } +} + +static uint32_t msm_ringbuffer_emit_reloc_ring(struct fd_ringbuffer *ring, + struct fd_ringbuffer *target, uint32_t cmd_idx) +{ + struct msm_cmd *cmd = NULL; + struct msm_ringbuffer *msm_target = to_msm_ringbuffer(target); + uint32_t idx = 0; + int added_cmd = FALSE; + uint32_t size; + uint32_t submit_offset = msm_target->offset; + + LIST_FOR_EACH_ENTRY(cmd, &msm_target->cmd_list, list) { + if (idx == cmd_idx) + break; + idx++; + } + + assert(cmd && (idx == cmd_idx)); + + if (idx < (msm_target->cmd_count - 1)) { + /* All but the last cmd buffer is fully "baked" (ie. already has + * done get_cmd() to add it to the cmds table). But in this case, + * the size we get is invalid (since it is calculated from the + * last cmd buffer): + */ + size = cmd->size; + } else { + struct fd_ringbuffer *parent = ring->parent ? ring->parent : ring; + size = offset_bytes(target->cur, target->start); + added_cmd = get_cmd(parent, cmd, submit_offset, size, + MSM_SUBMIT_CMD_IB_TARGET_BUF); + } + + msm_ringbuffer_emit_reloc(ring, &(struct fd_reloc){ + .bo = cmd->ring_bo, + .flags = FD_RELOC_READ, + .offset = submit_offset, + }); + + /* Unlike traditional ringbuffers which are deleted as a set (after + * being flushed), mesa can't really guarantee that a stateobj isn't + * destroyed after emitted but before flush, so we must hold a ref: + */ + if (added_cmd && (target->flags & FD_RINGBUFFER_OBJECT)) { + fd_ringbuffer_ref(target); + } + + return size; +} + +static uint32_t msm_ringbuffer_cmd_count(struct fd_ringbuffer *ring) +{ + return to_msm_ringbuffer(ring)->cmd_count; +} + +static void msm_ringbuffer_destroy(struct fd_ringbuffer *ring) +{ + struct msm_ringbuffer *msm_ring = to_msm_ringbuffer(ring); + + flush_reset(ring); + delete_cmds(msm_ring); + + free(msm_ring->submit.cmds); + free(msm_ring->submit.bos); + free(msm_ring->bos); + free(msm_ring->cmds); + free(msm_ring); +} + +static const struct fd_ringbuffer_funcs funcs = { + .hostptr = msm_ringbuffer_hostptr, + .flush = msm_ringbuffer_flush, + .grow = msm_ringbuffer_grow, + .reset = msm_ringbuffer_reset, + .emit_reloc = msm_ringbuffer_emit_reloc, + .emit_reloc_ring = msm_ringbuffer_emit_reloc_ring, + .cmd_count = msm_ringbuffer_cmd_count, + .destroy = msm_ringbuffer_destroy, +}; + +drm_private struct fd_ringbuffer * msm_ringbuffer_new(struct fd_pipe *pipe, + uint32_t size, enum fd_ringbuffer_flags flags) +{ + struct msm_ringbuffer *msm_ring; + struct fd_ringbuffer *ring; + + msm_ring = calloc(1, sizeof(*msm_ring)); + if (!msm_ring) { + ERROR_MSG("allocation failed"); + return NULL; + } + + if (size == 0) { + assert(pipe->dev->version >= FD_VERSION_UNLIMITED_CMDS); + size = INIT_SIZE; + msm_ring->is_growable = TRUE; + } + + list_inithead(&msm_ring->cmd_list); + msm_ring->seqno = ++to_msm_device(pipe->dev)->ring_cnt; + + ring = &msm_ring->base; + atomic_set(&ring->refcnt, 1); + + ring->funcs = &funcs; + ring->size = size; + ring->pipe = pipe; /* needed in ring_cmd_new() */ + + ring_cmd_new(ring, size, flags); + + return ring; +} diff --git a/gen_table_fourcc.py b/gen_table_fourcc.py new file mode 100644 index 0000000..1473d43 --- /dev/null +++ b/gen_table_fourcc.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 + +# Copyright 2021 Collabora, 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 (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 +# 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. + +# Helper script that reads drm_fourcc.h and writes a static table with the +# simpler format token modifiers + +import sys +import re + +filename = sys.argv[1] +towrite = sys.argv[2] + +fm_re = { + 'intel': r'^#define I915_FORMAT_MOD_(\w+)', + 'others': r'^#define DRM_FORMAT_MOD_((?:ARM|SAMSUNG|QCOM|VIVANTE|NVIDIA|BROADCOM|ALLWINNER)\w+)\s', + 'vendors': r'^#define DRM_FORMAT_MOD_VENDOR_(\w+)' +} + +def print_fm_intel(f, f_mod): + f.write(' {{ DRM_MODIFIER_INTEL({}, {}) }},\n'.format(f_mod, f_mod)) + +# generic write func +def print_fm(f, vendor, mod, f_name): + f.write(' {{ DRM_MODIFIER({}, {}, {}) }},\n'.format(vendor, mod, f_name)) + +with open(filename, "r") as f: + data = f.read() + for k, v in fm_re.items(): + fm_re[k] = re.findall(v, data, flags=re.M) + +with open(towrite, "w") as f: + f.write('''\ +/* AUTOMATICALLY GENERATED by gen_table_fourcc.py. You should modify + that script instead of adding here entries manually! */ +static const struct drmFormatModifierInfo drm_format_modifier_table[] = { +''') + f.write(' { DRM_MODIFIER_INVALID(NONE, INVALID) },\n') + f.write(' { DRM_MODIFIER_LINEAR(NONE, LINEAR) },\n') + + for entry in fm_re['intel']: + print_fm_intel(f, entry) + + for entry in fm_re['others']: + (vendor, mod) = entry.split('_', 1) + if vendor == 'ARM' and (mod == 'TYPE_AFBC' or mod == 'TYPE_MISC' or mod == 'TYPE_AFRC'): + continue + print_fm(f, vendor, mod, mod) + + f.write('''\ +}; +''') + + f.write('''\ +static const struct drmFormatModifierVendorInfo drm_format_modifier_vendor_table[] = { +''') + + for entry in fm_re['vendors']: + f.write(" {{ DRM_FORMAT_MOD_VENDOR_{}, \"{}\" }},\n".format(entry, entry)) + + f.write('''\ +}; +''') diff --git a/include/drm/README b/include/drm/README new file mode 100644 index 0000000..ea2320c --- /dev/null +++ b/include/drm/README @@ -0,0 +1,128 @@ +What are these headers ? +------------------------ +This is the canonical source of drm headers that user space should use for +communicating with the kernel DRM subsystem. + +They flow from the kernel, thus any changes must be merged there first. +Do _not_ attempt to "fix" these by deviating from the kernel ones ! + + +Non-linux platforms - changes/patches +------------------------------------- +If your platform has local changes, please send them upstream for inclusion. +Even if your patches don't get accepted in their current form, devs will +give you feedback on how to address things properly. + +git send-email --subject-prefix="PATCH libdrm" your patches to dri-devel +mailing list. + +Before doing so, please consider the following: + - Have the [libdrm vs kernel] headers on your platform deviated ? +Consider unifying them first. + + - Have you introduced additional ABI that's not available in Linux ? +Propose it for [Linux kernel] upstream inclusion. +If that doesn't work out (hopefully it never does), move it to another header +and/or keep the change(s) local ? + + - Are your changes DRI1/UMS specific ? +There is virtually no interest/power in keeping those legacy interfaces. They +are around due to the kernel "thou shalt not break existing user space" rule. + +Consider porting the driver to DRI2/KMS - all (almost?) sensible hardware is +capable of supporting those. + + +Which headers go where ? +------------------------ +A snipped from the, now removed, Makefile.am used to state: + + XXX airlied says, nothing besides *_drm.h and drm*.h should be necessary. + however, r300 and via need their reg headers installed in order to build. + better solutions are welcome. + +Obviously the r300 and via headers are no longer around ;-) + +Reason behind is that the drm headers can be used as a basic communications +channel with the respective kernel modules. If more advanced functionality is +required one can pull the specific libdrm_$driver which is free to pull +additional files from the kernel. + +For example: nouveau has nouveau/nvif/*.h while vc4 has vc4/*.h + +If your driver is still in prototyping/staging state, consider moving the +$driver_drm.h into $driver and _not_ installing it. An header providing opaque +definitions and access [via $driver_drmif.h or similar] would be better fit. + + +When and which headers to update +-------------------------------- +Ideally all files will be synced (updated) with the latest released kernel on +each libdrm release. Sadly that's not yet possible since quite a few headers +differ significantly - see Outdated or Broken Headers section below. + +That said, it's up-to the individual developers to sync with newer version +(from drm-next) as they see fit. + + +When and how to update these files +---------------------------------- +Note: One should not do _any_ changes to the files apart from the steps below. + +In order to update the files do the following: + - Switch to a Linux kernel tree/branch which is not rebased. + For example: drm-next (https://cgit.freedesktop.org/drm/drm) + - Install the headers via `make headers_install' to a separate location. + - Copy the drm header[s] + git add + git commit. + - Note: Your commit message must include: + a) Brief summary on the delta. If there's any change that looks like an +API/ABI break one _must_ explicitly state why it's safe to do so. + b) "Generated using make headers_install." + c) "Generated from $tree/branch commit $sha" + + +Outdated or Broken Headers +-------------------------- +This section contains a list of headers and the respective "issues" they might +have relative to their kernel equivalent. + +Most UMS headers: + - Not using fixed size integers - compat ioctls are broken. +Status: ? +Promote to fixed size ints, which match the current (32bit) ones. + +nouveau_drm.h + - Missing macros NOUVEAU_GETPARAM*, NOUVEAU_DRM_HEADER_PATCHLEVEL, structs, +enums +Status: Deliberate UABI choice; nouveau hides the exact kernel ABI behind libdrm + +r128_drm.h + - Broken compat ioctls. + +radeon_drm.h + - Missing RADEON_TILING_R600_NO_SCANOUT, CIK_TILE_MODE_*, broken UMS ioctls + - Both kernel and libdrm: missing padding - +drm_radeon_gem_{create,{g,s}et_tiling,set_domain} others ? +Status: ? + +savage_drm.h + - Renamed ioctls - DRM_IOCTL_SAVAGE_{,BCI}_EVENT_EMIT, compat ioctls are broken. +Status: ? + +sis_drm.h + - Borken ioctls + libdrm uses int vs kernel long +Status: ? + +via_drm.h + - Borken ioctls - libdrm int vs kernel long +Status: ? + + +omap_drm.h (living in $TOP/omap) + - License mismatch, missing DRM_IOCTL_OMAP_GEM_NEW and related struct +Status: ? + +exynos_drm.h (living in $TOP/exynos) + - License mismatch, now using fixed size ints (but not everywhere). Lots of +new stuff. +Status: ? diff --git a/include/drm/amdgpu_drm.h b/include/drm/amdgpu_drm.h new file mode 100644 index 0000000..c0a0ad1 --- /dev/null +++ b/include/drm/amdgpu_drm.h @@ -0,0 +1,1161 @@ +/* amdgpu_drm.h -- Public header for the amdgpu driver -*- linux-c -*- + * + * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Fremont, California. + * Copyright 2002 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright 2014 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + * Authors: + * Kevin E. Martin + * Gareth Hughes + * Keith Whitwell + */ + +#ifndef __AMDGPU_DRM_H__ +#define __AMDGPU_DRM_H__ + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +#define DRM_AMDGPU_GEM_CREATE 0x00 +#define DRM_AMDGPU_GEM_MMAP 0x01 +#define DRM_AMDGPU_CTX 0x02 +#define DRM_AMDGPU_BO_LIST 0x03 +#define DRM_AMDGPU_CS 0x04 +#define DRM_AMDGPU_INFO 0x05 +#define DRM_AMDGPU_GEM_METADATA 0x06 +#define DRM_AMDGPU_GEM_WAIT_IDLE 0x07 +#define DRM_AMDGPU_GEM_VA 0x08 +#define DRM_AMDGPU_WAIT_CS 0x09 +#define DRM_AMDGPU_GEM_OP 0x10 +#define DRM_AMDGPU_GEM_USERPTR 0x11 +#define DRM_AMDGPU_WAIT_FENCES 0x12 +#define DRM_AMDGPU_VM 0x13 +#define DRM_AMDGPU_FENCE_TO_HANDLE 0x14 +#define DRM_AMDGPU_SCHED 0x15 + +#define DRM_IOCTL_AMDGPU_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_CREATE, union drm_amdgpu_gem_create) +#define DRM_IOCTL_AMDGPU_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_MMAP, union drm_amdgpu_gem_mmap) +#define DRM_IOCTL_AMDGPU_CTX DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_CTX, union drm_amdgpu_ctx) +#define DRM_IOCTL_AMDGPU_BO_LIST DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_BO_LIST, union drm_amdgpu_bo_list) +#define DRM_IOCTL_AMDGPU_CS DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_CS, union drm_amdgpu_cs) +#define DRM_IOCTL_AMDGPU_INFO DRM_IOW(DRM_COMMAND_BASE + DRM_AMDGPU_INFO, struct drm_amdgpu_info) +#define DRM_IOCTL_AMDGPU_GEM_METADATA DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_METADATA, struct drm_amdgpu_gem_metadata) +#define DRM_IOCTL_AMDGPU_GEM_WAIT_IDLE DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_WAIT_IDLE, union drm_amdgpu_gem_wait_idle) +#define DRM_IOCTL_AMDGPU_GEM_VA DRM_IOW(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_VA, struct drm_amdgpu_gem_va) +#define DRM_IOCTL_AMDGPU_WAIT_CS DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_WAIT_CS, union drm_amdgpu_wait_cs) +#define DRM_IOCTL_AMDGPU_GEM_OP DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_OP, struct drm_amdgpu_gem_op) +#define DRM_IOCTL_AMDGPU_GEM_USERPTR DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_USERPTR, struct drm_amdgpu_gem_userptr) +#define DRM_IOCTL_AMDGPU_WAIT_FENCES DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_WAIT_FENCES, union drm_amdgpu_wait_fences) +#define DRM_IOCTL_AMDGPU_VM DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_VM, union drm_amdgpu_vm) +#define DRM_IOCTL_AMDGPU_FENCE_TO_HANDLE DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_FENCE_TO_HANDLE, union drm_amdgpu_fence_to_handle) +#define DRM_IOCTL_AMDGPU_SCHED DRM_IOW(DRM_COMMAND_BASE + DRM_AMDGPU_SCHED, union drm_amdgpu_sched) + +/** + * DOC: memory domains + * + * %AMDGPU_GEM_DOMAIN_CPU System memory that is not GPU accessible. + * Memory in this pool could be swapped out to disk if there is pressure. + * + * %AMDGPU_GEM_DOMAIN_GTT GPU accessible system memory, mapped into the + * GPU's virtual address space via gart. Gart memory linearizes non-contiguous + * pages of system memory, allows GPU access system memory in a linearized + * fashion. + * + * %AMDGPU_GEM_DOMAIN_VRAM Local video memory. For APUs, it is memory + * carved out by the BIOS. + * + * %AMDGPU_GEM_DOMAIN_GDS Global on-chip data storage used to share data + * across shader threads. + * + * %AMDGPU_GEM_DOMAIN_GWS Global wave sync, used to synchronize the + * execution of all the waves on a device. + * + * %AMDGPU_GEM_DOMAIN_OA Ordered append, used by 3D or Compute engines + * for appending data. + */ +#define AMDGPU_GEM_DOMAIN_CPU 0x1 +#define AMDGPU_GEM_DOMAIN_GTT 0x2 +#define AMDGPU_GEM_DOMAIN_VRAM 0x4 +#define AMDGPU_GEM_DOMAIN_GDS 0x8 +#define AMDGPU_GEM_DOMAIN_GWS 0x10 +#define AMDGPU_GEM_DOMAIN_OA 0x20 +#define AMDGPU_GEM_DOMAIN_MASK (AMDGPU_GEM_DOMAIN_CPU | \ + AMDGPU_GEM_DOMAIN_GTT | \ + AMDGPU_GEM_DOMAIN_VRAM | \ + AMDGPU_GEM_DOMAIN_GDS | \ + AMDGPU_GEM_DOMAIN_GWS | \ + AMDGPU_GEM_DOMAIN_OA) + +/* Flag that CPU access will be required for the case of VRAM domain */ +#define AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED (1 << 0) +/* Flag that CPU access will not work, this VRAM domain is invisible */ +#define AMDGPU_GEM_CREATE_NO_CPU_ACCESS (1 << 1) +/* Flag that USWC attributes should be used for GTT */ +#define AMDGPU_GEM_CREATE_CPU_GTT_USWC (1 << 2) +/* Flag that the memory should be in VRAM and cleared */ +#define AMDGPU_GEM_CREATE_VRAM_CLEARED (1 << 3) +/* Flag that allocating the BO should use linear VRAM */ +#define AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS (1 << 5) +/* Flag that BO is always valid in this VM */ +#define AMDGPU_GEM_CREATE_VM_ALWAYS_VALID (1 << 6) +/* Flag that BO sharing will be explicitly synchronized */ +#define AMDGPU_GEM_CREATE_EXPLICIT_SYNC (1 << 7) +/* Flag that indicates allocating MQD gart on GFX9, where the mtype + * for the second page onward should be set to NC. It should never + * be used by user space applications. + */ +#define AMDGPU_GEM_CREATE_CP_MQD_GFX9 (1 << 8) +/* Flag that BO may contain sensitive data that must be wiped before + * releasing the memory + */ +#define AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE (1 << 9) +/* Flag that BO will be encrypted and that the TMZ bit should be + * set in the PTEs when mapping this buffer via GPUVM or + * accessing it with various hw blocks + */ +#define AMDGPU_GEM_CREATE_ENCRYPTED (1 << 10) +/* Flag that BO will be used only in preemptible context, which does + * not require GTT memory accounting + */ +#define AMDGPU_GEM_CREATE_PREEMPTIBLE (1 << 11) + +struct drm_amdgpu_gem_create_in { + /** the requested memory size */ + __u64 bo_size; + /** physical start_addr alignment in bytes for some HW requirements */ + __u64 alignment; + /** the requested memory domains */ + __u64 domains; + /** allocation flags */ + __u64 domain_flags; +}; + +struct drm_amdgpu_gem_create_out { + /** returned GEM object handle */ + __u32 handle; + __u32 _pad; +}; + +union drm_amdgpu_gem_create { + struct drm_amdgpu_gem_create_in in; + struct drm_amdgpu_gem_create_out out; +}; + +/** Opcode to create new residency list. */ +#define AMDGPU_BO_LIST_OP_CREATE 0 +/** Opcode to destroy previously created residency list */ +#define AMDGPU_BO_LIST_OP_DESTROY 1 +/** Opcode to update resource information in the list */ +#define AMDGPU_BO_LIST_OP_UPDATE 2 + +struct drm_amdgpu_bo_list_in { + /** Type of operation */ + __u32 operation; + /** Handle of list or 0 if we want to create one */ + __u32 list_handle; + /** Number of BOs in list */ + __u32 bo_number; + /** Size of each element describing BO */ + __u32 bo_info_size; + /** Pointer to array describing BOs */ + __u64 bo_info_ptr; +}; + +struct drm_amdgpu_bo_list_entry { + /** Handle of BO */ + __u32 bo_handle; + /** New (if specified) BO priority to be used during migration */ + __u32 bo_priority; +}; + +struct drm_amdgpu_bo_list_out { + /** Handle of resource list */ + __u32 list_handle; + __u32 _pad; +}; + +union drm_amdgpu_bo_list { + struct drm_amdgpu_bo_list_in in; + struct drm_amdgpu_bo_list_out out; +}; + +/* context related */ +#define AMDGPU_CTX_OP_ALLOC_CTX 1 +#define AMDGPU_CTX_OP_FREE_CTX 2 +#define AMDGPU_CTX_OP_QUERY_STATE 3 +#define AMDGPU_CTX_OP_QUERY_STATE2 4 +#define AMDGPU_CTX_OP_GET_STABLE_PSTATE 5 +#define AMDGPU_CTX_OP_SET_STABLE_PSTATE 6 + +/* GPU reset status */ +#define AMDGPU_CTX_NO_RESET 0 +/* this the context caused it */ +#define AMDGPU_CTX_GUILTY_RESET 1 +/* some other context caused it */ +#define AMDGPU_CTX_INNOCENT_RESET 2 +/* unknown cause */ +#define AMDGPU_CTX_UNKNOWN_RESET 3 + +/* indicate gpu reset occured after ctx created */ +#define AMDGPU_CTX_QUERY2_FLAGS_RESET (1<<0) +/* indicate vram lost occured after ctx created */ +#define AMDGPU_CTX_QUERY2_FLAGS_VRAMLOST (1<<1) +/* indicate some job from this context once cause gpu hang */ +#define AMDGPU_CTX_QUERY2_FLAGS_GUILTY (1<<2) +/* indicate some errors are detected by RAS */ +#define AMDGPU_CTX_QUERY2_FLAGS_RAS_CE (1<<3) +#define AMDGPU_CTX_QUERY2_FLAGS_RAS_UE (1<<4) + +/* Context priority level */ +#define AMDGPU_CTX_PRIORITY_UNSET -2048 +#define AMDGPU_CTX_PRIORITY_VERY_LOW -1023 +#define AMDGPU_CTX_PRIORITY_LOW -512 +#define AMDGPU_CTX_PRIORITY_NORMAL 0 +/* + * When used in struct drm_amdgpu_ctx_in, a priority above NORMAL requires + * CAP_SYS_NICE or DRM_MASTER +*/ +#define AMDGPU_CTX_PRIORITY_HIGH 512 +#define AMDGPU_CTX_PRIORITY_VERY_HIGH 1023 + +/* select a stable profiling pstate for perfmon tools */ +#define AMDGPU_CTX_STABLE_PSTATE_FLAGS_MASK 0xf +#define AMDGPU_CTX_STABLE_PSTATE_NONE 0 +#define AMDGPU_CTX_STABLE_PSTATE_STANDARD 1 +#define AMDGPU_CTX_STABLE_PSTATE_MIN_SCLK 2 +#define AMDGPU_CTX_STABLE_PSTATE_MIN_MCLK 3 +#define AMDGPU_CTX_STABLE_PSTATE_PEAK 4 + +struct drm_amdgpu_ctx_in { + /** AMDGPU_CTX_OP_* */ + __u32 op; + /** Flags */ + __u32 flags; + __u32 ctx_id; + /** AMDGPU_CTX_PRIORITY_* */ + __s32 priority; +}; + +union drm_amdgpu_ctx_out { + struct { + __u32 ctx_id; + __u32 _pad; + } alloc; + + struct { + /** For future use, no flags defined so far */ + __u64 flags; + /** Number of resets caused by this context so far. */ + __u32 hangs; + /** Reset status since the last call of the ioctl. */ + __u32 reset_status; + } state; + + struct { + __u32 flags; + __u32 _pad; + } pstate; +}; + +union drm_amdgpu_ctx { + struct drm_amdgpu_ctx_in in; + union drm_amdgpu_ctx_out out; +}; + +/* vm ioctl */ +#define AMDGPU_VM_OP_RESERVE_VMID 1 +#define AMDGPU_VM_OP_UNRESERVE_VMID 2 + +struct drm_amdgpu_vm_in { + /** AMDGPU_VM_OP_* */ + __u32 op; + __u32 flags; +}; + +struct drm_amdgpu_vm_out { + /** For future use, no flags defined so far */ + __u64 flags; +}; + +union drm_amdgpu_vm { + struct drm_amdgpu_vm_in in; + struct drm_amdgpu_vm_out out; +}; + +/* sched ioctl */ +#define AMDGPU_SCHED_OP_PROCESS_PRIORITY_OVERRIDE 1 +#define AMDGPU_SCHED_OP_CONTEXT_PRIORITY_OVERRIDE 2 + +struct drm_amdgpu_sched_in { + /* AMDGPU_SCHED_OP_* */ + __u32 op; + __u32 fd; + /** AMDGPU_CTX_PRIORITY_* */ + __s32 priority; + __u32 ctx_id; +}; + +union drm_amdgpu_sched { + struct drm_amdgpu_sched_in in; +}; + +/* + * This is not a reliable API and you should expect it to fail for any + * number of reasons and have fallback path that do not use userptr to + * perform any operation. + */ +#define AMDGPU_GEM_USERPTR_READONLY (1 << 0) +#define AMDGPU_GEM_USERPTR_ANONONLY (1 << 1) +#define AMDGPU_GEM_USERPTR_VALIDATE (1 << 2) +#define AMDGPU_GEM_USERPTR_REGISTER (1 << 3) + +struct drm_amdgpu_gem_userptr { + __u64 addr; + __u64 size; + /* AMDGPU_GEM_USERPTR_* */ + __u32 flags; + /* Resulting GEM handle */ + __u32 handle; +}; + +/* SI-CI-VI: */ +/* same meaning as the GB_TILE_MODE and GL_MACRO_TILE_MODE fields */ +#define AMDGPU_TILING_ARRAY_MODE_SHIFT 0 +#define AMDGPU_TILING_ARRAY_MODE_MASK 0xf +#define AMDGPU_TILING_PIPE_CONFIG_SHIFT 4 +#define AMDGPU_TILING_PIPE_CONFIG_MASK 0x1f +#define AMDGPU_TILING_TILE_SPLIT_SHIFT 9 +#define AMDGPU_TILING_TILE_SPLIT_MASK 0x7 +#define AMDGPU_TILING_MICRO_TILE_MODE_SHIFT 12 +#define AMDGPU_TILING_MICRO_TILE_MODE_MASK 0x7 +#define AMDGPU_TILING_BANK_WIDTH_SHIFT 15 +#define AMDGPU_TILING_BANK_WIDTH_MASK 0x3 +#define AMDGPU_TILING_BANK_HEIGHT_SHIFT 17 +#define AMDGPU_TILING_BANK_HEIGHT_MASK 0x3 +#define AMDGPU_TILING_MACRO_TILE_ASPECT_SHIFT 19 +#define AMDGPU_TILING_MACRO_TILE_ASPECT_MASK 0x3 +#define AMDGPU_TILING_NUM_BANKS_SHIFT 21 +#define AMDGPU_TILING_NUM_BANKS_MASK 0x3 + +/* GFX9 and later: */ +#define AMDGPU_TILING_SWIZZLE_MODE_SHIFT 0 +#define AMDGPU_TILING_SWIZZLE_MODE_MASK 0x1f +#define AMDGPU_TILING_DCC_OFFSET_256B_SHIFT 5 +#define AMDGPU_TILING_DCC_OFFSET_256B_MASK 0xFFFFFF +#define AMDGPU_TILING_DCC_PITCH_MAX_SHIFT 29 +#define AMDGPU_TILING_DCC_PITCH_MAX_MASK 0x3FFF +#define AMDGPU_TILING_DCC_INDEPENDENT_64B_SHIFT 43 +#define AMDGPU_TILING_DCC_INDEPENDENT_64B_MASK 0x1 +#define AMDGPU_TILING_DCC_INDEPENDENT_128B_SHIFT 44 +#define AMDGPU_TILING_DCC_INDEPENDENT_128B_MASK 0x1 +#define AMDGPU_TILING_SCANOUT_SHIFT 63 +#define AMDGPU_TILING_SCANOUT_MASK 0x1 + +/* Set/Get helpers for tiling flags. */ +#define AMDGPU_TILING_SET(field, value) \ + (((__u64)(value) & AMDGPU_TILING_##field##_MASK) << AMDGPU_TILING_##field##_SHIFT) +#define AMDGPU_TILING_GET(value, field) \ + (((__u64)(value) >> AMDGPU_TILING_##field##_SHIFT) & AMDGPU_TILING_##field##_MASK) + +#define AMDGPU_GEM_METADATA_OP_SET_METADATA 1 +#define AMDGPU_GEM_METADATA_OP_GET_METADATA 2 + +/** The same structure is shared for input/output */ +struct drm_amdgpu_gem_metadata { + /** GEM Object handle */ + __u32 handle; + /** Do we want get or set metadata */ + __u32 op; + struct { + /** For future use, no flags defined so far */ + __u64 flags; + /** family specific tiling info */ + __u64 tiling_info; + __u32 data_size_bytes; + __u32 data[64]; + } data; +}; + +struct drm_amdgpu_gem_mmap_in { + /** the GEM object handle */ + __u32 handle; + __u32 _pad; +}; + +struct drm_amdgpu_gem_mmap_out { + /** mmap offset from the vma offset manager */ + __u64 addr_ptr; +}; + +union drm_amdgpu_gem_mmap { + struct drm_amdgpu_gem_mmap_in in; + struct drm_amdgpu_gem_mmap_out out; +}; + +struct drm_amdgpu_gem_wait_idle_in { + /** GEM object handle */ + __u32 handle; + /** For future use, no flags defined so far */ + __u32 flags; + /** Absolute timeout to wait */ + __u64 timeout; +}; + +struct drm_amdgpu_gem_wait_idle_out { + /** BO status: 0 - BO is idle, 1 - BO is busy */ + __u32 status; + /** Returned current memory domain */ + __u32 domain; +}; + +union drm_amdgpu_gem_wait_idle { + struct drm_amdgpu_gem_wait_idle_in in; + struct drm_amdgpu_gem_wait_idle_out out; +}; + +struct drm_amdgpu_wait_cs_in { + /* Command submission handle + * handle equals 0 means none to wait for + * handle equals ~0ull means wait for the latest sequence number + */ + __u64 handle; + /** Absolute timeout to wait */ + __u64 timeout; + __u32 ip_type; + __u32 ip_instance; + __u32 ring; + __u32 ctx_id; +}; + +struct drm_amdgpu_wait_cs_out { + /** CS status: 0 - CS completed, 1 - CS still busy */ + __u64 status; +}; + +union drm_amdgpu_wait_cs { + struct drm_amdgpu_wait_cs_in in; + struct drm_amdgpu_wait_cs_out out; +}; + +struct drm_amdgpu_fence { + __u32 ctx_id; + __u32 ip_type; + __u32 ip_instance; + __u32 ring; + __u64 seq_no; +}; + +struct drm_amdgpu_wait_fences_in { + /** This points to uint64_t * which points to fences */ + __u64 fences; + __u32 fence_count; + __u32 wait_all; + __u64 timeout_ns; +}; + +struct drm_amdgpu_wait_fences_out { + __u32 status; + __u32 first_signaled; +}; + +union drm_amdgpu_wait_fences { + struct drm_amdgpu_wait_fences_in in; + struct drm_amdgpu_wait_fences_out out; +}; + +#define AMDGPU_GEM_OP_GET_GEM_CREATE_INFO 0 +#define AMDGPU_GEM_OP_SET_PLACEMENT 1 + +/* Sets or returns a value associated with a buffer. */ +struct drm_amdgpu_gem_op { + /** GEM object handle */ + __u32 handle; + /** AMDGPU_GEM_OP_* */ + __u32 op; + /** Input or return value */ + __u64 value; +}; + +#define AMDGPU_VA_OP_MAP 1 +#define AMDGPU_VA_OP_UNMAP 2 +#define AMDGPU_VA_OP_CLEAR 3 +#define AMDGPU_VA_OP_REPLACE 4 + +/* Delay the page table update till the next CS */ +#define AMDGPU_VM_DELAY_UPDATE (1 << 0) + +/* Mapping flags */ +/* readable mapping */ +#define AMDGPU_VM_PAGE_READABLE (1 << 1) +/* writable mapping */ +#define AMDGPU_VM_PAGE_WRITEABLE (1 << 2) +/* executable mapping, new for VI */ +#define AMDGPU_VM_PAGE_EXECUTABLE (1 << 3) +/* partially resident texture */ +#define AMDGPU_VM_PAGE_PRT (1 << 4) +/* MTYPE flags use bit 5 to 8 */ +#define AMDGPU_VM_MTYPE_MASK (0xf << 5) +/* Default MTYPE. Pre-AI must use this. Recommended for newer ASICs. */ +#define AMDGPU_VM_MTYPE_DEFAULT (0 << 5) +/* Use Non Coherent MTYPE instead of default MTYPE */ +#define AMDGPU_VM_MTYPE_NC (1 << 5) +/* Use Write Combine MTYPE instead of default MTYPE */ +#define AMDGPU_VM_MTYPE_WC (2 << 5) +/* Use Cache Coherent MTYPE instead of default MTYPE */ +#define AMDGPU_VM_MTYPE_CC (3 << 5) +/* Use UnCached MTYPE instead of default MTYPE */ +#define AMDGPU_VM_MTYPE_UC (4 << 5) +/* Use Read Write MTYPE instead of default MTYPE */ +#define AMDGPU_VM_MTYPE_RW (5 << 5) + +struct drm_amdgpu_gem_va { + /** GEM object handle */ + __u32 handle; + __u32 _pad; + /** AMDGPU_VA_OP_* */ + __u32 operation; + /** AMDGPU_VM_PAGE_* */ + __u32 flags; + /** va address to assign . Must be correctly aligned.*/ + __u64 va_address; + /** Specify offset inside of BO to assign. Must be correctly aligned.*/ + __u64 offset_in_bo; + /** Specify mapping size. Must be correctly aligned. */ + __u64 map_size; +}; + +#define AMDGPU_HW_IP_GFX 0 +#define AMDGPU_HW_IP_COMPUTE 1 +#define AMDGPU_HW_IP_DMA 2 +#define AMDGPU_HW_IP_UVD 3 +#define AMDGPU_HW_IP_VCE 4 +#define AMDGPU_HW_IP_UVD_ENC 5 +#define AMDGPU_HW_IP_VCN_DEC 6 +/* + * From VCN4, AMDGPU_HW_IP_VCN_ENC is re-used to support + * both encoding and decoding jobs. + */ +#define AMDGPU_HW_IP_VCN_ENC 7 +#define AMDGPU_HW_IP_VCN_JPEG 8 +#define AMDGPU_HW_IP_NUM 9 + +#define AMDGPU_HW_IP_INSTANCE_MAX_COUNT 1 + +#define AMDGPU_CHUNK_ID_IB 0x01 +#define AMDGPU_CHUNK_ID_FENCE 0x02 +#define AMDGPU_CHUNK_ID_DEPENDENCIES 0x03 +#define AMDGPU_CHUNK_ID_SYNCOBJ_IN 0x04 +#define AMDGPU_CHUNK_ID_SYNCOBJ_OUT 0x05 +#define AMDGPU_CHUNK_ID_BO_HANDLES 0x06 +#define AMDGPU_CHUNK_ID_SCHEDULED_DEPENDENCIES 0x07 +#define AMDGPU_CHUNK_ID_SYNCOBJ_TIMELINE_WAIT 0x08 +#define AMDGPU_CHUNK_ID_SYNCOBJ_TIMELINE_SIGNAL 0x09 + +struct drm_amdgpu_cs_chunk { + __u32 chunk_id; + __u32 length_dw; + __u64 chunk_data; +}; + +struct drm_amdgpu_cs_in { + /** Rendering context id */ + __u32 ctx_id; + /** Handle of resource list associated with CS */ + __u32 bo_list_handle; + __u32 num_chunks; + __u32 flags; + /** this points to __u64 * which point to cs chunks */ + __u64 chunks; +}; + +struct drm_amdgpu_cs_out { + __u64 handle; +}; + +union drm_amdgpu_cs { + struct drm_amdgpu_cs_in in; + struct drm_amdgpu_cs_out out; +}; + +/* Specify flags to be used for IB */ + +/* This IB should be submitted to CE */ +#define AMDGPU_IB_FLAG_CE (1<<0) + +/* Preamble flag, which means the IB could be dropped if no context switch */ +#define AMDGPU_IB_FLAG_PREAMBLE (1<<1) + +/* Preempt flag, IB should set Pre_enb bit if PREEMPT flag detected */ +#define AMDGPU_IB_FLAG_PREEMPT (1<<2) + +/* The IB fence should do the L2 writeback but not invalidate any shader + * caches (L2/vL1/sL1/I$). */ +#define AMDGPU_IB_FLAG_TC_WB_NOT_INVALIDATE (1 << 3) + +/* Set GDS_COMPUTE_MAX_WAVE_ID = DEFAULT before PACKET3_INDIRECT_BUFFER. + * This will reset wave ID counters for the IB. + */ +#define AMDGPU_IB_FLAG_RESET_GDS_MAX_WAVE_ID (1 << 4) + +/* Flag the IB as secure (TMZ) + */ +#define AMDGPU_IB_FLAGS_SECURE (1 << 5) + +/* Tell KMD to flush and invalidate caches + */ +#define AMDGPU_IB_FLAG_EMIT_MEM_SYNC (1 << 6) + +struct drm_amdgpu_cs_chunk_ib { + __u32 _pad; + /** AMDGPU_IB_FLAG_* */ + __u32 flags; + /** Virtual address to begin IB execution */ + __u64 va_start; + /** Size of submission */ + __u32 ib_bytes; + /** HW IP to submit to */ + __u32 ip_type; + /** HW IP index of the same type to submit to */ + __u32 ip_instance; + /** Ring index to submit to */ + __u32 ring; +}; + +struct drm_amdgpu_cs_chunk_dep { + __u32 ip_type; + __u32 ip_instance; + __u32 ring; + __u32 ctx_id; + __u64 handle; +}; + +struct drm_amdgpu_cs_chunk_fence { + __u32 handle; + __u32 offset; +}; + +struct drm_amdgpu_cs_chunk_sem { + __u32 handle; +}; + +struct drm_amdgpu_cs_chunk_syncobj { + __u32 handle; + __u32 flags; + __u64 point; +}; + +#define AMDGPU_FENCE_TO_HANDLE_GET_SYNCOBJ 0 +#define AMDGPU_FENCE_TO_HANDLE_GET_SYNCOBJ_FD 1 +#define AMDGPU_FENCE_TO_HANDLE_GET_SYNC_FILE_FD 2 + +union drm_amdgpu_fence_to_handle { + struct { + struct drm_amdgpu_fence fence; + __u32 what; + __u32 pad; + } in; + struct { + __u32 handle; + } out; +}; + +struct drm_amdgpu_cs_chunk_data { + union { + struct drm_amdgpu_cs_chunk_ib ib_data; + struct drm_amdgpu_cs_chunk_fence fence_data; + }; +}; + +/* + * Query h/w info: Flag that this is integrated (a.h.a. fusion) GPU + * + */ +#define AMDGPU_IDS_FLAGS_FUSION 0x1 +#define AMDGPU_IDS_FLAGS_PREEMPTION 0x2 +#define AMDGPU_IDS_FLAGS_TMZ 0x4 + +/* indicate if acceleration can be working */ +#define AMDGPU_INFO_ACCEL_WORKING 0x00 +/* get the crtc_id from the mode object id? */ +#define AMDGPU_INFO_CRTC_FROM_ID 0x01 +/* query hw IP info */ +#define AMDGPU_INFO_HW_IP_INFO 0x02 +/* query hw IP instance count for the specified type */ +#define AMDGPU_INFO_HW_IP_COUNT 0x03 +/* timestamp for GL_ARB_timer_query */ +#define AMDGPU_INFO_TIMESTAMP 0x05 +/* Query the firmware version */ +#define AMDGPU_INFO_FW_VERSION 0x0e + /* Subquery id: Query VCE firmware version */ + #define AMDGPU_INFO_FW_VCE 0x1 + /* Subquery id: Query UVD firmware version */ + #define AMDGPU_INFO_FW_UVD 0x2 + /* Subquery id: Query GMC firmware version */ + #define AMDGPU_INFO_FW_GMC 0x03 + /* Subquery id: Query GFX ME firmware version */ + #define AMDGPU_INFO_FW_GFX_ME 0x04 + /* Subquery id: Query GFX PFP firmware version */ + #define AMDGPU_INFO_FW_GFX_PFP 0x05 + /* Subquery id: Query GFX CE firmware version */ + #define AMDGPU_INFO_FW_GFX_CE 0x06 + /* Subquery id: Query GFX RLC firmware version */ + #define AMDGPU_INFO_FW_GFX_RLC 0x07 + /* Subquery id: Query GFX MEC firmware version */ + #define AMDGPU_INFO_FW_GFX_MEC 0x08 + /* Subquery id: Query SMC firmware version */ + #define AMDGPU_INFO_FW_SMC 0x0a + /* Subquery id: Query SDMA firmware version */ + #define AMDGPU_INFO_FW_SDMA 0x0b + /* Subquery id: Query PSP SOS firmware version */ + #define AMDGPU_INFO_FW_SOS 0x0c + /* Subquery id: Query PSP ASD firmware version */ + #define AMDGPU_INFO_FW_ASD 0x0d + /* Subquery id: Query VCN firmware version */ + #define AMDGPU_INFO_FW_VCN 0x0e + /* Subquery id: Query GFX RLC SRLC firmware version */ + #define AMDGPU_INFO_FW_GFX_RLC_RESTORE_LIST_CNTL 0x0f + /* Subquery id: Query GFX RLC SRLG firmware version */ + #define AMDGPU_INFO_FW_GFX_RLC_RESTORE_LIST_GPM_MEM 0x10 + /* Subquery id: Query GFX RLC SRLS firmware version */ + #define AMDGPU_INFO_FW_GFX_RLC_RESTORE_LIST_SRM_MEM 0x11 + /* Subquery id: Query DMCU firmware version */ + #define AMDGPU_INFO_FW_DMCU 0x12 + #define AMDGPU_INFO_FW_TA 0x13 + /* Subquery id: Query DMCUB firmware version */ + #define AMDGPU_INFO_FW_DMCUB 0x14 + /* Subquery id: Query TOC firmware version */ + #define AMDGPU_INFO_FW_TOC 0x15 + +/* number of bytes moved for TTM migration */ +#define AMDGPU_INFO_NUM_BYTES_MOVED 0x0f +/* the used VRAM size */ +#define AMDGPU_INFO_VRAM_USAGE 0x10 +/* the used GTT size */ +#define AMDGPU_INFO_GTT_USAGE 0x11 +/* Information about GDS, etc. resource configuration */ +#define AMDGPU_INFO_GDS_CONFIG 0x13 +/* Query information about VRAM and GTT domains */ +#define AMDGPU_INFO_VRAM_GTT 0x14 +/* Query information about register in MMR address space*/ +#define AMDGPU_INFO_READ_MMR_REG 0x15 +/* Query information about device: rev id, family, etc. */ +#define AMDGPU_INFO_DEV_INFO 0x16 +/* visible vram usage */ +#define AMDGPU_INFO_VIS_VRAM_USAGE 0x17 +/* number of TTM buffer evictions */ +#define AMDGPU_INFO_NUM_EVICTIONS 0x18 +/* Query memory about VRAM and GTT domains */ +#define AMDGPU_INFO_MEMORY 0x19 +/* Query vce clock table */ +#define AMDGPU_INFO_VCE_CLOCK_TABLE 0x1A +/* Query vbios related information */ +#define AMDGPU_INFO_VBIOS 0x1B + /* Subquery id: Query vbios size */ + #define AMDGPU_INFO_VBIOS_SIZE 0x1 + /* Subquery id: Query vbios image */ + #define AMDGPU_INFO_VBIOS_IMAGE 0x2 + /* Subquery id: Query vbios info */ + #define AMDGPU_INFO_VBIOS_INFO 0x3 +/* Query UVD handles */ +#define AMDGPU_INFO_NUM_HANDLES 0x1C +/* Query sensor related information */ +#define AMDGPU_INFO_SENSOR 0x1D + /* Subquery id: Query GPU shader clock */ + #define AMDGPU_INFO_SENSOR_GFX_SCLK 0x1 + /* Subquery id: Query GPU memory clock */ + #define AMDGPU_INFO_SENSOR_GFX_MCLK 0x2 + /* Subquery id: Query GPU temperature */ + #define AMDGPU_INFO_SENSOR_GPU_TEMP 0x3 + /* Subquery id: Query GPU load */ + #define AMDGPU_INFO_SENSOR_GPU_LOAD 0x4 + /* Subquery id: Query average GPU power */ + #define AMDGPU_INFO_SENSOR_GPU_AVG_POWER 0x5 + /* Subquery id: Query northbridge voltage */ + #define AMDGPU_INFO_SENSOR_VDDNB 0x6 + /* Subquery id: Query graphics voltage */ + #define AMDGPU_INFO_SENSOR_VDDGFX 0x7 + /* Subquery id: Query GPU stable pstate shader clock */ + #define AMDGPU_INFO_SENSOR_STABLE_PSTATE_GFX_SCLK 0x8 + /* Subquery id: Query GPU stable pstate memory clock */ + #define AMDGPU_INFO_SENSOR_STABLE_PSTATE_GFX_MCLK 0x9 +/* Number of VRAM page faults on CPU access. */ +#define AMDGPU_INFO_NUM_VRAM_CPU_PAGE_FAULTS 0x1E +#define AMDGPU_INFO_VRAM_LOST_COUNTER 0x1F +/* query ras mask of enabled features*/ +#define AMDGPU_INFO_RAS_ENABLED_FEATURES 0x20 +/* RAS MASK: UMC (VRAM) */ +#define AMDGPU_INFO_RAS_ENABLED_UMC (1 << 0) +/* RAS MASK: SDMA */ +#define AMDGPU_INFO_RAS_ENABLED_SDMA (1 << 1) +/* RAS MASK: GFX */ +#define AMDGPU_INFO_RAS_ENABLED_GFX (1 << 2) +/* RAS MASK: MMHUB */ +#define AMDGPU_INFO_RAS_ENABLED_MMHUB (1 << 3) +/* RAS MASK: ATHUB */ +#define AMDGPU_INFO_RAS_ENABLED_ATHUB (1 << 4) +/* RAS MASK: PCIE */ +#define AMDGPU_INFO_RAS_ENABLED_PCIE (1 << 5) +/* RAS MASK: HDP */ +#define AMDGPU_INFO_RAS_ENABLED_HDP (1 << 6) +/* RAS MASK: XGMI */ +#define AMDGPU_INFO_RAS_ENABLED_XGMI (1 << 7) +/* RAS MASK: DF */ +#define AMDGPU_INFO_RAS_ENABLED_DF (1 << 8) +/* RAS MASK: SMN */ +#define AMDGPU_INFO_RAS_ENABLED_SMN (1 << 9) +/* RAS MASK: SEM */ +#define AMDGPU_INFO_RAS_ENABLED_SEM (1 << 10) +/* RAS MASK: MP0 */ +#define AMDGPU_INFO_RAS_ENABLED_MP0 (1 << 11) +/* RAS MASK: MP1 */ +#define AMDGPU_INFO_RAS_ENABLED_MP1 (1 << 12) +/* RAS MASK: FUSE */ +#define AMDGPU_INFO_RAS_ENABLED_FUSE (1 << 13) +/* query video encode/decode caps */ +#define AMDGPU_INFO_VIDEO_CAPS 0x21 + /* Subquery id: Decode */ + #define AMDGPU_INFO_VIDEO_CAPS_DECODE 0 + /* Subquery id: Encode */ + #define AMDGPU_INFO_VIDEO_CAPS_ENCODE 1 + +#define AMDGPU_INFO_MMR_SE_INDEX_SHIFT 0 +#define AMDGPU_INFO_MMR_SE_INDEX_MASK 0xff +#define AMDGPU_INFO_MMR_SH_INDEX_SHIFT 8 +#define AMDGPU_INFO_MMR_SH_INDEX_MASK 0xff + +struct drm_amdgpu_query_fw { + /** AMDGPU_INFO_FW_* */ + __u32 fw_type; + /** + * Index of the IP if there are more IPs of + * the same type. + */ + __u32 ip_instance; + /** + * Index of the engine. Whether this is used depends + * on the firmware type. (e.g. MEC, SDMA) + */ + __u32 index; + __u32 _pad; +}; + +/* Input structure for the INFO ioctl */ +struct drm_amdgpu_info { + /* Where the return value will be stored */ + __u64 return_pointer; + /* The size of the return value. Just like "size" in "snprintf", + * it limits how many bytes the kernel can write. */ + __u32 return_size; + /* The query request id. */ + __u32 query; + + union { + struct { + __u32 id; + __u32 _pad; + } mode_crtc; + + struct { + /** AMDGPU_HW_IP_* */ + __u32 type; + /** + * Index of the IP if there are more IPs of the same + * type. Ignored by AMDGPU_INFO_HW_IP_COUNT. + */ + __u32 ip_instance; + } query_hw_ip; + + struct { + __u32 dword_offset; + /** number of registers to read */ + __u32 count; + __u32 instance; + /** For future use, no flags defined so far */ + __u32 flags; + } read_mmr_reg; + + struct drm_amdgpu_query_fw query_fw; + + struct { + __u32 type; + __u32 offset; + } vbios_info; + + struct { + __u32 type; + } sensor_info; + + struct { + __u32 type; + } video_cap; + }; +}; + +struct drm_amdgpu_info_gds { + /** GDS GFX partition size */ + __u32 gds_gfx_partition_size; + /** GDS compute partition size */ + __u32 compute_partition_size; + /** total GDS memory size */ + __u32 gds_total_size; + /** GWS size per GFX partition */ + __u32 gws_per_gfx_partition; + /** GSW size per compute partition */ + __u32 gws_per_compute_partition; + /** OA size per GFX partition */ + __u32 oa_per_gfx_partition; + /** OA size per compute partition */ + __u32 oa_per_compute_partition; + __u32 _pad; +}; + +struct drm_amdgpu_info_vram_gtt { + __u64 vram_size; + __u64 vram_cpu_accessible_size; + __u64 gtt_size; +}; + +struct drm_amdgpu_heap_info { + /** max. physical memory */ + __u64 total_heap_size; + + /** Theoretical max. available memory in the given heap */ + __u64 usable_heap_size; + + /** + * Number of bytes allocated in the heap. This includes all processes + * and private allocations in the kernel. It changes when new buffers + * are allocated, freed, and moved. It cannot be larger than + * heap_size. + */ + __u64 heap_usage; + + /** + * Theoretical possible max. size of buffer which + * could be allocated in the given heap + */ + __u64 max_allocation; +}; + +struct drm_amdgpu_memory_info { + struct drm_amdgpu_heap_info vram; + struct drm_amdgpu_heap_info cpu_accessible_vram; + struct drm_amdgpu_heap_info gtt; +}; + +struct drm_amdgpu_info_firmware { + __u32 ver; + __u32 feature; +}; + +struct drm_amdgpu_info_vbios { + __u8 name[64]; + __u8 vbios_pn[64]; + __u32 version; + __u32 pad; + __u8 vbios_ver_str[32]; + __u8 date[32]; +}; + +#define AMDGPU_VRAM_TYPE_UNKNOWN 0 +#define AMDGPU_VRAM_TYPE_GDDR1 1 +#define AMDGPU_VRAM_TYPE_DDR2 2 +#define AMDGPU_VRAM_TYPE_GDDR3 3 +#define AMDGPU_VRAM_TYPE_GDDR4 4 +#define AMDGPU_VRAM_TYPE_GDDR5 5 +#define AMDGPU_VRAM_TYPE_HBM 6 +#define AMDGPU_VRAM_TYPE_DDR3 7 +#define AMDGPU_VRAM_TYPE_DDR4 8 +#define AMDGPU_VRAM_TYPE_GDDR6 9 +#define AMDGPU_VRAM_TYPE_DDR5 10 + +struct drm_amdgpu_info_device { + /** PCI Device ID */ + __u32 device_id; + /** Internal chip revision: A0, A1, etc.) */ + __u32 chip_rev; + __u32 external_rev; + /** Revision id in PCI Config space */ + __u32 pci_rev; + __u32 family; + __u32 num_shader_engines; + __u32 num_shader_arrays_per_engine; + /* in KHz */ + __u32 gpu_counter_freq; + __u64 max_engine_clock; + __u64 max_memory_clock; + /* cu information */ + __u32 cu_active_number; + /* NOTE: cu_ao_mask is INVALID, DON'T use it */ + __u32 cu_ao_mask; + __u32 cu_bitmap[4][4]; + /** Render backend pipe mask. One render backend is CB+DB. */ + __u32 enabled_rb_pipes_mask; + __u32 num_rb_pipes; + __u32 num_hw_gfx_contexts; + __u32 _pad; + __u64 ids_flags; + /** Starting virtual address for UMDs. */ + __u64 virtual_address_offset; + /** The maximum virtual address */ + __u64 virtual_address_max; + /** Required alignment of virtual addresses. */ + __u32 virtual_address_alignment; + /** Page table entry - fragment size */ + __u32 pte_fragment_size; + __u32 gart_page_size; + /** constant engine ram size*/ + __u32 ce_ram_size; + /** video memory type info*/ + __u32 vram_type; + /** video memory bit width*/ + __u32 vram_bit_width; + /* vce harvesting instance */ + __u32 vce_harvest_config; + /* gfx double offchip LDS buffers */ + __u32 gc_double_offchip_lds_buf; + /* NGG Primitive Buffer */ + __u64 prim_buf_gpu_addr; + /* NGG Position Buffer */ + __u64 pos_buf_gpu_addr; + /* NGG Control Sideband */ + __u64 cntl_sb_buf_gpu_addr; + /* NGG Parameter Cache */ + __u64 param_buf_gpu_addr; + __u32 prim_buf_size; + __u32 pos_buf_size; + __u32 cntl_sb_buf_size; + __u32 param_buf_size; + /* wavefront size*/ + __u32 wave_front_size; + /* shader visible vgprs*/ + __u32 num_shader_visible_vgprs; + /* CU per shader array*/ + __u32 num_cu_per_sh; + /* number of tcc blocks*/ + __u32 num_tcc_blocks; + /* gs vgt table depth*/ + __u32 gs_vgt_table_depth; + /* gs primitive buffer depth*/ + __u32 gs_prim_buffer_depth; + /* max gs wavefront per vgt*/ + __u32 max_gs_waves_per_vgt; + __u32 _pad1; + /* always on cu bitmap */ + __u32 cu_ao_bitmap[4][4]; + /** Starting high virtual address for UMDs. */ + __u64 high_va_offset; + /** The maximum high virtual address */ + __u64 high_va_max; + /* gfx10 pa_sc_tile_steering_override */ + __u32 pa_sc_tile_steering_override; + /* disabled TCCs */ + __u64 tcc_disabled_mask; +}; + +struct drm_amdgpu_info_hw_ip { + /** Version of h/w IP */ + __u32 hw_ip_version_major; + __u32 hw_ip_version_minor; + /** Capabilities */ + __u64 capabilities_flags; + /** command buffer address start alignment*/ + __u32 ib_start_alignment; + /** command buffer size alignment*/ + __u32 ib_size_alignment; + /** Bitmask of available rings. Bit 0 means ring 0, etc. */ + __u32 available_rings; + __u32 _pad; +}; + +struct drm_amdgpu_info_num_handles { + /** Max handles as supported by firmware for UVD */ + __u32 uvd_max_handles; + /** Handles currently in use for UVD */ + __u32 uvd_used_handles; +}; + +#define AMDGPU_VCE_CLOCK_TABLE_ENTRIES 6 + +struct drm_amdgpu_info_vce_clock_table_entry { + /** System clock */ + __u32 sclk; + /** Memory clock */ + __u32 mclk; + /** VCE clock */ + __u32 eclk; + __u32 pad; +}; + +struct drm_amdgpu_info_vce_clock_table { + struct drm_amdgpu_info_vce_clock_table_entry entries[AMDGPU_VCE_CLOCK_TABLE_ENTRIES]; + __u32 num_valid_entries; + __u32 pad; +}; + +/* query video encode/decode caps */ +#define AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG2 0 +#define AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4 1 +#define AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VC1 2 +#define AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_MPEG4_AVC 3 +#define AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_HEVC 4 +#define AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_JPEG 5 +#define AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_VP9 6 +#define AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_AV1 7 +#define AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_COUNT 8 + +struct drm_amdgpu_info_video_codec_info { + __u32 valid; + __u32 max_width; + __u32 max_height; + __u32 max_pixels_per_frame; + __u32 max_level; + __u32 pad; +}; + +struct drm_amdgpu_info_video_caps { + struct drm_amdgpu_info_video_codec_info codec_info[AMDGPU_INFO_VIDEO_CAPS_CODEC_IDX_COUNT]; +}; + +/* + * Supported GPU families + */ +#define AMDGPU_FAMILY_UNKNOWN 0 +#define AMDGPU_FAMILY_SI 110 /* Hainan, Oland, Verde, Pitcairn, Tahiti */ +#define AMDGPU_FAMILY_CI 120 /* Bonaire, Hawaii */ +#define AMDGPU_FAMILY_KV 125 /* Kaveri, Kabini, Mullins */ +#define AMDGPU_FAMILY_VI 130 /* Iceland, Tonga */ +#define AMDGPU_FAMILY_CZ 135 /* Carrizo, Stoney */ +#define AMDGPU_FAMILY_AI 141 /* Vega10 */ +#define AMDGPU_FAMILY_RV 142 /* Raven */ +#define AMDGPU_FAMILY_NV 143 /* Navi10 */ +#define AMDGPU_FAMILY_VGH 144 /* Van Gogh */ +#define AMDGPU_FAMILY_YC 146 /* Yellow Carp */ + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/include/drm/drm.h b/include/drm/drm.h new file mode 100644 index 0000000..398c396 --- /dev/null +++ b/include/drm/drm.h @@ -0,0 +1,1183 @@ +/* + * Header for the Direct Rendering Manager + * + * Author: Rickard E. (Rik) Faith + * + * Acknowledgments: + * Dec 1999, Richard Henderson , move to generic cmpxchg. + */ + +/* + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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, 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS 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 _DRM_H_ +#define _DRM_H_ + +#if defined(__linux__) + +#include +#include +typedef unsigned int drm_handle_t; + +#else /* One of the BSDs */ + +#include +#include +#include +typedef int8_t __s8; +typedef uint8_t __u8; +typedef int16_t __s16; +typedef uint16_t __u16; +typedef int32_t __s32; +typedef uint32_t __u32; +typedef int64_t __s64; +typedef uint64_t __u64; +typedef size_t __kernel_size_t; +typedef unsigned long drm_handle_t; + +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +#define DRM_NAME "drm" /**< Name in kernel, /dev, and /proc */ +#define DRM_MIN_ORDER 5 /**< At least 2^5 bytes = 32 bytes */ +#define DRM_MAX_ORDER 22 /**< Up to 2^22 bytes = 4MB */ +#define DRM_RAM_PERCENT 10 /**< How much system ram can we lock? */ + +#define _DRM_LOCK_HELD 0x80000000U /**< Hardware lock is held */ +#define _DRM_LOCK_CONT 0x40000000U /**< Hardware lock is contended */ +#define _DRM_LOCK_IS_HELD(lock) ((lock) & _DRM_LOCK_HELD) +#define _DRM_LOCK_IS_CONT(lock) ((lock) & _DRM_LOCK_CONT) +#define _DRM_LOCKING_CONTEXT(lock) ((lock) & ~(_DRM_LOCK_HELD|_DRM_LOCK_CONT)) + +typedef unsigned int drm_context_t; +typedef unsigned int drm_drawable_t; +typedef unsigned int drm_magic_t; + +/* + * Cliprect. + * + * \warning: If you change this structure, make sure you change + * XF86DRIClipRectRec in the server as well + * + * \note KW: Actually it's illegal to change either for + * backwards-compatibility reasons. + */ +struct drm_clip_rect { + unsigned short x1; + unsigned short y1; + unsigned short x2; + unsigned short y2; +}; + +/* + * Drawable information. + */ +struct drm_drawable_info { + unsigned int num_rects; + struct drm_clip_rect *rects; +}; + +/* + * Texture region, + */ +struct drm_tex_region { + unsigned char next; + unsigned char prev; + unsigned char in_use; + unsigned char padding; + unsigned int age; +}; + +/* + * Hardware lock. + * + * The lock structure is a simple cache-line aligned integer. To avoid + * processor bus contention on a multiprocessor system, there should not be any + * other data stored in the same cache line. + */ +struct drm_hw_lock { + __volatile__ unsigned int lock; /**< lock variable */ + char padding[60]; /**< Pad to cache line */ +}; + +/* + * DRM_IOCTL_VERSION ioctl argument type. + * + * \sa drmGetVersion(). + */ +struct drm_version { + int version_major; /**< Major version */ + int version_minor; /**< Minor version */ + int version_patchlevel; /**< Patch level */ + __kernel_size_t name_len; /**< Length of name buffer */ + char *name; /**< Name of driver */ + __kernel_size_t date_len; /**< Length of date buffer */ + char *date; /**< User-space buffer to hold date */ + __kernel_size_t desc_len; /**< Length of desc buffer */ + char *desc; /**< User-space buffer to hold desc */ +}; + +/* + * DRM_IOCTL_GET_UNIQUE ioctl argument type. + * + * \sa drmGetBusid() and drmSetBusId(). + */ +struct drm_unique { + __kernel_size_t unique_len; /**< Length of unique */ + char *unique; /**< Unique name for driver instantiation */ +}; + +struct drm_list { + int count; /**< Length of user-space structures */ + struct drm_version *version; +}; + +struct drm_block { + int unused; +}; + +/* + * DRM_IOCTL_CONTROL ioctl argument type. + * + * \sa drmCtlInstHandler() and drmCtlUninstHandler(). + */ +struct drm_control { + enum { + DRM_ADD_COMMAND, + DRM_RM_COMMAND, + DRM_INST_HANDLER, + DRM_UNINST_HANDLER + } func; + int irq; +}; + +/* + * Type of memory to map. + */ +enum drm_map_type { + _DRM_FRAME_BUFFER = 0, /**< WC (no caching), no core dump */ + _DRM_REGISTERS = 1, /**< no caching, no core dump */ + _DRM_SHM = 2, /**< shared, cached */ + _DRM_AGP = 3, /**< AGP/GART */ + _DRM_SCATTER_GATHER = 4, /**< Scatter/gather memory for PCI DMA */ + _DRM_CONSISTENT = 5 /**< Consistent memory for PCI DMA */ +}; + +/* + * Memory mapping flags. + */ +enum drm_map_flags { + _DRM_RESTRICTED = 0x01, /**< Cannot be mapped to user-virtual */ + _DRM_READ_ONLY = 0x02, + _DRM_LOCKED = 0x04, /**< shared, cached, locked */ + _DRM_KERNEL = 0x08, /**< kernel requires access */ + _DRM_WRITE_COMBINING = 0x10, /**< use write-combining if available */ + _DRM_CONTAINS_LOCK = 0x20, /**< SHM page that contains lock */ + _DRM_REMOVABLE = 0x40, /**< Removable mapping */ + _DRM_DRIVER = 0x80 /**< Managed by driver */ +}; + +struct drm_ctx_priv_map { + unsigned int ctx_id; /**< Context requesting private mapping */ + void *handle; /**< Handle of map */ +}; + +/* + * DRM_IOCTL_GET_MAP, DRM_IOCTL_ADD_MAP and DRM_IOCTL_RM_MAP ioctls + * argument type. + * + * \sa drmAddMap(). + */ +struct drm_map { + unsigned long offset; /**< Requested physical address (0 for SAREA)*/ + unsigned long size; /**< Requested physical size (bytes) */ + enum drm_map_type type; /**< Type of memory to map */ + enum drm_map_flags flags; /**< Flags */ + void *handle; /**< User-space: "Handle" to pass to mmap() */ + /**< Kernel-space: kernel-virtual address */ + int mtrr; /**< MTRR slot used */ + /* Private data */ +}; + +/* + * DRM_IOCTL_GET_CLIENT ioctl argument type. + */ +struct drm_client { + int idx; /**< Which client desired? */ + int auth; /**< Is client authenticated? */ + unsigned long pid; /**< Process ID */ + unsigned long uid; /**< User ID */ + unsigned long magic; /**< Magic */ + unsigned long iocs; /**< Ioctl count */ +}; + +enum drm_stat_type { + _DRM_STAT_LOCK, + _DRM_STAT_OPENS, + _DRM_STAT_CLOSES, + _DRM_STAT_IOCTLS, + _DRM_STAT_LOCKS, + _DRM_STAT_UNLOCKS, + _DRM_STAT_VALUE, /**< Generic value */ + _DRM_STAT_BYTE, /**< Generic byte counter (1024bytes/K) */ + _DRM_STAT_COUNT, /**< Generic non-byte counter (1000/k) */ + + _DRM_STAT_IRQ, /**< IRQ */ + _DRM_STAT_PRIMARY, /**< Primary DMA bytes */ + _DRM_STAT_SECONDARY, /**< Secondary DMA bytes */ + _DRM_STAT_DMA, /**< DMA */ + _DRM_STAT_SPECIAL, /**< Special DMA (e.g., priority or polled) */ + _DRM_STAT_MISSED /**< Missed DMA opportunity */ + /* Add to the *END* of the list */ +}; + +/* + * DRM_IOCTL_GET_STATS ioctl argument type. + */ +struct drm_stats { + unsigned long count; + struct { + unsigned long value; + enum drm_stat_type type; + } data[15]; +}; + +/* + * Hardware locking flags. + */ +enum drm_lock_flags { + _DRM_LOCK_READY = 0x01, /**< Wait until hardware is ready for DMA */ + _DRM_LOCK_QUIESCENT = 0x02, /**< Wait until hardware quiescent */ + _DRM_LOCK_FLUSH = 0x04, /**< Flush this context's DMA queue first */ + _DRM_LOCK_FLUSH_ALL = 0x08, /**< Flush all DMA queues first */ + /* These *HALT* flags aren't supported yet + -- they will be used to support the + full-screen DGA-like mode. */ + _DRM_HALT_ALL_QUEUES = 0x10, /**< Halt all current and future queues */ + _DRM_HALT_CUR_QUEUES = 0x20 /**< Halt all current queues */ +}; + +/* + * DRM_IOCTL_LOCK, DRM_IOCTL_UNLOCK and DRM_IOCTL_FINISH ioctl argument type. + * + * \sa drmGetLock() and drmUnlock(). + */ +struct drm_lock { + int context; + enum drm_lock_flags flags; +}; + +/* + * DMA flags + * + * \warning + * These values \e must match xf86drm.h. + * + * \sa drm_dma. + */ +enum drm_dma_flags { + /* Flags for DMA buffer dispatch */ + _DRM_DMA_BLOCK = 0x01, /**< + * Block until buffer dispatched. + * + * \note The buffer may not yet have + * been processed by the hardware -- + * getting a hardware lock with the + * hardware quiescent will ensure + * that the buffer has been + * processed. + */ + _DRM_DMA_WHILE_LOCKED = 0x02, /**< Dispatch while lock held */ + _DRM_DMA_PRIORITY = 0x04, /**< High priority dispatch */ + + /* Flags for DMA buffer request */ + _DRM_DMA_WAIT = 0x10, /**< Wait for free buffers */ + _DRM_DMA_SMALLER_OK = 0x20, /**< Smaller-than-requested buffers OK */ + _DRM_DMA_LARGER_OK = 0x40 /**< Larger-than-requested buffers OK */ +}; + +/* + * DRM_IOCTL_ADD_BUFS and DRM_IOCTL_MARK_BUFS ioctl argument type. + * + * \sa drmAddBufs(). + */ +struct drm_buf_desc { + int count; /**< Number of buffers of this size */ + int size; /**< Size in bytes */ + int low_mark; /**< Low water mark */ + int high_mark; /**< High water mark */ + enum { + _DRM_PAGE_ALIGN = 0x01, /**< Align on page boundaries for DMA */ + _DRM_AGP_BUFFER = 0x02, /**< Buffer is in AGP space */ + _DRM_SG_BUFFER = 0x04, /**< Scatter/gather memory buffer */ + _DRM_FB_BUFFER = 0x08, /**< Buffer is in frame buffer */ + _DRM_PCI_BUFFER_RO = 0x10 /**< Map PCI DMA buffer read-only */ + } flags; + unsigned long agp_start; /**< + * Start address of where the AGP buffers are + * in the AGP aperture + */ +}; + +/* + * DRM_IOCTL_INFO_BUFS ioctl argument type. + */ +struct drm_buf_info { + int count; /**< Entries in list */ + struct drm_buf_desc *list; +}; + +/* + * DRM_IOCTL_FREE_BUFS ioctl argument type. + */ +struct drm_buf_free { + int count; + int *list; +}; + +/* + * Buffer information + * + * \sa drm_buf_map. + */ +struct drm_buf_pub { + int idx; /**< Index into the master buffer list */ + int total; /**< Buffer size */ + int used; /**< Amount of buffer in use (for DMA) */ + void *address; /**< Address of buffer */ +}; + +/* + * DRM_IOCTL_MAP_BUFS ioctl argument type. + */ +struct drm_buf_map { + int count; /**< Length of the buffer list */ +#ifdef __cplusplus + void *virt; +#else + void *virtual; /**< Mmap'd area in user-virtual */ +#endif + struct drm_buf_pub *list; /**< Buffer information */ +}; + +/* + * DRM_IOCTL_DMA ioctl argument type. + * + * Indices here refer to the offset into the buffer list in drm_buf_get. + * + * \sa drmDMA(). + */ +struct drm_dma { + int context; /**< Context handle */ + int send_count; /**< Number of buffers to send */ + int *send_indices; /**< List of handles to buffers */ + int *send_sizes; /**< Lengths of data to send */ + enum drm_dma_flags flags; /**< Flags */ + int request_count; /**< Number of buffers requested */ + int request_size; /**< Desired size for buffers */ + int *request_indices; /**< Buffer information */ + int *request_sizes; + int granted_count; /**< Number of buffers granted */ +}; + +enum drm_ctx_flags { + _DRM_CONTEXT_PRESERVED = 0x01, + _DRM_CONTEXT_2DONLY = 0x02 +}; + +/* + * DRM_IOCTL_ADD_CTX ioctl argument type. + * + * \sa drmCreateContext() and drmDestroyContext(). + */ +struct drm_ctx { + drm_context_t handle; + enum drm_ctx_flags flags; +}; + +/* + * DRM_IOCTL_RES_CTX ioctl argument type. + */ +struct drm_ctx_res { + int count; + struct drm_ctx *contexts; +}; + +/* + * DRM_IOCTL_ADD_DRAW and DRM_IOCTL_RM_DRAW ioctl argument type. + */ +struct drm_draw { + drm_drawable_t handle; +}; + +/* + * DRM_IOCTL_UPDATE_DRAW ioctl argument type. + */ +typedef enum { + DRM_DRAWABLE_CLIPRECTS +} drm_drawable_info_type_t; + +struct drm_update_draw { + drm_drawable_t handle; + unsigned int type; + unsigned int num; + unsigned long long data; +}; + +/* + * DRM_IOCTL_GET_MAGIC and DRM_IOCTL_AUTH_MAGIC ioctl argument type. + */ +struct drm_auth { + drm_magic_t magic; +}; + +/* + * DRM_IOCTL_IRQ_BUSID ioctl argument type. + * + * \sa drmGetInterruptFromBusID(). + */ +struct drm_irq_busid { + int irq; /**< IRQ number */ + int busnum; /**< bus number */ + int devnum; /**< device number */ + int funcnum; /**< function number */ +}; + +enum drm_vblank_seq_type { + _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ + _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + /* bits 1-6 are reserved for high crtcs */ + _DRM_VBLANK_HIGH_CRTC_MASK = 0x0000003e, + _DRM_VBLANK_EVENT = 0x4000000, /**< Send event instead of blocking */ + _DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ + _DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ + _DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ + _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking, unsupported */ +}; +#define _DRM_VBLANK_HIGH_CRTC_SHIFT 1 + +#define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE) +#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_EVENT | _DRM_VBLANK_SIGNAL | \ + _DRM_VBLANK_SECONDARY | _DRM_VBLANK_NEXTONMISS) + +struct drm_wait_vblank_request { + enum drm_vblank_seq_type type; + unsigned int sequence; + unsigned long signal; +}; + +struct drm_wait_vblank_reply { + enum drm_vblank_seq_type type; + unsigned int sequence; + long tval_sec; + long tval_usec; +}; + +/* + * DRM_IOCTL_WAIT_VBLANK ioctl argument type. + * + * \sa drmWaitVBlank(). + */ +union drm_wait_vblank { + struct drm_wait_vblank_request request; + struct drm_wait_vblank_reply reply; +}; + +#define _DRM_PRE_MODESET 1 +#define _DRM_POST_MODESET 2 + +/* + * DRM_IOCTL_MODESET_CTL ioctl argument type + * + * \sa drmModesetCtl(). + */ +struct drm_modeset_ctl { + __u32 crtc; + __u32 cmd; +}; + +/* + * DRM_IOCTL_AGP_ENABLE ioctl argument type. + * + * \sa drmAgpEnable(). + */ +struct drm_agp_mode { + unsigned long mode; /**< AGP mode */ +}; + +/* + * DRM_IOCTL_AGP_ALLOC and DRM_IOCTL_AGP_FREE ioctls argument type. + * + * \sa drmAgpAlloc() and drmAgpFree(). + */ +struct drm_agp_buffer { + unsigned long size; /**< In bytes -- will round to page boundary */ + unsigned long handle; /**< Used for binding / unbinding */ + unsigned long type; /**< Type of memory to allocate */ + unsigned long physical; /**< Physical used by i810 */ +}; + +/* + * DRM_IOCTL_AGP_BIND and DRM_IOCTL_AGP_UNBIND ioctls argument type. + * + * \sa drmAgpBind() and drmAgpUnbind(). + */ +struct drm_agp_binding { + unsigned long handle; /**< From drm_agp_buffer */ + unsigned long offset; /**< In bytes -- will round to page boundary */ +}; + +/* + * DRM_IOCTL_AGP_INFO ioctl argument type. + * + * \sa drmAgpVersionMajor(), drmAgpVersionMinor(), drmAgpGetMode(), + * drmAgpBase(), drmAgpSize(), drmAgpMemoryUsed(), drmAgpMemoryAvail(), + * drmAgpVendorId() and drmAgpDeviceId(). + */ +struct drm_agp_info { + int agp_version_major; + int agp_version_minor; + unsigned long mode; + unsigned long aperture_base; /* physical address */ + unsigned long aperture_size; /* bytes */ + unsigned long memory_allowed; /* bytes */ + unsigned long memory_used; + + /* PCI information */ + unsigned short id_vendor; + unsigned short id_device; +}; + +/* + * DRM_IOCTL_SG_ALLOC ioctl argument type. + */ +struct drm_scatter_gather { + unsigned long size; /**< In bytes -- will round to page boundary */ + unsigned long handle; /**< Used for mapping / unmapping */ +}; + +/* + * DRM_IOCTL_SET_VERSION ioctl argument type. + */ +struct drm_set_version { + int drm_di_major; + int drm_di_minor; + int drm_dd_major; + int drm_dd_minor; +}; + +/* DRM_IOCTL_GEM_CLOSE ioctl argument type */ +struct drm_gem_close { + /** Handle of the object to be closed. */ + __u32 handle; + __u32 pad; +}; + +/* DRM_IOCTL_GEM_FLINK ioctl argument type */ +struct drm_gem_flink { + /** Handle for the object being named */ + __u32 handle; + + /** Returned global name */ + __u32 name; +}; + +/* DRM_IOCTL_GEM_OPEN ioctl argument type */ +struct drm_gem_open { + /** Name of object being opened */ + __u32 name; + + /** Returned handle for the object */ + __u32 handle; + + /** Returned size of the object */ + __u64 size; +}; + +/** + * DRM_CAP_DUMB_BUFFER + * + * If set to 1, the driver supports creating dumb buffers via the + * &DRM_IOCTL_MODE_CREATE_DUMB ioctl. + */ +#define DRM_CAP_DUMB_BUFFER 0x1 +/** + * DRM_CAP_VBLANK_HIGH_CRTC + * + * If set to 1, the kernel supports specifying a CRTC index in the high bits of + * &drm_wait_vblank_request.type. + * + * Starting kernel version 2.6.39, this capability is always set to 1. + */ +#define DRM_CAP_VBLANK_HIGH_CRTC 0x2 +/** + * DRM_CAP_DUMB_PREFERRED_DEPTH + * + * The preferred bit depth for dumb buffers. + * + * The bit depth is the number of bits used to indicate the color of a single + * pixel excluding any padding. This is different from the number of bits per + * pixel. For instance, XRGB8888 has a bit depth of 24 but has 32 bits per + * pixel. + * + * Note that this preference only applies to dumb buffers, it's irrelevant for + * other types of buffers. + */ +#define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3 +/** + * DRM_CAP_DUMB_PREFER_SHADOW + * + * If set to 1, the driver prefers userspace to render to a shadow buffer + * instead of directly rendering to a dumb buffer. For best speed, userspace + * should do streaming ordered memory copies into the dumb buffer and never + * read from it. + * + * Note that this preference only applies to dumb buffers, it's irrelevant for + * other types of buffers. + */ +#define DRM_CAP_DUMB_PREFER_SHADOW 0x4 +/** + * DRM_CAP_PRIME + * + * Bitfield of supported PRIME sharing capabilities. See &DRM_PRIME_CAP_IMPORT + * and &DRM_PRIME_CAP_EXPORT. + * + * PRIME buffers are exposed as dma-buf file descriptors. See + * Documentation/gpu/drm-mm.rst, section "PRIME Buffer Sharing". + */ +#define DRM_CAP_PRIME 0x5 +/** + * DRM_PRIME_CAP_IMPORT + * + * If this bit is set in &DRM_CAP_PRIME, the driver supports importing PRIME + * buffers via the &DRM_IOCTL_PRIME_FD_TO_HANDLE ioctl. + */ +#define DRM_PRIME_CAP_IMPORT 0x1 +/** + * DRM_PRIME_CAP_EXPORT + * + * If this bit is set in &DRM_CAP_PRIME, the driver supports exporting PRIME + * buffers via the &DRM_IOCTL_PRIME_HANDLE_TO_FD ioctl. + */ +#define DRM_PRIME_CAP_EXPORT 0x2 +/** + * DRM_CAP_TIMESTAMP_MONOTONIC + * + * If set to 0, the kernel will report timestamps with ``CLOCK_REALTIME`` in + * struct drm_event_vblank. If set to 1, the kernel will report timestamps with + * ``CLOCK_MONOTONIC``. See ``clock_gettime(2)`` for the definition of these + * clocks. + * + * Starting from kernel version 2.6.39, the default value for this capability + * is 1. Starting kernel version 4.15, this capability is always set to 1. + */ +#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6 +/** + * DRM_CAP_ASYNC_PAGE_FLIP + * + * If set to 1, the driver supports &DRM_MODE_PAGE_FLIP_ASYNC. + */ +#define DRM_CAP_ASYNC_PAGE_FLIP 0x7 +/** + * DRM_CAP_CURSOR_WIDTH + * + * The ``CURSOR_WIDTH`` and ``CURSOR_HEIGHT`` capabilities return a valid + * width x height combination for the hardware cursor. The intention is that a + * hardware agnostic userspace can query a cursor plane size to use. + * + * Note that the cross-driver contract is to merely return a valid size; + * drivers are free to attach another meaning on top, eg. i915 returns the + * maximum plane size. + */ +#define DRM_CAP_CURSOR_WIDTH 0x8 +/** + * DRM_CAP_CURSOR_HEIGHT + * + * See &DRM_CAP_CURSOR_WIDTH. + */ +#define DRM_CAP_CURSOR_HEIGHT 0x9 +/** + * DRM_CAP_ADDFB2_MODIFIERS + * + * If set to 1, the driver supports supplying modifiers in the + * &DRM_IOCTL_MODE_ADDFB2 ioctl. + */ +#define DRM_CAP_ADDFB2_MODIFIERS 0x10 +/** + * DRM_CAP_PAGE_FLIP_TARGET + * + * If set to 1, the driver supports the &DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE and + * &DRM_MODE_PAGE_FLIP_TARGET_RELATIVE flags in + * &drm_mode_crtc_page_flip_target.flags for the &DRM_IOCTL_MODE_PAGE_FLIP + * ioctl. + */ +#define DRM_CAP_PAGE_FLIP_TARGET 0x11 +/** + * DRM_CAP_CRTC_IN_VBLANK_EVENT + * + * If set to 1, the kernel supports reporting the CRTC ID in + * &drm_event_vblank.crtc_id for the &DRM_EVENT_VBLANK and + * &DRM_EVENT_FLIP_COMPLETE events. + * + * Starting kernel version 4.12, this capability is always set to 1. + */ +#define DRM_CAP_CRTC_IN_VBLANK_EVENT 0x12 +/** + * DRM_CAP_SYNCOBJ + * + * If set to 1, the driver supports sync objects. See + * Documentation/gpu/drm-mm.rst, section "DRM Sync Objects". + */ +#define DRM_CAP_SYNCOBJ 0x13 +/** + * DRM_CAP_SYNCOBJ_TIMELINE + * + * If set to 1, the driver supports timeline operations on sync objects. See + * Documentation/gpu/drm-mm.rst, section "DRM Sync Objects". + */ +#define DRM_CAP_SYNCOBJ_TIMELINE 0x14 + +/* DRM_IOCTL_GET_CAP ioctl argument type */ +struct drm_get_cap { + __u64 capability; + __u64 value; +}; + +/** + * DRM_CLIENT_CAP_STEREO_3D + * + * If set to 1, the DRM core will expose the stereo 3D capabilities of the + * monitor by advertising the supported 3D layouts in the flags of struct + * drm_mode_modeinfo. See ``DRM_MODE_FLAG_3D_*``. + * + * This capability is always supported for all drivers starting from kernel + * version 3.13. + */ +#define DRM_CLIENT_CAP_STEREO_3D 1 + +/** + * DRM_CLIENT_CAP_UNIVERSAL_PLANES + * + * If set to 1, the DRM core will expose all planes (overlay, primary, and + * cursor) to userspace. + * + * This capability has been introduced in kernel version 3.15. Starting from + * kernel version 3.17, this capability is always supported for all drivers. + */ +#define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2 + +/** + * DRM_CLIENT_CAP_ATOMIC + * + * If set to 1, the DRM core will expose atomic properties to userspace. This + * implicitly enables &DRM_CLIENT_CAP_UNIVERSAL_PLANES and + * &DRM_CLIENT_CAP_ASPECT_RATIO. + * + * If the driver doesn't support atomic mode-setting, enabling this capability + * will fail with -EOPNOTSUPP. + * + * This capability has been introduced in kernel version 4.0. Starting from + * kernel version 4.2, this capability is always supported for atomic-capable + * drivers. + */ +#define DRM_CLIENT_CAP_ATOMIC 3 + +/** + * DRM_CLIENT_CAP_ASPECT_RATIO + * + * If set to 1, the DRM core will provide aspect ratio information in modes. + * See ``DRM_MODE_FLAG_PIC_AR_*``. + * + * This capability is always supported for all drivers starting from kernel + * version 4.18. + */ +#define DRM_CLIENT_CAP_ASPECT_RATIO 4 + +/** + * DRM_CLIENT_CAP_WRITEBACK_CONNECTORS + * + * If set to 1, the DRM core will expose special connectors to be used for + * writing back to memory the scene setup in the commit. The client must enable + * &DRM_CLIENT_CAP_ATOMIC first. + * + * This capability is always supported for atomic-capable drivers starting from + * kernel version 4.19. + */ +#define DRM_CLIENT_CAP_WRITEBACK_CONNECTORS 5 + +/* DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */ +struct drm_set_client_cap { + __u64 capability; + __u64 value; +}; + +#define DRM_RDWR O_RDWR +#define DRM_CLOEXEC O_CLOEXEC +struct drm_prime_handle { + __u32 handle; + + /** Flags.. only applicable for handle->fd */ + __u32 flags; + + /** Returned dmabuf file descriptor */ + __s32 fd; +}; + +struct drm_syncobj_create { + __u32 handle; +#define DRM_SYNCOBJ_CREATE_SIGNALED (1 << 0) + __u32 flags; +}; + +struct drm_syncobj_destroy { + __u32 handle; + __u32 pad; +}; + +#define DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE (1 << 0) +#define DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE (1 << 0) +struct drm_syncobj_handle { + __u32 handle; + __u32 flags; + + __s32 fd; + __u32 pad; +}; + +struct drm_syncobj_transfer { + __u32 src_handle; + __u32 dst_handle; + __u64 src_point; + __u64 dst_point; + __u32 flags; + __u32 pad; +}; + +#define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL (1 << 0) +#define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT (1 << 1) +#define DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE (1 << 2) /* wait for time point to become available */ +struct drm_syncobj_wait { + __u64 handles; + /* absolute timeout */ + __s64 timeout_nsec; + __u32 count_handles; + __u32 flags; + __u32 first_signaled; /* only valid when not waiting all */ + __u32 pad; +}; + +struct drm_syncobj_timeline_wait { + __u64 handles; + /* wait on specific timeline point for every handles*/ + __u64 points; + /* absolute timeout */ + __s64 timeout_nsec; + __u32 count_handles; + __u32 flags; + __u32 first_signaled; /* only valid when not waiting all */ + __u32 pad; +}; + + +struct drm_syncobj_array { + __u64 handles; + __u32 count_handles; + __u32 pad; +}; + +#define DRM_SYNCOBJ_QUERY_FLAGS_LAST_SUBMITTED (1 << 0) /* last available point on timeline syncobj */ +struct drm_syncobj_timeline_array { + __u64 handles; + __u64 points; + __u32 count_handles; + __u32 flags; +}; + + +/* Query current scanout sequence number */ +struct drm_crtc_get_sequence { + __u32 crtc_id; /* requested crtc_id */ + __u32 active; /* return: crtc output is active */ + __u64 sequence; /* return: most recent vblank sequence */ + __s64 sequence_ns; /* return: most recent time of first pixel out */ +}; + +/* Queue event to be delivered at specified sequence. Time stamp marks + * when the first pixel of the refresh cycle leaves the display engine + * for the display + */ +#define DRM_CRTC_SEQUENCE_RELATIVE 0x00000001 /* sequence is relative to current */ +#define DRM_CRTC_SEQUENCE_NEXT_ON_MISS 0x00000002 /* Use next sequence if we've missed */ + +struct drm_crtc_queue_sequence { + __u32 crtc_id; + __u32 flags; + __u64 sequence; /* on input, target sequence. on output, actual sequence */ + __u64 user_data; /* user data passed to event */ +}; + +#if defined(__cplusplus) +} +#endif + +#include "drm_mode.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +#define DRM_IOCTL_BASE 'd' +#define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) +#define DRM_IOR(nr,type) _IOR(DRM_IOCTL_BASE,nr,type) +#define DRM_IOW(nr,type) _IOW(DRM_IOCTL_BASE,nr,type) +#define DRM_IOWR(nr,type) _IOWR(DRM_IOCTL_BASE,nr,type) + +#define DRM_IOCTL_VERSION DRM_IOWR(0x00, struct drm_version) +#define DRM_IOCTL_GET_UNIQUE DRM_IOWR(0x01, struct drm_unique) +#define DRM_IOCTL_GET_MAGIC DRM_IOR( 0x02, struct drm_auth) +#define DRM_IOCTL_IRQ_BUSID DRM_IOWR(0x03, struct drm_irq_busid) +#define DRM_IOCTL_GET_MAP DRM_IOWR(0x04, struct drm_map) +#define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, struct drm_client) +#define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, struct drm_stats) +#define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, struct drm_set_version) +#define DRM_IOCTL_MODESET_CTL DRM_IOW(0x08, struct drm_modeset_ctl) +#define DRM_IOCTL_GEM_CLOSE DRM_IOW (0x09, struct drm_gem_close) +#define DRM_IOCTL_GEM_FLINK DRM_IOWR(0x0a, struct drm_gem_flink) +#define DRM_IOCTL_GEM_OPEN DRM_IOWR(0x0b, struct drm_gem_open) +#define DRM_IOCTL_GET_CAP DRM_IOWR(0x0c, struct drm_get_cap) +#define DRM_IOCTL_SET_CLIENT_CAP DRM_IOW( 0x0d, struct drm_set_client_cap) + +#define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, struct drm_unique) +#define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, struct drm_auth) +#define DRM_IOCTL_BLOCK DRM_IOWR(0x12, struct drm_block) +#define DRM_IOCTL_UNBLOCK DRM_IOWR(0x13, struct drm_block) +#define DRM_IOCTL_CONTROL DRM_IOW( 0x14, struct drm_control) +#define DRM_IOCTL_ADD_MAP DRM_IOWR(0x15, struct drm_map) +#define DRM_IOCTL_ADD_BUFS DRM_IOWR(0x16, struct drm_buf_desc) +#define DRM_IOCTL_MARK_BUFS DRM_IOW( 0x17, struct drm_buf_desc) +#define DRM_IOCTL_INFO_BUFS DRM_IOWR(0x18, struct drm_buf_info) +#define DRM_IOCTL_MAP_BUFS DRM_IOWR(0x19, struct drm_buf_map) +#define DRM_IOCTL_FREE_BUFS DRM_IOW( 0x1a, struct drm_buf_free) + +#define DRM_IOCTL_RM_MAP DRM_IOW( 0x1b, struct drm_map) + +#define DRM_IOCTL_SET_SAREA_CTX DRM_IOW( 0x1c, struct drm_ctx_priv_map) +#define DRM_IOCTL_GET_SAREA_CTX DRM_IOWR(0x1d, struct drm_ctx_priv_map) + +#define DRM_IOCTL_SET_MASTER DRM_IO(0x1e) +#define DRM_IOCTL_DROP_MASTER DRM_IO(0x1f) + +#define DRM_IOCTL_ADD_CTX DRM_IOWR(0x20, struct drm_ctx) +#define DRM_IOCTL_RM_CTX DRM_IOWR(0x21, struct drm_ctx) +#define DRM_IOCTL_MOD_CTX DRM_IOW( 0x22, struct drm_ctx) +#define DRM_IOCTL_GET_CTX DRM_IOWR(0x23, struct drm_ctx) +#define DRM_IOCTL_SWITCH_CTX DRM_IOW( 0x24, struct drm_ctx) +#define DRM_IOCTL_NEW_CTX DRM_IOW( 0x25, struct drm_ctx) +#define DRM_IOCTL_RES_CTX DRM_IOWR(0x26, struct drm_ctx_res) +#define DRM_IOCTL_ADD_DRAW DRM_IOWR(0x27, struct drm_draw) +#define DRM_IOCTL_RM_DRAW DRM_IOWR(0x28, struct drm_draw) +#define DRM_IOCTL_DMA DRM_IOWR(0x29, struct drm_dma) +#define DRM_IOCTL_LOCK DRM_IOW( 0x2a, struct drm_lock) +#define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, struct drm_lock) +#define DRM_IOCTL_FINISH DRM_IOW( 0x2c, struct drm_lock) + +#define DRM_IOCTL_PRIME_HANDLE_TO_FD DRM_IOWR(0x2d, struct drm_prime_handle) +#define DRM_IOCTL_PRIME_FD_TO_HANDLE DRM_IOWR(0x2e, struct drm_prime_handle) + +#define DRM_IOCTL_AGP_ACQUIRE DRM_IO( 0x30) +#define DRM_IOCTL_AGP_RELEASE DRM_IO( 0x31) +#define DRM_IOCTL_AGP_ENABLE DRM_IOW( 0x32, struct drm_agp_mode) +#define DRM_IOCTL_AGP_INFO DRM_IOR( 0x33, struct drm_agp_info) +#define DRM_IOCTL_AGP_ALLOC DRM_IOWR(0x34, struct drm_agp_buffer) +#define DRM_IOCTL_AGP_FREE DRM_IOW( 0x35, struct drm_agp_buffer) +#define DRM_IOCTL_AGP_BIND DRM_IOW( 0x36, struct drm_agp_binding) +#define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, struct drm_agp_binding) + +#define DRM_IOCTL_SG_ALLOC DRM_IOWR(0x38, struct drm_scatter_gather) +#define DRM_IOCTL_SG_FREE DRM_IOW( 0x39, struct drm_scatter_gather) + +#define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, union drm_wait_vblank) + +#define DRM_IOCTL_CRTC_GET_SEQUENCE DRM_IOWR(0x3b, struct drm_crtc_get_sequence) +#define DRM_IOCTL_CRTC_QUEUE_SEQUENCE DRM_IOWR(0x3c, struct drm_crtc_queue_sequence) + +#define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, struct drm_update_draw) + +#define DRM_IOCTL_MODE_GETRESOURCES DRM_IOWR(0xA0, struct drm_mode_card_res) +#define DRM_IOCTL_MODE_GETCRTC DRM_IOWR(0xA1, struct drm_mode_crtc) +#define DRM_IOCTL_MODE_SETCRTC DRM_IOWR(0xA2, struct drm_mode_crtc) +#define DRM_IOCTL_MODE_CURSOR DRM_IOWR(0xA3, struct drm_mode_cursor) +#define DRM_IOCTL_MODE_GETGAMMA DRM_IOWR(0xA4, struct drm_mode_crtc_lut) +#define DRM_IOCTL_MODE_SETGAMMA DRM_IOWR(0xA5, struct drm_mode_crtc_lut) +#define DRM_IOCTL_MODE_GETENCODER DRM_IOWR(0xA6, struct drm_mode_get_encoder) +#define DRM_IOCTL_MODE_GETCONNECTOR DRM_IOWR(0xA7, struct drm_mode_get_connector) +#define DRM_IOCTL_MODE_ATTACHMODE DRM_IOWR(0xA8, struct drm_mode_mode_cmd) /* deprecated (never worked) */ +#define DRM_IOCTL_MODE_DETACHMODE DRM_IOWR(0xA9, struct drm_mode_mode_cmd) /* deprecated (never worked) */ + +#define DRM_IOCTL_MODE_GETPROPERTY DRM_IOWR(0xAA, struct drm_mode_get_property) +#define DRM_IOCTL_MODE_SETPROPERTY DRM_IOWR(0xAB, struct drm_mode_connector_set_property) +#define DRM_IOCTL_MODE_GETPROPBLOB DRM_IOWR(0xAC, struct drm_mode_get_blob) +#define DRM_IOCTL_MODE_GETFB DRM_IOWR(0xAD, struct drm_mode_fb_cmd) +#define DRM_IOCTL_MODE_ADDFB DRM_IOWR(0xAE, struct drm_mode_fb_cmd) +#define DRM_IOCTL_MODE_RMFB DRM_IOWR(0xAF, unsigned int) +#define DRM_IOCTL_MODE_PAGE_FLIP DRM_IOWR(0xB0, struct drm_mode_crtc_page_flip) +#define DRM_IOCTL_MODE_DIRTYFB DRM_IOWR(0xB1, struct drm_mode_fb_dirty_cmd) + +#define DRM_IOCTL_MODE_CREATE_DUMB DRM_IOWR(0xB2, struct drm_mode_create_dumb) +#define DRM_IOCTL_MODE_MAP_DUMB DRM_IOWR(0xB3, struct drm_mode_map_dumb) +#define DRM_IOCTL_MODE_DESTROY_DUMB DRM_IOWR(0xB4, struct drm_mode_destroy_dumb) +#define DRM_IOCTL_MODE_GETPLANERESOURCES DRM_IOWR(0xB5, struct drm_mode_get_plane_res) +#define DRM_IOCTL_MODE_GETPLANE DRM_IOWR(0xB6, struct drm_mode_get_plane) +#define DRM_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct drm_mode_set_plane) +#define DRM_IOCTL_MODE_ADDFB2 DRM_IOWR(0xB8, struct drm_mode_fb_cmd2) +#define DRM_IOCTL_MODE_OBJ_GETPROPERTIES DRM_IOWR(0xB9, struct drm_mode_obj_get_properties) +#define DRM_IOCTL_MODE_OBJ_SETPROPERTY DRM_IOWR(0xBA, struct drm_mode_obj_set_property) +#define DRM_IOCTL_MODE_CURSOR2 DRM_IOWR(0xBB, struct drm_mode_cursor2) +#define DRM_IOCTL_MODE_ATOMIC DRM_IOWR(0xBC, struct drm_mode_atomic) +#define DRM_IOCTL_MODE_CREATEPROPBLOB DRM_IOWR(0xBD, struct drm_mode_create_blob) +#define DRM_IOCTL_MODE_DESTROYPROPBLOB DRM_IOWR(0xBE, struct drm_mode_destroy_blob) + +#define DRM_IOCTL_SYNCOBJ_CREATE DRM_IOWR(0xBF, struct drm_syncobj_create) +#define DRM_IOCTL_SYNCOBJ_DESTROY DRM_IOWR(0xC0, struct drm_syncobj_destroy) +#define DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD DRM_IOWR(0xC1, struct drm_syncobj_handle) +#define DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE DRM_IOWR(0xC2, struct drm_syncobj_handle) +#define DRM_IOCTL_SYNCOBJ_WAIT DRM_IOWR(0xC3, struct drm_syncobj_wait) +#define DRM_IOCTL_SYNCOBJ_RESET DRM_IOWR(0xC4, struct drm_syncobj_array) +#define DRM_IOCTL_SYNCOBJ_SIGNAL DRM_IOWR(0xC5, struct drm_syncobj_array) + +#define DRM_IOCTL_MODE_CREATE_LEASE DRM_IOWR(0xC6, struct drm_mode_create_lease) +#define DRM_IOCTL_MODE_LIST_LESSEES DRM_IOWR(0xC7, struct drm_mode_list_lessees) +#define DRM_IOCTL_MODE_GET_LEASE DRM_IOWR(0xC8, struct drm_mode_get_lease) +#define DRM_IOCTL_MODE_REVOKE_LEASE DRM_IOWR(0xC9, struct drm_mode_revoke_lease) + +#define DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT DRM_IOWR(0xCA, struct drm_syncobj_timeline_wait) +#define DRM_IOCTL_SYNCOBJ_QUERY DRM_IOWR(0xCB, struct drm_syncobj_timeline_array) +#define DRM_IOCTL_SYNCOBJ_TRANSFER DRM_IOWR(0xCC, struct drm_syncobj_transfer) +#define DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL DRM_IOWR(0xCD, struct drm_syncobj_timeline_array) + +#define DRM_IOCTL_MODE_GETFB2 DRM_IOWR(0xCE, struct drm_mode_fb_cmd2) + +/* + * Device specific ioctls should only be in their respective headers + * The device specific ioctl range is from 0x40 to 0x9f. + * Generic IOCTLS restart at 0xA0. + * + * \sa drmCommandNone(), drmCommandRead(), drmCommandWrite(), and + * drmCommandReadWrite(). + */ +#define DRM_COMMAND_BASE 0x40 +#define DRM_COMMAND_END 0xA0 + +/* + * Header for events written back to userspace on the drm fd. The + * type defines the type of event, the length specifies the total + * length of the event (including the header), and user_data is + * typically a 64 bit value passed with the ioctl that triggered the + * event. A read on the drm fd will always only return complete + * events, that is, if for example the read buffer is 100 bytes, and + * there are two 64 byte events pending, only one will be returned. + * + * Event types 0 - 0x7fffffff are generic drm events, 0x80000000 and + * up are chipset specific. + */ +struct drm_event { + __u32 type; + __u32 length; +}; + +#define DRM_EVENT_VBLANK 0x01 +#define DRM_EVENT_FLIP_COMPLETE 0x02 +#define DRM_EVENT_CRTC_SEQUENCE 0x03 + +struct drm_event_vblank { + struct drm_event base; + __u64 user_data; + __u32 tv_sec; + __u32 tv_usec; + __u32 sequence; + __u32 crtc_id; /* 0 on older kernels that do not support this */ +}; + +/* Event delivered at sequence. Time stamp marks when the first pixel + * of the refresh cycle leaves the display engine for the display + */ +struct drm_event_crtc_sequence { + struct drm_event base; + __u64 user_data; + __s64 time_ns; + __u64 sequence; +}; + +/* typedef area */ +typedef struct drm_clip_rect drm_clip_rect_t; +typedef struct drm_drawable_info drm_drawable_info_t; +typedef struct drm_tex_region drm_tex_region_t; +typedef struct drm_hw_lock drm_hw_lock_t; +typedef struct drm_version drm_version_t; +typedef struct drm_unique drm_unique_t; +typedef struct drm_list drm_list_t; +typedef struct drm_block drm_block_t; +typedef struct drm_control drm_control_t; +typedef enum drm_map_type drm_map_type_t; +typedef enum drm_map_flags drm_map_flags_t; +typedef struct drm_ctx_priv_map drm_ctx_priv_map_t; +typedef struct drm_map drm_map_t; +typedef struct drm_client drm_client_t; +typedef enum drm_stat_type drm_stat_type_t; +typedef struct drm_stats drm_stats_t; +typedef enum drm_lock_flags drm_lock_flags_t; +typedef struct drm_lock drm_lock_t; +typedef enum drm_dma_flags drm_dma_flags_t; +typedef struct drm_buf_desc drm_buf_desc_t; +typedef struct drm_buf_info drm_buf_info_t; +typedef struct drm_buf_free drm_buf_free_t; +typedef struct drm_buf_pub drm_buf_pub_t; +typedef struct drm_buf_map drm_buf_map_t; +typedef struct drm_dma drm_dma_t; +typedef union drm_wait_vblank drm_wait_vblank_t; +typedef struct drm_agp_mode drm_agp_mode_t; +typedef enum drm_ctx_flags drm_ctx_flags_t; +typedef struct drm_ctx drm_ctx_t; +typedef struct drm_ctx_res drm_ctx_res_t; +typedef struct drm_draw drm_draw_t; +typedef struct drm_update_draw drm_update_draw_t; +typedef struct drm_auth drm_auth_t; +typedef struct drm_irq_busid drm_irq_busid_t; +typedef enum drm_vblank_seq_type drm_vblank_seq_type_t; + +typedef struct drm_agp_buffer drm_agp_buffer_t; +typedef struct drm_agp_binding drm_agp_binding_t; +typedef struct drm_agp_info drm_agp_info_t; +typedef struct drm_scatter_gather drm_scatter_gather_t; +typedef struct drm_set_version drm_set_version_t; + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h new file mode 100644 index 0000000..2c9051f --- /dev/null +++ b/include/drm/drm_fourcc.h @@ -0,0 +1,1459 @@ +/* + * Copyright 2011 Intel Corporation + * + * 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS 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 DRM_FOURCC_H +#define DRM_FOURCC_H + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * DOC: overview + * + * In the DRM subsystem, framebuffer pixel formats are described using the + * fourcc codes defined in `include/uapi/drm/drm_fourcc.h`. In addition to the + * fourcc code, a Format Modifier may optionally be provided, in order to + * further describe the buffer's format - for example tiling or compression. + * + * Format Modifiers + * ---------------- + * + * Format modifiers are used in conjunction with a fourcc code, forming a + * unique fourcc:modifier pair. This format:modifier pair must fully define the + * format and data layout of the buffer, and should be the only way to describe + * that particular buffer. + * + * Having multiple fourcc:modifier pairs which describe the same layout should + * be avoided, as such aliases run the risk of different drivers exposing + * different names for the same data format, forcing userspace to understand + * that they are aliases. + * + * Format modifiers may change any property of the buffer, including the number + * of planes and/or the required allocation size. Format modifiers are + * vendor-namespaced, and as such the relationship between a fourcc code and a + * modifier is specific to the modifer being used. For example, some modifiers + * may preserve meaning - such as number of planes - from the fourcc code, + * whereas others may not. + * + * Modifiers must uniquely encode buffer layout. In other words, a buffer must + * match only a single modifier. A modifier must not be a subset of layouts of + * another modifier. For instance, it's incorrect to encode pitch alignment in + * a modifier: a buffer may match a 64-pixel aligned modifier and a 32-pixel + * aligned modifier. That said, modifiers can have implicit minimal + * requirements. + * + * For modifiers where the combination of fourcc code and modifier can alias, + * a canonical pair needs to be defined and used by all drivers. Preferred + * combinations are also encouraged where all combinations might lead to + * confusion and unnecessarily reduced interoperability. An example for the + * latter is AFBC, where the ABGR layouts are preferred over ARGB layouts. + * + * There are two kinds of modifier users: + * + * - Kernel and user-space drivers: for drivers it's important that modifiers + * don't alias, otherwise two drivers might support the same format but use + * different aliases, preventing them from sharing buffers in an efficient + * format. + * - Higher-level programs interfacing with KMS/GBM/EGL/Vulkan/etc: these users + * see modifiers as opaque tokens they can check for equality and intersect. + * These users musn't need to know to reason about the modifier value + * (i.e. they are not expected to extract information out of the modifier). + * + * Vendors should document their modifier usage in as much detail as + * possible, to ensure maximum compatibility across devices, drivers and + * applications. + * + * The authoritative list of format modifier codes is found in + * `include/uapi/drm/drm_fourcc.h` + */ + +#define fourcc_code(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | \ + ((__u32)(c) << 16) | ((__u32)(d) << 24)) + +#define DRM_FORMAT_BIG_ENDIAN (1U<<31) /* format is big endian instead of little endian */ + +/* Reserve 0 for the invalid format specifier */ +#define DRM_FORMAT_INVALID 0 + +/* color index */ +#define DRM_FORMAT_C8 fourcc_code('C', '8', ' ', ' ') /* [7:0] C */ + +/* 8 bpp Red */ +#define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ') /* [7:0] R */ + +/* 10 bpp Red */ +#define DRM_FORMAT_R10 fourcc_code('R', '1', '0', ' ') /* [15:0] x:R 6:10 little endian */ + +/* 12 bpp Red */ +#define DRM_FORMAT_R12 fourcc_code('R', '1', '2', ' ') /* [15:0] x:R 4:12 little endian */ + +/* 16 bpp Red */ +#define DRM_FORMAT_R16 fourcc_code('R', '1', '6', ' ') /* [15:0] R little endian */ + +/* 16 bpp RG */ +#define DRM_FORMAT_RG88 fourcc_code('R', 'G', '8', '8') /* [15:0] R:G 8:8 little endian */ +#define DRM_FORMAT_GR88 fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */ + +/* 32 bpp RG */ +#define DRM_FORMAT_RG1616 fourcc_code('R', 'G', '3', '2') /* [31:0] R:G 16:16 little endian */ +#define DRM_FORMAT_GR1616 fourcc_code('G', 'R', '3', '2') /* [31:0] G:R 16:16 little endian */ + +/* 8 bpp RGB */ +#define DRM_FORMAT_RGB332 fourcc_code('R', 'G', 'B', '8') /* [7:0] R:G:B 3:3:2 */ +#define DRM_FORMAT_BGR233 fourcc_code('B', 'G', 'R', '8') /* [7:0] B:G:R 2:3:3 */ + +/* 16 bpp RGB */ +#define DRM_FORMAT_XRGB4444 fourcc_code('X', 'R', '1', '2') /* [15:0] x:R:G:B 4:4:4:4 little endian */ +#define DRM_FORMAT_XBGR4444 fourcc_code('X', 'B', '1', '2') /* [15:0] x:B:G:R 4:4:4:4 little endian */ +#define DRM_FORMAT_RGBX4444 fourcc_code('R', 'X', '1', '2') /* [15:0] R:G:B:x 4:4:4:4 little endian */ +#define DRM_FORMAT_BGRX4444 fourcc_code('B', 'X', '1', '2') /* [15:0] B:G:R:x 4:4:4:4 little endian */ + +#define DRM_FORMAT_ARGB4444 fourcc_code('A', 'R', '1', '2') /* [15:0] A:R:G:B 4:4:4:4 little endian */ +#define DRM_FORMAT_ABGR4444 fourcc_code('A', 'B', '1', '2') /* [15:0] A:B:G:R 4:4:4:4 little endian */ +#define DRM_FORMAT_RGBA4444 fourcc_code('R', 'A', '1', '2') /* [15:0] R:G:B:A 4:4:4:4 little endian */ +#define DRM_FORMAT_BGRA4444 fourcc_code('B', 'A', '1', '2') /* [15:0] B:G:R:A 4:4:4:4 little endian */ + +#define DRM_FORMAT_XRGB1555 fourcc_code('X', 'R', '1', '5') /* [15:0] x:R:G:B 1:5:5:5 little endian */ +#define DRM_FORMAT_XBGR1555 fourcc_code('X', 'B', '1', '5') /* [15:0] x:B:G:R 1:5:5:5 little endian */ +#define DRM_FORMAT_RGBX5551 fourcc_code('R', 'X', '1', '5') /* [15:0] R:G:B:x 5:5:5:1 little endian */ +#define DRM_FORMAT_BGRX5551 fourcc_code('B', 'X', '1', '5') /* [15:0] B:G:R:x 5:5:5:1 little endian */ + +#define DRM_FORMAT_ARGB1555 fourcc_code('A', 'R', '1', '5') /* [15:0] A:R:G:B 1:5:5:5 little endian */ +#define DRM_FORMAT_ABGR1555 fourcc_code('A', 'B', '1', '5') /* [15:0] A:B:G:R 1:5:5:5 little endian */ +#define DRM_FORMAT_RGBA5551 fourcc_code('R', 'A', '1', '5') /* [15:0] R:G:B:A 5:5:5:1 little endian */ +#define DRM_FORMAT_BGRA5551 fourcc_code('B', 'A', '1', '5') /* [15:0] B:G:R:A 5:5:5:1 little endian */ + +#define DRM_FORMAT_RGB565 fourcc_code('R', 'G', '1', '6') /* [15:0] R:G:B 5:6:5 little endian */ +#define DRM_FORMAT_BGR565 fourcc_code('B', 'G', '1', '6') /* [15:0] B:G:R 5:6:5 little endian */ + +/* 24 bpp RGB */ +#define DRM_FORMAT_RGB888 fourcc_code('R', 'G', '2', '4') /* [23:0] R:G:B little endian */ +#define DRM_FORMAT_BGR888 fourcc_code('B', 'G', '2', '4') /* [23:0] B:G:R little endian */ + +/* 32 bpp RGB */ +#define DRM_FORMAT_XRGB8888 fourcc_code('X', 'R', '2', '4') /* [31:0] x:R:G:B 8:8:8:8 little endian */ +#define DRM_FORMAT_XBGR8888 fourcc_code('X', 'B', '2', '4') /* [31:0] x:B:G:R 8:8:8:8 little endian */ +#define DRM_FORMAT_RGBX8888 fourcc_code('R', 'X', '2', '4') /* [31:0] R:G:B:x 8:8:8:8 little endian */ +#define DRM_FORMAT_BGRX8888 fourcc_code('B', 'X', '2', '4') /* [31:0] B:G:R:x 8:8:8:8 little endian */ + +#define DRM_FORMAT_ARGB8888 fourcc_code('A', 'R', '2', '4') /* [31:0] A:R:G:B 8:8:8:8 little endian */ +#define DRM_FORMAT_ABGR8888 fourcc_code('A', 'B', '2', '4') /* [31:0] A:B:G:R 8:8:8:8 little endian */ +#define DRM_FORMAT_RGBA8888 fourcc_code('R', 'A', '2', '4') /* [31:0] R:G:B:A 8:8:8:8 little endian */ +#define DRM_FORMAT_BGRA8888 fourcc_code('B', 'A', '2', '4') /* [31:0] B:G:R:A 8:8:8:8 little endian */ + +#define DRM_FORMAT_XRGB2101010 fourcc_code('X', 'R', '3', '0') /* [31:0] x:R:G:B 2:10:10:10 little endian */ +#define DRM_FORMAT_XBGR2101010 fourcc_code('X', 'B', '3', '0') /* [31:0] x:B:G:R 2:10:10:10 little endian */ +#define DRM_FORMAT_RGBX1010102 fourcc_code('R', 'X', '3', '0') /* [31:0] R:G:B:x 10:10:10:2 little endian */ +#define DRM_FORMAT_BGRX1010102 fourcc_code('B', 'X', '3', '0') /* [31:0] B:G:R:x 10:10:10:2 little endian */ + +#define DRM_FORMAT_ARGB2101010 fourcc_code('A', 'R', '3', '0') /* [31:0] A:R:G:B 2:10:10:10 little endian */ +#define DRM_FORMAT_ABGR2101010 fourcc_code('A', 'B', '3', '0') /* [31:0] A:B:G:R 2:10:10:10 little endian */ +#define DRM_FORMAT_RGBA1010102 fourcc_code('R', 'A', '3', '0') /* [31:0] R:G:B:A 10:10:10:2 little endian */ +#define DRM_FORMAT_BGRA1010102 fourcc_code('B', 'A', '3', '0') /* [31:0] B:G:R:A 10:10:10:2 little endian */ + +/* 64 bpp RGB */ +#define DRM_FORMAT_XRGB16161616 fourcc_code('X', 'R', '4', '8') /* [63:0] x:R:G:B 16:16:16:16 little endian */ +#define DRM_FORMAT_XBGR16161616 fourcc_code('X', 'B', '4', '8') /* [63:0] x:B:G:R 16:16:16:16 little endian */ + +#define DRM_FORMAT_ARGB16161616 fourcc_code('A', 'R', '4', '8') /* [63:0] A:R:G:B 16:16:16:16 little endian */ +#define DRM_FORMAT_ABGR16161616 fourcc_code('A', 'B', '4', '8') /* [63:0] A:B:G:R 16:16:16:16 little endian */ + +/* + * Floating point 64bpp RGB + * IEEE 754-2008 binary16 half-precision float + * [15:0] sign:exponent:mantissa 1:5:10 + */ +#define DRM_FORMAT_XRGB16161616F fourcc_code('X', 'R', '4', 'H') /* [63:0] x:R:G:B 16:16:16:16 little endian */ +#define DRM_FORMAT_XBGR16161616F fourcc_code('X', 'B', '4', 'H') /* [63:0] x:B:G:R 16:16:16:16 little endian */ + +#define DRM_FORMAT_ARGB16161616F fourcc_code('A', 'R', '4', 'H') /* [63:0] A:R:G:B 16:16:16:16 little endian */ +#define DRM_FORMAT_ABGR16161616F fourcc_code('A', 'B', '4', 'H') /* [63:0] A:B:G:R 16:16:16:16 little endian */ + +/* + * RGBA format with 10-bit components packed in 64-bit per pixel, with 6 bits + * of unused padding per component: + */ +#define DRM_FORMAT_AXBXGXRX106106106106 fourcc_code('A', 'B', '1', '0') /* [63:0] A:x:B:x:G:x:R:x 10:6:10:6:10:6:10:6 little endian */ + +/* packed YCbCr */ +#define DRM_FORMAT_YUYV fourcc_code('Y', 'U', 'Y', 'V') /* [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian */ +#define DRM_FORMAT_YVYU fourcc_code('Y', 'V', 'Y', 'U') /* [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian */ +#define DRM_FORMAT_UYVY fourcc_code('U', 'Y', 'V', 'Y') /* [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian */ +#define DRM_FORMAT_VYUY fourcc_code('V', 'Y', 'U', 'Y') /* [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian */ + +#define DRM_FORMAT_AYUV fourcc_code('A', 'Y', 'U', 'V') /* [31:0] A:Y:Cb:Cr 8:8:8:8 little endian */ +#define DRM_FORMAT_XYUV8888 fourcc_code('X', 'Y', 'U', 'V') /* [31:0] X:Y:Cb:Cr 8:8:8:8 little endian */ +#define DRM_FORMAT_VUY888 fourcc_code('V', 'U', '2', '4') /* [23:0] Cr:Cb:Y 8:8:8 little endian */ +#define DRM_FORMAT_VUY101010 fourcc_code('V', 'U', '3', '0') /* Y followed by U then V, 10:10:10. Non-linear modifier only */ + +/* + * packed Y2xx indicate for each component, xx valid data occupy msb + * 16-xx padding occupy lsb + */ +#define DRM_FORMAT_Y210 fourcc_code('Y', '2', '1', '0') /* [63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 10:6:10:6:10:6:10:6 little endian per 2 Y pixels */ +#define DRM_FORMAT_Y212 fourcc_code('Y', '2', '1', '2') /* [63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 12:4:12:4:12:4:12:4 little endian per 2 Y pixels */ +#define DRM_FORMAT_Y216 fourcc_code('Y', '2', '1', '6') /* [63:0] Cr0:Y1:Cb0:Y0 16:16:16:16 little endian per 2 Y pixels */ + +/* + * packed Y4xx indicate for each component, xx valid data occupy msb + * 16-xx padding occupy lsb except Y410 + */ +#define DRM_FORMAT_Y410 fourcc_code('Y', '4', '1', '0') /* [31:0] A:Cr:Y:Cb 2:10:10:10 little endian */ +#define DRM_FORMAT_Y412 fourcc_code('Y', '4', '1', '2') /* [63:0] A:0:Cr:0:Y:0:Cb:0 12:4:12:4:12:4:12:4 little endian */ +#define DRM_FORMAT_Y416 fourcc_code('Y', '4', '1', '6') /* [63:0] A:Cr:Y:Cb 16:16:16:16 little endian */ + +#define DRM_FORMAT_XVYU2101010 fourcc_code('X', 'V', '3', '0') /* [31:0] X:Cr:Y:Cb 2:10:10:10 little endian */ +#define DRM_FORMAT_XVYU12_16161616 fourcc_code('X', 'V', '3', '6') /* [63:0] X:0:Cr:0:Y:0:Cb:0 12:4:12:4:12:4:12:4 little endian */ +#define DRM_FORMAT_XVYU16161616 fourcc_code('X', 'V', '4', '8') /* [63:0] X:Cr:Y:Cb 16:16:16:16 little endian */ + +/* + * packed YCbCr420 2x2 tiled formats + * first 64 bits will contain Y,Cb,Cr components for a 2x2 tile + */ +/* [63:0] A3:A2:Y3:0:Cr0:0:Y2:0:A1:A0:Y1:0:Cb0:0:Y0:0 1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian */ +#define DRM_FORMAT_Y0L0 fourcc_code('Y', '0', 'L', '0') +/* [63:0] X3:X2:Y3:0:Cr0:0:Y2:0:X1:X0:Y1:0:Cb0:0:Y0:0 1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian */ +#define DRM_FORMAT_X0L0 fourcc_code('X', '0', 'L', '0') + +/* [63:0] A3:A2:Y3:Cr0:Y2:A1:A0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian */ +#define DRM_FORMAT_Y0L2 fourcc_code('Y', '0', 'L', '2') +/* [63:0] X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0 1:1:10:10:10:1:1:10:10:10 little endian */ +#define DRM_FORMAT_X0L2 fourcc_code('X', '0', 'L', '2') + +/* + * 1-plane YUV 4:2:0 + * In these formats, the component ordering is specified (Y, followed by U + * then V), but the exact Linear layout is undefined. + * These formats can only be used with a non-Linear modifier. + */ +#define DRM_FORMAT_YUV420_8BIT fourcc_code('Y', 'U', '0', '8') +#define DRM_FORMAT_YUV420_10BIT fourcc_code('Y', 'U', '1', '0') + +/* + * 2 plane RGB + A + * index 0 = RGB plane, same format as the corresponding non _A8 format has + * index 1 = A plane, [7:0] A + */ +#define DRM_FORMAT_XRGB8888_A8 fourcc_code('X', 'R', 'A', '8') +#define DRM_FORMAT_XBGR8888_A8 fourcc_code('X', 'B', 'A', '8') +#define DRM_FORMAT_RGBX8888_A8 fourcc_code('R', 'X', 'A', '8') +#define DRM_FORMAT_BGRX8888_A8 fourcc_code('B', 'X', 'A', '8') +#define DRM_FORMAT_RGB888_A8 fourcc_code('R', '8', 'A', '8') +#define DRM_FORMAT_BGR888_A8 fourcc_code('B', '8', 'A', '8') +#define DRM_FORMAT_RGB565_A8 fourcc_code('R', '5', 'A', '8') +#define DRM_FORMAT_BGR565_A8 fourcc_code('B', '5', 'A', '8') + +/* + * 2 plane YCbCr + * index 0 = Y plane, [7:0] Y + * index 1 = Cr:Cb plane, [15:0] Cr:Cb little endian + * or + * index 1 = Cb:Cr plane, [15:0] Cb:Cr little endian + */ +#define DRM_FORMAT_NV12 fourcc_code('N', 'V', '1', '2') /* 2x2 subsampled Cr:Cb plane */ +#define DRM_FORMAT_NV21 fourcc_code('N', 'V', '2', '1') /* 2x2 subsampled Cb:Cr plane */ +#define DRM_FORMAT_NV16 fourcc_code('N', 'V', '1', '6') /* 2x1 subsampled Cr:Cb plane */ +#define DRM_FORMAT_NV61 fourcc_code('N', 'V', '6', '1') /* 2x1 subsampled Cb:Cr plane */ +#define DRM_FORMAT_NV24 fourcc_code('N', 'V', '2', '4') /* non-subsampled Cr:Cb plane */ +#define DRM_FORMAT_NV42 fourcc_code('N', 'V', '4', '2') /* non-subsampled Cb:Cr plane */ +/* + * 2 plane YCbCr + * index 0 = Y plane, [39:0] Y3:Y2:Y1:Y0 little endian + * index 1 = Cr:Cb plane, [39:0] Cr1:Cb1:Cr0:Cb0 little endian + */ +#define DRM_FORMAT_NV15 fourcc_code('N', 'V', '1', '5') /* 2x2 subsampled Cr:Cb plane */ + +/* + * 2 plane YCbCr MSB aligned + * index 0 = Y plane, [15:0] Y:x [10:6] little endian + * index 1 = Cr:Cb plane, [31:0] Cr:x:Cb:x [10:6:10:6] little endian + */ +#define DRM_FORMAT_P210 fourcc_code('P', '2', '1', '0') /* 2x1 subsampled Cr:Cb plane, 10 bit per channel */ + +/* + * 2 plane YCbCr MSB aligned + * index 0 = Y plane, [15:0] Y:x [10:6] little endian + * index 1 = Cr:Cb plane, [31:0] Cr:x:Cb:x [10:6:10:6] little endian + */ +#define DRM_FORMAT_P010 fourcc_code('P', '0', '1', '0') /* 2x2 subsampled Cr:Cb plane 10 bits per channel */ + +/* + * 2 plane YCbCr MSB aligned + * index 0 = Y plane, [15:0] Y:x [12:4] little endian + * index 1 = Cr:Cb plane, [31:0] Cr:x:Cb:x [12:4:12:4] little endian + */ +#define DRM_FORMAT_P012 fourcc_code('P', '0', '1', '2') /* 2x2 subsampled Cr:Cb plane 12 bits per channel */ + +/* + * 2 plane YCbCr MSB aligned + * index 0 = Y plane, [15:0] Y little endian + * index 1 = Cr:Cb plane, [31:0] Cr:Cb [16:16] little endian + */ +#define DRM_FORMAT_P016 fourcc_code('P', '0', '1', '6') /* 2x2 subsampled Cr:Cb plane 16 bits per channel */ + +/* 2 plane YCbCr420. + * 3 10 bit components and 2 padding bits packed into 4 bytes. + * index 0 = Y plane, [31:0] x:Y2:Y1:Y0 2:10:10:10 little endian + * index 1 = Cr:Cb plane, [63:0] x:Cr2:Cb2:Cr1:x:Cb1:Cr0:Cb0 [2:10:10:10:2:10:10:10] little endian + */ +#define DRM_FORMAT_P030 fourcc_code('P', '0', '3', '0') /* 2x2 subsampled Cr:Cb plane 10 bits per channel packed */ + +/* 3 plane non-subsampled (444) YCbCr + * 16 bits per component, but only 10 bits are used and 6 bits are padded + * index 0: Y plane, [15:0] Y:x [10:6] little endian + * index 1: Cb plane, [15:0] Cb:x [10:6] little endian + * index 2: Cr plane, [15:0] Cr:x [10:6] little endian + */ +#define DRM_FORMAT_Q410 fourcc_code('Q', '4', '1', '0') + +/* 3 plane non-subsampled (444) YCrCb + * 16 bits per component, but only 10 bits are used and 6 bits are padded + * index 0: Y plane, [15:0] Y:x [10:6] little endian + * index 1: Cr plane, [15:0] Cr:x [10:6] little endian + * index 2: Cb plane, [15:0] Cb:x [10:6] little endian + */ +#define DRM_FORMAT_Q401 fourcc_code('Q', '4', '0', '1') + +/* + * 3 plane YCbCr + * index 0: Y plane, [7:0] Y + * index 1: Cb plane, [7:0] Cb + * index 2: Cr plane, [7:0] Cr + * or + * index 1: Cr plane, [7:0] Cr + * index 2: Cb plane, [7:0] Cb + */ +#define DRM_FORMAT_YUV410 fourcc_code('Y', 'U', 'V', '9') /* 4x4 subsampled Cb (1) and Cr (2) planes */ +#define DRM_FORMAT_YVU410 fourcc_code('Y', 'V', 'U', '9') /* 4x4 subsampled Cr (1) and Cb (2) planes */ +#define DRM_FORMAT_YUV411 fourcc_code('Y', 'U', '1', '1') /* 4x1 subsampled Cb (1) and Cr (2) planes */ +#define DRM_FORMAT_YVU411 fourcc_code('Y', 'V', '1', '1') /* 4x1 subsampled Cr (1) and Cb (2) planes */ +#define DRM_FORMAT_YUV420 fourcc_code('Y', 'U', '1', '2') /* 2x2 subsampled Cb (1) and Cr (2) planes */ +#define DRM_FORMAT_YVU420 fourcc_code('Y', 'V', '1', '2') /* 2x2 subsampled Cr (1) and Cb (2) planes */ +#define DRM_FORMAT_YUV422 fourcc_code('Y', 'U', '1', '6') /* 2x1 subsampled Cb (1) and Cr (2) planes */ +#define DRM_FORMAT_YVU422 fourcc_code('Y', 'V', '1', '6') /* 2x1 subsampled Cr (1) and Cb (2) planes */ +#define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */ +#define DRM_FORMAT_YVU444 fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */ + + +/* + * Format Modifiers: + * + * Format modifiers describe, typically, a re-ordering or modification + * of the data in a plane of an FB. This can be used to express tiled/ + * swizzled formats, or compression, or a combination of the two. + * + * The upper 8 bits of the format modifier are a vendor-id as assigned + * below. The lower 56 bits are assigned as vendor sees fit. + */ + +/* Vendor Ids: */ +#define DRM_FORMAT_MOD_VENDOR_NONE 0 +#define DRM_FORMAT_MOD_VENDOR_INTEL 0x01 +#define DRM_FORMAT_MOD_VENDOR_AMD 0x02 +#define DRM_FORMAT_MOD_VENDOR_NVIDIA 0x03 +#define DRM_FORMAT_MOD_VENDOR_SAMSUNG 0x04 +#define DRM_FORMAT_MOD_VENDOR_QCOM 0x05 +#define DRM_FORMAT_MOD_VENDOR_VIVANTE 0x06 +#define DRM_FORMAT_MOD_VENDOR_BROADCOM 0x07 +#define DRM_FORMAT_MOD_VENDOR_ARM 0x08 +#define DRM_FORMAT_MOD_VENDOR_ALLWINNER 0x09 +#define DRM_FORMAT_MOD_VENDOR_AMLOGIC 0x0a + +/* add more to the end as needed */ + +#define DRM_FORMAT_RESERVED ((1ULL << 56) - 1) + +#define fourcc_mod_get_vendor(modifier) \ + (((modifier) >> 56) & 0xff) + +#define fourcc_mod_is_vendor(modifier, vendor) \ + (fourcc_mod_get_vendor(modifier) == DRM_FORMAT_MOD_VENDOR_## vendor) + +#define fourcc_mod_code(vendor, val) \ + ((((__u64)DRM_FORMAT_MOD_VENDOR_## vendor) << 56) | ((val) & 0x00ffffffffffffffULL)) + +/* + * Format Modifier tokens: + * + * When adding a new token please document the layout with a code comment, + * similar to the fourcc codes above. drm_fourcc.h is considered the + * authoritative source for all of these. + * + * Generic modifier names: + * + * DRM_FORMAT_MOD_GENERIC_* definitions are used to provide vendor-neutral names + * for layouts which are common across multiple vendors. To preserve + * compatibility, in cases where a vendor-specific definition already exists and + * a generic name for it is desired, the common name is a purely symbolic alias + * and must use the same numerical value as the original definition. + * + * Note that generic names should only be used for modifiers which describe + * generic layouts (such as pixel re-ordering), which may have + * independently-developed support across multiple vendors. + * + * In future cases where a generic layout is identified before merging with a + * vendor-specific modifier, a new 'GENERIC' vendor or modifier using vendor + * 'NONE' could be considered. This should only be for obvious, exceptional + * cases to avoid polluting the 'GENERIC' namespace with modifiers which only + * apply to a single vendor. + * + * Generic names should not be used for cases where multiple hardware vendors + * have implementations of the same standardised compression scheme (such as + * AFBC). In those cases, all implementations should use the same format + * modifier(s), reflecting the vendor of the standard. + */ + +#define DRM_FORMAT_MOD_GENERIC_16_16_TILE DRM_FORMAT_MOD_SAMSUNG_16_16_TILE + +/* + * Invalid Modifier + * + * This modifier can be used as a sentinel to terminate the format modifiers + * list, or to initialize a variable with an invalid modifier. It might also be + * used to report an error back to userspace for certain APIs. + */ +#define DRM_FORMAT_MOD_INVALID fourcc_mod_code(NONE, DRM_FORMAT_RESERVED) + +/* + * Linear Layout + * + * Just plain linear layout. Note that this is different from no specifying any + * modifier (e.g. not setting DRM_MODE_FB_MODIFIERS in the DRM_ADDFB2 ioctl), + * which tells the driver to also take driver-internal information into account + * and so might actually result in a tiled framebuffer. + */ +#define DRM_FORMAT_MOD_LINEAR fourcc_mod_code(NONE, 0) + +/* + * Deprecated: use DRM_FORMAT_MOD_LINEAR instead + * + * The "none" format modifier doesn't actually mean that the modifier is + * implicit, instead it means that the layout is linear. Whether modifiers are + * used is out-of-band information carried in an API-specific way (e.g. in a + * flag for drm_mode_fb_cmd2). + */ +#define DRM_FORMAT_MOD_NONE 0 + +/* Intel framebuffer modifiers */ + +/* + * Intel X-tiling layout + * + * This is a tiled layout using 4Kb tiles (except on gen2 where the tiles 2Kb) + * in row-major layout. Within the tile bytes are laid out row-major, with + * a platform-dependent stride. On top of that the memory can apply + * platform-depending swizzling of some higher address bits into bit6. + * + * Note that this layout is only accurate on intel gen 8+ or valleyview chipsets. + * On earlier platforms the is highly platforms specific and not useful for + * cross-driver sharing. It exists since on a given platform it does uniquely + * identify the layout in a simple way for i915-specific userspace, which + * facilitated conversion of userspace to modifiers. Additionally the exact + * format on some really old platforms is not known. + */ +#define I915_FORMAT_MOD_X_TILED fourcc_mod_code(INTEL, 1) + +/* + * Intel Y-tiling layout + * + * This is a tiled layout using 4Kb tiles (except on gen2 where the tiles 2Kb) + * in row-major layout. Within the tile bytes are laid out in OWORD (16 bytes) + * chunks column-major, with a platform-dependent height. On top of that the + * memory can apply platform-depending swizzling of some higher address bits + * into bit6. + * + * Note that this layout is only accurate on intel gen 8+ or valleyview chipsets. + * On earlier platforms the is highly platforms specific and not useful for + * cross-driver sharing. It exists since on a given platform it does uniquely + * identify the layout in a simple way for i915-specific userspace, which + * facilitated conversion of userspace to modifiers. Additionally the exact + * format on some really old platforms is not known. + */ +#define I915_FORMAT_MOD_Y_TILED fourcc_mod_code(INTEL, 2) + +/* + * Intel Yf-tiling layout + * + * This is a tiled layout using 4Kb tiles in row-major layout. + * Within the tile pixels are laid out in 16 256 byte units / sub-tiles which + * are arranged in four groups (two wide, two high) with column-major layout. + * Each group therefore consits out of four 256 byte units, which are also laid + * out as 2x2 column-major. + * 256 byte units are made out of four 64 byte blocks of pixels, producing + * either a square block or a 2:1 unit. + * 64 byte blocks of pixels contain four pixel rows of 16 bytes, where the width + * in pixel depends on the pixel depth. + */ +#define I915_FORMAT_MOD_Yf_TILED fourcc_mod_code(INTEL, 3) + +/* + * Intel color control surface (CCS) for render compression + * + * The framebuffer format must be one of the 8:8:8:8 RGB formats. + * The main surface will be plane index 0 and must be Y/Yf-tiled, + * the CCS will be plane index 1. + * + * Each CCS tile matches a 1024x512 pixel area of the main surface. + * To match certain aspects of the 3D hardware the CCS is + * considered to be made up of normal 128Bx32 Y tiles, Thus + * the CCS pitch must be specified in multiples of 128 bytes. + * + * In reality the CCS tile appears to be a 64Bx64 Y tile, composed + * of QWORD (8 bytes) chunks instead of OWORD (16 bytes) chunks. + * But that fact is not relevant unless the memory is accessed + * directly. + */ +#define I915_FORMAT_MOD_Y_TILED_CCS fourcc_mod_code(INTEL, 4) +#define I915_FORMAT_MOD_Yf_TILED_CCS fourcc_mod_code(INTEL, 5) + +/* + * Intel color control surfaces (CCS) for Gen-12 render compression. + * + * The main surface is Y-tiled and at plane index 0, the CCS is linear and + * at index 1. A 64B CCS cache line corresponds to an area of 4x1 tiles in + * main surface. In other words, 4 bits in CCS map to a main surface cache + * line pair. The main surface pitch is required to be a multiple of four + * Y-tile widths. + */ +#define I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS fourcc_mod_code(INTEL, 6) + +/* + * Intel color control surfaces (CCS) for Gen-12 media compression + * + * The main surface is Y-tiled and at plane index 0, the CCS is linear and + * at index 1. A 64B CCS cache line corresponds to an area of 4x1 tiles in + * main surface. In other words, 4 bits in CCS map to a main surface cache + * line pair. The main surface pitch is required to be a multiple of four + * Y-tile widths. For semi-planar formats like NV12, CCS planes follow the + * Y and UV planes i.e., planes 0 and 1 are used for Y and UV surfaces, + * planes 2 and 3 for the respective CCS. + */ +#define I915_FORMAT_MOD_Y_TILED_GEN12_MC_CCS fourcc_mod_code(INTEL, 7) + +/* + * Intel Color Control Surface with Clear Color (CCS) for Gen-12 render + * compression. + * + * The main surface is Y-tiled and is at plane index 0 whereas CCS is linear + * and at index 1. The clear color is stored at index 2, and the pitch should + * be 64 bytes aligned. The clear color structure is 256 bits. The first 128 bits + * represents Raw Clear Color Red, Green, Blue and Alpha color each represented + * by 32 bits. The raw clear color is consumed by the 3d engine and generates + * the converted clear color of size 64 bits. The first 32 bits store the Lower + * Converted Clear Color value and the next 32 bits store the Higher Converted + * Clear Color value when applicable. The Converted Clear Color values are + * consumed by the DE. The last 64 bits are used to store Color Discard Enable + * and Depth Clear Value Valid which are ignored by the DE. A CCS cache line + * corresponds to an area of 4x1 tiles in the main surface. The main surface + * pitch is required to be a multiple of 4 tile widths. + */ +#define I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC fourcc_mod_code(INTEL, 8) + +/* + * Intel Tile 4 layout + * + * This is a tiled layout using 4KB tiles in a row-major layout. It has the same + * shape as Tile Y at two granularities: 4KB (128B x 32) and 64B (16B x 4). It + * only differs from Tile Y at the 256B granularity in between. At this + * granularity, Tile Y has a shape of 16B x 32 rows, but this tiling has a shape + * of 64B x 8 rows. + */ +#define I915_FORMAT_MOD_4_TILED fourcc_mod_code(INTEL, 9) + +/* + * Intel color control surfaces (CCS) for DG2 render compression. + * + * The main surface is Tile 4 and at plane index 0. The CCS data is stored + * outside of the GEM object in a reserved memory area dedicated for the + * storage of the CCS data for all RC/RC_CC/MC compressible GEM objects. The + * main surface pitch is required to be a multiple of four Tile 4 widths. + */ +#define I915_FORMAT_MOD_4_TILED_DG2_RC_CCS fourcc_mod_code(INTEL, 10) + +/* + * Intel color control surfaces (CCS) for DG2 media compression. + * + * The main surface is Tile 4 and at plane index 0. For semi-planar formats + * like NV12, the Y and UV planes are Tile 4 and are located at plane indices + * 0 and 1, respectively. The CCS for all planes are stored outside of the + * GEM object in a reserved memory area dedicated for the storage of the + * CCS data for all RC/RC_CC/MC compressible GEM objects. The main surface + * pitch is required to be a multiple of four Tile 4 widths. + */ +#define I915_FORMAT_MOD_4_TILED_DG2_MC_CCS fourcc_mod_code(INTEL, 11) + +/* + * Intel Color Control Surface with Clear Color (CCS) for DG2 render compression. + * + * The main surface is Tile 4 and at plane index 0. The CCS data is stored + * outside of the GEM object in a reserved memory area dedicated for the + * storage of the CCS data for all RC/RC_CC/MC compressible GEM objects. The + * main surface pitch is required to be a multiple of four Tile 4 widths. The + * clear color is stored at plane index 1 and the pitch should be 64 bytes + * aligned. The format of the 256 bits of clear color data matches the one used + * for the I915_FORMAT_MOD_Y_TILED_GEN12_RC_CCS_CC modifier, see its description + * for details. + */ +#define I915_FORMAT_MOD_4_TILED_DG2_RC_CCS_CC fourcc_mod_code(INTEL, 12) + +/* + * Tiled, NV12MT, grouped in 64 (pixels) x 32 (lines) -sized macroblocks + * + * Macroblocks are laid in a Z-shape, and each pixel data is following the + * standard NV12 style. + * As for NV12, an image is the result of two frame buffers: one for Y, + * one for the interleaved Cb/Cr components (1/2 the height of the Y buffer). + * Alignment requirements are (for each buffer): + * - multiple of 128 pixels for the width + * - multiple of 32 pixels for the height + * + * For more information: see https://linuxtv.org/downloads/v4l-dvb-apis/re32.html + */ +#define DRM_FORMAT_MOD_SAMSUNG_64_32_TILE fourcc_mod_code(SAMSUNG, 1) + +/* + * Tiled, 16 (pixels) x 16 (lines) - sized macroblocks + * + * This is a simple tiled layout using tiles of 16x16 pixels in a row-major + * layout. For YCbCr formats Cb/Cr components are taken in such a way that + * they correspond to their 16x16 luma block. + */ +#define DRM_FORMAT_MOD_SAMSUNG_16_16_TILE fourcc_mod_code(SAMSUNG, 2) + +/* + * Qualcomm Compressed Format + * + * Refers to a compressed variant of the base format that is compressed. + * Implementation may be platform and base-format specific. + * + * Each macrotile consists of m x n (mostly 4 x 4) tiles. + * Pixel data pitch/stride is aligned with macrotile width. + * Pixel data height is aligned with macrotile height. + * Entire pixel data buffer is aligned with 4k(bytes). + */ +#define DRM_FORMAT_MOD_QCOM_COMPRESSED fourcc_mod_code(QCOM, 1) + +/* + * Qualcomm Tiled Format + * + * Similar to DRM_FORMAT_MOD_QCOM_COMPRESSED but not compressed. + * Implementation may be platform and base-format specific. + * + * Each macrotile consists of m x n (mostly 4 x 4) tiles. + * Pixel data pitch/stride is aligned with macrotile width. + * Pixel data height is aligned with macrotile height. + * Entire pixel data buffer is aligned with 4k(bytes). + */ +#define DRM_FORMAT_MOD_QCOM_TILED3 fourcc_mod_code(QCOM, 3) + +/* + * Qualcomm Alternate Tiled Format + * + * Alternate tiled format typically only used within GMEM. + * Implementation may be platform and base-format specific. + */ +#define DRM_FORMAT_MOD_QCOM_TILED2 fourcc_mod_code(QCOM, 2) + + +/* Vivante framebuffer modifiers */ + +/* + * Vivante 4x4 tiling layout + * + * This is a simple tiled layout using tiles of 4x4 pixels in a row-major + * layout. + */ +#define DRM_FORMAT_MOD_VIVANTE_TILED fourcc_mod_code(VIVANTE, 1) + +/* + * Vivante 64x64 super-tiling layout + * + * This is a tiled layout using 64x64 pixel super-tiles, where each super-tile + * contains 8x4 groups of 2x4 tiles of 4x4 pixels (like above) each, all in row- + * major layout. + * + * For more information: see + * https://github.com/etnaviv/etna_viv/blob/master/doc/hardware.md#texture-tiling + */ +#define DRM_FORMAT_MOD_VIVANTE_SUPER_TILED fourcc_mod_code(VIVANTE, 2) + +/* + * Vivante 4x4 tiling layout for dual-pipe + * + * Same as the 4x4 tiling layout, except every second 4x4 pixel tile starts at a + * different base address. Offsets from the base addresses are therefore halved + * compared to the non-split tiled layout. + */ +#define DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED fourcc_mod_code(VIVANTE, 3) + +/* + * Vivante 64x64 super-tiling layout for dual-pipe + * + * Same as the 64x64 super-tiling layout, except every second 4x4 pixel tile + * starts at a different base address. Offsets from the base addresses are + * therefore halved compared to the non-split super-tiled layout. + */ +#define DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED fourcc_mod_code(VIVANTE, 4) + +/* NVIDIA frame buffer modifiers */ + +/* + * Tegra Tiled Layout, used by Tegra 2, 3 and 4. + * + * Pixels are arranged in simple tiles of 16 x 16 bytes. + */ +#define DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED fourcc_mod_code(NVIDIA, 1) + +/* + * Generalized Block Linear layout, used by desktop GPUs starting with NV50/G80, + * and Tegra GPUs starting with Tegra K1. + * + * Pixels are arranged in Groups of Bytes (GOBs). GOB size and layout varies + * based on the architecture generation. GOBs themselves are then arranged in + * 3D blocks, with the block dimensions (in terms of GOBs) always being a power + * of two, and hence expressible as their log2 equivalent (E.g., "2" represents + * a block depth or height of "4"). + * + * Chapter 20 "Pixel Memory Formats" of the Tegra X1 TRM describes this format + * in full detail. + * + * Macro + * Bits Param Description + * ---- ----- ----------------------------------------------------------------- + * + * 3:0 h log2(height) of each block, in GOBs. Placed here for + * compatibility with the existing + * DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK()-based modifiers. + * + * 4:4 - Must be 1, to indicate block-linear layout. Necessary for + * compatibility with the existing + * DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK()-based modifiers. + * + * 8:5 - Reserved (To support 3D-surfaces with variable log2(depth) block + * size). Must be zero. + * + * Note there is no log2(width) parameter. Some portions of the + * hardware support a block width of two gobs, but it is impractical + * to use due to lack of support elsewhere, and has no known + * benefits. + * + * 11:9 - Reserved (To support 2D-array textures with variable array stride + * in blocks, specified via log2(tile width in blocks)). Must be + * zero. + * + * 19:12 k Page Kind. This value directly maps to a field in the page + * tables of all GPUs >= NV50. It affects the exact layout of bits + * in memory and can be derived from the tuple + * + * (format, GPU model, compression type, samples per pixel) + * + * Where compression type is defined below. If GPU model were + * implied by the format modifier, format, or memory buffer, page + * kind would not need to be included in the modifier itself, but + * since the modifier should define the layout of the associated + * memory buffer independent from any device or other context, it + * must be included here. + * + * 21:20 g GOB Height and Page Kind Generation. The height of a GOB changed + * starting with Fermi GPUs. Additionally, the mapping between page + * kind and bit layout has changed at various points. + * + * 0 = Gob Height 8, Fermi - Volta, Tegra K1+ Page Kind mapping + * 1 = Gob Height 4, G80 - GT2XX Page Kind mapping + * 2 = Gob Height 8, Turing+ Page Kind mapping + * 3 = Reserved for future use. + * + * 22:22 s Sector layout. On Tegra GPUs prior to Xavier, there is a further + * bit remapping step that occurs at an even lower level than the + * page kind and block linear swizzles. This causes the layout of + * surfaces mapped in those SOC's GPUs to be incompatible with the + * equivalent mapping on other GPUs in the same system. + * + * 0 = Tegra K1 - Tegra Parker/TX2 Layout. + * 1 = Desktop GPU and Tegra Xavier+ Layout + * + * 25:23 c Lossless Framebuffer Compression type. + * + * 0 = none + * 1 = ROP/3D, layout 1, exact compression format implied by Page + * Kind field + * 2 = ROP/3D, layout 2, exact compression format implied by Page + * Kind field + * 3 = CDE horizontal + * 4 = CDE vertical + * 5 = Reserved for future use + * 6 = Reserved for future use + * 7 = Reserved for future use + * + * 55:25 - Reserved for future use. Must be zero. + */ +#define DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(c, s, g, k, h) \ + fourcc_mod_code(NVIDIA, (0x10 | \ + ((h) & 0xf) | \ + (((k) & 0xff) << 12) | \ + (((g) & 0x3) << 20) | \ + (((s) & 0x1) << 22) | \ + (((c) & 0x7) << 23))) + +/* To grandfather in prior block linear format modifiers to the above layout, + * the page kind "0", which corresponds to "pitch/linear" and hence is unusable + * with block-linear layouts, is remapped within drivers to the value 0xfe, + * which corresponds to the "generic" kind used for simple single-sample + * uncompressed color formats on Fermi - Volta GPUs. + */ +static __inline__ __u64 +drm_fourcc_canonicalize_nvidia_format_mod(__u64 modifier) +{ + if (!(modifier & 0x10) || (modifier & (0xff << 12))) + return modifier; + else + return modifier | (0xfe << 12); +} + +/* + * 16Bx2 Block Linear layout, used by Tegra K1 and later + * + * Pixels are arranged in 64x8 Groups Of Bytes (GOBs). GOBs are then stacked + * vertically by a power of 2 (1 to 32 GOBs) to form a block. + * + * Within a GOB, data is ordered as 16B x 2 lines sectors laid in Z-shape. + * + * Parameter 'v' is the log2 encoding of the number of GOBs stacked vertically. + * Valid values are: + * + * 0 == ONE_GOB + * 1 == TWO_GOBS + * 2 == FOUR_GOBS + * 3 == EIGHT_GOBS + * 4 == SIXTEEN_GOBS + * 5 == THIRTYTWO_GOBS + * + * Chapter 20 "Pixel Memory Formats" of the Tegra X1 TRM describes this format + * in full detail. + */ +#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(v) \ + DRM_FORMAT_MOD_NVIDIA_BLOCK_LINEAR_2D(0, 0, 0, 0, (v)) + +#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_ONE_GOB \ + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0) +#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_TWO_GOB \ + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1) +#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_FOUR_GOB \ + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2) +#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_EIGHT_GOB \ + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3) +#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_SIXTEEN_GOB \ + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4) +#define DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK_THIRTYTWO_GOB \ + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5) + +/* + * Some Broadcom modifiers take parameters, for example the number of + * vertical lines in the image. Reserve the lower 32 bits for modifier + * type, and the next 24 bits for parameters. Top 8 bits are the + * vendor code. + */ +#define __fourcc_mod_broadcom_param_shift 8 +#define __fourcc_mod_broadcom_param_bits 48 +#define fourcc_mod_broadcom_code(val, params) \ + fourcc_mod_code(BROADCOM, ((((__u64)params) << __fourcc_mod_broadcom_param_shift) | val)) +#define fourcc_mod_broadcom_param(m) \ + ((int)(((m) >> __fourcc_mod_broadcom_param_shift) & \ + ((1ULL << __fourcc_mod_broadcom_param_bits) - 1))) +#define fourcc_mod_broadcom_mod(m) \ + ((m) & ~(((1ULL << __fourcc_mod_broadcom_param_bits) - 1) << \ + __fourcc_mod_broadcom_param_shift)) + +/* + * Broadcom VC4 "T" format + * + * This is the primary layout that the V3D GPU can texture from (it + * can't do linear). The T format has: + * + * - 64b utiles of pixels in a raster-order grid according to cpp. It's 4x4 + * pixels at 32 bit depth. + * + * - 1k subtiles made of a 4x4 raster-order grid of 64b utiles (so usually + * 16x16 pixels). + * + * - 4k tiles made of a 2x2 grid of 1k subtiles (so usually 32x32 pixels). On + * even 4k tile rows, they're arranged as (BL, TL, TR, BR), and on odd rows + * they're (TR, BR, BL, TL), where bottom left is start of memory. + * + * - an image made of 4k tiles in rows either left-to-right (even rows of 4k + * tiles) or right-to-left (odd rows of 4k tiles). + */ +#define DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED fourcc_mod_code(BROADCOM, 1) + +/* + * Broadcom SAND format + * + * This is the native format that the H.264 codec block uses. For VC4 + * HVS, it is only valid for H.264 (NV12/21) and RGBA modes. + * + * The image can be considered to be split into columns, and the + * columns are placed consecutively into memory. The width of those + * columns can be either 32, 64, 128, or 256 pixels, but in practice + * only 128 pixel columns are used. + * + * The pitch between the start of each column is set to optimally + * switch between SDRAM banks. This is passed as the number of lines + * of column width in the modifier (we can't use the stride value due + * to various core checks that look at it , so you should set the + * stride to width*cpp). + * + * Note that the column height for this format modifier is the same + * for all of the planes, assuming that each column contains both Y + * and UV. Some SAND-using hardware stores UV in a separate tiled + * image from Y to reduce the column height, which is not supported + * with these modifiers. + * + * The DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT modifier is also + * supported for DRM_FORMAT_P030 where the columns remain as 128 bytes + * wide, but as this is a 10 bpp format that translates to 96 pixels. + */ + +#define DRM_FORMAT_MOD_BROADCOM_SAND32_COL_HEIGHT(v) \ + fourcc_mod_broadcom_code(2, v) +#define DRM_FORMAT_MOD_BROADCOM_SAND64_COL_HEIGHT(v) \ + fourcc_mod_broadcom_code(3, v) +#define DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT(v) \ + fourcc_mod_broadcom_code(4, v) +#define DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(v) \ + fourcc_mod_broadcom_code(5, v) + +#define DRM_FORMAT_MOD_BROADCOM_SAND32 \ + DRM_FORMAT_MOD_BROADCOM_SAND32_COL_HEIGHT(0) +#define DRM_FORMAT_MOD_BROADCOM_SAND64 \ + DRM_FORMAT_MOD_BROADCOM_SAND64_COL_HEIGHT(0) +#define DRM_FORMAT_MOD_BROADCOM_SAND128 \ + DRM_FORMAT_MOD_BROADCOM_SAND128_COL_HEIGHT(0) +#define DRM_FORMAT_MOD_BROADCOM_SAND256 \ + DRM_FORMAT_MOD_BROADCOM_SAND256_COL_HEIGHT(0) + +/* Broadcom UIF format + * + * This is the common format for the current Broadcom multimedia + * blocks, including V3D 3.x and newer, newer video codecs, and + * displays. + * + * The image consists of utiles (64b blocks), UIF blocks (2x2 utiles), + * and macroblocks (4x4 UIF blocks). Those 4x4 UIF block groups are + * stored in columns, with padding between the columns to ensure that + * moving from one column to the next doesn't hit the same SDRAM page + * bank. + * + * To calculate the padding, it is assumed that each hardware block + * and the software driving it knows the platform's SDRAM page size, + * number of banks, and XOR address, and that it's identical between + * all blocks using the format. This tiling modifier will use XOR as + * necessary to reduce the padding. If a hardware block can't do XOR, + * the assumption is that a no-XOR tiling modifier will be created. + */ +#define DRM_FORMAT_MOD_BROADCOM_UIF fourcc_mod_code(BROADCOM, 6) + +/* + * Arm Framebuffer Compression (AFBC) modifiers + * + * AFBC is a proprietary lossless image compression protocol and format. + * It provides fine-grained random access and minimizes the amount of data + * transferred between IP blocks. + * + * AFBC has several features which may be supported and/or used, which are + * represented using bits in the modifier. Not all combinations are valid, + * and different devices or use-cases may support different combinations. + * + * Further information on the use of AFBC modifiers can be found in + * Documentation/gpu/afbc.rst + */ + +/* + * The top 4 bits (out of the 56 bits alloted for specifying vendor specific + * modifiers) denote the category for modifiers. Currently we have three + * categories of modifiers ie AFBC, MISC and AFRC. We can have a maximum of + * sixteen different categories. + */ +#define DRM_FORMAT_MOD_ARM_CODE(__type, __val) \ + fourcc_mod_code(ARM, ((__u64)(__type) << 52) | ((__val) & 0x000fffffffffffffULL)) + +#define DRM_FORMAT_MOD_ARM_TYPE_AFBC 0x00 +#define DRM_FORMAT_MOD_ARM_TYPE_MISC 0x01 + +#define DRM_FORMAT_MOD_ARM_AFBC(__afbc_mode) \ + DRM_FORMAT_MOD_ARM_CODE(DRM_FORMAT_MOD_ARM_TYPE_AFBC, __afbc_mode) + +/* + * AFBC superblock size + * + * Indicates the superblock size(s) used for the AFBC buffer. The buffer + * size (in pixels) must be aligned to a multiple of the superblock size. + * Four lowest significant bits(LSBs) are reserved for block size. + * + * Where one superblock size is specified, it applies to all planes of the + * buffer (e.g. 16x16, 32x8). When multiple superblock sizes are specified, + * the first applies to the Luma plane and the second applies to the Chroma + * plane(s). e.g. (32x8_64x4 means 32x8 Luma, with 64x4 Chroma). + * Multiple superblock sizes are only valid for multi-plane YCbCr formats. + */ +#define AFBC_FORMAT_MOD_BLOCK_SIZE_MASK 0xf +#define AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 (1ULL) +#define AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 (2ULL) +#define AFBC_FORMAT_MOD_BLOCK_SIZE_64x4 (3ULL) +#define AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4 (4ULL) + +/* + * AFBC lossless colorspace transform + * + * Indicates that the buffer makes use of the AFBC lossless colorspace + * transform. + */ +#define AFBC_FORMAT_MOD_YTR (1ULL << 4) + +/* + * AFBC block-split + * + * Indicates that the payload of each superblock is split. The second + * half of the payload is positioned at a predefined offset from the start + * of the superblock payload. + */ +#define AFBC_FORMAT_MOD_SPLIT (1ULL << 5) + +/* + * AFBC sparse layout + * + * This flag indicates that the payload of each superblock must be stored at a + * predefined position relative to the other superblocks in the same AFBC + * buffer. This order is the same order used by the header buffer. In this mode + * each superblock is given the same amount of space as an uncompressed + * superblock of the particular format would require, rounding up to the next + * multiple of 128 bytes in size. + */ +#define AFBC_FORMAT_MOD_SPARSE (1ULL << 6) + +/* + * AFBC copy-block restrict + * + * Buffers with this flag must obey the copy-block restriction. The restriction + * is such that there are no copy-blocks referring across the border of 8x8 + * blocks. For the subsampled data the 8x8 limitation is also subsampled. + */ +#define AFBC_FORMAT_MOD_CBR (1ULL << 7) + +/* + * AFBC tiled layout + * + * The tiled layout groups superblocks in 8x8 or 4x4 tiles, where all + * superblocks inside a tile are stored together in memory. 8x8 tiles are used + * for pixel formats up to and including 32 bpp while 4x4 tiles are used for + * larger bpp formats. The order between the tiles is scan line. + * When the tiled layout is used, the buffer size (in pixels) must be aligned + * to the tile size. + */ +#define AFBC_FORMAT_MOD_TILED (1ULL << 8) + +/* + * AFBC solid color blocks + * + * Indicates that the buffer makes use of solid-color blocks, whereby bandwidth + * can be reduced if a whole superblock is a single color. + */ +#define AFBC_FORMAT_MOD_SC (1ULL << 9) + +/* + * AFBC double-buffer + * + * Indicates that the buffer is allocated in a layout safe for front-buffer + * rendering. + */ +#define AFBC_FORMAT_MOD_DB (1ULL << 10) + +/* + * AFBC buffer content hints + * + * Indicates that the buffer includes per-superblock content hints. + */ +#define AFBC_FORMAT_MOD_BCH (1ULL << 11) + +/* AFBC uncompressed storage mode + * + * Indicates that the buffer is using AFBC uncompressed storage mode. + * In this mode all superblock payloads in the buffer use the uncompressed + * storage mode, which is usually only used for data which cannot be compressed. + * The buffer layout is the same as for AFBC buffers without USM set, this only + * affects the storage mode of the individual superblocks. Note that even a + * buffer without USM set may use uncompressed storage mode for some or all + * superblocks, USM just guarantees it for all. + */ +#define AFBC_FORMAT_MOD_USM (1ULL << 12) + +/* + * Arm Fixed-Rate Compression (AFRC) modifiers + * + * AFRC is a proprietary fixed rate image compression protocol and format, + * designed to provide guaranteed bandwidth and memory footprint + * reductions in graphics and media use-cases. + * + * AFRC buffers consist of one or more planes, with the same components + * and meaning as an uncompressed buffer using the same pixel format. + * + * Within each plane, the pixel/luma/chroma values are grouped into + * "coding unit" blocks which are individually compressed to a + * fixed size (in bytes). All coding units within a given plane of a buffer + * store the same number of values, and have the same compressed size. + * + * The coding unit size is configurable, allowing different rates of compression. + * + * The start of each AFRC buffer plane must be aligned to an alignment granule which + * depends on the coding unit size. + * + * Coding Unit Size Plane Alignment + * ---------------- --------------- + * 16 bytes 1024 bytes + * 24 bytes 512 bytes + * 32 bytes 2048 bytes + * + * Coding units are grouped into paging tiles. AFRC buffer dimensions must be aligned + * to a multiple of the paging tile dimensions. + * The dimensions of each paging tile depend on whether the buffer is optimised for + * scanline (SCAN layout) or rotated (ROT layout) access. + * + * Layout Paging Tile Width Paging Tile Height + * ------ ----------------- ------------------ + * SCAN 16 coding units 4 coding units + * ROT 8 coding units 8 coding units + * + * The dimensions of each coding unit depend on the number of components + * in the compressed plane and whether the buffer is optimised for + * scanline (SCAN layout) or rotated (ROT layout) access. + * + * Number of Components in Plane Layout Coding Unit Width Coding Unit Height + * ----------------------------- --------- ----------------- ------------------ + * 1 SCAN 16 samples 4 samples + * Example: 16x4 luma samples in a 'Y' plane + * 16x4 chroma 'V' values, in the 'V' plane of a fully-planar YUV buffer + * ----------------------------- --------- ----------------- ------------------ + * 1 ROT 8 samples 8 samples + * Example: 8x8 luma samples in a 'Y' plane + * 8x8 chroma 'V' values, in the 'V' plane of a fully-planar YUV buffer + * ----------------------------- --------- ----------------- ------------------ + * 2 DONT CARE 8 samples 4 samples + * Example: 8x4 chroma pairs in the 'UV' plane of a semi-planar YUV buffer + * ----------------------------- --------- ----------------- ------------------ + * 3 DONT CARE 4 samples 4 samples + * Example: 4x4 pixels in an RGB buffer without alpha + * ----------------------------- --------- ----------------- ------------------ + * 4 DONT CARE 4 samples 4 samples + * Example: 4x4 pixels in an RGB buffer with alpha + */ + +#define DRM_FORMAT_MOD_ARM_TYPE_AFRC 0x02 + +#define DRM_FORMAT_MOD_ARM_AFRC(__afrc_mode) \ + DRM_FORMAT_MOD_ARM_CODE(DRM_FORMAT_MOD_ARM_TYPE_AFRC, __afrc_mode) + +/* + * AFRC coding unit size modifier. + * + * Indicates the number of bytes used to store each compressed coding unit for + * one or more planes in an AFRC encoded buffer. The coding unit size for chrominance + * is the same for both Cb and Cr, which may be stored in separate planes. + * + * AFRC_FORMAT_MOD_CU_SIZE_P0 indicates the number of bytes used to store + * each compressed coding unit in the first plane of the buffer. For RGBA buffers + * this is the only plane, while for semi-planar and fully-planar YUV buffers, + * this corresponds to the luma plane. + * + * AFRC_FORMAT_MOD_CU_SIZE_P12 indicates the number of bytes used to store + * each compressed coding unit in the second and third planes in the buffer. + * For semi-planar and fully-planar YUV buffers, this corresponds to the chroma plane(s). + * + * For single-plane buffers, AFRC_FORMAT_MOD_CU_SIZE_P0 must be specified + * and AFRC_FORMAT_MOD_CU_SIZE_P12 must be zero. + * For semi-planar and fully-planar buffers, both AFRC_FORMAT_MOD_CU_SIZE_P0 and + * AFRC_FORMAT_MOD_CU_SIZE_P12 must be specified. + */ +#define AFRC_FORMAT_MOD_CU_SIZE_MASK 0xf +#define AFRC_FORMAT_MOD_CU_SIZE_16 (1ULL) +#define AFRC_FORMAT_MOD_CU_SIZE_24 (2ULL) +#define AFRC_FORMAT_MOD_CU_SIZE_32 (3ULL) + +#define AFRC_FORMAT_MOD_CU_SIZE_P0(__afrc_cu_size) (__afrc_cu_size) +#define AFRC_FORMAT_MOD_CU_SIZE_P12(__afrc_cu_size) ((__afrc_cu_size) << 4) + +/* + * AFRC scanline memory layout. + * + * Indicates if the buffer uses the scanline-optimised layout + * for an AFRC encoded buffer, otherwise, it uses the rotation-optimised layout. + * The memory layout is the same for all planes. + */ +#define AFRC_FORMAT_MOD_LAYOUT_SCAN (1ULL << 8) + +/* + * Arm 16x16 Block U-Interleaved modifier + * + * This is used by Arm Mali Utgard and Midgard GPUs. It divides the image + * into 16x16 pixel blocks. Blocks are stored linearly in order, but pixels + * in the block are reordered. + */ +#define DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED \ + DRM_FORMAT_MOD_ARM_CODE(DRM_FORMAT_MOD_ARM_TYPE_MISC, 1ULL) + +/* + * Allwinner tiled modifier + * + * This tiling mode is implemented by the VPU found on all Allwinner platforms, + * codenamed sunxi. It is associated with a YUV format that uses either 2 or 3 + * planes. + * + * With this tiling, the luminance samples are disposed in tiles representing + * 32x32 pixels and the chrominance samples in tiles representing 32x64 pixels. + * The pixel order in each tile is linear and the tiles are disposed linearly, + * both in row-major order. + */ +#define DRM_FORMAT_MOD_ALLWINNER_TILED fourcc_mod_code(ALLWINNER, 1) + +/* + * Amlogic Video Framebuffer Compression modifiers + * + * Amlogic uses a proprietary lossless image compression protocol and format + * for their hardware video codec accelerators, either video decoders or + * video input encoders. + * + * It considerably reduces memory bandwidth while writing and reading + * frames in memory. + * + * The underlying storage is considered to be 3 components, 8bit or 10-bit + * per component YCbCr 420, single plane : + * - DRM_FORMAT_YUV420_8BIT + * - DRM_FORMAT_YUV420_10BIT + * + * The first 8 bits of the mode defines the layout, then the following 8 bits + * defines the options changing the layout. + * + * Not all combinations are valid, and different SoCs may support different + * combinations of layout and options. + */ +#define __fourcc_mod_amlogic_layout_mask 0xff +#define __fourcc_mod_amlogic_options_shift 8 +#define __fourcc_mod_amlogic_options_mask 0xff + +#define DRM_FORMAT_MOD_AMLOGIC_FBC(__layout, __options) \ + fourcc_mod_code(AMLOGIC, \ + ((__layout) & __fourcc_mod_amlogic_layout_mask) | \ + (((__options) & __fourcc_mod_amlogic_options_mask) \ + << __fourcc_mod_amlogic_options_shift)) + +/* Amlogic FBC Layouts */ + +/* + * Amlogic FBC Basic Layout + * + * The basic layout is composed of: + * - a body content organized in 64x32 superblocks with 4096 bytes per + * superblock in default mode. + * - a 32 bytes per 128x64 header block + * + * This layout is transferrable between Amlogic SoCs supporting this modifier. + */ +#define AMLOGIC_FBC_LAYOUT_BASIC (1ULL) + +/* + * Amlogic FBC Scatter Memory layout + * + * Indicates the header contains IOMMU references to the compressed + * frames content to optimize memory access and layout. + * + * In this mode, only the header memory address is needed, thus the + * content memory organization is tied to the current producer + * execution and cannot be saved/dumped neither transferrable between + * Amlogic SoCs supporting this modifier. + * + * Due to the nature of the layout, these buffers are not expected to + * be accessible by the user-space clients, but only accessible by the + * hardware producers and consumers. + * + * The user-space clients should expect a failure while trying to mmap + * the DMA-BUF handle returned by the producer. + */ +#define AMLOGIC_FBC_LAYOUT_SCATTER (2ULL) + +/* Amlogic FBC Layout Options Bit Mask */ + +/* + * Amlogic FBC Memory Saving mode + * + * Indicates the storage is packed when pixel size is multiple of word + * boudaries, i.e. 8bit should be stored in this mode to save allocation + * memory. + * + * This mode reduces body layout to 3072 bytes per 64x32 superblock with + * the basic layout and 3200 bytes per 64x32 superblock combined with + * the scatter layout. + */ +#define AMLOGIC_FBC_OPTION_MEM_SAVING (1ULL << 0) + +/* + * AMD modifiers + * + * Memory layout: + * + * without DCC: + * - main surface + * + * with DCC & without DCC_RETILE: + * - main surface in plane 0 + * - DCC surface in plane 1 (RB-aligned, pipe-aligned if DCC_PIPE_ALIGN is set) + * + * with DCC & DCC_RETILE: + * - main surface in plane 0 + * - displayable DCC surface in plane 1 (not RB-aligned & not pipe-aligned) + * - pipe-aligned DCC surface in plane 2 (RB-aligned & pipe-aligned) + * + * For multi-plane formats the above surfaces get merged into one plane for + * each format plane, based on the required alignment only. + * + * Bits Parameter Notes + * ----- ------------------------ --------------------------------------------- + * + * 7:0 TILE_VERSION Values are AMD_FMT_MOD_TILE_VER_* + * 12:8 TILE Values are AMD_FMT_MOD_TILE__* + * 13 DCC + * 14 DCC_RETILE + * 15 DCC_PIPE_ALIGN + * 16 DCC_INDEPENDENT_64B + * 17 DCC_INDEPENDENT_128B + * 19:18 DCC_MAX_COMPRESSED_BLOCK Values are AMD_FMT_MOD_DCC_BLOCK_* + * 20 DCC_CONSTANT_ENCODE + * 23:21 PIPE_XOR_BITS Only for some chips + * 26:24 BANK_XOR_BITS Only for some chips + * 29:27 PACKERS Only for some chips + * 32:30 RB Only for some chips + * 35:33 PIPE Only for some chips + * 55:36 - Reserved for future use, must be zero + */ +#define AMD_FMT_MOD fourcc_mod_code(AMD, 0) + +#define IS_AMD_FMT_MOD(val) (((val) >> 56) == DRM_FORMAT_MOD_VENDOR_AMD) + +/* Reserve 0 for GFX8 and older */ +#define AMD_FMT_MOD_TILE_VER_GFX9 1 +#define AMD_FMT_MOD_TILE_VER_GFX10 2 +#define AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS 3 +#define AMD_FMT_MOD_TILE_VER_GFX11 4 + +/* + * 64K_S is the same for GFX9/GFX10/GFX10_RBPLUS and hence has GFX9 as canonical + * version. + */ +#define AMD_FMT_MOD_TILE_GFX9_64K_S 9 + +/* + * 64K_D for non-32 bpp is the same for GFX9/GFX10/GFX10_RBPLUS and hence has + * GFX9 as canonical version. + */ +#define AMD_FMT_MOD_TILE_GFX9_64K_D 10 +#define AMD_FMT_MOD_TILE_GFX9_64K_S_X 25 +#define AMD_FMT_MOD_TILE_GFX9_64K_D_X 26 +#define AMD_FMT_MOD_TILE_GFX9_64K_R_X 27 +#define AMD_FMT_MOD_TILE_GFX11_256K_R_X 31 + +#define AMD_FMT_MOD_DCC_BLOCK_64B 0 +#define AMD_FMT_MOD_DCC_BLOCK_128B 1 +#define AMD_FMT_MOD_DCC_BLOCK_256B 2 + +#define AMD_FMT_MOD_TILE_VERSION_SHIFT 0 +#define AMD_FMT_MOD_TILE_VERSION_MASK 0xFF +#define AMD_FMT_MOD_TILE_SHIFT 8 +#define AMD_FMT_MOD_TILE_MASK 0x1F + +/* Whether DCC compression is enabled. */ +#define AMD_FMT_MOD_DCC_SHIFT 13 +#define AMD_FMT_MOD_DCC_MASK 0x1 + +/* + * Whether to include two DCC surfaces, one which is rb & pipe aligned, and + * one which is not-aligned. + */ +#define AMD_FMT_MOD_DCC_RETILE_SHIFT 14 +#define AMD_FMT_MOD_DCC_RETILE_MASK 0x1 + +/* Only set if DCC_RETILE = false */ +#define AMD_FMT_MOD_DCC_PIPE_ALIGN_SHIFT 15 +#define AMD_FMT_MOD_DCC_PIPE_ALIGN_MASK 0x1 + +#define AMD_FMT_MOD_DCC_INDEPENDENT_64B_SHIFT 16 +#define AMD_FMT_MOD_DCC_INDEPENDENT_64B_MASK 0x1 +#define AMD_FMT_MOD_DCC_INDEPENDENT_128B_SHIFT 17 +#define AMD_FMT_MOD_DCC_INDEPENDENT_128B_MASK 0x1 +#define AMD_FMT_MOD_DCC_MAX_COMPRESSED_BLOCK_SHIFT 18 +#define AMD_FMT_MOD_DCC_MAX_COMPRESSED_BLOCK_MASK 0x3 + +/* + * DCC supports embedding some clear colors directly in the DCC surface. + * However, on older GPUs the rendering HW ignores the embedded clear color + * and prefers the driver provided color. This necessitates doing a fastclear + * eliminate operation before a process transfers control. + * + * If this bit is set that means the fastclear eliminate is not needed for these + * embeddable colors. + */ +#define AMD_FMT_MOD_DCC_CONSTANT_ENCODE_SHIFT 20 +#define AMD_FMT_MOD_DCC_CONSTANT_ENCODE_MASK 0x1 + +/* + * The below fields are for accounting for per GPU differences. These are only + * relevant for GFX9 and later and if the tile field is *_X/_T. + * + * PIPE_XOR_BITS = always needed + * BANK_XOR_BITS = only for TILE_VER_GFX9 + * PACKERS = only for TILE_VER_GFX10_RBPLUS + * RB = only for TILE_VER_GFX9 & DCC + * PIPE = only for TILE_VER_GFX9 & DCC & (DCC_RETILE | DCC_PIPE_ALIGN) + */ +#define AMD_FMT_MOD_PIPE_XOR_BITS_SHIFT 21 +#define AMD_FMT_MOD_PIPE_XOR_BITS_MASK 0x7 +#define AMD_FMT_MOD_BANK_XOR_BITS_SHIFT 24 +#define AMD_FMT_MOD_BANK_XOR_BITS_MASK 0x7 +#define AMD_FMT_MOD_PACKERS_SHIFT 27 +#define AMD_FMT_MOD_PACKERS_MASK 0x7 +#define AMD_FMT_MOD_RB_SHIFT 30 +#define AMD_FMT_MOD_RB_MASK 0x7 +#define AMD_FMT_MOD_PIPE_SHIFT 33 +#define AMD_FMT_MOD_PIPE_MASK 0x7 + +#define AMD_FMT_MOD_SET(field, value) \ + ((__u64)(value) << AMD_FMT_MOD_##field##_SHIFT) +#define AMD_FMT_MOD_GET(field, value) \ + (((value) >> AMD_FMT_MOD_##field##_SHIFT) & AMD_FMT_MOD_##field##_MASK) +#define AMD_FMT_MOD_CLEAR(field) \ + (~((__u64)AMD_FMT_MOD_##field##_MASK << AMD_FMT_MOD_##field##_SHIFT)) + +#if defined(__cplusplus) +} +#endif + +#endif /* DRM_FOURCC_H */ diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h new file mode 100644 index 0000000..9b6722d --- /dev/null +++ b/include/drm/drm_mode.h @@ -0,0 +1,1129 @@ +/* + * Copyright (c) 2007 Dave Airlie + * Copyright (c) 2007 Jakob Bornecrantz + * Copyright (c) 2008 Red Hat Inc. + * Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, TX., USA + * Copyright (c) 2007-2008 Intel Corporation + * + * 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. + */ + +#ifndef _DRM_MODE_H +#define _DRM_MODE_H + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * DOC: overview + * + * DRM exposes many UAPI and structure definition to have a consistent + * and standardized interface with user. + * Userspace can refer to these structure definitions and UAPI formats + * to communicate to driver + */ + +#define DRM_CONNECTOR_NAME_LEN 32 +#define DRM_DISPLAY_MODE_LEN 32 +#define DRM_PROP_NAME_LEN 32 + +#define DRM_MODE_TYPE_BUILTIN (1<<0) /* deprecated */ +#define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN) /* deprecated */ +#define DRM_MODE_TYPE_CRTC_C ((1<<2) | DRM_MODE_TYPE_BUILTIN) /* deprecated */ +#define DRM_MODE_TYPE_PREFERRED (1<<3) +#define DRM_MODE_TYPE_DEFAULT (1<<4) /* deprecated */ +#define DRM_MODE_TYPE_USERDEF (1<<5) +#define DRM_MODE_TYPE_DRIVER (1<<6) + +#define DRM_MODE_TYPE_ALL (DRM_MODE_TYPE_PREFERRED | \ + DRM_MODE_TYPE_USERDEF | \ + DRM_MODE_TYPE_DRIVER) + +/* Video mode flags */ +/* bit compatible with the xrandr RR_ definitions (bits 0-13) + * + * ABI warning: Existing userspace really expects + * the mode flags to match the xrandr definitions. Any + * changes that don't match the xrandr definitions will + * likely need a new client cap or some other mechanism + * to avoid breaking existing userspace. This includes + * allocating new flags in the previously unused bits! + */ +#define DRM_MODE_FLAG_PHSYNC (1<<0) +#define DRM_MODE_FLAG_NHSYNC (1<<1) +#define DRM_MODE_FLAG_PVSYNC (1<<2) +#define DRM_MODE_FLAG_NVSYNC (1<<3) +#define DRM_MODE_FLAG_INTERLACE (1<<4) +#define DRM_MODE_FLAG_DBLSCAN (1<<5) +#define DRM_MODE_FLAG_CSYNC (1<<6) +#define DRM_MODE_FLAG_PCSYNC (1<<7) +#define DRM_MODE_FLAG_NCSYNC (1<<8) +#define DRM_MODE_FLAG_HSKEW (1<<9) /* hskew provided */ +#define DRM_MODE_FLAG_BCAST (1<<10) /* deprecated */ +#define DRM_MODE_FLAG_PIXMUX (1<<11) /* deprecated */ +#define DRM_MODE_FLAG_DBLCLK (1<<12) +#define DRM_MODE_FLAG_CLKDIV2 (1<<13) + /* + * When adding a new stereo mode don't forget to adjust DRM_MODE_FLAGS_3D_MAX + * (define not exposed to user space). + */ +#define DRM_MODE_FLAG_3D_MASK (0x1f<<14) +#define DRM_MODE_FLAG_3D_NONE (0<<14) +#define DRM_MODE_FLAG_3D_FRAME_PACKING (1<<14) +#define DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE (2<<14) +#define DRM_MODE_FLAG_3D_LINE_ALTERNATIVE (3<<14) +#define DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL (4<<14) +#define DRM_MODE_FLAG_3D_L_DEPTH (5<<14) +#define DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH (6<<14) +#define DRM_MODE_FLAG_3D_TOP_AND_BOTTOM (7<<14) +#define DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF (8<<14) + +/* Picture aspect ratio options */ +#define DRM_MODE_PICTURE_ASPECT_NONE 0 +#define DRM_MODE_PICTURE_ASPECT_4_3 1 +#define DRM_MODE_PICTURE_ASPECT_16_9 2 +#define DRM_MODE_PICTURE_ASPECT_64_27 3 +#define DRM_MODE_PICTURE_ASPECT_256_135 4 + +/* Content type options */ +#define DRM_MODE_CONTENT_TYPE_NO_DATA 0 +#define DRM_MODE_CONTENT_TYPE_GRAPHICS 1 +#define DRM_MODE_CONTENT_TYPE_PHOTO 2 +#define DRM_MODE_CONTENT_TYPE_CINEMA 3 +#define DRM_MODE_CONTENT_TYPE_GAME 4 + +/* Aspect ratio flag bitmask (4 bits 22:19) */ +#define DRM_MODE_FLAG_PIC_AR_MASK (0x0F<<19) +#define DRM_MODE_FLAG_PIC_AR_NONE \ + (DRM_MODE_PICTURE_ASPECT_NONE<<19) +#define DRM_MODE_FLAG_PIC_AR_4_3 \ + (DRM_MODE_PICTURE_ASPECT_4_3<<19) +#define DRM_MODE_FLAG_PIC_AR_16_9 \ + (DRM_MODE_PICTURE_ASPECT_16_9<<19) +#define DRM_MODE_FLAG_PIC_AR_64_27 \ + (DRM_MODE_PICTURE_ASPECT_64_27<<19) +#define DRM_MODE_FLAG_PIC_AR_256_135 \ + (DRM_MODE_PICTURE_ASPECT_256_135<<19) + +#define DRM_MODE_FLAG_ALL (DRM_MODE_FLAG_PHSYNC | \ + DRM_MODE_FLAG_NHSYNC | \ + DRM_MODE_FLAG_PVSYNC | \ + DRM_MODE_FLAG_NVSYNC | \ + DRM_MODE_FLAG_INTERLACE | \ + DRM_MODE_FLAG_DBLSCAN | \ + DRM_MODE_FLAG_CSYNC | \ + DRM_MODE_FLAG_PCSYNC | \ + DRM_MODE_FLAG_NCSYNC | \ + DRM_MODE_FLAG_HSKEW | \ + DRM_MODE_FLAG_DBLCLK | \ + DRM_MODE_FLAG_CLKDIV2 | \ + DRM_MODE_FLAG_3D_MASK) + +/* DPMS flags */ +/* bit compatible with the xorg definitions. */ +#define DRM_MODE_DPMS_ON 0 +#define DRM_MODE_DPMS_STANDBY 1 +#define DRM_MODE_DPMS_SUSPEND 2 +#define DRM_MODE_DPMS_OFF 3 + +/* Scaling mode options */ +#define DRM_MODE_SCALE_NONE 0 /* Unmodified timing (display or + software can still scale) */ +#define DRM_MODE_SCALE_FULLSCREEN 1 /* Full screen, ignore aspect */ +#define DRM_MODE_SCALE_CENTER 2 /* Centered, no scaling */ +#define DRM_MODE_SCALE_ASPECT 3 /* Full screen, preserve aspect */ + +/* Dithering mode options */ +#define DRM_MODE_DITHERING_OFF 0 +#define DRM_MODE_DITHERING_ON 1 +#define DRM_MODE_DITHERING_AUTO 2 + +/* Dirty info options */ +#define DRM_MODE_DIRTY_OFF 0 +#define DRM_MODE_DIRTY_ON 1 +#define DRM_MODE_DIRTY_ANNOTATE 2 + +/* Link Status options */ +#define DRM_MODE_LINK_STATUS_GOOD 0 +#define DRM_MODE_LINK_STATUS_BAD 1 + +/* + * DRM_MODE_ROTATE_ + * + * Signals that a drm plane is been rotated degrees in counter + * clockwise direction. + * + * This define is provided as a convenience, looking up the property id + * using the name->prop id lookup is the preferred method. + */ +#define DRM_MODE_ROTATE_0 (1<<0) +#define DRM_MODE_ROTATE_90 (1<<1) +#define DRM_MODE_ROTATE_180 (1<<2) +#define DRM_MODE_ROTATE_270 (1<<3) + +/* + * DRM_MODE_ROTATE_MASK + * + * Bitmask used to look for drm plane rotations. + */ +#define DRM_MODE_ROTATE_MASK (\ + DRM_MODE_ROTATE_0 | \ + DRM_MODE_ROTATE_90 | \ + DRM_MODE_ROTATE_180 | \ + DRM_MODE_ROTATE_270) + +/* + * DRM_MODE_REFLECT_ + * + * Signals that the contents of a drm plane is reflected along the axis, + * in the same way as mirroring. + * See kerneldoc chapter "Plane Composition Properties" for more details. + * + * This define is provided as a convenience, looking up the property id + * using the name->prop id lookup is the preferred method. + */ +#define DRM_MODE_REFLECT_X (1<<4) +#define DRM_MODE_REFLECT_Y (1<<5) + +/* + * DRM_MODE_REFLECT_MASK + * + * Bitmask used to look for drm plane reflections. + */ +#define DRM_MODE_REFLECT_MASK (\ + DRM_MODE_REFLECT_X | \ + DRM_MODE_REFLECT_Y) + +/* Content Protection Flags */ +#define DRM_MODE_CONTENT_PROTECTION_UNDESIRED 0 +#define DRM_MODE_CONTENT_PROTECTION_DESIRED 1 +#define DRM_MODE_CONTENT_PROTECTION_ENABLED 2 + +/** + * struct drm_mode_modeinfo - Display mode information. + * @clock: pixel clock in kHz + * @hdisplay: horizontal display size + * @hsync_start: horizontal sync start + * @hsync_end: horizontal sync end + * @htotal: horizontal total size + * @hskew: horizontal skew + * @vdisplay: vertical display size + * @vsync_start: vertical sync start + * @vsync_end: vertical sync end + * @vtotal: vertical total size + * @vscan: vertical scan + * @vrefresh: approximate vertical refresh rate in Hz + * @flags: bitmask of misc. flags, see DRM_MODE_FLAG_* defines + * @type: bitmask of type flags, see DRM_MODE_TYPE_* defines + * @name: string describing the mode resolution + * + * This is the user-space API display mode information structure. For the + * kernel version see struct drm_display_mode. + */ +struct drm_mode_modeinfo { + __u32 clock; + __u16 hdisplay; + __u16 hsync_start; + __u16 hsync_end; + __u16 htotal; + __u16 hskew; + __u16 vdisplay; + __u16 vsync_start; + __u16 vsync_end; + __u16 vtotal; + __u16 vscan; + + __u32 vrefresh; + + __u32 flags; + __u32 type; + char name[DRM_DISPLAY_MODE_LEN]; +}; + +struct drm_mode_card_res { + __u64 fb_id_ptr; + __u64 crtc_id_ptr; + __u64 connector_id_ptr; + __u64 encoder_id_ptr; + __u32 count_fbs; + __u32 count_crtcs; + __u32 count_connectors; + __u32 count_encoders; + __u32 min_width; + __u32 max_width; + __u32 min_height; + __u32 max_height; +}; + +struct drm_mode_crtc { + __u64 set_connectors_ptr; + __u32 count_connectors; + + __u32 crtc_id; /**< Id */ + __u32 fb_id; /**< Id of framebuffer */ + + __u32 x; /**< x Position on the framebuffer */ + __u32 y; /**< y Position on the framebuffer */ + + __u32 gamma_size; + __u32 mode_valid; + struct drm_mode_modeinfo mode; +}; + +#define DRM_MODE_PRESENT_TOP_FIELD (1<<0) +#define DRM_MODE_PRESENT_BOTTOM_FIELD (1<<1) + +/* Planes blend with or override other bits on the CRTC */ +struct drm_mode_set_plane { + __u32 plane_id; + __u32 crtc_id; + __u32 fb_id; /* fb object contains surface format type */ + __u32 flags; /* see above flags */ + + /* Signed dest location allows it to be partially off screen */ + __s32 crtc_x; + __s32 crtc_y; + __u32 crtc_w; + __u32 crtc_h; + + /* Source values are 16.16 fixed point */ + __u32 src_x; + __u32 src_y; + __u32 src_h; + __u32 src_w; +}; + +struct drm_mode_get_plane { + __u32 plane_id; + + __u32 crtc_id; + __u32 fb_id; + + __u32 possible_crtcs; + __u32 gamma_size; + + __u32 count_format_types; + __u64 format_type_ptr; +}; + +struct drm_mode_get_plane_res { + __u64 plane_id_ptr; + __u32 count_planes; +}; + +#define DRM_MODE_ENCODER_NONE 0 +#define DRM_MODE_ENCODER_DAC 1 +#define DRM_MODE_ENCODER_TMDS 2 +#define DRM_MODE_ENCODER_LVDS 3 +#define DRM_MODE_ENCODER_TVDAC 4 +#define DRM_MODE_ENCODER_VIRTUAL 5 +#define DRM_MODE_ENCODER_DSI 6 +#define DRM_MODE_ENCODER_DPMST 7 +#define DRM_MODE_ENCODER_DPI 8 + +struct drm_mode_get_encoder { + __u32 encoder_id; + __u32 encoder_type; + + __u32 crtc_id; /**< Id of crtc */ + + __u32 possible_crtcs; + __u32 possible_clones; +}; + +/* This is for connectors with multiple signal types. */ +/* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */ +enum drm_mode_subconnector { + DRM_MODE_SUBCONNECTOR_Automatic = 0, /* DVI-I, TV */ + DRM_MODE_SUBCONNECTOR_Unknown = 0, /* DVI-I, TV, DP */ + DRM_MODE_SUBCONNECTOR_VGA = 1, /* DP */ + DRM_MODE_SUBCONNECTOR_DVID = 3, /* DVI-I DP */ + DRM_MODE_SUBCONNECTOR_DVIA = 4, /* DVI-I */ + DRM_MODE_SUBCONNECTOR_Composite = 5, /* TV */ + DRM_MODE_SUBCONNECTOR_SVIDEO = 6, /* TV */ + DRM_MODE_SUBCONNECTOR_Component = 8, /* TV */ + DRM_MODE_SUBCONNECTOR_SCART = 9, /* TV */ + DRM_MODE_SUBCONNECTOR_DisplayPort = 10, /* DP */ + DRM_MODE_SUBCONNECTOR_HDMIA = 11, /* DP */ + DRM_MODE_SUBCONNECTOR_Native = 15, /* DP */ + DRM_MODE_SUBCONNECTOR_Wireless = 18, /* DP */ +}; + +#define DRM_MODE_CONNECTOR_Unknown 0 +#define DRM_MODE_CONNECTOR_VGA 1 +#define DRM_MODE_CONNECTOR_DVII 2 +#define DRM_MODE_CONNECTOR_DVID 3 +#define DRM_MODE_CONNECTOR_DVIA 4 +#define DRM_MODE_CONNECTOR_Composite 5 +#define DRM_MODE_CONNECTOR_SVIDEO 6 +#define DRM_MODE_CONNECTOR_LVDS 7 +#define DRM_MODE_CONNECTOR_Component 8 +#define DRM_MODE_CONNECTOR_9PinDIN 9 +#define DRM_MODE_CONNECTOR_DisplayPort 10 +#define DRM_MODE_CONNECTOR_HDMIA 11 +#define DRM_MODE_CONNECTOR_HDMIB 12 +#define DRM_MODE_CONNECTOR_TV 13 +#define DRM_MODE_CONNECTOR_eDP 14 +#define DRM_MODE_CONNECTOR_VIRTUAL 15 +#define DRM_MODE_CONNECTOR_DSI 16 +#define DRM_MODE_CONNECTOR_DPI 17 +#define DRM_MODE_CONNECTOR_WRITEBACK 18 +#define DRM_MODE_CONNECTOR_SPI 19 +#define DRM_MODE_CONNECTOR_USB 20 + +/** + * struct drm_mode_get_connector - Get connector metadata. + * + * User-space can perform a GETCONNECTOR ioctl to retrieve information about a + * connector. User-space is expected to retrieve encoders, modes and properties + * by performing this ioctl at least twice: the first time to retrieve the + * number of elements, the second time to retrieve the elements themselves. + * + * To retrieve the number of elements, set @count_props and @count_encoders to + * zero, set @count_modes to 1, and set @modes_ptr to a temporary struct + * drm_mode_modeinfo element. + * + * To retrieve the elements, allocate arrays for @encoders_ptr, @modes_ptr, + * @props_ptr and @prop_values_ptr, then set @count_modes, @count_props and + * @count_encoders to their capacity. + * + * Performing the ioctl only twice may be racy: the number of elements may have + * changed with a hotplug event in-between the two ioctls. User-space is + * expected to retry the last ioctl until the number of elements stabilizes. + * The kernel won't fill any array which doesn't have the expected length. + * + * **Force-probing a connector** + * + * If the @count_modes field is set to zero and the DRM client is the current + * DRM master, the kernel will perform a forced probe on the connector to + * refresh the connector status, modes and EDID. A forced-probe can be slow, + * might cause flickering and the ioctl will block. + * + * User-space needs to force-probe connectors to ensure their metadata is + * up-to-date at startup and after receiving a hot-plug event. User-space + * may perform a forced-probe when the user explicitly requests it. User-space + * shouldn't perform a forced-probe in other situations. + */ +struct drm_mode_get_connector { + /** @encoders_ptr: Pointer to ``__u32`` array of object IDs. */ + __u64 encoders_ptr; + /** @modes_ptr: Pointer to struct drm_mode_modeinfo array. */ + __u64 modes_ptr; + /** @props_ptr: Pointer to ``__u32`` array of property IDs. */ + __u64 props_ptr; + /** @prop_values_ptr: Pointer to ``__u64`` array of property values. */ + __u64 prop_values_ptr; + + /** @count_modes: Number of modes. */ + __u32 count_modes; + /** @count_props: Number of properties. */ + __u32 count_props; + /** @count_encoders: Number of encoders. */ + __u32 count_encoders; + + /** @encoder_id: Object ID of the current encoder. */ + __u32 encoder_id; + /** @connector_id: Object ID of the connector. */ + __u32 connector_id; + /** + * @connector_type: Type of the connector. + * + * See DRM_MODE_CONNECTOR_* defines. + */ + __u32 connector_type; + /** + * @connector_type_id: Type-specific connector number. + * + * This is not an object ID. This is a per-type connector number. Each + * (type, type_id) combination is unique across all connectors of a DRM + * device. + */ + __u32 connector_type_id; + + /** + * @connection: Status of the connector. + * + * See enum drm_connector_status. + */ + __u32 connection; + /** @mm_width: Width of the connected sink in millimeters. */ + __u32 mm_width; + /** @mm_height: Height of the connected sink in millimeters. */ + __u32 mm_height; + /** + * @subpixel: Subpixel order of the connected sink. + * + * See enum subpixel_order. + */ + __u32 subpixel; + + /** @pad: Padding, must be zero. */ + __u32 pad; +}; + +#define DRM_MODE_PROP_PENDING (1<<0) /* deprecated, do not use */ +#define DRM_MODE_PROP_RANGE (1<<1) +#define DRM_MODE_PROP_IMMUTABLE (1<<2) +#define DRM_MODE_PROP_ENUM (1<<3) /* enumerated type with text strings */ +#define DRM_MODE_PROP_BLOB (1<<4) +#define DRM_MODE_PROP_BITMASK (1<<5) /* bitmask of enumerated types */ + +/* non-extended types: legacy bitmask, one bit per type: */ +#define DRM_MODE_PROP_LEGACY_TYPE ( \ + DRM_MODE_PROP_RANGE | \ + DRM_MODE_PROP_ENUM | \ + DRM_MODE_PROP_BLOB | \ + DRM_MODE_PROP_BITMASK) + +/* extended-types: rather than continue to consume a bit per type, + * grab a chunk of the bits to use as integer type id. + */ +#define DRM_MODE_PROP_EXTENDED_TYPE 0x0000ffc0 +#define DRM_MODE_PROP_TYPE(n) ((n) << 6) +#define DRM_MODE_PROP_OBJECT DRM_MODE_PROP_TYPE(1) +#define DRM_MODE_PROP_SIGNED_RANGE DRM_MODE_PROP_TYPE(2) + +/* the PROP_ATOMIC flag is used to hide properties from userspace that + * is not aware of atomic properties. This is mostly to work around + * older userspace (DDX drivers) that read/write each prop they find, + * witout being aware that this could be triggering a lengthy modeset. + */ +#define DRM_MODE_PROP_ATOMIC 0x80000000 + +struct drm_mode_property_enum { + __u64 value; + char name[DRM_PROP_NAME_LEN]; +}; + +struct drm_mode_get_property { + __u64 values_ptr; /* values and blob lengths */ + __u64 enum_blob_ptr; /* enum and blob id ptrs */ + + __u32 prop_id; + __u32 flags; + char name[DRM_PROP_NAME_LEN]; + + __u32 count_values; + /* This is only used to count enum values, not blobs. The _blobs is + * simply because of a historical reason, i.e. backwards compat. */ + __u32 count_enum_blobs; +}; + +struct drm_mode_connector_set_property { + __u64 value; + __u32 prop_id; + __u32 connector_id; +}; + +#define DRM_MODE_OBJECT_CRTC 0xcccccccc +#define DRM_MODE_OBJECT_CONNECTOR 0xc0c0c0c0 +#define DRM_MODE_OBJECT_ENCODER 0xe0e0e0e0 +#define DRM_MODE_OBJECT_MODE 0xdededede +#define DRM_MODE_OBJECT_PROPERTY 0xb0b0b0b0 +#define DRM_MODE_OBJECT_FB 0xfbfbfbfb +#define DRM_MODE_OBJECT_BLOB 0xbbbbbbbb +#define DRM_MODE_OBJECT_PLANE 0xeeeeeeee +#define DRM_MODE_OBJECT_ANY 0 + +struct drm_mode_obj_get_properties { + __u64 props_ptr; + __u64 prop_values_ptr; + __u32 count_props; + __u32 obj_id; + __u32 obj_type; +}; + +struct drm_mode_obj_set_property { + __u64 value; + __u32 prop_id; + __u32 obj_id; + __u32 obj_type; +}; + +struct drm_mode_get_blob { + __u32 blob_id; + __u32 length; + __u64 data; +}; + +struct drm_mode_fb_cmd { + __u32 fb_id; + __u32 width; + __u32 height; + __u32 pitch; + __u32 bpp; + __u32 depth; + /* driver specific handle */ + __u32 handle; +}; + +#define DRM_MODE_FB_INTERLACED (1<<0) /* for interlaced framebuffers */ +#define DRM_MODE_FB_MODIFIERS (1<<1) /* enables ->modifer[] */ + +struct drm_mode_fb_cmd2 { + __u32 fb_id; + __u32 width; + __u32 height; + __u32 pixel_format; /* fourcc code from drm_fourcc.h */ + __u32 flags; /* see above flags */ + + /* + * In case of planar formats, this ioctl allows up to 4 + * buffer objects with offsets and pitches per plane. + * The pitch and offset order is dictated by the fourcc, + * e.g. NV12 (https://fourcc.org/yuv.php#NV12) is described as: + * + * YUV 4:2:0 image with a plane of 8 bit Y samples + * followed by an interleaved U/V plane containing + * 8 bit 2x2 subsampled colour difference samples. + * + * So it would consist of Y as offsets[0] and UV as + * offsets[1]. Note that offsets[0] will generally + * be 0 (but this is not required). + * + * To accommodate tiled, compressed, etc formats, a + * modifier can be specified. The default value of zero + * indicates "native" format as specified by the fourcc. + * Vendor specific modifier token. Note that even though + * it looks like we have a modifier per-plane, we in fact + * do not. The modifier for each plane must be identical. + * Thus all combinations of different data layouts for + * multi plane formats must be enumerated as separate + * modifiers. + */ + __u32 handles[4]; + __u32 pitches[4]; /* pitch for each plane */ + __u32 offsets[4]; /* offset of each plane */ + __u64 modifier[4]; /* ie, tiling, compress */ +}; + +#define DRM_MODE_FB_DIRTY_ANNOTATE_COPY 0x01 +#define DRM_MODE_FB_DIRTY_ANNOTATE_FILL 0x02 +#define DRM_MODE_FB_DIRTY_FLAGS 0x03 + +#define DRM_MODE_FB_DIRTY_MAX_CLIPS 256 + +/* + * Mark a region of a framebuffer as dirty. + * + * Some hardware does not automatically update display contents + * as a hardware or software draw to a framebuffer. This ioctl + * allows userspace to tell the kernel and the hardware what + * regions of the framebuffer have changed. + * + * The kernel or hardware is free to update more then just the + * region specified by the clip rects. The kernel or hardware + * may also delay and/or coalesce several calls to dirty into a + * single update. + * + * Userspace may annotate the updates, the annotates are a + * promise made by the caller that the change is either a copy + * of pixels or a fill of a single color in the region specified. + * + * If the DRM_MODE_FB_DIRTY_ANNOTATE_COPY flag is given then + * the number of updated regions are half of num_clips given, + * where the clip rects are paired in src and dst. The width and + * height of each one of the pairs must match. + * + * If the DRM_MODE_FB_DIRTY_ANNOTATE_FILL flag is given the caller + * promises that the region specified of the clip rects is filled + * completely with a single color as given in the color argument. + */ + +struct drm_mode_fb_dirty_cmd { + __u32 fb_id; + __u32 flags; + __u32 color; + __u32 num_clips; + __u64 clips_ptr; +}; + +struct drm_mode_mode_cmd { + __u32 connector_id; + struct drm_mode_modeinfo mode; +}; + +#define DRM_MODE_CURSOR_BO 0x01 +#define DRM_MODE_CURSOR_MOVE 0x02 +#define DRM_MODE_CURSOR_FLAGS 0x03 + +/* + * depending on the value in flags different members are used. + * + * CURSOR_BO uses + * crtc_id + * width + * height + * handle - if 0 turns the cursor off + * + * CURSOR_MOVE uses + * crtc_id + * x + * y + */ +struct drm_mode_cursor { + __u32 flags; + __u32 crtc_id; + __s32 x; + __s32 y; + __u32 width; + __u32 height; + /* driver specific handle */ + __u32 handle; +}; + +struct drm_mode_cursor2 { + __u32 flags; + __u32 crtc_id; + __s32 x; + __s32 y; + __u32 width; + __u32 height; + /* driver specific handle */ + __u32 handle; + __s32 hot_x; + __s32 hot_y; +}; + +struct drm_mode_crtc_lut { + __u32 crtc_id; + __u32 gamma_size; + + /* pointers to arrays */ + __u64 red; + __u64 green; + __u64 blue; +}; + +struct drm_color_ctm { + /* + * Conversion matrix in S31.32 sign-magnitude + * (not two's complement!) format. + */ + __u64 matrix[9]; +}; + +struct drm_color_lut { + /* + * Values are mapped linearly to 0.0 - 1.0 range, with 0x0 == 0.0 and + * 0xffff == 1.0. + */ + __u16 red; + __u16 green; + __u16 blue; + __u16 reserved; +}; + +/** + * struct hdr_metadata_infoframe - HDR Metadata Infoframe Data. + * + * HDR Metadata Infoframe as per CTA 861.G spec. This is expected + * to match exactly with the spec. + * + * Userspace is expected to pass the metadata information as per + * the format described in this structure. + */ +struct hdr_metadata_infoframe { + /** + * @eotf: Electro-Optical Transfer Function (EOTF) + * used in the stream. + */ + __u8 eotf; + /** + * @metadata_type: Static_Metadata_Descriptor_ID. + */ + __u8 metadata_type; + /** + * @display_primaries: Color Primaries of the Data. + * These are coded as unsigned 16-bit values in units of + * 0.00002, where 0x0000 represents zero and 0xC350 + * represents 1.0000. + * @display_primaries.x: X cordinate of color primary. + * @display_primaries.y: Y cordinate of color primary. + */ + struct { + __u16 x, y; + } display_primaries[3]; + /** + * @white_point: White Point of Colorspace Data. + * These are coded as unsigned 16-bit values in units of + * 0.00002, where 0x0000 represents zero and 0xC350 + * represents 1.0000. + * @white_point.x: X cordinate of whitepoint of color primary. + * @white_point.y: Y cordinate of whitepoint of color primary. + */ + struct { + __u16 x, y; + } white_point; + /** + * @max_display_mastering_luminance: Max Mastering Display Luminance. + * This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + * where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + */ + __u16 max_display_mastering_luminance; + /** + * @min_display_mastering_luminance: Min Mastering Display Luminance. + * This value is coded as an unsigned 16-bit value in units of + * 0.0001 cd/m2, where 0x0001 represents 0.0001 cd/m2 and 0xFFFF + * represents 6.5535 cd/m2. + */ + __u16 min_display_mastering_luminance; + /** + * @max_cll: Max Content Light Level. + * This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + * where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + */ + __u16 max_cll; + /** + * @max_fall: Max Frame Average Light Level. + * This value is coded as an unsigned 16-bit value in units of 1 cd/m2, + * where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2. + */ + __u16 max_fall; +}; + +/** + * struct hdr_output_metadata - HDR output metadata + * + * Metadata Information to be passed from userspace + */ +struct hdr_output_metadata { + /** + * @metadata_type: Static_Metadata_Descriptor_ID. + */ + __u32 metadata_type; + /** + * @hdmi_metadata_type1: HDR Metadata Infoframe. + */ + union { + struct hdr_metadata_infoframe hdmi_metadata_type1; + }; +}; + +#define DRM_MODE_PAGE_FLIP_EVENT 0x01 +#define DRM_MODE_PAGE_FLIP_ASYNC 0x02 +#define DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE 0x4 +#define DRM_MODE_PAGE_FLIP_TARGET_RELATIVE 0x8 +#define DRM_MODE_PAGE_FLIP_TARGET (DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE | \ + DRM_MODE_PAGE_FLIP_TARGET_RELATIVE) +#define DRM_MODE_PAGE_FLIP_FLAGS (DRM_MODE_PAGE_FLIP_EVENT | \ + DRM_MODE_PAGE_FLIP_ASYNC | \ + DRM_MODE_PAGE_FLIP_TARGET) + +/* + * Request a page flip on the specified crtc. + * + * This ioctl will ask KMS to schedule a page flip for the specified + * crtc. Once any pending rendering targeting the specified fb (as of + * ioctl time) has completed, the crtc will be reprogrammed to display + * that fb after the next vertical refresh. The ioctl returns + * immediately, but subsequent rendering to the current fb will block + * in the execbuffer ioctl until the page flip happens. If a page + * flip is already pending as the ioctl is called, EBUSY will be + * returned. + * + * Flag DRM_MODE_PAGE_FLIP_EVENT requests that drm sends back a vblank + * event (see drm.h: struct drm_event_vblank) when the page flip is + * done. The user_data field passed in with this ioctl will be + * returned as the user_data field in the vblank event struct. + * + * Flag DRM_MODE_PAGE_FLIP_ASYNC requests that the flip happen + * 'as soon as possible', meaning that it not delay waiting for vblank. + * This may cause tearing on the screen. + * + * The reserved field must be zero. + */ + +struct drm_mode_crtc_page_flip { + __u32 crtc_id; + __u32 fb_id; + __u32 flags; + __u32 reserved; + __u64 user_data; +}; + +/* + * Request a page flip on the specified crtc. + * + * Same as struct drm_mode_crtc_page_flip, but supports new flags and + * re-purposes the reserved field: + * + * The sequence field must be zero unless either of the + * DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags is specified. When + * the ABSOLUTE flag is specified, the sequence field denotes the absolute + * vblank sequence when the flip should take effect. When the RELATIVE + * flag is specified, the sequence field denotes the relative (to the + * current one when the ioctl is called) vblank sequence when the flip + * should take effect. NOTE: DRM_IOCTL_WAIT_VBLANK must still be used to + * make sure the vblank sequence before the target one has passed before + * calling this ioctl. The purpose of the + * DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags is merely to clarify + * the target for when code dealing with a page flip runs during a + * vertical blank period. + */ + +struct drm_mode_crtc_page_flip_target { + __u32 crtc_id; + __u32 fb_id; + __u32 flags; + __u32 sequence; + __u64 user_data; +}; + +/* create a dumb scanout buffer */ +struct drm_mode_create_dumb { + __u32 height; + __u32 width; + __u32 bpp; + __u32 flags; + /* handle, pitch, size will be returned */ + __u32 handle; + __u32 pitch; + __u64 size; +}; + +/* set up for mmap of a dumb scanout buffer */ +struct drm_mode_map_dumb { + /** Handle for the object being mapped. */ + __u32 handle; + __u32 pad; + /** + * Fake offset to use for subsequent mmap call + * + * This is a fixed-size type for 32/64 compatibility. + */ + __u64 offset; +}; + +struct drm_mode_destroy_dumb { + __u32 handle; +}; + +/* page-flip flags are valid, plus: */ +#define DRM_MODE_ATOMIC_TEST_ONLY 0x0100 +#define DRM_MODE_ATOMIC_NONBLOCK 0x0200 +#define DRM_MODE_ATOMIC_ALLOW_MODESET 0x0400 + +#define DRM_MODE_ATOMIC_FLAGS (\ + DRM_MODE_PAGE_FLIP_EVENT |\ + DRM_MODE_PAGE_FLIP_ASYNC |\ + DRM_MODE_ATOMIC_TEST_ONLY |\ + DRM_MODE_ATOMIC_NONBLOCK |\ + DRM_MODE_ATOMIC_ALLOW_MODESET) + +struct drm_mode_atomic { + __u32 flags; + __u32 count_objs; + __u64 objs_ptr; + __u64 count_props_ptr; + __u64 props_ptr; + __u64 prop_values_ptr; + __u64 reserved; + __u64 user_data; +}; + +struct drm_format_modifier_blob { +#define FORMAT_BLOB_CURRENT 1 + /* Version of this blob format */ + __u32 version; + + /* Flags */ + __u32 flags; + + /* Number of fourcc formats supported */ + __u32 count_formats; + + /* Where in this blob the formats exist (in bytes) */ + __u32 formats_offset; + + /* Number of drm_format_modifiers */ + __u32 count_modifiers; + + /* Where in this blob the modifiers exist (in bytes) */ + __u32 modifiers_offset; + + /* __u32 formats[] */ + /* struct drm_format_modifier modifiers[] */ +}; + +struct drm_format_modifier { + /* Bitmask of formats in get_plane format list this info applies to. The + * offset allows a sliding window of which 64 formats (bits). + * + * Some examples: + * In today's world with < 65 formats, and formats 0, and 2 are + * supported + * 0x0000000000000005 + * ^-offset = 0, formats = 5 + * + * If the number formats grew to 128, and formats 98-102 are + * supported with the modifier: + * + * 0x0000007c00000000 0000000000000000 + * ^ + * |__offset = 64, formats = 0x7c00000000 + * + */ + __u64 formats; + __u32 offset; + __u32 pad; + + /* The modifier that applies to the >get_plane format list bitmask. */ + __u64 modifier; +}; + +/** + * struct drm_mode_create_blob - Create New blob property + * + * Create a new 'blob' data property, copying length bytes from data pointer, + * and returning new blob ID. + */ +struct drm_mode_create_blob { + /** @data: Pointer to data to copy. */ + __u64 data; + /** @length: Length of data to copy. */ + __u32 length; + /** @blob_id: Return: new property ID. */ + __u32 blob_id; +}; + +/** + * struct drm_mode_destroy_blob - Destroy user blob + * @blob_id: blob_id to destroy + * + * Destroy a user-created blob property. + * + * User-space can release blobs as soon as they do not need to refer to them by + * their blob object ID. For instance, if you are using a MODE_ID blob in an + * atomic commit and you will not make another commit re-using the same ID, you + * can destroy the blob as soon as the commit has been issued, without waiting + * for it to complete. + */ +struct drm_mode_destroy_blob { + __u32 blob_id; +}; + +/** + * struct drm_mode_create_lease - Create lease + * + * Lease mode resources, creating another drm_master. + */ +struct drm_mode_create_lease { + /** @object_ids: Pointer to array of object ids (__u32) */ + __u64 object_ids; + /** @object_count: Number of object ids */ + __u32 object_count; + /** @flags: flags for new FD (O_CLOEXEC, etc) */ + __u32 flags; + + /** @lessee_id: Return: unique identifier for lessee. */ + __u32 lessee_id; + /** @fd: Return: file descriptor to new drm_master file */ + __u32 fd; +}; + +/** + * struct drm_mode_list_lessees - List lessees + * + * List lesses from a drm_master. + */ +struct drm_mode_list_lessees { + /** + * @count_lessees: Number of lessees. + * + * On input, provides length of the array. + * On output, provides total number. No + * more than the input number will be written + * back, so two calls can be used to get + * the size and then the data. + */ + __u32 count_lessees; + /** @pad: Padding. */ + __u32 pad; + + /** + * @lessees_ptr: Pointer to lessees. + * + * Pointer to __u64 array of lessee ids + */ + __u64 lessees_ptr; +}; + +/** + * struct drm_mode_get_lease - Get Lease + * + * Get leased objects. + */ +struct drm_mode_get_lease { + /** + * @count_objects: Number of leased objects. + * + * On input, provides length of the array. + * On output, provides total number. No + * more than the input number will be written + * back, so two calls can be used to get + * the size and then the data. + */ + __u32 count_objects; + /** @pad: Padding. */ + __u32 pad; + + /** + * @objects_ptr: Pointer to objects. + * + * Pointer to __u32 array of object ids. + */ + __u64 objects_ptr; +}; + +/** + * struct drm_mode_revoke_lease - Revoke lease + */ +struct drm_mode_revoke_lease { + /** @lessee_id: Unique ID of lessee */ + __u32 lessee_id; +}; + +/** + * struct drm_mode_rect - Two dimensional rectangle. + * @x1: Horizontal starting coordinate (inclusive). + * @y1: Vertical starting coordinate (inclusive). + * @x2: Horizontal ending coordinate (exclusive). + * @y2: Vertical ending coordinate (exclusive). + * + * With drm subsystem using struct drm_rect to manage rectangular area this + * export it to user-space. + * + * Currently used by drm_mode_atomic blob property FB_DAMAGE_CLIPS. + */ +struct drm_mode_rect { + __s32 x1; + __s32 y1; + __s32 x2; + __s32 y2; +}; + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/include/drm/drm_sarea.h b/include/drm/drm_sarea.h new file mode 100644 index 0000000..93025be --- /dev/null +++ b/include/drm/drm_sarea.h @@ -0,0 +1,92 @@ +/** + * \file drm_sarea.h + * \brief SAREA definitions + * + * \author Michel Dänzer + */ + +/* + * Copyright 2002 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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, 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * TUNGSTEN GRAPHICS 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 _DRM_SAREA_H_ +#define _DRM_SAREA_H_ + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/* SAREA area needs to be at least a page */ +#if defined(__alpha__) +#define SAREA_MAX 0x2000U +#elif defined(__mips__) +#define SAREA_MAX 0x4000U +#elif defined(__ia64__) +#define SAREA_MAX 0x10000U /* 64kB */ +#else +/* Intel 830M driver needs at least 8k SAREA */ +#define SAREA_MAX 0x2000U +#endif + +/** Maximum number of drawables in the SAREA */ +#define SAREA_MAX_DRAWABLES 256 + +#define SAREA_DRAWABLE_CLAIMED_ENTRY 0x80000000 + +/** SAREA drawable */ +struct drm_sarea_drawable { + unsigned int stamp; + unsigned int flags; +}; + +/** SAREA frame */ +struct drm_sarea_frame { + unsigned int x; + unsigned int y; + unsigned int width; + unsigned int height; + unsigned int fullscreen; +}; + +/** SAREA */ +struct drm_sarea { + /** first thing is always the DRM locking structure */ + struct drm_hw_lock lock; + /** \todo Use readers/writer lock for drm_sarea::drawable_lock */ + struct drm_hw_lock drawable_lock; + struct drm_sarea_drawable drawableTable[SAREA_MAX_DRAWABLES]; /**< drawables */ + struct drm_sarea_frame frame; /**< frame */ + drm_context_t dummy_context; +}; + +typedef struct drm_sarea_drawable drm_sarea_drawable_t; +typedef struct drm_sarea_frame drm_sarea_frame_t; +typedef struct drm_sarea drm_sarea_t; + +#if defined(__cplusplus) +} +#endif + +#endif /* _DRM_SAREA_H_ */ diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h new file mode 100644 index 0000000..1de0433 --- /dev/null +++ b/include/drm/i915_drm.h @@ -0,0 +1,3724 @@ +/* + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 TUNGSTEN GRAPHICS 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 _I915_DRM_H_ +#define _I915_DRM_H_ + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Please note that modifications to all structs defined here are + * subject to backwards-compatibility constraints. + */ + +/** + * DOC: uevents generated by i915 on it's device node + * + * I915_L3_PARITY_UEVENT - Generated when the driver receives a parity mismatch + * event from the gpu l3 cache. Additional information supplied is ROW, + * BANK, SUBBANK, SLICE of the affected cacheline. Userspace should keep + * track of these events and if a specific cache-line seems to have a + * persistent error remap it with the l3 remapping tool supplied in + * intel-gpu-tools. The value supplied with the event is always 1. + * + * I915_ERROR_UEVENT - Generated upon error detection, currently only via + * hangcheck. The error detection event is a good indicator of when things + * began to go badly. The value supplied with the event is a 1 upon error + * detection, and a 0 upon reset completion, signifying no more error + * exists. NOTE: Disabling hangcheck or reset via module parameter will + * cause the related events to not be seen. + * + * I915_RESET_UEVENT - Event is generated just before an attempt to reset the + * GPU. The value supplied with the event is always 1. NOTE: Disable + * reset via module parameter will cause this event to not be seen. + */ +#define I915_L3_PARITY_UEVENT "L3_PARITY_ERROR" +#define I915_ERROR_UEVENT "ERROR" +#define I915_RESET_UEVENT "RESET" + +/** + * struct i915_user_extension - Base class for defining a chain of extensions + * + * Many interfaces need to grow over time. In most cases we can simply + * extend the struct and have userspace pass in more data. Another option, + * as demonstrated by Vulkan's approach to providing extensions for forward + * and backward compatibility, is to use a list of optional structs to + * provide those extra details. + * + * The key advantage to using an extension chain is that it allows us to + * redefine the interface more easily than an ever growing struct of + * increasing complexity, and for large parts of that interface to be + * entirely optional. The downside is more pointer chasing; chasing across + * the boundary with pointers encapsulated inside u64. + * + * Example chaining: + * + * .. code-block:: C + * + * struct i915_user_extension ext3 { + * .next_extension = 0, // end + * .name = ..., + * }; + * struct i915_user_extension ext2 { + * .next_extension = (uintptr_t)&ext3, + * .name = ..., + * }; + * struct i915_user_extension ext1 { + * .next_extension = (uintptr_t)&ext2, + * .name = ..., + * }; + * + * Typically the struct i915_user_extension would be embedded in some uAPI + * struct, and in this case we would feed it the head of the chain(i.e ext1), + * which would then apply all of the above extensions. + * + */ +struct i915_user_extension { + /** + * @next_extension: + * + * Pointer to the next struct i915_user_extension, or zero if the end. + */ + __u64 next_extension; + /** + * @name: Name of the extension. + * + * Note that the name here is just some integer. + * + * Also note that the name space for this is not global for the whole + * driver, but rather its scope/meaning is limited to the specific piece + * of uAPI which has embedded the struct i915_user_extension. + */ + __u32 name; + /** + * @flags: MBZ + * + * All undefined bits must be zero. + */ + __u32 flags; + /** + * @rsvd: MBZ + * + * Reserved for future use; must be zero. + */ + __u32 rsvd[4]; +}; + +/* + * MOCS indexes used for GPU surfaces, defining the cacheability of the + * surface data and the coherency for this data wrt. CPU vs. GPU accesses. + */ +enum i915_mocs_table_index { + /* + * Not cached anywhere, coherency between CPU and GPU accesses is + * guaranteed. + */ + I915_MOCS_UNCACHED, + /* + * Cacheability and coherency controlled by the kernel automatically + * based on the DRM_I915_GEM_SET_CACHING IOCTL setting and the current + * usage of the surface (used for display scanout or not). + */ + I915_MOCS_PTE, + /* + * Cached in all GPU caches available on the platform. + * Coherency between CPU and GPU accesses to the surface is not + * guaranteed without extra synchronization. + */ + I915_MOCS_CACHED, +}; + +/** + * enum drm_i915_gem_engine_class - uapi engine type enumeration + * + * Different engines serve different roles, and there may be more than one + * engine serving each role. This enum provides a classification of the role + * of the engine, which may be used when requesting operations to be performed + * on a certain subset of engines, or for providing information about that + * group. + */ +enum drm_i915_gem_engine_class { + /** + * @I915_ENGINE_CLASS_RENDER: + * + * Render engines support instructions used for 3D, Compute (GPGPU), + * and programmable media workloads. These instructions fetch data and + * dispatch individual work items to threads that operate in parallel. + * The threads run small programs (called "kernels" or "shaders") on + * the GPU's execution units (EUs). + */ + I915_ENGINE_CLASS_RENDER = 0, + + /** + * @I915_ENGINE_CLASS_COPY: + * + * Copy engines (also referred to as "blitters") support instructions + * that move blocks of data from one location in memory to another, + * or that fill a specified location of memory with fixed data. + * Copy engines can perform pre-defined logical or bitwise operations + * on the source, destination, or pattern data. + */ + I915_ENGINE_CLASS_COPY = 1, + + /** + * @I915_ENGINE_CLASS_VIDEO: + * + * Video engines (also referred to as "bit stream decode" (BSD) or + * "vdbox") support instructions that perform fixed-function media + * decode and encode. + */ + I915_ENGINE_CLASS_VIDEO = 2, + + /** + * @I915_ENGINE_CLASS_VIDEO_ENHANCE: + * + * Video enhancement engines (also referred to as "vebox") support + * instructions related to image enhancement. + */ + I915_ENGINE_CLASS_VIDEO_ENHANCE = 3, + + /** + * @I915_ENGINE_CLASS_COMPUTE: + * + * Compute engines support a subset of the instructions available + * on render engines: compute engines support Compute (GPGPU) and + * programmable media workloads, but do not support the 3D pipeline. + */ + I915_ENGINE_CLASS_COMPUTE = 4, + + /* Values in this enum should be kept compact. */ + + /** + * @I915_ENGINE_CLASS_INVALID: + * + * Placeholder value to represent an invalid engine class assignment. + */ + I915_ENGINE_CLASS_INVALID = -1 +}; + +/** + * struct i915_engine_class_instance - Engine class/instance identifier + * + * There may be more than one engine fulfilling any role within the system. + * Each engine of a class is given a unique instance number and therefore + * any engine can be specified by its class:instance tuplet. APIs that allow + * access to any engine in the system will use struct i915_engine_class_instance + * for this identification. + */ +struct i915_engine_class_instance { + /** + * @engine_class: + * + * Engine class from enum drm_i915_gem_engine_class + */ + __u16 engine_class; +#define I915_ENGINE_CLASS_INVALID_NONE -1 +#define I915_ENGINE_CLASS_INVALID_VIRTUAL -2 + + /** + * @engine_instance: + * + * Engine instance. + */ + __u16 engine_instance; +}; + +/** + * DOC: perf_events exposed by i915 through /sys/bus/event_sources/drivers/i915 + * + */ + +enum drm_i915_pmu_engine_sample { + I915_SAMPLE_BUSY = 0, + I915_SAMPLE_WAIT = 1, + I915_SAMPLE_SEMA = 2 +}; + +#define I915_PMU_SAMPLE_BITS (4) +#define I915_PMU_SAMPLE_MASK (0xf) +#define I915_PMU_SAMPLE_INSTANCE_BITS (8) +#define I915_PMU_CLASS_SHIFT \ + (I915_PMU_SAMPLE_BITS + I915_PMU_SAMPLE_INSTANCE_BITS) + +#define __I915_PMU_ENGINE(class, instance, sample) \ + ((class) << I915_PMU_CLASS_SHIFT | \ + (instance) << I915_PMU_SAMPLE_BITS | \ + (sample)) + +#define I915_PMU_ENGINE_BUSY(class, instance) \ + __I915_PMU_ENGINE(class, instance, I915_SAMPLE_BUSY) + +#define I915_PMU_ENGINE_WAIT(class, instance) \ + __I915_PMU_ENGINE(class, instance, I915_SAMPLE_WAIT) + +#define I915_PMU_ENGINE_SEMA(class, instance) \ + __I915_PMU_ENGINE(class, instance, I915_SAMPLE_SEMA) + +#define __I915_PMU_OTHER(x) (__I915_PMU_ENGINE(0xff, 0xff, 0xf) + 1 + (x)) + +#define I915_PMU_ACTUAL_FREQUENCY __I915_PMU_OTHER(0) +#define I915_PMU_REQUESTED_FREQUENCY __I915_PMU_OTHER(1) +#define I915_PMU_INTERRUPTS __I915_PMU_OTHER(2) +#define I915_PMU_RC6_RESIDENCY __I915_PMU_OTHER(3) +#define I915_PMU_SOFTWARE_GT_AWAKE_TIME __I915_PMU_OTHER(4) + +#define I915_PMU_LAST /* Deprecated - do not use */ I915_PMU_RC6_RESIDENCY + +/* Each region is a minimum of 16k, and there are at most 255 of them. + */ +#define I915_NR_TEX_REGIONS 255 /* table size 2k - maximum due to use + * of chars for next/prev indices */ +#define I915_LOG_MIN_TEX_REGION_SIZE 14 + +typedef struct _drm_i915_init { + enum { + I915_INIT_DMA = 0x01, + I915_CLEANUP_DMA = 0x02, + I915_RESUME_DMA = 0x03 + } func; + unsigned int mmio_offset; + int sarea_priv_offset; + unsigned int ring_start; + unsigned int ring_end; + unsigned int ring_size; + unsigned int front_offset; + unsigned int back_offset; + unsigned int depth_offset; + unsigned int w; + unsigned int h; + unsigned int pitch; + unsigned int pitch_bits; + unsigned int back_pitch; + unsigned int depth_pitch; + unsigned int cpp; + unsigned int chipset; +} drm_i915_init_t; + +typedef struct _drm_i915_sarea { + struct drm_tex_region texList[I915_NR_TEX_REGIONS + 1]; + int last_upload; /* last time texture was uploaded */ + int last_enqueue; /* last time a buffer was enqueued */ + int last_dispatch; /* age of the most recently dispatched buffer */ + int ctxOwner; /* last context to upload state */ + int texAge; + int pf_enabled; /* is pageflipping allowed? */ + int pf_active; + int pf_current_page; /* which buffer is being displayed? */ + int perf_boxes; /* performance boxes to be displayed */ + int width, height; /* screen size in pixels */ + + drm_handle_t front_handle; + int front_offset; + int front_size; + + drm_handle_t back_handle; + int back_offset; + int back_size; + + drm_handle_t depth_handle; + int depth_offset; + int depth_size; + + drm_handle_t tex_handle; + int tex_offset; + int tex_size; + int log_tex_granularity; + int pitch; + int rotation; /* 0, 90, 180 or 270 */ + int rotated_offset; + int rotated_size; + int rotated_pitch; + int virtualX, virtualY; + + unsigned int front_tiled; + unsigned int back_tiled; + unsigned int depth_tiled; + unsigned int rotated_tiled; + unsigned int rotated2_tiled; + + int pipeA_x; + int pipeA_y; + int pipeA_w; + int pipeA_h; + int pipeB_x; + int pipeB_y; + int pipeB_w; + int pipeB_h; + + /* fill out some space for old userspace triple buffer */ + drm_handle_t unused_handle; + __u32 unused1, unused2, unused3; + + /* buffer object handles for static buffers. May change + * over the lifetime of the client. + */ + __u32 front_bo_handle; + __u32 back_bo_handle; + __u32 unused_bo_handle; + __u32 depth_bo_handle; + +} drm_i915_sarea_t; + +/* due to userspace building against these headers we need some compat here */ +#define planeA_x pipeA_x +#define planeA_y pipeA_y +#define planeA_w pipeA_w +#define planeA_h pipeA_h +#define planeB_x pipeB_x +#define planeB_y pipeB_y +#define planeB_w pipeB_w +#define planeB_h pipeB_h + +/* Flags for perf_boxes + */ +#define I915_BOX_RING_EMPTY 0x1 +#define I915_BOX_FLIP 0x2 +#define I915_BOX_WAIT 0x4 +#define I915_BOX_TEXTURE_LOAD 0x8 +#define I915_BOX_LOST_CONTEXT 0x10 + +/* + * i915 specific ioctls. + * + * The device specific ioctl range is [DRM_COMMAND_BASE, DRM_COMMAND_END) ie + * [0x40, 0xa0) (a0 is excluded). The numbers below are defined as offset + * against DRM_COMMAND_BASE and should be between [0x0, 0x60). + */ +#define DRM_I915_INIT 0x00 +#define DRM_I915_FLUSH 0x01 +#define DRM_I915_FLIP 0x02 +#define DRM_I915_BATCHBUFFER 0x03 +#define DRM_I915_IRQ_EMIT 0x04 +#define DRM_I915_IRQ_WAIT 0x05 +#define DRM_I915_GETPARAM 0x06 +#define DRM_I915_SETPARAM 0x07 +#define DRM_I915_ALLOC 0x08 +#define DRM_I915_FREE 0x09 +#define DRM_I915_INIT_HEAP 0x0a +#define DRM_I915_CMDBUFFER 0x0b +#define DRM_I915_DESTROY_HEAP 0x0c +#define DRM_I915_SET_VBLANK_PIPE 0x0d +#define DRM_I915_GET_VBLANK_PIPE 0x0e +#define DRM_I915_VBLANK_SWAP 0x0f +#define DRM_I915_HWS_ADDR 0x11 +#define DRM_I915_GEM_INIT 0x13 +#define DRM_I915_GEM_EXECBUFFER 0x14 +#define DRM_I915_GEM_PIN 0x15 +#define DRM_I915_GEM_UNPIN 0x16 +#define DRM_I915_GEM_BUSY 0x17 +#define DRM_I915_GEM_THROTTLE 0x18 +#define DRM_I915_GEM_ENTERVT 0x19 +#define DRM_I915_GEM_LEAVEVT 0x1a +#define DRM_I915_GEM_CREATE 0x1b +#define DRM_I915_GEM_PREAD 0x1c +#define DRM_I915_GEM_PWRITE 0x1d +#define DRM_I915_GEM_MMAP 0x1e +#define DRM_I915_GEM_SET_DOMAIN 0x1f +#define DRM_I915_GEM_SW_FINISH 0x20 +#define DRM_I915_GEM_SET_TILING 0x21 +#define DRM_I915_GEM_GET_TILING 0x22 +#define DRM_I915_GEM_GET_APERTURE 0x23 +#define DRM_I915_GEM_MMAP_GTT 0x24 +#define DRM_I915_GET_PIPE_FROM_CRTC_ID 0x25 +#define DRM_I915_GEM_MADVISE 0x26 +#define DRM_I915_OVERLAY_PUT_IMAGE 0x27 +#define DRM_I915_OVERLAY_ATTRS 0x28 +#define DRM_I915_GEM_EXECBUFFER2 0x29 +#define DRM_I915_GEM_EXECBUFFER2_WR DRM_I915_GEM_EXECBUFFER2 +#define DRM_I915_GET_SPRITE_COLORKEY 0x2a +#define DRM_I915_SET_SPRITE_COLORKEY 0x2b +#define DRM_I915_GEM_WAIT 0x2c +#define DRM_I915_GEM_CONTEXT_CREATE 0x2d +#define DRM_I915_GEM_CONTEXT_DESTROY 0x2e +#define DRM_I915_GEM_SET_CACHING 0x2f +#define DRM_I915_GEM_GET_CACHING 0x30 +#define DRM_I915_REG_READ 0x31 +#define DRM_I915_GET_RESET_STATS 0x32 +#define DRM_I915_GEM_USERPTR 0x33 +#define DRM_I915_GEM_CONTEXT_GETPARAM 0x34 +#define DRM_I915_GEM_CONTEXT_SETPARAM 0x35 +#define DRM_I915_PERF_OPEN 0x36 +#define DRM_I915_PERF_ADD_CONFIG 0x37 +#define DRM_I915_PERF_REMOVE_CONFIG 0x38 +#define DRM_I915_QUERY 0x39 +#define DRM_I915_GEM_VM_CREATE 0x3a +#define DRM_I915_GEM_VM_DESTROY 0x3b +#define DRM_I915_GEM_CREATE_EXT 0x3c +/* Must be kept compact -- no holes */ + +#define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) +#define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) +#define DRM_IOCTL_I915_FLIP DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLIP) +#define DRM_IOCTL_I915_BATCHBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_BATCHBUFFER, drm_i915_batchbuffer_t) +#define DRM_IOCTL_I915_IRQ_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_IRQ_EMIT, drm_i915_irq_emit_t) +#define DRM_IOCTL_I915_IRQ_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_IRQ_WAIT, drm_i915_irq_wait_t) +#define DRM_IOCTL_I915_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GETPARAM, drm_i915_getparam_t) +#define DRM_IOCTL_I915_SETPARAM DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SETPARAM, drm_i915_setparam_t) +#define DRM_IOCTL_I915_ALLOC DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_ALLOC, drm_i915_mem_alloc_t) +#define DRM_IOCTL_I915_FREE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_FREE, drm_i915_mem_free_t) +#define DRM_IOCTL_I915_INIT_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT_HEAP, drm_i915_mem_init_heap_t) +#define DRM_IOCTL_I915_CMDBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_CMDBUFFER, drm_i915_cmdbuffer_t) +#define DRM_IOCTL_I915_DESTROY_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_DESTROY_HEAP, drm_i915_mem_destroy_heap_t) +#define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t) +#define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t) +#define DRM_IOCTL_I915_VBLANK_SWAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_VBLANK_SWAP, drm_i915_vblank_swap_t) +#define DRM_IOCTL_I915_HWS_ADDR DRM_IOW(DRM_COMMAND_BASE + DRM_I915_HWS_ADDR, struct drm_i915_gem_init) +#define DRM_IOCTL_I915_GEM_INIT DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_INIT, struct drm_i915_gem_init) +#define DRM_IOCTL_I915_GEM_EXECBUFFER DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER, struct drm_i915_gem_execbuffer) +#define DRM_IOCTL_I915_GEM_EXECBUFFER2 DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER2, struct drm_i915_gem_execbuffer2) +#define DRM_IOCTL_I915_GEM_EXECBUFFER2_WR DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER2_WR, struct drm_i915_gem_execbuffer2) +#define DRM_IOCTL_I915_GEM_PIN DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_PIN, struct drm_i915_gem_pin) +#define DRM_IOCTL_I915_GEM_UNPIN DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_UNPIN, struct drm_i915_gem_unpin) +#define DRM_IOCTL_I915_GEM_BUSY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_BUSY, struct drm_i915_gem_busy) +#define DRM_IOCTL_I915_GEM_SET_CACHING DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_SET_CACHING, struct drm_i915_gem_caching) +#define DRM_IOCTL_I915_GEM_GET_CACHING DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_GET_CACHING, struct drm_i915_gem_caching) +#define DRM_IOCTL_I915_GEM_THROTTLE DRM_IO ( DRM_COMMAND_BASE + DRM_I915_GEM_THROTTLE) +#define DRM_IOCTL_I915_GEM_ENTERVT DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_ENTERVT) +#define DRM_IOCTL_I915_GEM_LEAVEVT DRM_IO(DRM_COMMAND_BASE + DRM_I915_GEM_LEAVEVT) +#define DRM_IOCTL_I915_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_CREATE, struct drm_i915_gem_create) +#define DRM_IOCTL_I915_GEM_CREATE_EXT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_CREATE_EXT, struct drm_i915_gem_create_ext) +#define DRM_IOCTL_I915_GEM_PREAD DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PREAD, struct drm_i915_gem_pread) +#define DRM_IOCTL_I915_GEM_PWRITE DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_PWRITE, struct drm_i915_gem_pwrite) +#define DRM_IOCTL_I915_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct drm_i915_gem_mmap) +#define DRM_IOCTL_I915_GEM_MMAP_GTT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP_GTT, struct drm_i915_gem_mmap_gtt) +#define DRM_IOCTL_I915_GEM_MMAP_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP_GTT, struct drm_i915_gem_mmap_offset) +#define DRM_IOCTL_I915_GEM_SET_DOMAIN DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SET_DOMAIN, struct drm_i915_gem_set_domain) +#define DRM_IOCTL_I915_GEM_SW_FINISH DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_SW_FINISH, struct drm_i915_gem_sw_finish) +#define DRM_IOCTL_I915_GEM_SET_TILING DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_SET_TILING, struct drm_i915_gem_set_tiling) +#define DRM_IOCTL_I915_GEM_GET_TILING DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_TILING, struct drm_i915_gem_get_tiling) +#define DRM_IOCTL_I915_GEM_GET_APERTURE DRM_IOR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_APERTURE, struct drm_i915_gem_get_aperture) +#define DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GET_PIPE_FROM_CRTC_ID, struct drm_i915_get_pipe_from_crtc_id) +#define DRM_IOCTL_I915_GEM_MADVISE DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MADVISE, struct drm_i915_gem_madvise) +#define DRM_IOCTL_I915_OVERLAY_PUT_IMAGE DRM_IOW(DRM_COMMAND_BASE + DRM_I915_OVERLAY_PUT_IMAGE, struct drm_intel_overlay_put_image) +#define DRM_IOCTL_I915_OVERLAY_ATTRS DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_OVERLAY_ATTRS, struct drm_intel_overlay_attrs) +#define DRM_IOCTL_I915_SET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey) +#define DRM_IOCTL_I915_GET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey) +#define DRM_IOCTL_I915_GEM_WAIT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_WAIT, struct drm_i915_gem_wait) +#define DRM_IOCTL_I915_GEM_CONTEXT_CREATE DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_CREATE, struct drm_i915_gem_context_create) +#define DRM_IOCTL_I915_GEM_CONTEXT_CREATE_EXT DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_CREATE, struct drm_i915_gem_context_create_ext) +#define DRM_IOCTL_I915_GEM_CONTEXT_DESTROY DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_DESTROY, struct drm_i915_gem_context_destroy) +#define DRM_IOCTL_I915_REG_READ DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_REG_READ, struct drm_i915_reg_read) +#define DRM_IOCTL_I915_GET_RESET_STATS DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GET_RESET_STATS, struct drm_i915_reset_stats) +#define DRM_IOCTL_I915_GEM_USERPTR DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_USERPTR, struct drm_i915_gem_userptr) +#define DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_GETPARAM, struct drm_i915_gem_context_param) +#define DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_SETPARAM, struct drm_i915_gem_context_param) +#define DRM_IOCTL_I915_PERF_OPEN DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_OPEN, struct drm_i915_perf_open_param) +#define DRM_IOCTL_I915_PERF_ADD_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_ADD_CONFIG, struct drm_i915_perf_oa_config) +#define DRM_IOCTL_I915_PERF_REMOVE_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_REMOVE_CONFIG, __u64) +#define DRM_IOCTL_I915_QUERY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_QUERY, struct drm_i915_query) +#define DRM_IOCTL_I915_GEM_VM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_VM_CREATE, struct drm_i915_gem_vm_control) +#define DRM_IOCTL_I915_GEM_VM_DESTROY DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_VM_DESTROY, struct drm_i915_gem_vm_control) + +/* Allow drivers to submit batchbuffers directly to hardware, relying + * on the security mechanisms provided by hardware. + */ +typedef struct drm_i915_batchbuffer { + int start; /* agp offset */ + int used; /* nr bytes in use */ + int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */ + int DR4; /* window origin for GFX_OP_DRAWRECT_INFO */ + int num_cliprects; /* mulitpass with multiple cliprects? */ + struct drm_clip_rect *cliprects; /* pointer to userspace cliprects */ +} drm_i915_batchbuffer_t; + +/* As above, but pass a pointer to userspace buffer which can be + * validated by the kernel prior to sending to hardware. + */ +typedef struct _drm_i915_cmdbuffer { + char *buf; /* pointer to userspace command buffer */ + int sz; /* nr bytes in buf */ + int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */ + int DR4; /* window origin for GFX_OP_DRAWRECT_INFO */ + int num_cliprects; /* mulitpass with multiple cliprects? */ + struct drm_clip_rect *cliprects; /* pointer to userspace cliprects */ +} drm_i915_cmdbuffer_t; + +/* Userspace can request & wait on irq's: + */ +typedef struct drm_i915_irq_emit { + int *irq_seq; +} drm_i915_irq_emit_t; + +typedef struct drm_i915_irq_wait { + int irq_seq; +} drm_i915_irq_wait_t; + +/* + * Different modes of per-process Graphics Translation Table, + * see I915_PARAM_HAS_ALIASING_PPGTT + */ +#define I915_GEM_PPGTT_NONE 0 +#define I915_GEM_PPGTT_ALIASING 1 +#define I915_GEM_PPGTT_FULL 2 + +/* Ioctl to query kernel params: + */ +#define I915_PARAM_IRQ_ACTIVE 1 +#define I915_PARAM_ALLOW_BATCHBUFFER 2 +#define I915_PARAM_LAST_DISPATCH 3 +#define I915_PARAM_CHIPSET_ID 4 +#define I915_PARAM_HAS_GEM 5 +#define I915_PARAM_NUM_FENCES_AVAIL 6 +#define I915_PARAM_HAS_OVERLAY 7 +#define I915_PARAM_HAS_PAGEFLIPPING 8 +#define I915_PARAM_HAS_EXECBUF2 9 +#define I915_PARAM_HAS_BSD 10 +#define I915_PARAM_HAS_BLT 11 +#define I915_PARAM_HAS_RELAXED_FENCING 12 +#define I915_PARAM_HAS_COHERENT_RINGS 13 +#define I915_PARAM_HAS_EXEC_CONSTANTS 14 +#define I915_PARAM_HAS_RELAXED_DELTA 15 +#define I915_PARAM_HAS_GEN7_SOL_RESET 16 +#define I915_PARAM_HAS_LLC 17 +#define I915_PARAM_HAS_ALIASING_PPGTT 18 +#define I915_PARAM_HAS_WAIT_TIMEOUT 19 +#define I915_PARAM_HAS_SEMAPHORES 20 +#define I915_PARAM_HAS_PRIME_VMAP_FLUSH 21 +#define I915_PARAM_HAS_VEBOX 22 +#define I915_PARAM_HAS_SECURE_BATCHES 23 +#define I915_PARAM_HAS_PINNED_BATCHES 24 +#define I915_PARAM_HAS_EXEC_NO_RELOC 25 +#define I915_PARAM_HAS_EXEC_HANDLE_LUT 26 +#define I915_PARAM_HAS_WT 27 +#define I915_PARAM_CMD_PARSER_VERSION 28 +#define I915_PARAM_HAS_COHERENT_PHYS_GTT 29 +#define I915_PARAM_MMAP_VERSION 30 +#define I915_PARAM_HAS_BSD2 31 +#define I915_PARAM_REVISION 32 +#define I915_PARAM_SUBSLICE_TOTAL 33 +#define I915_PARAM_EU_TOTAL 34 +#define I915_PARAM_HAS_GPU_RESET 35 +#define I915_PARAM_HAS_RESOURCE_STREAMER 36 +#define I915_PARAM_HAS_EXEC_SOFTPIN 37 +#define I915_PARAM_HAS_POOLED_EU 38 +#define I915_PARAM_MIN_EU_IN_POOL 39 +#define I915_PARAM_MMAP_GTT_VERSION 40 + +/* + * Query whether DRM_I915_GEM_EXECBUFFER2 supports user defined execution + * priorities and the driver will attempt to execute batches in priority order. + * The param returns a capability bitmask, nonzero implies that the scheduler + * is enabled, with different features present according to the mask. + * + * The initial priority for each batch is supplied by the context and is + * controlled via I915_CONTEXT_PARAM_PRIORITY. + */ +#define I915_PARAM_HAS_SCHEDULER 41 +#define I915_SCHEDULER_CAP_ENABLED (1ul << 0) +#define I915_SCHEDULER_CAP_PRIORITY (1ul << 1) +#define I915_SCHEDULER_CAP_PREEMPTION (1ul << 2) +#define I915_SCHEDULER_CAP_SEMAPHORES (1ul << 3) +#define I915_SCHEDULER_CAP_ENGINE_BUSY_STATS (1ul << 4) +/* + * Indicates the 2k user priority levels are statically mapped into 3 buckets as + * follows: + * + * -1k to -1 Low priority + * 0 Normal priority + * 1 to 1k Highest priority + */ +#define I915_SCHEDULER_CAP_STATIC_PRIORITY_MAP (1ul << 5) + +#define I915_PARAM_HUC_STATUS 42 + +/* Query whether DRM_I915_GEM_EXECBUFFER2 supports the ability to opt-out of + * synchronisation with implicit fencing on individual objects. + * See EXEC_OBJECT_ASYNC. + */ +#define I915_PARAM_HAS_EXEC_ASYNC 43 + +/* Query whether DRM_I915_GEM_EXECBUFFER2 supports explicit fence support - + * both being able to pass in a sync_file fd to wait upon before executing, + * and being able to return a new sync_file fd that is signaled when the + * current request is complete. See I915_EXEC_FENCE_IN and I915_EXEC_FENCE_OUT. + */ +#define I915_PARAM_HAS_EXEC_FENCE 44 + +/* Query whether DRM_I915_GEM_EXECBUFFER2 supports the ability to capture + * user specified bufffers for post-mortem debugging of GPU hangs. See + * EXEC_OBJECT_CAPTURE. + */ +#define I915_PARAM_HAS_EXEC_CAPTURE 45 + +#define I915_PARAM_SLICE_MASK 46 + +/* Assuming it's uniform for each slice, this queries the mask of subslices + * per-slice for this system. + */ +#define I915_PARAM_SUBSLICE_MASK 47 + +/* + * Query whether DRM_I915_GEM_EXECBUFFER2 supports supplying the batch buffer + * as the first execobject as opposed to the last. See I915_EXEC_BATCH_FIRST. + */ +#define I915_PARAM_HAS_EXEC_BATCH_FIRST 48 + +/* Query whether DRM_I915_GEM_EXECBUFFER2 supports supplying an array of + * drm_i915_gem_exec_fence structures. See I915_EXEC_FENCE_ARRAY. + */ +#define I915_PARAM_HAS_EXEC_FENCE_ARRAY 49 + +/* + * Query whether every context (both per-file default and user created) is + * isolated (insofar as HW supports). If this parameter is not true, then + * freshly created contexts may inherit values from an existing context, + * rather than default HW values. If true, it also ensures (insofar as HW + * supports) that all state set by this context will not leak to any other + * context. + * + * As not every engine across every gen support contexts, the returned + * value reports the support of context isolation for individual engines by + * returning a bitmask of each engine class set to true if that class supports + * isolation. + */ +#define I915_PARAM_HAS_CONTEXT_ISOLATION 50 + +/* Frequency of the command streamer timestamps given by the *_TIMESTAMP + * registers. This used to be fixed per platform but from CNL onwards, this + * might vary depending on the parts. + */ +#define I915_PARAM_CS_TIMESTAMP_FREQUENCY 51 + +/* + * Once upon a time we supposed that writes through the GGTT would be + * immediately in physical memory (once flushed out of the CPU path). However, + * on a few different processors and chipsets, this is not necessarily the case + * as the writes appear to be buffered internally. Thus a read of the backing + * storage (physical memory) via a different path (with different physical tags + * to the indirect write via the GGTT) will see stale values from before + * the GGTT write. Inside the kernel, we can for the most part keep track of + * the different read/write domains in use (e.g. set-domain), but the assumption + * of coherency is baked into the ABI, hence reporting its true state in this + * parameter. + * + * Reports true when writes via mmap_gtt are immediately visible following an + * lfence to flush the WCB. + * + * Reports false when writes via mmap_gtt are indeterminately delayed in an in + * internal buffer and are _not_ immediately visible to third parties accessing + * directly via mmap_cpu/mmap_wc. Use of mmap_gtt as part of an IPC + * communications channel when reporting false is strongly disadvised. + */ +#define I915_PARAM_MMAP_GTT_COHERENT 52 + +/* + * Query whether DRM_I915_GEM_EXECBUFFER2 supports coordination of parallel + * execution through use of explicit fence support. + * See I915_EXEC_FENCE_OUT and I915_EXEC_FENCE_SUBMIT. + */ +#define I915_PARAM_HAS_EXEC_SUBMIT_FENCE 53 + +/* + * Revision of the i915-perf uAPI. The value returned helps determine what + * i915-perf features are available. See drm_i915_perf_property_id. + */ +#define I915_PARAM_PERF_REVISION 54 + +/* Query whether DRM_I915_GEM_EXECBUFFER2 supports supplying an array of + * timeline syncobj through drm_i915_gem_execbuffer_ext_timeline_fences. See + * I915_EXEC_USE_EXTENSIONS. + */ +#define I915_PARAM_HAS_EXEC_TIMELINE_FENCES 55 + +/* Query if the kernel supports the I915_USERPTR_PROBE flag. */ +#define I915_PARAM_HAS_USERPTR_PROBE 56 + +/* Must be kept compact -- no holes and well documented */ + +/** + * struct drm_i915_getparam - Driver parameter query structure. + */ +struct drm_i915_getparam { + /** @param: Driver parameter to query. */ + __s32 param; + + /** + * @value: Address of memory where queried value should be put. + * + * WARNING: Using pointers instead of fixed-size u64 means we need to write + * compat32 code. Don't repeat this mistake. + */ + int *value; +}; + +/** + * typedef drm_i915_getparam_t - Driver parameter query structure. + * See struct drm_i915_getparam. + */ +typedef struct drm_i915_getparam drm_i915_getparam_t; + +/* Ioctl to set kernel params: + */ +#define I915_SETPARAM_USE_MI_BATCHBUFFER_START 1 +#define I915_SETPARAM_TEX_LRU_LOG_GRANULARITY 2 +#define I915_SETPARAM_ALLOW_BATCHBUFFER 3 +#define I915_SETPARAM_NUM_USED_FENCES 4 +/* Must be kept compact -- no holes */ + +typedef struct drm_i915_setparam { + int param; + int value; +} drm_i915_setparam_t; + +/* A memory manager for regions of shared memory: + */ +#define I915_MEM_REGION_AGP 1 + +typedef struct drm_i915_mem_alloc { + int region; + int alignment; + int size; + int *region_offset; /* offset from start of fb or agp */ +} drm_i915_mem_alloc_t; + +typedef struct drm_i915_mem_free { + int region; + int region_offset; +} drm_i915_mem_free_t; + +typedef struct drm_i915_mem_init_heap { + int region; + int size; + int start; +} drm_i915_mem_init_heap_t; + +/* Allow memory manager to be torn down and re-initialized (eg on + * rotate): + */ +typedef struct drm_i915_mem_destroy_heap { + int region; +} drm_i915_mem_destroy_heap_t; + +/* Allow X server to configure which pipes to monitor for vblank signals + */ +#define DRM_I915_VBLANK_PIPE_A 1 +#define DRM_I915_VBLANK_PIPE_B 2 + +typedef struct drm_i915_vblank_pipe { + int pipe; +} drm_i915_vblank_pipe_t; + +/* Schedule buffer swap at given vertical blank: + */ +typedef struct drm_i915_vblank_swap { + drm_drawable_t drawable; + enum drm_vblank_seq_type seqtype; + unsigned int sequence; +} drm_i915_vblank_swap_t; + +typedef struct drm_i915_hws_addr { + __u64 addr; +} drm_i915_hws_addr_t; + +struct drm_i915_gem_init { + /** + * Beginning offset in the GTT to be managed by the DRM memory + * manager. + */ + __u64 gtt_start; + /** + * Ending offset in the GTT to be managed by the DRM memory + * manager. + */ + __u64 gtt_end; +}; + +struct drm_i915_gem_create { + /** + * Requested size for the object. + * + * The (page-aligned) allocated size for the object will be returned. + */ + __u64 size; + /** + * Returned handle for the object. + * + * Object handles are nonzero. + */ + __u32 handle; + __u32 pad; +}; + +struct drm_i915_gem_pread { + /** Handle for the object being read. */ + __u32 handle; + __u32 pad; + /** Offset into the object to read from */ + __u64 offset; + /** Length of data to read */ + __u64 size; + /** + * Pointer to write the data into. + * + * This is a fixed-size type for 32/64 compatibility. + */ + __u64 data_ptr; +}; + +struct drm_i915_gem_pwrite { + /** Handle for the object being written to. */ + __u32 handle; + __u32 pad; + /** Offset into the object to write to */ + __u64 offset; + /** Length of data to write */ + __u64 size; + /** + * Pointer to read the data from. + * + * This is a fixed-size type for 32/64 compatibility. + */ + __u64 data_ptr; +}; + +struct drm_i915_gem_mmap { + /** Handle for the object being mapped. */ + __u32 handle; + __u32 pad; + /** Offset in the object to map. */ + __u64 offset; + /** + * Length of data to map. + * + * The value will be page-aligned. + */ + __u64 size; + /** + * Returned pointer the data was mapped at. + * + * This is a fixed-size type for 32/64 compatibility. + */ + __u64 addr_ptr; + + /** + * Flags for extended behaviour. + * + * Added in version 2. + */ + __u64 flags; +#define I915_MMAP_WC 0x1 +}; + +struct drm_i915_gem_mmap_gtt { + /** Handle for the object being mapped. */ + __u32 handle; + __u32 pad; + /** + * Fake offset to use for subsequent mmap call + * + * This is a fixed-size type for 32/64 compatibility. + */ + __u64 offset; +}; + +/** + * struct drm_i915_gem_mmap_offset - Retrieve an offset so we can mmap this buffer object. + * + * This struct is passed as argument to the `DRM_IOCTL_I915_GEM_MMAP_OFFSET` ioctl, + * and is used to retrieve the fake offset to mmap an object specified by &handle. + * + * The legacy way of using `DRM_IOCTL_I915_GEM_MMAP` is removed on gen12+. + * `DRM_IOCTL_I915_GEM_MMAP_GTT` is an older supported alias to this struct, but will behave + * as setting the &extensions to 0, and &flags to `I915_MMAP_OFFSET_GTT`. + */ +struct drm_i915_gem_mmap_offset { + /** @handle: Handle for the object being mapped. */ + __u32 handle; + /** @pad: Must be zero */ + __u32 pad; + /** + * @offset: The fake offset to use for subsequent mmap call + * + * This is a fixed-size type for 32/64 compatibility. + */ + __u64 offset; + + /** + * @flags: Flags for extended behaviour. + * + * It is mandatory that one of the `MMAP_OFFSET` types + * should be included: + * + * - `I915_MMAP_OFFSET_GTT`: Use mmap with the object bound to GTT. (Write-Combined) + * - `I915_MMAP_OFFSET_WC`: Use Write-Combined caching. + * - `I915_MMAP_OFFSET_WB`: Use Write-Back caching. + * - `I915_MMAP_OFFSET_FIXED`: Use object placement to determine caching. + * + * On devices with local memory `I915_MMAP_OFFSET_FIXED` is the only valid + * type. On devices without local memory, this caching mode is invalid. + * + * As caching mode when specifying `I915_MMAP_OFFSET_FIXED`, WC or WB will + * be used, depending on the object placement on creation. WB will be used + * when the object can only exist in system memory, WC otherwise. + */ + __u64 flags; + +#define I915_MMAP_OFFSET_GTT 0 +#define I915_MMAP_OFFSET_WC 1 +#define I915_MMAP_OFFSET_WB 2 +#define I915_MMAP_OFFSET_UC 3 +#define I915_MMAP_OFFSET_FIXED 4 + + /** + * @extensions: Zero-terminated chain of extensions. + * + * No current extensions defined; mbz. + */ + __u64 extensions; +}; + +/** + * struct drm_i915_gem_set_domain - Adjust the objects write or read domain, in + * preparation for accessing the pages via some CPU domain. + * + * Specifying a new write or read domain will flush the object out of the + * previous domain(if required), before then updating the objects domain + * tracking with the new domain. + * + * Note this might involve waiting for the object first if it is still active on + * the GPU. + * + * Supported values for @read_domains and @write_domain: + * + * - I915_GEM_DOMAIN_WC: Uncached write-combined domain + * - I915_GEM_DOMAIN_CPU: CPU cache domain + * - I915_GEM_DOMAIN_GTT: Mappable aperture domain + * + * All other domains are rejected. + * + * Note that for discrete, starting from DG1, this is no longer supported, and + * is instead rejected. On such platforms the CPU domain is effectively static, + * where we also only support a single &drm_i915_gem_mmap_offset cache mode, + * which can't be set explicitly and instead depends on the object placements, + * as per the below. + * + * Implicit caching rules, starting from DG1: + * + * - If any of the object placements (see &drm_i915_gem_create_ext_memory_regions) + * contain I915_MEMORY_CLASS_DEVICE then the object will be allocated and + * mapped as write-combined only. + * + * - Everything else is always allocated and mapped as write-back, with the + * guarantee that everything is also coherent with the GPU. + * + * Note that this is likely to change in the future again, where we might need + * more flexibility on future devices, so making this all explicit as part of a + * new &drm_i915_gem_create_ext extension is probable. + */ +struct drm_i915_gem_set_domain { + /** @handle: Handle for the object. */ + __u32 handle; + + /** @read_domains: New read domains. */ + __u32 read_domains; + + /** + * @write_domain: New write domain. + * + * Note that having something in the write domain implies it's in the + * read domain, and only that read domain. + */ + __u32 write_domain; +}; + +struct drm_i915_gem_sw_finish { + /** Handle for the object */ + __u32 handle; +}; + +struct drm_i915_gem_relocation_entry { + /** + * Handle of the buffer being pointed to by this relocation entry. + * + * It's appealing to make this be an index into the mm_validate_entry + * list to refer to the buffer, but this allows the driver to create + * a relocation list for state buffers and not re-write it per + * exec using the buffer. + */ + __u32 target_handle; + + /** + * Value to be added to the offset of the target buffer to make up + * the relocation entry. + */ + __u32 delta; + + /** Offset in the buffer the relocation entry will be written into */ + __u64 offset; + + /** + * Offset value of the target buffer that the relocation entry was last + * written as. + * + * If the buffer has the same offset as last time, we can skip syncing + * and writing the relocation. This value is written back out by + * the execbuffer ioctl when the relocation is written. + */ + __u64 presumed_offset; + + /** + * Target memory domains read by this operation. + */ + __u32 read_domains; + + /** + * Target memory domains written by this operation. + * + * Note that only one domain may be written by the whole + * execbuffer operation, so that where there are conflicts, + * the application will get -EINVAL back. + */ + __u32 write_domain; +}; + +/** @{ + * Intel memory domains + * + * Most of these just align with the various caches in + * the system and are used to flush and invalidate as + * objects end up cached in different domains. + */ +/** CPU cache */ +#define I915_GEM_DOMAIN_CPU 0x00000001 +/** Render cache, used by 2D and 3D drawing */ +#define I915_GEM_DOMAIN_RENDER 0x00000002 +/** Sampler cache, used by texture engine */ +#define I915_GEM_DOMAIN_SAMPLER 0x00000004 +/** Command queue, used to load batch buffers */ +#define I915_GEM_DOMAIN_COMMAND 0x00000008 +/** Instruction cache, used by shader programs */ +#define I915_GEM_DOMAIN_INSTRUCTION 0x00000010 +/** Vertex address cache */ +#define I915_GEM_DOMAIN_VERTEX 0x00000020 +/** GTT domain - aperture and scanout */ +#define I915_GEM_DOMAIN_GTT 0x00000040 +/** WC domain - uncached access */ +#define I915_GEM_DOMAIN_WC 0x00000080 +/** @} */ + +struct drm_i915_gem_exec_object { + /** + * User's handle for a buffer to be bound into the GTT for this + * operation. + */ + __u32 handle; + + /** Number of relocations to be performed on this buffer */ + __u32 relocation_count; + /** + * Pointer to array of struct drm_i915_gem_relocation_entry containing + * the relocations to be performed in this buffer. + */ + __u64 relocs_ptr; + + /** Required alignment in graphics aperture */ + __u64 alignment; + + /** + * Returned value of the updated offset of the object, for future + * presumed_offset writes. + */ + __u64 offset; +}; + +/* DRM_IOCTL_I915_GEM_EXECBUFFER was removed in Linux 5.13 */ +struct drm_i915_gem_execbuffer { + /** + * List of buffers to be validated with their relocations to be + * performend on them. + * + * This is a pointer to an array of struct drm_i915_gem_validate_entry. + * + * These buffers must be listed in an order such that all relocations + * a buffer is performing refer to buffers that have already appeared + * in the validate list. + */ + __u64 buffers_ptr; + __u32 buffer_count; + + /** Offset in the batchbuffer to start execution from. */ + __u32 batch_start_offset; + /** Bytes used in batchbuffer from batch_start_offset */ + __u32 batch_len; + __u32 DR1; + __u32 DR4; + __u32 num_cliprects; + /** This is a struct drm_clip_rect *cliprects */ + __u64 cliprects_ptr; +}; + +struct drm_i915_gem_exec_object2 { + /** + * User's handle for a buffer to be bound into the GTT for this + * operation. + */ + __u32 handle; + + /** Number of relocations to be performed on this buffer */ + __u32 relocation_count; + /** + * Pointer to array of struct drm_i915_gem_relocation_entry containing + * the relocations to be performed in this buffer. + */ + __u64 relocs_ptr; + + /** Required alignment in graphics aperture */ + __u64 alignment; + + /** + * When the EXEC_OBJECT_PINNED flag is specified this is populated by + * the user with the GTT offset at which this object will be pinned. + * + * When the I915_EXEC_NO_RELOC flag is specified this must contain the + * presumed_offset of the object. + * + * During execbuffer2 the kernel populates it with the value of the + * current GTT offset of the object, for future presumed_offset writes. + * + * See struct drm_i915_gem_create_ext for the rules when dealing with + * alignment restrictions with I915_MEMORY_CLASS_DEVICE, on devices with + * minimum page sizes, like DG2. + */ + __u64 offset; + +#define EXEC_OBJECT_NEEDS_FENCE (1<<0) +#define EXEC_OBJECT_NEEDS_GTT (1<<1) +#define EXEC_OBJECT_WRITE (1<<2) +#define EXEC_OBJECT_SUPPORTS_48B_ADDRESS (1<<3) +#define EXEC_OBJECT_PINNED (1<<4) +#define EXEC_OBJECT_PAD_TO_SIZE (1<<5) +/* The kernel implicitly tracks GPU activity on all GEM objects, and + * synchronises operations with outstanding rendering. This includes + * rendering on other devices if exported via dma-buf. However, sometimes + * this tracking is too coarse and the user knows better. For example, + * if the object is split into non-overlapping ranges shared between different + * clients or engines (i.e. suballocating objects), the implicit tracking + * by kernel assumes that each operation affects the whole object rather + * than an individual range, causing needless synchronisation between clients. + * The kernel will also forgo any CPU cache flushes prior to rendering from + * the object as the client is expected to be also handling such domain + * tracking. + * + * The kernel maintains the implicit tracking in order to manage resources + * used by the GPU - this flag only disables the synchronisation prior to + * rendering with this object in this execbuf. + * + * Opting out of implicit synhronisation requires the user to do its own + * explicit tracking to avoid rendering corruption. See, for example, + * I915_PARAM_HAS_EXEC_FENCE to order execbufs and execute them asynchronously. + */ +#define EXEC_OBJECT_ASYNC (1<<6) +/* Request that the contents of this execobject be copied into the error + * state upon a GPU hang involving this batch for post-mortem debugging. + * These buffers are recorded in no particular order as "user" in + * /sys/class/drm/cardN/error. Query I915_PARAM_HAS_EXEC_CAPTURE to see + * if the kernel supports this flag. + */ +#define EXEC_OBJECT_CAPTURE (1<<7) +/* All remaining bits are MBZ and RESERVED FOR FUTURE USE */ +#define __EXEC_OBJECT_UNKNOWN_FLAGS -(EXEC_OBJECT_CAPTURE<<1) + __u64 flags; + + union { + __u64 rsvd1; + __u64 pad_to_size; + }; + __u64 rsvd2; +}; + +/** + * struct drm_i915_gem_exec_fence - An input or output fence for the execbuf + * ioctl. + * + * The request will wait for input fence to signal before submission. + * + * The returned output fence will be signaled after the completion of the + * request. + */ +struct drm_i915_gem_exec_fence { + /** @handle: User's handle for a drm_syncobj to wait on or signal. */ + __u32 handle; + + /** + * @flags: Supported flags are: + * + * I915_EXEC_FENCE_WAIT: + * Wait for the input fence before request submission. + * + * I915_EXEC_FENCE_SIGNAL: + * Return request completion fence as output + */ + __u32 flags; +#define I915_EXEC_FENCE_WAIT (1<<0) +#define I915_EXEC_FENCE_SIGNAL (1<<1) +#define __I915_EXEC_FENCE_UNKNOWN_FLAGS (-(I915_EXEC_FENCE_SIGNAL << 1)) +}; + +/** + * struct drm_i915_gem_execbuffer_ext_timeline_fences - Timeline fences + * for execbuf ioctl. + * + * This structure describes an array of drm_syncobj and associated points for + * timeline variants of drm_syncobj. It is invalid to append this structure to + * the execbuf if I915_EXEC_FENCE_ARRAY is set. + */ +struct drm_i915_gem_execbuffer_ext_timeline_fences { +#define DRM_I915_GEM_EXECBUFFER_EXT_TIMELINE_FENCES 0 + /** @base: Extension link. See struct i915_user_extension. */ + struct i915_user_extension base; + + /** + * @fence_count: Number of elements in the @handles_ptr & @value_ptr + * arrays. + */ + __u64 fence_count; + + /** + * @handles_ptr: Pointer to an array of struct drm_i915_gem_exec_fence + * of length @fence_count. + */ + __u64 handles_ptr; + + /** + * @values_ptr: Pointer to an array of u64 values of length + * @fence_count. + * Values must be 0 for a binary drm_syncobj. A Value of 0 for a + * timeline drm_syncobj is invalid as it turns a drm_syncobj into a + * binary one. + */ + __u64 values_ptr; +}; + +/** + * struct drm_i915_gem_execbuffer2 - Structure for DRM_I915_GEM_EXECBUFFER2 + * ioctl. + */ +struct drm_i915_gem_execbuffer2 { + /** @buffers_ptr: Pointer to a list of gem_exec_object2 structs */ + __u64 buffers_ptr; + + /** @buffer_count: Number of elements in @buffers_ptr array */ + __u32 buffer_count; + + /** + * @batch_start_offset: Offset in the batchbuffer to start execution + * from. + */ + __u32 batch_start_offset; + + /** + * @batch_len: Length in bytes of the batch buffer, starting from the + * @batch_start_offset. If 0, length is assumed to be the batch buffer + * object size. + */ + __u32 batch_len; + + /** @DR1: deprecated */ + __u32 DR1; + + /** @DR4: deprecated */ + __u32 DR4; + + /** @num_cliprects: See @cliprects_ptr */ + __u32 num_cliprects; + + /** + * @cliprects_ptr: Kernel clipping was a DRI1 misfeature. + * + * It is invalid to use this field if I915_EXEC_FENCE_ARRAY or + * I915_EXEC_USE_EXTENSIONS flags are not set. + * + * If I915_EXEC_FENCE_ARRAY is set, then this is a pointer to an array + * of &drm_i915_gem_exec_fence and @num_cliprects is the length of the + * array. + * + * If I915_EXEC_USE_EXTENSIONS is set, then this is a pointer to a + * single &i915_user_extension and num_cliprects is 0. + */ + __u64 cliprects_ptr; + + /** @flags: Execbuf flags */ + __u64 flags; +#define I915_EXEC_RING_MASK (0x3f) +#define I915_EXEC_DEFAULT (0<<0) +#define I915_EXEC_RENDER (1<<0) +#define I915_EXEC_BSD (2<<0) +#define I915_EXEC_BLT (3<<0) +#define I915_EXEC_VEBOX (4<<0) + +/* Used for switching the constants addressing mode on gen4+ RENDER ring. + * Gen6+ only supports relative addressing to dynamic state (default) and + * absolute addressing. + * + * These flags are ignored for the BSD and BLT rings. + */ +#define I915_EXEC_CONSTANTS_MASK (3<<6) +#define I915_EXEC_CONSTANTS_REL_GENERAL (0<<6) /* default */ +#define I915_EXEC_CONSTANTS_ABSOLUTE (1<<6) +#define I915_EXEC_CONSTANTS_REL_SURFACE (2<<6) /* gen4/5 only */ + +/** Resets the SO write offset registers for transform feedback on gen7. */ +#define I915_EXEC_GEN7_SOL_RESET (1<<8) + +/** Request a privileged ("secure") batch buffer. Note only available for + * DRM_ROOT_ONLY | DRM_MASTER processes. + */ +#define I915_EXEC_SECURE (1<<9) + +/** Inform the kernel that the batch is and will always be pinned. This + * negates the requirement for a workaround to be performed to avoid + * an incoherent CS (such as can be found on 830/845). If this flag is + * not passed, the kernel will endeavour to make sure the batch is + * coherent with the CS before execution. If this flag is passed, + * userspace assumes the responsibility for ensuring the same. + */ +#define I915_EXEC_IS_PINNED (1<<10) + +/** Provide a hint to the kernel that the command stream and auxiliary + * state buffers already holds the correct presumed addresses and so the + * relocation process may be skipped if no buffers need to be moved in + * preparation for the execbuffer. + */ +#define I915_EXEC_NO_RELOC (1<<11) + +/** Use the reloc.handle as an index into the exec object array rather + * than as the per-file handle. + */ +#define I915_EXEC_HANDLE_LUT (1<<12) + +/** Used for switching BSD rings on the platforms with two BSD rings */ +#define I915_EXEC_BSD_SHIFT (13) +#define I915_EXEC_BSD_MASK (3 << I915_EXEC_BSD_SHIFT) +/* default ping-pong mode */ +#define I915_EXEC_BSD_DEFAULT (0 << I915_EXEC_BSD_SHIFT) +#define I915_EXEC_BSD_RING1 (1 << I915_EXEC_BSD_SHIFT) +#define I915_EXEC_BSD_RING2 (2 << I915_EXEC_BSD_SHIFT) + +/** Tell the kernel that the batchbuffer is processed by + * the resource streamer. + */ +#define I915_EXEC_RESOURCE_STREAMER (1<<15) + +/* Setting I915_EXEC_FENCE_IN implies that lower_32_bits(rsvd2) represent + * a sync_file fd to wait upon (in a nonblocking manner) prior to executing + * the batch. + * + * Returns -EINVAL if the sync_file fd cannot be found. + */ +#define I915_EXEC_FENCE_IN (1<<16) + +/* Setting I915_EXEC_FENCE_OUT causes the ioctl to return a sync_file fd + * in the upper_32_bits(rsvd2) upon success. Ownership of the fd is given + * to the caller, and it should be close() after use. (The fd is a regular + * file descriptor and will be cleaned up on process termination. It holds + * a reference to the request, but nothing else.) + * + * The sync_file fd can be combined with other sync_file and passed either + * to execbuf using I915_EXEC_FENCE_IN, to atomic KMS ioctls (so that a flip + * will only occur after this request completes), or to other devices. + * + * Using I915_EXEC_FENCE_OUT requires use of + * DRM_IOCTL_I915_GEM_EXECBUFFER2_WR ioctl so that the result is written + * back to userspace. Failure to do so will cause the out-fence to always + * be reported as zero, and the real fence fd to be leaked. + */ +#define I915_EXEC_FENCE_OUT (1<<17) + +/* + * Traditionally the execbuf ioctl has only considered the final element in + * the execobject[] to be the executable batch. Often though, the client + * will known the batch object prior to construction and being able to place + * it into the execobject[] array first can simplify the relocation tracking. + * Setting I915_EXEC_BATCH_FIRST tells execbuf to use element 0 of the + * execobject[] as the * batch instead (the default is to use the last + * element). + */ +#define I915_EXEC_BATCH_FIRST (1<<18) + +/* Setting I915_FENCE_ARRAY implies that num_cliprects and cliprects_ptr + * define an array of i915_gem_exec_fence structures which specify a set of + * dma fences to wait upon or signal. + */ +#define I915_EXEC_FENCE_ARRAY (1<<19) + +/* + * Setting I915_EXEC_FENCE_SUBMIT implies that lower_32_bits(rsvd2) represent + * a sync_file fd to wait upon (in a nonblocking manner) prior to executing + * the batch. + * + * Returns -EINVAL if the sync_file fd cannot be found. + */ +#define I915_EXEC_FENCE_SUBMIT (1 << 20) + +/* + * Setting I915_EXEC_USE_EXTENSIONS implies that + * drm_i915_gem_execbuffer2.cliprects_ptr is treated as a pointer to an linked + * list of i915_user_extension. Each i915_user_extension node is the base of a + * larger structure. The list of supported structures are listed in the + * drm_i915_gem_execbuffer_ext enum. + */ +#define I915_EXEC_USE_EXTENSIONS (1 << 21) +#define __I915_EXEC_UNKNOWN_FLAGS (-(I915_EXEC_USE_EXTENSIONS << 1)) + + /** @rsvd1: Context id */ + __u64 rsvd1; + + /** + * @rsvd2: in and out sync_file file descriptors. + * + * When I915_EXEC_FENCE_IN or I915_EXEC_FENCE_SUBMIT flag is set, the + * lower 32 bits of this field will have the in sync_file fd (input). + * + * When I915_EXEC_FENCE_OUT flag is set, the upper 32 bits of this + * field will have the out sync_file fd (output). + */ + __u64 rsvd2; +}; + +#define I915_EXEC_CONTEXT_ID_MASK (0xffffffff) +#define i915_execbuffer2_set_context_id(eb2, context) \ + (eb2).rsvd1 = context & I915_EXEC_CONTEXT_ID_MASK +#define i915_execbuffer2_get_context_id(eb2) \ + ((eb2).rsvd1 & I915_EXEC_CONTEXT_ID_MASK) + +struct drm_i915_gem_pin { + /** Handle of the buffer to be pinned. */ + __u32 handle; + __u32 pad; + + /** alignment required within the aperture */ + __u64 alignment; + + /** Returned GTT offset of the buffer. */ + __u64 offset; +}; + +struct drm_i915_gem_unpin { + /** Handle of the buffer to be unpinned. */ + __u32 handle; + __u32 pad; +}; + +struct drm_i915_gem_busy { + /** Handle of the buffer to check for busy */ + __u32 handle; + + /** Return busy status + * + * A return of 0 implies that the object is idle (after + * having flushed any pending activity), and a non-zero return that + * the object is still in-flight on the GPU. (The GPU has not yet + * signaled completion for all pending requests that reference the + * object.) An object is guaranteed to become idle eventually (so + * long as no new GPU commands are executed upon it). Due to the + * asynchronous nature of the hardware, an object reported + * as busy may become idle before the ioctl is completed. + * + * Furthermore, if the object is busy, which engine is busy is only + * provided as a guide and only indirectly by reporting its class + * (there may be more than one engine in each class). There are race + * conditions which prevent the report of which engines are busy from + * being always accurate. However, the converse is not true. If the + * object is idle, the result of the ioctl, that all engines are idle, + * is accurate. + * + * The returned dword is split into two fields to indicate both + * the engine classess on which the object is being read, and the + * engine class on which it is currently being written (if any). + * + * The low word (bits 0:15) indicate if the object is being written + * to by any engine (there can only be one, as the GEM implicit + * synchronisation rules force writes to be serialised). Only the + * engine class (offset by 1, I915_ENGINE_CLASS_RENDER is reported as + * 1 not 0 etc) for the last write is reported. + * + * The high word (bits 16:31) are a bitmask of which engines classes + * are currently reading from the object. Multiple engines may be + * reading from the object simultaneously. + * + * The value of each engine class is the same as specified in the + * I915_CONTEXT_PARAM_ENGINES context parameter and via perf, i.e. + * I915_ENGINE_CLASS_RENDER, I915_ENGINE_CLASS_COPY, etc. + * Some hardware may have parallel execution engines, e.g. multiple + * media engines, which are mapped to the same class identifier and so + * are not separately reported for busyness. + * + * Caveat emptor: + * Only the boolean result of this query is reliable; that is whether + * the object is idle or busy. The report of which engines are busy + * should be only used as a heuristic. + */ + __u32 busy; +}; + +/** + * struct drm_i915_gem_caching - Set or get the caching for given object + * handle. + * + * Allow userspace to control the GTT caching bits for a given object when the + * object is later mapped through the ppGTT(or GGTT on older platforms lacking + * ppGTT support, or if the object is used for scanout). Note that this might + * require unbinding the object from the GTT first, if its current caching value + * doesn't match. + * + * Note that this all changes on discrete platforms, starting from DG1, the + * set/get caching is no longer supported, and is now rejected. Instead the CPU + * caching attributes(WB vs WC) will become an immutable creation time property + * for the object, along with the GTT caching level. For now we don't expose any + * new uAPI for this, instead on DG1 this is all implicit, although this largely + * shouldn't matter since DG1 is coherent by default(without any way of + * controlling it). + * + * Implicit caching rules, starting from DG1: + * + * - If any of the object placements (see &drm_i915_gem_create_ext_memory_regions) + * contain I915_MEMORY_CLASS_DEVICE then the object will be allocated and + * mapped as write-combined only. + * + * - Everything else is always allocated and mapped as write-back, with the + * guarantee that everything is also coherent with the GPU. + * + * Note that this is likely to change in the future again, where we might need + * more flexibility on future devices, so making this all explicit as part of a + * new &drm_i915_gem_create_ext extension is probable. + * + * Side note: Part of the reason for this is that changing the at-allocation-time CPU + * caching attributes for the pages might be required(and is expensive) if we + * need to then CPU map the pages later with different caching attributes. This + * inconsistent caching behaviour, while supported on x86, is not universally + * supported on other architectures. So for simplicity we opt for setting + * everything at creation time, whilst also making it immutable, on discrete + * platforms. + */ +struct drm_i915_gem_caching { + /** + * @handle: Handle of the buffer to set/get the caching level. + */ + __u32 handle; + + /** + * @caching: The GTT caching level to apply or possible return value. + * + * The supported @caching values: + * + * I915_CACHING_NONE: + * + * GPU access is not coherent with CPU caches. Default for machines + * without an LLC. This means manual flushing might be needed, if we + * want GPU access to be coherent. + * + * I915_CACHING_CACHED: + * + * GPU access is coherent with CPU caches and furthermore the data is + * cached in last-level caches shared between CPU cores and the GPU GT. + * + * I915_CACHING_DISPLAY: + * + * Special GPU caching mode which is coherent with the scanout engines. + * Transparently falls back to I915_CACHING_NONE on platforms where no + * special cache mode (like write-through or gfdt flushing) is + * available. The kernel automatically sets this mode when using a + * buffer as a scanout target. Userspace can manually set this mode to + * avoid a costly stall and clflush in the hotpath of drawing the first + * frame. + */ +#define I915_CACHING_NONE 0 +#define I915_CACHING_CACHED 1 +#define I915_CACHING_DISPLAY 2 + __u32 caching; +}; + +#define I915_TILING_NONE 0 +#define I915_TILING_X 1 +#define I915_TILING_Y 2 +/* + * Do not add new tiling types here. The I915_TILING_* values are for + * de-tiling fence registers that no longer exist on modern platforms. Although + * the hardware may support new types of tiling in general (e.g., Tile4), we + * do not need to add them to the uapi that is specific to now-defunct ioctls. + */ +#define I915_TILING_LAST I915_TILING_Y + +#define I915_BIT_6_SWIZZLE_NONE 0 +#define I915_BIT_6_SWIZZLE_9 1 +#define I915_BIT_6_SWIZZLE_9_10 2 +#define I915_BIT_6_SWIZZLE_9_11 3 +#define I915_BIT_6_SWIZZLE_9_10_11 4 +/* Not seen by userland */ +#define I915_BIT_6_SWIZZLE_UNKNOWN 5 +/* Seen by userland. */ +#define I915_BIT_6_SWIZZLE_9_17 6 +#define I915_BIT_6_SWIZZLE_9_10_17 7 + +struct drm_i915_gem_set_tiling { + /** Handle of the buffer to have its tiling state updated */ + __u32 handle; + + /** + * Tiling mode for the object (I915_TILING_NONE, I915_TILING_X, + * I915_TILING_Y). + * + * This value is to be set on request, and will be updated by the + * kernel on successful return with the actual chosen tiling layout. + * + * The tiling mode may be demoted to I915_TILING_NONE when the system + * has bit 6 swizzling that can't be managed correctly by GEM. + * + * Buffer contents become undefined when changing tiling_mode. + */ + __u32 tiling_mode; + + /** + * Stride in bytes for the object when in I915_TILING_X or + * I915_TILING_Y. + */ + __u32 stride; + + /** + * Returned address bit 6 swizzling required for CPU access through + * mmap mapping. + */ + __u32 swizzle_mode; +}; + +struct drm_i915_gem_get_tiling { + /** Handle of the buffer to get tiling state for. */ + __u32 handle; + + /** + * Current tiling mode for the object (I915_TILING_NONE, I915_TILING_X, + * I915_TILING_Y). + */ + __u32 tiling_mode; + + /** + * Returned address bit 6 swizzling required for CPU access through + * mmap mapping. + */ + __u32 swizzle_mode; + + /** + * Returned address bit 6 swizzling required for CPU access through + * mmap mapping whilst bound. + */ + __u32 phys_swizzle_mode; +}; + +struct drm_i915_gem_get_aperture { + /** Total size of the aperture used by i915_gem_execbuffer, in bytes */ + __u64 aper_size; + + /** + * Available space in the aperture used by i915_gem_execbuffer, in + * bytes + */ + __u64 aper_available_size; +}; + +struct drm_i915_get_pipe_from_crtc_id { + /** ID of CRTC being requested **/ + __u32 crtc_id; + + /** pipe of requested CRTC **/ + __u32 pipe; +}; + +#define I915_MADV_WILLNEED 0 +#define I915_MADV_DONTNEED 1 +#define __I915_MADV_PURGED 2 /* internal state */ + +struct drm_i915_gem_madvise { + /** Handle of the buffer to change the backing store advice */ + __u32 handle; + + /* Advice: either the buffer will be needed again in the near future, + * or wont be and could be discarded under memory pressure. + */ + __u32 madv; + + /** Whether the backing store still exists. */ + __u32 retained; +}; + +/* flags */ +#define I915_OVERLAY_TYPE_MASK 0xff +#define I915_OVERLAY_YUV_PLANAR 0x01 +#define I915_OVERLAY_YUV_PACKED 0x02 +#define I915_OVERLAY_RGB 0x03 + +#define I915_OVERLAY_DEPTH_MASK 0xff00 +#define I915_OVERLAY_RGB24 0x1000 +#define I915_OVERLAY_RGB16 0x2000 +#define I915_OVERLAY_RGB15 0x3000 +#define I915_OVERLAY_YUV422 0x0100 +#define I915_OVERLAY_YUV411 0x0200 +#define I915_OVERLAY_YUV420 0x0300 +#define I915_OVERLAY_YUV410 0x0400 + +#define I915_OVERLAY_SWAP_MASK 0xff0000 +#define I915_OVERLAY_NO_SWAP 0x000000 +#define I915_OVERLAY_UV_SWAP 0x010000 +#define I915_OVERLAY_Y_SWAP 0x020000 +#define I915_OVERLAY_Y_AND_UV_SWAP 0x030000 + +#define I915_OVERLAY_FLAGS_MASK 0xff000000 +#define I915_OVERLAY_ENABLE 0x01000000 + +struct drm_intel_overlay_put_image { + /* various flags and src format description */ + __u32 flags; + /* source picture description */ + __u32 bo_handle; + /* stride values and offsets are in bytes, buffer relative */ + __u16 stride_Y; /* stride for packed formats */ + __u16 stride_UV; + __u32 offset_Y; /* offset for packet formats */ + __u32 offset_U; + __u32 offset_V; + /* in pixels */ + __u16 src_width; + __u16 src_height; + /* to compensate the scaling factors for partially covered surfaces */ + __u16 src_scan_width; + __u16 src_scan_height; + /* output crtc description */ + __u32 crtc_id; + __u16 dst_x; + __u16 dst_y; + __u16 dst_width; + __u16 dst_height; +}; + +/* flags */ +#define I915_OVERLAY_UPDATE_ATTRS (1<<0) +#define I915_OVERLAY_UPDATE_GAMMA (1<<1) +#define I915_OVERLAY_DISABLE_DEST_COLORKEY (1<<2) +struct drm_intel_overlay_attrs { + __u32 flags; + __u32 color_key; + __s32 brightness; + __u32 contrast; + __u32 saturation; + __u32 gamma0; + __u32 gamma1; + __u32 gamma2; + __u32 gamma3; + __u32 gamma4; + __u32 gamma5; +}; + +/* + * Intel sprite handling + * + * Color keying works with a min/mask/max tuple. Both source and destination + * color keying is allowed. + * + * Source keying: + * Sprite pixels within the min & max values, masked against the color channels + * specified in the mask field, will be transparent. All other pixels will + * be displayed on top of the primary plane. For RGB surfaces, only the min + * and mask fields will be used; ranged compares are not allowed. + * + * Destination keying: + * Primary plane pixels that match the min value, masked against the color + * channels specified in the mask field, will be replaced by corresponding + * pixels from the sprite plane. + * + * Note that source & destination keying are exclusive; only one can be + * active on a given plane. + */ + +#define I915_SET_COLORKEY_NONE (1<<0) /* Deprecated. Instead set + * flags==0 to disable colorkeying. + */ +#define I915_SET_COLORKEY_DESTINATION (1<<1) +#define I915_SET_COLORKEY_SOURCE (1<<2) +struct drm_intel_sprite_colorkey { + __u32 plane_id; + __u32 min_value; + __u32 channel_mask; + __u32 max_value; + __u32 flags; +}; + +struct drm_i915_gem_wait { + /** Handle of BO we shall wait on */ + __u32 bo_handle; + __u32 flags; + /** Number of nanoseconds to wait, Returns time remaining. */ + __s64 timeout_ns; +}; + +struct drm_i915_gem_context_create { + __u32 ctx_id; /* output: id of new context*/ + __u32 pad; +}; + +/** + * struct drm_i915_gem_context_create_ext - Structure for creating contexts. + */ +struct drm_i915_gem_context_create_ext { + /** @ctx_id: Id of the created context (output) */ + __u32 ctx_id; + + /** + * @flags: Supported flags are: + * + * I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS: + * + * Extensions may be appended to this structure and driver must check + * for those. See @extensions. + * + * I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE + * + * Created context will have single timeline. + */ + __u32 flags; +#define I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS (1u << 0) +#define I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE (1u << 1) +#define I915_CONTEXT_CREATE_FLAGS_UNKNOWN \ + (-(I915_CONTEXT_CREATE_FLAGS_SINGLE_TIMELINE << 1)) + + /** + * @extensions: Zero-terminated chain of extensions. + * + * I915_CONTEXT_CREATE_EXT_SETPARAM: + * Context parameter to set or query during context creation. + * See struct drm_i915_gem_context_create_ext_setparam. + * + * I915_CONTEXT_CREATE_EXT_CLONE: + * This extension has been removed. On the off chance someone somewhere + * has attempted to use it, never re-use this extension number. + */ + __u64 extensions; +#define I915_CONTEXT_CREATE_EXT_SETPARAM 0 +#define I915_CONTEXT_CREATE_EXT_CLONE 1 +}; + +/** + * struct drm_i915_gem_context_param - Context parameter to set or query. + */ +struct drm_i915_gem_context_param { + /** @ctx_id: Context id */ + __u32 ctx_id; + + /** @size: Size of the parameter @value */ + __u32 size; + + /** @param: Parameter to set or query */ + __u64 param; +#define I915_CONTEXT_PARAM_BAN_PERIOD 0x1 +/* I915_CONTEXT_PARAM_NO_ZEROMAP has been removed. On the off chance + * someone somewhere has attempted to use it, never re-use this context + * param number. + */ +#define I915_CONTEXT_PARAM_NO_ZEROMAP 0x2 +#define I915_CONTEXT_PARAM_GTT_SIZE 0x3 +#define I915_CONTEXT_PARAM_NO_ERROR_CAPTURE 0x4 +#define I915_CONTEXT_PARAM_BANNABLE 0x5 +#define I915_CONTEXT_PARAM_PRIORITY 0x6 +#define I915_CONTEXT_MAX_USER_PRIORITY 1023 /* inclusive */ +#define I915_CONTEXT_DEFAULT_PRIORITY 0 +#define I915_CONTEXT_MIN_USER_PRIORITY -1023 /* inclusive */ + /* + * When using the following param, value should be a pointer to + * drm_i915_gem_context_param_sseu. + */ +#define I915_CONTEXT_PARAM_SSEU 0x7 + +/* + * Not all clients may want to attempt automatic recover of a context after + * a hang (for example, some clients may only submit very small incremental + * batches relying on known logical state of previous batches which will never + * recover correctly and each attempt will hang), and so would prefer that + * the context is forever banned instead. + * + * If set to false (0), after a reset, subsequent (and in flight) rendering + * from this context is discarded, and the client will need to create a new + * context to use instead. + * + * If set to true (1), the kernel will automatically attempt to recover the + * context by skipping the hanging batch and executing the next batch starting + * from the default context state (discarding the incomplete logical context + * state lost due to the reset). + * + * On creation, all new contexts are marked as recoverable. + */ +#define I915_CONTEXT_PARAM_RECOVERABLE 0x8 + + /* + * The id of the associated virtual memory address space (ppGTT) of + * this context. Can be retrieved and passed to another context + * (on the same fd) for both to use the same ppGTT and so share + * address layouts, and avoid reloading the page tables on context + * switches between themselves. + * + * See DRM_I915_GEM_VM_CREATE and DRM_I915_GEM_VM_DESTROY. + */ +#define I915_CONTEXT_PARAM_VM 0x9 + +/* + * I915_CONTEXT_PARAM_ENGINES: + * + * Bind this context to operate on this subset of available engines. Henceforth, + * the I915_EXEC_RING selector for DRM_IOCTL_I915_GEM_EXECBUFFER2 operates as + * an index into this array of engines; I915_EXEC_DEFAULT selecting engine[0] + * and upwards. Slots 0...N are filled in using the specified (class, instance). + * Use + * engine_class: I915_ENGINE_CLASS_INVALID, + * engine_instance: I915_ENGINE_CLASS_INVALID_NONE + * to specify a gap in the array that can be filled in later, e.g. by a + * virtual engine used for load balancing. + * + * Setting the number of engines bound to the context to 0, by passing a zero + * sized argument, will revert back to default settings. + * + * See struct i915_context_param_engines. + * + * Extensions: + * i915_context_engines_load_balance (I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE) + * i915_context_engines_bond (I915_CONTEXT_ENGINES_EXT_BOND) + * i915_context_engines_parallel_submit (I915_CONTEXT_ENGINES_EXT_PARALLEL_SUBMIT) + */ +#define I915_CONTEXT_PARAM_ENGINES 0xa + +/* + * I915_CONTEXT_PARAM_PERSISTENCE: + * + * Allow the context and active rendering to survive the process until + * completion. Persistence allows fire-and-forget clients to queue up a + * bunch of work, hand the output over to a display server and then quit. + * If the context is marked as not persistent, upon closing (either via + * an explicit DRM_I915_GEM_CONTEXT_DESTROY or implicitly from file closure + * or process termination), the context and any outstanding requests will be + * cancelled (and exported fences for cancelled requests marked as -EIO). + * + * By default, new contexts allow persistence. + */ +#define I915_CONTEXT_PARAM_PERSISTENCE 0xb + +/* This API has been removed. On the off chance someone somewhere has + * attempted to use it, never re-use this context param number. + */ +#define I915_CONTEXT_PARAM_RINGSIZE 0xc + +/* + * I915_CONTEXT_PARAM_PROTECTED_CONTENT: + * + * Mark that the context makes use of protected content, which will result + * in the context being invalidated when the protected content session is. + * Given that the protected content session is killed on suspend, the device + * is kept awake for the lifetime of a protected context, so the user should + * make sure to dispose of them once done. + * This flag can only be set at context creation time and, when set to true, + * must be preceded by an explicit setting of I915_CONTEXT_PARAM_RECOVERABLE + * to false. This flag can't be set to true in conjunction with setting the + * I915_CONTEXT_PARAM_BANNABLE flag to false. Creation example: + * + * .. code-block:: C + * + * struct drm_i915_gem_context_create_ext_setparam p_protected = { + * .base = { + * .name = I915_CONTEXT_CREATE_EXT_SETPARAM, + * }, + * .param = { + * .param = I915_CONTEXT_PARAM_PROTECTED_CONTENT, + * .value = 1, + * } + * }; + * struct drm_i915_gem_context_create_ext_setparam p_norecover = { + * .base = { + * .name = I915_CONTEXT_CREATE_EXT_SETPARAM, + * .next_extension = to_user_pointer(&p_protected), + * }, + * .param = { + * .param = I915_CONTEXT_PARAM_RECOVERABLE, + * .value = 0, + * } + * }; + * struct drm_i915_gem_context_create_ext create = { + * .flags = I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS, + * .extensions = to_user_pointer(&p_norecover); + * }; + * + * ctx_id = gem_context_create_ext(drm_fd, &create); + * + * In addition to the normal failure cases, setting this flag during context + * creation can result in the following errors: + * + * -ENODEV: feature not available + * -EPERM: trying to mark a recoverable or not bannable context as protected + */ +#define I915_CONTEXT_PARAM_PROTECTED_CONTENT 0xd +/* Must be kept compact -- no holes and well documented */ + + /** @value: Context parameter value to be set or queried */ + __u64 value; +}; + +/* + * Context SSEU programming + * + * It may be necessary for either functional or performance reason to configure + * a context to run with a reduced number of SSEU (where SSEU stands for Slice/ + * Sub-slice/EU). + * + * This is done by configuring SSEU configuration using the below + * @struct drm_i915_gem_context_param_sseu for every supported engine which + * userspace intends to use. + * + * Not all GPUs or engines support this functionality in which case an error + * code -ENODEV will be returned. + * + * Also, flexibility of possible SSEU configuration permutations varies between + * GPU generations and software imposed limitations. Requesting such a + * combination will return an error code of -EINVAL. + * + * NOTE: When perf/OA is active the context's SSEU configuration is ignored in + * favour of a single global setting. + */ +struct drm_i915_gem_context_param_sseu { + /* + * Engine class & instance to be configured or queried. + */ + struct i915_engine_class_instance engine; + + /* + * Unknown flags must be cleared to zero. + */ + __u32 flags; +#define I915_CONTEXT_SSEU_FLAG_ENGINE_INDEX (1u << 0) + + /* + * Mask of slices to enable for the context. Valid values are a subset + * of the bitmask value returned for I915_PARAM_SLICE_MASK. + */ + __u64 slice_mask; + + /* + * Mask of subslices to enable for the context. Valid values are a + * subset of the bitmask value return by I915_PARAM_SUBSLICE_MASK. + */ + __u64 subslice_mask; + + /* + * Minimum/Maximum number of EUs to enable per subslice for the + * context. min_eus_per_subslice must be inferior or equal to + * max_eus_per_subslice. + */ + __u16 min_eus_per_subslice; + __u16 max_eus_per_subslice; + + /* + * Unused for now. Must be cleared to zero. + */ + __u32 rsvd; +}; + +/** + * DOC: Virtual Engine uAPI + * + * Virtual engine is a concept where userspace is able to configure a set of + * physical engines, submit a batch buffer, and let the driver execute it on any + * engine from the set as it sees fit. + * + * This is primarily useful on parts which have multiple instances of a same + * class engine, like for example GT3+ Skylake parts with their two VCS engines. + * + * For instance userspace can enumerate all engines of a certain class using the + * previously described `Engine Discovery uAPI`_. After that userspace can + * create a GEM context with a placeholder slot for the virtual engine (using + * `I915_ENGINE_CLASS_INVALID` and `I915_ENGINE_CLASS_INVALID_NONE` for class + * and instance respectively) and finally using the + * `I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE` extension place a virtual engine in + * the same reserved slot. + * + * Example of creating a virtual engine and submitting a batch buffer to it: + * + * .. code-block:: C + * + * I915_DEFINE_CONTEXT_ENGINES_LOAD_BALANCE(virtual, 2) = { + * .base.name = I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE, + * .engine_index = 0, // Place this virtual engine into engine map slot 0 + * .num_siblings = 2, + * .engines = { { I915_ENGINE_CLASS_VIDEO, 0 }, + * { I915_ENGINE_CLASS_VIDEO, 1 }, }, + * }; + * I915_DEFINE_CONTEXT_PARAM_ENGINES(engines, 1) = { + * .engines = { { I915_ENGINE_CLASS_INVALID, + * I915_ENGINE_CLASS_INVALID_NONE } }, + * .extensions = to_user_pointer(&virtual), // Chains after load_balance extension + * }; + * struct drm_i915_gem_context_create_ext_setparam p_engines = { + * .base = { + * .name = I915_CONTEXT_CREATE_EXT_SETPARAM, + * }, + * .param = { + * .param = I915_CONTEXT_PARAM_ENGINES, + * .value = to_user_pointer(&engines), + * .size = sizeof(engines), + * }, + * }; + * struct drm_i915_gem_context_create_ext create = { + * .flags = I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS, + * .extensions = to_user_pointer(&p_engines); + * }; + * + * ctx_id = gem_context_create_ext(drm_fd, &create); + * + * // Now we have created a GEM context with its engine map containing a + * // single virtual engine. Submissions to this slot can go either to + * // vcs0 or vcs1, depending on the load balancing algorithm used inside + * // the driver. The load balancing is dynamic from one batch buffer to + * // another and transparent to userspace. + * + * ... + * execbuf.rsvd1 = ctx_id; + * execbuf.flags = 0; // Submits to index 0 which is the virtual engine + * gem_execbuf(drm_fd, &execbuf); + */ + +/* + * i915_context_engines_load_balance: + * + * Enable load balancing across this set of engines. + * + * Into the I915_EXEC_DEFAULT slot [0], a virtual engine is created that when + * used will proxy the execbuffer request onto one of the set of engines + * in such a way as to distribute the load evenly across the set. + * + * The set of engines must be compatible (e.g. the same HW class) as they + * will share the same logical GPU context and ring. + * + * To intermix rendering with the virtual engine and direct rendering onto + * the backing engines (bypassing the load balancing proxy), the context must + * be defined to use a single timeline for all engines. + */ +struct i915_context_engines_load_balance { + struct i915_user_extension base; + + __u16 engine_index; + __u16 num_siblings; + __u32 flags; /* all undefined flags must be zero */ + + __u64 mbz64; /* reserved for future use; must be zero */ + + struct i915_engine_class_instance engines[]; +} __attribute__((packed)); + +#define I915_DEFINE_CONTEXT_ENGINES_LOAD_BALANCE(name__, N__) struct { \ + struct i915_user_extension base; \ + __u16 engine_index; \ + __u16 num_siblings; \ + __u32 flags; \ + __u64 mbz64; \ + struct i915_engine_class_instance engines[N__]; \ +} __attribute__((packed)) name__ + +/* + * i915_context_engines_bond: + * + * Constructed bonded pairs for execution within a virtual engine. + * + * All engines are equal, but some are more equal than others. Given + * the distribution of resources in the HW, it may be preferable to run + * a request on a given subset of engines in parallel to a request on a + * specific engine. We enable this selection of engines within a virtual + * engine by specifying bonding pairs, for any given master engine we will + * only execute on one of the corresponding siblings within the virtual engine. + * + * To execute a request in parallel on the master engine and a sibling requires + * coordination with a I915_EXEC_FENCE_SUBMIT. + */ +struct i915_context_engines_bond { + struct i915_user_extension base; + + struct i915_engine_class_instance master; + + __u16 virtual_index; /* index of virtual engine in ctx->engines[] */ + __u16 num_bonds; + + __u64 flags; /* all undefined flags must be zero */ + __u64 mbz64[4]; /* reserved for future use; must be zero */ + + struct i915_engine_class_instance engines[]; +} __attribute__((packed)); + +#define I915_DEFINE_CONTEXT_ENGINES_BOND(name__, N__) struct { \ + struct i915_user_extension base; \ + struct i915_engine_class_instance master; \ + __u16 virtual_index; \ + __u16 num_bonds; \ + __u64 flags; \ + __u64 mbz64[4]; \ + struct i915_engine_class_instance engines[N__]; \ +} __attribute__((packed)) name__ + +/** + * struct i915_context_engines_parallel_submit - Configure engine for + * parallel submission. + * + * Setup a slot in the context engine map to allow multiple BBs to be submitted + * in a single execbuf IOCTL. Those BBs will then be scheduled to run on the GPU + * in parallel. Multiple hardware contexts are created internally in the i915 to + * run these BBs. Once a slot is configured for N BBs only N BBs can be + * submitted in each execbuf IOCTL and this is implicit behavior e.g. The user + * doesn't tell the execbuf IOCTL there are N BBs, the execbuf IOCTL knows how + * many BBs there are based on the slot's configuration. The N BBs are the last + * N buffer objects or first N if I915_EXEC_BATCH_FIRST is set. + * + * The default placement behavior is to create implicit bonds between each + * context if each context maps to more than 1 physical engine (e.g. context is + * a virtual engine). Also we only allow contexts of same engine class and these + * contexts must be in logically contiguous order. Examples of the placement + * behavior are described below. Lastly, the default is to not allow BBs to be + * preempted mid-batch. Rather insert coordinated preemption points on all + * hardware contexts between each set of BBs. Flags could be added in the future + * to change both of these default behaviors. + * + * Returns -EINVAL if hardware context placement configuration is invalid or if + * the placement configuration isn't supported on the platform / submission + * interface. + * Returns -ENODEV if extension isn't supported on the platform / submission + * interface. + * + * .. code-block:: none + * + * Examples syntax: + * CS[X] = generic engine of same class, logical instance X + * INVALID = I915_ENGINE_CLASS_INVALID, I915_ENGINE_CLASS_INVALID_NONE + * + * Example 1 pseudo code: + * set_engines(INVALID) + * set_parallel(engine_index=0, width=2, num_siblings=1, + * engines=CS[0],CS[1]) + * + * Results in the following valid placement: + * CS[0], CS[1] + * + * Example 2 pseudo code: + * set_engines(INVALID) + * set_parallel(engine_index=0, width=2, num_siblings=2, + * engines=CS[0],CS[2],CS[1],CS[3]) + * + * Results in the following valid placements: + * CS[0], CS[1] + * CS[2], CS[3] + * + * This can be thought of as two virtual engines, each containing two + * engines thereby making a 2D array. However, there are bonds tying the + * entries together and placing restrictions on how they can be scheduled. + * Specifically, the scheduler can choose only vertical columns from the 2D + * array. That is, CS[0] is bonded to CS[1] and CS[2] to CS[3]. So if the + * scheduler wants to submit to CS[0], it must also choose CS[1] and vice + * versa. Same for CS[2] requires also using CS[3]. + * VE[0] = CS[0], CS[2] + * VE[1] = CS[1], CS[3] + * + * Example 3 pseudo code: + * set_engines(INVALID) + * set_parallel(engine_index=0, width=2, num_siblings=2, + * engines=CS[0],CS[1],CS[1],CS[3]) + * + * Results in the following valid and invalid placements: + * CS[0], CS[1] + * CS[1], CS[3] - Not logically contiguous, return -EINVAL + */ +struct i915_context_engines_parallel_submit { + /** + * @base: base user extension. + */ + struct i915_user_extension base; + + /** + * @engine_index: slot for parallel engine + */ + __u16 engine_index; + + /** + * @width: number of contexts per parallel engine or in other words the + * number of batches in each submission + */ + __u16 width; + + /** + * @num_siblings: number of siblings per context or in other words the + * number of possible placements for each submission + */ + __u16 num_siblings; + + /** + * @mbz16: reserved for future use; must be zero + */ + __u16 mbz16; + + /** + * @flags: all undefined flags must be zero, currently not defined flags + */ + __u64 flags; + + /** + * @mbz64: reserved for future use; must be zero + */ + __u64 mbz64[3]; + + /** + * @engines: 2-d array of engine instances to configure parallel engine + * + * length = width (i) * num_siblings (j) + * index = j + i * num_siblings + */ + struct i915_engine_class_instance engines[]; + +} __attribute__((packed)); + +#define I915_DEFINE_CONTEXT_ENGINES_PARALLEL_SUBMIT(name__, N__) struct { \ + struct i915_user_extension base; \ + __u16 engine_index; \ + __u16 width; \ + __u16 num_siblings; \ + __u16 mbz16; \ + __u64 flags; \ + __u64 mbz64[3]; \ + struct i915_engine_class_instance engines[N__]; \ +} __attribute__((packed)) name__ + +/** + * DOC: Context Engine Map uAPI + * + * Context engine map is a new way of addressing engines when submitting batch- + * buffers, replacing the existing way of using identifiers like `I915_EXEC_BLT` + * inside the flags field of `struct drm_i915_gem_execbuffer2`. + * + * To use it created GEM contexts need to be configured with a list of engines + * the user is intending to submit to. This is accomplished using the + * `I915_CONTEXT_PARAM_ENGINES` parameter and `struct + * i915_context_param_engines`. + * + * For such contexts the `I915_EXEC_RING_MASK` field becomes an index into the + * configured map. + * + * Example of creating such context and submitting against it: + * + * .. code-block:: C + * + * I915_DEFINE_CONTEXT_PARAM_ENGINES(engines, 2) = { + * .engines = { { I915_ENGINE_CLASS_RENDER, 0 }, + * { I915_ENGINE_CLASS_COPY, 0 } } + * }; + * struct drm_i915_gem_context_create_ext_setparam p_engines = { + * .base = { + * .name = I915_CONTEXT_CREATE_EXT_SETPARAM, + * }, + * .param = { + * .param = I915_CONTEXT_PARAM_ENGINES, + * .value = to_user_pointer(&engines), + * .size = sizeof(engines), + * }, + * }; + * struct drm_i915_gem_context_create_ext create = { + * .flags = I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS, + * .extensions = to_user_pointer(&p_engines); + * }; + * + * ctx_id = gem_context_create_ext(drm_fd, &create); + * + * // We have now created a GEM context with two engines in the map: + * // Index 0 points to rcs0 while index 1 points to bcs0. Other engines + * // will not be accessible from this context. + * + * ... + * execbuf.rsvd1 = ctx_id; + * execbuf.flags = 0; // Submits to index 0, which is rcs0 for this context + * gem_execbuf(drm_fd, &execbuf); + * + * ... + * execbuf.rsvd1 = ctx_id; + * execbuf.flags = 1; // Submits to index 0, which is bcs0 for this context + * gem_execbuf(drm_fd, &execbuf); + */ + +struct i915_context_param_engines { + __u64 extensions; /* linked chain of extension blocks, 0 terminates */ +#define I915_CONTEXT_ENGINES_EXT_LOAD_BALANCE 0 /* see i915_context_engines_load_balance */ +#define I915_CONTEXT_ENGINES_EXT_BOND 1 /* see i915_context_engines_bond */ +#define I915_CONTEXT_ENGINES_EXT_PARALLEL_SUBMIT 2 /* see i915_context_engines_parallel_submit */ + struct i915_engine_class_instance engines[0]; +} __attribute__((packed)); + +#define I915_DEFINE_CONTEXT_PARAM_ENGINES(name__, N__) struct { \ + __u64 extensions; \ + struct i915_engine_class_instance engines[N__]; \ +} __attribute__((packed)) name__ + +/** + * struct drm_i915_gem_context_create_ext_setparam - Context parameter + * to set or query during context creation. + */ +struct drm_i915_gem_context_create_ext_setparam { + /** @base: Extension link. See struct i915_user_extension. */ + struct i915_user_extension base; + + /** + * @param: Context parameter to set or query. + * See struct drm_i915_gem_context_param. + */ + struct drm_i915_gem_context_param param; +}; + +struct drm_i915_gem_context_destroy { + __u32 ctx_id; + __u32 pad; +}; + +/** + * struct drm_i915_gem_vm_control - Structure to create or destroy VM. + * + * DRM_I915_GEM_VM_CREATE - + * + * Create a new virtual memory address space (ppGTT) for use within a context + * on the same file. Extensions can be provided to configure exactly how the + * address space is setup upon creation. + * + * The id of new VM (bound to the fd) for use with I915_CONTEXT_PARAM_VM is + * returned in the outparam @id. + * + * An extension chain maybe provided, starting with @extensions, and terminated + * by the @next_extension being 0. Currently, no extensions are defined. + * + * DRM_I915_GEM_VM_DESTROY - + * + * Destroys a previously created VM id, specified in @vm_id. + * + * No extensions or flags are allowed currently, and so must be zero. + */ +struct drm_i915_gem_vm_control { + /** @extensions: Zero-terminated chain of extensions. */ + __u64 extensions; + + /** @flags: reserved for future usage, currently MBZ */ + __u32 flags; + + /** @vm_id: Id of the VM created or to be destroyed */ + __u32 vm_id; +}; + +struct drm_i915_reg_read { + /* + * Register offset. + * For 64bit wide registers where the upper 32bits don't immediately + * follow the lower 32bits, the offset of the lower 32bits must + * be specified + */ + __u64 offset; +#define I915_REG_READ_8B_WA (1ul << 0) + + __u64 val; /* Return value */ +}; + +/* Known registers: + * + * Render engine timestamp - 0x2358 + 64bit - gen7+ + * - Note this register returns an invalid value if using the default + * single instruction 8byte read, in order to workaround that pass + * flag I915_REG_READ_8B_WA in offset field. + * + */ + +struct drm_i915_reset_stats { + __u32 ctx_id; + __u32 flags; + + /* All resets since boot/module reload, for all contexts */ + __u32 reset_count; + + /* Number of batches lost when active in GPU, for this context */ + __u32 batch_active; + + /* Number of batches lost pending for execution, for this context */ + __u32 batch_pending; + + __u32 pad; +}; + +/** + * struct drm_i915_gem_userptr - Create GEM object from user allocated memory. + * + * Userptr objects have several restrictions on what ioctls can be used with the + * object handle. + */ +struct drm_i915_gem_userptr { + /** + * @user_ptr: The pointer to the allocated memory. + * + * Needs to be aligned to PAGE_SIZE. + */ + __u64 user_ptr; + + /** + * @user_size: + * + * The size in bytes for the allocated memory. This will also become the + * object size. + * + * Needs to be aligned to PAGE_SIZE, and should be at least PAGE_SIZE, + * or larger. + */ + __u64 user_size; + + /** + * @flags: + * + * Supported flags: + * + * I915_USERPTR_READ_ONLY: + * + * Mark the object as readonly, this also means GPU access can only be + * readonly. This is only supported on HW which supports readonly access + * through the GTT. If the HW can't support readonly access, an error is + * returned. + * + * I915_USERPTR_PROBE: + * + * Probe the provided @user_ptr range and validate that the @user_ptr is + * indeed pointing to normal memory and that the range is also valid. + * For example if some garbage address is given to the kernel, then this + * should complain. + * + * Returns -EFAULT if the probe failed. + * + * Note that this doesn't populate the backing pages, and also doesn't + * guarantee that the object will remain valid when the object is + * eventually used. + * + * The kernel supports this feature if I915_PARAM_HAS_USERPTR_PROBE + * returns a non-zero value. + * + * I915_USERPTR_UNSYNCHRONIZED: + * + * NOT USED. Setting this flag will result in an error. + */ + __u32 flags; +#define I915_USERPTR_READ_ONLY 0x1 +#define I915_USERPTR_PROBE 0x2 +#define I915_USERPTR_UNSYNCHRONIZED 0x80000000 + /** + * @handle: Returned handle for the object. + * + * Object handles are nonzero. + */ + __u32 handle; +}; + +enum drm_i915_oa_format { + I915_OA_FORMAT_A13 = 1, /* HSW only */ + I915_OA_FORMAT_A29, /* HSW only */ + I915_OA_FORMAT_A13_B8_C8, /* HSW only */ + I915_OA_FORMAT_B4_C8, /* HSW only */ + I915_OA_FORMAT_A45_B8_C8, /* HSW only */ + I915_OA_FORMAT_B4_C8_A16, /* HSW only */ + I915_OA_FORMAT_C4_B8, /* HSW+ */ + + /* Gen8+ */ + I915_OA_FORMAT_A12, + I915_OA_FORMAT_A12_B8_C8, + I915_OA_FORMAT_A32u40_A4u32_B8_C8, + + I915_OA_FORMAT_MAX /* non-ABI */ +}; + +enum drm_i915_perf_property_id { + /** + * Open the stream for a specific context handle (as used with + * execbuffer2). A stream opened for a specific context this way + * won't typically require root privileges. + * + * This property is available in perf revision 1. + */ + DRM_I915_PERF_PROP_CTX_HANDLE = 1, + + /** + * A value of 1 requests the inclusion of raw OA unit reports as + * part of stream samples. + * + * This property is available in perf revision 1. + */ + DRM_I915_PERF_PROP_SAMPLE_OA, + + /** + * The value specifies which set of OA unit metrics should be + * configured, defining the contents of any OA unit reports. + * + * This property is available in perf revision 1. + */ + DRM_I915_PERF_PROP_OA_METRICS_SET, + + /** + * The value specifies the size and layout of OA unit reports. + * + * This property is available in perf revision 1. + */ + DRM_I915_PERF_PROP_OA_FORMAT, + + /** + * Specifying this property implicitly requests periodic OA unit + * sampling and (at least on Haswell) the sampling frequency is derived + * from this exponent as follows: + * + * 80ns * 2^(period_exponent + 1) + * + * This property is available in perf revision 1. + */ + DRM_I915_PERF_PROP_OA_EXPONENT, + + /** + * Specifying this property is only valid when specify a context to + * filter with DRM_I915_PERF_PROP_CTX_HANDLE. Specifying this property + * will hold preemption of the particular context we want to gather + * performance data about. The execbuf2 submissions must include a + * drm_i915_gem_execbuffer_ext_perf parameter for this to apply. + * + * This property is available in perf revision 3. + */ + DRM_I915_PERF_PROP_HOLD_PREEMPTION, + + /** + * Specifying this pins all contexts to the specified SSEU power + * configuration for the duration of the recording. + * + * This parameter's value is a pointer to a struct + * drm_i915_gem_context_param_sseu. + * + * This property is available in perf revision 4. + */ + DRM_I915_PERF_PROP_GLOBAL_SSEU, + + /** + * This optional parameter specifies the timer interval in nanoseconds + * at which the i915 driver will check the OA buffer for available data. + * Minimum allowed value is 100 microseconds. A default value is used by + * the driver if this parameter is not specified. Note that larger timer + * values will reduce cpu consumption during OA perf captures. However, + * excessively large values would potentially result in OA buffer + * overwrites as captures reach end of the OA buffer. + * + * This property is available in perf revision 5. + */ + DRM_I915_PERF_PROP_POLL_OA_PERIOD, + + DRM_I915_PERF_PROP_MAX /* non-ABI */ +}; + +struct drm_i915_perf_open_param { + __u32 flags; +#define I915_PERF_FLAG_FD_CLOEXEC (1<<0) +#define I915_PERF_FLAG_FD_NONBLOCK (1<<1) +#define I915_PERF_FLAG_DISABLED (1<<2) + + /** The number of u64 (id, value) pairs */ + __u32 num_properties; + + /** + * Pointer to array of u64 (id, value) pairs configuring the stream + * to open. + */ + __u64 properties_ptr; +}; + +/* + * Enable data capture for a stream that was either opened in a disabled state + * via I915_PERF_FLAG_DISABLED or was later disabled via + * I915_PERF_IOCTL_DISABLE. + * + * It is intended to be cheaper to disable and enable a stream than it may be + * to close and re-open a stream with the same configuration. + * + * It's undefined whether any pending data for the stream will be lost. + * + * This ioctl is available in perf revision 1. + */ +#define I915_PERF_IOCTL_ENABLE _IO('i', 0x0) + +/* + * Disable data capture for a stream. + * + * It is an error to try and read a stream that is disabled. + * + * This ioctl is available in perf revision 1. + */ +#define I915_PERF_IOCTL_DISABLE _IO('i', 0x1) + +/* + * Change metrics_set captured by a stream. + * + * If the stream is bound to a specific context, the configuration change + * will performed __inline__ with that context such that it takes effect before + * the next execbuf submission. + * + * Returns the previously bound metrics set id, or a negative error code. + * + * This ioctl is available in perf revision 2. + */ +#define I915_PERF_IOCTL_CONFIG _IO('i', 0x2) + +/* + * Common to all i915 perf records + */ +struct drm_i915_perf_record_header { + __u32 type; + __u16 pad; + __u16 size; +}; + +enum drm_i915_perf_record_type { + + /** + * Samples are the work horse record type whose contents are extensible + * and defined when opening an i915 perf stream based on the given + * properties. + * + * Boolean properties following the naming convention + * DRM_I915_PERF_SAMPLE_xyz_PROP request the inclusion of 'xyz' data in + * every sample. + * + * The order of these sample properties given by userspace has no + * affect on the ordering of data within a sample. The order is + * documented here. + * + * struct { + * struct drm_i915_perf_record_header header; + * + * { u32 oa_report[]; } && DRM_I915_PERF_PROP_SAMPLE_OA + * }; + */ + DRM_I915_PERF_RECORD_SAMPLE = 1, + + /* + * Indicates that one or more OA reports were not written by the + * hardware. This can happen for example if an MI_REPORT_PERF_COUNT + * command collides with periodic sampling - which would be more likely + * at higher sampling frequencies. + */ + DRM_I915_PERF_RECORD_OA_REPORT_LOST = 2, + + /** + * An error occurred that resulted in all pending OA reports being lost. + */ + DRM_I915_PERF_RECORD_OA_BUFFER_LOST = 3, + + DRM_I915_PERF_RECORD_MAX /* non-ABI */ +}; + +/** + * struct drm_i915_perf_oa_config + * + * Structure to upload perf dynamic configuration into the kernel. + */ +struct drm_i915_perf_oa_config { + /** + * @uuid: + * + * String formatted like "%\08x-%\04x-%\04x-%\04x-%\012x" + */ + char uuid[36]; + + /** + * @n_mux_regs: + * + * Number of mux regs in &mux_regs_ptr. + */ + __u32 n_mux_regs; + + /** + * @n_boolean_regs: + * + * Number of boolean regs in &boolean_regs_ptr. + */ + __u32 n_boolean_regs; + + /** + * @n_flex_regs: + * + * Number of flex regs in &flex_regs_ptr. + */ + __u32 n_flex_regs; + + /** + * @mux_regs_ptr: + * + * Pointer to tuples of u32 values (register address, value) for mux + * registers. Expected length of buffer is (2 * sizeof(u32) * + * &n_mux_regs). + */ + __u64 mux_regs_ptr; + + /** + * @boolean_regs_ptr: + * + * Pointer to tuples of u32 values (register address, value) for mux + * registers. Expected length of buffer is (2 * sizeof(u32) * + * &n_boolean_regs). + */ + __u64 boolean_regs_ptr; + + /** + * @flex_regs_ptr: + * + * Pointer to tuples of u32 values (register address, value) for mux + * registers. Expected length of buffer is (2 * sizeof(u32) * + * &n_flex_regs). + */ + __u64 flex_regs_ptr; +}; + +/** + * struct drm_i915_query_item - An individual query for the kernel to process. + * + * The behaviour is determined by the @query_id. Note that exactly what + * @data_ptr is also depends on the specific @query_id. + */ +struct drm_i915_query_item { + /** + * @query_id: + * + * The id for this query. Currently accepted query IDs are: + * - %DRM_I915_QUERY_TOPOLOGY_INFO (see struct drm_i915_query_topology_info) + * - %DRM_I915_QUERY_ENGINE_INFO (see struct drm_i915_engine_info) + * - %DRM_I915_QUERY_PERF_CONFIG (see struct drm_i915_query_perf_config) + * - %DRM_I915_QUERY_MEMORY_REGIONS (see struct drm_i915_query_memory_regions) + * - %DRM_I915_QUERY_HWCONFIG_BLOB (see `GuC HWCONFIG blob uAPI`) + * - %DRM_I915_QUERY_GEOMETRY_SUBSLICES (see struct drm_i915_query_topology_info) + */ + __u64 query_id; +#define DRM_I915_QUERY_TOPOLOGY_INFO 1 +#define DRM_I915_QUERY_ENGINE_INFO 2 +#define DRM_I915_QUERY_PERF_CONFIG 3 +#define DRM_I915_QUERY_MEMORY_REGIONS 4 +#define DRM_I915_QUERY_HWCONFIG_BLOB 5 +#define DRM_I915_QUERY_GEOMETRY_SUBSLICES 6 +/* Must be kept compact -- no holes and well documented */ + + /** + * @length: + * + * When set to zero by userspace, this is filled with the size of the + * data to be written at the @data_ptr pointer. The kernel sets this + * value to a negative value to signal an error on a particular query + * item. + */ + __s32 length; + + /** + * @flags: + * + * When &query_id == %DRM_I915_QUERY_TOPOLOGY_INFO, must be 0. + * + * When &query_id == %DRM_I915_QUERY_PERF_CONFIG, must be one of the + * following: + * + * - %DRM_I915_QUERY_PERF_CONFIG_LIST + * - %DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID + * - %DRM_I915_QUERY_PERF_CONFIG_FOR_UUID + * + * When &query_id == %DRM_I915_QUERY_GEOMETRY_SUBSLICES must contain + * a struct i915_engine_class_instance that references a render engine. + */ + __u32 flags; +#define DRM_I915_QUERY_PERF_CONFIG_LIST 1 +#define DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID 2 +#define DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_ID 3 + + /** + * @data_ptr: + * + * Data will be written at the location pointed by @data_ptr when the + * value of @length matches the length of the data to be written by the + * kernel. + */ + __u64 data_ptr; +}; + +/** + * struct drm_i915_query - Supply an array of struct drm_i915_query_item for the + * kernel to fill out. + * + * Note that this is generally a two step process for each struct + * drm_i915_query_item in the array: + * + * 1. Call the DRM_IOCTL_I915_QUERY, giving it our array of struct + * drm_i915_query_item, with &drm_i915_query_item.length set to zero. The + * kernel will then fill in the size, in bytes, which tells userspace how + * memory it needs to allocate for the blob(say for an array of properties). + * + * 2. Next we call DRM_IOCTL_I915_QUERY again, this time with the + * &drm_i915_query_item.data_ptr equal to our newly allocated blob. Note that + * the &drm_i915_query_item.length should still be the same as what the + * kernel previously set. At this point the kernel can fill in the blob. + * + * Note that for some query items it can make sense for userspace to just pass + * in a buffer/blob equal to or larger than the required size. In this case only + * a single ioctl call is needed. For some smaller query items this can work + * quite well. + * + */ +struct drm_i915_query { + /** @num_items: The number of elements in the @items_ptr array */ + __u32 num_items; + + /** + * @flags: Unused for now. Must be cleared to zero. + */ + __u32 flags; + + /** + * @items_ptr: + * + * Pointer to an array of struct drm_i915_query_item. The number of + * array elements is @num_items. + */ + __u64 items_ptr; +}; + +/** + * struct drm_i915_query_topology_info + * + * Describes slice/subslice/EU information queried by + * %DRM_I915_QUERY_TOPOLOGY_INFO + */ +struct drm_i915_query_topology_info { + /** + * @flags: + * + * Unused for now. Must be cleared to zero. + */ + __u16 flags; + + /** + * @max_slices: + * + * The number of bits used to express the slice mask. + */ + __u16 max_slices; + + /** + * @max_subslices: + * + * The number of bits used to express the subslice mask. + */ + __u16 max_subslices; + + /** + * @max_eus_per_subslice: + * + * The number of bits in the EU mask that correspond to a single + * subslice's EUs. + */ + __u16 max_eus_per_subslice; + + /** + * @subslice_offset: + * + * Offset in data[] at which the subslice masks are stored. + */ + __u16 subslice_offset; + + /** + * @subslice_stride: + * + * Stride at which each of the subslice masks for each slice are + * stored. + */ + __u16 subslice_stride; + + /** + * @eu_offset: + * + * Offset in data[] at which the EU masks are stored. + */ + __u16 eu_offset; + + /** + * @eu_stride: + * + * Stride at which each of the EU masks for each subslice are stored. + */ + __u16 eu_stride; + + /** + * @data: + * + * Contains 3 pieces of information : + * + * - The slice mask with one bit per slice telling whether a slice is + * available. The availability of slice X can be queried with the + * following formula : + * + * .. code:: c + * + * (data[X / 8] >> (X % 8)) & 1 + * + * Starting with Xe_HP platforms, Intel hardware no longer has + * traditional slices so i915 will always report a single slice + * (hardcoded slicemask = 0x1) which contains all of the platform's + * subslices. I.e., the mask here does not reflect any of the newer + * hardware concepts such as "gslices" or "cslices" since userspace + * is capable of inferring those from the subslice mask. + * + * - The subslice mask for each slice with one bit per subslice telling + * whether a subslice is available. Starting with Gen12 we use the + * term "subslice" to refer to what the hardware documentation + * describes as a "dual-subslices." The availability of subslice Y + * in slice X can be queried with the following formula : + * + * .. code:: c + * + * (data[subslice_offset + X * subslice_stride + Y / 8] >> (Y % 8)) & 1 + * + * - The EU mask for each subslice in each slice, with one bit per EU + * telling whether an EU is available. The availability of EU Z in + * subslice Y in slice X can be queried with the following formula : + * + * .. code:: c + * + * (data[eu_offset + + * (X * max_subslices + Y) * eu_stride + + * Z / 8 + * ] >> (Z % 8)) & 1 + */ + __u8 data[]; +}; + +/** + * DOC: Engine Discovery uAPI + * + * Engine discovery uAPI is a way of enumerating physical engines present in a + * GPU associated with an open i915 DRM file descriptor. This supersedes the old + * way of using `DRM_IOCTL_I915_GETPARAM` and engine identifiers like + * `I915_PARAM_HAS_BLT`. + * + * The need for this interface came starting with Icelake and newer GPUs, which + * started to establish a pattern of having multiple engines of a same class, + * where not all instances were always completely functionally equivalent. + * + * Entry point for this uapi is `DRM_IOCTL_I915_QUERY` with the + * `DRM_I915_QUERY_ENGINE_INFO` as the queried item id. + * + * Example for getting the list of engines: + * + * .. code-block:: C + * + * struct drm_i915_query_engine_info *info; + * struct drm_i915_query_item item = { + * .query_id = DRM_I915_QUERY_ENGINE_INFO; + * }; + * struct drm_i915_query query = { + * .num_items = 1, + * .items_ptr = (uintptr_t)&item, + * }; + * int err, i; + * + * // First query the size of the blob we need, this needs to be large + * // enough to hold our array of engines. The kernel will fill out the + * // item.length for us, which is the number of bytes we need. + * // + * // Alternatively a large buffer can be allocated straight away enabling + * // querying in one pass, in which case item.length should contain the + * // length of the provided buffer. + * err = ioctl(fd, DRM_IOCTL_I915_QUERY, &query); + * if (err) ... + * + * info = calloc(1, item.length); + * // Now that we allocated the required number of bytes, we call the ioctl + * // again, this time with the data_ptr pointing to our newly allocated + * // blob, which the kernel can then populate with info on all engines. + * item.data_ptr = (uintptr_t)&info, + * + * err = ioctl(fd, DRM_IOCTL_I915_QUERY, &query); + * if (err) ... + * + * // We can now access each engine in the array + * for (i = 0; i < info->num_engines; i++) { + * struct drm_i915_engine_info einfo = info->engines[i]; + * u16 class = einfo.engine.class; + * u16 instance = einfo.engine.instance; + * .... + * } + * + * free(info); + * + * Each of the enumerated engines, apart from being defined by its class and + * instance (see `struct i915_engine_class_instance`), also can have flags and + * capabilities defined as documented in i915_drm.h. + * + * For instance video engines which support HEVC encoding will have the + * `I915_VIDEO_CLASS_CAPABILITY_HEVC` capability bit set. + * + * Engine discovery only fully comes to its own when combined with the new way + * of addressing engines when submitting batch buffers using contexts with + * engine maps configured. + */ + +/** + * struct drm_i915_engine_info + * + * Describes one engine and it's capabilities as known to the driver. + */ +struct drm_i915_engine_info { + /** @engine: Engine class and instance. */ + struct i915_engine_class_instance engine; + + /** @rsvd0: Reserved field. */ + __u32 rsvd0; + + /** @flags: Engine flags. */ + __u64 flags; +#define I915_ENGINE_INFO_HAS_LOGICAL_INSTANCE (1 << 0) + + /** @capabilities: Capabilities of this engine. */ + __u64 capabilities; +#define I915_VIDEO_CLASS_CAPABILITY_HEVC (1 << 0) +#define I915_VIDEO_AND_ENHANCE_CLASS_CAPABILITY_SFC (1 << 1) + + /** @logical_instance: Logical instance of engine */ + __u16 logical_instance; + + /** @rsvd1: Reserved fields. */ + __u16 rsvd1[3]; + /** @rsvd2: Reserved fields. */ + __u64 rsvd2[3]; +}; + +/** + * struct drm_i915_query_engine_info + * + * Engine info query enumerates all engines known to the driver by filling in + * an array of struct drm_i915_engine_info structures. + */ +struct drm_i915_query_engine_info { + /** @num_engines: Number of struct drm_i915_engine_info structs following. */ + __u32 num_engines; + + /** @rsvd: MBZ */ + __u32 rsvd[3]; + + /** @engines: Marker for drm_i915_engine_info structures. */ + struct drm_i915_engine_info engines[]; +}; + +/** + * struct drm_i915_query_perf_config + * + * Data written by the kernel with query %DRM_I915_QUERY_PERF_CONFIG and + * %DRM_I915_QUERY_GEOMETRY_SUBSLICES. + */ +struct drm_i915_query_perf_config { + union { + /** + * @n_configs: + * + * When &drm_i915_query_item.flags == + * %DRM_I915_QUERY_PERF_CONFIG_LIST, i915 sets this fields to + * the number of configurations available. + */ + __u64 n_configs; + + /** + * @config: + * + * When &drm_i915_query_item.flags == + * %DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_ID, i915 will use the + * value in this field as configuration identifier to decide + * what data to write into config_ptr. + */ + __u64 config; + + /** + * @uuid: + * + * When &drm_i915_query_item.flags == + * %DRM_I915_QUERY_PERF_CONFIG_DATA_FOR_UUID, i915 will use the + * value in this field as configuration identifier to decide + * what data to write into config_ptr. + * + * String formatted like "%08x-%04x-%04x-%04x-%012x" + */ + char uuid[36]; + }; + + /** + * @flags: + * + * Unused for now. Must be cleared to zero. + */ + __u32 flags; + + /** + * @data: + * + * When &drm_i915_query_item.flags == %DRM_I915_QUERY_PERF_CONFIG_LIST, + * i915 will write an array of __u64 of configuration identifiers. + * + * When &drm_i915_query_item.flags == %DRM_I915_QUERY_PERF_CONFIG_DATA, + * i915 will write a struct drm_i915_perf_oa_config. If the following + * fields of struct drm_i915_perf_oa_config are not set to 0, i915 will + * write into the associated pointers the values of submitted when the + * configuration was created : + * + * - &drm_i915_perf_oa_config.n_mux_regs + * - &drm_i915_perf_oa_config.n_boolean_regs + * - &drm_i915_perf_oa_config.n_flex_regs + */ + __u8 data[]; +}; + +/** + * enum drm_i915_gem_memory_class - Supported memory classes + */ +enum drm_i915_gem_memory_class { + /** @I915_MEMORY_CLASS_SYSTEM: System memory */ + I915_MEMORY_CLASS_SYSTEM = 0, + /** @I915_MEMORY_CLASS_DEVICE: Device local-memory */ + I915_MEMORY_CLASS_DEVICE, +}; + +/** + * struct drm_i915_gem_memory_class_instance - Identify particular memory region + */ +struct drm_i915_gem_memory_class_instance { + /** @memory_class: See enum drm_i915_gem_memory_class */ + __u16 memory_class; + + /** @memory_instance: Which instance */ + __u16 memory_instance; +}; + +/** + * struct drm_i915_memory_region_info - Describes one region as known to the + * driver. + * + * Note this is using both struct drm_i915_query_item and struct drm_i915_query. + * For this new query we are adding the new query id DRM_I915_QUERY_MEMORY_REGIONS + * at &drm_i915_query_item.query_id. + */ +struct drm_i915_memory_region_info { + /** @region: The class:instance pair encoding */ + struct drm_i915_gem_memory_class_instance region; + + /** @rsvd0: MBZ */ + __u32 rsvd0; + + /** + * @probed_size: Memory probed by the driver + * + * Note that it should not be possible to ever encounter a zero value + * here, also note that no current region type will ever return -1 here. + * Although for future region types, this might be a possibility. The + * same applies to the other size fields. + */ + __u64 probed_size; + + /** + * @unallocated_size: Estimate of memory remaining + * + * Requires CAP_PERFMON or CAP_SYS_ADMIN to get reliable accounting. + * Without this (or if this is an older kernel) the value here will + * always equal the @probed_size. Note this is only currently tracked + * for I915_MEMORY_CLASS_DEVICE regions (for other types the value here + * will always equal the @probed_size). + */ + __u64 unallocated_size; + + union { + /** @rsvd1: MBZ */ + __u64 rsvd1[8]; + struct { + /** + * @probed_cpu_visible_size: Memory probed by the driver + * that is CPU accessible. + * + * This will be always be <= @probed_size, and the + * remainder (if there is any) will not be CPU + * accessible. + * + * On systems without small BAR, the @probed_size will + * always equal the @probed_cpu_visible_size, since all + * of it will be CPU accessible. + * + * Note this is only tracked for + * I915_MEMORY_CLASS_DEVICE regions (for other types the + * value here will always equal the @probed_size). + * + * Note that if the value returned here is zero, then + * this must be an old kernel which lacks the relevant + * small-bar uAPI support (including + * I915_GEM_CREATE_EXT_FLAG_NEEDS_CPU_ACCESS), but on + * such systems we should never actually end up with a + * small BAR configuration, assuming we are able to load + * the kernel module. Hence it should be safe to treat + * this the same as when @probed_cpu_visible_size == + * @probed_size. + */ + __u64 probed_cpu_visible_size; + + /** + * @unallocated_cpu_visible_size: Estimate of CPU + * visible memory remaining. + * + * Note this is only tracked for + * I915_MEMORY_CLASS_DEVICE regions (for other types the + * value here will always equal the + * @probed_cpu_visible_size). + * + * Requires CAP_PERFMON or CAP_SYS_ADMIN to get reliable + * accounting. Without this the value here will always + * equal the @probed_cpu_visible_size. Note this is only + * currently tracked for I915_MEMORY_CLASS_DEVICE + * regions (for other types the value here will also + * always equal the @probed_cpu_visible_size). + * + * If this is an older kernel the value here will be + * zero, see also @probed_cpu_visible_size. + */ + __u64 unallocated_cpu_visible_size; + }; + }; +}; + +/** + * struct drm_i915_query_memory_regions + * + * The region info query enumerates all regions known to the driver by filling + * in an array of struct drm_i915_memory_region_info structures. + * + * Example for getting the list of supported regions: + * + * .. code-block:: C + * + * struct drm_i915_query_memory_regions *info; + * struct drm_i915_query_item item = { + * .query_id = DRM_I915_QUERY_MEMORY_REGIONS; + * }; + * struct drm_i915_query query = { + * .num_items = 1, + * .items_ptr = (uintptr_t)&item, + * }; + * int err, i; + * + * // First query the size of the blob we need, this needs to be large + * // enough to hold our array of regions. The kernel will fill out the + * // item.length for us, which is the number of bytes we need. + * err = ioctl(fd, DRM_IOCTL_I915_QUERY, &query); + * if (err) ... + * + * info = calloc(1, item.length); + * // Now that we allocated the required number of bytes, we call the ioctl + * // again, this time with the data_ptr pointing to our newly allocated + * // blob, which the kernel can then populate with the all the region info. + * item.data_ptr = (uintptr_t)&info, + * + * err = ioctl(fd, DRM_IOCTL_I915_QUERY, &query); + * if (err) ... + * + * // We can now access each region in the array + * for (i = 0; i < info->num_regions; i++) { + * struct drm_i915_memory_region_info mr = info->regions[i]; + * u16 class = mr.region.class; + * u16 instance = mr.region.instance; + * + * .... + * } + * + * free(info); + */ +struct drm_i915_query_memory_regions { + /** @num_regions: Number of supported regions */ + __u32 num_regions; + + /** @rsvd: MBZ */ + __u32 rsvd[3]; + + /** @regions: Info about each supported region */ + struct drm_i915_memory_region_info regions[]; +}; + +/** + * DOC: GuC HWCONFIG blob uAPI + * + * The GuC produces a blob with information about the current device. + * i915 reads this blob from GuC and makes it available via this uAPI. + * + * The format and meaning of the blob content are documented in the + * Programmer's Reference Manual. + */ + +/** + * struct drm_i915_gem_create_ext - Existing gem_create behaviour, with added + * extension support using struct i915_user_extension. + * + * Note that new buffer flags should be added here, at least for the stuff that + * is immutable. Previously we would have two ioctls, one to create the object + * with gem_create, and another to apply various parameters, however this + * creates some ambiguity for the params which are considered immutable. Also in + * general we're phasing out the various SET/GET ioctls. + */ +struct drm_i915_gem_create_ext { + /** + * @size: Requested size for the object. + * + * The (page-aligned) allocated size for the object will be returned. + * + * DG2 64K min page size implications: + * + * On discrete platforms, starting from DG2, we have to contend with GTT + * page size restrictions when dealing with I915_MEMORY_CLASS_DEVICE + * objects. Specifically the hardware only supports 64K or larger GTT + * page sizes for such memory. The kernel will already ensure that all + * I915_MEMORY_CLASS_DEVICE memory is allocated using 64K or larger page + * sizes underneath. + * + * Note that the returned size here will always reflect any required + * rounding up done by the kernel, i.e 4K will now become 64K on devices + * such as DG2. The kernel will always select the largest minimum + * page-size for the set of possible placements as the value to use when + * rounding up the @size. + * + * Special DG2 GTT address alignment requirement: + * + * The GTT alignment will also need to be at least 2M for such objects. + * + * Note that due to how the hardware implements 64K GTT page support, we + * have some further complications: + * + * 1) The entire PDE (which covers a 2MB virtual address range), must + * contain only 64K PTEs, i.e mixing 4K and 64K PTEs in the same + * PDE is forbidden by the hardware. + * + * 2) We still need to support 4K PTEs for I915_MEMORY_CLASS_SYSTEM + * objects. + * + * To keep things simple for userland, we mandate that any GTT mappings + * must be aligned to and rounded up to 2MB. The kernel will internally + * pad them out to the next 2MB boundary. As this only wastes virtual + * address space and avoids userland having to copy any needlessly + * complicated PDE sharing scheme (coloring) and only affects DG2, this + * is deemed to be a good compromise. + */ + __u64 size; + + /** + * @handle: Returned handle for the object. + * + * Object handles are nonzero. + */ + __u32 handle; + + /** + * @flags: Optional flags. + * + * Supported values: + * + * I915_GEM_CREATE_EXT_FLAG_NEEDS_CPU_ACCESS - Signal to the kernel that + * the object will need to be accessed via the CPU. + * + * Only valid when placing objects in I915_MEMORY_CLASS_DEVICE, and only + * strictly required on configurations where some subset of the device + * memory is directly visible/mappable through the CPU (which we also + * call small BAR), like on some DG2+ systems. Note that this is quite + * undesirable, but due to various factors like the client CPU, BIOS etc + * it's something we can expect to see in the wild. See + * &drm_i915_memory_region_info.probed_cpu_visible_size for how to + * determine if this system applies. + * + * Note that one of the placements MUST be I915_MEMORY_CLASS_SYSTEM, to + * ensure the kernel can always spill the allocation to system memory, + * if the object can't be allocated in the mappable part of + * I915_MEMORY_CLASS_DEVICE. + * + * Also note that since the kernel only supports flat-CCS on objects + * that can *only* be placed in I915_MEMORY_CLASS_DEVICE, we therefore + * don't support I915_GEM_CREATE_EXT_FLAG_NEEDS_CPU_ACCESS together with + * flat-CCS. + * + * Without this hint, the kernel will assume that non-mappable + * I915_MEMORY_CLASS_DEVICE is preferred for this object. Note that the + * kernel can still migrate the object to the mappable part, as a last + * resort, if userspace ever CPU faults this object, but this might be + * expensive, and so ideally should be avoided. + * + * On older kernels which lack the relevant small-bar uAPI support (see + * also &drm_i915_memory_region_info.probed_cpu_visible_size), + * usage of the flag will result in an error, but it should NEVER be + * possible to end up with a small BAR configuration, assuming we can + * also successfully load the i915 kernel module. In such cases the + * entire I915_MEMORY_CLASS_DEVICE region will be CPU accessible, and as + * such there are zero restrictions on where the object can be placed. + */ +#define I915_GEM_CREATE_EXT_FLAG_NEEDS_CPU_ACCESS (1 << 0) + __u32 flags; + + /** + * @extensions: The chain of extensions to apply to this object. + * + * This will be useful in the future when we need to support several + * different extensions, and we need to apply more than one when + * creating the object. See struct i915_user_extension. + * + * If we don't supply any extensions then we get the same old gem_create + * behaviour. + * + * For I915_GEM_CREATE_EXT_MEMORY_REGIONS usage see + * struct drm_i915_gem_create_ext_memory_regions. + * + * For I915_GEM_CREATE_EXT_PROTECTED_CONTENT usage see + * struct drm_i915_gem_create_ext_protected_content. + */ +#define I915_GEM_CREATE_EXT_MEMORY_REGIONS 0 +#define I915_GEM_CREATE_EXT_PROTECTED_CONTENT 1 + __u64 extensions; +}; + +/** + * struct drm_i915_gem_create_ext_memory_regions - The + * I915_GEM_CREATE_EXT_MEMORY_REGIONS extension. + * + * Set the object with the desired set of placements/regions in priority + * order. Each entry must be unique and supported by the device. + * + * This is provided as an array of struct drm_i915_gem_memory_class_instance, or + * an equivalent layout of class:instance pair encodings. See struct + * drm_i915_query_memory_regions and DRM_I915_QUERY_MEMORY_REGIONS for how to + * query the supported regions for a device. + * + * As an example, on discrete devices, if we wish to set the placement as + * device local-memory we can do something like: + * + * .. code-block:: C + * + * struct drm_i915_gem_memory_class_instance region_lmem = { + * .memory_class = I915_MEMORY_CLASS_DEVICE, + * .memory_instance = 0, + * }; + * struct drm_i915_gem_create_ext_memory_regions regions = { + * .base = { .name = I915_GEM_CREATE_EXT_MEMORY_REGIONS }, + * .regions = (uintptr_t)®ion_lmem, + * .num_regions = 1, + * }; + * struct drm_i915_gem_create_ext create_ext = { + * .size = 16 * PAGE_SIZE, + * .extensions = (uintptr_t)®ions, + * }; + * + * int err = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE_EXT, &create_ext); + * if (err) ... + * + * At which point we get the object handle in &drm_i915_gem_create_ext.handle, + * along with the final object size in &drm_i915_gem_create_ext.size, which + * should account for any rounding up, if required. + * + * Note that userspace has no means of knowing the current backing region + * for objects where @num_regions is larger than one. The kernel will only + * ensure that the priority order of the @regions array is honoured, either + * when initially placing the object, or when moving memory around due to + * memory pressure + * + * On Flat-CCS capable HW, compression is supported for the objects residing + * in I915_MEMORY_CLASS_DEVICE. When such objects (compressed) have other + * memory class in @regions and migrated (by i915, due to memory + * constraints) to the non I915_MEMORY_CLASS_DEVICE region, then i915 needs to + * decompress the content. But i915 doesn't have the required information to + * decompress the userspace compressed objects. + * + * So i915 supports Flat-CCS, on the objects which can reside only on + * I915_MEMORY_CLASS_DEVICE regions. + */ +struct drm_i915_gem_create_ext_memory_regions { + /** @base: Extension link. See struct i915_user_extension. */ + struct i915_user_extension base; + + /** @pad: MBZ */ + __u32 pad; + /** @num_regions: Number of elements in the @regions array. */ + __u32 num_regions; + /** + * @regions: The regions/placements array. + * + * An array of struct drm_i915_gem_memory_class_instance. + */ + __u64 regions; +}; + +/** + * struct drm_i915_gem_create_ext_protected_content - The + * I915_OBJECT_PARAM_PROTECTED_CONTENT extension. + * + * If this extension is provided, buffer contents are expected to be protected + * by PXP encryption and require decryption for scan out and processing. This + * is only possible on platforms that have PXP enabled, on all other scenarios + * using this extension will cause the ioctl to fail and return -ENODEV. The + * flags parameter is reserved for future expansion and must currently be set + * to zero. + * + * The buffer contents are considered invalid after a PXP session teardown. + * + * The encryption is guaranteed to be processed correctly only if the object + * is submitted with a context created using the + * I915_CONTEXT_PARAM_PROTECTED_CONTENT flag. This will also enable extra checks + * at submission time on the validity of the objects involved. + * + * Below is an example on how to create a protected object: + * + * .. code-block:: C + * + * struct drm_i915_gem_create_ext_protected_content protected_ext = { + * .base = { .name = I915_GEM_CREATE_EXT_PROTECTED_CONTENT }, + * .flags = 0, + * }; + * struct drm_i915_gem_create_ext create_ext = { + * .size = PAGE_SIZE, + * .extensions = (uintptr_t)&protected_ext, + * }; + * + * int err = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE_EXT, &create_ext); + * if (err) ... + */ +struct drm_i915_gem_create_ext_protected_content { + /** @base: Extension link. See struct i915_user_extension. */ + struct i915_user_extension base; + /** @flags: reserved for future usage, currently MBZ */ + __u32 flags; +}; + +/* ID of the protected content session managed by i915 when PXP is active */ +#define I915_PROTECTED_CONTENT_DEFAULT_SESSION 0xf + +#if defined(__cplusplus) +} +#endif + +#endif /* _I915_DRM_H_ */ diff --git a/include/drm/mach64_drm.h b/include/drm/mach64_drm.h new file mode 100644 index 0000000..1f5fd84 --- /dev/null +++ b/include/drm/mach64_drm.h @@ -0,0 +1,256 @@ +/* mach64_drm.h -- Public header for the mach64 driver -*- linux-c -*- + * Created: Thu Nov 30 20:04:32 2000 by gareth@valinux.com + */ +/* + * Copyright 2000 Gareth Hughes + * Copyright 2002 Frank C. Earl + * Copyright 2002-2003 Leif Delgass + * 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, 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT OWNER(S) 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. + * + * Authors: + * Gareth Hughes + * Frank C. Earl + * Leif Delgass + */ + +#ifndef __MACH64_DRM_H__ +#define __MACH64_DRM_H__ + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the Xserver file (mach64_sarea.h) + */ +#ifndef __MACH64_SAREA_DEFINES__ +#define __MACH64_SAREA_DEFINES__ + +/* What needs to be changed for the current vertex buffer? + * GH: We're going to be pedantic about this. We want the card to do as + * little as possible, so let's avoid having it fetch a whole bunch of + * register values that don't change all that often, if at all. + */ +#define MACH64_UPLOAD_DST_OFF_PITCH 0x0001 +#define MACH64_UPLOAD_Z_OFF_PITCH 0x0002 +#define MACH64_UPLOAD_Z_ALPHA_CNTL 0x0004 +#define MACH64_UPLOAD_SCALE_3D_CNTL 0x0008 +#define MACH64_UPLOAD_DP_FOG_CLR 0x0010 +#define MACH64_UPLOAD_DP_WRITE_MASK 0x0020 +#define MACH64_UPLOAD_DP_PIX_WIDTH 0x0040 +#define MACH64_UPLOAD_SETUP_CNTL 0x0080 +#define MACH64_UPLOAD_MISC 0x0100 +#define MACH64_UPLOAD_TEXTURE 0x0200 +#define MACH64_UPLOAD_TEX0IMAGE 0x0400 +#define MACH64_UPLOAD_TEX1IMAGE 0x0800 +#define MACH64_UPLOAD_CLIPRECTS 0x1000 /* handled client-side */ +#define MACH64_UPLOAD_CONTEXT 0x00ff +#define MACH64_UPLOAD_ALL 0x1fff + +/* DMA buffer size + */ +#define MACH64_BUFFER_SIZE 16384 + +/* Max number of swaps allowed on the ring + * before the client must wait + */ +#define MACH64_MAX_QUEUED_FRAMES 3U + +/* Byte offsets for host blit buffer data + */ +#define MACH64_HOSTDATA_BLIT_OFFSET 104 + +/* Keep these small for testing. + */ +#define MACH64_NR_SAREA_CLIPRECTS 8 + +#define MACH64_CARD_HEAP 0 +#define MACH64_AGP_HEAP 1 +#define MACH64_NR_TEX_HEAPS 2 +#define MACH64_NR_TEX_REGIONS 64 +#define MACH64_LOG_TEX_GRANULARITY 16 + +#define MACH64_TEX_MAXLEVELS 1 + +#define MACH64_NR_CONTEXT_REGS 15 +#define MACH64_NR_TEXTURE_REGS 4 + +#endif /* __MACH64_SAREA_DEFINES__ */ + +typedef struct { + unsigned int dst_off_pitch; + + unsigned int z_off_pitch; + unsigned int z_cntl; + unsigned int alpha_tst_cntl; + + unsigned int scale_3d_cntl; + + unsigned int sc_left_right; + unsigned int sc_top_bottom; + + unsigned int dp_fog_clr; + unsigned int dp_write_mask; + unsigned int dp_pix_width; + unsigned int dp_mix; + unsigned int dp_src; + + unsigned int clr_cmp_cntl; + unsigned int gui_traj_cntl; + + unsigned int setup_cntl; + + unsigned int tex_size_pitch; + unsigned int tex_cntl; + unsigned int secondary_tex_off; + unsigned int tex_offset; +} drm_mach64_context_regs_t; + +typedef struct drm_mach64_sarea { + /* The channel for communication of state information to the kernel + * on firing a vertex dma buffer. + */ + drm_mach64_context_regs_t context_state; + unsigned int dirty; + unsigned int vertsize; + + /* The current cliprects, or a subset thereof. + */ + struct drm_clip_rect boxes[MACH64_NR_SAREA_CLIPRECTS]; + unsigned int nbox; + + /* Counters for client-side throttling of rendering clients. + */ + unsigned int frames_queued; + + /* Texture memory LRU. + */ + struct drm_tex_region tex_list[MACH64_NR_TEX_HEAPS][MACH64_NR_TEX_REGIONS + + 1]; + unsigned int tex_age[MACH64_NR_TEX_HEAPS]; + int ctx_owner; +} drm_mach64_sarea_t; + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the Xserver file (mach64_common.h) + */ + +/* Mach64 specific ioctls + * The device specific ioctl range is 0x40 to 0x79. + */ + +#define DRM_MACH64_INIT 0x00 +#define DRM_MACH64_IDLE 0x01 +#define DRM_MACH64_RESET 0x02 +#define DRM_MACH64_SWAP 0x03 +#define DRM_MACH64_CLEAR 0x04 +#define DRM_MACH64_VERTEX 0x05 +#define DRM_MACH64_BLIT 0x06 +#define DRM_MACH64_FLUSH 0x07 +#define DRM_MACH64_GETPARAM 0x08 + +#define DRM_IOCTL_MACH64_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_MACH64_INIT, drm_mach64_init_t) +#define DRM_IOCTL_MACH64_IDLE DRM_IO( DRM_COMMAND_BASE + DRM_MACH64_IDLE ) +#define DRM_IOCTL_MACH64_RESET DRM_IO( DRM_COMMAND_BASE + DRM_MACH64_RESET ) +#define DRM_IOCTL_MACH64_SWAP DRM_IO( DRM_COMMAND_BASE + DRM_MACH64_SWAP ) +#define DRM_IOCTL_MACH64_CLEAR DRM_IOW( DRM_COMMAND_BASE + DRM_MACH64_CLEAR, drm_mach64_clear_t) +#define DRM_IOCTL_MACH64_VERTEX DRM_IOW( DRM_COMMAND_BASE + DRM_MACH64_VERTEX, drm_mach64_vertex_t) +#define DRM_IOCTL_MACH64_BLIT DRM_IOW( DRM_COMMAND_BASE + DRM_MACH64_BLIT, drm_mach64_blit_t) +#define DRM_IOCTL_MACH64_FLUSH DRM_IO( DRM_COMMAND_BASE + DRM_MACH64_FLUSH ) +#define DRM_IOCTL_MACH64_GETPARAM DRM_IOWR( DRM_COMMAND_BASE + DRM_MACH64_GETPARAM, drm_mach64_getparam_t) + +/* Buffer flags for clears + */ +#define MACH64_FRONT 0x1 +#define MACH64_BACK 0x2 +#define MACH64_DEPTH 0x4 + +/* Primitive types for vertex buffers + */ +#define MACH64_PRIM_POINTS 0x00000000 +#define MACH64_PRIM_LINES 0x00000001 +#define MACH64_PRIM_LINE_LOOP 0x00000002 +#define MACH64_PRIM_LINE_STRIP 0x00000003 +#define MACH64_PRIM_TRIANGLES 0x00000004 +#define MACH64_PRIM_TRIANGLE_STRIP 0x00000005 +#define MACH64_PRIM_TRIANGLE_FAN 0x00000006 +#define MACH64_PRIM_QUADS 0x00000007 +#define MACH64_PRIM_QUAD_STRIP 0x00000008 +#define MACH64_PRIM_POLYGON 0x00000009 + +typedef enum _drm_mach64_dma_mode_t { + MACH64_MODE_DMA_ASYNC, + MACH64_MODE_DMA_SYNC, + MACH64_MODE_MMIO +} drm_mach64_dma_mode_t; + +typedef struct drm_mach64_init { + enum { + DRM_MACH64_INIT_DMA = 0x01, + DRM_MACH64_CLEANUP_DMA = 0x02 + } func; + + unsigned long sarea_priv_offset; + int is_pci; + drm_mach64_dma_mode_t dma_mode; + + unsigned int fb_bpp; + unsigned int front_offset, front_pitch; + unsigned int back_offset, back_pitch; + + unsigned int depth_bpp; + unsigned int depth_offset, depth_pitch; + + unsigned long fb_offset; + unsigned long mmio_offset; + unsigned long ring_offset; + unsigned long buffers_offset; + unsigned long agp_textures_offset; +} drm_mach64_init_t; + +typedef struct drm_mach64_clear { + unsigned int flags; + int x, y, w, h; + unsigned int clear_color; + unsigned int clear_depth; +} drm_mach64_clear_t; + +typedef struct drm_mach64_vertex { + int prim; + void *buf; /* Address of vertex buffer */ + unsigned long used; /* Number of bytes in buffer */ + int discard; /* Client finished with buffer? */ +} drm_mach64_vertex_t; + +typedef struct drm_mach64_blit { + void *buf; + int pitch; + int offset; + int format; + unsigned short x, y; + unsigned short width, height; +} drm_mach64_blit_t; + +typedef struct drm_mach64_getparam { + enum { + MACH64_PARAM_FRAMES_QUEUED = 0x01, + MACH64_PARAM_IRQ_NR = 0x02 + } param; + void *value; +} drm_mach64_getparam_t; + +#endif diff --git a/include/drm/mga_drm.h b/include/drm/mga_drm.h new file mode 100644 index 0000000..7930011 --- /dev/null +++ b/include/drm/mga_drm.h @@ -0,0 +1,427 @@ +/* mga_drm.h -- Public header for the Matrox g200/g400 driver -*- linux-c -*- + * Created: Tue Jan 25 01:50:01 1999 by jhartmann@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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, 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS 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. + * + * Authors: + * Jeff Hartmann + * Keith Whitwell + * + * Rewritten by: + * Gareth Hughes + */ + +#ifndef __MGA_DRM_H__ +#define __MGA_DRM_H__ + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the Xserver file (mga_sarea.h) + */ + +#ifndef __MGA_SAREA_DEFINES__ +#define __MGA_SAREA_DEFINES__ + +/* WARP pipe flags + */ +#define MGA_F 0x1 /* fog */ +#define MGA_A 0x2 /* alpha */ +#define MGA_S 0x4 /* specular */ +#define MGA_T2 0x8 /* multitexture */ + +#define MGA_WARP_TGZ 0 +#define MGA_WARP_TGZF (MGA_F) +#define MGA_WARP_TGZA (MGA_A) +#define MGA_WARP_TGZAF (MGA_F|MGA_A) +#define MGA_WARP_TGZS (MGA_S) +#define MGA_WARP_TGZSF (MGA_S|MGA_F) +#define MGA_WARP_TGZSA (MGA_S|MGA_A) +#define MGA_WARP_TGZSAF (MGA_S|MGA_F|MGA_A) +#define MGA_WARP_T2GZ (MGA_T2) +#define MGA_WARP_T2GZF (MGA_T2|MGA_F) +#define MGA_WARP_T2GZA (MGA_T2|MGA_A) +#define MGA_WARP_T2GZAF (MGA_T2|MGA_A|MGA_F) +#define MGA_WARP_T2GZS (MGA_T2|MGA_S) +#define MGA_WARP_T2GZSF (MGA_T2|MGA_S|MGA_F) +#define MGA_WARP_T2GZSA (MGA_T2|MGA_S|MGA_A) +#define MGA_WARP_T2GZSAF (MGA_T2|MGA_S|MGA_F|MGA_A) + +#define MGA_MAX_G200_PIPES 8 /* no multitex */ +#define MGA_MAX_G400_PIPES 16 +#define MGA_MAX_WARP_PIPES MGA_MAX_G400_PIPES +#define MGA_WARP_UCODE_SIZE 32768 /* in bytes */ + +#define MGA_CARD_TYPE_G200 1 +#define MGA_CARD_TYPE_G400 2 +#define MGA_CARD_TYPE_G450 3 /* not currently used */ +#define MGA_CARD_TYPE_G550 4 + +#define MGA_FRONT 0x1 +#define MGA_BACK 0x2 +#define MGA_DEPTH 0x4 + +/* What needs to be changed for the current vertex dma buffer? + */ +#define MGA_UPLOAD_CONTEXT 0x1 +#define MGA_UPLOAD_TEX0 0x2 +#define MGA_UPLOAD_TEX1 0x4 +#define MGA_UPLOAD_PIPE 0x8 +#define MGA_UPLOAD_TEX0IMAGE 0x10 /* handled client-side */ +#define MGA_UPLOAD_TEX1IMAGE 0x20 /* handled client-side */ +#define MGA_UPLOAD_2D 0x40 +#define MGA_WAIT_AGE 0x80 /* handled client-side */ +#define MGA_UPLOAD_CLIPRECTS 0x100 /* handled client-side */ +#if 0 +#define MGA_DMA_FLUSH 0x200 /* set when someone gets the lock + quiescent */ +#endif + +/* 32 buffers of 64k each, total 2 meg. + */ +#define MGA_BUFFER_SIZE (1 << 16) +#define MGA_NUM_BUFFERS 128 + +/* Keep these small for testing. + */ +#define MGA_NR_SAREA_CLIPRECTS 8 + +/* 2 heaps (1 for card, 1 for agp), each divided into up to 128 + * regions, subject to a minimum region size of (1<<16) == 64k. + * + * Clients may subdivide regions internally, but when sharing between + * clients, the region size is the minimum granularity. + */ + +#define MGA_CARD_HEAP 0 +#define MGA_AGP_HEAP 1 +#define MGA_NR_TEX_HEAPS 2 +#define MGA_NR_TEX_REGIONS 16 +#define MGA_LOG_MIN_TEX_REGION_SIZE 16 + +#define DRM_MGA_IDLE_RETRY 2048 + +#endif /* __MGA_SAREA_DEFINES__ */ + +/* Setup registers for 3D context + */ +typedef struct { + unsigned int dstorg; + unsigned int maccess; + unsigned int plnwt; + unsigned int dwgctl; + unsigned int alphactrl; + unsigned int fogcolor; + unsigned int wflag; + unsigned int tdualstage0; + unsigned int tdualstage1; + unsigned int fcol; + unsigned int stencil; + unsigned int stencilctl; +} drm_mga_context_regs_t; + +/* Setup registers for 2D, X server + */ +typedef struct { + unsigned int pitch; +} drm_mga_server_regs_t; + +/* Setup registers for each texture unit + */ +typedef struct { + unsigned int texctl; + unsigned int texctl2; + unsigned int texfilter; + unsigned int texbordercol; + unsigned int texorg; + unsigned int texwidth; + unsigned int texheight; + unsigned int texorg1; + unsigned int texorg2; + unsigned int texorg3; + unsigned int texorg4; +} drm_mga_texture_regs_t; + +/* General aging mechanism + */ +typedef struct { + unsigned int head; /* Position of head pointer */ + unsigned int wrap; /* Primary DMA wrap count */ +} drm_mga_age_t; + +typedef struct _drm_mga_sarea { + /* The channel for communication of state information to the kernel + * on firing a vertex dma buffer. + */ + drm_mga_context_regs_t context_state; + drm_mga_server_regs_t server_state; + drm_mga_texture_regs_t tex_state[2]; + unsigned int warp_pipe; + unsigned int dirty; + unsigned int vertsize; + + /* The current cliprects, or a subset thereof. + */ + struct drm_clip_rect boxes[MGA_NR_SAREA_CLIPRECTS]; + unsigned int nbox; + + /* Information about the most recently used 3d drawable. The + * client fills in the req_* fields, the server fills in the + * exported_ fields and puts the cliprects into boxes, above. + * + * The client clears the exported_drawable field before + * clobbering the boxes data. + */ + unsigned int req_drawable; /* the X drawable id */ + unsigned int req_draw_buffer; /* MGA_FRONT or MGA_BACK */ + + unsigned int exported_drawable; + unsigned int exported_index; + unsigned int exported_stamp; + unsigned int exported_buffers; + unsigned int exported_nfront; + unsigned int exported_nback; + int exported_back_x, exported_front_x, exported_w; + int exported_back_y, exported_front_y, exported_h; + struct drm_clip_rect exported_boxes[MGA_NR_SAREA_CLIPRECTS]; + + /* Counters for aging textures and for client-side throttling. + */ + unsigned int status[4]; + unsigned int last_wrap; + + drm_mga_age_t last_frame; + unsigned int last_enqueue; /* last time a buffer was enqueued */ + unsigned int last_dispatch; /* age of the most recently dispatched buffer */ + unsigned int last_quiescent; /* */ + + /* LRU lists for texture memory in agp space and on the card. + */ + struct drm_tex_region texList[MGA_NR_TEX_HEAPS][MGA_NR_TEX_REGIONS + 1]; + unsigned int texAge[MGA_NR_TEX_HEAPS]; + + /* Mechanism to validate card state. + */ + int ctxOwner; +} drm_mga_sarea_t; + +/* MGA specific ioctls + * The device specific ioctl range is 0x40 to 0x79. + */ +#define DRM_MGA_INIT 0x00 +#define DRM_MGA_FLUSH 0x01 +#define DRM_MGA_RESET 0x02 +#define DRM_MGA_SWAP 0x03 +#define DRM_MGA_CLEAR 0x04 +#define DRM_MGA_VERTEX 0x05 +#define DRM_MGA_INDICES 0x06 +#define DRM_MGA_ILOAD 0x07 +#define DRM_MGA_BLIT 0x08 +#define DRM_MGA_GETPARAM 0x09 + +/* 3.2: + * ioctls for operating on fences. + */ +#define DRM_MGA_SET_FENCE 0x0a +#define DRM_MGA_WAIT_FENCE 0x0b +#define DRM_MGA_DMA_BOOTSTRAP 0x0c + +#define DRM_IOCTL_MGA_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_INIT, drm_mga_init_t) +#define DRM_IOCTL_MGA_FLUSH DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_FLUSH, struct drm_lock) +#define DRM_IOCTL_MGA_RESET DRM_IO( DRM_COMMAND_BASE + DRM_MGA_RESET) +#define DRM_IOCTL_MGA_SWAP DRM_IO( DRM_COMMAND_BASE + DRM_MGA_SWAP) +#define DRM_IOCTL_MGA_CLEAR DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_CLEAR, drm_mga_clear_t) +#define DRM_IOCTL_MGA_VERTEX DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_VERTEX, drm_mga_vertex_t) +#define DRM_IOCTL_MGA_INDICES DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_INDICES, drm_mga_indices_t) +#define DRM_IOCTL_MGA_ILOAD DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_ILOAD, drm_mga_iload_t) +#define DRM_IOCTL_MGA_BLIT DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_BLIT, drm_mga_blit_t) +#define DRM_IOCTL_MGA_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_GETPARAM, drm_mga_getparam_t) +#define DRM_IOCTL_MGA_SET_FENCE DRM_IOW( DRM_COMMAND_BASE + DRM_MGA_SET_FENCE, __u32) +#define DRM_IOCTL_MGA_WAIT_FENCE DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_WAIT_FENCE, __u32) +#define DRM_IOCTL_MGA_DMA_BOOTSTRAP DRM_IOWR(DRM_COMMAND_BASE + DRM_MGA_DMA_BOOTSTRAP, drm_mga_dma_bootstrap_t) + +typedef struct _drm_mga_warp_index { + int installed; + unsigned long phys_addr; + int size; +} drm_mga_warp_index_t; + +typedef struct drm_mga_init { + enum { + MGA_INIT_DMA = 0x01, + MGA_CLEANUP_DMA = 0x02 + } func; + + unsigned long sarea_priv_offset; + + int chipset; + int sgram; + + unsigned int maccess; + + unsigned int fb_cpp; + unsigned int front_offset, front_pitch; + unsigned int back_offset, back_pitch; + + unsigned int depth_cpp; + unsigned int depth_offset, depth_pitch; + + unsigned int texture_offset[MGA_NR_TEX_HEAPS]; + unsigned int texture_size[MGA_NR_TEX_HEAPS]; + + unsigned long fb_offset; + unsigned long mmio_offset; + unsigned long status_offset; + unsigned long warp_offset; + unsigned long primary_offset; + unsigned long buffers_offset; +} drm_mga_init_t; + +typedef struct drm_mga_dma_bootstrap { + /** + * \name AGP texture region + * + * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, these fields will + * be filled in with the actual AGP texture settings. + * + * \warning + * If these fields are non-zero, but dma_mga_dma_bootstrap::agp_mode + * is zero, it means that PCI memory (most likely through the use of + * an IOMMU) is being used for "AGP" textures. + */ + /*@{ */ + unsigned long texture_handle; /**< Handle used to map AGP textures. */ + __u32 texture_size; /**< Size of the AGP texture region. */ + /*@} */ + + /** + * Requested size of the primary DMA region. + * + * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be + * filled in with the actual AGP mode. If AGP was not available + */ + __u32 primary_size; + + /** + * Requested number of secondary DMA buffers. + * + * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be + * filled in with the actual number of secondary DMA buffers + * allocated. Particularly when PCI DMA is used, this may be + * (subtantially) less than the number requested. + */ + __u32 secondary_bin_count; + + /** + * Requested size of each secondary DMA buffer. + * + * While the kernel \b is free to reduce + * dma_mga_dma_bootstrap::secondary_bin_count, it is \b not allowed + * to reduce dma_mga_dma_bootstrap::secondary_bin_size. + */ + __u32 secondary_bin_size; + + /** + * Bit-wise mask of AGPSTAT2_* values. Currently only \c AGPSTAT2_1X, + * \c AGPSTAT2_2X, and \c AGPSTAT2_4X are supported. If this value is + * zero, it means that PCI DMA should be used, even if AGP is + * possible. + * + * On return from the DRM_MGA_DMA_BOOTSTRAP ioctl, this field will be + * filled in with the actual AGP mode. If AGP was not available + * (i.e., PCI DMA was used), this value will be zero. + */ + __u32 agp_mode; + + /** + * Desired AGP GART size, measured in megabytes. + */ + __u8 agp_size; +} drm_mga_dma_bootstrap_t; + +typedef struct drm_mga_clear { + unsigned int flags; + unsigned int clear_color; + unsigned int clear_depth; + unsigned int color_mask; + unsigned int depth_mask; +} drm_mga_clear_t; + +typedef struct drm_mga_vertex { + int idx; /* buffer to queue */ + int used; /* bytes in use */ + int discard; /* client finished with buffer? */ +} drm_mga_vertex_t; + +typedef struct drm_mga_indices { + int idx; /* buffer to queue */ + unsigned int start; + unsigned int end; + int discard; /* client finished with buffer? */ +} drm_mga_indices_t; + +typedef struct drm_mga_iload { + int idx; + unsigned int dstorg; + unsigned int length; +} drm_mga_iload_t; + +typedef struct _drm_mga_blit { + unsigned int planemask; + unsigned int srcorg; + unsigned int dstorg; + int src_pitch, dst_pitch; + int delta_sx, delta_sy; + int delta_dx, delta_dy; + int height, ydir; /* flip image vertically */ + int source_pitch, dest_pitch; +} drm_mga_blit_t; + +/* 3.1: An ioctl to get parameters that aren't available to the 3d + * client any other way. + */ +#define MGA_PARAM_IRQ_NR 1 + +/* 3.2: Query the actual card type. The DDX only distinguishes between + * G200 chips and non-G200 chips, which it calls G400. It turns out that + * there are some very sublte differences between the G4x0 chips and the G550 + * chips. Using this parameter query, a client-side driver can detect the + * difference between a G4x0 and a G550. + */ +#define MGA_PARAM_CARD_TYPE 2 + +typedef struct drm_mga_getparam { + int param; + void *value; +} drm_mga_getparam_t; + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/include/drm/msm_drm.h b/include/drm/msm_drm.h new file mode 100644 index 0000000..c06d0a5 --- /dev/null +++ b/include/drm/msm_drm.h @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark + * + * 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 (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 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. + */ + +#ifndef __MSM_DRM_H__ +#define __MSM_DRM_H__ + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Please note that modifications to all structs defined here are + * subject to backwards-compatibility constraints: + * 1) Do not use pointers, use __u64 instead for 32 bit / 64 bit + * user/kernel compatibility + * 2) Keep fields aligned to their size + * 3) Because of how drm_ioctl() works, we can add new fields at + * the end of an ioctl if some care is taken: drm_ioctl() will + * zero out the new fields at the tail of the ioctl, so a zero + * value should have a backwards compatible meaning. And for + * output params, userspace won't see the newly added output + * fields.. so that has to be somehow ok. + */ + +#define MSM_PIPE_NONE 0x00 +#define MSM_PIPE_2D0 0x01 +#define MSM_PIPE_2D1 0x02 +#define MSM_PIPE_3D0 0x10 + +/* The pipe-id just uses the lower bits, so can be OR'd with flags in + * the upper 16 bits (which could be extended further, if needed, maybe + * we extend/overload the pipe-id some day to deal with multiple rings, + * but even then I don't think we need the full lower 16 bits). + */ +#define MSM_PIPE_ID_MASK 0xffff +#define MSM_PIPE_ID(x) ((x) & MSM_PIPE_ID_MASK) +#define MSM_PIPE_FLAGS(x) ((x) & ~MSM_PIPE_ID_MASK) + +/* timeouts are specified in clock-monotonic absolute times (to simplify + * restarting interrupted ioctls). The following struct is logically the + * same as 'struct timespec' but 32/64b ABI safe. + */ +struct drm_msm_timespec { + __s64 tv_sec; /* seconds */ + __s64 tv_nsec; /* nanoseconds */ +}; + +#define MSM_PARAM_GPU_ID 0x01 +#define MSM_PARAM_GMEM_SIZE 0x02 +#define MSM_PARAM_CHIP_ID 0x03 +#define MSM_PARAM_MAX_FREQ 0x04 +#define MSM_PARAM_TIMESTAMP 0x05 +#define MSM_PARAM_GMEM_BASE 0x06 +#define MSM_PARAM_NR_RINGS 0x07 + +struct drm_msm_param { + __u32 pipe; /* in, MSM_PIPE_x */ + __u32 param; /* in, MSM_PARAM_x */ + __u64 value; /* out (get_param) or in (set_param) */ +}; + +/* + * GEM buffers: + */ + +#define MSM_BO_SCANOUT 0x00000001 /* scanout capable */ +#define MSM_BO_GPU_READONLY 0x00000002 +#define MSM_BO_CACHE_MASK 0x000f0000 +/* cache modes */ +#define MSM_BO_CACHED 0x00010000 +#define MSM_BO_WC 0x00020000 +#define MSM_BO_UNCACHED 0x00040000 + +#define MSM_BO_FLAGS (MSM_BO_SCANOUT | \ + MSM_BO_GPU_READONLY | \ + MSM_BO_CACHED | \ + MSM_BO_WC | \ + MSM_BO_UNCACHED) + +struct drm_msm_gem_new { + __u64 size; /* in */ + __u32 flags; /* in, mask of MSM_BO_x */ + __u32 handle; /* out */ +}; + +#define MSM_INFO_IOVA 0x01 + +#define MSM_INFO_FLAGS (MSM_INFO_IOVA) + +struct drm_msm_gem_info { + __u32 handle; /* in */ + __u32 flags; /* in - combination of MSM_INFO_* flags */ + __u64 offset; /* out, mmap() offset or iova */ +}; + +#define MSM_PREP_READ 0x01 +#define MSM_PREP_WRITE 0x02 +#define MSM_PREP_NOSYNC 0x04 + +#define MSM_PREP_FLAGS (MSM_PREP_READ | MSM_PREP_WRITE | MSM_PREP_NOSYNC) + +struct drm_msm_gem_cpu_prep { + __u32 handle; /* in */ + __u32 op; /* in, mask of MSM_PREP_x */ + struct drm_msm_timespec timeout; /* in */ +}; + +struct drm_msm_gem_cpu_fini { + __u32 handle; /* in */ +}; + +/* + * Cmdstream Submission: + */ + +/* The value written into the cmdstream is logically: + * + * ((relocbuf->gpuaddr + reloc_offset) << shift) | or + * + * When we have GPU's w/ >32bit ptrs, it should be possible to deal + * with this by emit'ing two reloc entries with appropriate shift + * values. Or a new MSM_SUBMIT_CMD_x type would also be an option. + * + * NOTE that reloc's must be sorted by order of increasing submit_offset, + * otherwise EINVAL. + */ +struct drm_msm_gem_submit_reloc { + __u32 submit_offset; /* in, offset from submit_bo */ + __u32 or; /* in, value OR'd with result */ + __s32 shift; /* in, amount of left shift (can be negative) */ + __u32 reloc_idx; /* in, index of reloc_bo buffer */ + __u64 reloc_offset; /* in, offset from start of reloc_bo */ +}; + +/* submit-types: + * BUF - this cmd buffer is executed normally. + * IB_TARGET_BUF - this cmd buffer is an IB target. Reloc's are + * processed normally, but the kernel does not setup an IB to + * this buffer in the first-level ringbuffer + * CTX_RESTORE_BUF - only executed if there has been a GPU context + * switch since the last SUBMIT ioctl + */ +#define MSM_SUBMIT_CMD_BUF 0x0001 +#define MSM_SUBMIT_CMD_IB_TARGET_BUF 0x0002 +#define MSM_SUBMIT_CMD_CTX_RESTORE_BUF 0x0003 +struct drm_msm_gem_submit_cmd { + __u32 type; /* in, one of MSM_SUBMIT_CMD_x */ + __u32 submit_idx; /* in, index of submit_bo cmdstream buffer */ + __u32 submit_offset; /* in, offset into submit_bo */ + __u32 size; /* in, cmdstream size */ + __u32 pad; + __u32 nr_relocs; /* in, number of submit_reloc's */ + __u64 relocs; /* in, ptr to array of submit_reloc's */ +}; + +/* Each buffer referenced elsewhere in the cmdstream submit (ie. the + * cmdstream buffer(s) themselves or reloc entries) has one (and only + * one) entry in the submit->bos[] table. + * + * As a optimization, the current buffer (gpu virtual address) can be + * passed back through the 'presumed' field. If on a subsequent reloc, + * userspace passes back a 'presumed' address that is still valid, + * then patching the cmdstream for this entry is skipped. This can + * avoid kernel needing to map/access the cmdstream bo in the common + * case. + */ +#define MSM_SUBMIT_BO_READ 0x0001 +#define MSM_SUBMIT_BO_WRITE 0x0002 + +#define MSM_SUBMIT_BO_FLAGS (MSM_SUBMIT_BO_READ | MSM_SUBMIT_BO_WRITE) + +struct drm_msm_gem_submit_bo { + __u32 flags; /* in, mask of MSM_SUBMIT_BO_x */ + __u32 handle; /* in, GEM handle */ + __u64 presumed; /* in/out, presumed buffer address */ +}; + +/* Valid submit ioctl flags: */ +#define MSM_SUBMIT_NO_IMPLICIT 0x80000000 /* disable implicit sync */ +#define MSM_SUBMIT_FENCE_FD_IN 0x40000000 /* enable input fence_fd */ +#define MSM_SUBMIT_FENCE_FD_OUT 0x20000000 /* enable output fence_fd */ +#define MSM_SUBMIT_SUDO 0x10000000 /* run submitted cmds from RB */ +#define MSM_SUBMIT_FLAGS ( \ + MSM_SUBMIT_NO_IMPLICIT | \ + MSM_SUBMIT_FENCE_FD_IN | \ + MSM_SUBMIT_FENCE_FD_OUT | \ + MSM_SUBMIT_SUDO | \ + 0) + +/* Each cmdstream submit consists of a table of buffers involved, and + * one or more cmdstream buffers. This allows for conditional execution + * (context-restore), and IB buffers needed for per tile/bin draw cmds. + */ +struct drm_msm_gem_submit { + __u32 flags; /* MSM_PIPE_x | MSM_SUBMIT_x */ + __u32 fence; /* out */ + __u32 nr_bos; /* in, number of submit_bo's */ + __u32 nr_cmds; /* in, number of submit_cmd's */ + __u64 bos; /* in, ptr to array of submit_bo's */ + __u64 cmds; /* in, ptr to array of submit_cmd's */ + __s32 fence_fd; /* in/out fence fd (see MSM_SUBMIT_FENCE_FD_IN/OUT) */ + __u32 queueid; /* in, submitqueue id */ +}; + +/* The normal way to synchronize with the GPU is just to CPU_PREP on + * a buffer if you need to access it from the CPU (other cmdstream + * submission from same or other contexts, PAGE_FLIP ioctl, etc, all + * handle the required synchronization under the hood). This ioctl + * mainly just exists as a way to implement the gallium pipe_fence + * APIs without requiring a dummy bo to synchronize on. + */ +struct drm_msm_wait_fence { + __u32 fence; /* in */ + __u32 pad; + struct drm_msm_timespec timeout; /* in */ + __u32 queueid; /* in, submitqueue id */ +}; + +/* madvise provides a way to tell the kernel in case a buffers contents + * can be discarded under memory pressure, which is useful for userspace + * bo cache where we want to optimistically hold on to buffer allocate + * and potential mmap, but allow the pages to be discarded under memory + * pressure. + * + * Typical usage would involve madvise(DONTNEED) when buffer enters BO + * cache, and madvise(WILLNEED) if trying to recycle buffer from BO cache. + * In the WILLNEED case, 'retained' indicates to userspace whether the + * backing pages still exist. + */ +#define MSM_MADV_WILLNEED 0 /* backing pages are needed, status returned in 'retained' */ +#define MSM_MADV_DONTNEED 1 /* backing pages not needed */ +#define __MSM_MADV_PURGED 2 /* internal state */ + +struct drm_msm_gem_madvise { + __u32 handle; /* in, GEM handle */ + __u32 madv; /* in, MSM_MADV_x */ + __u32 retained; /* out, whether backing store still exists */ +}; + +/* + * Draw queues allow the user to set specific submission parameter. Command + * submissions specify a specific submitqueue to use. ID 0 is reserved for + * backwards compatibility as a "default" submitqueue + */ + +#define MSM_SUBMITQUEUE_FLAGS (0) + +struct drm_msm_submitqueue { + __u32 flags; /* in, MSM_SUBMITQUEUE_x */ + __u32 prio; /* in, Priority level */ + __u32 id; /* out, identifier */ +}; + +#define DRM_MSM_GET_PARAM 0x00 +/* placeholder: +#define DRM_MSM_SET_PARAM 0x01 + */ +#define DRM_MSM_GEM_NEW 0x02 +#define DRM_MSM_GEM_INFO 0x03 +#define DRM_MSM_GEM_CPU_PREP 0x04 +#define DRM_MSM_GEM_CPU_FINI 0x05 +#define DRM_MSM_GEM_SUBMIT 0x06 +#define DRM_MSM_WAIT_FENCE 0x07 +#define DRM_MSM_GEM_MADVISE 0x08 +/* placeholder: +#define DRM_MSM_GEM_SVM_NEW 0x09 + */ +#define DRM_MSM_SUBMITQUEUE_NEW 0x0A +#define DRM_MSM_SUBMITQUEUE_CLOSE 0x0B + +#define DRM_IOCTL_MSM_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GET_PARAM, struct drm_msm_param) +#define DRM_IOCTL_MSM_GEM_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_NEW, struct drm_msm_gem_new) +#define DRM_IOCTL_MSM_GEM_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_INFO, struct drm_msm_gem_info) +#define DRM_IOCTL_MSM_GEM_CPU_PREP DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_GEM_CPU_PREP, struct drm_msm_gem_cpu_prep) +#define DRM_IOCTL_MSM_GEM_CPU_FINI DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_GEM_CPU_FINI, struct drm_msm_gem_cpu_fini) +#define DRM_IOCTL_MSM_GEM_SUBMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_SUBMIT, struct drm_msm_gem_submit) +#define DRM_IOCTL_MSM_WAIT_FENCE DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_WAIT_FENCE, struct drm_msm_wait_fence) +#define DRM_IOCTL_MSM_GEM_MADVISE DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_MADVISE, struct drm_msm_gem_madvise) +#define DRM_IOCTL_MSM_SUBMITQUEUE_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_SUBMITQUEUE_NEW, struct drm_msm_submitqueue) +#define DRM_IOCTL_MSM_SUBMITQUEUE_CLOSE DRM_IOW (DRM_COMMAND_BASE + DRM_MSM_SUBMITQUEUE_CLOSE, __u32) + +#if defined(__cplusplus) +} +#endif + +#endif /* __MSM_DRM_H__ */ diff --git a/include/drm/nouveau_drm.h b/include/drm/nouveau_drm.h new file mode 100644 index 0000000..4f94148 --- /dev/null +++ b/include/drm/nouveau_drm.h @@ -0,0 +1,256 @@ +/* + * Copyright 2005 Stephane Marchesin. + * 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, 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS 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 __NOUVEAU_DRM_H__ +#define __NOUVEAU_DRM_H__ + +#define NOUVEAU_DRM_HEADER_PATCHLEVEL 16 + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +struct drm_nouveau_channel_alloc { + uint32_t fb_ctxdma_handle; + uint32_t tt_ctxdma_handle; + + int channel; + uint32_t pushbuf_domains; + + /* Notifier memory */ + uint32_t notifier_handle; + + /* DRM-enforced subchannel assignments */ + struct { + uint32_t handle; + uint32_t grclass; + } subchan[8]; + uint32_t nr_subchan; +}; + +struct drm_nouveau_channel_free { + int channel; +}; + +struct drm_nouveau_grobj_alloc { + int channel; + uint32_t handle; + int class; +}; + +struct drm_nouveau_notifierobj_alloc { + uint32_t channel; + uint32_t handle; + uint32_t size; + uint32_t offset; +}; + +struct drm_nouveau_gpuobj_free { + int channel; + uint32_t handle; +}; + +#define NOUVEAU_GETPARAM_PCI_VENDOR 3 +#define NOUVEAU_GETPARAM_PCI_DEVICE 4 +#define NOUVEAU_GETPARAM_BUS_TYPE 5 +#define NOUVEAU_GETPARAM_FB_SIZE 8 +#define NOUVEAU_GETPARAM_AGP_SIZE 9 +#define NOUVEAU_GETPARAM_CHIPSET_ID 11 +#define NOUVEAU_GETPARAM_VM_VRAM_BASE 12 +#define NOUVEAU_GETPARAM_GRAPH_UNITS 13 +#define NOUVEAU_GETPARAM_PTIMER_TIME 14 +#define NOUVEAU_GETPARAM_HAS_BO_USAGE 15 +#define NOUVEAU_GETPARAM_HAS_PAGEFLIP 16 +struct drm_nouveau_getparam { + uint64_t param; + uint64_t value; +}; + +struct drm_nouveau_setparam { + uint64_t param; + uint64_t value; +}; + +#define NOUVEAU_GEM_DOMAIN_CPU (1 << 0) +#define NOUVEAU_GEM_DOMAIN_VRAM (1 << 1) +#define NOUVEAU_GEM_DOMAIN_GART (1 << 2) +#define NOUVEAU_GEM_DOMAIN_MAPPABLE (1 << 3) +#define NOUVEAU_GEM_DOMAIN_COHERENT (1 << 4) + +#define NOUVEAU_GEM_TILE_COMP 0x00030000 /* nv50-only */ +#define NOUVEAU_GEM_TILE_LAYOUT_MASK 0x0000ff00 +#define NOUVEAU_GEM_TILE_16BPP 0x00000001 +#define NOUVEAU_GEM_TILE_32BPP 0x00000002 +#define NOUVEAU_GEM_TILE_ZETA 0x00000004 +#define NOUVEAU_GEM_TILE_NONCONTIG 0x00000008 + +struct drm_nouveau_gem_info { + __u32 handle; + __u32 domain; + __u64 size; + __u64 offset; + __u64 map_handle; + __u32 tile_mode; + __u32 tile_flags; +}; + +struct drm_nouveau_gem_new { + struct drm_nouveau_gem_info info; + __u32 channel_hint; + __u32 align; +}; + +#define NOUVEAU_GEM_MAX_BUFFERS 1024 +struct drm_nouveau_gem_pushbuf_bo_presumed { + __u32 valid; + __u32 domain; + __u64 offset; +}; + +struct drm_nouveau_gem_pushbuf_bo { + __u64 user_priv; + __u32 handle; + __u32 read_domains; + __u32 write_domains; + __u32 valid_domains; + struct drm_nouveau_gem_pushbuf_bo_presumed presumed; +}; + +#define NOUVEAU_GEM_RELOC_LOW (1 << 0) +#define NOUVEAU_GEM_RELOC_HIGH (1 << 1) +#define NOUVEAU_GEM_RELOC_OR (1 << 2) +#define NOUVEAU_GEM_MAX_RELOCS 1024 +struct drm_nouveau_gem_pushbuf_reloc { + __u32 reloc_bo_index; + __u32 reloc_bo_offset; + __u32 bo_index; + __u32 flags; + __u32 data; + __u32 vor; + __u32 tor; +}; + +#define NOUVEAU_GEM_MAX_PUSH 512 +struct drm_nouveau_gem_pushbuf_push { + __u32 bo_index; + __u32 pad; + __u64 offset; + __u64 length; +}; + +struct drm_nouveau_gem_pushbuf { + __u32 channel; + __u32 nr_buffers; + __u64 buffers; + __u32 nr_relocs; + __u32 nr_push; + __u64 relocs; + __u64 push; + __u32 suffix0; + __u32 suffix1; +#define NOUVEAU_GEM_PUSHBUF_SYNC (1ULL << 0) + __u64 vram_available; + __u64 gart_available; +}; + +#define NOUVEAU_GEM_CPU_PREP_NOWAIT 0x00000001 +#define NOUVEAU_GEM_CPU_PREP_WRITE 0x00000004 +struct drm_nouveau_gem_cpu_prep { + __u32 handle; + __u32 flags; +}; + +struct drm_nouveau_gem_cpu_fini { + __u32 handle; +}; + +#define DRM_NOUVEAU_GETPARAM 0x00 /* deprecated */ +#define DRM_NOUVEAU_SETPARAM 0x01 /* deprecated */ +#define DRM_NOUVEAU_CHANNEL_ALLOC 0x02 /* deprecated */ +#define DRM_NOUVEAU_CHANNEL_FREE 0x03 /* deprecated */ +#define DRM_NOUVEAU_GROBJ_ALLOC 0x04 /* deprecated */ +#define DRM_NOUVEAU_NOTIFIEROBJ_ALLOC 0x05 /* deprecated */ +#define DRM_NOUVEAU_GPUOBJ_FREE 0x06 /* deprecated */ +#define DRM_NOUVEAU_NVIF 0x07 +#define DRM_NOUVEAU_SVM_INIT 0x08 +#define DRM_NOUVEAU_SVM_BIND 0x09 +#define DRM_NOUVEAU_GEM_NEW 0x40 +#define DRM_NOUVEAU_GEM_PUSHBUF 0x41 +#define DRM_NOUVEAU_GEM_CPU_PREP 0x42 +#define DRM_NOUVEAU_GEM_CPU_FINI 0x43 +#define DRM_NOUVEAU_GEM_INFO 0x44 + +struct drm_nouveau_svm_init { + __u64 unmanaged_addr; + __u64 unmanaged_size; +}; + +struct drm_nouveau_svm_bind { + __u64 header; + __u64 va_start; + __u64 va_end; + __u64 npages; + __u64 stride; + __u64 result; + __u64 reserved0; + __u64 reserved1; +}; + +#define NOUVEAU_SVM_BIND_COMMAND_SHIFT 0 +#define NOUVEAU_SVM_BIND_COMMAND_BITS 8 +#define NOUVEAU_SVM_BIND_COMMAND_MASK ((1 << 8) - 1) +#define NOUVEAU_SVM_BIND_PRIORITY_SHIFT 8 +#define NOUVEAU_SVM_BIND_PRIORITY_BITS 8 +#define NOUVEAU_SVM_BIND_PRIORITY_MASK ((1 << 8) - 1) +#define NOUVEAU_SVM_BIND_TARGET_SHIFT 16 +#define NOUVEAU_SVM_BIND_TARGET_BITS 32 +#define NOUVEAU_SVM_BIND_TARGET_MASK 0xffffffff + +/* + * Below is use to validate ioctl argument, userspace can also use it to make + * sure that no bit are set beyond known fields for a given kernel version. + */ +#define NOUVEAU_SVM_BIND_VALID_BITS 48 +#define NOUVEAU_SVM_BIND_VALID_MASK ((1ULL << NOUVEAU_SVM_BIND_VALID_BITS) - 1) + + +/* + * NOUVEAU_BIND_COMMAND__MIGRATE: synchronous migrate to target memory. + * result: number of page successfuly migrate to the target memory. + */ +#define NOUVEAU_SVM_BIND_COMMAND__MIGRATE 0 + +/* + * NOUVEAU_SVM_BIND_HEADER_TARGET__GPU_VRAM: target the GPU VRAM memory. + */ +#define NOUVEAU_SVM_BIND_TARGET__GPU_VRAM (1UL << 31) + + +#if defined(__cplusplus) +} +#endif + +#endif /* __NOUVEAU_DRM_H__ */ diff --git a/include/drm/qxl_drm.h b/include/drm/qxl_drm.h new file mode 100644 index 0000000..880999d --- /dev/null +++ b/include/drm/qxl_drm.h @@ -0,0 +1,158 @@ +/* + * Copyright 2013 Red Hat + * 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, 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS 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 QXL_DRM_H +#define QXL_DRM_H + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Please note that modifications to all structs defined here are + * subject to backwards-compatibility constraints. + * + * Do not use pointers, use __u64 instead for 32 bit / 64 bit user/kernel + * compatibility Keep fields aligned to their size + */ + +#define QXL_GEM_DOMAIN_CPU 0 +#define QXL_GEM_DOMAIN_VRAM 1 +#define QXL_GEM_DOMAIN_SURFACE 2 + +#define DRM_QXL_ALLOC 0x00 +#define DRM_QXL_MAP 0x01 +#define DRM_QXL_EXECBUFFER 0x02 +#define DRM_QXL_UPDATE_AREA 0x03 +#define DRM_QXL_GETPARAM 0x04 +#define DRM_QXL_CLIENTCAP 0x05 + +#define DRM_QXL_ALLOC_SURF 0x06 + +struct drm_qxl_alloc { + __u32 size; + __u32 handle; /* 0 is an invalid handle */ +}; + +struct drm_qxl_map { + __u64 offset; /* use for mmap system call */ + __u32 handle; + __u32 pad; +}; + +/* + * dest is the bo we are writing the relocation into + * src is bo we are relocating. + * *(dest_handle.base_addr + dest_offset) = physical_address(src_handle.addr + + * src_offset) + */ +#define QXL_RELOC_TYPE_BO 1 +#define QXL_RELOC_TYPE_SURF 2 + +struct drm_qxl_reloc { + __u64 src_offset; /* offset into src_handle or src buffer */ + __u64 dst_offset; /* offset in dest handle */ + __u32 src_handle; /* dest handle to compute address from */ + __u32 dst_handle; /* 0 if to command buffer */ + __u32 reloc_type; + __u32 pad; +}; + +struct drm_qxl_command { + __u64 command; /* void* */ + __u64 relocs; /* struct drm_qxl_reloc* */ + __u32 type; + __u32 command_size; + __u32 relocs_num; + __u32 pad; +}; + +struct drm_qxl_execbuffer { + __u32 flags; /* for future use */ + __u32 commands_num; + __u64 commands; /* struct drm_qxl_command* */ +}; + +struct drm_qxl_update_area { + __u32 handle; + __u32 top; + __u32 left; + __u32 bottom; + __u32 right; + __u32 pad; +}; + +#define QXL_PARAM_NUM_SURFACES 1 /* rom->n_surfaces */ +#define QXL_PARAM_MAX_RELOCS 2 +struct drm_qxl_getparam { + __u64 param; + __u64 value; +}; + +/* these are one bit values */ +struct drm_qxl_clientcap { + __u32 index; + __u32 pad; +}; + +struct drm_qxl_alloc_surf { + __u32 format; + __u32 width; + __u32 height; + __s32 stride; + __u32 handle; + __u32 pad; +}; + +#define DRM_IOCTL_QXL_ALLOC \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_QXL_ALLOC, struct drm_qxl_alloc) + +#define DRM_IOCTL_QXL_MAP \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_QXL_MAP, struct drm_qxl_map) + +#define DRM_IOCTL_QXL_EXECBUFFER \ + DRM_IOW(DRM_COMMAND_BASE + DRM_QXL_EXECBUFFER,\ + struct drm_qxl_execbuffer) + +#define DRM_IOCTL_QXL_UPDATE_AREA \ + DRM_IOW(DRM_COMMAND_BASE + DRM_QXL_UPDATE_AREA,\ + struct drm_qxl_update_area) + +#define DRM_IOCTL_QXL_GETPARAM \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_QXL_GETPARAM,\ + struct drm_qxl_getparam) + +#define DRM_IOCTL_QXL_CLIENTCAP \ + DRM_IOW(DRM_COMMAND_BASE + DRM_QXL_CLIENTCAP,\ + struct drm_qxl_clientcap) + +#define DRM_IOCTL_QXL_ALLOC_SURF \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_QXL_ALLOC_SURF,\ + struct drm_qxl_alloc_surf) + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/include/drm/r128_drm.h b/include/drm/r128_drm.h new file mode 100644 index 0000000..bf431a0 --- /dev/null +++ b/include/drm/r128_drm.h @@ -0,0 +1,336 @@ +/* r128_drm.h -- Public header for the r128 driver -*- linux-c -*- + * Created: Wed Apr 5 19:24:19 2000 by kevin@precisioninsight.com + */ +/* + * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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, 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT 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. + * + * Authors: + * Gareth Hughes + * Kevin E. Martin + */ + +#ifndef __R128_DRM_H__ +#define __R128_DRM_H__ + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the X server file (r128_sarea.h) + */ +#ifndef __R128_SAREA_DEFINES__ +#define __R128_SAREA_DEFINES__ + +/* What needs to be changed for the current vertex buffer? + */ +#define R128_UPLOAD_CONTEXT 0x001 +#define R128_UPLOAD_SETUP 0x002 +#define R128_UPLOAD_TEX0 0x004 +#define R128_UPLOAD_TEX1 0x008 +#define R128_UPLOAD_TEX0IMAGES 0x010 +#define R128_UPLOAD_TEX1IMAGES 0x020 +#define R128_UPLOAD_CORE 0x040 +#define R128_UPLOAD_MASKS 0x080 +#define R128_UPLOAD_WINDOW 0x100 +#define R128_UPLOAD_CLIPRECTS 0x200 /* handled client-side */ +#define R128_REQUIRE_QUIESCENCE 0x400 +#define R128_UPLOAD_ALL 0x7ff + +#define R128_FRONT 0x1 +#define R128_BACK 0x2 +#define R128_DEPTH 0x4 + +/* Primitive types + */ +#define R128_POINTS 0x1 +#define R128_LINES 0x2 +#define R128_LINE_STRIP 0x3 +#define R128_TRIANGLES 0x4 +#define R128_TRIANGLE_FAN 0x5 +#define R128_TRIANGLE_STRIP 0x6 + +/* Vertex/indirect buffer size + */ +#define R128_BUFFER_SIZE 16384 + +/* Byte offsets for indirect buffer data + */ +#define R128_INDEX_PRIM_OFFSET 20 +#define R128_HOSTDATA_BLIT_OFFSET 32 + +/* Keep these small for testing. + */ +#define R128_NR_SAREA_CLIPRECTS 12 + +/* There are 2 heaps (local/AGP). Each region within a heap is a + * minimum of 64k, and there are at most 64 of them per heap. + */ +#define R128_LOCAL_TEX_HEAP 0 +#define R128_AGP_TEX_HEAP 1 +#define R128_NR_TEX_HEAPS 2 +#define R128_NR_TEX_REGIONS 64 +#define R128_LOG_TEX_GRANULARITY 16 + +#define R128_NR_CONTEXT_REGS 12 + +#define R128_MAX_TEXTURE_LEVELS 11 +#define R128_MAX_TEXTURE_UNITS 2 + +#endif /* __R128_SAREA_DEFINES__ */ + +typedef struct { + /* Context state - can be written in one large chunk */ + unsigned int dst_pitch_offset_c; + unsigned int dp_gui_master_cntl_c; + unsigned int sc_top_left_c; + unsigned int sc_bottom_right_c; + unsigned int z_offset_c; + unsigned int z_pitch_c; + unsigned int z_sten_cntl_c; + unsigned int tex_cntl_c; + unsigned int misc_3d_state_cntl_reg; + unsigned int texture_clr_cmp_clr_c; + unsigned int texture_clr_cmp_msk_c; + unsigned int fog_color_c; + + /* Texture state */ + unsigned int tex_size_pitch_c; + unsigned int constant_color_c; + + /* Setup state */ + unsigned int pm4_vc_fpu_setup; + unsigned int setup_cntl; + + /* Mask state */ + unsigned int dp_write_mask; + unsigned int sten_ref_mask_c; + unsigned int plane_3d_mask_c; + + /* Window state */ + unsigned int window_xy_offset; + + /* Core state */ + unsigned int scale_3d_cntl; +} drm_r128_context_regs_t; + +/* Setup registers for each texture unit + */ +typedef struct { + unsigned int tex_cntl; + unsigned int tex_combine_cntl; + unsigned int tex_size_pitch; + unsigned int tex_offset[R128_MAX_TEXTURE_LEVELS]; + unsigned int tex_border_color; +} drm_r128_texture_regs_t; + +typedef struct drm_r128_sarea { + /* The channel for communication of state information to the kernel + * on firing a vertex buffer. + */ + drm_r128_context_regs_t context_state; + drm_r128_texture_regs_t tex_state[R128_MAX_TEXTURE_UNITS]; + unsigned int dirty; + unsigned int vertsize; + unsigned int vc_format; + + /* The current cliprects, or a subset thereof. + */ + struct drm_clip_rect boxes[R128_NR_SAREA_CLIPRECTS]; + unsigned int nbox; + + /* Counters for client-side throttling of rendering clients. + */ + unsigned int last_frame; + unsigned int last_dispatch; + + struct drm_tex_region tex_list[R128_NR_TEX_HEAPS][R128_NR_TEX_REGIONS + 1]; + unsigned int tex_age[R128_NR_TEX_HEAPS]; + int ctx_owner; + int pfAllowPageFlip; /* number of 3d windows (0,1,2 or more) */ + int pfCurrentPage; /* which buffer is being displayed? */ +} drm_r128_sarea_t; + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the Xserver file (xf86drmR128.h) + */ + +/* Rage 128 specific ioctls + * The device specific ioctl range is 0x40 to 0x79. + */ +#define DRM_R128_INIT 0x00 +#define DRM_R128_CCE_START 0x01 +#define DRM_R128_CCE_STOP 0x02 +#define DRM_R128_CCE_RESET 0x03 +#define DRM_R128_CCE_IDLE 0x04 +/* 0x05 not used */ +#define DRM_R128_RESET 0x06 +#define DRM_R128_SWAP 0x07 +#define DRM_R128_CLEAR 0x08 +#define DRM_R128_VERTEX 0x09 +#define DRM_R128_INDICES 0x0a +#define DRM_R128_BLIT 0x0b +#define DRM_R128_DEPTH 0x0c +#define DRM_R128_STIPPLE 0x0d +/* 0x0e not used */ +#define DRM_R128_INDIRECT 0x0f +#define DRM_R128_FULLSCREEN 0x10 +#define DRM_R128_CLEAR2 0x11 +#define DRM_R128_GETPARAM 0x12 +#define DRM_R128_FLIP 0x13 + +#define DRM_IOCTL_R128_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_R128_INIT, drm_r128_init_t) +#define DRM_IOCTL_R128_CCE_START DRM_IO( DRM_COMMAND_BASE + DRM_R128_CCE_START) +#define DRM_IOCTL_R128_CCE_STOP DRM_IOW( DRM_COMMAND_BASE + DRM_R128_CCE_STOP, drm_r128_cce_stop_t) +#define DRM_IOCTL_R128_CCE_RESET DRM_IO( DRM_COMMAND_BASE + DRM_R128_CCE_RESET) +#define DRM_IOCTL_R128_CCE_IDLE DRM_IO( DRM_COMMAND_BASE + DRM_R128_CCE_IDLE) +/* 0x05 not used */ +#define DRM_IOCTL_R128_RESET DRM_IO( DRM_COMMAND_BASE + DRM_R128_RESET) +#define DRM_IOCTL_R128_SWAP DRM_IO( DRM_COMMAND_BASE + DRM_R128_SWAP) +#define DRM_IOCTL_R128_CLEAR DRM_IOW( DRM_COMMAND_BASE + DRM_R128_CLEAR, drm_r128_clear_t) +#define DRM_IOCTL_R128_VERTEX DRM_IOW( DRM_COMMAND_BASE + DRM_R128_VERTEX, drm_r128_vertex_t) +#define DRM_IOCTL_R128_INDICES DRM_IOW( DRM_COMMAND_BASE + DRM_R128_INDICES, drm_r128_indices_t) +#define DRM_IOCTL_R128_BLIT DRM_IOW( DRM_COMMAND_BASE + DRM_R128_BLIT, drm_r128_blit_t) +#define DRM_IOCTL_R128_DEPTH DRM_IOW( DRM_COMMAND_BASE + DRM_R128_DEPTH, drm_r128_depth_t) +#define DRM_IOCTL_R128_STIPPLE DRM_IOW( DRM_COMMAND_BASE + DRM_R128_STIPPLE, drm_r128_stipple_t) +/* 0x0e not used */ +#define DRM_IOCTL_R128_INDIRECT DRM_IOWR(DRM_COMMAND_BASE + DRM_R128_INDIRECT, drm_r128_indirect_t) +#define DRM_IOCTL_R128_FULLSCREEN DRM_IOW( DRM_COMMAND_BASE + DRM_R128_FULLSCREEN, drm_r128_fullscreen_t) +#define DRM_IOCTL_R128_CLEAR2 DRM_IOW( DRM_COMMAND_BASE + DRM_R128_CLEAR2, drm_r128_clear2_t) +#define DRM_IOCTL_R128_GETPARAM DRM_IOWR( DRM_COMMAND_BASE + DRM_R128_GETPARAM, drm_r128_getparam_t) +#define DRM_IOCTL_R128_FLIP DRM_IO( DRM_COMMAND_BASE + DRM_R128_FLIP) + +typedef struct drm_r128_init { + enum { + R128_INIT_CCE = 0x01, + R128_CLEANUP_CCE = 0x02 + } func; + unsigned long sarea_priv_offset; + int is_pci; + int cce_mode; + int cce_secure; + int ring_size; + int usec_timeout; + + unsigned int fb_bpp; + unsigned int front_offset, front_pitch; + unsigned int back_offset, back_pitch; + unsigned int depth_bpp; + unsigned int depth_offset, depth_pitch; + unsigned int span_offset; + + unsigned long fb_offset; + unsigned long mmio_offset; + unsigned long ring_offset; + unsigned long ring_rptr_offset; + unsigned long buffers_offset; + unsigned long agp_textures_offset; +} drm_r128_init_t; + +typedef struct drm_r128_cce_stop { + int flush; + int idle; +} drm_r128_cce_stop_t; + +typedef struct drm_r128_clear { + unsigned int flags; + unsigned int clear_color; + unsigned int clear_depth; + unsigned int color_mask; + unsigned int depth_mask; +} drm_r128_clear_t; + +typedef struct drm_r128_vertex { + int prim; + int idx; /* Index of vertex buffer */ + int count; /* Number of vertices in buffer */ + int discard; /* Client finished with buffer? */ +} drm_r128_vertex_t; + +typedef struct drm_r128_indices { + int prim; + int idx; + int start; + int end; + int discard; /* Client finished with buffer? */ +} drm_r128_indices_t; + +typedef struct drm_r128_blit { + int idx; + int pitch; + int offset; + int format; + unsigned short x, y; + unsigned short width, height; +} drm_r128_blit_t; + +typedef struct drm_r128_depth { + enum { + R128_WRITE_SPAN = 0x01, + R128_WRITE_PIXELS = 0x02, + R128_READ_SPAN = 0x03, + R128_READ_PIXELS = 0x04 + } func; + int n; + int *x; + int *y; + unsigned int *buffer; + unsigned char *mask; +} drm_r128_depth_t; + +typedef struct drm_r128_stipple { + unsigned int *mask; +} drm_r128_stipple_t; + +typedef struct drm_r128_indirect { + int idx; + int start; + int end; + int discard; +} drm_r128_indirect_t; + +typedef struct drm_r128_fullscreen { + enum { + R128_INIT_FULLSCREEN = 0x01, + R128_CLEANUP_FULLSCREEN = 0x02 + } func; +} drm_r128_fullscreen_t; + +/* 2.3: An ioctl to get parameters that aren't available to the 3d + * client any other way. + */ +#define R128_PARAM_IRQ_NR 1 + +typedef struct drm_r128_getparam { + int param; + void *value; +} drm_r128_getparam_t; + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/include/drm/radeon_drm.h b/include/drm/radeon_drm.h new file mode 100644 index 0000000..a1e385d --- /dev/null +++ b/include/drm/radeon_drm.h @@ -0,0 +1,1079 @@ +/* radeon_drm.h -- Public header for the radeon driver -*- linux-c -*- + * + * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Fremont, California. + * Copyright 2002 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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, 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT 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. + * + * Authors: + * Kevin E. Martin + * Gareth Hughes + * Keith Whitwell + */ + +#ifndef __RADEON_DRM_H__ +#define __RADEON_DRM_H__ + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the X server file (radeon_sarea.h) + */ +#ifndef __RADEON_SAREA_DEFINES__ +#define __RADEON_SAREA_DEFINES__ + +/* Old style state flags, required for sarea interface (1.1 and 1.2 + * clears) and 1.2 drm_vertex2 ioctl. + */ +#define RADEON_UPLOAD_CONTEXT 0x00000001 +#define RADEON_UPLOAD_VERTFMT 0x00000002 +#define RADEON_UPLOAD_LINE 0x00000004 +#define RADEON_UPLOAD_BUMPMAP 0x00000008 +#define RADEON_UPLOAD_MASKS 0x00000010 +#define RADEON_UPLOAD_VIEWPORT 0x00000020 +#define RADEON_UPLOAD_SETUP 0x00000040 +#define RADEON_UPLOAD_TCL 0x00000080 +#define RADEON_UPLOAD_MISC 0x00000100 +#define RADEON_UPLOAD_TEX0 0x00000200 +#define RADEON_UPLOAD_TEX1 0x00000400 +#define RADEON_UPLOAD_TEX2 0x00000800 +#define RADEON_UPLOAD_TEX0IMAGES 0x00001000 +#define RADEON_UPLOAD_TEX1IMAGES 0x00002000 +#define RADEON_UPLOAD_TEX2IMAGES 0x00004000 +#define RADEON_UPLOAD_CLIPRECTS 0x00008000 /* handled client-side */ +#define RADEON_REQUIRE_QUIESCENCE 0x00010000 +#define RADEON_UPLOAD_ZBIAS 0x00020000 /* version 1.2 and newer */ +#define RADEON_UPLOAD_ALL 0x003effff +#define RADEON_UPLOAD_CONTEXT_ALL 0x003e01ff + +/* New style per-packet identifiers for use in cmd_buffer ioctl with + * the RADEON_EMIT_PACKET command. Comments relate new packets to old + * state bits and the packet size: + */ +#define RADEON_EMIT_PP_MISC 0 /* context/7 */ +#define RADEON_EMIT_PP_CNTL 1 /* context/3 */ +#define RADEON_EMIT_RB3D_COLORPITCH 2 /* context/1 */ +#define RADEON_EMIT_RE_LINE_PATTERN 3 /* line/2 */ +#define RADEON_EMIT_SE_LINE_WIDTH 4 /* line/1 */ +#define RADEON_EMIT_PP_LUM_MATRIX 5 /* bumpmap/1 */ +#define RADEON_EMIT_PP_ROT_MATRIX_0 6 /* bumpmap/2 */ +#define RADEON_EMIT_RB3D_STENCILREFMASK 7 /* masks/3 */ +#define RADEON_EMIT_SE_VPORT_XSCALE 8 /* viewport/6 */ +#define RADEON_EMIT_SE_CNTL 9 /* setup/2 */ +#define RADEON_EMIT_SE_CNTL_STATUS 10 /* setup/1 */ +#define RADEON_EMIT_RE_MISC 11 /* misc/1 */ +#define RADEON_EMIT_PP_TXFILTER_0 12 /* tex0/6 */ +#define RADEON_EMIT_PP_BORDER_COLOR_0 13 /* tex0/1 */ +#define RADEON_EMIT_PP_TXFILTER_1 14 /* tex1/6 */ +#define RADEON_EMIT_PP_BORDER_COLOR_1 15 /* tex1/1 */ +#define RADEON_EMIT_PP_TXFILTER_2 16 /* tex2/6 */ +#define RADEON_EMIT_PP_BORDER_COLOR_2 17 /* tex2/1 */ +#define RADEON_EMIT_SE_ZBIAS_FACTOR 18 /* zbias/2 */ +#define RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT 19 /* tcl/11 */ +#define RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED 20 /* material/17 */ +#define R200_EMIT_PP_TXCBLEND_0 21 /* tex0/4 */ +#define R200_EMIT_PP_TXCBLEND_1 22 /* tex1/4 */ +#define R200_EMIT_PP_TXCBLEND_2 23 /* tex2/4 */ +#define R200_EMIT_PP_TXCBLEND_3 24 /* tex3/4 */ +#define R200_EMIT_PP_TXCBLEND_4 25 /* tex4/4 */ +#define R200_EMIT_PP_TXCBLEND_5 26 /* tex5/4 */ +#define R200_EMIT_PP_TXCBLEND_6 27 /* /4 */ +#define R200_EMIT_PP_TXCBLEND_7 28 /* /4 */ +#define R200_EMIT_TCL_LIGHT_MODEL_CTL_0 29 /* tcl/7 */ +#define R200_EMIT_TFACTOR_0 30 /* tf/7 */ +#define R200_EMIT_VTX_FMT_0 31 /* vtx/5 */ +#define R200_EMIT_VAP_CTL 32 /* vap/1 */ +#define R200_EMIT_MATRIX_SELECT_0 33 /* msl/5 */ +#define R200_EMIT_TEX_PROC_CTL_2 34 /* tcg/5 */ +#define R200_EMIT_TCL_UCP_VERT_BLEND_CTL 35 /* tcl/1 */ +#define R200_EMIT_PP_TXFILTER_0 36 /* tex0/6 */ +#define R200_EMIT_PP_TXFILTER_1 37 /* tex1/6 */ +#define R200_EMIT_PP_TXFILTER_2 38 /* tex2/6 */ +#define R200_EMIT_PP_TXFILTER_3 39 /* tex3/6 */ +#define R200_EMIT_PP_TXFILTER_4 40 /* tex4/6 */ +#define R200_EMIT_PP_TXFILTER_5 41 /* tex5/6 */ +#define R200_EMIT_PP_TXOFFSET_0 42 /* tex0/1 */ +#define R200_EMIT_PP_TXOFFSET_1 43 /* tex1/1 */ +#define R200_EMIT_PP_TXOFFSET_2 44 /* tex2/1 */ +#define R200_EMIT_PP_TXOFFSET_3 45 /* tex3/1 */ +#define R200_EMIT_PP_TXOFFSET_4 46 /* tex4/1 */ +#define R200_EMIT_PP_TXOFFSET_5 47 /* tex5/1 */ +#define R200_EMIT_VTE_CNTL 48 /* vte/1 */ +#define R200_EMIT_OUTPUT_VTX_COMP_SEL 49 /* vtx/1 */ +#define R200_EMIT_PP_TAM_DEBUG3 50 /* tam/1 */ +#define R200_EMIT_PP_CNTL_X 51 /* cst/1 */ +#define R200_EMIT_RB3D_DEPTHXY_OFFSET 52 /* cst/1 */ +#define R200_EMIT_RE_AUX_SCISSOR_CNTL 53 /* cst/1 */ +#define R200_EMIT_RE_SCISSOR_TL_0 54 /* cst/2 */ +#define R200_EMIT_RE_SCISSOR_TL_1 55 /* cst/2 */ +#define R200_EMIT_RE_SCISSOR_TL_2 56 /* cst/2 */ +#define R200_EMIT_SE_VAP_CNTL_STATUS 57 /* cst/1 */ +#define R200_EMIT_SE_VTX_STATE_CNTL 58 /* cst/1 */ +#define R200_EMIT_RE_POINTSIZE 59 /* cst/1 */ +#define R200_EMIT_TCL_INPUT_VTX_VECTOR_ADDR_0 60 /* cst/4 */ +#define R200_EMIT_PP_CUBIC_FACES_0 61 +#define R200_EMIT_PP_CUBIC_OFFSETS_0 62 +#define R200_EMIT_PP_CUBIC_FACES_1 63 +#define R200_EMIT_PP_CUBIC_OFFSETS_1 64 +#define R200_EMIT_PP_CUBIC_FACES_2 65 +#define R200_EMIT_PP_CUBIC_OFFSETS_2 66 +#define R200_EMIT_PP_CUBIC_FACES_3 67 +#define R200_EMIT_PP_CUBIC_OFFSETS_3 68 +#define R200_EMIT_PP_CUBIC_FACES_4 69 +#define R200_EMIT_PP_CUBIC_OFFSETS_4 70 +#define R200_EMIT_PP_CUBIC_FACES_5 71 +#define R200_EMIT_PP_CUBIC_OFFSETS_5 72 +#define RADEON_EMIT_PP_TEX_SIZE_0 73 +#define RADEON_EMIT_PP_TEX_SIZE_1 74 +#define RADEON_EMIT_PP_TEX_SIZE_2 75 +#define R200_EMIT_RB3D_BLENDCOLOR 76 +#define R200_EMIT_TCL_POINT_SPRITE_CNTL 77 +#define RADEON_EMIT_PP_CUBIC_FACES_0 78 +#define RADEON_EMIT_PP_CUBIC_OFFSETS_T0 79 +#define RADEON_EMIT_PP_CUBIC_FACES_1 80 +#define RADEON_EMIT_PP_CUBIC_OFFSETS_T1 81 +#define RADEON_EMIT_PP_CUBIC_FACES_2 82 +#define RADEON_EMIT_PP_CUBIC_OFFSETS_T2 83 +#define R200_EMIT_PP_TRI_PERF_CNTL 84 +#define R200_EMIT_PP_AFS_0 85 +#define R200_EMIT_PP_AFS_1 86 +#define R200_EMIT_ATF_TFACTOR 87 +#define R200_EMIT_PP_TXCTLALL_0 88 +#define R200_EMIT_PP_TXCTLALL_1 89 +#define R200_EMIT_PP_TXCTLALL_2 90 +#define R200_EMIT_PP_TXCTLALL_3 91 +#define R200_EMIT_PP_TXCTLALL_4 92 +#define R200_EMIT_PP_TXCTLALL_5 93 +#define R200_EMIT_VAP_PVS_CNTL 94 +#define RADEON_MAX_STATE_PACKETS 95 + +/* Commands understood by cmd_buffer ioctl. More can be added but + * obviously these can't be removed or changed: + */ +#define RADEON_CMD_PACKET 1 /* emit one of the register packets above */ +#define RADEON_CMD_SCALARS 2 /* emit scalar data */ +#define RADEON_CMD_VECTORS 3 /* emit vector data */ +#define RADEON_CMD_DMA_DISCARD 4 /* discard current dma buf */ +#define RADEON_CMD_PACKET3 5 /* emit hw packet */ +#define RADEON_CMD_PACKET3_CLIP 6 /* emit hw packet wrapped in cliprects */ +#define RADEON_CMD_SCALARS2 7 /* r200 stopgap */ +#define RADEON_CMD_WAIT 8 /* emit hw wait commands -- note: + * doesn't make the cpu wait, just + * the graphics hardware */ +#define RADEON_CMD_VECLINEAR 9 /* another r200 stopgap */ + +typedef union { + int i; + struct { + unsigned char cmd_type, pad0, pad1, pad2; + } header; + struct { + unsigned char cmd_type, packet_id, pad0, pad1; + } packet; + struct { + unsigned char cmd_type, offset, stride, count; + } scalars; + struct { + unsigned char cmd_type, offset, stride, count; + } vectors; + struct { + unsigned char cmd_type, addr_lo, addr_hi, count; + } veclinear; + struct { + unsigned char cmd_type, buf_idx, pad0, pad1; + } dma; + struct { + unsigned char cmd_type, flags, pad0, pad1; + } wait; +} drm_radeon_cmd_header_t; + +#define RADEON_WAIT_2D 0x1 +#define RADEON_WAIT_3D 0x2 + +/* Allowed parameters for R300_CMD_PACKET3 + */ +#define R300_CMD_PACKET3_CLEAR 0 +#define R300_CMD_PACKET3_RAW 1 + +/* Commands understood by cmd_buffer ioctl for R300. + * The interface has not been stabilized, so some of these may be removed + * and eventually reordered before stabilization. + */ +#define R300_CMD_PACKET0 1 +#define R300_CMD_VPU 2 /* emit vertex program upload */ +#define R300_CMD_PACKET3 3 /* emit a packet3 */ +#define R300_CMD_END3D 4 /* emit sequence ending 3d rendering */ +#define R300_CMD_CP_DELAY 5 +#define R300_CMD_DMA_DISCARD 6 +#define R300_CMD_WAIT 7 +# define R300_WAIT_2D 0x1 +# define R300_WAIT_3D 0x2 +/* these two defines are DOING IT WRONG - however + * we have userspace which relies on using these. + * The wait interface is backwards compat new + * code should use the NEW_WAIT defines below + * THESE ARE NOT BIT FIELDS + */ +# define R300_WAIT_2D_CLEAN 0x3 +# define R300_WAIT_3D_CLEAN 0x4 + +# define R300_NEW_WAIT_2D_3D 0x3 +# define R300_NEW_WAIT_2D_2D_CLEAN 0x4 +# define R300_NEW_WAIT_3D_3D_CLEAN 0x6 +# define R300_NEW_WAIT_2D_2D_CLEAN_3D_3D_CLEAN 0x8 + +#define R300_CMD_SCRATCH 8 +#define R300_CMD_R500FP 9 + +typedef union { + unsigned int u; + struct { + unsigned char cmd_type, pad0, pad1, pad2; + } header; + struct { + unsigned char cmd_type, count, reglo, reghi; + } packet0; + struct { + unsigned char cmd_type, count, adrlo, adrhi; + } vpu; + struct { + unsigned char cmd_type, packet, pad0, pad1; + } packet3; + struct { + unsigned char cmd_type, packet; + unsigned short count; /* amount of packet2 to emit */ + } delay; + struct { + unsigned char cmd_type, buf_idx, pad0, pad1; + } dma; + struct { + unsigned char cmd_type, flags, pad0, pad1; + } wait; + struct { + unsigned char cmd_type, reg, n_bufs, flags; + } scratch; + struct { + unsigned char cmd_type, count, adrlo, adrhi_flags; + } r500fp; +} drm_r300_cmd_header_t; + +#define RADEON_FRONT 0x1 +#define RADEON_BACK 0x2 +#define RADEON_DEPTH 0x4 +#define RADEON_STENCIL 0x8 +#define RADEON_CLEAR_FASTZ 0x80000000 +#define RADEON_USE_HIERZ 0x40000000 +#define RADEON_USE_COMP_ZBUF 0x20000000 + +#define R500FP_CONSTANT_TYPE (1 << 1) +#define R500FP_CONSTANT_CLAMP (1 << 2) + +/* Primitive types + */ +#define RADEON_POINTS 0x1 +#define RADEON_LINES 0x2 +#define RADEON_LINE_STRIP 0x3 +#define RADEON_TRIANGLES 0x4 +#define RADEON_TRIANGLE_FAN 0x5 +#define RADEON_TRIANGLE_STRIP 0x6 + +/* Vertex/indirect buffer size + */ +#define RADEON_BUFFER_SIZE 65536 + +/* Byte offsets for indirect buffer data + */ +#define RADEON_INDEX_PRIM_OFFSET 20 + +#define RADEON_SCRATCH_REG_OFFSET 32 + +#define R600_SCRATCH_REG_OFFSET 256 + +#define RADEON_NR_SAREA_CLIPRECTS 12 + +/* There are 2 heaps (local/GART). Each region within a heap is a + * minimum of 64k, and there are at most 64 of them per heap. + */ +#define RADEON_LOCAL_TEX_HEAP 0 +#define RADEON_GART_TEX_HEAP 1 +#define RADEON_NR_TEX_HEAPS 2 +#define RADEON_NR_TEX_REGIONS 64 +#define RADEON_LOG_TEX_GRANULARITY 16 + +#define RADEON_MAX_TEXTURE_LEVELS 12 +#define RADEON_MAX_TEXTURE_UNITS 3 + +#define RADEON_MAX_SURFACES 8 + +/* Blits have strict offset rules. All blit offset must be aligned on + * a 1K-byte boundary. + */ +#define RADEON_OFFSET_SHIFT 10 +#define RADEON_OFFSET_ALIGN (1 << RADEON_OFFSET_SHIFT) +#define RADEON_OFFSET_MASK (RADEON_OFFSET_ALIGN - 1) + +#endif /* __RADEON_SAREA_DEFINES__ */ + +typedef struct { + unsigned int red; + unsigned int green; + unsigned int blue; + unsigned int alpha; +} radeon_color_regs_t; + +typedef struct { + /* Context state */ + unsigned int pp_misc; /* 0x1c14 */ + unsigned int pp_fog_color; + unsigned int re_solid_color; + unsigned int rb3d_blendcntl; + unsigned int rb3d_depthoffset; + unsigned int rb3d_depthpitch; + unsigned int rb3d_zstencilcntl; + + unsigned int pp_cntl; /* 0x1c38 */ + unsigned int rb3d_cntl; + unsigned int rb3d_coloroffset; + unsigned int re_width_height; + unsigned int rb3d_colorpitch; + unsigned int se_cntl; + + /* Vertex format state */ + unsigned int se_coord_fmt; /* 0x1c50 */ + + /* Line state */ + unsigned int re_line_pattern; /* 0x1cd0 */ + unsigned int re_line_state; + + unsigned int se_line_width; /* 0x1db8 */ + + /* Bumpmap state */ + unsigned int pp_lum_matrix; /* 0x1d00 */ + + unsigned int pp_rot_matrix_0; /* 0x1d58 */ + unsigned int pp_rot_matrix_1; + + /* Mask state */ + unsigned int rb3d_stencilrefmask; /* 0x1d7c */ + unsigned int rb3d_ropcntl; + unsigned int rb3d_planemask; + + /* Viewport state */ + unsigned int se_vport_xscale; /* 0x1d98 */ + unsigned int se_vport_xoffset; + unsigned int se_vport_yscale; + unsigned int se_vport_yoffset; + unsigned int se_vport_zscale; + unsigned int se_vport_zoffset; + + /* Setup state */ + unsigned int se_cntl_status; /* 0x2140 */ + + /* Misc state */ + unsigned int re_top_left; /* 0x26c0 */ + unsigned int re_misc; +} drm_radeon_context_regs_t; + +typedef struct { + /* Zbias state */ + unsigned int se_zbias_factor; /* 0x1dac */ + unsigned int se_zbias_constant; +} drm_radeon_context2_regs_t; + +/* Setup registers for each texture unit + */ +typedef struct { + unsigned int pp_txfilter; + unsigned int pp_txformat; + unsigned int pp_txoffset; + unsigned int pp_txcblend; + unsigned int pp_txablend; + unsigned int pp_tfactor; + unsigned int pp_border_color; +} drm_radeon_texture_regs_t; + +typedef struct { + unsigned int start; + unsigned int finish; + unsigned int prim:8; + unsigned int stateidx:8; + unsigned int numverts:16; /* overloaded as offset/64 for elt prims */ + unsigned int vc_format; /* vertex format */ +} drm_radeon_prim_t; + +typedef struct { + drm_radeon_context_regs_t context; + drm_radeon_texture_regs_t tex[RADEON_MAX_TEXTURE_UNITS]; + drm_radeon_context2_regs_t context2; + unsigned int dirty; +} drm_radeon_state_t; + +typedef struct { + /* The channel for communication of state information to the + * kernel on firing a vertex buffer with either of the + * obsoleted vertex/index ioctls. + */ + drm_radeon_context_regs_t context_state; + drm_radeon_texture_regs_t tex_state[RADEON_MAX_TEXTURE_UNITS]; + unsigned int dirty; + unsigned int vertsize; + unsigned int vc_format; + + /* The current cliprects, or a subset thereof. + */ + struct drm_clip_rect boxes[RADEON_NR_SAREA_CLIPRECTS]; + unsigned int nbox; + + /* Counters for client-side throttling of rendering clients. + */ + unsigned int last_frame; + unsigned int last_dispatch; + unsigned int last_clear; + + struct drm_tex_region tex_list[RADEON_NR_TEX_HEAPS][RADEON_NR_TEX_REGIONS + + 1]; + unsigned int tex_age[RADEON_NR_TEX_HEAPS]; + int ctx_owner; + int pfState; /* number of 3d windows (0,1,2ormore) */ + int pfCurrentPage; /* which buffer is being displayed? */ + int crtc2_base; /* CRTC2 frame offset */ + int tiling_enabled; /* set by drm, read by 2d + 3d clients */ +} drm_radeon_sarea_t; + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the Xserver file (xf86drmRadeon.h) + * + * KW: actually it's illegal to change any of this (backwards compatibility). + */ + +/* Radeon specific ioctls + * The device specific ioctl range is 0x40 to 0x79. + */ +#define DRM_RADEON_CP_INIT 0x00 +#define DRM_RADEON_CP_START 0x01 +#define DRM_RADEON_CP_STOP 0x02 +#define DRM_RADEON_CP_RESET 0x03 +#define DRM_RADEON_CP_IDLE 0x04 +#define DRM_RADEON_RESET 0x05 +#define DRM_RADEON_FULLSCREEN 0x06 +#define DRM_RADEON_SWAP 0x07 +#define DRM_RADEON_CLEAR 0x08 +#define DRM_RADEON_VERTEX 0x09 +#define DRM_RADEON_INDICES 0x0A +#define DRM_RADEON_NOT_USED +#define DRM_RADEON_STIPPLE 0x0C +#define DRM_RADEON_INDIRECT 0x0D +#define DRM_RADEON_TEXTURE 0x0E +#define DRM_RADEON_VERTEX2 0x0F +#define DRM_RADEON_CMDBUF 0x10 +#define DRM_RADEON_GETPARAM 0x11 +#define DRM_RADEON_FLIP 0x12 +#define DRM_RADEON_ALLOC 0x13 +#define DRM_RADEON_FREE 0x14 +#define DRM_RADEON_INIT_HEAP 0x15 +#define DRM_RADEON_IRQ_EMIT 0x16 +#define DRM_RADEON_IRQ_WAIT 0x17 +#define DRM_RADEON_CP_RESUME 0x18 +#define DRM_RADEON_SETPARAM 0x19 +#define DRM_RADEON_SURF_ALLOC 0x1a +#define DRM_RADEON_SURF_FREE 0x1b +/* KMS ioctl */ +#define DRM_RADEON_GEM_INFO 0x1c +#define DRM_RADEON_GEM_CREATE 0x1d +#define DRM_RADEON_GEM_MMAP 0x1e +#define DRM_RADEON_GEM_PREAD 0x21 +#define DRM_RADEON_GEM_PWRITE 0x22 +#define DRM_RADEON_GEM_SET_DOMAIN 0x23 +#define DRM_RADEON_GEM_WAIT_IDLE 0x24 +#define DRM_RADEON_CS 0x26 +#define DRM_RADEON_INFO 0x27 +#define DRM_RADEON_GEM_SET_TILING 0x28 +#define DRM_RADEON_GEM_GET_TILING 0x29 +#define DRM_RADEON_GEM_BUSY 0x2a +#define DRM_RADEON_GEM_VA 0x2b +#define DRM_RADEON_GEM_OP 0x2c +#define DRM_RADEON_GEM_USERPTR 0x2d + +#define DRM_IOCTL_RADEON_CP_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_INIT, drm_radeon_init_t) +#define DRM_IOCTL_RADEON_CP_START DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_CP_START) +#define DRM_IOCTL_RADEON_CP_STOP DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_STOP, drm_radeon_cp_stop_t) +#define DRM_IOCTL_RADEON_CP_RESET DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_CP_RESET) +#define DRM_IOCTL_RADEON_CP_IDLE DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_CP_IDLE) +#define DRM_IOCTL_RADEON_RESET DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_RESET) +#define DRM_IOCTL_RADEON_FULLSCREEN DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_FULLSCREEN, drm_radeon_fullscreen_t) +#define DRM_IOCTL_RADEON_SWAP DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_SWAP) +#define DRM_IOCTL_RADEON_CLEAR DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CLEAR, drm_radeon_clear_t) +#define DRM_IOCTL_RADEON_VERTEX DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_VERTEX, drm_radeon_vertex_t) +#define DRM_IOCTL_RADEON_INDICES DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_INDICES, drm_radeon_indices_t) +#define DRM_IOCTL_RADEON_STIPPLE DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_STIPPLE, drm_radeon_stipple_t) +#define DRM_IOCTL_RADEON_INDIRECT DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_INDIRECT, drm_radeon_indirect_t) +#define DRM_IOCTL_RADEON_TEXTURE DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_TEXTURE, drm_radeon_texture_t) +#define DRM_IOCTL_RADEON_VERTEX2 DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_VERTEX2, drm_radeon_vertex2_t) +#define DRM_IOCTL_RADEON_CMDBUF DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CMDBUF, drm_radeon_cmd_buffer_t) +#define DRM_IOCTL_RADEON_GETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GETPARAM, drm_radeon_getparam_t) +#define DRM_IOCTL_RADEON_FLIP DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_FLIP) +#define DRM_IOCTL_RADEON_ALLOC DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_ALLOC, drm_radeon_mem_alloc_t) +#define DRM_IOCTL_RADEON_FREE DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_FREE, drm_radeon_mem_free_t) +#define DRM_IOCTL_RADEON_INIT_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_INIT_HEAP, drm_radeon_mem_init_heap_t) +#define DRM_IOCTL_RADEON_IRQ_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_IRQ_EMIT, drm_radeon_irq_emit_t) +#define DRM_IOCTL_RADEON_IRQ_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_IRQ_WAIT, drm_radeon_irq_wait_t) +#define DRM_IOCTL_RADEON_CP_RESUME DRM_IO( DRM_COMMAND_BASE + DRM_RADEON_CP_RESUME) +#define DRM_IOCTL_RADEON_SETPARAM DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_SETPARAM, drm_radeon_setparam_t) +#define DRM_IOCTL_RADEON_SURF_ALLOC DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_SURF_ALLOC, drm_radeon_surface_alloc_t) +#define DRM_IOCTL_RADEON_SURF_FREE DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_SURF_FREE, drm_radeon_surface_free_t) +/* KMS */ +#define DRM_IOCTL_RADEON_GEM_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_INFO, struct drm_radeon_gem_info) +#define DRM_IOCTL_RADEON_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_CREATE, struct drm_radeon_gem_create) +#define DRM_IOCTL_RADEON_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_MMAP, struct drm_radeon_gem_mmap) +#define DRM_IOCTL_RADEON_GEM_PREAD DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_PREAD, struct drm_radeon_gem_pread) +#define DRM_IOCTL_RADEON_GEM_PWRITE DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_PWRITE, struct drm_radeon_gem_pwrite) +#define DRM_IOCTL_RADEON_GEM_SET_DOMAIN DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_SET_DOMAIN, struct drm_radeon_gem_set_domain) +#define DRM_IOCTL_RADEON_GEM_WAIT_IDLE DRM_IOW(DRM_COMMAND_BASE + DRM_RADEON_GEM_WAIT_IDLE, struct drm_radeon_gem_wait_idle) +#define DRM_IOCTL_RADEON_CS DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_CS, struct drm_radeon_cs) +#define DRM_IOCTL_RADEON_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_INFO, struct drm_radeon_info) +#define DRM_IOCTL_RADEON_GEM_SET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_SET_TILING, struct drm_radeon_gem_set_tiling) +#define DRM_IOCTL_RADEON_GEM_GET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_GET_TILING, struct drm_radeon_gem_get_tiling) +#define DRM_IOCTL_RADEON_GEM_BUSY DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_BUSY, struct drm_radeon_gem_busy) +#define DRM_IOCTL_RADEON_GEM_VA DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_VA, struct drm_radeon_gem_va) +#define DRM_IOCTL_RADEON_GEM_OP DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_OP, struct drm_radeon_gem_op) +#define DRM_IOCTL_RADEON_GEM_USERPTR DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_USERPTR, struct drm_radeon_gem_userptr) + +typedef struct drm_radeon_init { + enum { + RADEON_INIT_CP = 0x01, + RADEON_CLEANUP_CP = 0x02, + RADEON_INIT_R200_CP = 0x03, + RADEON_INIT_R300_CP = 0x04, + RADEON_INIT_R600_CP = 0x05 + } func; + unsigned long sarea_priv_offset; + int is_pci; + int cp_mode; + int gart_size; + int ring_size; + int usec_timeout; + + unsigned int fb_bpp; + unsigned int front_offset, front_pitch; + unsigned int back_offset, back_pitch; + unsigned int depth_bpp; + unsigned int depth_offset, depth_pitch; + + unsigned long fb_offset; + unsigned long mmio_offset; + unsigned long ring_offset; + unsigned long ring_rptr_offset; + unsigned long buffers_offset; + unsigned long gart_textures_offset; +} drm_radeon_init_t; + +typedef struct drm_radeon_cp_stop { + int flush; + int idle; +} drm_radeon_cp_stop_t; + +typedef struct drm_radeon_fullscreen { + enum { + RADEON_INIT_FULLSCREEN = 0x01, + RADEON_CLEANUP_FULLSCREEN = 0x02 + } func; +} drm_radeon_fullscreen_t; + +#define CLEAR_X1 0 +#define CLEAR_Y1 1 +#define CLEAR_X2 2 +#define CLEAR_Y2 3 +#define CLEAR_DEPTH 4 + +typedef union drm_radeon_clear_rect { + float f[5]; + unsigned int ui[5]; +} drm_radeon_clear_rect_t; + +typedef struct drm_radeon_clear { + unsigned int flags; + unsigned int clear_color; + unsigned int clear_depth; + unsigned int color_mask; + unsigned int depth_mask; /* misnamed field: should be stencil */ + drm_radeon_clear_rect_t *depth_boxes; +} drm_radeon_clear_t; + +typedef struct drm_radeon_vertex { + int prim; + int idx; /* Index of vertex buffer */ + int count; /* Number of vertices in buffer */ + int discard; /* Client finished with buffer? */ +} drm_radeon_vertex_t; + +typedef struct drm_radeon_indices { + int prim; + int idx; + int start; + int end; + int discard; /* Client finished with buffer? */ +} drm_radeon_indices_t; + +/* v1.2 - obsoletes drm_radeon_vertex and drm_radeon_indices + * - allows multiple primitives and state changes in a single ioctl + * - supports driver change to emit native primitives + */ +typedef struct drm_radeon_vertex2 { + int idx; /* Index of vertex buffer */ + int discard; /* Client finished with buffer? */ + int nr_states; + drm_radeon_state_t *state; + int nr_prims; + drm_radeon_prim_t *prim; +} drm_radeon_vertex2_t; + +/* v1.3 - obsoletes drm_radeon_vertex2 + * - allows arbitrarily large cliprect list + * - allows updating of tcl packet, vector and scalar state + * - allows memory-efficient description of state updates + * - allows state to be emitted without a primitive + * (for clears, ctx switches) + * - allows more than one dma buffer to be referenced per ioctl + * - supports tcl driver + * - may be extended in future versions with new cmd types, packets + */ +typedef struct drm_radeon_cmd_buffer { + int bufsz; + char *buf; + int nbox; + struct drm_clip_rect *boxes; +} drm_radeon_cmd_buffer_t; + +typedef struct drm_radeon_tex_image { + unsigned int x, y; /* Blit coordinates */ + unsigned int width, height; + const void *data; +} drm_radeon_tex_image_t; + +typedef struct drm_radeon_texture { + unsigned int offset; + int pitch; + int format; + int width; /* Texture image coordinates */ + int height; + drm_radeon_tex_image_t *image; +} drm_radeon_texture_t; + +typedef struct drm_radeon_stipple { + unsigned int *mask; +} drm_radeon_stipple_t; + +typedef struct drm_radeon_indirect { + int idx; + int start; + int end; + int discard; +} drm_radeon_indirect_t; + +/* enum for card type parameters */ +#define RADEON_CARD_PCI 0 +#define RADEON_CARD_AGP 1 +#define RADEON_CARD_PCIE 2 + +/* 1.3: An ioctl to get parameters that aren't available to the 3d + * client any other way. + */ +#define RADEON_PARAM_GART_BUFFER_OFFSET 1 /* card offset of 1st GART buffer */ +#define RADEON_PARAM_LAST_FRAME 2 +#define RADEON_PARAM_LAST_DISPATCH 3 +#define RADEON_PARAM_LAST_CLEAR 4 +/* Added with DRM version 1.6. */ +#define RADEON_PARAM_IRQ_NR 5 +#define RADEON_PARAM_GART_BASE 6 /* card offset of GART base */ +/* Added with DRM version 1.8. */ +#define RADEON_PARAM_REGISTER_HANDLE 7 /* for drmMap() */ +#define RADEON_PARAM_STATUS_HANDLE 8 +#define RADEON_PARAM_SAREA_HANDLE 9 +#define RADEON_PARAM_GART_TEX_HANDLE 10 +#define RADEON_PARAM_SCRATCH_OFFSET 11 +#define RADEON_PARAM_CARD_TYPE 12 +#define RADEON_PARAM_VBLANK_CRTC 13 /* VBLANK CRTC */ +#define RADEON_PARAM_FB_LOCATION 14 /* FB location */ +#define RADEON_PARAM_NUM_GB_PIPES 15 /* num GB pipes */ +#define RADEON_PARAM_DEVICE_ID 16 +#define RADEON_PARAM_NUM_Z_PIPES 17 /* num Z pipes */ + +typedef struct drm_radeon_getparam { + int param; + void *value; +} drm_radeon_getparam_t; + +/* 1.6: Set up a memory manager for regions of shared memory: + */ +#define RADEON_MEM_REGION_GART 1 +#define RADEON_MEM_REGION_FB 2 + +typedef struct drm_radeon_mem_alloc { + int region; + int alignment; + int size; + int *region_offset; /* offset from start of fb or GART */ +} drm_radeon_mem_alloc_t; + +typedef struct drm_radeon_mem_free { + int region; + int region_offset; +} drm_radeon_mem_free_t; + +typedef struct drm_radeon_mem_init_heap { + int region; + int size; + int start; +} drm_radeon_mem_init_heap_t; + +/* 1.6: Userspace can request & wait on irq's: + */ +typedef struct drm_radeon_irq_emit { + int *irq_seq; +} drm_radeon_irq_emit_t; + +typedef struct drm_radeon_irq_wait { + int irq_seq; +} drm_radeon_irq_wait_t; + +/* 1.10: Clients tell the DRM where they think the framebuffer is located in + * the card's address space, via a new generic ioctl to set parameters + */ + +typedef struct drm_radeon_setparam { + unsigned int param; + __s64 value; +} drm_radeon_setparam_t; + +#define RADEON_SETPARAM_FB_LOCATION 1 /* determined framebuffer location */ +#define RADEON_SETPARAM_SWITCH_TILING 2 /* enable/disable color tiling */ +#define RADEON_SETPARAM_PCIGART_LOCATION 3 /* PCI Gart Location */ +#define RADEON_SETPARAM_NEW_MEMMAP 4 /* Use new memory map */ +#define RADEON_SETPARAM_PCIGART_TABLE_SIZE 5 /* PCI GART Table Size */ +#define RADEON_SETPARAM_VBLANK_CRTC 6 /* VBLANK CRTC */ +/* 1.14: Clients can allocate/free a surface + */ +typedef struct drm_radeon_surface_alloc { + unsigned int address; + unsigned int size; + unsigned int flags; +} drm_radeon_surface_alloc_t; + +typedef struct drm_radeon_surface_free { + unsigned int address; +} drm_radeon_surface_free_t; + +#define DRM_RADEON_VBLANK_CRTC1 1 +#define DRM_RADEON_VBLANK_CRTC2 2 + +/* + * Kernel modesetting world below. + */ +#define RADEON_GEM_DOMAIN_CPU 0x1 +#define RADEON_GEM_DOMAIN_GTT 0x2 +#define RADEON_GEM_DOMAIN_VRAM 0x4 + +struct drm_radeon_gem_info { + __u64 gart_size; + __u64 vram_size; + __u64 vram_visible; +}; + +#define RADEON_GEM_NO_BACKING_STORE (1 << 0) +#define RADEON_GEM_GTT_UC (1 << 1) +#define RADEON_GEM_GTT_WC (1 << 2) +/* BO is expected to be accessed by the CPU */ +#define RADEON_GEM_CPU_ACCESS (1 << 3) +/* CPU access is not expected to work for this BO */ +#define RADEON_GEM_NO_CPU_ACCESS (1 << 4) + +struct drm_radeon_gem_create { + __u64 size; + __u64 alignment; + __u32 handle; + __u32 initial_domain; + __u32 flags; +}; + +/* + * This is not a reliable API and you should expect it to fail for any + * number of reasons and have fallback path that do not use userptr to + * perform any operation. + */ +#define RADEON_GEM_USERPTR_READONLY (1 << 0) +#define RADEON_GEM_USERPTR_ANONONLY (1 << 1) +#define RADEON_GEM_USERPTR_VALIDATE (1 << 2) +#define RADEON_GEM_USERPTR_REGISTER (1 << 3) + +struct drm_radeon_gem_userptr { + __u64 addr; + __u64 size; + __u32 flags; + __u32 handle; +}; + +#define RADEON_TILING_MACRO 0x1 +#define RADEON_TILING_MICRO 0x2 +#define RADEON_TILING_SWAP_16BIT 0x4 +#define RADEON_TILING_R600_NO_SCANOUT RADEON_TILING_SWAP_16BIT +#define RADEON_TILING_SWAP_32BIT 0x8 +/* this object requires a surface when mapped - i.e. front buffer */ +#define RADEON_TILING_SURFACE 0x10 +#define RADEON_TILING_MICRO_SQUARE 0x20 +#define RADEON_TILING_EG_BANKW_SHIFT 8 +#define RADEON_TILING_EG_BANKW_MASK 0xf +#define RADEON_TILING_EG_BANKH_SHIFT 12 +#define RADEON_TILING_EG_BANKH_MASK 0xf +#define RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT 16 +#define RADEON_TILING_EG_MACRO_TILE_ASPECT_MASK 0xf +#define RADEON_TILING_EG_TILE_SPLIT_SHIFT 24 +#define RADEON_TILING_EG_TILE_SPLIT_MASK 0xf +#define RADEON_TILING_EG_STENCIL_TILE_SPLIT_SHIFT 28 +#define RADEON_TILING_EG_STENCIL_TILE_SPLIT_MASK 0xf + +struct drm_radeon_gem_set_tiling { + __u32 handle; + __u32 tiling_flags; + __u32 pitch; +}; + +struct drm_radeon_gem_get_tiling { + __u32 handle; + __u32 tiling_flags; + __u32 pitch; +}; + +struct drm_radeon_gem_mmap { + __u32 handle; + __u32 pad; + __u64 offset; + __u64 size; + __u64 addr_ptr; +}; + +struct drm_radeon_gem_set_domain { + __u32 handle; + __u32 read_domains; + __u32 write_domain; +}; + +struct drm_radeon_gem_wait_idle { + __u32 handle; + __u32 pad; +}; + +struct drm_radeon_gem_busy { + __u32 handle; + __u32 domain; +}; + +struct drm_radeon_gem_pread { + /** Handle for the object being read. */ + __u32 handle; + __u32 pad; + /** Offset into the object to read from */ + __u64 offset; + /** Length of data to read */ + __u64 size; + /** Pointer to write the data into. */ + /* void *, but pointers are not 32/64 compatible */ + __u64 data_ptr; +}; + +struct drm_radeon_gem_pwrite { + /** Handle for the object being written to. */ + __u32 handle; + __u32 pad; + /** Offset into the object to write to */ + __u64 offset; + /** Length of data to write */ + __u64 size; + /** Pointer to read the data from. */ + /* void *, but pointers are not 32/64 compatible */ + __u64 data_ptr; +}; + +/* Sets or returns a value associated with a buffer. */ +struct drm_radeon_gem_op { + __u32 handle; /* buffer */ + __u32 op; /* RADEON_GEM_OP_* */ + __u64 value; /* input or return value */ +}; + +#define RADEON_GEM_OP_GET_INITIAL_DOMAIN 0 +#define RADEON_GEM_OP_SET_INITIAL_DOMAIN 1 + +#define RADEON_VA_MAP 1 +#define RADEON_VA_UNMAP 2 + +#define RADEON_VA_RESULT_OK 0 +#define RADEON_VA_RESULT_ERROR 1 +#define RADEON_VA_RESULT_VA_EXIST 2 + +#define RADEON_VM_PAGE_VALID (1 << 0) +#define RADEON_VM_PAGE_READABLE (1 << 1) +#define RADEON_VM_PAGE_WRITEABLE (1 << 2) +#define RADEON_VM_PAGE_SYSTEM (1 << 3) +#define RADEON_VM_PAGE_SNOOPED (1 << 4) + +struct drm_radeon_gem_va { + __u32 handle; + __u32 operation; + __u32 vm_id; + __u32 flags; + __u64 offset; +}; + +#define RADEON_CHUNK_ID_RELOCS 0x01 +#define RADEON_CHUNK_ID_IB 0x02 +#define RADEON_CHUNK_ID_FLAGS 0x03 +#define RADEON_CHUNK_ID_CONST_IB 0x04 + +/* The first dword of RADEON_CHUNK_ID_FLAGS is a uint32 of these flags: */ +#define RADEON_CS_KEEP_TILING_FLAGS 0x01 +#define RADEON_CS_USE_VM 0x02 +#define RADEON_CS_END_OF_FRAME 0x04 /* a hint from userspace which CS is the last one */ +/* The second dword of RADEON_CHUNK_ID_FLAGS is a uint32 that sets the ring type */ +#define RADEON_CS_RING_GFX 0 +#define RADEON_CS_RING_COMPUTE 1 +#define RADEON_CS_RING_DMA 2 +#define RADEON_CS_RING_UVD 3 +#define RADEON_CS_RING_VCE 4 +/* The third dword of RADEON_CHUNK_ID_FLAGS is a sint32 that sets the priority */ +/* 0 = normal, + = higher priority, - = lower priority */ + +struct drm_radeon_cs_chunk { + __u32 chunk_id; + __u32 length_dw; + __u64 chunk_data; +}; + +/* drm_radeon_cs_reloc.flags */ +#define RADEON_RELOC_PRIO_MASK (0xf << 0) + +struct drm_radeon_cs_reloc { + __u32 handle; + __u32 read_domains; + __u32 write_domain; + __u32 flags; +}; + +struct drm_radeon_cs { + __u32 num_chunks; + __u32 cs_id; + /* this points to __u64 * which point to cs chunks */ + __u64 chunks; + /* updates to the limits after this CS ioctl */ + __u64 gart_limit; + __u64 vram_limit; +}; + +#define RADEON_INFO_DEVICE_ID 0x00 +#define RADEON_INFO_NUM_GB_PIPES 0x01 +#define RADEON_INFO_NUM_Z_PIPES 0x02 +#define RADEON_INFO_ACCEL_WORKING 0x03 +#define RADEON_INFO_CRTC_FROM_ID 0x04 +#define RADEON_INFO_ACCEL_WORKING2 0x05 +#define RADEON_INFO_TILING_CONFIG 0x06 +#define RADEON_INFO_WANT_HYPERZ 0x07 +#define RADEON_INFO_WANT_CMASK 0x08 /* get access to CMASK on r300 */ +#define RADEON_INFO_CLOCK_CRYSTAL_FREQ 0x09 /* clock crystal frequency */ +#define RADEON_INFO_NUM_BACKENDS 0x0a /* DB/backends for r600+ - need for OQ */ +#define RADEON_INFO_NUM_TILE_PIPES 0x0b /* tile pipes for r600+ */ +#define RADEON_INFO_FUSION_GART_WORKING 0x0c /* fusion writes to GTT were broken before this */ +#define RADEON_INFO_BACKEND_MAP 0x0d /* pipe to backend map, needed by mesa */ +/* virtual address start, va < start are reserved by the kernel */ +#define RADEON_INFO_VA_START 0x0e +/* maximum size of ib using the virtual memory cs */ +#define RADEON_INFO_IB_VM_MAX_SIZE 0x0f +/* max pipes - needed for compute shaders */ +#define RADEON_INFO_MAX_PIPES 0x10 +/* timestamp for GL_ARB_timer_query (OpenGL), returns the current GPU clock */ +#define RADEON_INFO_TIMESTAMP 0x11 +/* max shader engines (SE) - needed for geometry shaders, etc. */ +#define RADEON_INFO_MAX_SE 0x12 +/* max SH per SE */ +#define RADEON_INFO_MAX_SH_PER_SE 0x13 +/* fast fb access is enabled */ +#define RADEON_INFO_FASTFB_WORKING 0x14 +/* query if a RADEON_CS_RING_* submission is supported */ +#define RADEON_INFO_RING_WORKING 0x15 +/* SI tile mode array */ +#define RADEON_INFO_SI_TILE_MODE_ARRAY 0x16 +/* query if CP DMA is supported on the compute ring */ +#define RADEON_INFO_SI_CP_DMA_COMPUTE 0x17 +/* CIK macrotile mode array */ +#define RADEON_INFO_CIK_MACROTILE_MODE_ARRAY 0x18 +/* query the number of render backends */ +#define RADEON_INFO_SI_BACKEND_ENABLED_MASK 0x19 +/* max engine clock - needed for OpenCL */ +#define RADEON_INFO_MAX_SCLK 0x1a +/* version of VCE firmware */ +#define RADEON_INFO_VCE_FW_VERSION 0x1b +/* version of VCE feedback */ +#define RADEON_INFO_VCE_FB_VERSION 0x1c +#define RADEON_INFO_NUM_BYTES_MOVED 0x1d +#define RADEON_INFO_VRAM_USAGE 0x1e +#define RADEON_INFO_GTT_USAGE 0x1f +#define RADEON_INFO_ACTIVE_CU_COUNT 0x20 +#define RADEON_INFO_CURRENT_GPU_TEMP 0x21 +#define RADEON_INFO_CURRENT_GPU_SCLK 0x22 +#define RADEON_INFO_CURRENT_GPU_MCLK 0x23 +#define RADEON_INFO_READ_REG 0x24 +#define RADEON_INFO_VA_UNMAP_WORKING 0x25 +#define RADEON_INFO_GPU_RESET_COUNTER 0x26 + +struct drm_radeon_info { + __u32 request; + __u32 pad; + __u64 value; +}; + +/* Those correspond to the tile index to use, this is to explicitly state + * the API that is implicitly defined by the tile mode array. + */ +#define SI_TILE_MODE_COLOR_LINEAR_ALIGNED 8 +#define SI_TILE_MODE_COLOR_1D 13 +#define SI_TILE_MODE_COLOR_1D_SCANOUT 9 +#define SI_TILE_MODE_COLOR_2D_8BPP 14 +#define SI_TILE_MODE_COLOR_2D_16BPP 15 +#define SI_TILE_MODE_COLOR_2D_32BPP 16 +#define SI_TILE_MODE_COLOR_2D_64BPP 17 +#define SI_TILE_MODE_COLOR_2D_SCANOUT_16BPP 11 +#define SI_TILE_MODE_COLOR_2D_SCANOUT_32BPP 12 +#define SI_TILE_MODE_DEPTH_STENCIL_1D 4 +#define SI_TILE_MODE_DEPTH_STENCIL_2D 0 +#define SI_TILE_MODE_DEPTH_STENCIL_2D_2AA 3 +#define SI_TILE_MODE_DEPTH_STENCIL_2D_4AA 3 +#define SI_TILE_MODE_DEPTH_STENCIL_2D_8AA 2 + +#define CIK_TILE_MODE_DEPTH_STENCIL_1D 5 + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/include/drm/savage_drm.h b/include/drm/savage_drm.h new file mode 100644 index 0000000..1a91234 --- /dev/null +++ b/include/drm/savage_drm.h @@ -0,0 +1,220 @@ +/* savage_drm.h -- Public header for the savage driver + * + * Copyright 2004 Felix Kuehling + * 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 FELIX KUEHLING 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 __SAVAGE_DRM_H__ +#define __SAVAGE_DRM_H__ + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +#ifndef __SAVAGE_SAREA_DEFINES__ +#define __SAVAGE_SAREA_DEFINES__ + +/* 2 heaps (1 for card, 1 for agp), each divided into up to 128 + * regions, subject to a minimum region size of (1<<16) == 64k. + * + * Clients may subdivide regions internally, but when sharing between + * clients, the region size is the minimum granularity. + */ + +#define SAVAGE_CARD_HEAP 0 +#define SAVAGE_AGP_HEAP 1 +#define SAVAGE_NR_TEX_HEAPS 2 +#define SAVAGE_NR_TEX_REGIONS 16 +#define SAVAGE_LOG_MIN_TEX_REGION_SIZE 16 + +#endif /* __SAVAGE_SAREA_DEFINES__ */ + +typedef struct _drm_savage_sarea { + /* LRU lists for texture memory in agp space and on the card. + */ + struct drm_tex_region texList[SAVAGE_NR_TEX_HEAPS][SAVAGE_NR_TEX_REGIONS + + 1]; + unsigned int texAge[SAVAGE_NR_TEX_HEAPS]; + + /* Mechanism to validate card state. + */ + int ctxOwner; +} drm_savage_sarea_t, *drm_savage_sarea_ptr; + +/* Savage-specific ioctls + */ +#define DRM_SAVAGE_BCI_INIT 0x00 +#define DRM_SAVAGE_BCI_CMDBUF 0x01 +#define DRM_SAVAGE_BCI_EVENT_EMIT 0x02 +#define DRM_SAVAGE_BCI_EVENT_WAIT 0x03 + +#define DRM_IOCTL_SAVAGE_BCI_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_INIT, drm_savage_init_t) +#define DRM_IOCTL_SAVAGE_BCI_CMDBUF DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_CMDBUF, drm_savage_cmdbuf_t) +#define DRM_IOCTL_SAVAGE_BCI_EVENT_EMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_SAVAGE_BCI_EVENT_EMIT, drm_savage_event_emit_t) +#define DRM_IOCTL_SAVAGE_BCI_EVENT_WAIT DRM_IOW( DRM_COMMAND_BASE + DRM_SAVAGE_BCI_EVENT_WAIT, drm_savage_event_wait_t) + +#define SAVAGE_DMA_PCI 1 +#define SAVAGE_DMA_AGP 3 +typedef struct drm_savage_init { + enum { + SAVAGE_INIT_BCI = 1, + SAVAGE_CLEANUP_BCI = 2 + } func; + unsigned int sarea_priv_offset; + + /* some parameters */ + unsigned int cob_size; + unsigned int bci_threshold_lo, bci_threshold_hi; + unsigned int dma_type; + + /* frame buffer layout */ + unsigned int fb_bpp; + unsigned int front_offset, front_pitch; + unsigned int back_offset, back_pitch; + unsigned int depth_bpp; + unsigned int depth_offset, depth_pitch; + + /* local textures */ + unsigned int texture_offset; + unsigned int texture_size; + + /* physical locations of non-permanent maps */ + unsigned long status_offset; + unsigned long buffers_offset; + unsigned long agp_textures_offset; + unsigned long cmd_dma_offset; +} drm_savage_init_t; + +typedef union drm_savage_cmd_header drm_savage_cmd_header_t; +typedef struct drm_savage_cmdbuf { + /* command buffer in client's address space */ + drm_savage_cmd_header_t *cmd_addr; + unsigned int size; /* size of the command buffer in 64bit units */ + + unsigned int dma_idx; /* DMA buffer index to use */ + int discard; /* discard DMA buffer when done */ + /* vertex buffer in client's address space */ + unsigned int *vb_addr; + unsigned int vb_size; /* size of client vertex buffer in bytes */ + unsigned int vb_stride; /* stride of vertices in 32bit words */ + /* boxes in client's address space */ + struct drm_clip_rect *box_addr; + unsigned int nbox; /* number of clipping boxes */ +} drm_savage_cmdbuf_t; + +#define SAVAGE_WAIT_2D 0x1 /* wait for 2D idle before updating event tag */ +#define SAVAGE_WAIT_3D 0x2 /* wait for 3D idle before updating event tag */ +#define SAVAGE_WAIT_IRQ 0x4 /* emit or wait for IRQ, not implemented yet */ +typedef struct drm_savage_event { + unsigned int count; + unsigned int flags; +} drm_savage_event_emit_t, drm_savage_event_wait_t; + +/* Commands for the cmdbuf ioctl + */ +#define SAVAGE_CMD_STATE 0 /* a range of state registers */ +#define SAVAGE_CMD_DMA_PRIM 1 /* vertices from DMA buffer */ +#define SAVAGE_CMD_VB_PRIM 2 /* vertices from client vertex buffer */ +#define SAVAGE_CMD_DMA_IDX 3 /* indexed vertices from DMA buffer */ +#define SAVAGE_CMD_VB_IDX 4 /* indexed vertices client vertex buffer */ +#define SAVAGE_CMD_CLEAR 5 /* clear buffers */ +#define SAVAGE_CMD_SWAP 6 /* swap buffers */ + +/* Primitive types +*/ +#define SAVAGE_PRIM_TRILIST 0 /* triangle list */ +#define SAVAGE_PRIM_TRISTRIP 1 /* triangle strip */ +#define SAVAGE_PRIM_TRIFAN 2 /* triangle fan */ +#define SAVAGE_PRIM_TRILIST_201 3 /* reorder verts for correct flat + * shading on s3d */ + +/* Skip flags (vertex format) + */ +#define SAVAGE_SKIP_Z 0x01 +#define SAVAGE_SKIP_W 0x02 +#define SAVAGE_SKIP_C0 0x04 +#define SAVAGE_SKIP_C1 0x08 +#define SAVAGE_SKIP_S0 0x10 +#define SAVAGE_SKIP_T0 0x20 +#define SAVAGE_SKIP_ST0 0x30 +#define SAVAGE_SKIP_S1 0x40 +#define SAVAGE_SKIP_T1 0x80 +#define SAVAGE_SKIP_ST1 0xc0 +#define SAVAGE_SKIP_ALL_S3D 0x3f +#define SAVAGE_SKIP_ALL_S4 0xff + +/* Buffer names for clear command + */ +#define SAVAGE_FRONT 0x1 +#define SAVAGE_BACK 0x2 +#define SAVAGE_DEPTH 0x4 + +/* 64-bit command header + */ +union drm_savage_cmd_header { + struct { + unsigned char cmd; /* command */ + unsigned char pad0; + unsigned short pad1; + unsigned short pad2; + unsigned short pad3; + } cmd; /* generic */ + struct { + unsigned char cmd; + unsigned char global; /* need idle engine? */ + unsigned short count; /* number of consecutive registers */ + unsigned short start; /* first register */ + unsigned short pad3; + } state; /* SAVAGE_CMD_STATE */ + struct { + unsigned char cmd; + unsigned char prim; /* primitive type */ + unsigned short skip; /* vertex format (skip flags) */ + unsigned short count; /* number of vertices */ + unsigned short start; /* first vertex in DMA/vertex buffer */ + } prim; /* SAVAGE_CMD_DMA_PRIM, SAVAGE_CMD_VB_PRIM */ + struct { + unsigned char cmd; + unsigned char prim; + unsigned short skip; + unsigned short count; /* number of indices that follow */ + unsigned short pad3; + } idx; /* SAVAGE_CMD_DMA_IDX, SAVAGE_CMD_VB_IDX */ + struct { + unsigned char cmd; + unsigned char pad0; + unsigned short pad1; + unsigned int flags; + } clear0; /* SAVAGE_CMD_CLEAR */ + struct { + unsigned int mask; + unsigned int value; + } clear1; /* SAVAGE_CMD_CLEAR data */ +}; + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/include/drm/sis_drm.h b/include/drm/sis_drm.h new file mode 100644 index 0000000..8e51bb9 --- /dev/null +++ b/include/drm/sis_drm.h @@ -0,0 +1,77 @@ +/* sis_drv.h -- Private header for sis driver -*- linux-c -*- */ +/* + * Copyright 2005 Eric Anholt + * 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, 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 (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 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. + * + */ + +#ifndef __SIS_DRM_H__ +#define __SIS_DRM_H__ + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/* SiS specific ioctls */ +#define NOT_USED_0_3 +#define DRM_SIS_FB_ALLOC 0x04 +#define DRM_SIS_FB_FREE 0x05 +#define NOT_USED_6_12 +#define DRM_SIS_AGP_INIT 0x13 +#define DRM_SIS_AGP_ALLOC 0x14 +#define DRM_SIS_AGP_FREE 0x15 +#define DRM_SIS_FB_INIT 0x16 + +#define DRM_IOCTL_SIS_FB_ALLOC DRM_IOWR(DRM_COMMAND_BASE + DRM_SIS_FB_ALLOC, drm_sis_mem_t) +#define DRM_IOCTL_SIS_FB_FREE DRM_IOW( DRM_COMMAND_BASE + DRM_SIS_FB_FREE, drm_sis_mem_t) +#define DRM_IOCTL_SIS_AGP_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_SIS_AGP_INIT, drm_sis_agp_t) +#define DRM_IOCTL_SIS_AGP_ALLOC DRM_IOWR(DRM_COMMAND_BASE + DRM_SIS_AGP_ALLOC, drm_sis_mem_t) +#define DRM_IOCTL_SIS_AGP_FREE DRM_IOW( DRM_COMMAND_BASE + DRM_SIS_AGP_FREE, drm_sis_mem_t) +#define DRM_IOCTL_SIS_FB_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_SIS_FB_INIT, drm_sis_fb_t) +/* +#define DRM_IOCTL_SIS_FLIP DRM_IOW( 0x48, drm_sis_flip_t) +#define DRM_IOCTL_SIS_FLIP_INIT DRM_IO( 0x49) +#define DRM_IOCTL_SIS_FLIP_FINAL DRM_IO( 0x50) +*/ + +typedef struct { + int context; + unsigned int offset; + unsigned int size; + unsigned long free; +} drm_sis_mem_t; + +typedef struct { + unsigned int offset, size; +} drm_sis_agp_t; + +typedef struct { + unsigned int offset, size; +} drm_sis_fb_t; + +#if defined(__cplusplus) +} +#endif + +#endif /* __SIS_DRM_H__ */ diff --git a/include/drm/tegra_drm.h b/include/drm/tegra_drm.h new file mode 100644 index 0000000..94cfc30 --- /dev/null +++ b/include/drm/tegra_drm.h @@ -0,0 +1,1060 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright (c) 2012-2020 NVIDIA Corporation */ + +#ifndef _UAPI_TEGRA_DRM_H_ +#define _UAPI_TEGRA_DRM_H_ + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Tegra DRM legacy UAPI. Only enabled with STAGING */ + +#define DRM_TEGRA_GEM_CREATE_TILED (1 << 0) +#define DRM_TEGRA_GEM_CREATE_BOTTOM_UP (1 << 1) + +/** + * struct drm_tegra_gem_create - parameters for the GEM object creation IOCTL + */ +struct drm_tegra_gem_create { + /** + * @size: + * + * The size, in bytes, of the buffer object to be created. + */ + __u64 size; + + /** + * @flags: + * + * A bitmask of flags that influence the creation of GEM objects: + * + * DRM_TEGRA_GEM_CREATE_TILED + * Use the 16x16 tiling format for this buffer. + * + * DRM_TEGRA_GEM_CREATE_BOTTOM_UP + * The buffer has a bottom-up layout. + */ + __u32 flags; + + /** + * @handle: + * + * The handle of the created GEM object. Set by the kernel upon + * successful completion of the IOCTL. + */ + __u32 handle; +}; + +/** + * struct drm_tegra_gem_mmap - parameters for the GEM mmap IOCTL + */ +struct drm_tegra_gem_mmap { + /** + * @handle: + * + * Handle of the GEM object to obtain an mmap offset for. + */ + __u32 handle; + + /** + * @pad: + * + * Structure padding that may be used in the future. Must be 0. + */ + __u32 pad; + + /** + * @offset: + * + * The mmap offset for the given GEM object. Set by the kernel upon + * successful completion of the IOCTL. + */ + __u64 offset; +}; + +/** + * struct drm_tegra_syncpt_read - parameters for the read syncpoint IOCTL + */ +struct drm_tegra_syncpt_read { + /** + * @id: + * + * ID of the syncpoint to read the current value from. + */ + __u32 id; + + /** + * @value: + * + * The current syncpoint value. Set by the kernel upon successful + * completion of the IOCTL. + */ + __u32 value; +}; + +/** + * struct drm_tegra_syncpt_incr - parameters for the increment syncpoint IOCTL + */ +struct drm_tegra_syncpt_incr { + /** + * @id: + * + * ID of the syncpoint to increment. + */ + __u32 id; + + /** + * @pad: + * + * Structure padding that may be used in the future. Must be 0. + */ + __u32 pad; +}; + +/** + * struct drm_tegra_syncpt_wait - parameters for the wait syncpoint IOCTL + */ +struct drm_tegra_syncpt_wait { + /** + * @id: + * + * ID of the syncpoint to wait on. + */ + __u32 id; + + /** + * @thresh: + * + * Threshold value for which to wait. + */ + __u32 thresh; + + /** + * @timeout: + * + * Timeout, in milliseconds, to wait. + */ + __u32 timeout; + + /** + * @value: + * + * The new syncpoint value after the wait. Set by the kernel upon + * successful completion of the IOCTL. + */ + __u32 value; +}; + +#define DRM_TEGRA_NO_TIMEOUT (0xffffffff) + +/** + * struct drm_tegra_open_channel - parameters for the open channel IOCTL + */ +struct drm_tegra_open_channel { + /** + * @client: + * + * The client ID for this channel. + */ + __u32 client; + + /** + * @pad: + * + * Structure padding that may be used in the future. Must be 0. + */ + __u32 pad; + + /** + * @context: + * + * The application context of this channel. Set by the kernel upon + * successful completion of the IOCTL. This context needs to be passed + * to the DRM_TEGRA_CHANNEL_CLOSE or the DRM_TEGRA_SUBMIT IOCTLs. + */ + __u64 context; +}; + +/** + * struct drm_tegra_close_channel - parameters for the close channel IOCTL + */ +struct drm_tegra_close_channel { + /** + * @context: + * + * The application context of this channel. This is obtained from the + * DRM_TEGRA_OPEN_CHANNEL IOCTL. + */ + __u64 context; +}; + +/** + * struct drm_tegra_get_syncpt - parameters for the get syncpoint IOCTL + */ +struct drm_tegra_get_syncpt { + /** + * @context: + * + * The application context identifying the channel for which to obtain + * the syncpoint ID. + */ + __u64 context; + + /** + * @index: + * + * Index of the client syncpoint for which to obtain the ID. + */ + __u32 index; + + /** + * @id: + * + * The ID of the given syncpoint. Set by the kernel upon successful + * completion of the IOCTL. + */ + __u32 id; +}; + +/** + * struct drm_tegra_get_syncpt_base - parameters for the get wait base IOCTL + */ +struct drm_tegra_get_syncpt_base { + /** + * @context: + * + * The application context identifying for which channel to obtain the + * wait base. + */ + __u64 context; + + /** + * @syncpt: + * + * ID of the syncpoint for which to obtain the wait base. + */ + __u32 syncpt; + + /** + * @id: + * + * The ID of the wait base corresponding to the client syncpoint. Set + * by the kernel upon successful completion of the IOCTL. + */ + __u32 id; +}; + +/** + * struct drm_tegra_syncpt - syncpoint increment operation + */ +struct drm_tegra_syncpt { + /** + * @id: + * + * ID of the syncpoint to operate on. + */ + __u32 id; + + /** + * @incrs: + * + * Number of increments to perform for the syncpoint. + */ + __u32 incrs; +}; + +/** + * struct drm_tegra_cmdbuf - structure describing a command buffer + */ +struct drm_tegra_cmdbuf { + /** + * @handle: + * + * Handle to a GEM object containing the command buffer. + */ + __u32 handle; + + /** + * @offset: + * + * Offset, in bytes, into the GEM object identified by @handle at + * which the command buffer starts. + */ + __u32 offset; + + /** + * @words: + * + * Number of 32-bit words in this command buffer. + */ + __u32 words; + + /** + * @pad: + * + * Structure padding that may be used in the future. Must be 0. + */ + __u32 pad; +}; + +/** + * struct drm_tegra_reloc - GEM object relocation structure + */ +struct drm_tegra_reloc { + struct { + /** + * @cmdbuf.handle: + * + * Handle to the GEM object containing the command buffer for + * which to perform this GEM object relocation. + */ + __u32 handle; + + /** + * @cmdbuf.offset: + * + * Offset, in bytes, into the command buffer at which to + * insert the relocated address. + */ + __u32 offset; + } cmdbuf; + struct { + /** + * @target.handle: + * + * Handle to the GEM object to be relocated. + */ + __u32 handle; + + /** + * @target.offset: + * + * Offset, in bytes, into the target GEM object at which the + * relocated data starts. + */ + __u32 offset; + } target; + + /** + * @shift: + * + * The number of bits by which to shift relocated addresses. + */ + __u32 shift; + + /** + * @pad: + * + * Structure padding that may be used in the future. Must be 0. + */ + __u32 pad; +}; + +/** + * struct drm_tegra_waitchk - wait check structure + */ +struct drm_tegra_waitchk { + /** + * @handle: + * + * Handle to the GEM object containing a command stream on which to + * perform the wait check. + */ + __u32 handle; + + /** + * @offset: + * + * Offset, in bytes, of the location in the command stream to perform + * the wait check on. + */ + __u32 offset; + + /** + * @syncpt: + * + * ID of the syncpoint to wait check. + */ + __u32 syncpt; + + /** + * @thresh: + * + * Threshold value for which to check. + */ + __u32 thresh; +}; + +/** + * struct drm_tegra_submit - job submission structure + */ +struct drm_tegra_submit { + /** + * @context: + * + * The application context identifying the channel to use for the + * execution of this job. + */ + __u64 context; + + /** + * @num_syncpts: + * + * The number of syncpoints operated on by this job. This defines the + * length of the array pointed to by @syncpts. + */ + __u32 num_syncpts; + + /** + * @num_cmdbufs: + * + * The number of command buffers to execute as part of this job. This + * defines the length of the array pointed to by @cmdbufs. + */ + __u32 num_cmdbufs; + + /** + * @num_relocs: + * + * The number of relocations to perform before executing this job. + * This defines the length of the array pointed to by @relocs. + */ + __u32 num_relocs; + + /** + * @num_waitchks: + * + * The number of wait checks to perform as part of this job. This + * defines the length of the array pointed to by @waitchks. + */ + __u32 num_waitchks; + + /** + * @waitchk_mask: + * + * Bitmask of valid wait checks. + */ + __u32 waitchk_mask; + + /** + * @timeout: + * + * Timeout, in milliseconds, before this job is cancelled. + */ + __u32 timeout; + + /** + * @syncpts: + * + * A pointer to an array of &struct drm_tegra_syncpt structures that + * specify the syncpoint operations performed as part of this job. + * The number of elements in the array must be equal to the value + * given by @num_syncpts. + */ + __u64 syncpts; + + /** + * @cmdbufs: + * + * A pointer to an array of &struct drm_tegra_cmdbuf structures that + * define the command buffers to execute as part of this job. The + * number of elements in the array must be equal to the value given + * by @num_syncpts. + */ + __u64 cmdbufs; + + /** + * @relocs: + * + * A pointer to an array of &struct drm_tegra_reloc structures that + * specify the relocations that need to be performed before executing + * this job. The number of elements in the array must be equal to the + * value given by @num_relocs. + */ + __u64 relocs; + + /** + * @waitchks: + * + * A pointer to an array of &struct drm_tegra_waitchk structures that + * specify the wait checks to be performed while executing this job. + * The number of elements in the array must be equal to the value + * given by @num_waitchks. + */ + __u64 waitchks; + + /** + * @fence: + * + * The threshold of the syncpoint associated with this job after it + * has been completed. Set by the kernel upon successful completion of + * the IOCTL. This can be used with the DRM_TEGRA_SYNCPT_WAIT IOCTL to + * wait for this job to be finished. + */ + __u32 fence; + + /** + * @reserved: + * + * This field is reserved for future use. Must be 0. + */ + __u32 reserved[5]; +}; + +#define DRM_TEGRA_GEM_TILING_MODE_PITCH 0 +#define DRM_TEGRA_GEM_TILING_MODE_TILED 1 +#define DRM_TEGRA_GEM_TILING_MODE_BLOCK 2 + +/** + * struct drm_tegra_gem_set_tiling - parameters for the set tiling IOCTL + */ +struct drm_tegra_gem_set_tiling { + /** + * @handle: + * + * Handle to the GEM object for which to set the tiling parameters. + */ + __u32 handle; + + /** + * @mode: + * + * The tiling mode to set. Must be one of: + * + * DRM_TEGRA_GEM_TILING_MODE_PITCH + * pitch linear format + * + * DRM_TEGRA_GEM_TILING_MODE_TILED + * 16x16 tiling format + * + * DRM_TEGRA_GEM_TILING_MODE_BLOCK + * 16Bx2 tiling format + */ + __u32 mode; + + /** + * @value: + * + * The value to set for the tiling mode parameter. + */ + __u32 value; + + /** + * @pad: + * + * Structure padding that may be used in the future. Must be 0. + */ + __u32 pad; +}; + +/** + * struct drm_tegra_gem_get_tiling - parameters for the get tiling IOCTL + */ +struct drm_tegra_gem_get_tiling { + /** + * @handle: + * + * Handle to the GEM object for which to query the tiling parameters. + */ + __u32 handle; + + /** + * @mode: + * + * The tiling mode currently associated with the GEM object. Set by + * the kernel upon successful completion of the IOCTL. + */ + __u32 mode; + + /** + * @value: + * + * The tiling mode parameter currently associated with the GEM object. + * Set by the kernel upon successful completion of the IOCTL. + */ + __u32 value; + + /** + * @pad: + * + * Structure padding that may be used in the future. Must be 0. + */ + __u32 pad; +}; + +#define DRM_TEGRA_GEM_BOTTOM_UP (1 << 0) +#define DRM_TEGRA_GEM_FLAGS (DRM_TEGRA_GEM_BOTTOM_UP) + +/** + * struct drm_tegra_gem_set_flags - parameters for the set flags IOCTL + */ +struct drm_tegra_gem_set_flags { + /** + * @handle: + * + * Handle to the GEM object for which to set the flags. + */ + __u32 handle; + + /** + * @flags: + * + * The flags to set for the GEM object. + */ + __u32 flags; +}; + +/** + * struct drm_tegra_gem_get_flags - parameters for the get flags IOCTL + */ +struct drm_tegra_gem_get_flags { + /** + * @handle: + * + * Handle to the GEM object for which to query the flags. + */ + __u32 handle; + + /** + * @flags: + * + * The flags currently associated with the GEM object. Set by the + * kernel upon successful completion of the IOCTL. + */ + __u32 flags; +}; + +#define DRM_TEGRA_GEM_CREATE 0x00 +#define DRM_TEGRA_GEM_MMAP 0x01 +#define DRM_TEGRA_SYNCPT_READ 0x02 +#define DRM_TEGRA_SYNCPT_INCR 0x03 +#define DRM_TEGRA_SYNCPT_WAIT 0x04 +#define DRM_TEGRA_OPEN_CHANNEL 0x05 +#define DRM_TEGRA_CLOSE_CHANNEL 0x06 +#define DRM_TEGRA_GET_SYNCPT 0x07 +#define DRM_TEGRA_SUBMIT 0x08 +#define DRM_TEGRA_GET_SYNCPT_BASE 0x09 +#define DRM_TEGRA_GEM_SET_TILING 0x0a +#define DRM_TEGRA_GEM_GET_TILING 0x0b +#define DRM_TEGRA_GEM_SET_FLAGS 0x0c +#define DRM_TEGRA_GEM_GET_FLAGS 0x0d + +#define DRM_IOCTL_TEGRA_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_CREATE, struct drm_tegra_gem_create) +#define DRM_IOCTL_TEGRA_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_MMAP, struct drm_tegra_gem_mmap) +#define DRM_IOCTL_TEGRA_SYNCPT_READ DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SYNCPT_READ, struct drm_tegra_syncpt_read) +#define DRM_IOCTL_TEGRA_SYNCPT_INCR DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SYNCPT_INCR, struct drm_tegra_syncpt_incr) +#define DRM_IOCTL_TEGRA_SYNCPT_WAIT DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SYNCPT_WAIT, struct drm_tegra_syncpt_wait) +#define DRM_IOCTL_TEGRA_OPEN_CHANNEL DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_OPEN_CHANNEL, struct drm_tegra_open_channel) +#define DRM_IOCTL_TEGRA_CLOSE_CHANNEL DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_CLOSE_CHANNEL, struct drm_tegra_close_channel) +#define DRM_IOCTL_TEGRA_GET_SYNCPT DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GET_SYNCPT, struct drm_tegra_get_syncpt) +#define DRM_IOCTL_TEGRA_SUBMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_SUBMIT, struct drm_tegra_submit) +#define DRM_IOCTL_TEGRA_GET_SYNCPT_BASE DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GET_SYNCPT_BASE, struct drm_tegra_get_syncpt_base) +#define DRM_IOCTL_TEGRA_GEM_SET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_SET_TILING, struct drm_tegra_gem_set_tiling) +#define DRM_IOCTL_TEGRA_GEM_GET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_GET_TILING, struct drm_tegra_gem_get_tiling) +#define DRM_IOCTL_TEGRA_GEM_SET_FLAGS DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_SET_FLAGS, struct drm_tegra_gem_set_flags) +#define DRM_IOCTL_TEGRA_GEM_GET_FLAGS DRM_IOWR(DRM_COMMAND_BASE + DRM_TEGRA_GEM_GET_FLAGS, struct drm_tegra_gem_get_flags) + +/* New Tegra DRM UAPI */ + +/* + * Reported by the driver in the `capabilities` field. + * + * DRM_TEGRA_CHANNEL_CAP_CACHE_COHERENT: If set, the engine is cache coherent + * with regard to the system memory. + */ +#define DRM_TEGRA_CHANNEL_CAP_CACHE_COHERENT (1 << 0) + +struct drm_tegra_channel_open { + /** + * @host1x_class: [in] + * + * Host1x class of the engine that will be programmed using this + * channel. + */ + __u32 host1x_class; + + /** + * @flags: [in] + * + * Flags. + */ + __u32 flags; + + /** + * @context: [out] + * + * Opaque identifier corresponding to the opened channel. + */ + __u32 context; + + /** + * @version: [out] + * + * Version of the engine hardware. This can be used by userspace + * to determine how the engine needs to be programmed. + */ + __u32 version; + + /** + * @capabilities: [out] + * + * Flags describing the hardware capabilities. + */ + __u32 capabilities; + __u32 padding; +}; + +struct drm_tegra_channel_close { + /** + * @context: [in] + * + * Identifier of the channel to close. + */ + __u32 context; + __u32 padding; +}; + +/* + * Mapping flags that can be used to influence how the mapping is created. + * + * DRM_TEGRA_CHANNEL_MAP_READ: create mapping that allows HW read access + * DRM_TEGRA_CHANNEL_MAP_WRITE: create mapping that allows HW write access + */ +#define DRM_TEGRA_CHANNEL_MAP_READ (1 << 0) +#define DRM_TEGRA_CHANNEL_MAP_WRITE (1 << 1) +#define DRM_TEGRA_CHANNEL_MAP_READ_WRITE (DRM_TEGRA_CHANNEL_MAP_READ | \ + DRM_TEGRA_CHANNEL_MAP_WRITE) + +struct drm_tegra_channel_map { + /** + * @context: [in] + * + * Identifier of the channel to which make memory available for. + */ + __u32 context; + + /** + * @handle: [in] + * + * GEM handle of the memory to map. + */ + __u32 handle; + + /** + * @flags: [in] + * + * Flags. + */ + __u32 flags; + + /** + * @mapping: [out] + * + * Identifier corresponding to the mapping, to be used for + * relocations or unmapping later. + */ + __u32 mapping; +}; + +struct drm_tegra_channel_unmap { + /** + * @context: [in] + * + * Channel identifier of the channel to unmap memory from. + */ + __u32 context; + + /** + * @mapping: [in] + * + * Mapping identifier of the memory mapping to unmap. + */ + __u32 mapping; +}; + +/* Submission */ + +/** + * Specify that bit 39 of the patched-in address should be set to switch + * swizzling between Tegra and non-Tegra sector layout on systems that store + * surfaces in system memory in non-Tegra sector layout. + */ +#define DRM_TEGRA_SUBMIT_RELOC_SECTOR_LAYOUT (1 << 0) + +struct drm_tegra_submit_buf { + /** + * @mapping: [in] + * + * Identifier of the mapping to use in the submission. + */ + __u32 mapping; + + /** + * @flags: [in] + * + * Flags. + */ + __u32 flags; + + /** + * Information for relocation patching. + */ + struct { + /** + * @target_offset: [in] + * + * Offset from the start of the mapping of the data whose + * address is to be patched into the gather. + */ + __u64 target_offset; + + /** + * @gather_offset_words: [in] + * + * Offset in words from the start of the gather data to + * where the address should be patched into. + */ + __u32 gather_offset_words; + + /** + * @shift: [in] + * + * Number of bits the address should be shifted right before + * patching in. + */ + __u32 shift; + } reloc; +}; + +/** + * Execute `words` words of Host1x opcodes specified in the `gather_data_ptr` + * buffer. Each GATHER_UPTR command uses successive words from the buffer. + */ +#define DRM_TEGRA_SUBMIT_CMD_GATHER_UPTR 0 +/** + * Wait for a syncpoint to reach a value before continuing with further + * commands. + */ +#define DRM_TEGRA_SUBMIT_CMD_WAIT_SYNCPT 1 +/** + * Wait for a syncpoint to reach a value before continuing with further + * commands. The threshold is calculated relative to the start of the job. + */ +#define DRM_TEGRA_SUBMIT_CMD_WAIT_SYNCPT_RELATIVE 2 + +struct drm_tegra_submit_cmd_gather_uptr { + __u32 words; + __u32 reserved[3]; +}; + +struct drm_tegra_submit_cmd_wait_syncpt { + __u32 id; + __u32 value; + __u32 reserved[2]; +}; + +struct drm_tegra_submit_cmd { + /** + * @type: [in] + * + * Command type to execute. One of the DRM_TEGRA_SUBMIT_CMD* + * defines. + */ + __u32 type; + + /** + * @flags: [in] + * + * Flags. + */ + __u32 flags; + + union { + struct drm_tegra_submit_cmd_gather_uptr gather_uptr; + struct drm_tegra_submit_cmd_wait_syncpt wait_syncpt; + __u32 reserved[4]; + }; +}; + +struct drm_tegra_submit_syncpt { + /** + * @id: [in] + * + * ID of the syncpoint that the job will increment. + */ + __u32 id; + + /** + * @flags: [in] + * + * Flags. + */ + __u32 flags; + + /** + * @increments: [in] + * + * Number of times the job will increment this syncpoint. + */ + __u32 increments; + + /** + * @value: [out] + * + * Value the syncpoint will have once the job has completed all + * its specified syncpoint increments. + * + * Note that the kernel may increment the syncpoint before or after + * the job. These increments are not reflected in this field. + * + * If the job hangs or times out, not all of the increments may + * get executed. + */ + __u32 value; +}; + +struct drm_tegra_channel_submit { + /** + * @context: [in] + * + * Identifier of the channel to submit this job to. + */ + __u32 context; + + /** + * @num_bufs: [in] + * + * Number of elements in the `bufs_ptr` array. + */ + __u32 num_bufs; + + /** + * @num_cmds: [in] + * + * Number of elements in the `cmds_ptr` array. + */ + __u32 num_cmds; + + /** + * @gather_data_words: [in] + * + * Number of 32-bit words in the `gather_data_ptr` array. + */ + __u32 gather_data_words; + + /** + * @bufs_ptr: [in] + * + * Pointer to an array of drm_tegra_submit_buf structures. + */ + __u64 bufs_ptr; + + /** + * @cmds_ptr: [in] + * + * Pointer to an array of drm_tegra_submit_cmd structures. + */ + __u64 cmds_ptr; + + /** + * @gather_data_ptr: [in] + * + * Pointer to an array of Host1x opcodes to be used by GATHER_UPTR + * commands. + */ + __u64 gather_data_ptr; + + /** + * @syncobj_in: [in] + * + * Handle for DRM syncobj that will be waited before submission. + * Ignored if zero. + */ + __u32 syncobj_in; + + /** + * @syncobj_out: [in] + * + * Handle for DRM syncobj that will have its fence replaced with + * the job's completion fence. Ignored if zero. + */ + __u32 syncobj_out; + + /** + * @syncpt_incr: [in,out] + * + * Information about the syncpoint the job will increment. + */ + struct drm_tegra_submit_syncpt syncpt; +}; + +struct drm_tegra_syncpoint_allocate { + /** + * @id: [out] + * + * ID of allocated syncpoint. + */ + __u32 id; + __u32 padding; +}; + +struct drm_tegra_syncpoint_free { + /** + * @id: [in] + * + * ID of syncpoint to free. + */ + __u32 id; + __u32 padding; +}; + +struct drm_tegra_syncpoint_wait { + /** + * @timeout: [in] + * + * Absolute timestamp at which the wait will time out. + */ + __s64 timeout_ns; + + /** + * @id: [in] + * + * ID of syncpoint to wait on. + */ + __u32 id; + + /** + * @threshold: [in] + * + * Threshold to wait for. + */ + __u32 threshold; + + /** + * @value: [out] + * + * Value of the syncpoint upon wait completion. + */ + __u32 value; + + __u32 padding; +}; + +#define DRM_IOCTL_TEGRA_CHANNEL_OPEN DRM_IOWR(DRM_COMMAND_BASE + 0x10, struct drm_tegra_channel_open) +#define DRM_IOCTL_TEGRA_CHANNEL_CLOSE DRM_IOWR(DRM_COMMAND_BASE + 0x11, struct drm_tegra_channel_close) +#define DRM_IOCTL_TEGRA_CHANNEL_MAP DRM_IOWR(DRM_COMMAND_BASE + 0x12, struct drm_tegra_channel_map) +#define DRM_IOCTL_TEGRA_CHANNEL_UNMAP DRM_IOWR(DRM_COMMAND_BASE + 0x13, struct drm_tegra_channel_unmap) +#define DRM_IOCTL_TEGRA_CHANNEL_SUBMIT DRM_IOWR(DRM_COMMAND_BASE + 0x14, struct drm_tegra_channel_submit) + +#define DRM_IOCTL_TEGRA_SYNCPOINT_ALLOCATE DRM_IOWR(DRM_COMMAND_BASE + 0x20, struct drm_tegra_syncpoint_allocate) +#define DRM_IOCTL_TEGRA_SYNCPOINT_FREE DRM_IOWR(DRM_COMMAND_BASE + 0x21, struct drm_tegra_syncpoint_free) +#define DRM_IOCTL_TEGRA_SYNCPOINT_WAIT DRM_IOWR(DRM_COMMAND_BASE + 0x22, struct drm_tegra_syncpoint_wait) + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/include/drm/vc4_drm.h b/include/drm/vc4_drm.h new file mode 100644 index 0000000..31f50de --- /dev/null +++ b/include/drm/vc4_drm.h @@ -0,0 +1,442 @@ +/* + * Copyright © 2014-2015 Broadcom + * + * 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 (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 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. + */ + +#ifndef _VC4_DRM_H_ +#define _VC4_DRM_H_ + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +#define DRM_VC4_SUBMIT_CL 0x00 +#define DRM_VC4_WAIT_SEQNO 0x01 +#define DRM_VC4_WAIT_BO 0x02 +#define DRM_VC4_CREATE_BO 0x03 +#define DRM_VC4_MMAP_BO 0x04 +#define DRM_VC4_CREATE_SHADER_BO 0x05 +#define DRM_VC4_GET_HANG_STATE 0x06 +#define DRM_VC4_GET_PARAM 0x07 +#define DRM_VC4_SET_TILING 0x08 +#define DRM_VC4_GET_TILING 0x09 +#define DRM_VC4_LABEL_BO 0x0a +#define DRM_VC4_GEM_MADVISE 0x0b +#define DRM_VC4_PERFMON_CREATE 0x0c +#define DRM_VC4_PERFMON_DESTROY 0x0d +#define DRM_VC4_PERFMON_GET_VALUES 0x0e + +#define DRM_IOCTL_VC4_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl) +#define DRM_IOCTL_VC4_WAIT_SEQNO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno) +#define DRM_IOCTL_VC4_WAIT_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_BO, struct drm_vc4_wait_bo) +#define DRM_IOCTL_VC4_CREATE_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_CREATE_BO, struct drm_vc4_create_bo) +#define DRM_IOCTL_VC4_MMAP_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_MMAP_BO, struct drm_vc4_mmap_bo) +#define DRM_IOCTL_VC4_CREATE_SHADER_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_CREATE_SHADER_BO, struct drm_vc4_create_shader_bo) +#define DRM_IOCTL_VC4_GET_HANG_STATE DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_HANG_STATE, struct drm_vc4_get_hang_state) +#define DRM_IOCTL_VC4_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_PARAM, struct drm_vc4_get_param) +#define DRM_IOCTL_VC4_SET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SET_TILING, struct drm_vc4_set_tiling) +#define DRM_IOCTL_VC4_GET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_TILING, struct drm_vc4_get_tiling) +#define DRM_IOCTL_VC4_LABEL_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_LABEL_BO, struct drm_vc4_label_bo) +#define DRM_IOCTL_VC4_GEM_MADVISE DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GEM_MADVISE, struct drm_vc4_gem_madvise) +#define DRM_IOCTL_VC4_PERFMON_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_PERFMON_CREATE, struct drm_vc4_perfmon_create) +#define DRM_IOCTL_VC4_PERFMON_DESTROY DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_PERFMON_DESTROY, struct drm_vc4_perfmon_destroy) +#define DRM_IOCTL_VC4_PERFMON_GET_VALUES DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_PERFMON_GET_VALUES, struct drm_vc4_perfmon_get_values) + +struct drm_vc4_submit_rcl_surface { + __u32 hindex; /* Handle index, or ~0 if not present. */ + __u32 offset; /* Offset to start of buffer. */ + /* + * Bits for either render config (color_write) or load/store packet. + * Bits should all be 0 for MSAA load/stores. + */ + __u16 bits; + +#define VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES (1 << 0) + __u16 flags; +}; + +/** + * struct drm_vc4_submit_cl - ioctl argument for submitting commands to the 3D + * engine. + * + * Drivers typically use GPU BOs to store batchbuffers / command lists and + * their associated state. However, because the VC4 lacks an MMU, we have to + * do validation of memory accesses by the GPU commands. If we were to store + * our commands in BOs, we'd need to do uncached readback from them to do the + * validation process, which is too expensive. Instead, userspace accumulates + * commands and associated state in plain memory, then the kernel copies the + * data to its own address space, and then validates and stores it in a GPU + * BO. + */ +struct drm_vc4_submit_cl { + /* Pointer to the binner command list. + * + * This is the first set of commands executed, which runs the + * coordinate shader to determine where primitives land on the screen, + * then writes out the state updates and draw calls necessary per tile + * to the tile allocation BO. + */ + __u64 bin_cl; + + /* Pointer to the shader records. + * + * Shader records are the structures read by the hardware that contain + * pointers to uniforms, shaders, and vertex attributes. The + * reference to the shader record has enough information to determine + * how many pointers are necessary (fixed number for shaders/uniforms, + * and an attribute count), so those BO indices into bo_handles are + * just stored as __u32s before each shader record passed in. + */ + __u64 shader_rec; + + /* Pointer to uniform data and texture handles for the textures + * referenced by the shader. + * + * For each shader state record, there is a set of uniform data in the + * order referenced by the record (FS, VS, then CS). Each set of + * uniform data has a __u32 index into bo_handles per texture + * sample operation, in the order the QPU_W_TMUn_S writes appear in + * the program. Following the texture BO handle indices is the actual + * uniform data. + * + * The individual uniform state blocks don't have sizes passed in, + * because the kernel has to determine the sizes anyway during shader + * code validation. + */ + __u64 uniforms; + __u64 bo_handles; + + /* Size in bytes of the binner command list. */ + __u32 bin_cl_size; + /* Size in bytes of the set of shader records. */ + __u32 shader_rec_size; + /* Number of shader records. + * + * This could just be computed from the contents of shader_records and + * the address bits of references to them from the bin CL, but it + * keeps the kernel from having to resize some allocations it makes. + */ + __u32 shader_rec_count; + /* Size in bytes of the uniform state. */ + __u32 uniforms_size; + + /* Number of BO handles passed in (size is that times 4). */ + __u32 bo_handle_count; + + /* RCL setup: */ + __u16 width; + __u16 height; + __u8 min_x_tile; + __u8 min_y_tile; + __u8 max_x_tile; + __u8 max_y_tile; + struct drm_vc4_submit_rcl_surface color_read; + struct drm_vc4_submit_rcl_surface color_write; + struct drm_vc4_submit_rcl_surface zs_read; + struct drm_vc4_submit_rcl_surface zs_write; + struct drm_vc4_submit_rcl_surface msaa_color_write; + struct drm_vc4_submit_rcl_surface msaa_zs_write; + __u32 clear_color[2]; + __u32 clear_z; + __u8 clear_s; + + __u32 pad:24; + +#define VC4_SUBMIT_CL_USE_CLEAR_COLOR (1 << 0) +/* By default, the kernel gets to choose the order that the tiles are + * rendered in. If this is set, then the tiles will be rendered in a + * raster order, with the right-to-left vs left-to-right and + * top-to-bottom vs bottom-to-top dictated by + * VC4_SUBMIT_CL_RCL_ORDER_INCREASING_*. This allows overlapping + * blits to be implemented using the 3D engine. + */ +#define VC4_SUBMIT_CL_FIXED_RCL_ORDER (1 << 1) +#define VC4_SUBMIT_CL_RCL_ORDER_INCREASING_X (1 << 2) +#define VC4_SUBMIT_CL_RCL_ORDER_INCREASING_Y (1 << 3) + __u32 flags; + + /* Returned value of the seqno of this render job (for the + * wait ioctl). + */ + __u64 seqno; + + /* ID of the perfmon to attach to this job. 0 means no perfmon. */ + __u32 perfmonid; + + /* Syncobj handle to wait on. If set, processing of this render job + * will not start until the syncobj is signaled. 0 means ignore. + */ + __u32 in_sync; + + /* Syncobj handle to export fence to. If set, the fence in the syncobj + * will be replaced with a fence that signals upon completion of this + * render job. 0 means ignore. + */ + __u32 out_sync; + + __u32 pad2; +}; + +/** + * struct drm_vc4_wait_seqno - ioctl argument for waiting for + * DRM_VC4_SUBMIT_CL completion using its returned seqno. + * + * timeout_ns is the timeout in nanoseconds, where "0" means "don't + * block, just return the status." + */ +struct drm_vc4_wait_seqno { + __u64 seqno; + __u64 timeout_ns; +}; + +/** + * struct drm_vc4_wait_bo - ioctl argument for waiting for + * completion of the last DRM_VC4_SUBMIT_CL on a BO. + * + * This is useful for cases where multiple processes might be + * rendering to a BO and you want to wait for all rendering to be + * completed. + */ +struct drm_vc4_wait_bo { + __u32 handle; + __u32 pad; + __u64 timeout_ns; +}; + +/** + * struct drm_vc4_create_bo - ioctl argument for creating VC4 BOs. + * + * There are currently no values for the flags argument, but it may be + * used in a future extension. + */ +struct drm_vc4_create_bo { + __u32 size; + __u32 flags; + /** Returned GEM handle for the BO. */ + __u32 handle; + __u32 pad; +}; + +/** + * struct drm_vc4_mmap_bo - ioctl argument for mapping VC4 BOs. + * + * This doesn't actually perform an mmap. Instead, it returns the + * offset you need to use in an mmap on the DRM device node. This + * means that tools like valgrind end up knowing about the mapped + * memory. + * + * There are currently no values for the flags argument, but it may be + * used in a future extension. + */ +struct drm_vc4_mmap_bo { + /** Handle for the object being mapped. */ + __u32 handle; + __u32 flags; + /** offset into the drm node to use for subsequent mmap call. */ + __u64 offset; +}; + +/** + * struct drm_vc4_create_shader_bo - ioctl argument for creating VC4 + * shader BOs. + * + * Since allowing a shader to be overwritten while it's also being + * executed from would allow privlege escalation, shaders must be + * created using this ioctl, and they can't be mmapped later. + */ +struct drm_vc4_create_shader_bo { + /* Size of the data argument. */ + __u32 size; + /* Flags, currently must be 0. */ + __u32 flags; + + /* Pointer to the data. */ + __u64 data; + + /** Returned GEM handle for the BO. */ + __u32 handle; + /* Pad, must be 0. */ + __u32 pad; +}; + +struct drm_vc4_get_hang_state_bo { + __u32 handle; + __u32 paddr; + __u32 size; + __u32 pad; +}; + +/** + * struct drm_vc4_hang_state - ioctl argument for collecting state + * from a GPU hang for analysis. +*/ +struct drm_vc4_get_hang_state { + /** Pointer to array of struct drm_vc4_get_hang_state_bo. */ + __u64 bo; + /** + * On input, the size of the bo array. Output is the number + * of bos to be returned. + */ + __u32 bo_count; + + __u32 start_bin, start_render; + + __u32 ct0ca, ct0ea; + __u32 ct1ca, ct1ea; + __u32 ct0cs, ct1cs; + __u32 ct0ra0, ct1ra0; + + __u32 bpca, bpcs; + __u32 bpoa, bpos; + + __u32 vpmbase; + + __u32 dbge; + __u32 fdbgo; + __u32 fdbgb; + __u32 fdbgr; + __u32 fdbgs; + __u32 errstat; + + /* Pad that we may save more registers into in the future. */ + __u32 pad[16]; +}; + +#define DRM_VC4_PARAM_V3D_IDENT0 0 +#define DRM_VC4_PARAM_V3D_IDENT1 1 +#define DRM_VC4_PARAM_V3D_IDENT2 2 +#define DRM_VC4_PARAM_SUPPORTS_BRANCHES 3 +#define DRM_VC4_PARAM_SUPPORTS_ETC1 4 +#define DRM_VC4_PARAM_SUPPORTS_THREADED_FS 5 +#define DRM_VC4_PARAM_SUPPORTS_FIXED_RCL_ORDER 6 +#define DRM_VC4_PARAM_SUPPORTS_MADVISE 7 +#define DRM_VC4_PARAM_SUPPORTS_PERFMON 8 + +struct drm_vc4_get_param { + __u32 param; + __u32 pad; + __u64 value; +}; + +struct drm_vc4_get_tiling { + __u32 handle; + __u32 flags; + __u64 modifier; +}; + +struct drm_vc4_set_tiling { + __u32 handle; + __u32 flags; + __u64 modifier; +}; + +/** + * struct drm_vc4_label_bo - Attach a name to a BO for debug purposes. + */ +struct drm_vc4_label_bo { + __u32 handle; + __u32 len; + __u64 name; +}; + +/* + * States prefixed with '__' are internal states and cannot be passed to the + * DRM_IOCTL_VC4_GEM_MADVISE ioctl. + */ +#define VC4_MADV_WILLNEED 0 +#define VC4_MADV_DONTNEED 1 +#define __VC4_MADV_PURGED 2 +#define __VC4_MADV_NOTSUPP 3 + +struct drm_vc4_gem_madvise { + __u32 handle; + __u32 madv; + __u32 retained; + __u32 pad; +}; + +enum { + VC4_PERFCNT_FEP_VALID_PRIMS_NO_RENDER, + VC4_PERFCNT_FEP_VALID_PRIMS_RENDER, + VC4_PERFCNT_FEP_CLIPPED_QUADS, + VC4_PERFCNT_FEP_VALID_QUADS, + VC4_PERFCNT_TLB_QUADS_NOT_PASSING_STENCIL, + VC4_PERFCNT_TLB_QUADS_NOT_PASSING_Z_AND_STENCIL, + VC4_PERFCNT_TLB_QUADS_PASSING_Z_AND_STENCIL, + VC4_PERFCNT_TLB_QUADS_ZERO_COVERAGE, + VC4_PERFCNT_TLB_QUADS_NON_ZERO_COVERAGE, + VC4_PERFCNT_TLB_QUADS_WRITTEN_TO_COLOR_BUF, + VC4_PERFCNT_PLB_PRIMS_OUTSIDE_VIEWPORT, + VC4_PERFCNT_PLB_PRIMS_NEED_CLIPPING, + VC4_PERFCNT_PSE_PRIMS_REVERSED, + VC4_PERFCNT_QPU_TOTAL_IDLE_CYCLES, + VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_VERTEX_COORD_SHADING, + VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_FRAGMENT_SHADING, + VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_EXEC_VALID_INST, + VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_WAITING_TMUS, + VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_WAITING_SCOREBOARD, + VC4_PERFCNT_QPU_TOTAL_CLK_CYCLES_WAITING_VARYINGS, + VC4_PERFCNT_QPU_TOTAL_INST_CACHE_HIT, + VC4_PERFCNT_QPU_TOTAL_INST_CACHE_MISS, + VC4_PERFCNT_QPU_TOTAL_UNIFORM_CACHE_HIT, + VC4_PERFCNT_QPU_TOTAL_UNIFORM_CACHE_MISS, + VC4_PERFCNT_TMU_TOTAL_TEXT_QUADS_PROCESSED, + VC4_PERFCNT_TMU_TOTAL_TEXT_CACHE_MISS, + VC4_PERFCNT_VPM_TOTAL_CLK_CYCLES_VDW_STALLED, + VC4_PERFCNT_VPM_TOTAL_CLK_CYCLES_VCD_STALLED, + VC4_PERFCNT_L2C_TOTAL_L2_CACHE_HIT, + VC4_PERFCNT_L2C_TOTAL_L2_CACHE_MISS, + VC4_PERFCNT_NUM_EVENTS, +}; + +#define DRM_VC4_MAX_PERF_COUNTERS 16 + +struct drm_vc4_perfmon_create { + __u32 id; + __u32 ncounters; + __u8 events[DRM_VC4_MAX_PERF_COUNTERS]; +}; + +struct drm_vc4_perfmon_destroy { + __u32 id; +}; + +/* + * Returns the values of the performance counters tracked by this + * perfmon (as an array of ncounters u64 values). + * + * No implicit synchronization is performed, so the user has to + * guarantee that any jobs using this perfmon have already been + * completed (probably by blocking on the seqno returned by the + * last exec that used the perfmon). + */ +struct drm_vc4_perfmon_get_values { + __u32 id; + __u64 values_ptr; +}; + +#if defined(__cplusplus) +} +#endif + +#endif /* _VC4_DRM_H_ */ diff --git a/include/drm/via_drm.h b/include/drm/via_drm.h new file mode 100644 index 0000000..8b69e81 --- /dev/null +++ b/include/drm/via_drm.h @@ -0,0 +1,283 @@ +/* + * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. + * Copyright 2001-2003 S3 Graphics, Inc. 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 + * VIA, S3 GRAPHICS, 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 _VIA_DRM_H_ +#define _VIA_DRM_H_ + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/* WARNING: These defines must be the same as what the Xserver uses. + * if you change them, you must change the defines in the Xserver. + */ + +#ifndef _VIA_DEFINES_ +#define _VIA_DEFINES_ + +#include "via_drmclient.h" + +#define VIA_NR_SAREA_CLIPRECTS 8 +#define VIA_NR_XVMC_PORTS 10 +#define VIA_NR_XVMC_LOCKS 5 +#define VIA_MAX_CACHELINE_SIZE 64 +#define XVMCLOCKPTR(saPriv,lockNo) \ + ((__volatile__ struct drm_hw_lock *)(((((unsigned long) (saPriv)->XvMCLockArea) + \ + (VIA_MAX_CACHELINE_SIZE - 1)) & \ + ~(VIA_MAX_CACHELINE_SIZE - 1)) + \ + VIA_MAX_CACHELINE_SIZE*(lockNo))) + +/* Each region is a minimum of 64k, and there are at most 64 of them. + */ +#define VIA_NR_TEX_REGIONS 64 +#define VIA_LOG_MIN_TEX_REGION_SIZE 16 +#endif + +#define VIA_UPLOAD_TEX0IMAGE 0x1 /* handled clientside */ +#define VIA_UPLOAD_TEX1IMAGE 0x2 /* handled clientside */ +#define VIA_UPLOAD_CTX 0x4 +#define VIA_UPLOAD_BUFFERS 0x8 +#define VIA_UPLOAD_TEX0 0x10 +#define VIA_UPLOAD_TEX1 0x20 +#define VIA_UPLOAD_CLIPRECTS 0x40 +#define VIA_UPLOAD_ALL 0xff + +/* VIA specific ioctls */ +#define DRM_VIA_ALLOCMEM 0x00 +#define DRM_VIA_FREEMEM 0x01 +#define DRM_VIA_AGP_INIT 0x02 +#define DRM_VIA_FB_INIT 0x03 +#define DRM_VIA_MAP_INIT 0x04 +#define DRM_VIA_DEC_FUTEX 0x05 +#define NOT_USED +#define DRM_VIA_DMA_INIT 0x07 +#define DRM_VIA_CMDBUFFER 0x08 +#define DRM_VIA_FLUSH 0x09 +#define DRM_VIA_PCICMD 0x0a +#define DRM_VIA_CMDBUF_SIZE 0x0b +#define NOT_USED +#define DRM_VIA_WAIT_IRQ 0x0d +#define DRM_VIA_DMA_BLIT 0x0e +#define DRM_VIA_BLIT_SYNC 0x0f + +#define DRM_IOCTL_VIA_ALLOCMEM DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_ALLOCMEM, drm_via_mem_t) +#define DRM_IOCTL_VIA_FREEMEM DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_FREEMEM, drm_via_mem_t) +#define DRM_IOCTL_VIA_AGP_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_AGP_INIT, drm_via_agp_t) +#define DRM_IOCTL_VIA_FB_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_FB_INIT, drm_via_fb_t) +#define DRM_IOCTL_VIA_MAP_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_MAP_INIT, drm_via_init_t) +#define DRM_IOCTL_VIA_DEC_FUTEX DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_DEC_FUTEX, drm_via_futex_t) +#define DRM_IOCTL_VIA_DMA_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_DMA_INIT, drm_via_dma_init_t) +#define DRM_IOCTL_VIA_CMDBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_CMDBUFFER, drm_via_cmdbuffer_t) +#define DRM_IOCTL_VIA_FLUSH DRM_IO( DRM_COMMAND_BASE + DRM_VIA_FLUSH) +#define DRM_IOCTL_VIA_PCICMD DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_PCICMD, drm_via_cmdbuffer_t) +#define DRM_IOCTL_VIA_CMDBUF_SIZE DRM_IOWR( DRM_COMMAND_BASE + DRM_VIA_CMDBUF_SIZE, \ + drm_via_cmdbuf_size_t) +#define DRM_IOCTL_VIA_WAIT_IRQ DRM_IOWR( DRM_COMMAND_BASE + DRM_VIA_WAIT_IRQ, drm_via_irqwait_t) +#define DRM_IOCTL_VIA_DMA_BLIT DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_DMA_BLIT, drm_via_dmablit_t) +#define DRM_IOCTL_VIA_BLIT_SYNC DRM_IOW(DRM_COMMAND_BASE + DRM_VIA_BLIT_SYNC, drm_via_blitsync_t) + +/* Indices into buf.Setup where various bits of state are mirrored per + * context and per buffer. These can be fired at the card as a unit, + * or in a piecewise fashion as required. + */ + +#define VIA_TEX_SETUP_SIZE 8 + +/* Flags for clear ioctl + */ +#define VIA_FRONT 0x1 +#define VIA_BACK 0x2 +#define VIA_DEPTH 0x4 +#define VIA_STENCIL 0x8 +#define VIA_MEM_VIDEO 0 /* matches drm constant */ +#define VIA_MEM_AGP 1 /* matches drm constant */ +#define VIA_MEM_SYSTEM 2 +#define VIA_MEM_MIXED 3 +#define VIA_MEM_UNKNOWN 4 + +typedef struct { + __u32 offset; + __u32 size; +} drm_via_agp_t; + +typedef struct { + __u32 offset; + __u32 size; +} drm_via_fb_t; + +typedef struct { + __u32 context; + __u32 type; + __u32 size; + unsigned long index; + unsigned long offset; +} drm_via_mem_t; + +typedef struct _drm_via_init { + enum { + VIA_INIT_MAP = 0x01, + VIA_CLEANUP_MAP = 0x02 + } func; + + unsigned long sarea_priv_offset; + unsigned long fb_offset; + unsigned long mmio_offset; + unsigned long agpAddr; +} drm_via_init_t; + +typedef struct _drm_via_futex { + enum { + VIA_FUTEX_WAIT = 0x00, + VIA_FUTEX_WAKE = 0X01 + } func; + __u32 ms; + __u32 lock; + __u32 val; +} drm_via_futex_t; + +typedef struct _drm_via_dma_init { + enum { + VIA_INIT_DMA = 0x01, + VIA_CLEANUP_DMA = 0x02, + VIA_DMA_INITIALIZED = 0x03 + } func; + + unsigned long offset; + unsigned long size; + unsigned long reg_pause_addr; +} drm_via_dma_init_t; + +typedef struct _drm_via_cmdbuffer { + char *buf; + unsigned long size; +} drm_via_cmdbuffer_t; + +/* Warning: If you change the SAREA structure you must change the Xserver + * structure as well */ + +typedef struct _drm_via_tex_region { + unsigned char next, prev; /* indices to form a circular LRU */ + unsigned char inUse; /* owned by a client, or free? */ + int age; /* tracked by clients to update local LRU's */ +} drm_via_tex_region_t; + +typedef struct _drm_via_sarea { + unsigned int dirty; + unsigned int nbox; + struct drm_clip_rect boxes[VIA_NR_SAREA_CLIPRECTS]; + drm_via_tex_region_t texList[VIA_NR_TEX_REGIONS + 1]; + int texAge; /* last time texture was uploaded */ + int ctxOwner; /* last context to upload state */ + int vertexPrim; + + /* + * Below is for XvMC. + * We want the lock integers alone on, and aligned to, a cache line. + * Therefore this somewhat strange construct. + */ + + char XvMCLockArea[VIA_MAX_CACHELINE_SIZE * (VIA_NR_XVMC_LOCKS + 1)]; + + unsigned int XvMCDisplaying[VIA_NR_XVMC_PORTS]; + unsigned int XvMCSubPicOn[VIA_NR_XVMC_PORTS]; + unsigned int XvMCCtxNoGrabbed; /* Last context to hold decoder */ + + /* Used by the 3d driver only at this point, for pageflipping: + */ + unsigned int pfCurrentOffset; +} drm_via_sarea_t; + +typedef struct _drm_via_cmdbuf_size { + enum { + VIA_CMDBUF_SPACE = 0x01, + VIA_CMDBUF_LAG = 0x02 + } func; + int wait; + __u32 size; +} drm_via_cmdbuf_size_t; + +typedef enum { + VIA_IRQ_ABSOLUTE = 0x0, + VIA_IRQ_RELATIVE = 0x1, + VIA_IRQ_SIGNAL = 0x10000000, + VIA_IRQ_FORCE_SEQUENCE = 0x20000000 +} via_irq_seq_type_t; + +#define VIA_IRQ_FLAGS_MASK 0xF0000000 + +enum drm_via_irqs { + drm_via_irq_hqv0 = 0, + drm_via_irq_hqv1, + drm_via_irq_dma0_dd, + drm_via_irq_dma0_td, + drm_via_irq_dma1_dd, + drm_via_irq_dma1_td, + drm_via_irq_num +}; + +struct drm_via_wait_irq_request { + unsigned irq; + via_irq_seq_type_t type; + __u32 sequence; + __u32 signal; +}; + +typedef union drm_via_irqwait { + struct drm_via_wait_irq_request request; + struct drm_wait_vblank_reply reply; +} drm_via_irqwait_t; + +typedef struct drm_via_blitsync { + __u32 sync_handle; + unsigned engine; +} drm_via_blitsync_t; + +/* - * Below,"flags" is currently unused but will be used for possible future + * extensions like kernel space bounce buffers for bad alignments and + * blit engine busy-wait polling for better latency in the absence of + * interrupts. + */ + +typedef struct drm_via_dmablit { + __u32 num_lines; + __u32 line_length; + + __u32 fb_addr; + __u32 fb_stride; + + unsigned char *mem_addr; + __u32 mem_stride; + + __u32 flags; + int to_fb; + + drm_via_blitsync_t sync; +} drm_via_dmablit_t; + +#if defined(__cplusplus) +} +#endif + +#endif /* _VIA_DRM_H_ */ diff --git a/include/drm/virtgpu_drm.h b/include/drm/virtgpu_drm.h new file mode 100644 index 0000000..f06a789 --- /dev/null +++ b/include/drm/virtgpu_drm.h @@ -0,0 +1,182 @@ +/* + * Copyright 2013 Red Hat + * 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, 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS 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 VIRTGPU_DRM_H +#define VIRTGPU_DRM_H + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Please note that modifications to all structs defined here are + * subject to backwards-compatibility constraints. + * + * Do not use pointers, use __u64 instead for 32 bit / 64 bit user/kernel + * compatibility Keep fields aligned to their size + */ + +#define DRM_VIRTGPU_MAP 0x01 +#define DRM_VIRTGPU_EXECBUFFER 0x02 +#define DRM_VIRTGPU_GETPARAM 0x03 +#define DRM_VIRTGPU_RESOURCE_CREATE 0x04 +#define DRM_VIRTGPU_RESOURCE_INFO 0x05 +#define DRM_VIRTGPU_TRANSFER_FROM_HOST 0x06 +#define DRM_VIRTGPU_TRANSFER_TO_HOST 0x07 +#define DRM_VIRTGPU_WAIT 0x08 +#define DRM_VIRTGPU_GET_CAPS 0x09 + +#define VIRTGPU_EXECBUF_FENCE_FD_IN 0x01 +#define VIRTGPU_EXECBUF_FENCE_FD_OUT 0x02 +#define VIRTGPU_EXECBUF_FLAGS (\ + VIRTGPU_EXECBUF_FENCE_FD_IN |\ + VIRTGPU_EXECBUF_FENCE_FD_OUT |\ + 0) + +struct drm_virtgpu_map { + __u64 offset; /* use for mmap system call */ + __u32 handle; + __u32 pad; +}; + +struct drm_virtgpu_execbuffer { + __u32 flags; + __u32 size; + __u64 command; /* void* */ + __u64 bo_handles; + __u32 num_bo_handles; + __s32 fence_fd; /* in/out fence fd (see VIRTGPU_EXECBUF_FENCE_FD_IN/OUT) */ +}; + +#define VIRTGPU_PARAM_3D_FEATURES 1 /* do we have 3D features in the hw */ +#define VIRTGPU_PARAM_CAPSET_QUERY_FIX 2 /* do we have the capset fix */ + +struct drm_virtgpu_getparam { + __u64 param; + __u64 value; +}; + +/* NO_BO flags? NO resource flag? */ +/* resource flag for y_0_top */ +struct drm_virtgpu_resource_create { + __u32 target; + __u32 format; + __u32 bind; + __u32 width; + __u32 height; + __u32 depth; + __u32 array_size; + __u32 last_level; + __u32 nr_samples; + __u32 flags; + __u32 bo_handle; /* if this is set - recreate a new resource attached to this bo ? */ + __u32 res_handle; /* returned by kernel */ + __u32 size; /* validate transfer in the host */ + __u32 stride; /* validate transfer in the host */ +}; + +struct drm_virtgpu_resource_info { + __u32 bo_handle; + __u32 res_handle; + __u32 size; + __u32 stride; +}; + +struct drm_virtgpu_3d_box { + __u32 x; + __u32 y; + __u32 z; + __u32 w; + __u32 h; + __u32 d; +}; + +struct drm_virtgpu_3d_transfer_to_host { + __u32 bo_handle; + struct drm_virtgpu_3d_box box; + __u32 level; + __u32 offset; +}; + +struct drm_virtgpu_3d_transfer_from_host { + __u32 bo_handle; + struct drm_virtgpu_3d_box box; + __u32 level; + __u32 offset; +}; + +#define VIRTGPU_WAIT_NOWAIT 1 /* like it */ +struct drm_virtgpu_3d_wait { + __u32 handle; /* 0 is an invalid handle */ + __u32 flags; +}; + +struct drm_virtgpu_get_caps { + __u32 cap_set_id; + __u32 cap_set_ver; + __u64 addr; + __u32 size; + __u32 pad; +}; + +#define DRM_IOCTL_VIRTGPU_MAP \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_MAP, struct drm_virtgpu_map) + +#define DRM_IOCTL_VIRTGPU_EXECBUFFER \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_EXECBUFFER,\ + struct drm_virtgpu_execbuffer) + +#define DRM_IOCTL_VIRTGPU_GETPARAM \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_GETPARAM,\ + struct drm_virtgpu_getparam) + +#define DRM_IOCTL_VIRTGPU_RESOURCE_CREATE \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_RESOURCE_CREATE, \ + struct drm_virtgpu_resource_create) + +#define DRM_IOCTL_VIRTGPU_RESOURCE_INFO \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_RESOURCE_INFO, \ + struct drm_virtgpu_resource_info) + +#define DRM_IOCTL_VIRTGPU_TRANSFER_FROM_HOST \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_TRANSFER_FROM_HOST, \ + struct drm_virtgpu_3d_transfer_from_host) + +#define DRM_IOCTL_VIRTGPU_TRANSFER_TO_HOST \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_TRANSFER_TO_HOST, \ + struct drm_virtgpu_3d_transfer_to_host) + +#define DRM_IOCTL_VIRTGPU_WAIT \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_WAIT, \ + struct drm_virtgpu_3d_wait) + +#define DRM_IOCTL_VIRTGPU_GET_CAPS \ + DRM_IOWR(DRM_COMMAND_BASE + DRM_VIRTGPU_GET_CAPS, \ + struct drm_virtgpu_get_caps) + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/include/drm/vmwgfx_drm.h b/include/drm/vmwgfx_drm.h new file mode 100644 index 0000000..2b8d47e --- /dev/null +++ b/include/drm/vmwgfx_drm.h @@ -0,0 +1,1128 @@ +/************************************************************************** + * + * Copyright © 2009-2015 VMware, Inc., Palo Alto, CA., USA + * 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 + * THE COPYRIGHT HOLDERS, AUTHORS 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 __VMWGFX_DRM_H__ +#define __VMWGFX_DRM_H__ + +#include "drm.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +#define DRM_VMW_MAX_SURFACE_FACES 6 +#define DRM_VMW_MAX_MIP_LEVELS 24 + + +#define DRM_VMW_GET_PARAM 0 +#define DRM_VMW_ALLOC_DMABUF 1 +#define DRM_VMW_UNREF_DMABUF 2 +#define DRM_VMW_HANDLE_CLOSE 2 +#define DRM_VMW_CURSOR_BYPASS 3 +/* guarded by DRM_VMW_PARAM_NUM_STREAMS != 0*/ +#define DRM_VMW_CONTROL_STREAM 4 +#define DRM_VMW_CLAIM_STREAM 5 +#define DRM_VMW_UNREF_STREAM 6 +/* guarded by DRM_VMW_PARAM_3D == 1 */ +#define DRM_VMW_CREATE_CONTEXT 7 +#define DRM_VMW_UNREF_CONTEXT 8 +#define DRM_VMW_CREATE_SURFACE 9 +#define DRM_VMW_UNREF_SURFACE 10 +#define DRM_VMW_REF_SURFACE 11 +#define DRM_VMW_EXECBUF 12 +#define DRM_VMW_GET_3D_CAP 13 +#define DRM_VMW_FENCE_WAIT 14 +#define DRM_VMW_FENCE_SIGNALED 15 +#define DRM_VMW_FENCE_UNREF 16 +#define DRM_VMW_FENCE_EVENT 17 +#define DRM_VMW_PRESENT 18 +#define DRM_VMW_PRESENT_READBACK 19 +#define DRM_VMW_UPDATE_LAYOUT 20 +#define DRM_VMW_CREATE_SHADER 21 +#define DRM_VMW_UNREF_SHADER 22 +#define DRM_VMW_GB_SURFACE_CREATE 23 +#define DRM_VMW_GB_SURFACE_REF 24 +#define DRM_VMW_SYNCCPU 25 +#define DRM_VMW_CREATE_EXTENDED_CONTEXT 26 + +/*************************************************************************/ +/** + * DRM_VMW_GET_PARAM - get device information. + * + * DRM_VMW_PARAM_FIFO_OFFSET: + * Offset to use to map the first page of the FIFO read-only. + * The fifo is mapped using the mmap() system call on the drm device. + * + * DRM_VMW_PARAM_OVERLAY_IOCTL: + * Does the driver support the overlay ioctl. + */ + +#define DRM_VMW_PARAM_NUM_STREAMS 0 +#define DRM_VMW_PARAM_NUM_FREE_STREAMS 1 +#define DRM_VMW_PARAM_3D 2 +#define DRM_VMW_PARAM_HW_CAPS 3 +#define DRM_VMW_PARAM_FIFO_CAPS 4 +#define DRM_VMW_PARAM_MAX_FB_SIZE 5 +#define DRM_VMW_PARAM_FIFO_HW_VERSION 6 +#define DRM_VMW_PARAM_MAX_SURF_MEMORY 7 +#define DRM_VMW_PARAM_3D_CAPS_SIZE 8 +#define DRM_VMW_PARAM_MAX_MOB_MEMORY 9 +#define DRM_VMW_PARAM_MAX_MOB_SIZE 10 +#define DRM_VMW_PARAM_SCREEN_TARGET 11 +#define DRM_VMW_PARAM_DX 12 + +/** + * enum drm_vmw_handle_type - handle type for ref ioctls + * + */ +enum drm_vmw_handle_type { + DRM_VMW_HANDLE_LEGACY = 0, + DRM_VMW_HANDLE_PRIME = 1 +}; + +/** + * struct drm_vmw_getparam_arg + * + * @value: Returned value. //Out + * @param: Parameter to query. //In. + * + * Argument to the DRM_VMW_GET_PARAM Ioctl. + */ + +struct drm_vmw_getparam_arg { + __u64 value; + __u32 param; + __u32 pad64; +}; + +/*************************************************************************/ +/** + * DRM_VMW_CREATE_CONTEXT - Create a host context. + * + * Allocates a device unique context id, and queues a create context command + * for the host. Does not wait for host completion. + */ + +/** + * struct drm_vmw_context_arg + * + * @cid: Device unique context ID. + * + * Output argument to the DRM_VMW_CREATE_CONTEXT Ioctl. + * Input argument to the DRM_VMW_UNREF_CONTEXT Ioctl. + */ + +struct drm_vmw_context_arg { + __s32 cid; + __u32 pad64; +}; + +/*************************************************************************/ +/** + * DRM_VMW_UNREF_CONTEXT - Create a host context. + * + * Frees a global context id, and queues a destroy host command for the host. + * Does not wait for host completion. The context ID can be used directly + * in the command stream and shows up as the same context ID on the host. + */ + +/*************************************************************************/ +/** + * DRM_VMW_CREATE_SURFACE - Create a host suface. + * + * Allocates a device unique surface id, and queues a create surface command + * for the host. Does not wait for host completion. The surface ID can be + * used directly in the command stream and shows up as the same surface + * ID on the host. + */ + +/** + * struct drm_wmv_surface_create_req + * + * @flags: Surface flags as understood by the host. + * @format: Surface format as understood by the host. + * @mip_levels: Number of mip levels for each face. + * An unused face should have 0 encoded. + * @size_addr: Address of a user-space array of sruct drm_vmw_size + * cast to an __u64 for 32-64 bit compatibility. + * The size of the array should equal the total number of mipmap levels. + * @shareable: Boolean whether other clients (as identified by file descriptors) + * may reference this surface. + * @scanout: Boolean whether the surface is intended to be used as a + * scanout. + * + * Input data to the DRM_VMW_CREATE_SURFACE Ioctl. + * Output data from the DRM_VMW_REF_SURFACE Ioctl. + */ + +struct drm_vmw_surface_create_req { + __u32 flags; + __u32 format; + __u32 mip_levels[DRM_VMW_MAX_SURFACE_FACES]; + __u64 size_addr; + __s32 shareable; + __s32 scanout; +}; + +/** + * struct drm_wmv_surface_arg + * + * @sid: Surface id of created surface or surface to destroy or reference. + * @handle_type: Handle type for DRM_VMW_REF_SURFACE Ioctl. + * + * Output data from the DRM_VMW_CREATE_SURFACE Ioctl. + * Input argument to the DRM_VMW_UNREF_SURFACE Ioctl. + * Input argument to the DRM_VMW_REF_SURFACE Ioctl. + */ + +struct drm_vmw_surface_arg { + __s32 sid; + enum drm_vmw_handle_type handle_type; +}; + +/** + * struct drm_vmw_size ioctl. + * + * @width - mip level width + * @height - mip level height + * @depth - mip level depth + * + * Description of a mip level. + * Input data to the DRM_WMW_CREATE_SURFACE Ioctl. + */ + +struct drm_vmw_size { + __u32 width; + __u32 height; + __u32 depth; + __u32 pad64; +}; + +/** + * union drm_vmw_surface_create_arg + * + * @rep: Output data as described above. + * @req: Input data as described above. + * + * Argument to the DRM_VMW_CREATE_SURFACE Ioctl. + */ + +union drm_vmw_surface_create_arg { + struct drm_vmw_surface_arg rep; + struct drm_vmw_surface_create_req req; +}; + +/*************************************************************************/ +/** + * DRM_VMW_REF_SURFACE - Reference a host surface. + * + * Puts a reference on a host surface with a give sid, as previously + * returned by the DRM_VMW_CREATE_SURFACE ioctl. + * A reference will make sure the surface isn't destroyed while we hold + * it and will allow the calling client to use the surface ID in the command + * stream. + * + * On successful return, the Ioctl returns the surface information given + * in the DRM_VMW_CREATE_SURFACE ioctl. + */ + +/** + * union drm_vmw_surface_reference_arg + * + * @rep: Output data as described above. + * @req: Input data as described above. + * + * Argument to the DRM_VMW_REF_SURFACE Ioctl. + */ + +union drm_vmw_surface_reference_arg { + struct drm_vmw_surface_create_req rep; + struct drm_vmw_surface_arg req; +}; + +/*************************************************************************/ +/** + * DRM_VMW_UNREF_SURFACE - Unreference a host surface. + * + * Clear a reference previously put on a host surface. + * When all references are gone, including the one implicitly placed + * on creation, + * a destroy surface command will be queued for the host. + * Does not wait for completion. + */ + +/*************************************************************************/ +/** + * DRM_VMW_EXECBUF + * + * Submit a command buffer for execution on the host, and return a + * fence seqno that when signaled, indicates that the command buffer has + * executed. + */ + +/** + * struct drm_vmw_execbuf_arg + * + * @commands: User-space address of a command buffer cast to an __u64. + * @command-size: Size in bytes of the command buffer. + * @throttle-us: Sleep until software is less than @throttle_us + * microseconds ahead of hardware. The driver may round this value + * to the nearest kernel tick. + * @fence_rep: User-space address of a struct drm_vmw_fence_rep cast to an + * __u64. + * @version: Allows expanding the execbuf ioctl parameters without breaking + * backwards compatibility, since user-space will always tell the kernel + * which version it uses. + * @flags: Execbuf flags. + * @imported_fence_fd: FD for a fence imported from another device + * + * Argument to the DRM_VMW_EXECBUF Ioctl. + */ + +#define DRM_VMW_EXECBUF_VERSION 2 + +#define DRM_VMW_EXECBUF_FLAG_IMPORT_FENCE_FD (1 << 0) +#define DRM_VMW_EXECBUF_FLAG_EXPORT_FENCE_FD (1 << 1) + +struct drm_vmw_execbuf_arg { + __u64 commands; + __u32 command_size; + __u32 throttle_us; + __u64 fence_rep; + __u32 version; + __u32 flags; + __u32 context_handle; + __s32 imported_fence_fd; +}; + +/** + * struct drm_vmw_fence_rep + * + * @handle: Fence object handle for fence associated with a command submission. + * @mask: Fence flags relevant for this fence object. + * @seqno: Fence sequence number in fifo. A fence object with a lower + * seqno will signal the EXEC flag before a fence object with a higher + * seqno. This can be used by user-space to avoid kernel calls to determine + * whether a fence has signaled the EXEC flag. Note that @seqno will + * wrap at 32-bit. + * @passed_seqno: The highest seqno number processed by the hardware + * so far. This can be used to mark user-space fence objects as signaled, and + * to determine whether a fence seqno might be stale. + * @fd: FD associated with the fence, -1 if not exported + * @error: This member should've been set to -EFAULT on submission. + * The following actions should be take on completion: + * error == -EFAULT: Fence communication failed. The host is synchronized. + * Use the last fence id read from the FIFO fence register. + * error != 0 && error != -EFAULT: + * Fence submission failed. The host is synchronized. Use the fence_seq member. + * error == 0: All is OK, The host may not be synchronized. + * Use the fence_seq member. + * + * Input / Output data to the DRM_VMW_EXECBUF Ioctl. + */ + +struct drm_vmw_fence_rep { + __u32 handle; + __u32 mask; + __u32 seqno; + __u32 passed_seqno; + __s32 fd; + __s32 error; +}; + +/*************************************************************************/ +/** + * DRM_VMW_ALLOC_DMABUF + * + * Allocate a DMA buffer that is visible also to the host. + * NOTE: The buffer is + * identified by a handle and an offset, which are private to the guest, but + * usable in the command stream. The guest kernel may translate these + * and patch up the command stream accordingly. In the future, the offset may + * be zero at all times, or it may disappear from the interface before it is + * fixed. + * + * The DMA buffer may stay user-space mapped in the guest at all times, + * and is thus suitable for sub-allocation. + * + * DMA buffers are mapped using the mmap() syscall on the drm device. + */ + +/** + * struct drm_vmw_alloc_dmabuf_req + * + * @size: Required minimum size of the buffer. + * + * Input data to the DRM_VMW_ALLOC_DMABUF Ioctl. + */ + +struct drm_vmw_alloc_dmabuf_req { + __u32 size; + __u32 pad64; +}; + +/** + * struct drm_vmw_dmabuf_rep + * + * @map_handle: Offset to use in the mmap() call used to map the buffer. + * @handle: Handle unique to this buffer. Used for unreferencing. + * @cur_gmr_id: GMR id to use in the command stream when this buffer is + * referenced. See not above. + * @cur_gmr_offset: Offset to use in the command stream when this buffer is + * referenced. See note above. + * + * Output data from the DRM_VMW_ALLOC_DMABUF Ioctl. + */ + +struct drm_vmw_dmabuf_rep { + __u64 map_handle; + __u32 handle; + __u32 cur_gmr_id; + __u32 cur_gmr_offset; + __u32 pad64; +}; + +/** + * union drm_vmw_dmabuf_arg + * + * @req: Input data as described above. + * @rep: Output data as described above. + * + * Argument to the DRM_VMW_ALLOC_DMABUF Ioctl. + */ + +union drm_vmw_alloc_dmabuf_arg { + struct drm_vmw_alloc_dmabuf_req req; + struct drm_vmw_dmabuf_rep rep; +}; + +/*************************************************************************/ +/** + * DRM_VMW_UNREF_DMABUF - Free a DMA buffer. + * + */ + +/** + * struct drm_vmw_unref_dmabuf_arg + * + * @handle: Handle indicating what buffer to free. Obtained from the + * DRM_VMW_ALLOC_DMABUF Ioctl. + * + * Argument to the DRM_VMW_UNREF_DMABUF Ioctl. + */ + +struct drm_vmw_unref_dmabuf_arg { + __u32 handle; + __u32 pad64; +}; + +/*************************************************************************/ +/** + * DRM_VMW_CONTROL_STREAM - Control overlays, aka streams. + * + * This IOCTL controls the overlay units of the svga device. + * The SVGA overlay units does not work like regular hardware units in + * that they do not automatically read back the contents of the given dma + * buffer. But instead only read back for each call to this ioctl, and + * at any point between this call being made and a following call that + * either changes the buffer or disables the stream. + */ + +/** + * struct drm_vmw_rect + * + * Defines a rectangle. Used in the overlay ioctl to define + * source and destination rectangle. + */ + +struct drm_vmw_rect { + __s32 x; + __s32 y; + __u32 w; + __u32 h; +}; + +/** + * struct drm_vmw_control_stream_arg + * + * @stream_id: Stearm to control + * @enabled: If false all following arguments are ignored. + * @handle: Handle to buffer for getting data from. + * @format: Format of the overlay as understood by the host. + * @width: Width of the overlay. + * @height: Height of the overlay. + * @size: Size of the overlay in bytes. + * @pitch: Array of pitches, the two last are only used for YUV12 formats. + * @offset: Offset from start of dma buffer to overlay. + * @src: Source rect, must be within the defined area above. + * @dst: Destination rect, x and y may be negative. + * + * Argument to the DRM_VMW_CONTROL_STREAM Ioctl. + */ + +struct drm_vmw_control_stream_arg { + __u32 stream_id; + __u32 enabled; + + __u32 flags; + __u32 color_key; + + __u32 handle; + __u32 offset; + __s32 format; + __u32 size; + __u32 width; + __u32 height; + __u32 pitch[3]; + + __u32 pad64; + struct drm_vmw_rect src; + struct drm_vmw_rect dst; +}; + +/*************************************************************************/ +/** + * DRM_VMW_CURSOR_BYPASS - Give extra information about cursor bypass. + * + */ + +#define DRM_VMW_CURSOR_BYPASS_ALL (1 << 0) +#define DRM_VMW_CURSOR_BYPASS_FLAGS (1) + +/** + * struct drm_vmw_cursor_bypass_arg + * + * @flags: Flags. + * @crtc_id: Crtc id, only used if DMR_CURSOR_BYPASS_ALL isn't passed. + * @xpos: X position of cursor. + * @ypos: Y position of cursor. + * @xhot: X hotspot. + * @yhot: Y hotspot. + * + * Argument to the DRM_VMW_CURSOR_BYPASS Ioctl. + */ + +struct drm_vmw_cursor_bypass_arg { + __u32 flags; + __u32 crtc_id; + __s32 xpos; + __s32 ypos; + __s32 xhot; + __s32 yhot; +}; + +/*************************************************************************/ +/** + * DRM_VMW_CLAIM_STREAM - Claim a single stream. + */ + +/** + * struct drm_vmw_context_arg + * + * @stream_id: Device unique context ID. + * + * Output argument to the DRM_VMW_CREATE_CONTEXT Ioctl. + * Input argument to the DRM_VMW_UNREF_CONTEXT Ioctl. + */ + +struct drm_vmw_stream_arg { + __u32 stream_id; + __u32 pad64; +}; + +/*************************************************************************/ +/** + * DRM_VMW_UNREF_STREAM - Unclaim a stream. + * + * Return a single stream that was claimed by this process. Also makes + * sure that the stream has been stopped. + */ + +/*************************************************************************/ +/** + * DRM_VMW_GET_3D_CAP + * + * Read 3D capabilities from the FIFO + * + */ + +/** + * struct drm_vmw_get_3d_cap_arg + * + * @buffer: Pointer to a buffer for capability data, cast to an __u64 + * @size: Max size to copy + * + * Input argument to the DRM_VMW_GET_3D_CAP_IOCTL + * ioctls. + */ + +struct drm_vmw_get_3d_cap_arg { + __u64 buffer; + __u32 max_size; + __u32 pad64; +}; + +/*************************************************************************/ +/** + * DRM_VMW_FENCE_WAIT + * + * Waits for a fence object to signal. The wait is interruptible, so that + * signals may be delivered during the interrupt. The wait may timeout, + * in which case the calls returns -EBUSY. If the wait is restarted, + * that is restarting without resetting @cookie_valid to zero, + * the timeout is computed from the first call. + * + * The flags argument to the DRM_VMW_FENCE_WAIT ioctl indicates what to wait + * on: + * DRM_VMW_FENCE_FLAG_EXEC: All commands ahead of the fence in the command + * stream + * have executed. + * DRM_VMW_FENCE_FLAG_QUERY: All query results resulting from query finish + * commands + * in the buffer given to the EXECBUF ioctl returning the fence object handle + * are available to user-space. + * + * DRM_VMW_WAIT_OPTION_UNREF: If this wait option is given, and the + * fenc wait ioctl returns 0, the fence object has been unreferenced after + * the wait. + */ + +#define DRM_VMW_FENCE_FLAG_EXEC (1 << 0) +#define DRM_VMW_FENCE_FLAG_QUERY (1 << 1) + +#define DRM_VMW_WAIT_OPTION_UNREF (1 << 0) + +/** + * struct drm_vmw_fence_wait_arg + * + * @handle: Fence object handle as returned by the DRM_VMW_EXECBUF ioctl. + * @cookie_valid: Must be reset to 0 on first call. Left alone on restart. + * @kernel_cookie: Set to 0 on first call. Left alone on restart. + * @timeout_us: Wait timeout in microseconds. 0 for indefinite timeout. + * @lazy: Set to 1 if timing is not critical. Allow more than a kernel tick + * before returning. + * @flags: Fence flags to wait on. + * @wait_options: Options that control the behaviour of the wait ioctl. + * + * Input argument to the DRM_VMW_FENCE_WAIT ioctl. + */ + +struct drm_vmw_fence_wait_arg { + __u32 handle; + __s32 cookie_valid; + __u64 kernel_cookie; + __u64 timeout_us; + __s32 lazy; + __s32 flags; + __s32 wait_options; + __s32 pad64; +}; + +/*************************************************************************/ +/** + * DRM_VMW_FENCE_SIGNALED + * + * Checks if a fence object is signaled.. + */ + +/** + * struct drm_vmw_fence_signaled_arg + * + * @handle: Fence object handle as returned by the DRM_VMW_EXECBUF ioctl. + * @flags: Fence object flags input to DRM_VMW_FENCE_SIGNALED ioctl + * @signaled: Out: Flags signaled. + * @sequence: Out: Highest sequence passed so far. Can be used to signal the + * EXEC flag of user-space fence objects. + * + * Input/Output argument to the DRM_VMW_FENCE_SIGNALED and DRM_VMW_FENCE_UNREF + * ioctls. + */ + +struct drm_vmw_fence_signaled_arg { + __u32 handle; + __u32 flags; + __s32 signaled; + __u32 passed_seqno; + __u32 signaled_flags; + __u32 pad64; +}; + +/*************************************************************************/ +/** + * DRM_VMW_FENCE_UNREF + * + * Unreferences a fence object, and causes it to be destroyed if there are no + * other references to it. + * + */ + +/** + * struct drm_vmw_fence_arg + * + * @handle: Fence object handle as returned by the DRM_VMW_EXECBUF ioctl. + * + * Input/Output argument to the DRM_VMW_FENCE_UNREF ioctl.. + */ + +struct drm_vmw_fence_arg { + __u32 handle; + __u32 pad64; +}; + + +/*************************************************************************/ +/** + * DRM_VMW_FENCE_EVENT + * + * Queues an event on a fence to be delivered on the drm character device + * when the fence has signaled the DRM_VMW_FENCE_FLAG_EXEC flag. + * Optionally the approximate time when the fence signaled is + * given by the event. + */ + +/* + * The event type + */ +#define DRM_VMW_EVENT_FENCE_SIGNALED 0x80000000 + +struct drm_vmw_event_fence { + struct drm_event base; + __u64 user_data; + __u32 tv_sec; + __u32 tv_usec; +}; + +/* + * Flags that may be given to the command. + */ +/* Request fence signaled time on the event. */ +#define DRM_VMW_FE_FLAG_REQ_TIME (1 << 0) + +/** + * struct drm_vmw_fence_event_arg + * + * @fence_rep: Pointer to fence_rep structure cast to __u64 or 0 if + * the fence is not supposed to be referenced by user-space. + * @user_info: Info to be delivered with the event. + * @handle: Attach the event to this fence only. + * @flags: A set of flags as defined above. + */ +struct drm_vmw_fence_event_arg { + __u64 fence_rep; + __u64 user_data; + __u32 handle; + __u32 flags; +}; + + +/*************************************************************************/ +/** + * DRM_VMW_PRESENT + * + * Executes an SVGA present on a given fb for a given surface. The surface + * is placed on the framebuffer. Cliprects are given relative to the given + * point (the point disignated by dest_{x|y}). + * + */ + +/** + * struct drm_vmw_present_arg + * @fb_id: framebuffer id to present / read back from. + * @sid: Surface id to present from. + * @dest_x: X placement coordinate for surface. + * @dest_y: Y placement coordinate for surface. + * @clips_ptr: Pointer to an array of clip rects cast to an __u64. + * @num_clips: Number of cliprects given relative to the framebuffer origin, + * in the same coordinate space as the frame buffer. + * @pad64: Unused 64-bit padding. + * + * Input argument to the DRM_VMW_PRESENT ioctl. + */ + +struct drm_vmw_present_arg { + __u32 fb_id; + __u32 sid; + __s32 dest_x; + __s32 dest_y; + __u64 clips_ptr; + __u32 num_clips; + __u32 pad64; +}; + + +/*************************************************************************/ +/** + * DRM_VMW_PRESENT_READBACK + * + * Executes an SVGA present readback from a given fb to the dma buffer + * currently bound as the fb. If there is no dma buffer bound to the fb, + * an error will be returned. + * + */ + +/** + * struct drm_vmw_present_arg + * @fb_id: fb_id to present / read back from. + * @num_clips: Number of cliprects. + * @clips_ptr: Pointer to an array of clip rects cast to an __u64. + * @fence_rep: Pointer to a struct drm_vmw_fence_rep, cast to an __u64. + * If this member is NULL, then the ioctl should not return a fence. + */ + +struct drm_vmw_present_readback_arg { + __u32 fb_id; + __u32 num_clips; + __u64 clips_ptr; + __u64 fence_rep; +}; + +/*************************************************************************/ +/** + * DRM_VMW_UPDATE_LAYOUT - Update layout + * + * Updates the preferred modes and connection status for connectors. The + * command consists of one drm_vmw_update_layout_arg pointing to an array + * of num_outputs drm_vmw_rect's. + */ + +/** + * struct drm_vmw_update_layout_arg + * + * @num_outputs: number of active connectors + * @rects: pointer to array of drm_vmw_rect cast to an __u64 + * + * Input argument to the DRM_VMW_UPDATE_LAYOUT Ioctl. + */ +struct drm_vmw_update_layout_arg { + __u32 num_outputs; + __u32 pad64; + __u64 rects; +}; + + +/*************************************************************************/ +/** + * DRM_VMW_CREATE_SHADER - Create shader + * + * Creates a shader and optionally binds it to a dma buffer containing + * the shader byte-code. + */ + +/** + * enum drm_vmw_shader_type - Shader types + */ +enum drm_vmw_shader_type { + drm_vmw_shader_type_vs = 0, + drm_vmw_shader_type_ps, +}; + + +/** + * struct drm_vmw_shader_create_arg + * + * @shader_type: Shader type of the shader to create. + * @size: Size of the byte-code in bytes. + * where the shader byte-code starts + * @buffer_handle: Buffer handle identifying the buffer containing the + * shader byte-code + * @shader_handle: On successful completion contains a handle that + * can be used to subsequently identify the shader. + * @offset: Offset in bytes into the buffer given by @buffer_handle, + * + * Input / Output argument to the DRM_VMW_CREATE_SHADER Ioctl. + */ +struct drm_vmw_shader_create_arg { + enum drm_vmw_shader_type shader_type; + __u32 size; + __u32 buffer_handle; + __u32 shader_handle; + __u64 offset; +}; + +/*************************************************************************/ +/** + * DRM_VMW_UNREF_SHADER - Unreferences a shader + * + * Destroys a user-space reference to a shader, optionally destroying + * it. + */ + +/** + * struct drm_vmw_shader_arg + * + * @handle: Handle identifying the shader to destroy. + * + * Input argument to the DRM_VMW_UNREF_SHADER ioctl. + */ +struct drm_vmw_shader_arg { + __u32 handle; + __u32 pad64; +}; + +/*************************************************************************/ +/** + * DRM_VMW_GB_SURFACE_CREATE - Create a host guest-backed surface. + * + * Allocates a surface handle and queues a create surface command + * for the host on the first use of the surface. The surface ID can + * be used as the surface ID in commands referencing the surface. + */ + +/** + * enum drm_vmw_surface_flags + * + * @drm_vmw_surface_flag_shareable: Whether the surface is shareable + * @drm_vmw_surface_flag_scanout: Whether the surface is a scanout + * surface. + * @drm_vmw_surface_flag_create_buffer: Create a backup buffer if none is + * given. + */ +enum drm_vmw_surface_flags { + drm_vmw_surface_flag_shareable = (1 << 0), + drm_vmw_surface_flag_scanout = (1 << 1), + drm_vmw_surface_flag_create_buffer = (1 << 2) +}; + +/** + * struct drm_vmw_gb_surface_create_req + * + * @svga3d_flags: SVGA3d surface flags for the device. + * @format: SVGA3d format. + * @mip_level: Number of mip levels for all faces. + * @drm_surface_flags Flags as described above. + * @multisample_count Future use. Set to 0. + * @autogen_filter Future use. Set to 0. + * @buffer_handle Buffer handle of backup buffer. SVGA3D_INVALID_ID + * if none. + * @base_size Size of the base mip level for all faces. + * @array_size Must be zero for non-DX hardware, and if non-zero + * svga3d_flags must have proper bind flags setup. + * + * Input argument to the DRM_VMW_GB_SURFACE_CREATE Ioctl. + * Part of output argument for the DRM_VMW_GB_SURFACE_REF Ioctl. + */ +struct drm_vmw_gb_surface_create_req { + __u32 svga3d_flags; + __u32 format; + __u32 mip_levels; + enum drm_vmw_surface_flags drm_surface_flags; + __u32 multisample_count; + __u32 autogen_filter; + __u32 buffer_handle; + __u32 array_size; + struct drm_vmw_size base_size; +}; + +/** + * struct drm_vmw_gb_surface_create_rep + * + * @handle: Surface handle. + * @backup_size: Size of backup buffers for this surface. + * @buffer_handle: Handle of backup buffer. SVGA3D_INVALID_ID if none. + * @buffer_size: Actual size of the buffer identified by + * @buffer_handle + * @buffer_map_handle: Offset into device address space for the buffer + * identified by @buffer_handle. + * + * Part of output argument for the DRM_VMW_GB_SURFACE_REF ioctl. + * Output argument for the DRM_VMW_GB_SURFACE_CREATE ioctl. + */ +struct drm_vmw_gb_surface_create_rep { + __u32 handle; + __u32 backup_size; + __u32 buffer_handle; + __u32 buffer_size; + __u64 buffer_map_handle; +}; + +/** + * union drm_vmw_gb_surface_create_arg + * + * @req: Input argument as described above. + * @rep: Output argument as described above. + * + * Argument to the DRM_VMW_GB_SURFACE_CREATE ioctl. + */ +union drm_vmw_gb_surface_create_arg { + struct drm_vmw_gb_surface_create_rep rep; + struct drm_vmw_gb_surface_create_req req; +}; + +/*************************************************************************/ +/** + * DRM_VMW_GB_SURFACE_REF - Reference a host surface. + * + * Puts a reference on a host surface with a given handle, as previously + * returned by the DRM_VMW_GB_SURFACE_CREATE ioctl. + * A reference will make sure the surface isn't destroyed while we hold + * it and will allow the calling client to use the surface handle in + * the command stream. + * + * On successful return, the Ioctl returns the surface information given + * to and returned from the DRM_VMW_GB_SURFACE_CREATE ioctl. + */ + +/** + * struct drm_vmw_gb_surface_reference_arg + * + * @creq: The data used as input when the surface was created, as described + * above at "struct drm_vmw_gb_surface_create_req" + * @crep: Additional data output when the surface was created, as described + * above at "struct drm_vmw_gb_surface_create_rep" + * + * Output Argument to the DRM_VMW_GB_SURFACE_REF ioctl. + */ +struct drm_vmw_gb_surface_ref_rep { + struct drm_vmw_gb_surface_create_req creq; + struct drm_vmw_gb_surface_create_rep crep; +}; + +/** + * union drm_vmw_gb_surface_reference_arg + * + * @req: Input data as described above at "struct drm_vmw_surface_arg" + * @rep: Output data as described above at "struct drm_vmw_gb_surface_ref_rep" + * + * Argument to the DRM_VMW_GB_SURFACE_REF Ioctl. + */ +union drm_vmw_gb_surface_reference_arg { + struct drm_vmw_gb_surface_ref_rep rep; + struct drm_vmw_surface_arg req; +}; + + +/*************************************************************************/ +/** + * DRM_VMW_SYNCCPU - Sync a DMA buffer / MOB for CPU access. + * + * Idles any previously submitted GPU operations on the buffer and + * by default blocks command submissions that reference the buffer. + * If the file descriptor used to grab a blocking CPU sync is closed, the + * cpu sync is released. + * The flags argument indicates how the grab / release operation should be + * performed: + */ + +/** + * enum drm_vmw_synccpu_flags - Synccpu flags: + * + * @drm_vmw_synccpu_read: Sync for read. If sync is done for read only, it's a + * hint to the kernel to allow command submissions that references the buffer + * for read-only. + * @drm_vmw_synccpu_write: Sync for write. Block all command submissions + * referencing this buffer. + * @drm_vmw_synccpu_dontblock: Don't wait for GPU idle, but rather return + * -EBUSY should the buffer be busy. + * @drm_vmw_synccpu_allow_cs: Allow command submission that touches the buffer + * while the buffer is synced for CPU. This is similar to the GEM bo idle + * behavior. + */ +enum drm_vmw_synccpu_flags { + drm_vmw_synccpu_read = (1 << 0), + drm_vmw_synccpu_write = (1 << 1), + drm_vmw_synccpu_dontblock = (1 << 2), + drm_vmw_synccpu_allow_cs = (1 << 3) +}; + +/** + * enum drm_vmw_synccpu_op - Synccpu operations: + * + * @drm_vmw_synccpu_grab: Grab the buffer for CPU operations + * @drm_vmw_synccpu_release: Release a previous grab. + */ +enum drm_vmw_synccpu_op { + drm_vmw_synccpu_grab, + drm_vmw_synccpu_release +}; + +/** + * struct drm_vmw_synccpu_arg + * + * @op: The synccpu operation as described above. + * @handle: Handle identifying the buffer object. + * @flags: Flags as described above. + */ +struct drm_vmw_synccpu_arg { + enum drm_vmw_synccpu_op op; + enum drm_vmw_synccpu_flags flags; + __u32 handle; + __u32 pad64; +}; + +/*************************************************************************/ +/** + * DRM_VMW_CREATE_EXTENDED_CONTEXT - Create a host context. + * + * Allocates a device unique context id, and queues a create context command + * for the host. Does not wait for host completion. + */ +enum drm_vmw_extended_context { + drm_vmw_context_legacy, + drm_vmw_context_dx +}; + +/** + * union drm_vmw_extended_context_arg + * + * @req: Context type. + * @rep: Context identifier. + * + * Argument to the DRM_VMW_CREATE_EXTENDED_CONTEXT Ioctl. + */ +union drm_vmw_extended_context_arg { + enum drm_vmw_extended_context req; + struct drm_vmw_context_arg rep; +}; + +/*************************************************************************/ +/* + * DRM_VMW_HANDLE_CLOSE - Close a user-space handle and release its + * underlying resource. + * + * Note that this ioctl is overlaid on the DRM_VMW_UNREF_DMABUF Ioctl. + * The ioctl arguments therefore need to be identical in layout. + * + */ + +/** + * struct drm_vmw_handle_close_arg + * + * @handle: Handle to close. + * + * Argument to the DRM_VMW_HANDLE_CLOSE Ioctl. + */ +struct drm_vmw_handle_close_arg { + __u32 handle; + __u32 pad64; +}; + + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/intel/.gitignore b/intel/.gitignore new file mode 100644 index 0000000..528b408 --- /dev/null +++ b/intel/.gitignore @@ -0,0 +1 @@ +test_decode diff --git a/intel/Android.mk b/intel/Android.mk new file mode 100644 index 0000000..f45312d --- /dev/null +++ b/intel/Android.mk @@ -0,0 +1,38 @@ +# +# Copyright © 2011 Intel Corporation +# +# 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 (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 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. +# + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +# Import variables LIBDRM_INTEL_FILES, LIBDRM_INTEL_H_FILES +include $(LOCAL_PATH)/Makefile.sources + +LOCAL_MODULE := libdrm_intel + +LOCAL_SRC_FILES := $(LIBDRM_INTEL_FILES) + +LOCAL_SHARED_LIBRARIES := \ + libdrm + +include $(LIBDRM_COMMON_MK) +include $(BUILD_SHARED_LIBRARY) diff --git a/intel/Makefile.sources b/intel/Makefile.sources new file mode 100644 index 0000000..aa27e27 --- /dev/null +++ b/intel/Makefile.sources @@ -0,0 +1,17 @@ +LIBDRM_INTEL_FILES := \ + i915_pciids.h \ + intel_bufmgr.c \ + intel_bufmgr_priv.h \ + intel_bufmgr_fake.c \ + intel_bufmgr_gem.c \ + intel_decode.c \ + intel_chipset.h \ + intel_chipset.c \ + mm.c \ + mm.h \ + uthash.h + +LIBDRM_INTEL_H_FILES := \ + intel_bufmgr.h \ + intel_aub.h \ + intel_debug.h diff --git a/intel/i915_pciids.h b/intel/i915_pciids.h new file mode 100644 index 0000000..278031a --- /dev/null +++ b/intel/i915_pciids.h @@ -0,0 +1,750 @@ +/* + * Copyright 2013 Intel Corporation + * 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 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. + */ +#ifndef _I915_PCIIDS_H +#define _I915_PCIIDS_H + +/* + * A pci_device_id struct { + * __u32 vendor, device; + * __u32 subvendor, subdevice; + * __u32 class, class_mask; + * kernel_ulong_t driver_data; + * }; + * Don't use C99 here because "class" is reserved and we want to + * give userspace flexibility. + */ +#define INTEL_VGA_DEVICE(id, info) { \ + 0x8086, id, \ + ~0, ~0, \ + 0x030000, 0xff0000, \ + (unsigned long) info } + +#define INTEL_QUANTA_VGA_DEVICE(info) { \ + 0x8086, 0x16a, \ + 0x152d, 0x8990, \ + 0x030000, 0xff0000, \ + (unsigned long) info } + +#define INTEL_I810_IDS(info) \ + INTEL_VGA_DEVICE(0x7121, info), /* I810 */ \ + INTEL_VGA_DEVICE(0x7123, info), /* I810_DC100 */ \ + INTEL_VGA_DEVICE(0x7125, info) /* I810_E */ + +#define INTEL_I815_IDS(info) \ + INTEL_VGA_DEVICE(0x1132, info) /* I815*/ + +#define INTEL_I830_IDS(info) \ + INTEL_VGA_DEVICE(0x3577, info) + +#define INTEL_I845G_IDS(info) \ + INTEL_VGA_DEVICE(0x2562, info) + +#define INTEL_I85X_IDS(info) \ + INTEL_VGA_DEVICE(0x3582, info), /* I855_GM */ \ + INTEL_VGA_DEVICE(0x358e, info) + +#define INTEL_I865G_IDS(info) \ + INTEL_VGA_DEVICE(0x2572, info) /* I865_G */ + +#define INTEL_I915G_IDS(info) \ + INTEL_VGA_DEVICE(0x2582, info), /* I915_G */ \ + INTEL_VGA_DEVICE(0x258a, info) /* E7221_G */ + +#define INTEL_I915GM_IDS(info) \ + INTEL_VGA_DEVICE(0x2592, info) /* I915_GM */ + +#define INTEL_I945G_IDS(info) \ + INTEL_VGA_DEVICE(0x2772, info) /* I945_G */ + +#define INTEL_I945GM_IDS(info) \ + INTEL_VGA_DEVICE(0x27a2, info), /* I945_GM */ \ + INTEL_VGA_DEVICE(0x27ae, info) /* I945_GME */ + +#define INTEL_I965G_IDS(info) \ + INTEL_VGA_DEVICE(0x2972, info), /* I946_GZ */ \ + INTEL_VGA_DEVICE(0x2982, info), /* G35_G */ \ + INTEL_VGA_DEVICE(0x2992, info), /* I965_Q */ \ + INTEL_VGA_DEVICE(0x29a2, info) /* I965_G */ + +#define INTEL_G33_IDS(info) \ + INTEL_VGA_DEVICE(0x29b2, info), /* Q35_G */ \ + INTEL_VGA_DEVICE(0x29c2, info), /* G33_G */ \ + INTEL_VGA_DEVICE(0x29d2, info) /* Q33_G */ + +#define INTEL_I965GM_IDS(info) \ + INTEL_VGA_DEVICE(0x2a02, info), /* I965_GM */ \ + INTEL_VGA_DEVICE(0x2a12, info) /* I965_GME */ + +#define INTEL_GM45_IDS(info) \ + INTEL_VGA_DEVICE(0x2a42, info) /* GM45_G */ + +#define INTEL_G45_IDS(info) \ + INTEL_VGA_DEVICE(0x2e02, info), /* IGD_E_G */ \ + INTEL_VGA_DEVICE(0x2e12, info), /* Q45_G */ \ + INTEL_VGA_DEVICE(0x2e22, info), /* G45_G */ \ + INTEL_VGA_DEVICE(0x2e32, info), /* G41_G */ \ + INTEL_VGA_DEVICE(0x2e42, info), /* B43_G */ \ + INTEL_VGA_DEVICE(0x2e92, info) /* B43_G.1 */ + +#define INTEL_PINEVIEW_G_IDS(info) \ + INTEL_VGA_DEVICE(0xa001, info) + +#define INTEL_PINEVIEW_M_IDS(info) \ + INTEL_VGA_DEVICE(0xa011, info) + +#define INTEL_IRONLAKE_D_IDS(info) \ + INTEL_VGA_DEVICE(0x0042, info) + +#define INTEL_IRONLAKE_M_IDS(info) \ + INTEL_VGA_DEVICE(0x0046, info) + +#define INTEL_SNB_D_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x0102, info), \ + INTEL_VGA_DEVICE(0x010A, info) + +#define INTEL_SNB_D_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x0112, info), \ + INTEL_VGA_DEVICE(0x0122, info) + +#define INTEL_SNB_D_IDS(info) \ + INTEL_SNB_D_GT1_IDS(info), \ + INTEL_SNB_D_GT2_IDS(info) + +#define INTEL_SNB_M_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x0106, info) + +#define INTEL_SNB_M_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x0116, info), \ + INTEL_VGA_DEVICE(0x0126, info) + +#define INTEL_SNB_M_IDS(info) \ + INTEL_SNB_M_GT1_IDS(info), \ + INTEL_SNB_M_GT2_IDS(info) + +#define INTEL_IVB_M_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x0156, info) /* GT1 mobile */ + +#define INTEL_IVB_M_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x0166, info) /* GT2 mobile */ + +#define INTEL_IVB_M_IDS(info) \ + INTEL_IVB_M_GT1_IDS(info), \ + INTEL_IVB_M_GT2_IDS(info) + +#define INTEL_IVB_D_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x0152, info), /* GT1 desktop */ \ + INTEL_VGA_DEVICE(0x015a, info) /* GT1 server */ + +#define INTEL_IVB_D_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x0162, info), /* GT2 desktop */ \ + INTEL_VGA_DEVICE(0x016a, info) /* GT2 server */ + +#define INTEL_IVB_D_IDS(info) \ + INTEL_IVB_D_GT1_IDS(info), \ + INTEL_IVB_D_GT2_IDS(info) + +#define INTEL_IVB_Q_IDS(info) \ + INTEL_QUANTA_VGA_DEVICE(info) /* Quanta transcode */ + +#define INTEL_HSW_ULT_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x0A02, info), /* ULT GT1 desktop */ \ + INTEL_VGA_DEVICE(0x0A06, info), /* ULT GT1 mobile */ \ + INTEL_VGA_DEVICE(0x0A0A, info), /* ULT GT1 server */ \ + INTEL_VGA_DEVICE(0x0A0B, info) /* ULT GT1 reserved */ + +#define INTEL_HSW_ULX_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x0A0E, info) /* ULX GT1 mobile */ + +#define INTEL_HSW_GT1_IDS(info) \ + INTEL_HSW_ULT_GT1_IDS(info), \ + INTEL_HSW_ULX_GT1_IDS(info), \ + INTEL_VGA_DEVICE(0x0402, info), /* GT1 desktop */ \ + INTEL_VGA_DEVICE(0x0406, info), /* GT1 mobile */ \ + INTEL_VGA_DEVICE(0x040A, info), /* GT1 server */ \ + INTEL_VGA_DEVICE(0x040B, info), /* GT1 reserved */ \ + INTEL_VGA_DEVICE(0x040E, info), /* GT1 reserved */ \ + INTEL_VGA_DEVICE(0x0C02, info), /* SDV GT1 desktop */ \ + INTEL_VGA_DEVICE(0x0C06, info), /* SDV GT1 mobile */ \ + INTEL_VGA_DEVICE(0x0C0A, info), /* SDV GT1 server */ \ + INTEL_VGA_DEVICE(0x0C0B, info), /* SDV GT1 reserved */ \ + INTEL_VGA_DEVICE(0x0C0E, info), /* SDV GT1 reserved */ \ + INTEL_VGA_DEVICE(0x0D02, info), /* CRW GT1 desktop */ \ + INTEL_VGA_DEVICE(0x0D06, info), /* CRW GT1 mobile */ \ + INTEL_VGA_DEVICE(0x0D0A, info), /* CRW GT1 server */ \ + INTEL_VGA_DEVICE(0x0D0B, info), /* CRW GT1 reserved */ \ + INTEL_VGA_DEVICE(0x0D0E, info) /* CRW GT1 reserved */ + +#define INTEL_HSW_ULT_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x0A12, info), /* ULT GT2 desktop */ \ + INTEL_VGA_DEVICE(0x0A16, info), /* ULT GT2 mobile */ \ + INTEL_VGA_DEVICE(0x0A1A, info), /* ULT GT2 server */ \ + INTEL_VGA_DEVICE(0x0A1B, info) /* ULT GT2 reserved */ \ + +#define INTEL_HSW_ULX_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x0A1E, info) /* ULX GT2 mobile */ \ + +#define INTEL_HSW_GT2_IDS(info) \ + INTEL_HSW_ULT_GT2_IDS(info), \ + INTEL_HSW_ULX_GT2_IDS(info), \ + INTEL_VGA_DEVICE(0x0412, info), /* GT2 desktop */ \ + INTEL_VGA_DEVICE(0x0416, info), /* GT2 mobile */ \ + INTEL_VGA_DEVICE(0x041A, info), /* GT2 server */ \ + INTEL_VGA_DEVICE(0x041B, info), /* GT2 reserved */ \ + INTEL_VGA_DEVICE(0x041E, info), /* GT2 reserved */ \ + INTEL_VGA_DEVICE(0x0C12, info), /* SDV GT2 desktop */ \ + INTEL_VGA_DEVICE(0x0C16, info), /* SDV GT2 mobile */ \ + INTEL_VGA_DEVICE(0x0C1A, info), /* SDV GT2 server */ \ + INTEL_VGA_DEVICE(0x0C1B, info), /* SDV GT2 reserved */ \ + INTEL_VGA_DEVICE(0x0C1E, info), /* SDV GT2 reserved */ \ + INTEL_VGA_DEVICE(0x0D12, info), /* CRW GT2 desktop */ \ + INTEL_VGA_DEVICE(0x0D16, info), /* CRW GT2 mobile */ \ + INTEL_VGA_DEVICE(0x0D1A, info), /* CRW GT2 server */ \ + INTEL_VGA_DEVICE(0x0D1B, info), /* CRW GT2 reserved */ \ + INTEL_VGA_DEVICE(0x0D1E, info) /* CRW GT2 reserved */ + +#define INTEL_HSW_ULT_GT3_IDS(info) \ + INTEL_VGA_DEVICE(0x0A22, info), /* ULT GT3 desktop */ \ + INTEL_VGA_DEVICE(0x0A26, info), /* ULT GT3 mobile */ \ + INTEL_VGA_DEVICE(0x0A2A, info), /* ULT GT3 server */ \ + INTEL_VGA_DEVICE(0x0A2B, info), /* ULT GT3 reserved */ \ + INTEL_VGA_DEVICE(0x0A2E, info) /* ULT GT3 reserved */ + +#define INTEL_HSW_GT3_IDS(info) \ + INTEL_HSW_ULT_GT3_IDS(info), \ + INTEL_VGA_DEVICE(0x0422, info), /* GT3 desktop */ \ + INTEL_VGA_DEVICE(0x0426, info), /* GT3 mobile */ \ + INTEL_VGA_DEVICE(0x042A, info), /* GT3 server */ \ + INTEL_VGA_DEVICE(0x042B, info), /* GT3 reserved */ \ + INTEL_VGA_DEVICE(0x042E, info), /* GT3 reserved */ \ + INTEL_VGA_DEVICE(0x0C22, info), /* SDV GT3 desktop */ \ + INTEL_VGA_DEVICE(0x0C26, info), /* SDV GT3 mobile */ \ + INTEL_VGA_DEVICE(0x0C2A, info), /* SDV GT3 server */ \ + INTEL_VGA_DEVICE(0x0C2B, info), /* SDV GT3 reserved */ \ + INTEL_VGA_DEVICE(0x0C2E, info), /* SDV GT3 reserved */ \ + INTEL_VGA_DEVICE(0x0D22, info), /* CRW GT3 desktop */ \ + INTEL_VGA_DEVICE(0x0D26, info), /* CRW GT3 mobile */ \ + INTEL_VGA_DEVICE(0x0D2A, info), /* CRW GT3 server */ \ + INTEL_VGA_DEVICE(0x0D2B, info), /* CRW GT3 reserved */ \ + INTEL_VGA_DEVICE(0x0D2E, info) /* CRW GT3 reserved */ + +#define INTEL_HSW_IDS(info) \ + INTEL_HSW_GT1_IDS(info), \ + INTEL_HSW_GT2_IDS(info), \ + INTEL_HSW_GT3_IDS(info) + +#define INTEL_VLV_IDS(info) \ + INTEL_VGA_DEVICE(0x0f30, info), \ + INTEL_VGA_DEVICE(0x0f31, info), \ + INTEL_VGA_DEVICE(0x0f32, info), \ + INTEL_VGA_DEVICE(0x0f33, info) + +#define INTEL_BDW_ULT_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x1606, info), /* GT1 ULT */ \ + INTEL_VGA_DEVICE(0x160B, info) /* GT1 Iris */ + +#define INTEL_BDW_ULX_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x160E, info) /* GT1 ULX */ + +#define INTEL_BDW_GT1_IDS(info) \ + INTEL_BDW_ULT_GT1_IDS(info), \ + INTEL_BDW_ULX_GT1_IDS(info), \ + INTEL_VGA_DEVICE(0x1602, info), /* GT1 ULT */ \ + INTEL_VGA_DEVICE(0x160A, info), /* GT1 Server */ \ + INTEL_VGA_DEVICE(0x160D, info) /* GT1 Workstation */ + +#define INTEL_BDW_ULT_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x1616, info), /* GT2 ULT */ \ + INTEL_VGA_DEVICE(0x161B, info) /* GT2 ULT */ + +#define INTEL_BDW_ULX_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x161E, info) /* GT2 ULX */ + +#define INTEL_BDW_GT2_IDS(info) \ + INTEL_BDW_ULT_GT2_IDS(info), \ + INTEL_BDW_ULX_GT2_IDS(info), \ + INTEL_VGA_DEVICE(0x1612, info), /* GT2 Halo */ \ + INTEL_VGA_DEVICE(0x161A, info), /* GT2 Server */ \ + INTEL_VGA_DEVICE(0x161D, info) /* GT2 Workstation */ + +#define INTEL_BDW_ULT_GT3_IDS(info) \ + INTEL_VGA_DEVICE(0x1626, info), /* ULT */ \ + INTEL_VGA_DEVICE(0x162B, info) /* Iris */ \ + +#define INTEL_BDW_ULX_GT3_IDS(info) \ + INTEL_VGA_DEVICE(0x162E, info) /* ULX */ + +#define INTEL_BDW_GT3_IDS(info) \ + INTEL_BDW_ULT_GT3_IDS(info), \ + INTEL_BDW_ULX_GT3_IDS(info), \ + INTEL_VGA_DEVICE(0x1622, info), /* ULT */ \ + INTEL_VGA_DEVICE(0x162A, info), /* Server */ \ + INTEL_VGA_DEVICE(0x162D, info) /* Workstation */ + +#define INTEL_BDW_ULT_RSVD_IDS(info) \ + INTEL_VGA_DEVICE(0x1636, info), /* ULT */ \ + INTEL_VGA_DEVICE(0x163B, info) /* Iris */ + +#define INTEL_BDW_ULX_RSVD_IDS(info) \ + INTEL_VGA_DEVICE(0x163E, info) /* ULX */ + +#define INTEL_BDW_RSVD_IDS(info) \ + INTEL_BDW_ULT_RSVD_IDS(info), \ + INTEL_BDW_ULX_RSVD_IDS(info), \ + INTEL_VGA_DEVICE(0x1632, info), /* ULT */ \ + INTEL_VGA_DEVICE(0x163A, info), /* Server */ \ + INTEL_VGA_DEVICE(0x163D, info) /* Workstation */ + +#define INTEL_BDW_IDS(info) \ + INTEL_BDW_GT1_IDS(info), \ + INTEL_BDW_GT2_IDS(info), \ + INTEL_BDW_GT3_IDS(info), \ + INTEL_BDW_RSVD_IDS(info) + +#define INTEL_CHV_IDS(info) \ + INTEL_VGA_DEVICE(0x22b0, info), \ + INTEL_VGA_DEVICE(0x22b1, info), \ + INTEL_VGA_DEVICE(0x22b2, info), \ + INTEL_VGA_DEVICE(0x22b3, info) + +#define INTEL_SKL_ULT_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x1906, info), /* ULT GT1 */ \ + INTEL_VGA_DEVICE(0x1913, info) /* ULT GT1.5 */ + +#define INTEL_SKL_ULX_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x190E, info), /* ULX GT1 */ \ + INTEL_VGA_DEVICE(0x1915, info) /* ULX GT1.5 */ + +#define INTEL_SKL_GT1_IDS(info) \ + INTEL_SKL_ULT_GT1_IDS(info), \ + INTEL_SKL_ULX_GT1_IDS(info), \ + INTEL_VGA_DEVICE(0x1902, info), /* DT GT1 */ \ + INTEL_VGA_DEVICE(0x190A, info), /* SRV GT1 */ \ + INTEL_VGA_DEVICE(0x190B, info), /* Halo GT1 */ \ + INTEL_VGA_DEVICE(0x1917, info) /* DT GT1.5 */ + +#define INTEL_SKL_ULT_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x1916, info), /* ULT GT2 */ \ + INTEL_VGA_DEVICE(0x1921, info) /* ULT GT2F */ + +#define INTEL_SKL_ULX_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x191E, info) /* ULX GT2 */ + +#define INTEL_SKL_GT2_IDS(info) \ + INTEL_SKL_ULT_GT2_IDS(info), \ + INTEL_SKL_ULX_GT2_IDS(info), \ + INTEL_VGA_DEVICE(0x1912, info), /* DT GT2 */ \ + INTEL_VGA_DEVICE(0x191A, info), /* SRV GT2 */ \ + INTEL_VGA_DEVICE(0x191B, info), /* Halo GT2 */ \ + INTEL_VGA_DEVICE(0x191D, info) /* WKS GT2 */ + +#define INTEL_SKL_ULT_GT3_IDS(info) \ + INTEL_VGA_DEVICE(0x1923, info), /* ULT GT3 */ \ + INTEL_VGA_DEVICE(0x1926, info), /* ULT GT3e */ \ + INTEL_VGA_DEVICE(0x1927, info) /* ULT GT3e */ + +#define INTEL_SKL_GT3_IDS(info) \ + INTEL_SKL_ULT_GT3_IDS(info), \ + INTEL_VGA_DEVICE(0x192A, info), /* SRV GT3 */ \ + INTEL_VGA_DEVICE(0x192B, info), /* Halo GT3e */ \ + INTEL_VGA_DEVICE(0x192D, info) /* SRV GT3e */ + +#define INTEL_SKL_GT4_IDS(info) \ + INTEL_VGA_DEVICE(0x1932, info), /* DT GT4 */ \ + INTEL_VGA_DEVICE(0x193A, info), /* SRV GT4e */ \ + INTEL_VGA_DEVICE(0x193B, info), /* Halo GT4e */ \ + INTEL_VGA_DEVICE(0x193D, info) /* WKS GT4e */ + +#define INTEL_SKL_IDS(info) \ + INTEL_SKL_GT1_IDS(info), \ + INTEL_SKL_GT2_IDS(info), \ + INTEL_SKL_GT3_IDS(info), \ + INTEL_SKL_GT4_IDS(info) + +#define INTEL_BXT_IDS(info) \ + INTEL_VGA_DEVICE(0x0A84, info), \ + INTEL_VGA_DEVICE(0x1A84, info), \ + INTEL_VGA_DEVICE(0x1A85, info), \ + INTEL_VGA_DEVICE(0x5A84, info), /* APL HD Graphics 505 */ \ + INTEL_VGA_DEVICE(0x5A85, info) /* APL HD Graphics 500 */ + +#define INTEL_GLK_IDS(info) \ + INTEL_VGA_DEVICE(0x3184, info), \ + INTEL_VGA_DEVICE(0x3185, info) + +#define INTEL_KBL_ULT_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x5906, info), /* ULT GT1 */ \ + INTEL_VGA_DEVICE(0x5913, info) /* ULT GT1.5 */ + +#define INTEL_KBL_ULX_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x590E, info), /* ULX GT1 */ \ + INTEL_VGA_DEVICE(0x5915, info) /* ULX GT1.5 */ + +#define INTEL_KBL_GT1_IDS(info) \ + INTEL_KBL_ULT_GT1_IDS(info), \ + INTEL_KBL_ULX_GT1_IDS(info), \ + INTEL_VGA_DEVICE(0x5902, info), /* DT GT1 */ \ + INTEL_VGA_DEVICE(0x5908, info), /* Halo GT1 */ \ + INTEL_VGA_DEVICE(0x590A, info), /* SRV GT1 */ \ + INTEL_VGA_DEVICE(0x590B, info) /* Halo GT1 */ + +#define INTEL_KBL_ULT_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x5916, info), /* ULT GT2 */ \ + INTEL_VGA_DEVICE(0x5921, info) /* ULT GT2F */ + +#define INTEL_KBL_ULX_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x591E, info) /* ULX GT2 */ + +#define INTEL_KBL_GT2_IDS(info) \ + INTEL_KBL_ULT_GT2_IDS(info), \ + INTEL_KBL_ULX_GT2_IDS(info), \ + INTEL_VGA_DEVICE(0x5912, info), /* DT GT2 */ \ + INTEL_VGA_DEVICE(0x5917, info), /* Mobile GT2 */ \ + INTEL_VGA_DEVICE(0x591A, info), /* SRV GT2 */ \ + INTEL_VGA_DEVICE(0x591B, info), /* Halo GT2 */ \ + INTEL_VGA_DEVICE(0x591D, info) /* WKS GT2 */ + +#define INTEL_KBL_ULT_GT3_IDS(info) \ + INTEL_VGA_DEVICE(0x5926, info) /* ULT GT3 */ + +#define INTEL_KBL_GT3_IDS(info) \ + INTEL_KBL_ULT_GT3_IDS(info), \ + INTEL_VGA_DEVICE(0x5923, info), /* ULT GT3 */ \ + INTEL_VGA_DEVICE(0x5927, info) /* ULT GT3 */ + +#define INTEL_KBL_GT4_IDS(info) \ + INTEL_VGA_DEVICE(0x593B, info) /* Halo GT4 */ + +/* AML/KBL Y GT2 */ +#define INTEL_AML_KBL_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x591C, info), /* ULX GT2 */ \ + INTEL_VGA_DEVICE(0x87C0, info) /* ULX GT2 */ + +/* AML/CFL Y GT2 */ +#define INTEL_AML_CFL_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x87CA, info) + +/* CML GT1 */ +#define INTEL_CML_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x9BA2, info), \ + INTEL_VGA_DEVICE(0x9BA4, info), \ + INTEL_VGA_DEVICE(0x9BA5, info), \ + INTEL_VGA_DEVICE(0x9BA8, info) + +#define INTEL_CML_U_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x9B21, info), \ + INTEL_VGA_DEVICE(0x9BAA, info), \ + INTEL_VGA_DEVICE(0x9BAC, info) + +/* CML GT2 */ +#define INTEL_CML_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x9BC2, info), \ + INTEL_VGA_DEVICE(0x9BC4, info), \ + INTEL_VGA_DEVICE(0x9BC5, info), \ + INTEL_VGA_DEVICE(0x9BC6, info), \ + INTEL_VGA_DEVICE(0x9BC8, info), \ + INTEL_VGA_DEVICE(0x9BE6, info), \ + INTEL_VGA_DEVICE(0x9BF6, info) + +#define INTEL_CML_U_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x9B41, info), \ + INTEL_VGA_DEVICE(0x9BCA, info), \ + INTEL_VGA_DEVICE(0x9BCC, info) + +#define INTEL_KBL_IDS(info) \ + INTEL_KBL_GT1_IDS(info), \ + INTEL_KBL_GT2_IDS(info), \ + INTEL_KBL_GT3_IDS(info), \ + INTEL_KBL_GT4_IDS(info), \ + INTEL_AML_KBL_GT2_IDS(info) + +/* CFL S */ +#define INTEL_CFL_S_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x3E90, info), /* SRV GT1 */ \ + INTEL_VGA_DEVICE(0x3E93, info), /* SRV GT1 */ \ + INTEL_VGA_DEVICE(0x3E99, info) /* SRV GT1 */ + +#define INTEL_CFL_S_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x3E91, info), /* SRV GT2 */ \ + INTEL_VGA_DEVICE(0x3E92, info), /* SRV GT2 */ \ + INTEL_VGA_DEVICE(0x3E96, info), /* SRV GT2 */ \ + INTEL_VGA_DEVICE(0x3E98, info), /* SRV GT2 */ \ + INTEL_VGA_DEVICE(0x3E9A, info) /* SRV GT2 */ + +/* CFL H */ +#define INTEL_CFL_H_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x3E9C, info) + +#define INTEL_CFL_H_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x3E94, info), /* Halo GT2 */ \ + INTEL_VGA_DEVICE(0x3E9B, info) /* Halo GT2 */ + +/* CFL U GT2 */ +#define INTEL_CFL_U_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x3EA9, info) + +/* CFL U GT3 */ +#define INTEL_CFL_U_GT3_IDS(info) \ + INTEL_VGA_DEVICE(0x3EA5, info), /* ULT GT3 */ \ + INTEL_VGA_DEVICE(0x3EA6, info), /* ULT GT3 */ \ + INTEL_VGA_DEVICE(0x3EA7, info), /* ULT GT3 */ \ + INTEL_VGA_DEVICE(0x3EA8, info) /* ULT GT3 */ + +/* WHL/CFL U GT1 */ +#define INTEL_WHL_U_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x3EA1, info), \ + INTEL_VGA_DEVICE(0x3EA4, info) + +/* WHL/CFL U GT2 */ +#define INTEL_WHL_U_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x3EA0, info), \ + INTEL_VGA_DEVICE(0x3EA3, info) + +/* WHL/CFL U GT3 */ +#define INTEL_WHL_U_GT3_IDS(info) \ + INTEL_VGA_DEVICE(0x3EA2, info) + +#define INTEL_CFL_IDS(info) \ + INTEL_CFL_S_GT1_IDS(info), \ + INTEL_CFL_S_GT2_IDS(info), \ + INTEL_CFL_H_GT1_IDS(info), \ + INTEL_CFL_H_GT2_IDS(info), \ + INTEL_CFL_U_GT2_IDS(info), \ + INTEL_CFL_U_GT3_IDS(info), \ + INTEL_WHL_U_GT1_IDS(info), \ + INTEL_WHL_U_GT2_IDS(info), \ + INTEL_WHL_U_GT3_IDS(info), \ + INTEL_AML_CFL_GT2_IDS(info), \ + INTEL_CML_GT1_IDS(info), \ + INTEL_CML_GT2_IDS(info), \ + INTEL_CML_U_GT1_IDS(info), \ + INTEL_CML_U_GT2_IDS(info) + +/* CNL */ +#define INTEL_CNL_PORT_F_IDS(info) \ + INTEL_VGA_DEVICE(0x5A44, info), \ + INTEL_VGA_DEVICE(0x5A4C, info), \ + INTEL_VGA_DEVICE(0x5A54, info), \ + INTEL_VGA_DEVICE(0x5A5C, info) + +#define INTEL_CNL_IDS(info) \ + INTEL_CNL_PORT_F_IDS(info), \ + INTEL_VGA_DEVICE(0x5A40, info), \ + INTEL_VGA_DEVICE(0x5A41, info), \ + INTEL_VGA_DEVICE(0x5A42, info), \ + INTEL_VGA_DEVICE(0x5A49, info), \ + INTEL_VGA_DEVICE(0x5A4A, info), \ + INTEL_VGA_DEVICE(0x5A50, info), \ + INTEL_VGA_DEVICE(0x5A51, info), \ + INTEL_VGA_DEVICE(0x5A52, info), \ + INTEL_VGA_DEVICE(0x5A59, info), \ + INTEL_VGA_DEVICE(0x5A5A, info) + +/* ICL */ +#define INTEL_ICL_PORT_F_IDS(info) \ + INTEL_VGA_DEVICE(0x8A50, info), \ + INTEL_VGA_DEVICE(0x8A52, info), \ + INTEL_VGA_DEVICE(0x8A53, info), \ + INTEL_VGA_DEVICE(0x8A54, info), \ + INTEL_VGA_DEVICE(0x8A56, info), \ + INTEL_VGA_DEVICE(0x8A57, info), \ + INTEL_VGA_DEVICE(0x8A58, info), \ + INTEL_VGA_DEVICE(0x8A59, info), \ + INTEL_VGA_DEVICE(0x8A5A, info), \ + INTEL_VGA_DEVICE(0x8A5B, info), \ + INTEL_VGA_DEVICE(0x8A5C, info), \ + INTEL_VGA_DEVICE(0x8A70, info), \ + INTEL_VGA_DEVICE(0x8A71, info) + +#define INTEL_ICL_11_IDS(info) \ + INTEL_ICL_PORT_F_IDS(info), \ + INTEL_VGA_DEVICE(0x8A51, info), \ + INTEL_VGA_DEVICE(0x8A5D, info) + +/* EHL */ +#define INTEL_EHL_IDS(info) \ + INTEL_VGA_DEVICE(0x4541, info), \ + INTEL_VGA_DEVICE(0x4551, info), \ + INTEL_VGA_DEVICE(0x4555, info), \ + INTEL_VGA_DEVICE(0x4557, info), \ + INTEL_VGA_DEVICE(0x4571, info) + +/* JSL */ +#define INTEL_JSL_IDS(info) \ + INTEL_VGA_DEVICE(0x4E51, info), \ + INTEL_VGA_DEVICE(0x4E55, info), \ + INTEL_VGA_DEVICE(0x4E57, info), \ + INTEL_VGA_DEVICE(0x4E61, info), \ + INTEL_VGA_DEVICE(0x4E71, info) + +/* TGL */ +#define INTEL_TGL_12_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x9A60, info), \ + INTEL_VGA_DEVICE(0x9A68, info), \ + INTEL_VGA_DEVICE(0x9A70, info) + +#define INTEL_TGL_12_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x9A40, info), \ + INTEL_VGA_DEVICE(0x9A49, info), \ + INTEL_VGA_DEVICE(0x9A59, info), \ + INTEL_VGA_DEVICE(0x9A78, info), \ + INTEL_VGA_DEVICE(0x9AC0, info), \ + INTEL_VGA_DEVICE(0x9AC9, info), \ + INTEL_VGA_DEVICE(0x9AD9, info), \ + INTEL_VGA_DEVICE(0x9AF8, info) + +#define INTEL_TGL_12_IDS(info) \ + INTEL_TGL_12_GT1_IDS(info), \ + INTEL_TGL_12_GT2_IDS(info) + +/* RKL */ +#define INTEL_RKL_IDS(info) \ + INTEL_VGA_DEVICE(0x4C80, info), \ + INTEL_VGA_DEVICE(0x4C8A, info), \ + INTEL_VGA_DEVICE(0x4C8B, info), \ + INTEL_VGA_DEVICE(0x4C8C, info), \ + INTEL_VGA_DEVICE(0x4C90, info), \ + INTEL_VGA_DEVICE(0x4C9A, info) + +/* DG1 */ +#define INTEL_DG1_IDS(info) \ + INTEL_VGA_DEVICE(0x4905, info), \ + INTEL_VGA_DEVICE(0x4906, info), \ + INTEL_VGA_DEVICE(0x4907, info), \ + INTEL_VGA_DEVICE(0x4908, info), \ + INTEL_VGA_DEVICE(0x4909, info) + +/* ADL-S */ +#define INTEL_ADLS_IDS(info) \ + INTEL_VGA_DEVICE(0x4680, info), \ + INTEL_VGA_DEVICE(0x4682, info), \ + INTEL_VGA_DEVICE(0x4688, info), \ + INTEL_VGA_DEVICE(0x468A, info), \ + INTEL_VGA_DEVICE(0x4690, info), \ + INTEL_VGA_DEVICE(0x4692, info), \ + INTEL_VGA_DEVICE(0x4693, info) + +/* ADL-P */ +#define INTEL_ADLP_IDS(info) \ + INTEL_VGA_DEVICE(0x46A0, info), \ + INTEL_VGA_DEVICE(0x46A1, info), \ + INTEL_VGA_DEVICE(0x46A2, info), \ + INTEL_VGA_DEVICE(0x46A3, info), \ + INTEL_VGA_DEVICE(0x46A6, info), \ + INTEL_VGA_DEVICE(0x46A8, info), \ + INTEL_VGA_DEVICE(0x46AA, info), \ + INTEL_VGA_DEVICE(0x462A, info), \ + INTEL_VGA_DEVICE(0x4626, info), \ + INTEL_VGA_DEVICE(0x4628, info), \ + INTEL_VGA_DEVICE(0x46B0, info), \ + INTEL_VGA_DEVICE(0x46B1, info), \ + INTEL_VGA_DEVICE(0x46B2, info), \ + INTEL_VGA_DEVICE(0x46B3, info), \ + INTEL_VGA_DEVICE(0x46C0, info), \ + INTEL_VGA_DEVICE(0x46C1, info), \ + INTEL_VGA_DEVICE(0x46C2, info), \ + INTEL_VGA_DEVICE(0x46C3, info) + +/* ADL-N */ +#define INTEL_ADLN_IDS(info) \ + INTEL_VGA_DEVICE(0x46D0, info), \ + INTEL_VGA_DEVICE(0x46D1, info), \ + INTEL_VGA_DEVICE(0x46D2, info) + +/* RPL-S */ +#define INTEL_RPLS_IDS(info) \ + INTEL_VGA_DEVICE(0xA780, info), \ + INTEL_VGA_DEVICE(0xA781, info), \ + INTEL_VGA_DEVICE(0xA782, info), \ + INTEL_VGA_DEVICE(0xA783, info), \ + INTEL_VGA_DEVICE(0xA788, info), \ + INTEL_VGA_DEVICE(0xA789, info), \ + INTEL_VGA_DEVICE(0xA78A, info), \ + INTEL_VGA_DEVICE(0xA78B, info) + +/* RPL-P */ +#define INTEL_RPLP_IDS(info) \ + INTEL_VGA_DEVICE(0xA720, info), \ + INTEL_VGA_DEVICE(0xA721, info), \ + INTEL_VGA_DEVICE(0xA7A0, info), \ + INTEL_VGA_DEVICE(0xA7A1, info), \ + INTEL_VGA_DEVICE(0xA7A8, info), \ + INTEL_VGA_DEVICE(0xA7A9, info) + +/* DG2 */ +#define INTEL_DG2_G10_IDS(info) \ + INTEL_VGA_DEVICE(0x5690, info), \ + INTEL_VGA_DEVICE(0x5691, info), \ + INTEL_VGA_DEVICE(0x5692, info), \ + INTEL_VGA_DEVICE(0x56A0, info), \ + INTEL_VGA_DEVICE(0x56A1, info), \ + INTEL_VGA_DEVICE(0x56A2, info) + +#define INTEL_DG2_G11_IDS(info) \ + INTEL_VGA_DEVICE(0x5693, info), \ + INTEL_VGA_DEVICE(0x5694, info), \ + INTEL_VGA_DEVICE(0x5695, info), \ + INTEL_VGA_DEVICE(0x5698, info), \ + INTEL_VGA_DEVICE(0x56A5, info), \ + INTEL_VGA_DEVICE(0x56A6, info), \ + INTEL_VGA_DEVICE(0x56B0, info), \ + INTEL_VGA_DEVICE(0x56B1, info) + +#define INTEL_DG2_G12_IDS(info) \ + INTEL_VGA_DEVICE(0x5696, info), \ + INTEL_VGA_DEVICE(0x5697, info), \ + INTEL_VGA_DEVICE(0x56A3, info), \ + INTEL_VGA_DEVICE(0x56A4, info), \ + INTEL_VGA_DEVICE(0x56B2, info), \ + INTEL_VGA_DEVICE(0x56B3, info) + +#define INTEL_DG2_IDS(info) \ + INTEL_DG2_G10_IDS(info), \ + INTEL_DG2_G11_IDS(info), \ + INTEL_DG2_G12_IDS(info) + +#define INTEL_ATS_M150_IDS(info) \ + INTEL_VGA_DEVICE(0x56C0, info) + +#define INTEL_ATS_M75_IDS(info) \ + INTEL_VGA_DEVICE(0x56C1, info) + +#define INTEL_ATS_M_IDS(info) \ + INTEL_ATS_M150_IDS(info), \ + INTEL_ATS_M75_IDS(info) +/* MTL */ +#define INTEL_MTL_M_IDS(info) \ + INTEL_VGA_DEVICE(0x7D40, info), \ + INTEL_VGA_DEVICE(0x7D60, info) + +#define INTEL_MTL_P_IDS(info) \ + INTEL_VGA_DEVICE(0x7D45, info), \ + INTEL_VGA_DEVICE(0x7D55, info), \ + INTEL_VGA_DEVICE(0x7DD5, info) + +#define INTEL_MTL_IDS(info) \ + INTEL_MTL_M_IDS(info), \ + INTEL_MTL_P_IDS(info) + +#endif /* _I915_PCIIDS_H */ diff --git a/intel/intel-symbols.txt b/intel/intel-symbols.txt new file mode 100644 index 0000000..132df96 --- /dev/null +++ b/intel/intel-symbols.txt @@ -0,0 +1,83 @@ +drm_intel_bo_alloc +drm_intel_bo_alloc_for_render +drm_intel_bo_alloc_tiled +drm_intel_bo_alloc_userptr +drm_intel_bo_busy +drm_intel_bo_disable_reuse +drm_intel_bo_emit_reloc +drm_intel_bo_emit_reloc_fence +drm_intel_bo_exec +drm_intel_bo_fake_alloc_static +drm_intel_bo_fake_disable_backing_store +drm_intel_bo_flink +drm_intel_bo_gem_create_from_name +drm_intel_bo_gem_create_from_prime +drm_intel_bo_gem_export_to_prime +drm_intel_bo_get_subdata +drm_intel_bo_get_tiling +drm_intel_bo_is_reusable +drm_intel_bo_madvise +drm_intel_bo_map +drm_intel_bo_mrb_exec +drm_intel_bo_pin +drm_intel_bo_reference +drm_intel_bo_references +drm_intel_bo_set_softpin_offset +drm_intel_bo_set_tiling +drm_intel_bo_subdata +drm_intel_bo_unmap +drm_intel_bo_unpin +drm_intel_bo_unreference +drm_intel_bo_use_48b_address_range +drm_intel_bo_wait_rendering +drm_intel_bufmgr_check_aperture_space +drm_intel_bufmgr_destroy +drm_intel_bufmgr_fake_contended_lock_take +drm_intel_bufmgr_fake_evict_all +drm_intel_bufmgr_fake_init +drm_intel_bufmgr_fake_set_exec_callback +drm_intel_bufmgr_fake_set_fence_callback +drm_intel_bufmgr_fake_set_last_dispatch +drm_intel_bufmgr_gem_can_disable_implicit_sync +drm_intel_bufmgr_gem_enable_fenced_relocs +drm_intel_bufmgr_gem_enable_reuse +drm_intel_bufmgr_gem_get_devid +drm_intel_bufmgr_gem_init +drm_intel_bufmgr_gem_set_aub_annotations +drm_intel_bufmgr_gem_set_aub_dump +drm_intel_bufmgr_gem_set_aub_filename +drm_intel_bufmgr_gem_set_vma_cache_size +drm_intel_bufmgr_set_debug +drm_intel_decode +drm_intel_decode_context_alloc +drm_intel_decode_context_free +drm_intel_decode_set_batch_pointer +drm_intel_decode_set_dump_past_end +drm_intel_decode_set_head_tail +drm_intel_decode_set_output_file +drm_intel_gem_bo_aub_dump_bmp +drm_intel_gem_bo_clear_relocs +drm_intel_gem_bo_context_exec +drm_intel_gem_bo_disable_implicit_sync +drm_intel_gem_bo_enable_implicit_sync +drm_intel_gem_bo_fence_exec +drm_intel_gem_bo_get_reloc_count +drm_intel_gem_bo_map__cpu +drm_intel_gem_bo_map__gtt +drm_intel_gem_bo_map__wc +drm_intel_gem_bo_map_gtt +drm_intel_gem_bo_map_unsynchronized +drm_intel_gem_bo_start_gtt_access +drm_intel_gem_bo_unmap_gtt +drm_intel_gem_bo_wait +drm_intel_gem_context_create +drm_intel_gem_context_destroy +drm_intel_gem_context_get_id +drm_intel_get_aperture_sizes +drm_intel_get_eu_total +drm_intel_get_min_eu_in_pool +drm_intel_get_pipe_from_crtc_id +drm_intel_get_pooled_eu +drm_intel_get_reset_stats +drm_intel_get_subslice_total +drm_intel_reg_read diff --git a/intel/intel_aub.h b/intel/intel_aub.h new file mode 100644 index 0000000..5f0aba8 --- /dev/null +++ b/intel/intel_aub.h @@ -0,0 +1,153 @@ +/* + * Copyright © 2010 Intel Corporation + * + * 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 (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 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. + * + * Authors: + * Eric Anholt + * + */ + +/** @file intel_aub.h + * + * The AUB file is a file format used by Intel's internal simulation + * and other validation tools. It can be used at various levels by a + * driver to input state to the simulated hardware or a replaying + * debugger. + * + * We choose to dump AUB files using the trace block format for ease + * of implementation -- dump out the blocks of memory as plain blobs + * and insert ring commands to execute the batchbuffer blob. + */ + +#ifndef _INTEL_AUB_H +#define _INTEL_AUB_H + +#define AUB_MI_NOOP (0) +#define AUB_MI_BATCH_BUFFER_START (0x31 << 23) +#define AUB_PIPE_CONTROL (0x7a000002) + +/* DW0: instruction type. */ + +#define CMD_AUB (7 << 29) + +#define CMD_AUB_HEADER (CMD_AUB | (1 << 23) | (0x05 << 16)) +/* DW1 */ +# define AUB_HEADER_MAJOR_SHIFT 24 +# define AUB_HEADER_MINOR_SHIFT 16 + +#define CMD_AUB_TRACE_HEADER_BLOCK (CMD_AUB | (1 << 23) | (0x41 << 16)) +#define CMD_AUB_DUMP_BMP (CMD_AUB | (1 << 23) | (0x9e << 16)) + +/* DW1 */ +#define AUB_TRACE_OPERATION_MASK 0x000000ff +#define AUB_TRACE_OP_COMMENT 0x00000000 +#define AUB_TRACE_OP_DATA_WRITE 0x00000001 +#define AUB_TRACE_OP_COMMAND_WRITE 0x00000002 +#define AUB_TRACE_OP_MMIO_WRITE 0x00000003 +// operation = TRACE_DATA_WRITE, Type +#define AUB_TRACE_TYPE_MASK 0x0000ff00 +#define AUB_TRACE_TYPE_NOTYPE (0 << 8) +#define AUB_TRACE_TYPE_BATCH (1 << 8) +#define AUB_TRACE_TYPE_VERTEX_BUFFER (5 << 8) +#define AUB_TRACE_TYPE_2D_MAP (6 << 8) +#define AUB_TRACE_TYPE_CUBE_MAP (7 << 8) +#define AUB_TRACE_TYPE_VOLUME_MAP (9 << 8) +#define AUB_TRACE_TYPE_1D_MAP (10 << 8) +#define AUB_TRACE_TYPE_CONSTANT_BUFFER (11 << 8) +#define AUB_TRACE_TYPE_CONSTANT_URB (12 << 8) +#define AUB_TRACE_TYPE_INDEX_BUFFER (13 << 8) +#define AUB_TRACE_TYPE_GENERAL (14 << 8) +#define AUB_TRACE_TYPE_SURFACE (15 << 8) + + +// operation = TRACE_COMMAND_WRITE, Type = +#define AUB_TRACE_TYPE_RING_HWB (1 << 8) +#define AUB_TRACE_TYPE_RING_PRB0 (2 << 8) +#define AUB_TRACE_TYPE_RING_PRB1 (3 << 8) +#define AUB_TRACE_TYPE_RING_PRB2 (4 << 8) + +// Address space +#define AUB_TRACE_ADDRESS_SPACE_MASK 0x00ff0000 +#define AUB_TRACE_MEMTYPE_GTT (0 << 16) +#define AUB_TRACE_MEMTYPE_LOCAL (1 << 16) +#define AUB_TRACE_MEMTYPE_NONLOCAL (2 << 16) +#define AUB_TRACE_MEMTYPE_PCI (3 << 16) +#define AUB_TRACE_MEMTYPE_GTT_ENTRY (4 << 16) + +/* DW2 */ + +/** + * aub_state_struct_type enum values are encoded with the top 16 bits + * representing the type to be delivered to the .aub file, and the bottom 16 + * bits representing the subtype. This macro performs the encoding. + */ +#define ENCODE_SS_TYPE(type, subtype) (((type) << 16) | (subtype)) + +enum aub_state_struct_type { + AUB_TRACE_VS_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 1), + AUB_TRACE_GS_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 2), + AUB_TRACE_CLIP_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 3), + AUB_TRACE_SF_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 4), + AUB_TRACE_WM_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 5), + AUB_TRACE_CC_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 6), + AUB_TRACE_CLIP_VP_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 7), + AUB_TRACE_SF_VP_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 8), + AUB_TRACE_CC_VP_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0x9), + AUB_TRACE_SAMPLER_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0xa), + AUB_TRACE_KERNEL_INSTRUCTIONS = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0xb), + AUB_TRACE_SCRATCH_SPACE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0xc), + AUB_TRACE_SAMPLER_DEFAULT_COLOR = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0xd), + + AUB_TRACE_SCISSOR_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0x15), + AUB_TRACE_BLEND_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0x16), + AUB_TRACE_DEPTH_STENCIL_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_GENERAL, 0x17), + + AUB_TRACE_VERTEX_BUFFER = ENCODE_SS_TYPE(AUB_TRACE_TYPE_VERTEX_BUFFER, 0), + AUB_TRACE_BINDING_TABLE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_SURFACE, 0x100), + AUB_TRACE_SURFACE_STATE = ENCODE_SS_TYPE(AUB_TRACE_TYPE_SURFACE, 0x200), + AUB_TRACE_VS_CONSTANTS = ENCODE_SS_TYPE(AUB_TRACE_TYPE_CONSTANT_BUFFER, 0), + AUB_TRACE_WM_CONSTANTS = ENCODE_SS_TYPE(AUB_TRACE_TYPE_CONSTANT_BUFFER, 1), +}; + +#undef ENCODE_SS_TYPE + +/** + * Decode a aub_state_struct_type value to determine the type that should be + * stored in the .aub file. + */ +static inline uint32_t AUB_TRACE_TYPE(enum aub_state_struct_type ss_type) +{ + return (ss_type & 0xFFFF0000) >> 16; +} + +/** + * Decode a state_struct_type value to determine the subtype that should be + * stored in the .aub file. + */ +static inline uint32_t AUB_TRACE_SUBTYPE(enum aub_state_struct_type ss_type) +{ + return ss_type & 0xFFFF; +} + +/* DW3: address */ +/* DW4: len */ + +#endif /* _INTEL_AUB_H */ diff --git a/intel/intel_bufmgr.c b/intel/intel_bufmgr.c new file mode 100644 index 0000000..68d97c0 --- /dev/null +++ b/intel/intel_bufmgr.c @@ -0,0 +1,382 @@ +/* + * Copyright © 2007 Intel Corporation + * + * 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 (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 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. + * + * Authors: + * Eric Anholt + * + */ + +#include +#include +#include +#include +#include +#include +#include +#ifndef __ANDROID__ +#include +#endif +#include "libdrm_macros.h" +#include "intel_bufmgr.h" +#include "intel_bufmgr_priv.h" +#include "xf86drm.h" + +/** @file intel_bufmgr.c + * + * Convenience functions for buffer management methods. + */ + +drm_public drm_intel_bo * +drm_intel_bo_alloc(drm_intel_bufmgr *bufmgr, const char *name, + unsigned long size, unsigned int alignment) +{ + return bufmgr->bo_alloc(bufmgr, name, size, alignment); +} + +drm_public drm_intel_bo * +drm_intel_bo_alloc_for_render(drm_intel_bufmgr *bufmgr, const char *name, + unsigned long size, unsigned int alignment) +{ + return bufmgr->bo_alloc_for_render(bufmgr, name, size, alignment); +} + +drm_public drm_intel_bo * +drm_intel_bo_alloc_userptr(drm_intel_bufmgr *bufmgr, + const char *name, void *addr, + uint32_t tiling_mode, + uint32_t stride, + unsigned long size, + unsigned long flags) +{ + if (bufmgr->bo_alloc_userptr) + return bufmgr->bo_alloc_userptr(bufmgr, name, addr, tiling_mode, + stride, size, flags); + return NULL; +} + +drm_public drm_intel_bo * +drm_intel_bo_alloc_tiled(drm_intel_bufmgr *bufmgr, const char *name, + int x, int y, int cpp, uint32_t *tiling_mode, + unsigned long *pitch, unsigned long flags) +{ + return bufmgr->bo_alloc_tiled(bufmgr, name, x, y, cpp, + tiling_mode, pitch, flags); +} + +drm_public void +drm_intel_bo_reference(drm_intel_bo *bo) +{ + bo->bufmgr->bo_reference(bo); +} + +drm_public void +drm_intel_bo_unreference(drm_intel_bo *bo) +{ + if (bo == NULL) + return; + + bo->bufmgr->bo_unreference(bo); +} + +drm_public int +drm_intel_bo_map(drm_intel_bo *buf, int write_enable) +{ + return buf->bufmgr->bo_map(buf, write_enable); +} + +drm_public int +drm_intel_bo_unmap(drm_intel_bo *buf) +{ + return buf->bufmgr->bo_unmap(buf); +} + +drm_public int +drm_intel_bo_subdata(drm_intel_bo *bo, unsigned long offset, + unsigned long size, const void *data) +{ + return bo->bufmgr->bo_subdata(bo, offset, size, data); +} + +drm_public int +drm_intel_bo_get_subdata(drm_intel_bo *bo, unsigned long offset, + unsigned long size, void *data) +{ + int ret; + if (bo->bufmgr->bo_get_subdata) + return bo->bufmgr->bo_get_subdata(bo, offset, size, data); + + if (size == 0 || data == NULL) + return 0; + + ret = drm_intel_bo_map(bo, 0); + if (ret) + return ret; + memcpy(data, (unsigned char *)bo->virtual + offset, size); + drm_intel_bo_unmap(bo); + return 0; +} + +drm_public void +drm_intel_bo_wait_rendering(drm_intel_bo *bo) +{ + bo->bufmgr->bo_wait_rendering(bo); +} + +drm_public void +drm_intel_bufmgr_destroy(drm_intel_bufmgr *bufmgr) +{ + bufmgr->destroy(bufmgr); +} + +drm_public int +drm_intel_bo_exec(drm_intel_bo *bo, int used, + drm_clip_rect_t * cliprects, int num_cliprects, int DR4) +{ + return bo->bufmgr->bo_exec(bo, used, cliprects, num_cliprects, DR4); +} + +drm_public int +drm_intel_bo_mrb_exec(drm_intel_bo *bo, int used, + drm_clip_rect_t *cliprects, int num_cliprects, int DR4, + unsigned int rings) +{ + if (bo->bufmgr->bo_mrb_exec) + return bo->bufmgr->bo_mrb_exec(bo, used, + cliprects, num_cliprects, DR4, + rings); + + switch (rings) { + case I915_EXEC_DEFAULT: + case I915_EXEC_RENDER: + return bo->bufmgr->bo_exec(bo, used, + cliprects, num_cliprects, DR4); + default: + return -ENODEV; + } +} + +drm_public void +drm_intel_bufmgr_set_debug(drm_intel_bufmgr *bufmgr, int enable_debug) +{ + bufmgr->debug = enable_debug; +} + +drm_public int +drm_intel_bufmgr_check_aperture_space(drm_intel_bo ** bo_array, int count) +{ + return bo_array[0]->bufmgr->check_aperture_space(bo_array, count); +} + +drm_public int +drm_intel_bo_flink(drm_intel_bo *bo, uint32_t * name) +{ + if (bo->bufmgr->bo_flink) + return bo->bufmgr->bo_flink(bo, name); + + return -ENODEV; +} + +drm_public int +drm_intel_bo_emit_reloc(drm_intel_bo *bo, uint32_t offset, + drm_intel_bo *target_bo, uint32_t target_offset, + uint32_t read_domains, uint32_t write_domain) +{ + return bo->bufmgr->bo_emit_reloc(bo, offset, + target_bo, target_offset, + read_domains, write_domain); +} + +/* For fence registers, not GL fences */ +drm_public int +drm_intel_bo_emit_reloc_fence(drm_intel_bo *bo, uint32_t offset, + drm_intel_bo *target_bo, uint32_t target_offset, + uint32_t read_domains, uint32_t write_domain) +{ + return bo->bufmgr->bo_emit_reloc_fence(bo, offset, + target_bo, target_offset, + read_domains, write_domain); +} + + +drm_public int +drm_intel_bo_pin(drm_intel_bo *bo, uint32_t alignment) +{ + if (bo->bufmgr->bo_pin) + return bo->bufmgr->bo_pin(bo, alignment); + + return -ENODEV; +} + +drm_public int +drm_intel_bo_unpin(drm_intel_bo *bo) +{ + if (bo->bufmgr->bo_unpin) + return bo->bufmgr->bo_unpin(bo); + + return -ENODEV; +} + +drm_public int +drm_intel_bo_set_tiling(drm_intel_bo *bo, uint32_t * tiling_mode, + uint32_t stride) +{ + if (bo->bufmgr->bo_set_tiling) + return bo->bufmgr->bo_set_tiling(bo, tiling_mode, stride); + + *tiling_mode = I915_TILING_NONE; + return 0; +} + +drm_public int +drm_intel_bo_get_tiling(drm_intel_bo *bo, uint32_t * tiling_mode, + uint32_t * swizzle_mode) +{ + if (bo->bufmgr->bo_get_tiling) + return bo->bufmgr->bo_get_tiling(bo, tiling_mode, swizzle_mode); + + *tiling_mode = I915_TILING_NONE; + *swizzle_mode = I915_BIT_6_SWIZZLE_NONE; + return 0; +} + +drm_public int +drm_intel_bo_set_softpin_offset(drm_intel_bo *bo, uint64_t offset) +{ + if (bo->bufmgr->bo_set_softpin_offset) + return bo->bufmgr->bo_set_softpin_offset(bo, offset); + + return -ENODEV; +} + +drm_public int +drm_intel_bo_disable_reuse(drm_intel_bo *bo) +{ + if (bo->bufmgr->bo_disable_reuse) + return bo->bufmgr->bo_disable_reuse(bo); + return 0; +} + +drm_public int +drm_intel_bo_is_reusable(drm_intel_bo *bo) +{ + if (bo->bufmgr->bo_is_reusable) + return bo->bufmgr->bo_is_reusable(bo); + return 0; +} + +drm_public int +drm_intel_bo_busy(drm_intel_bo *bo) +{ + if (bo->bufmgr->bo_busy) + return bo->bufmgr->bo_busy(bo); + return 0; +} + +drm_public int +drm_intel_bo_madvise(drm_intel_bo *bo, int madv) +{ + if (bo->bufmgr->bo_madvise) + return bo->bufmgr->bo_madvise(bo, madv); + return -1; +} + +drm_public int +drm_intel_bo_use_48b_address_range(drm_intel_bo *bo, uint32_t enable) +{ + if (bo->bufmgr->bo_use_48b_address_range) { + bo->bufmgr->bo_use_48b_address_range(bo, enable); + return 0; + } + + return -ENODEV; +} + +drm_public int +drm_intel_bo_references(drm_intel_bo *bo, drm_intel_bo *target_bo) +{ + return bo->bufmgr->bo_references(bo, target_bo); +} + +drm_public int +drm_intel_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, int crtc_id) +{ + if (bufmgr->get_pipe_from_crtc_id) + return bufmgr->get_pipe_from_crtc_id(bufmgr, crtc_id); + return -1; +} + +#ifndef __ANDROID__ +static size_t +drm_intel_probe_agp_aperture_size(int fd) +{ + struct pci_device *pci_dev; + size_t size = 0; + int ret; + + ret = pci_system_init(); + if (ret) + goto err; + + /* XXX handle multiple adaptors? */ + pci_dev = pci_device_find_by_slot(0, 0, 2, 0); + if (pci_dev == NULL) + goto err; + + ret = pci_device_probe(pci_dev); + if (ret) + goto err; + + size = pci_dev->regions[2].size; +err: + pci_system_cleanup (); + return size; +} +#else +static size_t +drm_intel_probe_agp_aperture_size(int fd) +{ + /* Nothing seems to rely on this value on Android anyway... */ + fprintf(stderr, "%s: Mappable aperture size hardcoded to 64MiB\n", __func__); + return 64 * 1024 * 1024; +} +#endif + +drm_public int +drm_intel_get_aperture_sizes(int fd, size_t *mappable, size_t *total) +{ + + struct drm_i915_gem_get_aperture aperture; + int ret; + + ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture); + if (ret) + return ret; + + *mappable = 0; + /* XXX add a query for the kernel value? */ + if (*mappable == 0) + *mappable = drm_intel_probe_agp_aperture_size(fd); + if (*mappable == 0) + *mappable = 64 * 1024 * 1024; /* minimum possible value */ + *total = aperture.aper_size; + return 0; +} diff --git a/intel/intel_bufmgr.h b/intel/intel_bufmgr.h new file mode 100644 index 0000000..693472a --- /dev/null +++ b/intel/intel_bufmgr.h @@ -0,0 +1,341 @@ +/* + * Copyright © 2008-2012 Intel Corporation + * + * 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 (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 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. + * + * Authors: + * Eric Anholt + * + */ + +/** + * @file intel_bufmgr.h + * + * Public definitions of Intel-specific bufmgr functions. + */ + +#ifndef INTEL_BUFMGR_H +#define INTEL_BUFMGR_H + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +struct drm_clip_rect; + +typedef struct _drm_intel_bufmgr drm_intel_bufmgr; +typedef struct _drm_intel_context drm_intel_context; +typedef struct _drm_intel_bo drm_intel_bo; + +struct _drm_intel_bo { + /** + * Size in bytes of the buffer object. + * + * The size may be larger than the size originally requested for the + * allocation, such as being aligned to page size. + */ + unsigned long size; + + /** + * Alignment requirement for object + * + * Used for GTT mapping & pinning the object. + */ + unsigned long align; + + /** + * Deprecated field containing (possibly the low 32-bits of) the last + * seen virtual card address. Use offset64 instead. + */ + unsigned long offset; + + /** + * Virtual address for accessing the buffer data. Only valid while + * mapped. + */ +#ifdef __cplusplus + void *virt; +#else + void *virtual; +#endif + + /** Buffer manager context associated with this buffer object */ + drm_intel_bufmgr *bufmgr; + + /** + * MM-specific handle for accessing object + */ + int handle; + + /** + * Last seen card virtual address (offset from the beginning of the + * aperture) for the object. This should be used to fill relocation + * entries when calling drm_intel_bo_emit_reloc() + */ + uint64_t offset64; +}; + +enum aub_dump_bmp_format { + AUB_DUMP_BMP_FORMAT_8BIT = 1, + AUB_DUMP_BMP_FORMAT_ARGB_4444 = 4, + AUB_DUMP_BMP_FORMAT_ARGB_0888 = 6, + AUB_DUMP_BMP_FORMAT_ARGB_8888 = 7, +}; + +typedef struct _drm_intel_aub_annotation { + uint32_t type; + uint32_t subtype; + uint32_t ending_offset; +} drm_intel_aub_annotation; + +#define BO_ALLOC_FOR_RENDER (1<<0) + +drm_intel_bo *drm_intel_bo_alloc(drm_intel_bufmgr *bufmgr, const char *name, + unsigned long size, unsigned int alignment); +drm_intel_bo *drm_intel_bo_alloc_for_render(drm_intel_bufmgr *bufmgr, + const char *name, + unsigned long size, + unsigned int alignment); +drm_intel_bo *drm_intel_bo_alloc_userptr(drm_intel_bufmgr *bufmgr, + const char *name, + void *addr, uint32_t tiling_mode, + uint32_t stride, unsigned long size, + unsigned long flags); +drm_intel_bo *drm_intel_bo_alloc_tiled(drm_intel_bufmgr *bufmgr, + const char *name, + int x, int y, int cpp, + uint32_t *tiling_mode, + unsigned long *pitch, + unsigned long flags); +void drm_intel_bo_reference(drm_intel_bo *bo); +void drm_intel_bo_unreference(drm_intel_bo *bo); +int drm_intel_bo_map(drm_intel_bo *bo, int write_enable); +int drm_intel_bo_unmap(drm_intel_bo *bo); + +int drm_intel_bo_subdata(drm_intel_bo *bo, unsigned long offset, + unsigned long size, const void *data); +int drm_intel_bo_get_subdata(drm_intel_bo *bo, unsigned long offset, + unsigned long size, void *data); +void drm_intel_bo_wait_rendering(drm_intel_bo *bo); + +void drm_intel_bufmgr_set_debug(drm_intel_bufmgr *bufmgr, int enable_debug); +void drm_intel_bufmgr_destroy(drm_intel_bufmgr *bufmgr); +int drm_intel_bo_exec(drm_intel_bo *bo, int used, + struct drm_clip_rect *cliprects, int num_cliprects, int DR4); +int drm_intel_bo_mrb_exec(drm_intel_bo *bo, int used, + struct drm_clip_rect *cliprects, int num_cliprects, int DR4, + unsigned int flags); +int drm_intel_bufmgr_check_aperture_space(drm_intel_bo ** bo_array, int count); + +int drm_intel_bo_emit_reloc(drm_intel_bo *bo, uint32_t offset, + drm_intel_bo *target_bo, uint32_t target_offset, + uint32_t read_domains, uint32_t write_domain); +int drm_intel_bo_emit_reloc_fence(drm_intel_bo *bo, uint32_t offset, + drm_intel_bo *target_bo, + uint32_t target_offset, + uint32_t read_domains, uint32_t write_domain); +int drm_intel_bo_pin(drm_intel_bo *bo, uint32_t alignment); +int drm_intel_bo_unpin(drm_intel_bo *bo); +int drm_intel_bo_set_tiling(drm_intel_bo *bo, uint32_t * tiling_mode, + uint32_t stride); +int drm_intel_bo_get_tiling(drm_intel_bo *bo, uint32_t * tiling_mode, + uint32_t * swizzle_mode); +int drm_intel_bo_flink(drm_intel_bo *bo, uint32_t * name); +int drm_intel_bo_busy(drm_intel_bo *bo); +int drm_intel_bo_madvise(drm_intel_bo *bo, int madv); +int drm_intel_bo_use_48b_address_range(drm_intel_bo *bo, uint32_t enable); +int drm_intel_bo_set_softpin_offset(drm_intel_bo *bo, uint64_t offset); + +int drm_intel_bo_disable_reuse(drm_intel_bo *bo); +int drm_intel_bo_is_reusable(drm_intel_bo *bo); +int drm_intel_bo_references(drm_intel_bo *bo, drm_intel_bo *target_bo); + +/* drm_intel_bufmgr_gem.c */ +drm_intel_bufmgr *drm_intel_bufmgr_gem_init(int fd, int batch_size); +drm_intel_bo *drm_intel_bo_gem_create_from_name(drm_intel_bufmgr *bufmgr, + const char *name, + unsigned int handle); +void drm_intel_bufmgr_gem_enable_reuse(drm_intel_bufmgr *bufmgr); +void drm_intel_bufmgr_gem_enable_fenced_relocs(drm_intel_bufmgr *bufmgr); +void drm_intel_bufmgr_gem_set_vma_cache_size(drm_intel_bufmgr *bufmgr, + int limit); +int drm_intel_gem_bo_map_unsynchronized(drm_intel_bo *bo); +int drm_intel_gem_bo_map_gtt(drm_intel_bo *bo); +int drm_intel_gem_bo_unmap_gtt(drm_intel_bo *bo); + +#define HAVE_DRM_INTEL_GEM_BO_DISABLE_IMPLICIT_SYNC 1 +int drm_intel_bufmgr_gem_can_disable_implicit_sync(drm_intel_bufmgr *bufmgr); +void drm_intel_gem_bo_disable_implicit_sync(drm_intel_bo *bo); +void drm_intel_gem_bo_enable_implicit_sync(drm_intel_bo *bo); + +void *drm_intel_gem_bo_map__cpu(drm_intel_bo *bo); +void *drm_intel_gem_bo_map__gtt(drm_intel_bo *bo); +void *drm_intel_gem_bo_map__wc(drm_intel_bo *bo); + +int drm_intel_gem_bo_get_reloc_count(drm_intel_bo *bo); +void drm_intel_gem_bo_clear_relocs(drm_intel_bo *bo, int start); +void drm_intel_gem_bo_start_gtt_access(drm_intel_bo *bo, int write_enable); + +void +drm_intel_bufmgr_gem_set_aub_filename(drm_intel_bufmgr *bufmgr, + const char *filename); +void drm_intel_bufmgr_gem_set_aub_dump(drm_intel_bufmgr *bufmgr, int enable); +void drm_intel_gem_bo_aub_dump_bmp(drm_intel_bo *bo, + int x1, int y1, int width, int height, + enum aub_dump_bmp_format format, + int pitch, int offset); +void +drm_intel_bufmgr_gem_set_aub_annotations(drm_intel_bo *bo, + drm_intel_aub_annotation *annotations, + unsigned count); + +int drm_intel_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, int crtc_id); + +int drm_intel_get_aperture_sizes(int fd, size_t *mappable, size_t *total); +int drm_intel_bufmgr_gem_get_devid(drm_intel_bufmgr *bufmgr); +int drm_intel_gem_bo_wait(drm_intel_bo *bo, int64_t timeout_ns); + +drm_intel_context *drm_intel_gem_context_create(drm_intel_bufmgr *bufmgr); +int drm_intel_gem_context_get_id(drm_intel_context *ctx, + uint32_t *ctx_id); +void drm_intel_gem_context_destroy(drm_intel_context *ctx); +int drm_intel_gem_bo_context_exec(drm_intel_bo *bo, drm_intel_context *ctx, + int used, unsigned int flags); +int drm_intel_gem_bo_fence_exec(drm_intel_bo *bo, + drm_intel_context *ctx, + int used, + int in_fence, + int *out_fence, + unsigned int flags); + +int drm_intel_bo_gem_export_to_prime(drm_intel_bo *bo, int *prime_fd); +drm_intel_bo *drm_intel_bo_gem_create_from_prime(drm_intel_bufmgr *bufmgr, + int prime_fd, int size); + +/* drm_intel_bufmgr_fake.c */ +drm_intel_bufmgr *drm_intel_bufmgr_fake_init(int fd, + unsigned long low_offset, + void *low_virtual, + unsigned long size, + volatile unsigned int + *last_dispatch); +void drm_intel_bufmgr_fake_set_last_dispatch(drm_intel_bufmgr *bufmgr, + volatile unsigned int + *last_dispatch); +void drm_intel_bufmgr_fake_set_exec_callback(drm_intel_bufmgr *bufmgr, + int (*exec) (drm_intel_bo *bo, + unsigned int used, + void *priv), + void *priv); +void drm_intel_bufmgr_fake_set_fence_callback(drm_intel_bufmgr *bufmgr, + unsigned int (*emit) (void *priv), + void (*wait) (unsigned int fence, + void *priv), + void *priv); +drm_intel_bo *drm_intel_bo_fake_alloc_static(drm_intel_bufmgr *bufmgr, + const char *name, + unsigned long offset, + unsigned long size, void *virt); +void drm_intel_bo_fake_disable_backing_store(drm_intel_bo *bo, + void (*invalidate_cb) (drm_intel_bo + * bo, + void *ptr), + void *ptr); + +void drm_intel_bufmgr_fake_contended_lock_take(drm_intel_bufmgr *bufmgr); +void drm_intel_bufmgr_fake_evict_all(drm_intel_bufmgr *bufmgr); + +struct drm_intel_decode *drm_intel_decode_context_alloc(uint32_t devid); +void drm_intel_decode_context_free(struct drm_intel_decode *ctx); +void drm_intel_decode_set_batch_pointer(struct drm_intel_decode *ctx, + void *data, uint32_t hw_offset, + int count); +void drm_intel_decode_set_dump_past_end(struct drm_intel_decode *ctx, + int dump_past_end); +void drm_intel_decode_set_head_tail(struct drm_intel_decode *ctx, + uint32_t head, uint32_t tail); +void drm_intel_decode_set_output_file(struct drm_intel_decode *ctx, FILE *out); +void drm_intel_decode(struct drm_intel_decode *ctx); + +int drm_intel_reg_read(drm_intel_bufmgr *bufmgr, + uint32_t offset, + uint64_t *result); + +int drm_intel_get_reset_stats(drm_intel_context *ctx, + uint32_t *reset_count, + uint32_t *active, + uint32_t *pending); + +int drm_intel_get_subslice_total(int fd, unsigned int *subslice_total); +int drm_intel_get_eu_total(int fd, unsigned int *eu_total); + +int drm_intel_get_pooled_eu(int fd); +int drm_intel_get_min_eu_in_pool(int fd); + +/** @{ Compatibility defines to keep old code building despite the symbol rename + * from dri_* to drm_intel_* + */ +#define dri_bo drm_intel_bo +#define dri_bufmgr drm_intel_bufmgr +#define dri_bo_alloc drm_intel_bo_alloc +#define dri_bo_reference drm_intel_bo_reference +#define dri_bo_unreference drm_intel_bo_unreference +#define dri_bo_map drm_intel_bo_map +#define dri_bo_unmap drm_intel_bo_unmap +#define dri_bo_subdata drm_intel_bo_subdata +#define dri_bo_get_subdata drm_intel_bo_get_subdata +#define dri_bo_wait_rendering drm_intel_bo_wait_rendering +#define dri_bufmgr_set_debug drm_intel_bufmgr_set_debug +#define dri_bufmgr_destroy drm_intel_bufmgr_destroy +#define dri_bo_exec drm_intel_bo_exec +#define dri_bufmgr_check_aperture_space drm_intel_bufmgr_check_aperture_space +#define dri_bo_emit_reloc(reloc_bo, read, write, target_offset, \ + reloc_offset, target_bo) \ + drm_intel_bo_emit_reloc(reloc_bo, reloc_offset, \ + target_bo, target_offset, \ + read, write); +#define dri_bo_pin drm_intel_bo_pin +#define dri_bo_unpin drm_intel_bo_unpin +#define dri_bo_get_tiling drm_intel_bo_get_tiling +#define dri_bo_set_tiling(bo, mode) drm_intel_bo_set_tiling(bo, mode, 0) +#define dri_bo_flink drm_intel_bo_flink +#define intel_bufmgr_gem_init drm_intel_bufmgr_gem_init +#define intel_bo_gem_create_from_name drm_intel_bo_gem_create_from_name +#define intel_bufmgr_gem_enable_reuse drm_intel_bufmgr_gem_enable_reuse +#define intel_bufmgr_fake_init drm_intel_bufmgr_fake_init +#define intel_bufmgr_fake_set_last_dispatch drm_intel_bufmgr_fake_set_last_dispatch +#define intel_bufmgr_fake_set_exec_callback drm_intel_bufmgr_fake_set_exec_callback +#define intel_bufmgr_fake_set_fence_callback drm_intel_bufmgr_fake_set_fence_callback +#define intel_bo_fake_alloc_static drm_intel_bo_fake_alloc_static +#define intel_bo_fake_disable_backing_store drm_intel_bo_fake_disable_backing_store +#define intel_bufmgr_fake_contended_lock_take drm_intel_bufmgr_fake_contended_lock_take +#define intel_bufmgr_fake_evict_all drm_intel_bufmgr_fake_evict_all + +/** @{ */ + +#if defined(__cplusplus) +} +#endif + +#endif /* INTEL_BUFMGR_H */ diff --git a/intel/intel_bufmgr_fake.c b/intel/intel_bufmgr_fake.c new file mode 100644 index 0000000..0cec51f --- /dev/null +++ b/intel/intel_bufmgr_fake.c @@ -0,0 +1,1626 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 TUNGSTEN GRAPHICS 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. + * + **************************************************************************/ + +/* Originally a fake version of the buffer manager so that we can + * prototype the changes in a driver fairly quickly, has been fleshed + * out to a fully functional interim solution. + * + * Basically wraps the old style memory management in the new + * programming interface, but is more expressive and avoids many of + * the bugs in the old texture manager. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "intel_bufmgr.h" +#include "intel_bufmgr_priv.h" +#include "drm.h" +#include "i915_drm.h" +#include "mm.h" +#include "libdrm_macros.h" +#include "libdrm_lists.h" + +#define DBG(...) do { \ + if (bufmgr_fake->bufmgr.debug) \ + drmMsg(__VA_ARGS__); \ +} while (0) + +/* Internal flags: + */ +#define BM_NO_BACKING_STORE 0x00000001 +#define BM_NO_FENCE_SUBDATA 0x00000002 +#define BM_PINNED 0x00000004 + +/* Wrapper around mm.c's mem_block, which understands that you must + * wait for fences to expire before memory can be freed. This is + * specific to our use of memcpy for uploads - an upload that was + * processed through the command queue wouldn't need to care about + * fences. + */ +#define MAX_RELOCS 4096 + +struct fake_buffer_reloc { + /** Buffer object that the relocation points at. */ + drm_intel_bo *target_buf; + /** Offset of the relocation entry within reloc_buf. */ + uint32_t offset; + /** + * Cached value of the offset when we last performed this relocation. + */ + uint32_t last_target_offset; + /** Value added to target_buf's offset to get the relocation entry. */ + uint32_t delta; + /** Cache domains the target buffer is read into. */ + uint32_t read_domains; + /** Cache domain the target buffer will have dirty cachelines in. */ + uint32_t write_domain; +}; + +struct block { + struct block *next, *prev; + struct mem_block *mem; /* BM_MEM_AGP */ + + /** + * Marks that the block is currently in the aperture and has yet to be + * fenced. + */ + unsigned on_hardware:1; + /** + * Marks that the block is currently fenced (being used by rendering) + * and can't be freed until @fence is passed. + */ + unsigned fenced:1; + + /** Fence cookie for the block. */ + unsigned fence; /* Split to read_fence, write_fence */ + + drm_intel_bo *bo; + void *virtual; +}; + +typedef struct _bufmgr_fake { + drm_intel_bufmgr bufmgr; + + pthread_mutex_t lock; + + unsigned long low_offset; + unsigned long size; + void *virtual; + + struct mem_block *heap; + + unsigned buf_nr; /* for generating ids */ + + /** + * List of blocks which are currently in the GART but haven't been + * fenced yet. + */ + struct block on_hardware; + /** + * List of blocks which are in the GART and have an active fence on + * them. + */ + struct block fenced; + /** + * List of blocks which have an expired fence and are ready to be + * evicted. + */ + struct block lru; + + unsigned int last_fence; + + unsigned fail:1; + unsigned need_fence:1; + int thrashing; + + /** + * Driver callback to emit a fence, returning the cookie. + * + * This allows the driver to hook in a replacement for the DRM usage in + * bufmgr_fake. + * + * Currently, this also requires that a write flush be emitted before + * emitting the fence, but this should change. + */ + unsigned int (*fence_emit) (void *private); + /** Driver callback to wait for a fence cookie to have passed. */ + void (*fence_wait) (unsigned int fence, void *private); + void *fence_priv; + + /** + * Driver callback to execute a buffer. + * + * This allows the driver to hook in a replacement for the DRM usage in + * bufmgr_fake. + */ + int (*exec) (drm_intel_bo *bo, unsigned int used, void *priv); + void *exec_priv; + + /** Driver-supplied argument to driver callbacks */ + void *driver_priv; + /** + * Pointer to kernel-updated sarea data for the last completed user irq + */ + volatile int *last_dispatch; + + int fd; + + int debug; + + int performed_rendering; +} drm_intel_bufmgr_fake; + +typedef struct _drm_intel_bo_fake { + drm_intel_bo bo; + + unsigned id; /* debug only */ + const char *name; + + unsigned dirty:1; + /** + * has the card written to this buffer - we make need to copy it back + */ + unsigned card_dirty:1; + unsigned int refcount; + /* Flags may consist of any of the DRM_BO flags, plus + * DRM_BO_NO_BACKING_STORE and BM_NO_FENCE_SUBDATA, which are the + * first two driver private flags. + */ + uint64_t flags; + /** Cache domains the target buffer is read into. */ + uint32_t read_domains; + /** Cache domain the target buffer will have dirty cachelines in. */ + uint32_t write_domain; + + unsigned int alignment; + int is_static, validated; + unsigned int map_count; + + /** relocation list */ + struct fake_buffer_reloc *relocs; + int nr_relocs; + /** + * Total size of the target_bos of this buffer. + * + * Used for estimation in check_aperture. + */ + unsigned int child_size; + + struct block *block; + void *backing_store; + void (*invalidate_cb) (drm_intel_bo *bo, void *ptr); + void *invalidate_ptr; +} drm_intel_bo_fake; + +static int clear_fenced(drm_intel_bufmgr_fake *bufmgr_fake, + unsigned int fence_cookie); + +#define MAXFENCE 0x7fffffff + +static int +FENCE_LTE(unsigned a, unsigned b) +{ + if (a == b) + return 1; + + if (a < b && b - a < (1 << 24)) + return 1; + + if (a > b && MAXFENCE - a + b < (1 << 24)) + return 1; + + return 0; +} + +drm_public void +drm_intel_bufmgr_fake_set_fence_callback(drm_intel_bufmgr *bufmgr, + unsigned int (*emit) (void *priv), + void (*wait) (unsigned int fence, + void *priv), + void *priv) +{ + drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr; + + bufmgr_fake->fence_emit = emit; + bufmgr_fake->fence_wait = wait; + bufmgr_fake->fence_priv = priv; +} + +static unsigned int +_fence_emit_internal(drm_intel_bufmgr_fake *bufmgr_fake) +{ + struct drm_i915_irq_emit ie; + int ret, seq = 1; + + if (bufmgr_fake->fence_emit != NULL) { + seq = bufmgr_fake->fence_emit(bufmgr_fake->fence_priv); + return seq; + } + + ie.irq_seq = &seq; + ret = drmCommandWriteRead(bufmgr_fake->fd, DRM_I915_IRQ_EMIT, + &ie, sizeof(ie)); + if (ret) { + drmMsg("%s: drm_i915_irq_emit: %d\n", __func__, ret); + abort(); + } + + DBG("emit 0x%08x\n", seq); + return seq; +} + +static void +_fence_wait_internal(drm_intel_bufmgr_fake *bufmgr_fake, int seq) +{ + struct drm_i915_irq_wait iw; + int hw_seq, busy_count = 0; + int ret; + int kernel_lied; + + if (bufmgr_fake->fence_wait != NULL) { + bufmgr_fake->fence_wait(seq, bufmgr_fake->fence_priv); + clear_fenced(bufmgr_fake, seq); + return; + } + + iw.irq_seq = seq; + + DBG("wait 0x%08x\n", iw.irq_seq); + + /* The kernel IRQ_WAIT implementation is all sorts of broken. + * 1) It returns 1 to 0x7fffffff instead of using the full 32-bit + * unsigned range. + * 2) It returns 0 if hw_seq >= seq, not seq - hw_seq < 0 on the 32-bit + * signed range. + * 3) It waits if seq < hw_seq, not seq - hw_seq > 0 on the 32-bit + * signed range. + * 4) It returns -EBUSY in 3 seconds even if the hardware is still + * successfully chewing through buffers. + * + * Assume that in userland we treat sequence numbers as ints, which + * makes some of the comparisons convenient, since the sequence + * numbers are all positive signed integers. + * + * From this we get several cases we need to handle. Here's a timeline. + * 0x2 0x7 0x7ffffff8 0x7ffffffd + * | | | | + * ------------------------------------------------------------ + * + * A) Normal wait for hw to catch up + * hw_seq seq + * | | + * ------------------------------------------------------------ + * seq - hw_seq = 5. If we call IRQ_WAIT, it will wait for hw to + * catch up. + * + * B) Normal wait for a sequence number that's already passed. + * seq hw_seq + * | | + * ------------------------------------------------------------ + * seq - hw_seq = -5. If we call IRQ_WAIT, it returns 0 quickly. + * + * C) Hardware has already wrapped around ahead of us + * hw_seq seq + * | | + * ------------------------------------------------------------ + * seq - hw_seq = 0x80000000 - 5. If we called IRQ_WAIT, it would wait + * for hw_seq >= seq, which may never occur. Thus, we want to catch + * this in userland and return 0. + * + * D) We've wrapped around ahead of the hardware. + * seq hw_seq + * | | + * ------------------------------------------------------------ + * seq - hw_seq = -(0x80000000 - 5). If we called IRQ_WAIT, it would + * return 0 quickly because hw_seq >= seq, even though the hardware + * isn't caught up. Thus, we need to catch this early return in + * userland and bother the kernel until the hardware really does + * catch up. + * + * E) Hardware might wrap after we test in userland. + * hw_seq seq + * | | + * ------------------------------------------------------------ + * seq - hw_seq = 5. If we call IRQ_WAIT, it will likely see seq >= + * hw_seq and wait. However, suppose hw_seq wraps before we make it + * into the kernel. The kernel sees hw_seq >= seq and waits for 3 + * seconds then returns -EBUSY. This is case C). We should catch + * this and then return successfully. + * + * F) Hardware might take a long time on a buffer. + * hw_seq seq + * | | + * ------------------------------------------------------------------- + * seq - hw_seq = 5. If we call IRQ_WAIT, if sequence 2 through 5 + * take too long, it will return -EBUSY. Batchbuffers in the + * gltestperf demo were seen to take up to 7 seconds. We should + * catch early -EBUSY return and keep trying. + */ + + do { + /* Keep a copy of last_dispatch so that if the wait -EBUSYs + * because the hardware didn't catch up in 3 seconds, we can + * see if it at least made progress and retry. + */ + hw_seq = *bufmgr_fake->last_dispatch; + + /* Catch case C */ + if (seq - hw_seq > 0x40000000) + return; + + ret = drmCommandWrite(bufmgr_fake->fd, DRM_I915_IRQ_WAIT, + &iw, sizeof(iw)); + /* Catch case D */ + kernel_lied = (ret == 0) && (seq - *bufmgr_fake->last_dispatch < + -0x40000000); + + /* Catch case E */ + if (ret == -EBUSY + && (seq - *bufmgr_fake->last_dispatch > 0x40000000)) + ret = 0; + + /* Catch case F: Allow up to 15 seconds chewing on one buffer. */ + if ((ret == -EBUSY) && (hw_seq != *bufmgr_fake->last_dispatch)) + busy_count = 0; + else + busy_count++; + } while (kernel_lied || ret == -EAGAIN || ret == -EINTR || + (ret == -EBUSY && busy_count < 5)); + + if (ret != 0) { + drmMsg("%s:%d: Error waiting for fence: %s.\n", __FILE__, + __LINE__, strerror(-ret)); + abort(); + } + clear_fenced(bufmgr_fake, seq); +} + +static int +_fence_test(drm_intel_bufmgr_fake *bufmgr_fake, unsigned fence) +{ + /* Slight problem with wrap-around: + */ + return fence == 0 || FENCE_LTE(fence, bufmgr_fake->last_fence); +} + +/** + * Allocate a memory manager block for the buffer. + */ +static int +alloc_block(drm_intel_bo *bo) +{ + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + struct block *block = (struct block *)calloc(sizeof *block, 1); + unsigned int align_log2 = ffs(bo_fake->alignment) - 1; + unsigned int sz; + + if (!block) + return 1; + + sz = (bo->size + bo_fake->alignment - 1) & ~(bo_fake->alignment - 1); + + block->mem = mmAllocMem(bufmgr_fake->heap, sz, align_log2, 0); + if (!block->mem) { + free(block); + return 0; + } + + DRMINITLISTHEAD(block); + + /* Insert at head or at tail??? */ + DRMLISTADDTAIL(block, &bufmgr_fake->lru); + + block->virtual = (uint8_t *) bufmgr_fake->virtual + + block->mem->ofs - bufmgr_fake->low_offset; + block->bo = bo; + + bo_fake->block = block; + + return 1; +} + +/* Release the card storage associated with buf: + */ +static void +free_block(drm_intel_bufmgr_fake *bufmgr_fake, struct block *block, + int skip_dirty_copy) +{ + drm_intel_bo_fake *bo_fake; + DBG("free block %p %08x %d %d\n", block, block->mem->ofs, + block->on_hardware, block->fenced); + + if (!block) + return; + + bo_fake = (drm_intel_bo_fake *) block->bo; + + if (bo_fake->flags & (BM_PINNED | BM_NO_BACKING_STORE)) + skip_dirty_copy = 1; + + if (!skip_dirty_copy && (bo_fake->card_dirty == 1)) { + memcpy(bo_fake->backing_store, block->virtual, block->bo->size); + bo_fake->card_dirty = 0; + bo_fake->dirty = 1; + } + + if (block->on_hardware) { + block->bo = NULL; + } else if (block->fenced) { + block->bo = NULL; + } else { + DBG(" - free immediately\n"); + DRMLISTDEL(block); + + mmFreeMem(block->mem); + free(block); + } +} + +static void +alloc_backing_store(drm_intel_bo *bo) +{ + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + assert(!bo_fake->backing_store); + assert(!(bo_fake->flags & (BM_PINNED | BM_NO_BACKING_STORE))); + + bo_fake->backing_store = malloc(bo->size); + + DBG("alloc_backing - buf %d %p %lu\n", bo_fake->id, + bo_fake->backing_store, bo->size); + assert(bo_fake->backing_store); +} + +static void +free_backing_store(drm_intel_bo *bo) +{ + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + + if (bo_fake->backing_store) { + assert(!(bo_fake->flags & (BM_PINNED | BM_NO_BACKING_STORE))); + free(bo_fake->backing_store); + bo_fake->backing_store = NULL; + } +} + +static void +set_dirty(drm_intel_bo *bo) +{ + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + + if (bo_fake->flags & BM_NO_BACKING_STORE + && bo_fake->invalidate_cb != NULL) + bo_fake->invalidate_cb(bo, bo_fake->invalidate_ptr); + + assert(!(bo_fake->flags & BM_PINNED)); + + DBG("set_dirty - buf %d\n", bo_fake->id); + bo_fake->dirty = 1; +} + +static int +evict_lru(drm_intel_bufmgr_fake *bufmgr_fake, unsigned int max_fence) +{ + struct block *block, *tmp; + + DBG("%s\n", __func__); + + DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->lru) { + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) block->bo; + + if (bo_fake != NULL && (bo_fake->flags & BM_NO_FENCE_SUBDATA)) + continue; + + if (block->fence && max_fence && !FENCE_LTE(block->fence, + max_fence)) + return 0; + + set_dirty(&bo_fake->bo); + bo_fake->block = NULL; + + free_block(bufmgr_fake, block, 0); + return 1; + } + + return 0; +} + +static int +evict_mru(drm_intel_bufmgr_fake *bufmgr_fake) +{ + struct block *block, *tmp; + + DBG("%s\n", __func__); + + DRMLISTFOREACHSAFEREVERSE(block, tmp, &bufmgr_fake->lru) { + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) block->bo; + + if (bo_fake && (bo_fake->flags & BM_NO_FENCE_SUBDATA)) + continue; + + set_dirty(&bo_fake->bo); + bo_fake->block = NULL; + + free_block(bufmgr_fake, block, 0); + return 1; + } + + return 0; +} + +/** + * Removes all objects from the fenced list older than the given fence. + */ +static int +clear_fenced(drm_intel_bufmgr_fake *bufmgr_fake, unsigned int fence_cookie) +{ + struct block *block, *tmp; + int ret = 0; + + bufmgr_fake->last_fence = fence_cookie; + DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->fenced) { + assert(block->fenced); + + if (_fence_test(bufmgr_fake, block->fence)) { + + block->fenced = 0; + + if (!block->bo) { + DBG("delayed free: offset %x sz %x\n", + block->mem->ofs, block->mem->size); + DRMLISTDEL(block); + mmFreeMem(block->mem); + free(block); + } else { + DBG("return to lru: offset %x sz %x\n", + block->mem->ofs, block->mem->size); + DRMLISTDEL(block); + DRMLISTADDTAIL(block, &bufmgr_fake->lru); + } + + ret = 1; + } else { + /* Blocks are ordered by fence, so if one fails, all + * from here will fail also: + */ + DBG("fence not passed: offset %x sz %x %d %d \n", + block->mem->ofs, block->mem->size, block->fence, + bufmgr_fake->last_fence); + break; + } + } + + DBG("%s: %d\n", __func__, ret); + return ret; +} + +static void +fence_blocks(drm_intel_bufmgr_fake *bufmgr_fake, unsigned fence) +{ + struct block *block, *tmp; + + DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->on_hardware) { + DBG("Fence block %p (sz 0x%x ofs %x buf %p) with fence %d\n", + block, block->mem->size, block->mem->ofs, block->bo, fence); + block->fence = fence; + + block->on_hardware = 0; + block->fenced = 1; + + /* Move to tail of pending list here + */ + DRMLISTDEL(block); + DRMLISTADDTAIL(block, &bufmgr_fake->fenced); + } + + assert(DRMLISTEMPTY(&bufmgr_fake->on_hardware)); +} + +static int +evict_and_alloc_block(drm_intel_bo *bo) +{ + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + + assert(bo_fake->block == NULL); + + /* Search for already free memory: + */ + if (alloc_block(bo)) + return 1; + + /* If we're not thrashing, allow lru eviction to dig deeper into + * recently used textures. We'll probably be thrashing soon: + */ + if (!bufmgr_fake->thrashing) { + while (evict_lru(bufmgr_fake, 0)) + if (alloc_block(bo)) + return 1; + } + + /* Keep thrashing counter alive? + */ + if (bufmgr_fake->thrashing) + bufmgr_fake->thrashing = 20; + + /* Wait on any already pending fences - here we are waiting for any + * freed memory that has been submitted to hardware and fenced to + * become available: + */ + while (!DRMLISTEMPTY(&bufmgr_fake->fenced)) { + uint32_t fence = bufmgr_fake->fenced.next->fence; + _fence_wait_internal(bufmgr_fake, fence); + + if (alloc_block(bo)) + return 1; + } + + if (!DRMLISTEMPTY(&bufmgr_fake->on_hardware)) { + while (!DRMLISTEMPTY(&bufmgr_fake->fenced)) { + uint32_t fence = bufmgr_fake->fenced.next->fence; + _fence_wait_internal(bufmgr_fake, fence); + } + + if (!bufmgr_fake->thrashing) { + DBG("thrashing\n"); + } + bufmgr_fake->thrashing = 20; + + if (alloc_block(bo)) + return 1; + } + + while (evict_mru(bufmgr_fake)) + if (alloc_block(bo)) + return 1; + + DBG("%s 0x%lx bytes failed\n", __func__, bo->size); + + return 0; +} + +/*********************************************************************** + * Public functions + */ + +/** + * Wait for hardware idle by emitting a fence and waiting for it. + */ +static void +drm_intel_bufmgr_fake_wait_idle(drm_intel_bufmgr_fake *bufmgr_fake) +{ + unsigned int cookie; + + cookie = _fence_emit_internal(bufmgr_fake); + _fence_wait_internal(bufmgr_fake, cookie); +} + +/** + * Wait for rendering to a buffer to complete. + * + * It is assumed that the batchbuffer which performed the rendering included + * the necessary flushing. + */ +static void +drm_intel_fake_bo_wait_rendering_locked(drm_intel_bo *bo) +{ + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + + if (bo_fake->block == NULL || !bo_fake->block->fenced) + return; + + _fence_wait_internal(bufmgr_fake, bo_fake->block->fence); +} + +static void +drm_intel_fake_bo_wait_rendering(drm_intel_bo *bo) +{ + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + + pthread_mutex_lock(&bufmgr_fake->lock); + drm_intel_fake_bo_wait_rendering_locked(bo); + pthread_mutex_unlock(&bufmgr_fake->lock); +} + +/* Specifically ignore texture memory sharing. + * -- just evict everything + * -- and wait for idle + */ +drm_public void +drm_intel_bufmgr_fake_contended_lock_take(drm_intel_bufmgr *bufmgr) +{ + drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr; + struct block *block, *tmp; + + pthread_mutex_lock(&bufmgr_fake->lock); + + bufmgr_fake->need_fence = 1; + bufmgr_fake->fail = 0; + + /* Wait for hardware idle. We don't know where acceleration has been + * happening, so we'll need to wait anyway before letting anything get + * put on the card again. + */ + drm_intel_bufmgr_fake_wait_idle(bufmgr_fake); + + /* Check that we hadn't released the lock without having fenced the last + * set of buffers. + */ + assert(DRMLISTEMPTY(&bufmgr_fake->fenced)); + assert(DRMLISTEMPTY(&bufmgr_fake->on_hardware)); + + DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->lru) { + assert(_fence_test(bufmgr_fake, block->fence)); + set_dirty(block->bo); + } + + pthread_mutex_unlock(&bufmgr_fake->lock); +} + +static drm_intel_bo * +drm_intel_fake_bo_alloc(drm_intel_bufmgr *bufmgr, + const char *name, + unsigned long size, + unsigned int alignment) +{ + drm_intel_bufmgr_fake *bufmgr_fake; + drm_intel_bo_fake *bo_fake; + + bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr; + + assert(size != 0); + + bo_fake = calloc(1, sizeof(*bo_fake)); + if (!bo_fake) + return NULL; + + bo_fake->bo.size = size; + bo_fake->bo.offset = -1; + bo_fake->bo.virtual = NULL; + bo_fake->bo.bufmgr = bufmgr; + bo_fake->refcount = 1; + + /* Alignment must be a power of two */ + assert((alignment & (alignment - 1)) == 0); + if (alignment == 0) + alignment = 1; + bo_fake->alignment = alignment; + bo_fake->id = ++bufmgr_fake->buf_nr; + bo_fake->name = name; + bo_fake->flags = 0; + bo_fake->is_static = 0; + + DBG("drm_bo_alloc: (buf %d: %s, %lu kb)\n", bo_fake->id, bo_fake->name, + bo_fake->bo.size / 1024); + + return &bo_fake->bo; +} + +static drm_intel_bo * +drm_intel_fake_bo_alloc_tiled(drm_intel_bufmgr * bufmgr, + const char *name, + int x, int y, int cpp, + uint32_t *tiling_mode, + unsigned long *pitch, + unsigned long flags) +{ + unsigned long stride, aligned_y; + + /* No runtime tiling support for fake. */ + *tiling_mode = I915_TILING_NONE; + + /* Align it for being a render target. Shouldn't need anything else. */ + stride = x * cpp; + stride = ROUND_UP_TO(stride, 64); + + /* 965 subspan loading alignment */ + aligned_y = ALIGN(y, 2); + + *pitch = stride; + + return drm_intel_fake_bo_alloc(bufmgr, name, stride * aligned_y, + 4096); +} + +drm_public drm_intel_bo * +drm_intel_bo_fake_alloc_static(drm_intel_bufmgr *bufmgr, + const char *name, + unsigned long offset, + unsigned long size, void *virtual) +{ + drm_intel_bufmgr_fake *bufmgr_fake; + drm_intel_bo_fake *bo_fake; + + bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr; + + assert(size != 0); + + bo_fake = calloc(1, sizeof(*bo_fake)); + if (!bo_fake) + return NULL; + + bo_fake->bo.size = size; + bo_fake->bo.offset = offset; + bo_fake->bo.virtual = virtual; + bo_fake->bo.bufmgr = bufmgr; + bo_fake->refcount = 1; + bo_fake->id = ++bufmgr_fake->buf_nr; + bo_fake->name = name; + bo_fake->flags = BM_PINNED; + bo_fake->is_static = 1; + + DBG("drm_bo_alloc_static: (buf %d: %s, %lu kb)\n", bo_fake->id, + bo_fake->name, bo_fake->bo.size / 1024); + + return &bo_fake->bo; +} + +static void +drm_intel_fake_bo_reference(drm_intel_bo *bo) +{ + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + + pthread_mutex_lock(&bufmgr_fake->lock); + bo_fake->refcount++; + pthread_mutex_unlock(&bufmgr_fake->lock); +} + +static void +drm_intel_fake_bo_reference_locked(drm_intel_bo *bo) +{ + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + + bo_fake->refcount++; +} + +static void +drm_intel_fake_bo_unreference_locked(drm_intel_bo *bo) +{ + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + int i; + + if (--bo_fake->refcount == 0) { + assert(bo_fake->map_count == 0); + /* No remaining references, so free it */ + if (bo_fake->block) + free_block(bufmgr_fake, bo_fake->block, 1); + free_backing_store(bo); + + for (i = 0; i < bo_fake->nr_relocs; i++) + drm_intel_fake_bo_unreference_locked(bo_fake->relocs[i]. + target_buf); + + DBG("drm_bo_unreference: free buf %d %s\n", bo_fake->id, + bo_fake->name); + + free(bo_fake->relocs); + free(bo); + } +} + +static void +drm_intel_fake_bo_unreference(drm_intel_bo *bo) +{ + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + + pthread_mutex_lock(&bufmgr_fake->lock); + drm_intel_fake_bo_unreference_locked(bo); + pthread_mutex_unlock(&bufmgr_fake->lock); +} + +/** + * Set the buffer as not requiring backing store, and instead get the callback + * invoked whenever it would be set dirty. + */ +drm_public void +drm_intel_bo_fake_disable_backing_store(drm_intel_bo *bo, + void (*invalidate_cb) (drm_intel_bo *bo, + void *ptr), + void *ptr) +{ + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + + pthread_mutex_lock(&bufmgr_fake->lock); + + if (bo_fake->backing_store) + free_backing_store(bo); + + bo_fake->flags |= BM_NO_BACKING_STORE; + + DBG("disable_backing_store set buf %d dirty\n", bo_fake->id); + bo_fake->dirty = 1; + bo_fake->invalidate_cb = invalidate_cb; + bo_fake->invalidate_ptr = ptr; + + /* Note that it is invalid right from the start. Also note + * invalidate_cb is called with the bufmgr locked, so cannot + * itself make bufmgr calls. + */ + if (invalidate_cb != NULL) + invalidate_cb(bo, ptr); + + pthread_mutex_unlock(&bufmgr_fake->lock); +} + +/** + * Map a buffer into bo->virtual, allocating either card memory space (If + * BM_NO_BACKING_STORE or BM_PINNED) or backing store, as necessary. + */ +static int + drm_intel_fake_bo_map_locked(drm_intel_bo *bo, int write_enable) +{ + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + + /* Static buffers are always mapped. */ + if (bo_fake->is_static) { + if (bo_fake->card_dirty) { + drm_intel_bufmgr_fake_wait_idle(bufmgr_fake); + bo_fake->card_dirty = 0; + } + return 0; + } + + /* Allow recursive mapping. Mesa may recursively map buffers with + * nested display loops, and it is used internally in bufmgr_fake + * for relocation. + */ + if (bo_fake->map_count++ != 0) + return 0; + + { + DBG("drm_bo_map: (buf %d: %s, %lu kb)\n", bo_fake->id, + bo_fake->name, bo_fake->bo.size / 1024); + + if (bo->virtual != NULL) { + drmMsg("%s: already mapped\n", __func__); + abort(); + } else if (bo_fake->flags & (BM_NO_BACKING_STORE | BM_PINNED)) { + + if (!bo_fake->block && !evict_and_alloc_block(bo)) { + DBG("%s: alloc failed\n", __func__); + bufmgr_fake->fail = 1; + return 1; + } else { + assert(bo_fake->block); + bo_fake->dirty = 0; + + if (!(bo_fake->flags & BM_NO_FENCE_SUBDATA) && + bo_fake->block->fenced) { + drm_intel_fake_bo_wait_rendering_locked + (bo); + } + + bo->virtual = bo_fake->block->virtual; + } + } else { + if (write_enable) + set_dirty(bo); + + if (bo_fake->backing_store == 0) + alloc_backing_store(bo); + + if ((bo_fake->card_dirty == 1) && bo_fake->block) { + if (bo_fake->block->fenced) + drm_intel_fake_bo_wait_rendering_locked + (bo); + + memcpy(bo_fake->backing_store, + bo_fake->block->virtual, + bo_fake->block->bo->size); + bo_fake->card_dirty = 0; + } + + bo->virtual = bo_fake->backing_store; + } + } + + return 0; +} + +static int + drm_intel_fake_bo_map(drm_intel_bo *bo, int write_enable) +{ + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + int ret; + + pthread_mutex_lock(&bufmgr_fake->lock); + ret = drm_intel_fake_bo_map_locked(bo, write_enable); + pthread_mutex_unlock(&bufmgr_fake->lock); + + return ret; +} + +static int + drm_intel_fake_bo_unmap_locked(drm_intel_bo *bo) +{ + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + + /* Static buffers are always mapped. */ + if (bo_fake->is_static) + return 0; + + assert(bo_fake->map_count != 0); + if (--bo_fake->map_count != 0) + return 0; + + DBG("drm_bo_unmap: (buf %d: %s, %lu kb)\n", bo_fake->id, bo_fake->name, + bo_fake->bo.size / 1024); + + bo->virtual = NULL; + + return 0; +} + +static int drm_intel_fake_bo_unmap(drm_intel_bo *bo) +{ + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + int ret; + + pthread_mutex_lock(&bufmgr_fake->lock); + ret = drm_intel_fake_bo_unmap_locked(bo); + pthread_mutex_unlock(&bufmgr_fake->lock); + + return ret; +} + +static int +drm_intel_fake_bo_subdata(drm_intel_bo *bo, unsigned long offset, + unsigned long size, const void *data) +{ + int ret; + + if (size == 0 || data == NULL) + return 0; + + ret = drm_intel_bo_map(bo, 1); + if (ret) + return ret; + memcpy((unsigned char *)bo->virtual + offset, data, size); + drm_intel_bo_unmap(bo); + return 0; +} + +static void + drm_intel_fake_kick_all_locked(drm_intel_bufmgr_fake *bufmgr_fake) +{ + struct block *block, *tmp; + + bufmgr_fake->performed_rendering = 0; + /* okay for ever BO that is on the HW kick it off. + seriously not afraid of the POLICE right now */ + DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->on_hardware) { + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) block->bo; + + block->on_hardware = 0; + free_block(bufmgr_fake, block, 0); + bo_fake->block = NULL; + bo_fake->validated = 0; + if (!(bo_fake->flags & BM_NO_BACKING_STORE)) + bo_fake->dirty = 1; + } + +} + +static int + drm_intel_fake_bo_validate(drm_intel_bo *bo) +{ + drm_intel_bufmgr_fake *bufmgr_fake; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + + bufmgr_fake = (drm_intel_bufmgr_fake *) bo->bufmgr; + + DBG("drm_bo_validate: (buf %d: %s, %lu kb)\n", bo_fake->id, + bo_fake->name, bo_fake->bo.size / 1024); + + /* Sanity check: Buffers should be unmapped before being validated. + * This is not so much of a problem for bufmgr_fake, but TTM refuses, + * and the problem is harder to debug there. + */ + assert(bo_fake->map_count == 0); + + if (bo_fake->is_static) { + /* Add it to the needs-fence list */ + bufmgr_fake->need_fence = 1; + return 0; + } + + /* Allocate the card memory */ + if (!bo_fake->block && !evict_and_alloc_block(bo)) { + bufmgr_fake->fail = 1; + DBG("Failed to validate buf %d:%s\n", bo_fake->id, + bo_fake->name); + return -1; + } + + assert(bo_fake->block); + assert(bo_fake->block->bo == &bo_fake->bo); + + bo->offset = bo_fake->block->mem->ofs; + + /* Upload the buffer contents if necessary */ + if (bo_fake->dirty) { + DBG("Upload dirty buf %d:%s, sz %lu offset 0x%x\n", bo_fake->id, + bo_fake->name, bo->size, bo_fake->block->mem->ofs); + + assert(!(bo_fake->flags & (BM_NO_BACKING_STORE | BM_PINNED))); + + /* Actually, should be able to just wait for a fence on the + * memory, which we would be tracking when we free it. Waiting + * for idle is a sufficiently large hammer for now. + */ + drm_intel_bufmgr_fake_wait_idle(bufmgr_fake); + + /* we may never have mapped this BO so it might not have any + * backing store if this happens it should be rare, but 0 the + * card memory in any case */ + if (bo_fake->backing_store) + memcpy(bo_fake->block->virtual, bo_fake->backing_store, + bo->size); + else + memset(bo_fake->block->virtual, 0, bo->size); + + bo_fake->dirty = 0; + } + + bo_fake->block->fenced = 0; + bo_fake->block->on_hardware = 1; + DRMLISTDEL(bo_fake->block); + DRMLISTADDTAIL(bo_fake->block, &bufmgr_fake->on_hardware); + + bo_fake->validated = 1; + bufmgr_fake->need_fence = 1; + + return 0; +} + +static void +drm_intel_fake_fence_validated(drm_intel_bufmgr *bufmgr) +{ + drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr; + unsigned int cookie; + + cookie = _fence_emit_internal(bufmgr_fake); + fence_blocks(bufmgr_fake, cookie); + + DBG("drm_fence_validated: 0x%08x cookie\n", cookie); +} + +static void +drm_intel_fake_destroy(drm_intel_bufmgr *bufmgr) +{ + drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr; + + pthread_mutex_destroy(&bufmgr_fake->lock); + mmDestroy(bufmgr_fake->heap); + free(bufmgr); +} + +static int +drm_intel_fake_emit_reloc(drm_intel_bo *bo, uint32_t offset, + drm_intel_bo *target_bo, uint32_t target_offset, + uint32_t read_domains, uint32_t write_domain) +{ + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + struct fake_buffer_reloc *r; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + drm_intel_bo_fake *target_fake = (drm_intel_bo_fake *) target_bo; + int i; + + pthread_mutex_lock(&bufmgr_fake->lock); + + assert(bo); + assert(target_bo); + + if (bo_fake->relocs == NULL) { + bo_fake->relocs = + malloc(sizeof(struct fake_buffer_reloc) * MAX_RELOCS); + } + + r = &bo_fake->relocs[bo_fake->nr_relocs++]; + + assert(bo_fake->nr_relocs <= MAX_RELOCS); + + drm_intel_fake_bo_reference_locked(target_bo); + + if (!target_fake->is_static) { + bo_fake->child_size += + ALIGN(target_bo->size, target_fake->alignment); + bo_fake->child_size += target_fake->child_size; + } + r->target_buf = target_bo; + r->offset = offset; + r->last_target_offset = target_bo->offset; + r->delta = target_offset; + r->read_domains = read_domains; + r->write_domain = write_domain; + + if (bufmgr_fake->debug) { + /* Check that a conflicting relocation hasn't already been + * emitted. + */ + for (i = 0; i < bo_fake->nr_relocs - 1; i++) { + struct fake_buffer_reloc *r2 = &bo_fake->relocs[i]; + + assert(r->offset != r2->offset); + } + } + + pthread_mutex_unlock(&bufmgr_fake->lock); + + return 0; +} + +/** + * Incorporates the validation flags associated with each relocation into + * the combined validation flags for the buffer on this batchbuffer submission. + */ +static void +drm_intel_fake_calculate_domains(drm_intel_bo *bo) +{ + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + int i; + + for (i = 0; i < bo_fake->nr_relocs; i++) { + struct fake_buffer_reloc *r = &bo_fake->relocs[i]; + drm_intel_bo_fake *target_fake = + (drm_intel_bo_fake *) r->target_buf; + + /* Do the same for the tree of buffers we depend on */ + drm_intel_fake_calculate_domains(r->target_buf); + + target_fake->read_domains |= r->read_domains; + target_fake->write_domain |= r->write_domain; + } +} + +static int +drm_intel_fake_reloc_and_validate_buffer(drm_intel_bo *bo) +{ + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + int i, ret; + + assert(bo_fake->map_count == 0); + + for (i = 0; i < bo_fake->nr_relocs; i++) { + struct fake_buffer_reloc *r = &bo_fake->relocs[i]; + drm_intel_bo_fake *target_fake = + (drm_intel_bo_fake *) r->target_buf; + uint32_t reloc_data; + + /* Validate the target buffer if that hasn't been done. */ + if (!target_fake->validated) { + ret = + drm_intel_fake_reloc_and_validate_buffer(r->target_buf); + if (ret != 0) { + if (bo->virtual != NULL) + drm_intel_fake_bo_unmap_locked(bo); + return ret; + } + } + + /* Calculate the value of the relocation entry. */ + if (r->target_buf->offset != r->last_target_offset) { + reloc_data = r->target_buf->offset + r->delta; + + if (bo->virtual == NULL) + drm_intel_fake_bo_map_locked(bo, 1); + + *(uint32_t *) ((uint8_t *) bo->virtual + r->offset) = + reloc_data; + + r->last_target_offset = r->target_buf->offset; + } + } + + if (bo->virtual != NULL) + drm_intel_fake_bo_unmap_locked(bo); + + if (bo_fake->write_domain != 0) { + if (!(bo_fake->flags & (BM_NO_BACKING_STORE | BM_PINNED))) { + if (bo_fake->backing_store == 0) + alloc_backing_store(bo); + } + bo_fake->card_dirty = 1; + bufmgr_fake->performed_rendering = 1; + } + + return drm_intel_fake_bo_validate(bo); +} + +static void +drm_intel_bo_fake_post_submit(drm_intel_bo *bo) +{ + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + int i; + + for (i = 0; i < bo_fake->nr_relocs; i++) { + struct fake_buffer_reloc *r = &bo_fake->relocs[i]; + drm_intel_bo_fake *target_fake = + (drm_intel_bo_fake *) r->target_buf; + + if (target_fake->validated) + drm_intel_bo_fake_post_submit(r->target_buf); + + DBG("%s@0x%08x + 0x%08x -> %s@0x%08x + 0x%08x\n", + bo_fake->name, (uint32_t) bo->offset, r->offset, + target_fake->name, (uint32_t) r->target_buf->offset, + r->delta); + } + + assert(bo_fake->map_count == 0); + bo_fake->validated = 0; + bo_fake->read_domains = 0; + bo_fake->write_domain = 0; +} + +drm_public void +drm_intel_bufmgr_fake_set_exec_callback(drm_intel_bufmgr *bufmgr, + int (*exec) (drm_intel_bo *bo, + unsigned int used, + void *priv), + void *priv) +{ + drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr; + + bufmgr_fake->exec = exec; + bufmgr_fake->exec_priv = priv; +} + +static int +drm_intel_fake_bo_exec(drm_intel_bo *bo, int used, + drm_clip_rect_t * cliprects, int num_cliprects, int DR4) +{ + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + drm_intel_bo_fake *batch_fake = (drm_intel_bo_fake *) bo; + struct drm_i915_batchbuffer batch; + int ret; + int retry_count = 0; + + pthread_mutex_lock(&bufmgr_fake->lock); + + bufmgr_fake->performed_rendering = 0; + + drm_intel_fake_calculate_domains(bo); + + batch_fake->read_domains = I915_GEM_DOMAIN_COMMAND; + + /* we've ran out of RAM so blow the whole lot away and retry */ +restart: + ret = drm_intel_fake_reloc_and_validate_buffer(bo); + if (bufmgr_fake->fail == 1) { + if (retry_count == 0) { + retry_count++; + drm_intel_fake_kick_all_locked(bufmgr_fake); + bufmgr_fake->fail = 0; + goto restart; + } else /* dump out the memory here */ + mmDumpMemInfo(bufmgr_fake->heap); + } + + assert(ret == 0); + + if (bufmgr_fake->exec != NULL) { + ret = bufmgr_fake->exec(bo, used, bufmgr_fake->exec_priv); + if (ret != 0) { + pthread_mutex_unlock(&bufmgr_fake->lock); + return ret; + } + } else { + batch.start = bo->offset; + batch.used = used; + batch.cliprects = cliprects; + batch.num_cliprects = num_cliprects; + batch.DR1 = 0; + batch.DR4 = DR4; + + if (drmCommandWrite + (bufmgr_fake->fd, DRM_I915_BATCHBUFFER, &batch, + sizeof(batch))) { + drmMsg("DRM_I915_BATCHBUFFER: %d\n", -errno); + pthread_mutex_unlock(&bufmgr_fake->lock); + return -errno; + } + } + + drm_intel_fake_fence_validated(bo->bufmgr); + + drm_intel_bo_fake_post_submit(bo); + + pthread_mutex_unlock(&bufmgr_fake->lock); + + return 0; +} + +/** + * Return an error if the list of BOs will exceed the aperture size. + * + * This is a rough guess and likely to fail, as during the validate sequence we + * may place a buffer in an inopportune spot early on and then fail to fit + * a set smaller than the aperture. + */ +static int +drm_intel_fake_check_aperture_space(drm_intel_bo ** bo_array, int count) +{ + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo_array[0]->bufmgr; + unsigned int sz = 0; + int i; + + for (i = 0; i < count; i++) { + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo_array[i]; + + if (bo_fake == NULL) + continue; + + if (!bo_fake->is_static) + sz += ALIGN(bo_array[i]->size, bo_fake->alignment); + sz += bo_fake->child_size; + } + + if (sz > bufmgr_fake->size) { + DBG("check_space: overflowed bufmgr size, %ukb vs %lukb\n", + sz / 1024, bufmgr_fake->size / 1024); + return -1; + } + + DBG("drm_check_space: sz %ukb vs bufgr %lukb\n", sz / 1024, + bufmgr_fake->size / 1024); + return 0; +} + +/** + * Evicts all buffers, waiting for fences to pass and copying contents out + * as necessary. + * + * Used by the X Server on LeaveVT, when the card memory is no longer our + * own. + */ +drm_public void +drm_intel_bufmgr_fake_evict_all(drm_intel_bufmgr *bufmgr) +{ + drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr; + struct block *block, *tmp; + + pthread_mutex_lock(&bufmgr_fake->lock); + + bufmgr_fake->need_fence = 1; + bufmgr_fake->fail = 0; + + /* Wait for hardware idle. We don't know where acceleration has been + * happening, so we'll need to wait anyway before letting anything get + * put on the card again. + */ + drm_intel_bufmgr_fake_wait_idle(bufmgr_fake); + + /* Check that we hadn't released the lock without having fenced the last + * set of buffers. + */ + assert(DRMLISTEMPTY(&bufmgr_fake->fenced)); + assert(DRMLISTEMPTY(&bufmgr_fake->on_hardware)); + + DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->lru) { + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) block->bo; + /* Releases the memory, and memcpys dirty contents out if + * necessary. + */ + free_block(bufmgr_fake, block, 0); + bo_fake->block = NULL; + } + + pthread_mutex_unlock(&bufmgr_fake->lock); +} + +drm_public void +drm_intel_bufmgr_fake_set_last_dispatch(drm_intel_bufmgr *bufmgr, + volatile unsigned int + *last_dispatch) +{ + drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr; + + bufmgr_fake->last_dispatch = (volatile int *)last_dispatch; +} + +drm_public drm_intel_bufmgr * +drm_intel_bufmgr_fake_init(int fd, unsigned long low_offset, + void *low_virtual, unsigned long size, + volatile unsigned int *last_dispatch) +{ + drm_intel_bufmgr_fake *bufmgr_fake; + + bufmgr_fake = calloc(1, sizeof(*bufmgr_fake)); + + if (pthread_mutex_init(&bufmgr_fake->lock, NULL) != 0) { + free(bufmgr_fake); + return NULL; + } + + /* Initialize allocator */ + DRMINITLISTHEAD(&bufmgr_fake->fenced); + DRMINITLISTHEAD(&bufmgr_fake->on_hardware); + DRMINITLISTHEAD(&bufmgr_fake->lru); + + bufmgr_fake->low_offset = low_offset; + bufmgr_fake->virtual = low_virtual; + bufmgr_fake->size = size; + bufmgr_fake->heap = mmInit(low_offset, size); + + /* Hook in methods */ + bufmgr_fake->bufmgr.bo_alloc = drm_intel_fake_bo_alloc; + bufmgr_fake->bufmgr.bo_alloc_for_render = drm_intel_fake_bo_alloc; + bufmgr_fake->bufmgr.bo_alloc_tiled = drm_intel_fake_bo_alloc_tiled; + bufmgr_fake->bufmgr.bo_reference = drm_intel_fake_bo_reference; + bufmgr_fake->bufmgr.bo_unreference = drm_intel_fake_bo_unreference; + bufmgr_fake->bufmgr.bo_map = drm_intel_fake_bo_map; + bufmgr_fake->bufmgr.bo_unmap = drm_intel_fake_bo_unmap; + bufmgr_fake->bufmgr.bo_subdata = drm_intel_fake_bo_subdata; + bufmgr_fake->bufmgr.bo_wait_rendering = + drm_intel_fake_bo_wait_rendering; + bufmgr_fake->bufmgr.bo_emit_reloc = drm_intel_fake_emit_reloc; + bufmgr_fake->bufmgr.destroy = drm_intel_fake_destroy; + bufmgr_fake->bufmgr.bo_exec = drm_intel_fake_bo_exec; + bufmgr_fake->bufmgr.check_aperture_space = + drm_intel_fake_check_aperture_space; + bufmgr_fake->bufmgr.debug = 0; + + bufmgr_fake->fd = fd; + bufmgr_fake->last_dispatch = (volatile int *)last_dispatch; + + return &bufmgr_fake->bufmgr; +} diff --git a/intel/intel_bufmgr_gem.c b/intel/intel_bufmgr_gem.c new file mode 100644 index 0000000..78eb88a --- /dev/null +++ b/intel/intel_bufmgr_gem.c @@ -0,0 +1,3748 @@ +/************************************************************************** + * + * Copyright © 2007 Red Hat Inc. + * Copyright © 2007-2012 Intel Corporation + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA + * 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 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 + * THE COPYRIGHT HOLDERS, AUTHORS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ +/* + * Authors: Thomas Hellström + * Keith Whitwell + * Eric Anholt + * Dave Airlie + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "errno.h" +#ifndef ETIME +#define ETIME ETIMEDOUT +#endif +#include "libdrm_macros.h" +#include "libdrm_lists.h" +#include "intel_bufmgr.h" +#include "intel_bufmgr_priv.h" +#include "intel_chipset.h" +#include "string.h" + +#include "i915_drm.h" +#include "uthash.h" + +#if HAVE_VALGRIND +#include +#include +#define VG(x) x +#else +#define VG(x) +#endif + +#define memclear(s) memset(&s, 0, sizeof(s)) + +#define DBG(...) do { \ + if (bufmgr_gem->bufmgr.debug) \ + fprintf(stderr, __VA_ARGS__); \ +} while (0) + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#define MAX2(A, B) ((A) > (B) ? (A) : (B)) + +/** + * upper_32_bits - return bits 32-63 of a number + * @n: the number we're accessing + * + * A basic shift-right of a 64- or 32-bit quantity. Use this to suppress + * the "right shift count >= width of type" warning when that quantity is + * 32-bits. + */ +#define upper_32_bits(n) ((__u32)(((n) >> 16) >> 16)) + +/** + * lower_32_bits - return bits 0-31 of a number + * @n: the number we're accessing + */ +#define lower_32_bits(n) ((__u32)(n)) + +typedef struct _drm_intel_bo_gem drm_intel_bo_gem; + +struct drm_intel_gem_bo_bucket { + drmMMListHead head; + unsigned long size; +}; + +typedef struct _drm_intel_bufmgr_gem { + drm_intel_bufmgr bufmgr; + + atomic_t refcount; + + int fd; + + int max_relocs; + + pthread_mutex_t lock; + + struct drm_i915_gem_exec_object2 *exec2_objects; + drm_intel_bo **exec_bos; + int exec_size; + int exec_count; + + /** Array of lists of cached gem objects of power-of-two sizes */ + struct drm_intel_gem_bo_bucket cache_bucket[14 * 4]; + int num_buckets; + time_t time; + + drmMMListHead managers; + + drm_intel_bo_gem *name_table; + drm_intel_bo_gem *handle_table; + + drmMMListHead vma_cache; + int vma_count, vma_open, vma_max; + + uint64_t gtt_size; + int available_fences; + int pci_device; + int gen; + unsigned int has_bsd : 1; + unsigned int has_blt : 1; + unsigned int has_relaxed_fencing : 1; + unsigned int has_llc : 1; + unsigned int has_wait_timeout : 1; + unsigned int bo_reuse : 1; + unsigned int no_exec : 1; + unsigned int has_vebox : 1; + unsigned int has_exec_async : 1; + bool fenced_relocs; + + struct { + void *ptr; + uint32_t handle; + } userptr_active; + +} drm_intel_bufmgr_gem; + +#define DRM_INTEL_RELOC_FENCE (1<<0) + +typedef struct _drm_intel_reloc_target_info { + drm_intel_bo *bo; + int flags; +} drm_intel_reloc_target; + +struct _drm_intel_bo_gem { + drm_intel_bo bo; + + atomic_t refcount; + uint32_t gem_handle; + const char *name; + + /** + * Kenel-assigned global name for this object + * + * List contains both flink named and prime fd'd objects + */ + unsigned int global_name; + + UT_hash_handle handle_hh; + UT_hash_handle name_hh; + + /** + * Index of the buffer within the validation list while preparing a + * batchbuffer execution. + */ + int validate_index; + + /** + * Current tiling mode + */ + uint32_t tiling_mode; + uint32_t swizzle_mode; + unsigned long stride; + + unsigned long kflags; + + time_t free_time; + + /** Array passed to the DRM containing relocation information. */ + struct drm_i915_gem_relocation_entry *relocs; + /** + * Array of info structs corresponding to relocs[i].target_handle etc + */ + drm_intel_reloc_target *reloc_target_info; + /** Number of entries in relocs */ + int reloc_count; + /** Array of BOs that are referenced by this buffer and will be softpinned */ + drm_intel_bo **softpin_target; + /** Number softpinned BOs that are referenced by this buffer */ + int softpin_target_count; + /** Maximum amount of softpinned BOs that are referenced by this buffer */ + int softpin_target_size; + + /** Mapped address for the buffer, saved across map/unmap cycles */ + void *mem_virtual; + /** GTT virtual address for the buffer, saved across map/unmap cycles */ + void *gtt_virtual; + /** WC CPU address for the buffer, saved across map/unmap cycles */ + void *wc_virtual; + /** + * Virtual address of the buffer allocated by user, used for userptr + * objects only. + */ + void *user_virtual; + int map_count; + drmMMListHead vma_list; + + /** BO cache list */ + drmMMListHead head; + + /** + * Boolean of whether this BO and its children have been included in + * the current drm_intel_bufmgr_check_aperture_space() total. + */ + bool included_in_check_aperture; + + /** + * Boolean of whether this buffer has been used as a relocation + * target and had its size accounted for, and thus can't have any + * further relocations added to it. + */ + bool used_as_reloc_target; + + /** + * Boolean of whether we have encountered an error whilst building the relocation tree. + */ + bool has_error; + + /** + * Boolean of whether this buffer can be re-used + */ + bool reusable; + + /** + * Boolean of whether the GPU is definitely not accessing the buffer. + * + * This is only valid when reusable, since non-reusable + * buffers are those that have been shared with other + * processes, so we don't know their state. + */ + bool idle; + + /** + * Boolean of whether this buffer was allocated with userptr + */ + bool is_userptr; + + /** + * Size in bytes of this buffer and its relocation descendents. + * + * Used to avoid costly tree walking in + * drm_intel_bufmgr_check_aperture in the common case. + */ + int reloc_tree_size; + + /** + * Number of potential fence registers required by this buffer and its + * relocations. + */ + int reloc_tree_fences; + + /** Flags that we may need to do the SW_FINISH ioctl on unmap. */ + bool mapped_cpu_write; +}; + +static unsigned int +drm_intel_gem_estimate_batch_space(drm_intel_bo ** bo_array, int count); + +static unsigned int +drm_intel_gem_compute_batch_space(drm_intel_bo ** bo_array, int count); + +static int +drm_intel_gem_bo_get_tiling(drm_intel_bo *bo, uint32_t * tiling_mode, + uint32_t * swizzle_mode); + +static int +drm_intel_gem_bo_set_tiling_internal(drm_intel_bo *bo, + uint32_t tiling_mode, + uint32_t stride); + +static void drm_intel_gem_bo_unreference_locked_timed(drm_intel_bo *bo, + time_t time); + +static void drm_intel_gem_bo_unreference(drm_intel_bo *bo); + +static void drm_intel_gem_bo_free(drm_intel_bo *bo); + +static inline drm_intel_bo_gem *to_bo_gem(drm_intel_bo *bo) +{ + return (drm_intel_bo_gem *)bo; +} + +static unsigned long +drm_intel_gem_bo_tile_size(drm_intel_bufmgr_gem *bufmgr_gem, unsigned long size, + uint32_t *tiling_mode) +{ + unsigned long min_size, max_size; + unsigned long i; + + if (*tiling_mode == I915_TILING_NONE) + return size; + + /* 965+ just need multiples of page size for tiling */ + if (bufmgr_gem->gen >= 4) + return ROUND_UP_TO(size, 4096); + + /* Older chips need powers of two, of at least 512k or 1M */ + if (bufmgr_gem->gen == 3) { + min_size = 1024*1024; + max_size = 128*1024*1024; + } else { + min_size = 512*1024; + max_size = 64*1024*1024; + } + + if (size > max_size) { + *tiling_mode = I915_TILING_NONE; + return size; + } + + /* Do we need to allocate every page for the fence? */ + if (bufmgr_gem->has_relaxed_fencing) + return ROUND_UP_TO(size, 4096); + + for (i = min_size; i < size; i <<= 1) + ; + + return i; +} + +/* + * Round a given pitch up to the minimum required for X tiling on a + * given chip. We use 512 as the minimum to allow for a later tiling + * change. + */ +static unsigned long +drm_intel_gem_bo_tile_pitch(drm_intel_bufmgr_gem *bufmgr_gem, + unsigned long pitch, uint32_t *tiling_mode) +{ + unsigned long tile_width; + unsigned long i; + + /* If untiled, then just align it so that we can do rendering + * to it with the 3D engine. + */ + if (*tiling_mode == I915_TILING_NONE) + return ALIGN(pitch, 64); + + if (*tiling_mode == I915_TILING_X + || (IS_915(bufmgr_gem->pci_device) + && *tiling_mode == I915_TILING_Y)) + tile_width = 512; + else + tile_width = 128; + + /* 965 is flexible */ + if (bufmgr_gem->gen >= 4) + return ROUND_UP_TO(pitch, tile_width); + + /* The older hardware has a maximum pitch of 8192 with tiled + * surfaces, so fallback to untiled if it's too large. + */ + if (pitch > 8192) { + *tiling_mode = I915_TILING_NONE; + return ALIGN(pitch, 64); + } + + /* Pre-965 needs power of two tile width */ + for (i = tile_width; i < pitch; i <<= 1) + ; + + return i; +} + +static struct drm_intel_gem_bo_bucket * +drm_intel_gem_bo_bucket_for_size(drm_intel_bufmgr_gem *bufmgr_gem, + unsigned long size) +{ + int i; + + for (i = 0; i < bufmgr_gem->num_buckets; i++) { + struct drm_intel_gem_bo_bucket *bucket = + &bufmgr_gem->cache_bucket[i]; + if (bucket->size >= size) { + return bucket; + } + } + + return NULL; +} + +static void +drm_intel_gem_dump_validation_list(drm_intel_bufmgr_gem *bufmgr_gem) +{ + int i, j; + + for (i = 0; i < bufmgr_gem->exec_count; i++) { + drm_intel_bo *bo = bufmgr_gem->exec_bos[i]; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + + if (bo_gem->relocs == NULL && bo_gem->softpin_target == NULL) { + DBG("%2d: %d %s(%s)\n", i, bo_gem->gem_handle, + bo_gem->kflags & EXEC_OBJECT_PINNED ? "*" : "", + bo_gem->name); + continue; + } + + for (j = 0; j < bo_gem->reloc_count; j++) { + drm_intel_bo *target_bo = bo_gem->reloc_target_info[j].bo; + drm_intel_bo_gem *target_gem = + (drm_intel_bo_gem *) target_bo; + + DBG("%2d: %d %s(%s)@0x%08x %08x -> " + "%d (%s)@0x%08x %08x + 0x%08x\n", + i, + bo_gem->gem_handle, + bo_gem->kflags & EXEC_OBJECT_PINNED ? "*" : "", + bo_gem->name, + upper_32_bits(bo_gem->relocs[j].offset), + lower_32_bits(bo_gem->relocs[j].offset), + target_gem->gem_handle, + target_gem->name, + upper_32_bits(target_bo->offset64), + lower_32_bits(target_bo->offset64), + bo_gem->relocs[j].delta); + } + + for (j = 0; j < bo_gem->softpin_target_count; j++) { + drm_intel_bo *target_bo = bo_gem->softpin_target[j]; + drm_intel_bo_gem *target_gem = + (drm_intel_bo_gem *) target_bo; + DBG("%2d: %d %s(%s) -> " + "%d *(%s)@0x%08x %08x\n", + i, + bo_gem->gem_handle, + bo_gem->kflags & EXEC_OBJECT_PINNED ? "*" : "", + bo_gem->name, + target_gem->gem_handle, + target_gem->name, + upper_32_bits(target_bo->offset64), + lower_32_bits(target_bo->offset64)); + } + } +} + +static inline void +drm_intel_gem_bo_reference(drm_intel_bo *bo) +{ + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + + atomic_inc(&bo_gem->refcount); +} + +/** + * Adds the given buffer to the list of buffers to be validated (moved into the + * appropriate memory type) with the next batch submission. + * + * If a buffer is validated multiple times in a batch submission, it ends up + * with the intersection of the memory type flags and the union of the + * access flags. + */ +static void +drm_intel_add_validate_buffer2(drm_intel_bo *bo, int need_fence) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo; + int index; + unsigned long flags; + + flags = 0; + if (need_fence) + flags |= EXEC_OBJECT_NEEDS_FENCE; + + if (bo_gem->validate_index != -1) { + bufmgr_gem->exec2_objects[bo_gem->validate_index].flags |= flags; + return; + } + + /* Extend the array of validation entries as necessary. */ + if (bufmgr_gem->exec_count == bufmgr_gem->exec_size) { + int new_size = bufmgr_gem->exec_size * 2; + + if (new_size == 0) + new_size = 5; + + bufmgr_gem->exec2_objects = + realloc(bufmgr_gem->exec2_objects, + sizeof(*bufmgr_gem->exec2_objects) * new_size); + bufmgr_gem->exec_bos = + realloc(bufmgr_gem->exec_bos, + sizeof(*bufmgr_gem->exec_bos) * new_size); + bufmgr_gem->exec_size = new_size; + } + + index = bufmgr_gem->exec_count; + bo_gem->validate_index = index; + /* Fill in array entry */ + bufmgr_gem->exec2_objects[index].handle = bo_gem->gem_handle; + bufmgr_gem->exec2_objects[index].relocation_count = bo_gem->reloc_count; + bufmgr_gem->exec2_objects[index].relocs_ptr = (uintptr_t)bo_gem->relocs; + bufmgr_gem->exec2_objects[index].alignment = bo->align; + bufmgr_gem->exec2_objects[index].offset = bo->offset64; + bufmgr_gem->exec2_objects[index].flags = bo_gem->kflags | flags; + bufmgr_gem->exec2_objects[index].rsvd1 = 0; + bufmgr_gem->exec2_objects[index].rsvd2 = 0; + bufmgr_gem->exec_bos[index] = bo; + bufmgr_gem->exec_count++; +} + +#define RELOC_BUF_SIZE(x) ((I915_RELOC_HEADER + x * I915_RELOC0_STRIDE) * \ + sizeof(uint32_t)) + +static void +drm_intel_bo_gem_set_in_aperture_size(drm_intel_bufmgr_gem *bufmgr_gem, + drm_intel_bo_gem *bo_gem, + unsigned int alignment) +{ + unsigned int size; + + assert(!bo_gem->used_as_reloc_target); + + /* The older chipsets are far-less flexible in terms of tiling, + * and require tiled buffer to be size aligned in the aperture. + * This means that in the worst possible case we will need a hole + * twice as large as the object in order for it to fit into the + * aperture. Optimal packing is for wimps. + */ + size = bo_gem->bo.size; + if (bufmgr_gem->gen < 4 && bo_gem->tiling_mode != I915_TILING_NONE) { + unsigned int min_size; + + if (bufmgr_gem->has_relaxed_fencing) { + if (bufmgr_gem->gen == 3) + min_size = 1024*1024; + else + min_size = 512*1024; + + while (min_size < size) + min_size *= 2; + } else + min_size = size; + + /* Account for worst-case alignment. */ + alignment = MAX2(alignment, min_size); + } + + bo_gem->reloc_tree_size = size + alignment; +} + +static int +drm_intel_setup_reloc_list(drm_intel_bo *bo) +{ + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + unsigned int max_relocs = bufmgr_gem->max_relocs; + + if (bo->size / 4 < max_relocs) + max_relocs = bo->size / 4; + + bo_gem->relocs = malloc(max_relocs * + sizeof(struct drm_i915_gem_relocation_entry)); + bo_gem->reloc_target_info = malloc(max_relocs * + sizeof(drm_intel_reloc_target)); + if (bo_gem->relocs == NULL || bo_gem->reloc_target_info == NULL) { + bo_gem->has_error = true; + + free (bo_gem->relocs); + bo_gem->relocs = NULL; + + free (bo_gem->reloc_target_info); + bo_gem->reloc_target_info = NULL; + + return 1; + } + + return 0; +} + +static int +drm_intel_gem_bo_busy(drm_intel_bo *bo) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + struct drm_i915_gem_busy busy; + int ret; + + if (bo_gem->reusable && bo_gem->idle) + return false; + + memclear(busy); + busy.handle = bo_gem->gem_handle; + + ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_BUSY, &busy); + if (ret == 0) { + bo_gem->idle = !busy.busy; + return busy.busy; + } else { + return false; + } +} + +static int +drm_intel_gem_bo_madvise_internal(drm_intel_bufmgr_gem *bufmgr_gem, + drm_intel_bo_gem *bo_gem, int state) +{ + struct drm_i915_gem_madvise madv; + + memclear(madv); + madv.handle = bo_gem->gem_handle; + madv.madv = state; + madv.retained = 1; + drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_MADVISE, &madv); + + return madv.retained; +} + +static int +drm_intel_gem_bo_madvise(drm_intel_bo *bo, int madv) +{ + return drm_intel_gem_bo_madvise_internal + ((drm_intel_bufmgr_gem *) bo->bufmgr, + (drm_intel_bo_gem *) bo, + madv); +} + +/* drop the oldest entries that have been purged by the kernel */ +static void +drm_intel_gem_bo_cache_purge_bucket(drm_intel_bufmgr_gem *bufmgr_gem, + struct drm_intel_gem_bo_bucket *bucket) +{ + while (!DRMLISTEMPTY(&bucket->head)) { + drm_intel_bo_gem *bo_gem; + + bo_gem = DRMLISTENTRY(drm_intel_bo_gem, + bucket->head.next, head); + if (drm_intel_gem_bo_madvise_internal + (bufmgr_gem, bo_gem, I915_MADV_DONTNEED)) + break; + + DRMLISTDEL(&bo_gem->head); + drm_intel_gem_bo_free(&bo_gem->bo); + } +} + +static drm_intel_bo * +drm_intel_gem_bo_alloc_internal(drm_intel_bufmgr *bufmgr, + const char *name, + unsigned long size, + unsigned long flags, + uint32_t tiling_mode, + unsigned long stride, + unsigned int alignment) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr; + drm_intel_bo_gem *bo_gem; + unsigned int page_size = getpagesize(); + int ret; + struct drm_intel_gem_bo_bucket *bucket; + bool alloc_from_cache; + unsigned long bo_size; + bool for_render = false; + + if (flags & BO_ALLOC_FOR_RENDER) + for_render = true; + + /* Round the allocated size up to a power of two number of pages. */ + bucket = drm_intel_gem_bo_bucket_for_size(bufmgr_gem, size); + + /* If we don't have caching at this size, don't actually round the + * allocation up. + */ + if (bucket == NULL) { + bo_size = size; + if (bo_size < page_size) + bo_size = page_size; + } else { + bo_size = bucket->size; + } + + pthread_mutex_lock(&bufmgr_gem->lock); + /* Get a buffer out of the cache if available */ +retry: + alloc_from_cache = false; + if (bucket != NULL && !DRMLISTEMPTY(&bucket->head)) { + if (for_render) { + /* Allocate new render-target BOs from the tail (MRU) + * of the list, as it will likely be hot in the GPU + * cache and in the aperture for us. + */ + bo_gem = DRMLISTENTRY(drm_intel_bo_gem, + bucket->head.prev, head); + DRMLISTDEL(&bo_gem->head); + alloc_from_cache = true; + bo_gem->bo.align = alignment; + } else { + assert(alignment == 0); + /* For non-render-target BOs (where we're probably + * going to map it first thing in order to fill it + * with data), check if the last BO in the cache is + * unbusy, and only reuse in that case. Otherwise, + * allocating a new buffer is probably faster than + * waiting for the GPU to finish. + */ + bo_gem = DRMLISTENTRY(drm_intel_bo_gem, + bucket->head.next, head); + if (!drm_intel_gem_bo_busy(&bo_gem->bo)) { + alloc_from_cache = true; + DRMLISTDEL(&bo_gem->head); + } + } + + if (alloc_from_cache) { + if (!drm_intel_gem_bo_madvise_internal + (bufmgr_gem, bo_gem, I915_MADV_WILLNEED)) { + drm_intel_gem_bo_free(&bo_gem->bo); + drm_intel_gem_bo_cache_purge_bucket(bufmgr_gem, + bucket); + goto retry; + } + + if (drm_intel_gem_bo_set_tiling_internal(&bo_gem->bo, + tiling_mode, + stride)) { + drm_intel_gem_bo_free(&bo_gem->bo); + goto retry; + } + } + } + + if (!alloc_from_cache) { + struct drm_i915_gem_create create; + + bo_gem = calloc(1, sizeof(*bo_gem)); + if (!bo_gem) + goto err; + + /* drm_intel_gem_bo_free calls DRMLISTDEL() for an uninitialized + list (vma_list), so better set the list head here */ + DRMINITLISTHEAD(&bo_gem->vma_list); + + bo_gem->bo.size = bo_size; + + memclear(create); + create.size = bo_size; + + ret = drmIoctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GEM_CREATE, + &create); + if (ret != 0) { + free(bo_gem); + goto err; + } + + bo_gem->gem_handle = create.handle; + HASH_ADD(handle_hh, bufmgr_gem->handle_table, + gem_handle, sizeof(bo_gem->gem_handle), + bo_gem); + + bo_gem->bo.handle = bo_gem->gem_handle; + bo_gem->bo.bufmgr = bufmgr; + bo_gem->bo.align = alignment; + + bo_gem->tiling_mode = I915_TILING_NONE; + bo_gem->swizzle_mode = I915_BIT_6_SWIZZLE_NONE; + bo_gem->stride = 0; + + if (drm_intel_gem_bo_set_tiling_internal(&bo_gem->bo, + tiling_mode, + stride)) + goto err_free; + } + + bo_gem->name = name; + atomic_set(&bo_gem->refcount, 1); + bo_gem->validate_index = -1; + bo_gem->reloc_tree_fences = 0; + bo_gem->used_as_reloc_target = false; + bo_gem->has_error = false; + bo_gem->reusable = true; + + drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem, alignment); + pthread_mutex_unlock(&bufmgr_gem->lock); + + DBG("bo_create: buf %d (%s) %ldb\n", + bo_gem->gem_handle, bo_gem->name, size); + + return &bo_gem->bo; + +err_free: + drm_intel_gem_bo_free(&bo_gem->bo); +err: + pthread_mutex_unlock(&bufmgr_gem->lock); + return NULL; +} + +static drm_intel_bo * +drm_intel_gem_bo_alloc_for_render(drm_intel_bufmgr *bufmgr, + const char *name, + unsigned long size, + unsigned int alignment) +{ + return drm_intel_gem_bo_alloc_internal(bufmgr, name, size, + BO_ALLOC_FOR_RENDER, + I915_TILING_NONE, 0, + alignment); +} + +static drm_intel_bo * +drm_intel_gem_bo_alloc(drm_intel_bufmgr *bufmgr, + const char *name, + unsigned long size, + unsigned int alignment) +{ + return drm_intel_gem_bo_alloc_internal(bufmgr, name, size, 0, + I915_TILING_NONE, 0, 0); +} + +static drm_intel_bo * +drm_intel_gem_bo_alloc_tiled(drm_intel_bufmgr *bufmgr, const char *name, + int x, int y, int cpp, uint32_t *tiling_mode, + unsigned long *pitch, unsigned long flags) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr; + unsigned long size, stride; + uint32_t tiling; + + do { + unsigned long aligned_y, height_alignment; + + tiling = *tiling_mode; + + /* If we're tiled, our allocations are in 8 or 32-row blocks, + * so failure to align our height means that we won't allocate + * enough pages. + * + * If we're untiled, we still have to align to 2 rows high + * because the data port accesses 2x2 blocks even if the + * bottom row isn't to be rendered, so failure to align means + * we could walk off the end of the GTT and fault. This is + * documented on 965, and may be the case on older chipsets + * too so we try to be careful. + */ + aligned_y = y; + height_alignment = 2; + + if ((bufmgr_gem->gen == 2) && tiling != I915_TILING_NONE) + height_alignment = 16; + else if (tiling == I915_TILING_X + || (IS_915(bufmgr_gem->pci_device) + && tiling == I915_TILING_Y)) + height_alignment = 8; + else if (tiling == I915_TILING_Y) + height_alignment = 32; + aligned_y = ALIGN(y, height_alignment); + + stride = x * cpp; + stride = drm_intel_gem_bo_tile_pitch(bufmgr_gem, stride, tiling_mode); + size = stride * aligned_y; + size = drm_intel_gem_bo_tile_size(bufmgr_gem, size, tiling_mode); + } while (*tiling_mode != tiling); + *pitch = stride; + + if (tiling == I915_TILING_NONE) + stride = 0; + + return drm_intel_gem_bo_alloc_internal(bufmgr, name, size, flags, + tiling, stride, 0); +} + +static drm_intel_bo * +drm_intel_gem_bo_alloc_userptr(drm_intel_bufmgr *bufmgr, + const char *name, + void *addr, + uint32_t tiling_mode, + uint32_t stride, + unsigned long size, + unsigned long flags) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr; + drm_intel_bo_gem *bo_gem; + int ret; + struct drm_i915_gem_userptr userptr; + + /* Tiling with userptr surfaces is not supported + * on all hardware so refuse it for time being. + */ + if (tiling_mode != I915_TILING_NONE) + return NULL; + + bo_gem = calloc(1, sizeof(*bo_gem)); + if (!bo_gem) + return NULL; + + atomic_set(&bo_gem->refcount, 1); + DRMINITLISTHEAD(&bo_gem->vma_list); + + bo_gem->bo.size = size; + + memclear(userptr); + userptr.user_ptr = (__u64)((unsigned long)addr); + userptr.user_size = size; + userptr.flags = flags; + + ret = drmIoctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GEM_USERPTR, + &userptr); + if (ret != 0) { + DBG("bo_create_userptr: " + "ioctl failed with user ptr %p size 0x%lx, " + "user flags 0x%lx\n", addr, size, flags); + free(bo_gem); + return NULL; + } + + pthread_mutex_lock(&bufmgr_gem->lock); + + bo_gem->gem_handle = userptr.handle; + bo_gem->bo.handle = bo_gem->gem_handle; + bo_gem->bo.bufmgr = bufmgr; + bo_gem->is_userptr = true; + bo_gem->bo.virtual = addr; + /* Save the address provided by user */ + bo_gem->user_virtual = addr; + bo_gem->tiling_mode = I915_TILING_NONE; + bo_gem->swizzle_mode = I915_BIT_6_SWIZZLE_NONE; + bo_gem->stride = 0; + + HASH_ADD(handle_hh, bufmgr_gem->handle_table, + gem_handle, sizeof(bo_gem->gem_handle), + bo_gem); + + bo_gem->name = name; + bo_gem->validate_index = -1; + bo_gem->reloc_tree_fences = 0; + bo_gem->used_as_reloc_target = false; + bo_gem->has_error = false; + bo_gem->reusable = false; + + drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem, 0); + pthread_mutex_unlock(&bufmgr_gem->lock); + + DBG("bo_create_userptr: " + "ptr %p buf %d (%s) size %ldb, stride 0x%x, tile mode %d\n", + addr, bo_gem->gem_handle, bo_gem->name, + size, stride, tiling_mode); + + return &bo_gem->bo; +} + +static bool +has_userptr(drm_intel_bufmgr_gem *bufmgr_gem) +{ + int ret; + void *ptr; + long pgsz; + struct drm_i915_gem_userptr userptr; + + pgsz = sysconf(_SC_PAGESIZE); + assert(pgsz > 0); + + ret = posix_memalign(&ptr, pgsz, pgsz); + if (ret) { + DBG("Failed to get a page (%ld) for userptr detection!\n", + pgsz); + return false; + } + + memclear(userptr); + userptr.user_ptr = (__u64)(unsigned long)ptr; + userptr.user_size = pgsz; + +retry: + ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_USERPTR, &userptr); + if (ret) { + if (errno == ENODEV && userptr.flags == 0) { + userptr.flags = I915_USERPTR_UNSYNCHRONIZED; + goto retry; + } + free(ptr); + return false; + } + + /* We don't release the userptr bo here as we want to keep the + * kernel mm tracking alive for our lifetime. The first time we + * create a userptr object the kernel has to install a mmu_notifer + * which is a heavyweight operation (e.g. it requires taking all + * mm_locks and stop_machine()). + */ + + bufmgr_gem->userptr_active.ptr = ptr; + bufmgr_gem->userptr_active.handle = userptr.handle; + + return true; +} + +static drm_intel_bo * +check_bo_alloc_userptr(drm_intel_bufmgr *bufmgr, + const char *name, + void *addr, + uint32_t tiling_mode, + uint32_t stride, + unsigned long size, + unsigned long flags) +{ + if (has_userptr((drm_intel_bufmgr_gem *)bufmgr)) + bufmgr->bo_alloc_userptr = drm_intel_gem_bo_alloc_userptr; + else + bufmgr->bo_alloc_userptr = NULL; + + return drm_intel_bo_alloc_userptr(bufmgr, name, addr, + tiling_mode, stride, size, flags); +} + +static int get_tiling_mode(drm_intel_bufmgr_gem *bufmgr_gem, + uint32_t gem_handle, + uint32_t *tiling_mode, + uint32_t *swizzle_mode) +{ + struct drm_i915_gem_get_tiling get_tiling = { + .handle = gem_handle, + }; + int ret; + + ret = drmIoctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GEM_GET_TILING, + &get_tiling); + if (ret != 0 && errno != EOPNOTSUPP) + return ret; + + *tiling_mode = get_tiling.tiling_mode; + *swizzle_mode = get_tiling.swizzle_mode; + + return 0; +} + +/** + * Returns a drm_intel_bo wrapping the given buffer object handle. + * + * This can be used when one application needs to pass a buffer object + * to another. + */ +drm_public drm_intel_bo * +drm_intel_bo_gem_create_from_name(drm_intel_bufmgr *bufmgr, + const char *name, + unsigned int handle) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr; + drm_intel_bo_gem *bo_gem; + int ret; + struct drm_gem_open open_arg; + + /* At the moment most applications only have a few named bo. + * For instance, in a DRI client only the render buffers passed + * between X and the client are named. And since X returns the + * alternating names for the front/back buffer a linear search + * provides a sufficiently fast match. + */ + pthread_mutex_lock(&bufmgr_gem->lock); + HASH_FIND(name_hh, bufmgr_gem->name_table, + &handle, sizeof(handle), bo_gem); + if (bo_gem) { + drm_intel_gem_bo_reference(&bo_gem->bo); + goto out; + } + + memclear(open_arg); + open_arg.name = handle; + ret = drmIoctl(bufmgr_gem->fd, + DRM_IOCTL_GEM_OPEN, + &open_arg); + if (ret != 0) { + DBG("Couldn't reference %s handle 0x%08x: %s\n", + name, handle, strerror(errno)); + bo_gem = NULL; + goto out; + } + /* Now see if someone has used a prime handle to get this + * object from the kernel before by looking through the list + * again for a matching gem_handle + */ + HASH_FIND(handle_hh, bufmgr_gem->handle_table, + &open_arg.handle, sizeof(open_arg.handle), bo_gem); + if (bo_gem) { + drm_intel_gem_bo_reference(&bo_gem->bo); + goto out; + } + + bo_gem = calloc(1, sizeof(*bo_gem)); + if (!bo_gem) + goto out; + + atomic_set(&bo_gem->refcount, 1); + DRMINITLISTHEAD(&bo_gem->vma_list); + + bo_gem->bo.size = open_arg.size; + bo_gem->bo.offset = 0; + bo_gem->bo.offset64 = 0; + bo_gem->bo.virtual = NULL; + bo_gem->bo.bufmgr = bufmgr; + bo_gem->name = name; + bo_gem->validate_index = -1; + bo_gem->gem_handle = open_arg.handle; + bo_gem->bo.handle = open_arg.handle; + bo_gem->global_name = handle; + bo_gem->reusable = false; + + HASH_ADD(handle_hh, bufmgr_gem->handle_table, + gem_handle, sizeof(bo_gem->gem_handle), bo_gem); + HASH_ADD(name_hh, bufmgr_gem->name_table, + global_name, sizeof(bo_gem->global_name), bo_gem); + + ret = get_tiling_mode(bufmgr_gem, bo_gem->gem_handle, + &bo_gem->tiling_mode, &bo_gem->swizzle_mode); + if (ret != 0) + goto err_unref; + + /* XXX stride is unknown */ + drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem, 0); + DBG("bo_create_from_handle: %d (%s)\n", handle, bo_gem->name); + +out: + pthread_mutex_unlock(&bufmgr_gem->lock); + return &bo_gem->bo; + +err_unref: + drm_intel_gem_bo_free(&bo_gem->bo); + pthread_mutex_unlock(&bufmgr_gem->lock); + return NULL; +} + +static void +drm_intel_gem_bo_free(drm_intel_bo *bo) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + int ret; + + DRMLISTDEL(&bo_gem->vma_list); + if (bo_gem->mem_virtual) { + VG(VALGRIND_FREELIKE_BLOCK(bo_gem->mem_virtual, 0)); + drm_munmap(bo_gem->mem_virtual, bo_gem->bo.size); + bufmgr_gem->vma_count--; + } + if (bo_gem->wc_virtual) { + VG(VALGRIND_FREELIKE_BLOCK(bo_gem->wc_virtual, 0)); + drm_munmap(bo_gem->wc_virtual, bo_gem->bo.size); + bufmgr_gem->vma_count--; + } + if (bo_gem->gtt_virtual) { + drm_munmap(bo_gem->gtt_virtual, bo_gem->bo.size); + bufmgr_gem->vma_count--; + } + + if (bo_gem->global_name) + HASH_DELETE(name_hh, bufmgr_gem->name_table, bo_gem); + HASH_DELETE(handle_hh, bufmgr_gem->handle_table, bo_gem); + + /* Close this object */ + ret = drmCloseBufferHandle(bufmgr_gem->fd, bo_gem->gem_handle); + if (ret != 0) { + DBG("drmCloseBufferHandle %d failed (%s): %s\n", + bo_gem->gem_handle, bo_gem->name, strerror(errno)); + } + free(bo); +} + +static void +drm_intel_gem_bo_mark_mmaps_incoherent(drm_intel_bo *bo) +{ +#if HAVE_VALGRIND + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + + if (bo_gem->mem_virtual) + VALGRIND_MAKE_MEM_NOACCESS(bo_gem->mem_virtual, bo->size); + + if (bo_gem->wc_virtual) + VALGRIND_MAKE_MEM_NOACCESS(bo_gem->wc_virtual, bo->size); + + if (bo_gem->gtt_virtual) + VALGRIND_MAKE_MEM_NOACCESS(bo_gem->gtt_virtual, bo->size); +#endif +} + +/** Frees all cached buffers significantly older than @time. */ +static void +drm_intel_gem_cleanup_bo_cache(drm_intel_bufmgr_gem *bufmgr_gem, time_t time) +{ + int i; + + if (bufmgr_gem->time == time) + return; + + for (i = 0; i < bufmgr_gem->num_buckets; i++) { + struct drm_intel_gem_bo_bucket *bucket = + &bufmgr_gem->cache_bucket[i]; + + while (!DRMLISTEMPTY(&bucket->head)) { + drm_intel_bo_gem *bo_gem; + + bo_gem = DRMLISTENTRY(drm_intel_bo_gem, + bucket->head.next, head); + if (time - bo_gem->free_time <= 1) + break; + + DRMLISTDEL(&bo_gem->head); + + drm_intel_gem_bo_free(&bo_gem->bo); + } + } + + bufmgr_gem->time = time; +} + +static void drm_intel_gem_bo_purge_vma_cache(drm_intel_bufmgr_gem *bufmgr_gem) +{ + int limit; + + DBG("%s: cached=%d, open=%d, limit=%d\n", __FUNCTION__, + bufmgr_gem->vma_count, bufmgr_gem->vma_open, bufmgr_gem->vma_max); + + if (bufmgr_gem->vma_max < 0) + return; + + /* We may need to evict a few entries in order to create new mmaps */ + limit = bufmgr_gem->vma_max - 2*bufmgr_gem->vma_open; + if (limit < 0) + limit = 0; + + while (bufmgr_gem->vma_count > limit) { + drm_intel_bo_gem *bo_gem; + + bo_gem = DRMLISTENTRY(drm_intel_bo_gem, + bufmgr_gem->vma_cache.next, + vma_list); + assert(bo_gem->map_count == 0); + DRMLISTDELINIT(&bo_gem->vma_list); + + if (bo_gem->mem_virtual) { + drm_munmap(bo_gem->mem_virtual, bo_gem->bo.size); + bo_gem->mem_virtual = NULL; + bufmgr_gem->vma_count--; + } + if (bo_gem->wc_virtual) { + drm_munmap(bo_gem->wc_virtual, bo_gem->bo.size); + bo_gem->wc_virtual = NULL; + bufmgr_gem->vma_count--; + } + if (bo_gem->gtt_virtual) { + drm_munmap(bo_gem->gtt_virtual, bo_gem->bo.size); + bo_gem->gtt_virtual = NULL; + bufmgr_gem->vma_count--; + } + } +} + +static void drm_intel_gem_bo_close_vma(drm_intel_bufmgr_gem *bufmgr_gem, + drm_intel_bo_gem *bo_gem) +{ + bufmgr_gem->vma_open--; + DRMLISTADDTAIL(&bo_gem->vma_list, &bufmgr_gem->vma_cache); + if (bo_gem->mem_virtual) + bufmgr_gem->vma_count++; + if (bo_gem->wc_virtual) + bufmgr_gem->vma_count++; + if (bo_gem->gtt_virtual) + bufmgr_gem->vma_count++; + drm_intel_gem_bo_purge_vma_cache(bufmgr_gem); +} + +static void drm_intel_gem_bo_open_vma(drm_intel_bufmgr_gem *bufmgr_gem, + drm_intel_bo_gem *bo_gem) +{ + bufmgr_gem->vma_open++; + DRMLISTDEL(&bo_gem->vma_list); + if (bo_gem->mem_virtual) + bufmgr_gem->vma_count--; + if (bo_gem->wc_virtual) + bufmgr_gem->vma_count--; + if (bo_gem->gtt_virtual) + bufmgr_gem->vma_count--; + drm_intel_gem_bo_purge_vma_cache(bufmgr_gem); +} + +static void +drm_intel_gem_bo_unreference_final(drm_intel_bo *bo, time_t time) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + struct drm_intel_gem_bo_bucket *bucket; + int i; + + /* Unreference all the target buffers */ + for (i = 0; i < bo_gem->reloc_count; i++) { + if (bo_gem->reloc_target_info[i].bo != bo) { + drm_intel_gem_bo_unreference_locked_timed(bo_gem-> + reloc_target_info[i].bo, + time); + } + } + for (i = 0; i < bo_gem->softpin_target_count; i++) + drm_intel_gem_bo_unreference_locked_timed(bo_gem->softpin_target[i], + time); + bo_gem->kflags = 0; + bo_gem->reloc_count = 0; + bo_gem->used_as_reloc_target = false; + bo_gem->softpin_target_count = 0; + + DBG("bo_unreference final: %d (%s)\n", + bo_gem->gem_handle, bo_gem->name); + + /* release memory associated with this object */ + if (bo_gem->reloc_target_info) { + free(bo_gem->reloc_target_info); + bo_gem->reloc_target_info = NULL; + } + if (bo_gem->relocs) { + free(bo_gem->relocs); + bo_gem->relocs = NULL; + } + if (bo_gem->softpin_target) { + free(bo_gem->softpin_target); + bo_gem->softpin_target = NULL; + bo_gem->softpin_target_size = 0; + } + + /* Clear any left-over mappings */ + if (bo_gem->map_count) { + DBG("bo freed with non-zero map-count %d\n", bo_gem->map_count); + bo_gem->map_count = 0; + drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem); + drm_intel_gem_bo_mark_mmaps_incoherent(bo); + } + + bucket = drm_intel_gem_bo_bucket_for_size(bufmgr_gem, bo->size); + /* Put the buffer into our internal cache for reuse if we can. */ + if (bufmgr_gem->bo_reuse && bo_gem->reusable && bucket != NULL && + drm_intel_gem_bo_madvise_internal(bufmgr_gem, bo_gem, + I915_MADV_DONTNEED)) { + bo_gem->free_time = time; + + bo_gem->name = NULL; + bo_gem->validate_index = -1; + + DRMLISTADDTAIL(&bo_gem->head, &bucket->head); + } else { + drm_intel_gem_bo_free(bo); + } +} + +static void drm_intel_gem_bo_unreference_locked_timed(drm_intel_bo *bo, + time_t time) +{ + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + + assert(atomic_read(&bo_gem->refcount) > 0); + if (atomic_dec_and_test(&bo_gem->refcount)) + drm_intel_gem_bo_unreference_final(bo, time); +} + +static void drm_intel_gem_bo_unreference(drm_intel_bo *bo) +{ + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + drm_intel_bufmgr_gem *bufmgr_gem; + struct timespec time; + + assert(atomic_read(&bo_gem->refcount) > 0); + + if (atomic_add_unless(&bo_gem->refcount, -1, 1)) + return; + + bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + + clock_gettime(CLOCK_MONOTONIC, &time); + + pthread_mutex_lock(&bufmgr_gem->lock); + + if (atomic_dec_and_test(&bo_gem->refcount)) { + drm_intel_gem_bo_unreference_final(bo, time.tv_sec); + drm_intel_gem_cleanup_bo_cache(bufmgr_gem, time.tv_sec); + } + + pthread_mutex_unlock(&bufmgr_gem->lock); +} + +static int drm_intel_gem_bo_map(drm_intel_bo *bo, int write_enable) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + struct drm_i915_gem_set_domain set_domain; + int ret; + + if (bo_gem->is_userptr) { + /* Return the same user ptr */ + bo->virtual = bo_gem->user_virtual; + return 0; + } + + pthread_mutex_lock(&bufmgr_gem->lock); + + if (bo_gem->map_count++ == 0) + drm_intel_gem_bo_open_vma(bufmgr_gem, bo_gem); + + if (!bo_gem->mem_virtual) { + struct drm_i915_gem_mmap mmap_arg; + + DBG("bo_map: %d (%s), map_count=%d\n", + bo_gem->gem_handle, bo_gem->name, bo_gem->map_count); + + memclear(mmap_arg); + mmap_arg.handle = bo_gem->gem_handle; + mmap_arg.size = bo->size; + ret = drmIoctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GEM_MMAP, + &mmap_arg); + if (ret != 0) { + ret = -errno; + DBG("%s:%d: Error mapping buffer %d (%s): %s .\n", + __FILE__, __LINE__, bo_gem->gem_handle, + bo_gem->name, strerror(errno)); + if (--bo_gem->map_count == 0) + drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem); + pthread_mutex_unlock(&bufmgr_gem->lock); + return ret; + } + VG(VALGRIND_MALLOCLIKE_BLOCK(mmap_arg.addr_ptr, mmap_arg.size, 0, 1)); + bo_gem->mem_virtual = (void *)(uintptr_t) mmap_arg.addr_ptr; + } + DBG("bo_map: %d (%s) -> %p\n", bo_gem->gem_handle, bo_gem->name, + bo_gem->mem_virtual); + bo->virtual = bo_gem->mem_virtual; + + memclear(set_domain); + set_domain.handle = bo_gem->gem_handle; + set_domain.read_domains = I915_GEM_DOMAIN_CPU; + if (write_enable) + set_domain.write_domain = I915_GEM_DOMAIN_CPU; + else + set_domain.write_domain = 0; + ret = drmIoctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GEM_SET_DOMAIN, + &set_domain); + if (ret != 0) { + DBG("%s:%d: Error setting to CPU domain %d: %s\n", + __FILE__, __LINE__, bo_gem->gem_handle, + strerror(errno)); + } + + if (write_enable) + bo_gem->mapped_cpu_write = true; + + drm_intel_gem_bo_mark_mmaps_incoherent(bo); + VG(VALGRIND_MAKE_MEM_DEFINED(bo_gem->mem_virtual, bo->size)); + pthread_mutex_unlock(&bufmgr_gem->lock); + + return 0; +} + +static int +map_gtt(drm_intel_bo *bo) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + int ret; + + if (bo_gem->is_userptr) + return -EINVAL; + + if (bo_gem->map_count++ == 0) + drm_intel_gem_bo_open_vma(bufmgr_gem, bo_gem); + + /* Get a mapping of the buffer if we haven't before. */ + if (bo_gem->gtt_virtual == NULL) { + struct drm_i915_gem_mmap_gtt mmap_arg; + + DBG("bo_map_gtt: mmap %d (%s), map_count=%d\n", + bo_gem->gem_handle, bo_gem->name, bo_gem->map_count); + + memclear(mmap_arg); + mmap_arg.handle = bo_gem->gem_handle; + + /* Get the fake offset back... */ + ret = drmIoctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GEM_MMAP_GTT, + &mmap_arg); + if (ret != 0) { + ret = -errno; + DBG("%s:%d: Error preparing buffer map %d (%s): %s .\n", + __FILE__, __LINE__, + bo_gem->gem_handle, bo_gem->name, + strerror(errno)); + if (--bo_gem->map_count == 0) + drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem); + return ret; + } + + /* and mmap it */ + bo_gem->gtt_virtual = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, + MAP_SHARED, bufmgr_gem->fd, + mmap_arg.offset); + if (bo_gem->gtt_virtual == MAP_FAILED) { + bo_gem->gtt_virtual = NULL; + ret = -errno; + DBG("%s:%d: Error mapping buffer %d (%s): %s .\n", + __FILE__, __LINE__, + bo_gem->gem_handle, bo_gem->name, + strerror(errno)); + if (--bo_gem->map_count == 0) + drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem); + return ret; + } + } + + bo->virtual = bo_gem->gtt_virtual; + + DBG("bo_map_gtt: %d (%s) -> %p\n", bo_gem->gem_handle, bo_gem->name, + bo_gem->gtt_virtual); + + return 0; +} + +drm_public int +drm_intel_gem_bo_map_gtt(drm_intel_bo *bo) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + struct drm_i915_gem_set_domain set_domain; + int ret; + + pthread_mutex_lock(&bufmgr_gem->lock); + + ret = map_gtt(bo); + if (ret) { + pthread_mutex_unlock(&bufmgr_gem->lock); + return ret; + } + + /* Now move it to the GTT domain so that the GPU and CPU + * caches are flushed and the GPU isn't actively using the + * buffer. + * + * The pagefault handler does this domain change for us when + * it has unbound the BO from the GTT, but it's up to us to + * tell it when we're about to use things if we had done + * rendering and it still happens to be bound to the GTT. + */ + memclear(set_domain); + set_domain.handle = bo_gem->gem_handle; + set_domain.read_domains = I915_GEM_DOMAIN_GTT; + set_domain.write_domain = I915_GEM_DOMAIN_GTT; + ret = drmIoctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GEM_SET_DOMAIN, + &set_domain); + if (ret != 0) { + DBG("%s:%d: Error setting domain %d: %s\n", + __FILE__, __LINE__, bo_gem->gem_handle, + strerror(errno)); + } + + drm_intel_gem_bo_mark_mmaps_incoherent(bo); + VG(VALGRIND_MAKE_MEM_DEFINED(bo_gem->gtt_virtual, bo->size)); + pthread_mutex_unlock(&bufmgr_gem->lock); + + return 0; +} + +/** + * Performs a mapping of the buffer object like the normal GTT + * mapping, but avoids waiting for the GPU to be done reading from or + * rendering to the buffer. + * + * This is used in the implementation of GL_ARB_map_buffer_range: The + * user asks to create a buffer, then does a mapping, fills some + * space, runs a drawing command, then asks to map it again without + * synchronizing because it guarantees that it won't write over the + * data that the GPU is busy using (or, more specifically, that if it + * does write over the data, it acknowledges that rendering is + * undefined). + */ + +drm_public int +drm_intel_gem_bo_map_unsynchronized(drm_intel_bo *bo) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; +#if HAVE_VALGRIND + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; +#endif + int ret; + + /* If the CPU cache isn't coherent with the GTT, then use a + * regular synchronized mapping. The problem is that we don't + * track where the buffer was last used on the CPU side in + * terms of drm_intel_bo_map vs drm_intel_gem_bo_map_gtt, so + * we would potentially corrupt the buffer even when the user + * does reasonable things. + */ + if (!bufmgr_gem->has_llc) + return drm_intel_gem_bo_map_gtt(bo); + + pthread_mutex_lock(&bufmgr_gem->lock); + + ret = map_gtt(bo); + if (ret == 0) { + drm_intel_gem_bo_mark_mmaps_incoherent(bo); + VG(VALGRIND_MAKE_MEM_DEFINED(bo_gem->gtt_virtual, bo->size)); + } + + pthread_mutex_unlock(&bufmgr_gem->lock); + + return ret; +} + +static int drm_intel_gem_bo_unmap(drm_intel_bo *bo) +{ + drm_intel_bufmgr_gem *bufmgr_gem; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + int ret = 0; + + if (bo == NULL) + return 0; + + if (bo_gem->is_userptr) + return 0; + + bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + + pthread_mutex_lock(&bufmgr_gem->lock); + + if (bo_gem->map_count <= 0) { + DBG("attempted to unmap an unmapped bo\n"); + pthread_mutex_unlock(&bufmgr_gem->lock); + /* Preserve the old behaviour of just treating this as a + * no-op rather than reporting the error. + */ + return 0; + } + + if (bo_gem->mapped_cpu_write) { + struct drm_i915_gem_sw_finish sw_finish; + + /* Cause a flush to happen if the buffer's pinned for + * scanout, so the results show up in a timely manner. + * Unlike GTT set domains, this only does work if the + * buffer should be scanout-related. + */ + memclear(sw_finish); + sw_finish.handle = bo_gem->gem_handle; + ret = drmIoctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GEM_SW_FINISH, + &sw_finish); + ret = ret == -1 ? -errno : 0; + + bo_gem->mapped_cpu_write = false; + } + + /* We need to unmap after every innovation as we cannot track + * an open vma for every bo as that will exhaust the system + * limits and cause later failures. + */ + if (--bo_gem->map_count == 0) { + drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem); + drm_intel_gem_bo_mark_mmaps_incoherent(bo); + bo->virtual = NULL; + } + pthread_mutex_unlock(&bufmgr_gem->lock); + + return ret; +} + +drm_public int +drm_intel_gem_bo_unmap_gtt(drm_intel_bo *bo) +{ + return drm_intel_gem_bo_unmap(bo); +} + +static bool is_cache_coherent(drm_intel_bo *bo) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + struct drm_i915_gem_caching arg = {}; + + arg.handle = bo_gem->gem_handle; + if (drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_GET_CACHING, &arg)) + assert(false); + return arg.caching != I915_CACHING_NONE; +} + +static void set_domain(drm_intel_bo *bo, uint32_t read, uint32_t write) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + struct drm_i915_gem_set_domain arg = {}; + + arg.handle = bo_gem->gem_handle; + arg.read_domains = read; + arg.write_domain = write; + if (drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &arg)) + assert(false); +} + +static int mmap_write(drm_intel_bo *bo, unsigned long offset, + unsigned long length, const void *buf) +{ + void *map = NULL; + + if (!length) + return 0; + + if (is_cache_coherent(bo)) { + map = drm_intel_gem_bo_map__cpu(bo); + if (map) + set_domain(bo, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU); + } + if (!map) { + map = drm_intel_gem_bo_map__wc(bo); + if (map) + set_domain(bo, I915_GEM_DOMAIN_WC, I915_GEM_DOMAIN_WC); + } + + assert(map); + memcpy((char *)map + offset, buf, length); + drm_intel_gem_bo_unmap(bo); + return 0; +} + +static int mmap_read(drm_intel_bo *bo, unsigned long offset, + unsigned long length, void *buf) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + void *map = NULL; + + if (!length) + return 0; + + if (bufmgr_gem->has_llc || is_cache_coherent(bo)) { + map = drm_intel_gem_bo_map__cpu(bo); + if (map) + set_domain(bo, I915_GEM_DOMAIN_CPU, 0); + } + if (!map) { + map = drm_intel_gem_bo_map__wc(bo); + if (map) + set_domain(bo, I915_GEM_DOMAIN_WC, 0); + } + + assert(map); + memcpy(buf, (char *)map + offset, length); + drm_intel_gem_bo_unmap(bo); + return 0; +} + +static int +drm_intel_gem_bo_subdata(drm_intel_bo *bo, unsigned long offset, + unsigned long size, const void *data) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + struct drm_i915_gem_pwrite pwrite; + int ret; + + if (bo_gem->is_userptr) + return -EINVAL; + + memclear(pwrite); + pwrite.handle = bo_gem->gem_handle; + pwrite.offset = offset; + pwrite.size = size; + pwrite.data_ptr = (uint64_t) (uintptr_t) data; + ret = drmIoctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GEM_PWRITE, + &pwrite); + if (ret) + ret = -errno; + + if (ret != 0 && ret != -EOPNOTSUPP) { + DBG("%s:%d: Error writing data to buffer %d: (%d %d) %s .\n", + __FILE__, __LINE__, bo_gem->gem_handle, (int)offset, + (int)size, strerror(errno)); + return ret; + } + + if (ret == -EOPNOTSUPP) + mmap_write(bo, offset, size, data); + + return 0; +} + +static int +drm_intel_gem_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, int crtc_id) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr; + struct drm_i915_get_pipe_from_crtc_id get_pipe_from_crtc_id; + int ret; + + memclear(get_pipe_from_crtc_id); + get_pipe_from_crtc_id.crtc_id = crtc_id; + ret = drmIoctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID, + &get_pipe_from_crtc_id); + if (ret != 0) { + /* We return -1 here to signal that we don't + * know which pipe is associated with this crtc. + * This lets the caller know that this information + * isn't available; using the wrong pipe for + * vblank waiting can cause the chipset to lock up + */ + return -1; + } + + return get_pipe_from_crtc_id.pipe; +} + +static int +drm_intel_gem_bo_get_subdata(drm_intel_bo *bo, unsigned long offset, + unsigned long size, void *data) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + struct drm_i915_gem_pread pread; + int ret; + + if (bo_gem->is_userptr) + return -EINVAL; + + memclear(pread); + pread.handle = bo_gem->gem_handle; + pread.offset = offset; + pread.size = size; + pread.data_ptr = (uint64_t) (uintptr_t) data; + ret = drmIoctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GEM_PREAD, + &pread); + if (ret) + ret = -errno; + + if (ret != 0 && ret != -EOPNOTSUPP) { + DBG("%s:%d: Error reading data from buffer %d: (%d %d) %s .\n", + __FILE__, __LINE__, bo_gem->gem_handle, (int)offset, + (int)size, strerror(errno)); + return ret; + } + + if (ret == -EOPNOTSUPP) + mmap_read(bo, offset, size, data); + + return 0; +} + +/** Waits for all GPU rendering with the object to have completed. */ +static void +drm_intel_gem_bo_wait_rendering(drm_intel_bo *bo) +{ + drm_intel_gem_bo_start_gtt_access(bo, 1); +} + +/** + * Waits on a BO for the given amount of time. + * + * @bo: buffer object to wait for + * @timeout_ns: amount of time to wait in nanoseconds. + * If value is less than 0, an infinite wait will occur. + * + * Returns 0 if the wait was successful ie. the last batch referencing the + * object has completed within the allotted time. Otherwise some negative return + * value describes the error. Of particular interest is -ETIME when the wait has + * failed to yield the desired result. + * + * Similar to drm_intel_gem_bo_wait_rendering except a timeout parameter allows + * the operation to give up after a certain amount of time. Another subtle + * difference is the internal locking semantics are different (this variant does + * not hold the lock for the duration of the wait). This makes the wait subject + * to a larger userspace race window. + * + * The implementation shall wait until the object is no longer actively + * referenced within a batch buffer at the time of the call. The wait will + * not guarantee that the buffer is re-issued via another thread, or an flinked + * handle. Userspace must make sure this race does not occur if such precision + * is important. + * + * Note that some kernels have broken the inifite wait for negative values + * promise, upgrade to latest stable kernels if this is the case. + */ +drm_public int +drm_intel_gem_bo_wait(drm_intel_bo *bo, int64_t timeout_ns) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + struct drm_i915_gem_wait wait; + int ret; + + if (!bufmgr_gem->has_wait_timeout) { + DBG("%s:%d: Timed wait is not supported. Falling back to " + "infinite wait\n", __FILE__, __LINE__); + if (timeout_ns) { + drm_intel_gem_bo_wait_rendering(bo); + return 0; + } else { + return drm_intel_gem_bo_busy(bo) ? -ETIME : 0; + } + } + + memclear(wait); + wait.bo_handle = bo_gem->gem_handle; + wait.timeout_ns = timeout_ns; + ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_WAIT, &wait); + if (ret == -1) + return -errno; + + return ret; +} + +/** + * Sets the object to the GTT read and possibly write domain, used by the X + * 2D driver in the absence of kernel support to do drm_intel_gem_bo_map_gtt(). + * + * In combination with drm_intel_gem_bo_pin() and manual fence management, we + * can do tiled pixmaps this way. + */ +drm_public void +drm_intel_gem_bo_start_gtt_access(drm_intel_bo *bo, int write_enable) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + struct drm_i915_gem_set_domain set_domain; + int ret; + + memclear(set_domain); + set_domain.handle = bo_gem->gem_handle; + set_domain.read_domains = I915_GEM_DOMAIN_GTT; + set_domain.write_domain = write_enable ? I915_GEM_DOMAIN_GTT : 0; + ret = drmIoctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GEM_SET_DOMAIN, + &set_domain); + if (ret != 0) { + DBG("%s:%d: Error setting memory domains %d (%08x %08x): %s .\n", + __FILE__, __LINE__, bo_gem->gem_handle, + set_domain.read_domains, set_domain.write_domain, + strerror(errno)); + } +} + +static void +drm_intel_bufmgr_gem_destroy(drm_intel_bufmgr *bufmgr) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr; + int i, ret; + + free(bufmgr_gem->exec2_objects); + free(bufmgr_gem->exec_bos); + + pthread_mutex_destroy(&bufmgr_gem->lock); + + /* Free any cached buffer objects we were going to reuse */ + for (i = 0; i < bufmgr_gem->num_buckets; i++) { + struct drm_intel_gem_bo_bucket *bucket = + &bufmgr_gem->cache_bucket[i]; + drm_intel_bo_gem *bo_gem; + + while (!DRMLISTEMPTY(&bucket->head)) { + bo_gem = DRMLISTENTRY(drm_intel_bo_gem, + bucket->head.next, head); + DRMLISTDEL(&bo_gem->head); + + drm_intel_gem_bo_free(&bo_gem->bo); + } + } + + /* Release userptr bo kept hanging around for optimisation. */ + if (bufmgr_gem->userptr_active.ptr) { + ret = drmCloseBufferHandle(bufmgr_gem->fd, + bufmgr_gem->userptr_active.handle); + free(bufmgr_gem->userptr_active.ptr); + if (ret) + fprintf(stderr, + "Failed to release test userptr object! (%d) " + "i915 kernel driver may not be sane!\n", errno); + } + + free(bufmgr); +} + +/** + * Adds the target buffer to the validation list and adds the relocation + * to the reloc_buffer's relocation list. + * + * The relocation entry at the given offset must already contain the + * precomputed relocation value, because the kernel will optimize out + * the relocation entry write when the buffer hasn't moved from the + * last known offset in target_bo. + */ +static int +do_bo_emit_reloc(drm_intel_bo *bo, uint32_t offset, + drm_intel_bo *target_bo, uint32_t target_offset, + uint32_t read_domains, uint32_t write_domain, + bool need_fence) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + drm_intel_bo_gem *target_bo_gem = (drm_intel_bo_gem *) target_bo; + bool fenced_command; + + if (bo_gem->has_error) + return -ENOMEM; + + if (target_bo_gem->has_error) { + bo_gem->has_error = true; + return -ENOMEM; + } + + /* We never use HW fences for rendering on 965+ */ + if (bufmgr_gem->gen >= 4) + need_fence = false; + + fenced_command = need_fence; + if (target_bo_gem->tiling_mode == I915_TILING_NONE) + need_fence = false; + + /* Create a new relocation list if needed */ + if (bo_gem->relocs == NULL && drm_intel_setup_reloc_list(bo)) + return -ENOMEM; + + /* Check overflow */ + assert(bo_gem->reloc_count < bufmgr_gem->max_relocs); + + /* Check args */ + assert(offset <= bo->size - 4); + assert((write_domain & (write_domain - 1)) == 0); + + /* An object needing a fence is a tiled buffer, so it won't have + * relocs to other buffers. + */ + if (need_fence) { + assert(target_bo_gem->reloc_count == 0); + target_bo_gem->reloc_tree_fences = 1; + } + + /* Make sure that we're not adding a reloc to something whose size has + * already been accounted for. + */ + assert(!bo_gem->used_as_reloc_target); + if (target_bo_gem != bo_gem) { + target_bo_gem->used_as_reloc_target = true; + bo_gem->reloc_tree_size += target_bo_gem->reloc_tree_size; + bo_gem->reloc_tree_fences += target_bo_gem->reloc_tree_fences; + } + + bo_gem->reloc_target_info[bo_gem->reloc_count].bo = target_bo; + if (target_bo != bo) + drm_intel_gem_bo_reference(target_bo); + if (fenced_command) + bo_gem->reloc_target_info[bo_gem->reloc_count].flags = + DRM_INTEL_RELOC_FENCE; + else + bo_gem->reloc_target_info[bo_gem->reloc_count].flags = 0; + + bo_gem->relocs[bo_gem->reloc_count].offset = offset; + bo_gem->relocs[bo_gem->reloc_count].delta = target_offset; + bo_gem->relocs[bo_gem->reloc_count].target_handle = + target_bo_gem->gem_handle; + bo_gem->relocs[bo_gem->reloc_count].read_domains = read_domains; + bo_gem->relocs[bo_gem->reloc_count].write_domain = write_domain; + bo_gem->relocs[bo_gem->reloc_count].presumed_offset = target_bo->offset64; + bo_gem->reloc_count++; + + return 0; +} + +static void +drm_intel_gem_bo_use_48b_address_range(drm_intel_bo *bo, uint32_t enable) +{ + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + + if (enable) + bo_gem->kflags |= EXEC_OBJECT_SUPPORTS_48B_ADDRESS; + else + bo_gem->kflags &= ~EXEC_OBJECT_SUPPORTS_48B_ADDRESS; +} + +static int +drm_intel_gem_bo_add_softpin_target(drm_intel_bo *bo, drm_intel_bo *target_bo) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + drm_intel_bo_gem *target_bo_gem = (drm_intel_bo_gem *) target_bo; + if (bo_gem->has_error) + return -ENOMEM; + + if (target_bo_gem->has_error) { + bo_gem->has_error = true; + return -ENOMEM; + } + + if (!(target_bo_gem->kflags & EXEC_OBJECT_PINNED)) + return -EINVAL; + if (target_bo_gem == bo_gem) + return -EINVAL; + + if (bo_gem->softpin_target_count == bo_gem->softpin_target_size) { + int new_size = bo_gem->softpin_target_size * 2; + if (new_size == 0) + new_size = bufmgr_gem->max_relocs; + + bo_gem->softpin_target = realloc(bo_gem->softpin_target, new_size * + sizeof(drm_intel_bo *)); + if (!bo_gem->softpin_target) + return -ENOMEM; + + bo_gem->softpin_target_size = new_size; + } + bo_gem->softpin_target[bo_gem->softpin_target_count] = target_bo; + drm_intel_gem_bo_reference(target_bo); + bo_gem->softpin_target_count++; + + return 0; +} + +static int +drm_intel_gem_bo_emit_reloc(drm_intel_bo *bo, uint32_t offset, + drm_intel_bo *target_bo, uint32_t target_offset, + uint32_t read_domains, uint32_t write_domain) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bo->bufmgr; + drm_intel_bo_gem *target_bo_gem = (drm_intel_bo_gem *)target_bo; + + if (target_bo_gem->kflags & EXEC_OBJECT_PINNED) + return drm_intel_gem_bo_add_softpin_target(bo, target_bo); + else + return do_bo_emit_reloc(bo, offset, target_bo, target_offset, + read_domains, write_domain, + !bufmgr_gem->fenced_relocs); +} + +static int +drm_intel_gem_bo_emit_reloc_fence(drm_intel_bo *bo, uint32_t offset, + drm_intel_bo *target_bo, + uint32_t target_offset, + uint32_t read_domains, uint32_t write_domain) +{ + return do_bo_emit_reloc(bo, offset, target_bo, target_offset, + read_domains, write_domain, true); +} + +drm_public int +drm_intel_gem_bo_get_reloc_count(drm_intel_bo *bo) +{ + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + + return bo_gem->reloc_count; +} + +/** + * Removes existing relocation entries in the BO after "start". + * + * This allows a user to avoid a two-step process for state setup with + * counting up all the buffer objects and doing a + * drm_intel_bufmgr_check_aperture_space() before emitting any of the + * relocations for the state setup. Instead, save the state of the + * batchbuffer including drm_intel_gem_get_reloc_count(), emit all the + * state, and then check if it still fits in the aperture. + * + * Any further drm_intel_bufmgr_check_aperture_space() queries + * involving this buffer in the tree are undefined after this call. + * + * This also removes all softpinned targets being referenced by the BO. + */ +drm_public void +drm_intel_gem_bo_clear_relocs(drm_intel_bo *bo, int start) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + int i; + struct timespec time; + + clock_gettime(CLOCK_MONOTONIC, &time); + + assert(bo_gem->reloc_count >= start); + + /* Unreference the cleared target buffers */ + pthread_mutex_lock(&bufmgr_gem->lock); + + for (i = start; i < bo_gem->reloc_count; i++) { + drm_intel_bo_gem *target_bo_gem = (drm_intel_bo_gem *) bo_gem->reloc_target_info[i].bo; + if (&target_bo_gem->bo != bo) { + bo_gem->reloc_tree_fences -= target_bo_gem->reloc_tree_fences; + drm_intel_gem_bo_unreference_locked_timed(&target_bo_gem->bo, + time.tv_sec); + } + } + bo_gem->reloc_count = start; + + for (i = 0; i < bo_gem->softpin_target_count; i++) { + drm_intel_bo_gem *target_bo_gem = (drm_intel_bo_gem *) bo_gem->softpin_target[i]; + drm_intel_gem_bo_unreference_locked_timed(&target_bo_gem->bo, time.tv_sec); + } + bo_gem->softpin_target_count = 0; + + pthread_mutex_unlock(&bufmgr_gem->lock); + +} + +/** + * Walk the tree of relocations rooted at BO and accumulate the list of + * validations to be performed and update the relocation buffers with + * index values into the validation list. + */ +static void +drm_intel_gem_bo_process_reloc2(drm_intel_bo *bo) +{ + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo; + int i; + + if (bo_gem->relocs == NULL && bo_gem->softpin_target == NULL) + return; + + for (i = 0; i < bo_gem->reloc_count; i++) { + drm_intel_bo *target_bo = bo_gem->reloc_target_info[i].bo; + int need_fence; + + if (target_bo == bo) + continue; + + drm_intel_gem_bo_mark_mmaps_incoherent(bo); + + /* Continue walking the tree depth-first. */ + drm_intel_gem_bo_process_reloc2(target_bo); + + need_fence = (bo_gem->reloc_target_info[i].flags & + DRM_INTEL_RELOC_FENCE); + + /* Add the target to the validate list */ + drm_intel_add_validate_buffer2(target_bo, need_fence); + } + + for (i = 0; i < bo_gem->softpin_target_count; i++) { + drm_intel_bo *target_bo = bo_gem->softpin_target[i]; + + if (target_bo == bo) + continue; + + drm_intel_gem_bo_mark_mmaps_incoherent(bo); + drm_intel_gem_bo_process_reloc2(target_bo); + drm_intel_add_validate_buffer2(target_bo, false); + } +} + +static void +drm_intel_update_buffer_offsets2 (drm_intel_bufmgr_gem *bufmgr_gem) +{ + int i; + + for (i = 0; i < bufmgr_gem->exec_count; i++) { + drm_intel_bo *bo = bufmgr_gem->exec_bos[i]; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo; + + /* Update the buffer offset */ + if (bufmgr_gem->exec2_objects[i].offset != bo->offset64) { + /* If we're seeing softpinned object here it means that the kernel + * has relocated our object... Indicating a programming error + */ + assert(!(bo_gem->kflags & EXEC_OBJECT_PINNED)); + DBG("BO %d (%s) migrated: 0x%08x %08x -> 0x%08x %08x\n", + bo_gem->gem_handle, bo_gem->name, + upper_32_bits(bo->offset64), + lower_32_bits(bo->offset64), + upper_32_bits(bufmgr_gem->exec2_objects[i].offset), + lower_32_bits(bufmgr_gem->exec2_objects[i].offset)); + bo->offset64 = bufmgr_gem->exec2_objects[i].offset; + bo->offset = bufmgr_gem->exec2_objects[i].offset; + } + } +} + +drm_public void +drm_intel_gem_bo_aub_dump_bmp(drm_intel_bo *bo, + int x1, int y1, int width, int height, + enum aub_dump_bmp_format format, + int pitch, int offset) +{ +} + +static int +do_exec2(drm_intel_bo *bo, int used, drm_intel_context *ctx, + drm_clip_rect_t *cliprects, int num_cliprects, int DR4, + int in_fence, int *out_fence, + unsigned int flags) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bo->bufmgr; + struct drm_i915_gem_execbuffer2 execbuf; + int ret = 0; + int i; + + if (to_bo_gem(bo)->has_error) + return -ENOMEM; + + switch (flags & 0x7) { + default: + return -EINVAL; + case I915_EXEC_BLT: + if (!bufmgr_gem->has_blt) + return -EINVAL; + break; + case I915_EXEC_BSD: + if (!bufmgr_gem->has_bsd) + return -EINVAL; + break; + case I915_EXEC_VEBOX: + if (!bufmgr_gem->has_vebox) + return -EINVAL; + break; + case I915_EXEC_RENDER: + case I915_EXEC_DEFAULT: + break; + } + + pthread_mutex_lock(&bufmgr_gem->lock); + /* Update indices and set up the validate list. */ + drm_intel_gem_bo_process_reloc2(bo); + + /* Add the batch buffer to the validation list. There are no relocations + * pointing to it. + */ + drm_intel_add_validate_buffer2(bo, 0); + + memclear(execbuf); + execbuf.buffers_ptr = (uintptr_t)bufmgr_gem->exec2_objects; + execbuf.buffer_count = bufmgr_gem->exec_count; + execbuf.batch_start_offset = 0; + execbuf.batch_len = used; + execbuf.cliprects_ptr = (uintptr_t)cliprects; + execbuf.num_cliprects = num_cliprects; + execbuf.DR1 = 0; + execbuf.DR4 = DR4; + execbuf.flags = flags; + if (ctx == NULL) + i915_execbuffer2_set_context_id(execbuf, 0); + else + i915_execbuffer2_set_context_id(execbuf, ctx->ctx_id); + execbuf.rsvd2 = 0; + if (in_fence != -1) { + execbuf.rsvd2 = in_fence; + execbuf.flags |= I915_EXEC_FENCE_IN; + } + if (out_fence != NULL) { + *out_fence = -1; + execbuf.flags |= I915_EXEC_FENCE_OUT; + } + + if (bufmgr_gem->no_exec) + goto skip_execution; + + ret = drmIoctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GEM_EXECBUFFER2_WR, + &execbuf); + if (ret != 0) { + ret = -errno; + if (ret == -ENOSPC) { + DBG("Execbuffer fails to pin. " + "Estimate: %u. Actual: %u. Available: %u\n", + drm_intel_gem_estimate_batch_space(bufmgr_gem->exec_bos, + bufmgr_gem->exec_count), + drm_intel_gem_compute_batch_space(bufmgr_gem->exec_bos, + bufmgr_gem->exec_count), + (unsigned int) bufmgr_gem->gtt_size); + } + } + drm_intel_update_buffer_offsets2(bufmgr_gem); + + if (ret == 0 && out_fence != NULL) + *out_fence = execbuf.rsvd2 >> 32; + +skip_execution: + if (bufmgr_gem->bufmgr.debug) + drm_intel_gem_dump_validation_list(bufmgr_gem); + + for (i = 0; i < bufmgr_gem->exec_count; i++) { + drm_intel_bo_gem *bo_gem = to_bo_gem(bufmgr_gem->exec_bos[i]); + + bo_gem->idle = false; + + /* Disconnect the buffer from the validate list */ + bo_gem->validate_index = -1; + bufmgr_gem->exec_bos[i] = NULL; + } + bufmgr_gem->exec_count = 0; + pthread_mutex_unlock(&bufmgr_gem->lock); + + return ret; +} + +static int +drm_intel_gem_bo_exec2(drm_intel_bo *bo, int used, + drm_clip_rect_t *cliprects, int num_cliprects, + int DR4) +{ + return do_exec2(bo, used, NULL, cliprects, num_cliprects, DR4, + -1, NULL, I915_EXEC_RENDER); +} + +static int +drm_intel_gem_bo_mrb_exec2(drm_intel_bo *bo, int used, + drm_clip_rect_t *cliprects, int num_cliprects, int DR4, + unsigned int flags) +{ + return do_exec2(bo, used, NULL, cliprects, num_cliprects, DR4, + -1, NULL, flags); +} + +drm_public int +drm_intel_gem_bo_context_exec(drm_intel_bo *bo, drm_intel_context *ctx, + int used, unsigned int flags) +{ + return do_exec2(bo, used, ctx, NULL, 0, 0, -1, NULL, flags); +} + +drm_public int +drm_intel_gem_bo_fence_exec(drm_intel_bo *bo, + drm_intel_context *ctx, + int used, + int in_fence, + int *out_fence, + unsigned int flags) +{ + return do_exec2(bo, used, ctx, NULL, 0, 0, in_fence, out_fence, flags); +} + +static int +drm_intel_gem_bo_pin(drm_intel_bo *bo, uint32_t alignment) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + struct drm_i915_gem_pin pin; + int ret; + + memclear(pin); + pin.handle = bo_gem->gem_handle; + pin.alignment = alignment; + + ret = drmIoctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GEM_PIN, + &pin); + if (ret != 0) + return -errno; + + bo->offset64 = pin.offset; + bo->offset = pin.offset; + return 0; +} + +static int +drm_intel_gem_bo_unpin(drm_intel_bo *bo) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + struct drm_i915_gem_unpin unpin; + int ret; + + memclear(unpin); + unpin.handle = bo_gem->gem_handle; + + ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_UNPIN, &unpin); + if (ret != 0) + return -errno; + + return 0; +} + +static int +drm_intel_gem_bo_set_tiling_internal(drm_intel_bo *bo, + uint32_t tiling_mode, + uint32_t stride) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + struct drm_i915_gem_set_tiling set_tiling; + int ret; + + if (bo_gem->global_name == 0 && + tiling_mode == bo_gem->tiling_mode && + stride == bo_gem->stride) + return 0; + + memset(&set_tiling, 0, sizeof(set_tiling)); + do { + /* set_tiling is slightly broken and overwrites the + * input on the error path, so we have to open code + * rmIoctl. + */ + set_tiling.handle = bo_gem->gem_handle; + set_tiling.tiling_mode = tiling_mode; + set_tiling.stride = stride; + + ret = ioctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GEM_SET_TILING, + &set_tiling); + } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); + if (ret == -1) + return -errno; + + bo_gem->tiling_mode = set_tiling.tiling_mode; + bo_gem->swizzle_mode = set_tiling.swizzle_mode; + bo_gem->stride = set_tiling.stride; + return 0; +} + +static int +drm_intel_gem_bo_set_tiling(drm_intel_bo *bo, uint32_t * tiling_mode, + uint32_t stride) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + int ret; + + /* Tiling with userptr surfaces is not supported + * on all hardware so refuse it for time being. + */ + if (bo_gem->is_userptr) + return -EINVAL; + + /* Linear buffers have no stride. By ensuring that we only ever use + * stride 0 with linear buffers, we simplify our code. + */ + if (*tiling_mode == I915_TILING_NONE) + stride = 0; + + ret = drm_intel_gem_bo_set_tiling_internal(bo, *tiling_mode, stride); + if (ret == 0) + drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem, 0); + + *tiling_mode = bo_gem->tiling_mode; + return ret; +} + +static int +drm_intel_gem_bo_get_tiling(drm_intel_bo *bo, uint32_t * tiling_mode, + uint32_t * swizzle_mode) +{ + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + + *tiling_mode = bo_gem->tiling_mode; + *swizzle_mode = bo_gem->swizzle_mode; + return 0; +} + +static int +drm_intel_gem_bo_set_softpin_offset(drm_intel_bo *bo, uint64_t offset) +{ + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + + bo->offset64 = offset; + bo->offset = offset; + bo_gem->kflags |= EXEC_OBJECT_PINNED; + + return 0; +} + +drm_public drm_intel_bo * +drm_intel_bo_gem_create_from_prime(drm_intel_bufmgr *bufmgr, int prime_fd, int size) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr; + int ret; + uint32_t handle; + drm_intel_bo_gem *bo_gem; + + pthread_mutex_lock(&bufmgr_gem->lock); + ret = drmPrimeFDToHandle(bufmgr_gem->fd, prime_fd, &handle); + if (ret) { + DBG("create_from_prime: failed to obtain handle from fd: %s\n", strerror(errno)); + pthread_mutex_unlock(&bufmgr_gem->lock); + return NULL; + } + + /* + * See if the kernel has already returned this buffer to us. Just as + * for named buffers, we must not create two bo's pointing at the same + * kernel object + */ + HASH_FIND(handle_hh, bufmgr_gem->handle_table, + &handle, sizeof(handle), bo_gem); + if (bo_gem) { + drm_intel_gem_bo_reference(&bo_gem->bo); + goto out; + } + + bo_gem = calloc(1, sizeof(*bo_gem)); + if (!bo_gem) + goto out; + + atomic_set(&bo_gem->refcount, 1); + DRMINITLISTHEAD(&bo_gem->vma_list); + + /* Determine size of bo. The fd-to-handle ioctl really should + * return the size, but it doesn't. If we have kernel 3.12 or + * later, we can lseek on the prime fd to get the size. Older + * kernels will just fail, in which case we fall back to the + * provided (estimated or guess size). */ + ret = lseek(prime_fd, 0, SEEK_END); + if (ret != -1) + bo_gem->bo.size = ret; + else + bo_gem->bo.size = size; + + bo_gem->bo.handle = handle; + bo_gem->bo.bufmgr = bufmgr; + + bo_gem->gem_handle = handle; + HASH_ADD(handle_hh, bufmgr_gem->handle_table, + gem_handle, sizeof(bo_gem->gem_handle), bo_gem); + + bo_gem->name = "prime"; + bo_gem->validate_index = -1; + bo_gem->reloc_tree_fences = 0; + bo_gem->used_as_reloc_target = false; + bo_gem->has_error = false; + bo_gem->reusable = false; + + ret = get_tiling_mode(bufmgr_gem, handle, + &bo_gem->tiling_mode, &bo_gem->swizzle_mode); + if (ret) + goto err; + + /* XXX stride is unknown */ + drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem, 0); + +out: + pthread_mutex_unlock(&bufmgr_gem->lock); + return &bo_gem->bo; + +err: + drm_intel_gem_bo_free(&bo_gem->bo); + pthread_mutex_unlock(&bufmgr_gem->lock); + return NULL; +} + +drm_public int +drm_intel_bo_gem_export_to_prime(drm_intel_bo *bo, int *prime_fd) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + + if (drmPrimeHandleToFD(bufmgr_gem->fd, bo_gem->gem_handle, + DRM_CLOEXEC | DRM_RDWR, prime_fd) != 0) + return -errno; + + bo_gem->reusable = false; + + return 0; +} + +static int +drm_intel_gem_bo_flink(drm_intel_bo *bo, uint32_t * name) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + + if (!bo_gem->global_name) { + struct drm_gem_flink flink; + + memclear(flink); + flink.handle = bo_gem->gem_handle; + if (drmIoctl(bufmgr_gem->fd, DRM_IOCTL_GEM_FLINK, &flink)) + return -errno; + + pthread_mutex_lock(&bufmgr_gem->lock); + if (!bo_gem->global_name) { + bo_gem->global_name = flink.name; + bo_gem->reusable = false; + + HASH_ADD(name_hh, bufmgr_gem->name_table, + global_name, sizeof(bo_gem->global_name), + bo_gem); + } + pthread_mutex_unlock(&bufmgr_gem->lock); + } + + *name = bo_gem->global_name; + return 0; +} + +/** + * Enables unlimited caching of buffer objects for reuse. + * + * This is potentially very memory expensive, as the cache at each bucket + * size is only bounded by how many buffers of that size we've managed to have + * in flight at once. + */ +drm_public void +drm_intel_bufmgr_gem_enable_reuse(drm_intel_bufmgr *bufmgr) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr; + + bufmgr_gem->bo_reuse = true; +} + +/** + * Disables implicit synchronisation before executing the bo + * + * This will cause rendering corruption unless you correctly manage explicit + * fences for all rendering involving this buffer - including use by others. + * Disabling the implicit serialisation is only required if that serialisation + * is too coarse (for example, you have split the buffer into many + * non-overlapping regions and are sharing the whole buffer between concurrent + * independent command streams). + * + * Note the kernel must advertise support via I915_PARAM_HAS_EXEC_ASYNC, + * which can be checked using drm_intel_bufmgr_can_disable_implicit_sync, + * or subsequent execbufs involving the bo will generate EINVAL. + */ +drm_public void +drm_intel_gem_bo_disable_implicit_sync(drm_intel_bo *bo) +{ + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + + bo_gem->kflags |= EXEC_OBJECT_ASYNC; +} + +/** + * Enables implicit synchronisation before executing the bo + * + * This is the default behaviour of the kernel, to wait upon prior writes + * completing on the object before rendering with it, or to wait for prior + * reads to complete before writing into the object. + * drm_intel_gem_bo_disable_implicit_sync() can stop this behaviour, telling + * the kernel never to insert a stall before using the object. Then this + * function can be used to restore the implicit sync before subsequent + * rendering. + */ +drm_public void +drm_intel_gem_bo_enable_implicit_sync(drm_intel_bo *bo) +{ + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + + bo_gem->kflags &= ~EXEC_OBJECT_ASYNC; +} + +/** + * Query whether the kernel supports disabling of its implicit synchronisation + * before execbuf. See drm_intel_gem_bo_disable_implicit_sync() + */ +drm_public int +drm_intel_bufmgr_gem_can_disable_implicit_sync(drm_intel_bufmgr *bufmgr) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr; + + return bufmgr_gem->has_exec_async; +} + +/** + * Enable use of fenced reloc type. + * + * New code should enable this to avoid unnecessary fence register + * allocation. If this option is not enabled, all relocs will have fence + * register allocated. + */ +drm_public void +drm_intel_bufmgr_gem_enable_fenced_relocs(drm_intel_bufmgr *bufmgr) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr; + bufmgr_gem->fenced_relocs = true; +} + +/** + * Return the additional aperture space required by the tree of buffer objects + * rooted at bo. + */ +static int +drm_intel_gem_bo_get_aperture_space(drm_intel_bo *bo) +{ + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + int i; + int total = 0; + + if (bo == NULL || bo_gem->included_in_check_aperture) + return 0; + + total += bo->size; + bo_gem->included_in_check_aperture = true; + + for (i = 0; i < bo_gem->reloc_count; i++) + total += + drm_intel_gem_bo_get_aperture_space(bo_gem-> + reloc_target_info[i].bo); + + return total; +} + +/** + * Count the number of buffers in this list that need a fence reg + * + * If the count is greater than the number of available regs, we'll have + * to ask the caller to resubmit a batch with fewer tiled buffers. + * + * This function over-counts if the same buffer is used multiple times. + */ +static unsigned int +drm_intel_gem_total_fences(drm_intel_bo ** bo_array, int count) +{ + int i; + unsigned int total = 0; + + for (i = 0; i < count; i++) { + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo_array[i]; + + if (bo_gem == NULL) + continue; + + total += bo_gem->reloc_tree_fences; + } + return total; +} + +/** + * Clear the flag set by drm_intel_gem_bo_get_aperture_space() so we're ready + * for the next drm_intel_bufmgr_check_aperture_space() call. + */ +static void +drm_intel_gem_bo_clear_aperture_space_flag(drm_intel_bo *bo) +{ + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + int i; + + if (bo == NULL || !bo_gem->included_in_check_aperture) + return; + + bo_gem->included_in_check_aperture = false; + + for (i = 0; i < bo_gem->reloc_count; i++) + drm_intel_gem_bo_clear_aperture_space_flag(bo_gem-> + reloc_target_info[i].bo); +} + +/** + * Return a conservative estimate for the amount of aperture required + * for a collection of buffers. This may double-count some buffers. + */ +static unsigned int +drm_intel_gem_estimate_batch_space(drm_intel_bo **bo_array, int count) +{ + int i; + unsigned int total = 0; + + for (i = 0; i < count; i++) { + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo_array[i]; + if (bo_gem != NULL) + total += bo_gem->reloc_tree_size; + } + return total; +} + +/** + * Return the amount of aperture needed for a collection of buffers. + * This avoids double counting any buffers, at the cost of looking + * at every buffer in the set. + */ +static unsigned int +drm_intel_gem_compute_batch_space(drm_intel_bo **bo_array, int count) +{ + int i; + unsigned int total = 0; + + for (i = 0; i < count; i++) { + total += drm_intel_gem_bo_get_aperture_space(bo_array[i]); + /* For the first buffer object in the array, we get an + * accurate count back for its reloc_tree size (since nothing + * had been flagged as being counted yet). We can save that + * value out as a more conservative reloc_tree_size that + * avoids double-counting target buffers. Since the first + * buffer happens to usually be the batch buffer in our + * callers, this can pull us back from doing the tree + * walk on every new batch emit. + */ + if (i == 0) { + drm_intel_bo_gem *bo_gem = + (drm_intel_bo_gem *) bo_array[i]; + bo_gem->reloc_tree_size = total; + } + } + + for (i = 0; i < count; i++) + drm_intel_gem_bo_clear_aperture_space_flag(bo_array[i]); + return total; +} + +/** + * Return -1 if the batchbuffer should be flushed before attempting to + * emit rendering referencing the buffers pointed to by bo_array. + * + * This is required because if we try to emit a batchbuffer with relocations + * to a tree of buffers that won't simultaneously fit in the aperture, + * the rendering will return an error at a point where the software is not + * prepared to recover from it. + * + * However, we also want to emit the batchbuffer significantly before we reach + * the limit, as a series of batchbuffers each of which references buffers + * covering almost all of the aperture means that at each emit we end up + * waiting to evict a buffer from the last rendering, and we get synchronous + * performance. By emitting smaller batchbuffers, we eat some CPU overhead to + * get better parallelism. + */ +static int +drm_intel_gem_check_aperture_space(drm_intel_bo **bo_array, int count) +{ + drm_intel_bufmgr_gem *bufmgr_gem = + (drm_intel_bufmgr_gem *) bo_array[0]->bufmgr; + unsigned int total = 0; + unsigned int threshold = bufmgr_gem->gtt_size * 3 / 4; + int total_fences; + + /* Check for fence reg constraints if necessary */ + if (bufmgr_gem->available_fences) { + total_fences = drm_intel_gem_total_fences(bo_array, count); + if (total_fences > bufmgr_gem->available_fences) + return -ENOSPC; + } + + total = drm_intel_gem_estimate_batch_space(bo_array, count); + + if (total > threshold) + total = drm_intel_gem_compute_batch_space(bo_array, count); + + if (total > threshold) { + DBG("check_space: overflowed available aperture, " + "%dkb vs %dkb\n", + total / 1024, (int)bufmgr_gem->gtt_size / 1024); + return -ENOSPC; + } else { + DBG("drm_check_space: total %dkb vs bufgr %dkb\n", total / 1024, + (int)bufmgr_gem->gtt_size / 1024); + return 0; + } +} + +/* + * Disable buffer reuse for objects which are shared with the kernel + * as scanout buffers + */ +static int +drm_intel_gem_bo_disable_reuse(drm_intel_bo *bo) +{ + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + + bo_gem->reusable = false; + return 0; +} + +static int +drm_intel_gem_bo_is_reusable(drm_intel_bo *bo) +{ + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + + return bo_gem->reusable; +} + +static int +_drm_intel_gem_bo_references(drm_intel_bo *bo, drm_intel_bo *target_bo) +{ + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + int i; + + for (i = 0; i < bo_gem->reloc_count; i++) { + if (bo_gem->reloc_target_info[i].bo == target_bo) + return 1; + if (bo == bo_gem->reloc_target_info[i].bo) + continue; + if (_drm_intel_gem_bo_references(bo_gem->reloc_target_info[i].bo, + target_bo)) + return 1; + } + + for (i = 0; i< bo_gem->softpin_target_count; i++) { + if (bo_gem->softpin_target[i] == target_bo) + return 1; + if (_drm_intel_gem_bo_references(bo_gem->softpin_target[i], target_bo)) + return 1; + } + + return 0; +} + +/** Return true if target_bo is referenced by bo's relocation tree. */ +static int +drm_intel_gem_bo_references(drm_intel_bo *bo, drm_intel_bo *target_bo) +{ + drm_intel_bo_gem *target_bo_gem = (drm_intel_bo_gem *) target_bo; + + if (bo == NULL || target_bo == NULL) + return 0; + if (target_bo_gem->used_as_reloc_target) + return _drm_intel_gem_bo_references(bo, target_bo); + return 0; +} + +static void +add_bucket(drm_intel_bufmgr_gem *bufmgr_gem, int size) +{ + unsigned int i = bufmgr_gem->num_buckets; + + assert(i < ARRAY_SIZE(bufmgr_gem->cache_bucket)); + + DRMINITLISTHEAD(&bufmgr_gem->cache_bucket[i].head); + bufmgr_gem->cache_bucket[i].size = size; + bufmgr_gem->num_buckets++; +} + +static void +init_cache_buckets(drm_intel_bufmgr_gem *bufmgr_gem) +{ + unsigned long size, cache_max_size = 64 * 1024 * 1024; + + /* OK, so power of two buckets was too wasteful of memory. + * Give 3 other sizes between each power of two, to hopefully + * cover things accurately enough. (The alternative is + * probably to just go for exact matching of sizes, and assume + * that for things like composited window resize the tiled + * width/height alignment and rounding of sizes to pages will + * get us useful cache hit rates anyway) + */ + add_bucket(bufmgr_gem, 4096); + add_bucket(bufmgr_gem, 4096 * 2); + add_bucket(bufmgr_gem, 4096 * 3); + + /* Initialize the linked lists for BO reuse cache. */ + for (size = 4 * 4096; size <= cache_max_size; size *= 2) { + add_bucket(bufmgr_gem, size); + + add_bucket(bufmgr_gem, size + size * 1 / 4); + add_bucket(bufmgr_gem, size + size * 2 / 4); + add_bucket(bufmgr_gem, size + size * 3 / 4); + } +} + +drm_public void +drm_intel_bufmgr_gem_set_vma_cache_size(drm_intel_bufmgr *bufmgr, int limit) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr; + + bufmgr_gem->vma_max = limit; + + drm_intel_gem_bo_purge_vma_cache(bufmgr_gem); +} + +static int +parse_devid_override(const char *devid_override) +{ + static const struct { + const char *name; + int pci_id; + } name_map[] = { + { "brw", PCI_CHIP_I965_GM }, + { "g4x", PCI_CHIP_GM45_GM }, + { "ilk", PCI_CHIP_ILD_G }, + { "snb", PCI_CHIP_SANDYBRIDGE_M_GT2_PLUS }, + { "ivb", PCI_CHIP_IVYBRIDGE_S_GT2 }, + { "hsw", PCI_CHIP_HASWELL_CRW_E_GT3 }, + { "byt", PCI_CHIP_VALLEYVIEW_3 }, + { "bdw", 0x1620 | BDW_ULX }, + { "skl", PCI_CHIP_SKYLAKE_DT_GT2 }, + { "kbl", PCI_CHIP_KABYLAKE_DT_GT2 }, + }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(name_map); i++) { + if (!strcmp(name_map[i].name, devid_override)) + return name_map[i].pci_id; + } + + return strtod(devid_override, NULL); +} + +/** + * Get the PCI ID for the device. This can be overridden by setting the + * INTEL_DEVID_OVERRIDE environment variable to the desired ID. + */ +static int +get_pci_device_id(drm_intel_bufmgr_gem *bufmgr_gem) +{ + char *devid_override; + int devid = 0; + int ret; + drm_i915_getparam_t gp; + + if (geteuid() == getuid()) { + devid_override = getenv("INTEL_DEVID_OVERRIDE"); + if (devid_override) { + bufmgr_gem->no_exec = true; + return parse_devid_override(devid_override); + } + } + + memclear(gp); + gp.param = I915_PARAM_CHIPSET_ID; + gp.value = &devid; + ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp); + if (ret) { + fprintf(stderr, "get chip id failed: %d [%d]\n", ret, errno); + fprintf(stderr, "param: %d, val: %d\n", gp.param, *gp.value); + } + return devid; +} + +drm_public int +drm_intel_bufmgr_gem_get_devid(drm_intel_bufmgr *bufmgr) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr; + + return bufmgr_gem->pci_device; +} + +/** + * Sets the AUB filename. + * + * This function has to be called before drm_intel_bufmgr_gem_set_aub_dump() + * for it to have any effect. + */ +drm_public void +drm_intel_bufmgr_gem_set_aub_filename(drm_intel_bufmgr *bufmgr, + const char *filename) +{ +} + +/** + * Sets up AUB dumping. + * + * This is a trace file format that can be used with the simulator. + * Packets are emitted in a format somewhat like GPU command packets. + * You can set up a GTT and upload your objects into the referenced + * space, then send off batchbuffers and get BMPs out the other end. + */ +drm_public void +drm_intel_bufmgr_gem_set_aub_dump(drm_intel_bufmgr *bufmgr, int enable) +{ + fprintf(stderr, "libdrm aub dumping is deprecated.\n\n" + "Use intel_aubdump from intel-gpu-tools instead. Install intel-gpu-tools,\n" + "then run (for example)\n\n" + "\t$ intel_aubdump --output=trace.aub glxgears -geometry 500x500\n\n" + "See the intel_aubdump man page for more details.\n"); +} + +drm_public drm_intel_context * +drm_intel_gem_context_create(drm_intel_bufmgr *bufmgr) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr; + struct drm_i915_gem_context_create create; + drm_intel_context *context = NULL; + int ret; + + context = calloc(1, sizeof(*context)); + if (!context) + return NULL; + + memclear(create); + ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE, &create); + if (ret != 0) { + DBG("DRM_IOCTL_I915_GEM_CONTEXT_CREATE failed: %s\n", + strerror(errno)); + free(context); + return NULL; + } + + context->ctx_id = create.ctx_id; + context->bufmgr = bufmgr; + + return context; +} + +drm_public int +drm_intel_gem_context_get_id(drm_intel_context *ctx, uint32_t *ctx_id) +{ + if (ctx == NULL) + return -EINVAL; + + *ctx_id = ctx->ctx_id; + + return 0; +} + +drm_public void +drm_intel_gem_context_destroy(drm_intel_context *ctx) +{ + drm_intel_bufmgr_gem *bufmgr_gem; + struct drm_i915_gem_context_destroy destroy; + int ret; + + if (ctx == NULL) + return; + + memclear(destroy); + + bufmgr_gem = (drm_intel_bufmgr_gem *)ctx->bufmgr; + destroy.ctx_id = ctx->ctx_id; + ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_CONTEXT_DESTROY, + &destroy); + if (ret != 0) + fprintf(stderr, "DRM_IOCTL_I915_GEM_CONTEXT_DESTROY failed: %s\n", + strerror(errno)); + + free(ctx); +} + +drm_public int +drm_intel_get_reset_stats(drm_intel_context *ctx, + uint32_t *reset_count, + uint32_t *active, + uint32_t *pending) +{ + drm_intel_bufmgr_gem *bufmgr_gem; + struct drm_i915_reset_stats stats; + int ret; + + if (ctx == NULL) + return -EINVAL; + + memclear(stats); + + bufmgr_gem = (drm_intel_bufmgr_gem *)ctx->bufmgr; + stats.ctx_id = ctx->ctx_id; + ret = drmIoctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GET_RESET_STATS, + &stats); + if (ret == 0) { + if (reset_count != NULL) + *reset_count = stats.reset_count; + + if (active != NULL) + *active = stats.batch_active; + + if (pending != NULL) + *pending = stats.batch_pending; + } + + return ret; +} + +drm_public int +drm_intel_reg_read(drm_intel_bufmgr *bufmgr, + uint32_t offset, + uint64_t *result) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr; + struct drm_i915_reg_read reg_read; + int ret; + + memclear(reg_read); + reg_read.offset = offset; + + ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_REG_READ, ®_read); + + *result = reg_read.val; + return ret; +} + +drm_public int +drm_intel_get_subslice_total(int fd, unsigned int *subslice_total) +{ + drm_i915_getparam_t gp; + int ret; + + memclear(gp); + gp.value = (int*)subslice_total; + gp.param = I915_PARAM_SUBSLICE_TOTAL; + ret = drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp); + if (ret) + return -errno; + + return 0; +} + +drm_public int +drm_intel_get_eu_total(int fd, unsigned int *eu_total) +{ + drm_i915_getparam_t gp; + int ret; + + memclear(gp); + gp.value = (int*)eu_total; + gp.param = I915_PARAM_EU_TOTAL; + ret = drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp); + if (ret) + return -errno; + + return 0; +} + +drm_public int +drm_intel_get_pooled_eu(int fd) +{ + drm_i915_getparam_t gp; + int ret = -1; + + memclear(gp); + gp.param = I915_PARAM_HAS_POOLED_EU; + gp.value = &ret; + if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp)) + return -errno; + + return ret; +} + +drm_public int +drm_intel_get_min_eu_in_pool(int fd) +{ + drm_i915_getparam_t gp; + int ret = -1; + + memclear(gp); + gp.param = I915_PARAM_MIN_EU_IN_POOL; + gp.value = &ret; + if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp)) + return -errno; + + return ret; +} + +/** + * Annotate the given bo for use in aub dumping. + * + * \param annotations is an array of drm_intel_aub_annotation objects + * describing the type of data in various sections of the bo. Each + * element of the array specifies the type and subtype of a section of + * the bo, and the past-the-end offset of that section. The elements + * of \c annotations must be sorted so that ending_offset is + * increasing. + * + * \param count is the number of elements in the \c annotations array. + * If \c count is zero, then \c annotations will not be dereferenced. + * + * Annotations are copied into a private data structure, so caller may + * re-use the memory pointed to by \c annotations after the call + * returns. + * + * Annotations are stored for the lifetime of the bo; to reset to the + * default state (no annotations), call this function with a \c count + * of zero. + */ +drm_public void drm_intel_bufmgr_gem_set_aub_annotations(drm_intel_bo *bo, + drm_intel_aub_annotation *annotations, + unsigned count) +{ +} + +static pthread_mutex_t bufmgr_list_mutex = PTHREAD_MUTEX_INITIALIZER; +static drmMMListHead bufmgr_list = { &bufmgr_list, &bufmgr_list }; + +static drm_intel_bufmgr_gem * +drm_intel_bufmgr_gem_find(int fd) +{ + drm_intel_bufmgr_gem *bufmgr_gem; + + DRMLISTFOREACHENTRY(bufmgr_gem, &bufmgr_list, managers) { + if (bufmgr_gem->fd == fd) { + atomic_inc(&bufmgr_gem->refcount); + return bufmgr_gem; + } + } + + return NULL; +} + +static void +drm_intel_bufmgr_gem_unref(drm_intel_bufmgr *bufmgr) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr; + + if (atomic_add_unless(&bufmgr_gem->refcount, -1, 1)) + return; + + pthread_mutex_lock(&bufmgr_list_mutex); + + if (atomic_dec_and_test(&bufmgr_gem->refcount)) { + DRMLISTDEL(&bufmgr_gem->managers); + drm_intel_bufmgr_gem_destroy(bufmgr); + } + + pthread_mutex_unlock(&bufmgr_list_mutex); +} + +drm_public void *drm_intel_gem_bo_map__gtt(drm_intel_bo *bo) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + + if (bo_gem->gtt_virtual) + return bo_gem->gtt_virtual; + + if (bo_gem->is_userptr) + return NULL; + + pthread_mutex_lock(&bufmgr_gem->lock); + if (bo_gem->gtt_virtual == NULL) { + struct drm_i915_gem_mmap_gtt mmap_arg; + void *ptr; + + DBG("bo_map_gtt: mmap %d (%s), map_count=%d\n", + bo_gem->gem_handle, bo_gem->name, bo_gem->map_count); + + if (bo_gem->map_count++ == 0) + drm_intel_gem_bo_open_vma(bufmgr_gem, bo_gem); + + memclear(mmap_arg); + mmap_arg.handle = bo_gem->gem_handle; + + /* Get the fake offset back... */ + ptr = MAP_FAILED; + if (drmIoctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GEM_MMAP_GTT, + &mmap_arg) == 0) { + /* and mmap it */ + ptr = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, + MAP_SHARED, bufmgr_gem->fd, + mmap_arg.offset); + } + if (ptr == MAP_FAILED) { + if (--bo_gem->map_count == 0) + drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem); + ptr = NULL; + } + + bo_gem->gtt_virtual = ptr; + } + pthread_mutex_unlock(&bufmgr_gem->lock); + + return bo_gem->gtt_virtual; +} + +drm_public void *drm_intel_gem_bo_map__cpu(drm_intel_bo *bo) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + + if (bo_gem->mem_virtual) + return bo_gem->mem_virtual; + + if (bo_gem->is_userptr) { + /* Return the same user ptr */ + return bo_gem->user_virtual; + } + + pthread_mutex_lock(&bufmgr_gem->lock); + if (!bo_gem->mem_virtual) { + struct drm_i915_gem_mmap mmap_arg; + + if (bo_gem->map_count++ == 0) + drm_intel_gem_bo_open_vma(bufmgr_gem, bo_gem); + + DBG("bo_map: %d (%s), map_count=%d\n", + bo_gem->gem_handle, bo_gem->name, bo_gem->map_count); + + memclear(mmap_arg); + mmap_arg.handle = bo_gem->gem_handle; + mmap_arg.size = bo->size; + if (drmIoctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GEM_MMAP, + &mmap_arg)) { + DBG("%s:%d: Error mapping buffer %d (%s): %s .\n", + __FILE__, __LINE__, bo_gem->gem_handle, + bo_gem->name, strerror(errno)); + if (--bo_gem->map_count == 0) + drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem); + } else { + VG(VALGRIND_MALLOCLIKE_BLOCK(mmap_arg.addr_ptr, mmap_arg.size, 0, 1)); + bo_gem->mem_virtual = (void *)(uintptr_t) mmap_arg.addr_ptr; + } + } + pthread_mutex_unlock(&bufmgr_gem->lock); + + return bo_gem->mem_virtual; +} + +drm_public void *drm_intel_gem_bo_map__wc(drm_intel_bo *bo) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + + if (bo_gem->wc_virtual) + return bo_gem->wc_virtual; + + if (bo_gem->is_userptr) + return NULL; + + pthread_mutex_lock(&bufmgr_gem->lock); + if (!bo_gem->wc_virtual) { + struct drm_i915_gem_mmap mmap_arg; + + if (bo_gem->map_count++ == 0) + drm_intel_gem_bo_open_vma(bufmgr_gem, bo_gem); + + DBG("bo_map: %d (%s), map_count=%d\n", + bo_gem->gem_handle, bo_gem->name, bo_gem->map_count); + + memclear(mmap_arg); + mmap_arg.handle = bo_gem->gem_handle; + mmap_arg.size = bo->size; + mmap_arg.flags = I915_MMAP_WC; + if (drmIoctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GEM_MMAP, + &mmap_arg)) { + DBG("%s:%d: Error mapping buffer %d (%s): %s .\n", + __FILE__, __LINE__, bo_gem->gem_handle, + bo_gem->name, strerror(errno)); + if (--bo_gem->map_count == 0) + drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem); + } else { + VG(VALGRIND_MALLOCLIKE_BLOCK(mmap_arg.addr_ptr, mmap_arg.size, 0, 1)); + bo_gem->wc_virtual = (void *)(uintptr_t) mmap_arg.addr_ptr; + } + } + pthread_mutex_unlock(&bufmgr_gem->lock); + + return bo_gem->wc_virtual; +} + +/** + * Initializes the GEM buffer manager, which uses the kernel to allocate, map, + * and manage map buffer objections. + * + * \param fd File descriptor of the opened DRM device. + */ +drm_public drm_intel_bufmgr * +drm_intel_bufmgr_gem_init(int fd, int batch_size) +{ + drm_intel_bufmgr_gem *bufmgr_gem; + struct drm_i915_gem_get_aperture aperture; + drm_i915_getparam_t gp; + int ret, tmp; + + pthread_mutex_lock(&bufmgr_list_mutex); + + bufmgr_gem = drm_intel_bufmgr_gem_find(fd); + if (bufmgr_gem) + goto exit; + + bufmgr_gem = calloc(1, sizeof(*bufmgr_gem)); + if (bufmgr_gem == NULL) + goto exit; + + bufmgr_gem->fd = fd; + atomic_set(&bufmgr_gem->refcount, 1); + + if (pthread_mutex_init(&bufmgr_gem->lock, NULL) != 0) { + free(bufmgr_gem); + bufmgr_gem = NULL; + goto exit; + } + + memclear(aperture); + ret = drmIoctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GEM_GET_APERTURE, + &aperture); + + if (ret == 0) + bufmgr_gem->gtt_size = aperture.aper_available_size; + else { + fprintf(stderr, "DRM_IOCTL_I915_GEM_APERTURE failed: %s\n", + strerror(errno)); + bufmgr_gem->gtt_size = 128 * 1024 * 1024; + fprintf(stderr, "Assuming %dkB available aperture size.\n" + "May lead to reduced performance or incorrect " + "rendering.\n", + (int)bufmgr_gem->gtt_size / 1024); + } + + bufmgr_gem->pci_device = get_pci_device_id(bufmgr_gem); + + if (IS_GEN2(bufmgr_gem->pci_device)) + bufmgr_gem->gen = 2; + else if (IS_GEN3(bufmgr_gem->pci_device)) + bufmgr_gem->gen = 3; + else if (IS_GEN4(bufmgr_gem->pci_device)) + bufmgr_gem->gen = 4; + else if (IS_GEN5(bufmgr_gem->pci_device)) + bufmgr_gem->gen = 5; + else if (IS_GEN6(bufmgr_gem->pci_device)) + bufmgr_gem->gen = 6; + else if (IS_GEN7(bufmgr_gem->pci_device)) + bufmgr_gem->gen = 7; + else if (IS_GEN8(bufmgr_gem->pci_device)) + bufmgr_gem->gen = 8; + else if (!intel_get_genx(bufmgr_gem->pci_device, &bufmgr_gem->gen)) { + free(bufmgr_gem); + bufmgr_gem = NULL; + goto exit; + } + + if (IS_GEN3(bufmgr_gem->pci_device) && + bufmgr_gem->gtt_size > 256*1024*1024) { + /* The unmappable part of gtt on gen 3 (i.e. above 256MB) can't + * be used for tiled blits. To simplify the accounting, just + * subtract the unmappable part (fixed to 256MB on all known + * gen3 devices) if the kernel advertises it. */ + bufmgr_gem->gtt_size -= 256*1024*1024; + } + + memclear(gp); + gp.value = &tmp; + + gp.param = I915_PARAM_HAS_EXECBUF2; + ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp); + if (ret) { + fprintf(stderr, "i915 does not support EXECBUFER2\n"); + free(bufmgr_gem); + bufmgr_gem = NULL; + goto exit; + } + + gp.param = I915_PARAM_HAS_BSD; + ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp); + bufmgr_gem->has_bsd = ret == 0; + + gp.param = I915_PARAM_HAS_BLT; + ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp); + bufmgr_gem->has_blt = ret == 0; + + gp.param = I915_PARAM_HAS_RELAXED_FENCING; + ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp); + bufmgr_gem->has_relaxed_fencing = ret == 0; + + gp.param = I915_PARAM_HAS_EXEC_ASYNC; + ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp); + bufmgr_gem->has_exec_async = ret == 0; + + bufmgr_gem->bufmgr.bo_alloc_userptr = check_bo_alloc_userptr; + + gp.param = I915_PARAM_HAS_WAIT_TIMEOUT; + ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp); + bufmgr_gem->has_wait_timeout = ret == 0; + + gp.param = I915_PARAM_HAS_LLC; + ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp); + if (ret != 0) { + /* Kernel does not supports HAS_LLC query, fallback to GPU + * generation detection and assume that we have LLC on GEN6/7 + */ + bufmgr_gem->has_llc = (IS_GEN6(bufmgr_gem->pci_device) | + IS_GEN7(bufmgr_gem->pci_device)); + } else + bufmgr_gem->has_llc = *gp.value; + + gp.param = I915_PARAM_HAS_VEBOX; + ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp); + bufmgr_gem->has_vebox = (ret == 0) & (*gp.value > 0); + + gp.param = I915_PARAM_HAS_EXEC_SOFTPIN; + ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp); + if (ret == 0 && *gp.value > 0) + bufmgr_gem->bufmgr.bo_set_softpin_offset = drm_intel_gem_bo_set_softpin_offset; + + if (bufmgr_gem->gen < 4) { + gp.param = I915_PARAM_NUM_FENCES_AVAIL; + gp.value = &bufmgr_gem->available_fences; + ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp); + if (ret) { + fprintf(stderr, "get fences failed: %d [%d]\n", ret, + errno); + fprintf(stderr, "param: %d, val: %d\n", gp.param, + *gp.value); + bufmgr_gem->available_fences = 0; + } else { + /* XXX The kernel reports the total number of fences, + * including any that may be pinned. + * + * We presume that there will be at least one pinned + * fence for the scanout buffer, but there may be more + * than one scanout and the user may be manually + * pinning buffers. Let's move to execbuffer2 and + * thereby forget the insanity of using fences... + */ + bufmgr_gem->available_fences -= 2; + if (bufmgr_gem->available_fences < 0) + bufmgr_gem->available_fences = 0; + } + } + + if (bufmgr_gem->gen >= 8) { + gp.param = I915_PARAM_HAS_ALIASING_PPGTT; + ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp); + if (ret == 0 && *gp.value == 3) + bufmgr_gem->bufmgr.bo_use_48b_address_range = drm_intel_gem_bo_use_48b_address_range; + } + + /* Let's go with one relocation per every 2 dwords (but round down a bit + * since a power of two will mean an extra page allocation for the reloc + * buffer). + * + * Every 4 was too few for the blender benchmark. + */ + bufmgr_gem->max_relocs = batch_size / sizeof(uint32_t) / 2 - 2; + + bufmgr_gem->bufmgr.bo_alloc = drm_intel_gem_bo_alloc; + bufmgr_gem->bufmgr.bo_alloc_for_render = + drm_intel_gem_bo_alloc_for_render; + bufmgr_gem->bufmgr.bo_alloc_tiled = drm_intel_gem_bo_alloc_tiled; + bufmgr_gem->bufmgr.bo_reference = drm_intel_gem_bo_reference; + bufmgr_gem->bufmgr.bo_unreference = drm_intel_gem_bo_unreference; + bufmgr_gem->bufmgr.bo_map = drm_intel_gem_bo_map; + bufmgr_gem->bufmgr.bo_unmap = drm_intel_gem_bo_unmap; + bufmgr_gem->bufmgr.bo_subdata = drm_intel_gem_bo_subdata; + bufmgr_gem->bufmgr.bo_get_subdata = drm_intel_gem_bo_get_subdata; + bufmgr_gem->bufmgr.bo_wait_rendering = drm_intel_gem_bo_wait_rendering; + bufmgr_gem->bufmgr.bo_emit_reloc = drm_intel_gem_bo_emit_reloc; + bufmgr_gem->bufmgr.bo_emit_reloc_fence = drm_intel_gem_bo_emit_reloc_fence; + bufmgr_gem->bufmgr.bo_pin = drm_intel_gem_bo_pin; + bufmgr_gem->bufmgr.bo_unpin = drm_intel_gem_bo_unpin; + bufmgr_gem->bufmgr.bo_get_tiling = drm_intel_gem_bo_get_tiling; + bufmgr_gem->bufmgr.bo_set_tiling = drm_intel_gem_bo_set_tiling; + bufmgr_gem->bufmgr.bo_flink = drm_intel_gem_bo_flink; + bufmgr_gem->bufmgr.bo_exec = drm_intel_gem_bo_exec2; + bufmgr_gem->bufmgr.bo_mrb_exec = drm_intel_gem_bo_mrb_exec2; + bufmgr_gem->bufmgr.bo_busy = drm_intel_gem_bo_busy; + bufmgr_gem->bufmgr.bo_madvise = drm_intel_gem_bo_madvise; + bufmgr_gem->bufmgr.destroy = drm_intel_bufmgr_gem_unref; + bufmgr_gem->bufmgr.debug = 0; + bufmgr_gem->bufmgr.check_aperture_space = + drm_intel_gem_check_aperture_space; + bufmgr_gem->bufmgr.bo_disable_reuse = drm_intel_gem_bo_disable_reuse; + bufmgr_gem->bufmgr.bo_is_reusable = drm_intel_gem_bo_is_reusable; + bufmgr_gem->bufmgr.get_pipe_from_crtc_id = + drm_intel_gem_get_pipe_from_crtc_id; + bufmgr_gem->bufmgr.bo_references = drm_intel_gem_bo_references; + + init_cache_buckets(bufmgr_gem); + + DRMINITLISTHEAD(&bufmgr_gem->vma_cache); + bufmgr_gem->vma_max = -1; /* unlimited by default */ + + DRMLISTADD(&bufmgr_gem->managers, &bufmgr_list); + +exit: + pthread_mutex_unlock(&bufmgr_list_mutex); + + return bufmgr_gem != NULL ? &bufmgr_gem->bufmgr : NULL; +} diff --git a/intel/intel_bufmgr_priv.h b/intel/intel_bufmgr_priv.h new file mode 100644 index 0000000..baaf4bb --- /dev/null +++ b/intel/intel_bufmgr_priv.h @@ -0,0 +1,325 @@ +/* + * Copyright © 2008 Intel Corporation + * + * 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 (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 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. + * + * Authors: + * Eric Anholt + * + */ + +/** + * @file intel_bufmgr_priv.h + * + * Private definitions of Intel-specific bufmgr functions and structures. + */ + +#ifndef INTEL_BUFMGR_PRIV_H +#define INTEL_BUFMGR_PRIV_H + +/** + * Context for a buffer manager instance. + * + * Contains public methods followed by private storage for the buffer manager. + */ +struct _drm_intel_bufmgr { + /** + * Allocate a buffer object. + * + * Buffer objects are not necessarily initially mapped into CPU virtual + * address space or graphics device aperture. They must be mapped + * using bo_map() or drm_intel_gem_bo_map_gtt() to be used by the CPU. + */ + drm_intel_bo *(*bo_alloc) (drm_intel_bufmgr *bufmgr, const char *name, + unsigned long size, unsigned int alignment); + + /** + * Allocate a buffer object, hinting that it will be used as a + * render target. + * + * This is otherwise the same as bo_alloc. + */ + drm_intel_bo *(*bo_alloc_for_render) (drm_intel_bufmgr *bufmgr, + const char *name, + unsigned long size, + unsigned int alignment); + + /** + * Allocate a buffer object from an existing user accessible + * address malloc'd with the provided size. + * Alignment is used when mapping to the gtt. + * Flags may be I915_VMAP_READ_ONLY or I915_USERPTR_UNSYNCHRONIZED + */ + drm_intel_bo *(*bo_alloc_userptr)(drm_intel_bufmgr *bufmgr, + const char *name, void *addr, + uint32_t tiling_mode, uint32_t stride, + unsigned long size, + unsigned long flags); + + /** + * Allocate a tiled buffer object. + * + * Alignment for tiled objects is set automatically; the 'flags' + * argument provides a hint about how the object will be used initially. + * + * Valid tiling formats are: + * I915_TILING_NONE + * I915_TILING_X + * I915_TILING_Y + * + * Note the tiling format may be rejected; callers should check the + * 'tiling_mode' field on return, as well as the pitch value, which + * may have been rounded up to accommodate for tiling restrictions. + */ + drm_intel_bo *(*bo_alloc_tiled) (drm_intel_bufmgr *bufmgr, + const char *name, + int x, int y, int cpp, + uint32_t *tiling_mode, + unsigned long *pitch, + unsigned long flags); + + /** Takes a reference on a buffer object */ + void (*bo_reference) (drm_intel_bo *bo); + + /** + * Releases a reference on a buffer object, freeing the data if + * no references remain. + */ + void (*bo_unreference) (drm_intel_bo *bo); + + /** + * Maps the buffer into userspace. + * + * This function will block waiting for any existing execution on the + * buffer to complete, first. The resulting mapping is available at + * buf->virtual. + */ + int (*bo_map) (drm_intel_bo *bo, int write_enable); + + /** + * Reduces the refcount on the userspace mapping of the buffer + * object. + */ + int (*bo_unmap) (drm_intel_bo *bo); + + /** + * Write data into an object. + * + * This is an optional function, if missing, + * drm_intel_bo will map/memcpy/unmap. + */ + int (*bo_subdata) (drm_intel_bo *bo, unsigned long offset, + unsigned long size, const void *data); + + /** + * Read data from an object + * + * This is an optional function, if missing, + * drm_intel_bo will map/memcpy/unmap. + */ + int (*bo_get_subdata) (drm_intel_bo *bo, unsigned long offset, + unsigned long size, void *data); + + /** + * Waits for rendering to an object by the GPU to have completed. + * + * This is not required for any access to the BO by bo_map, + * bo_subdata, etc. It is merely a way for the driver to implement + * glFinish. + */ + void (*bo_wait_rendering) (drm_intel_bo *bo); + + /** + * Tears down the buffer manager instance. + */ + void (*destroy) (drm_intel_bufmgr *bufmgr); + + /** + * Indicate if the buffer can be placed anywhere in the full ppgtt + * address range (2^48). + * + * Any resource used with flat/heapless (0x00000000-0xfffff000) + * General State Heap (GSH) or Instructions State Heap (ISH) must + * be in a 32-bit range. 48-bit range will only be used when explicitly + * requested. + * + * \param bo Buffer to set the use_48b_address_range flag. + * \param enable The flag value. + */ + void (*bo_use_48b_address_range) (drm_intel_bo *bo, uint32_t enable); + + /** + * Add relocation entry in reloc_buf, which will be updated with the + * target buffer's real offset on on command submission. + * + * Relocations remain in place for the lifetime of the buffer object. + * + * \param bo Buffer to write the relocation into. + * \param offset Byte offset within reloc_bo of the pointer to + * target_bo. + * \param target_bo Buffer whose offset should be written into the + * relocation entry. + * \param target_offset Constant value to be added to target_bo's + * offset in relocation entry. + * \param read_domains GEM read domains which the buffer will be + * read into by the command that this relocation + * is part of. + * \param write_domains GEM read domains which the buffer will be + * dirtied in by the command that this + * relocation is part of. + */ + int (*bo_emit_reloc) (drm_intel_bo *bo, uint32_t offset, + drm_intel_bo *target_bo, uint32_t target_offset, + uint32_t read_domains, uint32_t write_domain); + int (*bo_emit_reloc_fence)(drm_intel_bo *bo, uint32_t offset, + drm_intel_bo *target_bo, + uint32_t target_offset, + uint32_t read_domains, + uint32_t write_domain); + + /** Executes the command buffer pointed to by bo. */ + int (*bo_exec) (drm_intel_bo *bo, int used, + drm_clip_rect_t *cliprects, int num_cliprects, + int DR4); + + /** Executes the command buffer pointed to by bo on the selected + * ring buffer + */ + int (*bo_mrb_exec) (drm_intel_bo *bo, int used, + drm_clip_rect_t *cliprects, int num_cliprects, + int DR4, unsigned flags); + + /** + * Pin a buffer to the aperture and fix the offset until unpinned + * + * \param buf Buffer to pin + * \param alignment Required alignment for aperture, in bytes + */ + int (*bo_pin) (drm_intel_bo *bo, uint32_t alignment); + + /** + * Unpin a buffer from the aperture, allowing it to be removed + * + * \param buf Buffer to unpin + */ + int (*bo_unpin) (drm_intel_bo *bo); + + /** + * Ask that the buffer be placed in tiling mode + * + * \param buf Buffer to set tiling mode for + * \param tiling_mode desired, and returned tiling mode + */ + int (*bo_set_tiling) (drm_intel_bo *bo, uint32_t * tiling_mode, + uint32_t stride); + + /** + * Get the current tiling (and resulting swizzling) mode for the bo. + * + * \param buf Buffer to get tiling mode for + * \param tiling_mode returned tiling mode + * \param swizzle_mode returned swizzling mode + */ + int (*bo_get_tiling) (drm_intel_bo *bo, uint32_t * tiling_mode, + uint32_t * swizzle_mode); + + /** + * Set the offset at which this buffer will be softpinned + * \param bo Buffer to set the softpin offset for + * \param offset Softpin offset + */ + int (*bo_set_softpin_offset) (drm_intel_bo *bo, uint64_t offset); + + /** + * Create a visible name for a buffer which can be used by other apps + * + * \param buf Buffer to create a name for + * \param name Returned name + */ + int (*bo_flink) (drm_intel_bo *bo, uint32_t * name); + + /** + * Returns 1 if mapping the buffer for write could cause the process + * to block, due to the object being active in the GPU. + */ + int (*bo_busy) (drm_intel_bo *bo); + + /** + * Specify the volatility of the buffer. + * \param bo Buffer to create a name for + * \param madv The purgeable status + * + * Use I915_MADV_DONTNEED to mark the buffer as purgeable, and it will be + * reclaimed under memory pressure. If you subsequently require the buffer, + * then you must pass I915_MADV_WILLNEED to mark the buffer as required. + * + * Returns 1 if the buffer was retained, or 0 if it was discarded whilst + * marked as I915_MADV_DONTNEED. + */ + int (*bo_madvise) (drm_intel_bo *bo, int madv); + + int (*check_aperture_space) (drm_intel_bo ** bo_array, int count); + + /** + * Disable buffer reuse for buffers which will be shared in some way, + * as with scanout buffers. When the buffer reference count goes to + * zero, it will be freed and not placed in the reuse list. + * + * \param bo Buffer to disable reuse for + */ + int (*bo_disable_reuse) (drm_intel_bo *bo); + + /** + * Query whether a buffer is reusable. + * + * \param bo Buffer to query + */ + int (*bo_is_reusable) (drm_intel_bo *bo); + + /** + * + * Return the pipe associated with a crtc_id so that vblank + * synchronization can use the correct data in the request. + * This is only supported for KMS and gem at this point, when + * unsupported, this function returns -1 and leaves the decision + * of what to do in that case to the caller + * + * \param bufmgr the associated buffer manager + * \param crtc_id the crtc identifier + */ + int (*get_pipe_from_crtc_id) (drm_intel_bufmgr *bufmgr, int crtc_id); + + /** Returns true if target_bo is in the relocation tree rooted at bo. */ + int (*bo_references) (drm_intel_bo *bo, drm_intel_bo *target_bo); + + /**< Enables verbose debugging printouts */ + int debug; +}; + +struct _drm_intel_context { + unsigned int ctx_id; + struct _drm_intel_bufmgr *bufmgr; +}; + +#define ALIGN(value, alignment) ((value + alignment - 1) & ~(alignment - 1)) +#define ROUND_UP_TO(x, y) (((x) + (y) - 1) / (y) * (y)) +#define ROUND_UP_TO_MB(x) ROUND_UP_TO((x), 1024*1024) + +#endif /* INTEL_BUFMGR_PRIV_H */ diff --git a/intel/intel_chipset.c b/intel/intel_chipset.c new file mode 100644 index 0000000..76b1940 --- /dev/null +++ b/intel/intel_chipset.c @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2018 Intel Corporation + * + * 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 (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 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. + */ +#include "intel_chipset.h" + +#include +#include + +#include "i915_pciids.h" + +#undef INTEL_VGA_DEVICE +#define INTEL_VGA_DEVICE(id, gen) { id, gen } + +static const struct pci_device { + uint16_t device; + uint16_t gen; +} pciids[] = { + /* Keep ids sorted by gen; latest gen first */ + INTEL_MTL_IDS(12), + INTEL_ATS_M_IDS(12), + INTEL_DG2_IDS(12), + INTEL_ADLN_IDS(12), + INTEL_RPLP_IDS(12), + INTEL_ADLP_IDS(12), + INTEL_RPLS_IDS(12), + INTEL_ADLS_IDS(12), + INTEL_RKL_IDS(12), + INTEL_DG1_IDS(12), + INTEL_TGL_12_IDS(12), + INTEL_JSL_IDS(11), + INTEL_EHL_IDS(11), + INTEL_ICL_11_IDS(11), + INTEL_CNL_IDS(10), + INTEL_CFL_IDS(9), + INTEL_GLK_IDS(9), + INTEL_KBL_IDS(9), + INTEL_BXT_IDS(9), + INTEL_SKL_IDS(9), +}; + +drm_private bool intel_is_genx(unsigned int devid, int gen) +{ + const struct pci_device *p, + *pend = pciids + sizeof(pciids) / sizeof(pciids[0]); + + for (p = pciids; p < pend; p++) { + /* PCI IDs are sorted */ + if (p->gen < gen) + break; + + if (p->device != devid) + continue; + + if (gen == p->gen) + return true; + + break; + } + + return false; +} + +drm_private bool intel_get_genx(unsigned int devid, int *gen) +{ + const struct pci_device *p, + *pend = pciids + sizeof(pciids) / sizeof(pciids[0]); + + for (p = pciids; p < pend; p++) { + if (p->device != devid) + continue; + + if (gen) + *gen = p->gen; + + return true; + } + + return false; +} diff --git a/intel/intel_chipset.h b/intel/intel_chipset.h new file mode 100644 index 0000000..0a48e0d --- /dev/null +++ b/intel/intel_chipset.h @@ -0,0 +1,350 @@ +/* + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 TUNGSTEN GRAPHICS 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 _INTEL_CHIPSET_H +#define _INTEL_CHIPSET_H + +#define PCI_CHIP_I810 0x7121 +#define PCI_CHIP_I810_DC100 0x7123 +#define PCI_CHIP_I810_E 0x7125 +#define PCI_CHIP_I815 0x1132 + +#define PCI_CHIP_I830_M 0x3577 +#define PCI_CHIP_845_G 0x2562 +#define PCI_CHIP_I855_GM 0x3582 +#define PCI_CHIP_I865_G 0x2572 + +#define PCI_CHIP_I915_G 0x2582 +#define PCI_CHIP_E7221_G 0x258A +#define PCI_CHIP_I915_GM 0x2592 +#define PCI_CHIP_I945_G 0x2772 +#define PCI_CHIP_I945_GM 0x27A2 +#define PCI_CHIP_I945_GME 0x27AE + +#define PCI_CHIP_Q35_G 0x29B2 +#define PCI_CHIP_G33_G 0x29C2 +#define PCI_CHIP_Q33_G 0x29D2 + +#define PCI_CHIP_IGD_GM 0xA011 +#define PCI_CHIP_IGD_G 0xA001 + +#define IS_IGDGM(devid) ((devid) == PCI_CHIP_IGD_GM) +#define IS_IGDG(devid) ((devid) == PCI_CHIP_IGD_G) +#define IS_IGD(devid) (IS_IGDG(devid) || IS_IGDGM(devid)) + +#define PCI_CHIP_I965_G 0x29A2 +#define PCI_CHIP_I965_Q 0x2992 +#define PCI_CHIP_I965_G_1 0x2982 +#define PCI_CHIP_I946_GZ 0x2972 +#define PCI_CHIP_I965_GM 0x2A02 +#define PCI_CHIP_I965_GME 0x2A12 + +#define PCI_CHIP_GM45_GM 0x2A42 + +#define PCI_CHIP_IGD_E_G 0x2E02 +#define PCI_CHIP_Q45_G 0x2E12 +#define PCI_CHIP_G45_G 0x2E22 +#define PCI_CHIP_G41_G 0x2E32 + +#define PCI_CHIP_ILD_G 0x0042 +#define PCI_CHIP_ILM_G 0x0046 + +#define PCI_CHIP_SANDYBRIDGE_GT1 0x0102 /* desktop */ +#define PCI_CHIP_SANDYBRIDGE_GT2 0x0112 +#define PCI_CHIP_SANDYBRIDGE_GT2_PLUS 0x0122 +#define PCI_CHIP_SANDYBRIDGE_M_GT1 0x0106 /* mobile */ +#define PCI_CHIP_SANDYBRIDGE_M_GT2 0x0116 +#define PCI_CHIP_SANDYBRIDGE_M_GT2_PLUS 0x0126 +#define PCI_CHIP_SANDYBRIDGE_S 0x010A /* server */ + +#define PCI_CHIP_IVYBRIDGE_GT1 0x0152 /* desktop */ +#define PCI_CHIP_IVYBRIDGE_GT2 0x0162 +#define PCI_CHIP_IVYBRIDGE_M_GT1 0x0156 /* mobile */ +#define PCI_CHIP_IVYBRIDGE_M_GT2 0x0166 +#define PCI_CHIP_IVYBRIDGE_S 0x015a /* server */ +#define PCI_CHIP_IVYBRIDGE_S_GT2 0x016a /* server */ + +#define PCI_CHIP_HASWELL_GT1 0x0402 /* Desktop */ +#define PCI_CHIP_HASWELL_GT2 0x0412 +#define PCI_CHIP_HASWELL_GT3 0x0422 +#define PCI_CHIP_HASWELL_M_GT1 0x0406 /* Mobile */ +#define PCI_CHIP_HASWELL_M_GT2 0x0416 +#define PCI_CHIP_HASWELL_M_GT3 0x0426 +#define PCI_CHIP_HASWELL_S_GT1 0x040A /* Server */ +#define PCI_CHIP_HASWELL_S_GT2 0x041A +#define PCI_CHIP_HASWELL_S_GT3 0x042A +#define PCI_CHIP_HASWELL_B_GT1 0x040B /* Reserved */ +#define PCI_CHIP_HASWELL_B_GT2 0x041B +#define PCI_CHIP_HASWELL_B_GT3 0x042B +#define PCI_CHIP_HASWELL_E_GT1 0x040E /* Reserved */ +#define PCI_CHIP_HASWELL_E_GT2 0x041E +#define PCI_CHIP_HASWELL_E_GT3 0x042E +#define PCI_CHIP_HASWELL_SDV_GT1 0x0C02 /* Desktop */ +#define PCI_CHIP_HASWELL_SDV_GT2 0x0C12 +#define PCI_CHIP_HASWELL_SDV_GT3 0x0C22 +#define PCI_CHIP_HASWELL_SDV_M_GT1 0x0C06 /* Mobile */ +#define PCI_CHIP_HASWELL_SDV_M_GT2 0x0C16 +#define PCI_CHIP_HASWELL_SDV_M_GT3 0x0C26 +#define PCI_CHIP_HASWELL_SDV_S_GT1 0x0C0A /* Server */ +#define PCI_CHIP_HASWELL_SDV_S_GT2 0x0C1A +#define PCI_CHIP_HASWELL_SDV_S_GT3 0x0C2A +#define PCI_CHIP_HASWELL_SDV_B_GT1 0x0C0B /* Reserved */ +#define PCI_CHIP_HASWELL_SDV_B_GT2 0x0C1B +#define PCI_CHIP_HASWELL_SDV_B_GT3 0x0C2B +#define PCI_CHIP_HASWELL_SDV_E_GT1 0x0C0E /* Reserved */ +#define PCI_CHIP_HASWELL_SDV_E_GT2 0x0C1E +#define PCI_CHIP_HASWELL_SDV_E_GT3 0x0C2E +#define PCI_CHIP_HASWELL_ULT_GT1 0x0A02 /* Desktop */ +#define PCI_CHIP_HASWELL_ULT_GT2 0x0A12 +#define PCI_CHIP_HASWELL_ULT_GT3 0x0A22 +#define PCI_CHIP_HASWELL_ULT_M_GT1 0x0A06 /* Mobile */ +#define PCI_CHIP_HASWELL_ULT_M_GT2 0x0A16 +#define PCI_CHIP_HASWELL_ULT_M_GT3 0x0A26 +#define PCI_CHIP_HASWELL_ULT_S_GT1 0x0A0A /* Server */ +#define PCI_CHIP_HASWELL_ULT_S_GT2 0x0A1A +#define PCI_CHIP_HASWELL_ULT_S_GT3 0x0A2A +#define PCI_CHIP_HASWELL_ULT_B_GT1 0x0A0B /* Reserved */ +#define PCI_CHIP_HASWELL_ULT_B_GT2 0x0A1B +#define PCI_CHIP_HASWELL_ULT_B_GT3 0x0A2B +#define PCI_CHIP_HASWELL_ULT_E_GT1 0x0A0E /* Reserved */ +#define PCI_CHIP_HASWELL_ULT_E_GT2 0x0A1E +#define PCI_CHIP_HASWELL_ULT_E_GT3 0x0A2E +#define PCI_CHIP_HASWELL_CRW_GT1 0x0D02 /* Desktop */ +#define PCI_CHIP_HASWELL_CRW_GT2 0x0D12 +#define PCI_CHIP_HASWELL_CRW_GT3 0x0D22 +#define PCI_CHIP_HASWELL_CRW_M_GT1 0x0D06 /* Mobile */ +#define PCI_CHIP_HASWELL_CRW_M_GT2 0x0D16 +#define PCI_CHIP_HASWELL_CRW_M_GT3 0x0D26 +#define PCI_CHIP_HASWELL_CRW_S_GT1 0x0D0A /* Server */ +#define PCI_CHIP_HASWELL_CRW_S_GT2 0x0D1A +#define PCI_CHIP_HASWELL_CRW_S_GT3 0x0D2A +#define PCI_CHIP_HASWELL_CRW_B_GT1 0x0D0B /* Reserved */ +#define PCI_CHIP_HASWELL_CRW_B_GT2 0x0D1B +#define PCI_CHIP_HASWELL_CRW_B_GT3 0x0D2B +#define PCI_CHIP_HASWELL_CRW_E_GT1 0x0D0E /* Reserved */ +#define PCI_CHIP_HASWELL_CRW_E_GT2 0x0D1E +#define PCI_CHIP_HASWELL_CRW_E_GT3 0x0D2E +#define BDW_SPARE 0x2 +#define BDW_ULT 0x6 +#define BDW_SERVER 0xa +#define BDW_IRIS 0xb +#define BDW_WORKSTATION 0xd +#define BDW_ULX 0xe + +#define PCI_CHIP_VALLEYVIEW_PO 0x0f30 /* VLV PO board */ +#define PCI_CHIP_VALLEYVIEW_1 0x0f31 +#define PCI_CHIP_VALLEYVIEW_2 0x0f32 +#define PCI_CHIP_VALLEYVIEW_3 0x0f33 + +#define PCI_CHIP_CHERRYVIEW_0 0x22b0 +#define PCI_CHIP_CHERRYVIEW_1 0x22b1 +#define PCI_CHIP_CHERRYVIEW_2 0x22b2 +#define PCI_CHIP_CHERRYVIEW_3 0x22b3 + +#define PCI_CHIP_SKYLAKE_DT_GT2 0x1912 +#define PCI_CHIP_KABYLAKE_DT_GT2 0x5912 + +#define IS_MOBILE(devid) ((devid) == PCI_CHIP_I855_GM || \ + (devid) == PCI_CHIP_I915_GM || \ + (devid) == PCI_CHIP_I945_GM || \ + (devid) == PCI_CHIP_I945_GME || \ + (devid) == PCI_CHIP_I965_GM || \ + (devid) == PCI_CHIP_I965_GME || \ + (devid) == PCI_CHIP_GM45_GM || IS_IGD(devid) || \ + (devid) == PCI_CHIP_IVYBRIDGE_M_GT1 || \ + (devid) == PCI_CHIP_IVYBRIDGE_M_GT2) + +#define IS_G45(devid) ((devid) == PCI_CHIP_IGD_E_G || \ + (devid) == PCI_CHIP_Q45_G || \ + (devid) == PCI_CHIP_G45_G || \ + (devid) == PCI_CHIP_G41_G) +#define IS_GM45(devid) ((devid) == PCI_CHIP_GM45_GM) +#define IS_G4X(devid) (IS_G45(devid) || IS_GM45(devid)) + +#define IS_ILD(devid) ((devid) == PCI_CHIP_ILD_G) +#define IS_ILM(devid) ((devid) == PCI_CHIP_ILM_G) + +#define IS_915(devid) ((devid) == PCI_CHIP_I915_G || \ + (devid) == PCI_CHIP_E7221_G || \ + (devid) == PCI_CHIP_I915_GM) + +#define IS_945GM(devid) ((devid) == PCI_CHIP_I945_GM || \ + (devid) == PCI_CHIP_I945_GME) + +#define IS_945(devid) ((devid) == PCI_CHIP_I945_G || \ + (devid) == PCI_CHIP_I945_GM || \ + (devid) == PCI_CHIP_I945_GME || \ + IS_G33(devid)) + +#define IS_G33(devid) ((devid) == PCI_CHIP_G33_G || \ + (devid) == PCI_CHIP_Q33_G || \ + (devid) == PCI_CHIP_Q35_G || IS_IGD(devid)) + +#define IS_GEN2(devid) ((devid) == PCI_CHIP_I830_M || \ + (devid) == PCI_CHIP_845_G || \ + (devid) == PCI_CHIP_I855_GM || \ + (devid) == PCI_CHIP_I865_G) + +#define IS_GEN3(devid) (IS_945(devid) || IS_915(devid)) + +#define IS_GEN4(devid) ((devid) == PCI_CHIP_I965_G || \ + (devid) == PCI_CHIP_I965_Q || \ + (devid) == PCI_CHIP_I965_G_1 || \ + (devid) == PCI_CHIP_I965_GM || \ + (devid) == PCI_CHIP_I965_GME || \ + (devid) == PCI_CHIP_I946_GZ || \ + IS_G4X(devid)) + +#define IS_GEN5(devid) (IS_ILD(devid) || IS_ILM(devid)) + +#define IS_GEN6(devid) ((devid) == PCI_CHIP_SANDYBRIDGE_GT1 || \ + (devid) == PCI_CHIP_SANDYBRIDGE_GT2 || \ + (devid) == PCI_CHIP_SANDYBRIDGE_GT2_PLUS || \ + (devid) == PCI_CHIP_SANDYBRIDGE_M_GT1 || \ + (devid) == PCI_CHIP_SANDYBRIDGE_M_GT2 || \ + (devid) == PCI_CHIP_SANDYBRIDGE_M_GT2_PLUS || \ + (devid) == PCI_CHIP_SANDYBRIDGE_S) + +#define IS_GEN7(devid) (IS_IVYBRIDGE(devid) || \ + IS_HASWELL(devid) || \ + IS_VALLEYVIEW(devid)) + +#define IS_IVYBRIDGE(devid) ((devid) == PCI_CHIP_IVYBRIDGE_GT1 || \ + (devid) == PCI_CHIP_IVYBRIDGE_GT2 || \ + (devid) == PCI_CHIP_IVYBRIDGE_M_GT1 || \ + (devid) == PCI_CHIP_IVYBRIDGE_M_GT2 || \ + (devid) == PCI_CHIP_IVYBRIDGE_S || \ + (devid) == PCI_CHIP_IVYBRIDGE_S_GT2) + +#define IS_VALLEYVIEW(devid) ((devid) == PCI_CHIP_VALLEYVIEW_PO || \ + (devid) == PCI_CHIP_VALLEYVIEW_1 || \ + (devid) == PCI_CHIP_VALLEYVIEW_2 || \ + (devid) == PCI_CHIP_VALLEYVIEW_3) + +#define IS_HSW_GT1(devid) ((devid) == PCI_CHIP_HASWELL_GT1 || \ + (devid) == PCI_CHIP_HASWELL_M_GT1 || \ + (devid) == PCI_CHIP_HASWELL_S_GT1 || \ + (devid) == PCI_CHIP_HASWELL_B_GT1 || \ + (devid) == PCI_CHIP_HASWELL_E_GT1 || \ + (devid) == PCI_CHIP_HASWELL_SDV_GT1 || \ + (devid) == PCI_CHIP_HASWELL_SDV_M_GT1 || \ + (devid) == PCI_CHIP_HASWELL_SDV_S_GT1 || \ + (devid) == PCI_CHIP_HASWELL_SDV_B_GT1 || \ + (devid) == PCI_CHIP_HASWELL_SDV_E_GT1 || \ + (devid) == PCI_CHIP_HASWELL_ULT_GT1 || \ + (devid) == PCI_CHIP_HASWELL_ULT_M_GT1 || \ + (devid) == PCI_CHIP_HASWELL_ULT_S_GT1 || \ + (devid) == PCI_CHIP_HASWELL_ULT_B_GT1 || \ + (devid) == PCI_CHIP_HASWELL_ULT_E_GT1 || \ + (devid) == PCI_CHIP_HASWELL_CRW_GT1 || \ + (devid) == PCI_CHIP_HASWELL_CRW_M_GT1 || \ + (devid) == PCI_CHIP_HASWELL_CRW_S_GT1 || \ + (devid) == PCI_CHIP_HASWELL_CRW_B_GT1 || \ + (devid) == PCI_CHIP_HASWELL_CRW_E_GT1) +#define IS_HSW_GT2(devid) ((devid) == PCI_CHIP_HASWELL_GT2 || \ + (devid) == PCI_CHIP_HASWELL_M_GT2 || \ + (devid) == PCI_CHIP_HASWELL_S_GT2 || \ + (devid) == PCI_CHIP_HASWELL_B_GT2 || \ + (devid) == PCI_CHIP_HASWELL_E_GT2 || \ + (devid) == PCI_CHIP_HASWELL_SDV_GT2 || \ + (devid) == PCI_CHIP_HASWELL_SDV_M_GT2 || \ + (devid) == PCI_CHIP_HASWELL_SDV_S_GT2 || \ + (devid) == PCI_CHIP_HASWELL_SDV_B_GT2 || \ + (devid) == PCI_CHIP_HASWELL_SDV_E_GT2 || \ + (devid) == PCI_CHIP_HASWELL_ULT_GT2 || \ + (devid) == PCI_CHIP_HASWELL_ULT_M_GT2 || \ + (devid) == PCI_CHIP_HASWELL_ULT_S_GT2 || \ + (devid) == PCI_CHIP_HASWELL_ULT_B_GT2 || \ + (devid) == PCI_CHIP_HASWELL_ULT_E_GT2 || \ + (devid) == PCI_CHIP_HASWELL_CRW_GT2 || \ + (devid) == PCI_CHIP_HASWELL_CRW_M_GT2 || \ + (devid) == PCI_CHIP_HASWELL_CRW_S_GT2 || \ + (devid) == PCI_CHIP_HASWELL_CRW_B_GT2 || \ + (devid) == PCI_CHIP_HASWELL_CRW_E_GT2) +#define IS_HSW_GT3(devid) ((devid) == PCI_CHIP_HASWELL_GT3 || \ + (devid) == PCI_CHIP_HASWELL_M_GT3 || \ + (devid) == PCI_CHIP_HASWELL_S_GT3 || \ + (devid) == PCI_CHIP_HASWELL_B_GT3 || \ + (devid) == PCI_CHIP_HASWELL_E_GT3 || \ + (devid) == PCI_CHIP_HASWELL_SDV_GT3 || \ + (devid) == PCI_CHIP_HASWELL_SDV_M_GT3 || \ + (devid) == PCI_CHIP_HASWELL_SDV_S_GT3 || \ + (devid) == PCI_CHIP_HASWELL_SDV_B_GT3 || \ + (devid) == PCI_CHIP_HASWELL_SDV_E_GT3 || \ + (devid) == PCI_CHIP_HASWELL_ULT_GT3 || \ + (devid) == PCI_CHIP_HASWELL_ULT_M_GT3 || \ + (devid) == PCI_CHIP_HASWELL_ULT_S_GT3 || \ + (devid) == PCI_CHIP_HASWELL_ULT_B_GT3 || \ + (devid) == PCI_CHIP_HASWELL_ULT_E_GT3 || \ + (devid) == PCI_CHIP_HASWELL_CRW_GT3 || \ + (devid) == PCI_CHIP_HASWELL_CRW_M_GT3 || \ + (devid) == PCI_CHIP_HASWELL_CRW_S_GT3 || \ + (devid) == PCI_CHIP_HASWELL_CRW_B_GT3 || \ + (devid) == PCI_CHIP_HASWELL_CRW_E_GT3) + +#define IS_HASWELL(devid) (IS_HSW_GT1(devid) || \ + IS_HSW_GT2(devid) || \ + IS_HSW_GT3(devid)) + +#define IS_BROADWELL(devid) (((devid & 0xff00) != 0x1600) ? 0 : \ + (((devid & 0x00f0) >> 4) > 3) ? 0 : \ + ((devid & 0x000f) == BDW_SPARE) ? 1 : \ + ((devid & 0x000f) == BDW_ULT) ? 1 : \ + ((devid & 0x000f) == BDW_IRIS) ? 1 : \ + ((devid & 0x000f) == BDW_SERVER) ? 1 : \ + ((devid & 0x000f) == BDW_WORKSTATION) ? 1 : \ + ((devid & 0x000f) == BDW_ULX) ? 1 : 0) + +#define IS_CHERRYVIEW(devid) ((devid) == PCI_CHIP_CHERRYVIEW_0 || \ + (devid) == PCI_CHIP_CHERRYVIEW_1 || \ + (devid) == PCI_CHIP_CHERRYVIEW_2 || \ + (devid) == PCI_CHIP_CHERRYVIEW_3) + +#define IS_GEN8(devid) (IS_BROADWELL(devid) || \ + IS_CHERRYVIEW(devid)) + +/* New platforms use kernel pci ids */ +#include +#include + +drm_private bool intel_is_genx(unsigned int devid, int gen); +drm_private bool intel_get_genx(unsigned int devid, int *gen); + +#define IS_GEN9(devid) intel_is_genx(devid, 9) +#define IS_GEN10(devid) intel_is_genx(devid, 10) +#define IS_GEN11(devid) intel_is_genx(devid, 11) +#define IS_GEN12(devid) intel_is_genx(devid, 12) + +#define IS_9XX(dev) (IS_GEN3(dev) || \ + IS_GEN4(dev) || \ + IS_GEN5(dev) || \ + IS_GEN6(dev) || \ + IS_GEN7(dev) || \ + IS_GEN8(dev) || \ + intel_get_genx(dev, NULL)) + +#endif /* _INTEL_CHIPSET_H */ diff --git a/intel/intel_debug.h b/intel/intel_debug.h new file mode 100644 index 0000000..fa0737c --- /dev/null +++ b/intel/intel_debug.h @@ -0,0 +1,44 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 (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 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. + * + * Authors: + * Ben Widawsky + * + */ + +#ifndef INTEL_DEBUG_H +#define INTEL_DEBUG_H + +#include + +#define SHADER_DEBUG_SOCKET "/var/run/gen_debug" +#define DEBUG_HANDSHAKE_VERSION 0x3 +#define DEBUG_HANDSHAKE_ACK "okay" + +/* First byte must always be the 1 byte version */ +struct intel_debug_handshake { + uint32_t version; + int flink_handle; + uint32_t per_thread_scratch; +} __attribute__((packed)); + +#endif diff --git a/intel/intel_decode.c b/intel/intel_decode.c new file mode 100644 index 0000000..be6f779 --- /dev/null +++ b/intel/intel_decode.c @@ -0,0 +1,3983 @@ +/* + * Copyright © 2009-2011 Intel Corporation + * + * 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 (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 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "libdrm_macros.h" +#include "xf86drm.h" +#include "intel_chipset.h" +#include "intel_bufmgr.h" + + +/* Struct for tracking drm_intel_decode state. */ +struct drm_intel_decode { + /** stdio file where the output should land. Defaults to stdout. */ + FILE *out; + + /** PCI device ID. */ + uint32_t devid; + + /** + * Shorthand device identifier: 3 is 915, 4 is 965, 5 is + * Ironlake, etc. + */ + int gen; + + /** GPU address of the start of the current packet. */ + uint32_t hw_offset; + /** CPU virtual address of the start of the current packet. */ + uint32_t *data; + /** DWORDs of remaining batchbuffer data starting from the packet. */ + uint32_t count; + + /** GPU address of the start of the batchbuffer data. */ + uint32_t base_hw_offset; + /** CPU Virtual address of the start of the batchbuffer data. */ + uint32_t *base_data; + /** Number of DWORDs of batchbuffer data. */ + uint32_t base_count; + + /** @{ + * GPU head and tail pointers, which will be noted in the dump, or ~0. + */ + uint32_t head, tail; + /** @} */ + + /** + * Whether to dump the dwords after MI_BATCHBUFFER_END. + * + * This sometimes provides clues in corrupted batchbuffers, + * and is used by the intel-gpu-tools. + */ + bool dump_past_end; + + bool overflowed; +}; + +static FILE *out; +static uint32_t saved_s2 = 0, saved_s4 = 0; +static char saved_s2_set = 0, saved_s4_set = 0; +static uint32_t head_offset = 0xffffffff; /* undefined */ +static uint32_t tail_offset = 0xffffffff; /* undefined */ + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(A) (sizeof(A)/sizeof(A[0])) +#endif + +#define BUFFER_FAIL(_count, _len, _name) do { \ + fprintf(out, "Buffer size too small in %s (%d < %d)\n", \ + (_name), (_count), (_len)); \ + return _count; \ +} while (0) + +static float int_as_float(uint32_t intval) +{ + union intfloat { + uint32_t i; + float f; + } uval; + + uval.i = intval; + return uval.f; +} + +static void DRM_PRINTFLIKE(3, 4) +instr_out(struct drm_intel_decode *ctx, unsigned int index, + const char *fmt, ...) +{ + va_list va; + const char *parseinfo; + uint32_t offset = ctx->hw_offset + index * 4; + + if (index > ctx->count) { + if (!ctx->overflowed) { + fprintf(out, "ERROR: Decode attempted to continue beyond end of batchbuffer\n"); + ctx->overflowed = true; + } + return; + } + + if (offset == head_offset) + parseinfo = "HEAD"; + else if (offset == tail_offset) + parseinfo = "TAIL"; + else + parseinfo = " "; + + fprintf(out, "0x%08x: %s 0x%08x: %s", offset, parseinfo, + ctx->data[index], index == 0 ? "" : " "); + va_start(va, fmt); + vfprintf(out, fmt, va); + va_end(va); +} + +static int +decode_MI_SET_CONTEXT(struct drm_intel_decode *ctx) +{ + uint32_t data = ctx->data[1]; + if (ctx->gen > 7) + return 1; + + instr_out(ctx, 0, "MI_SET_CONTEXT\n"); + instr_out(ctx, 1, "gtt offset = 0x%x%s%s\n", + data & ~0xfff, + data & (1<<1)? ", Force Restore": "", + data & (1<<0)? ", Restore Inhibit": ""); + + return 2; +} + +static int +decode_MI_WAIT_FOR_EVENT(struct drm_intel_decode *ctx) +{ + const char *cc_wait; + int cc_shift = 0; + uint32_t data = ctx->data[0]; + + if (ctx->gen <= 5) + cc_shift = 9; + else + cc_shift = 16; + + switch ((data >> cc_shift) & 0x1f) { + case 1: + cc_wait = ", cc wait 1"; + break; + case 2: + cc_wait = ", cc wait 2"; + break; + case 3: + cc_wait = ", cc wait 3"; + break; + case 4: + cc_wait = ", cc wait 4"; + break; + case 5: + cc_wait = ", cc wait 4"; + break; + default: + cc_wait = ""; + break; + } + + if (ctx->gen <= 5) { + instr_out(ctx, 0, "MI_WAIT_FOR_EVENT%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + data & (1<<18)? ", pipe B start vblank wait": "", + data & (1<<17)? ", pipe A start vblank wait": "", + data & (1<<16)? ", overlay flip pending wait": "", + data & (1<<14)? ", pipe B hblank wait": "", + data & (1<<13)? ", pipe A hblank wait": "", + cc_wait, + data & (1<<8)? ", plane C pending flip wait": "", + data & (1<<7)? ", pipe B vblank wait": "", + data & (1<<6)? ", plane B pending flip wait": "", + data & (1<<5)? ", pipe B scan line wait": "", + data & (1<<4)? ", fbc idle wait": "", + data & (1<<3)? ", pipe A vblank wait": "", + data & (1<<2)? ", plane A pending flip wait": "", + data & (1<<1)? ", plane A scan line wait": ""); + } else { + instr_out(ctx, 0, "MI_WAIT_FOR_EVENT%s%s%s%s%s%s%s%s%s%s%s%s\n", + data & (1<<20)? ", sprite C pending flip wait": "", /* ivb */ + cc_wait, + data & (1<<13)? ", pipe B hblank wait": "", + data & (1<<11)? ", pipe B vblank wait": "", + data & (1<<10)? ", sprite B pending flip wait": "", + data & (1<<9)? ", plane B pending flip wait": "", + data & (1<<8)? ", plane B scan line wait": "", + data & (1<<5)? ", pipe A hblank wait": "", + data & (1<<3)? ", pipe A vblank wait": "", + data & (1<<2)? ", sprite A pending flip wait": "", + data & (1<<1)? ", plane A pending flip wait": "", + data & (1<<0)? ", plane A scan line wait": ""); + } + + return 1; +} + +static int +decode_mi(struct drm_intel_decode *ctx) +{ + unsigned int opcode, len = -1; + const char *post_sync_op = ""; + uint32_t *data = ctx->data; + + struct { + uint32_t opcode; + int len_mask; + unsigned int min_len; + unsigned int max_len; + const char *name; + int (*func)(struct drm_intel_decode *ctx); + } opcodes_mi[] = { + { 0x08, 0, 1, 1, "MI_ARB_ON_OFF" }, + { 0x0a, 0, 1, 1, "MI_BATCH_BUFFER_END" }, + { 0x30, 0x3f, 3, 3, "MI_BATCH_BUFFER" }, + { 0x31, 0x3f, 2, 2, "MI_BATCH_BUFFER_START" }, + { 0x14, 0x3f, 3, 3, "MI_DISPLAY_BUFFER_INFO" }, + { 0x04, 0, 1, 1, "MI_FLUSH" }, + { 0x22, 0x1f, 3, 3, "MI_LOAD_REGISTER_IMM" }, + { 0x13, 0x3f, 2, 2, "MI_LOAD_SCAN_LINES_EXCL" }, + { 0x12, 0x3f, 2, 2, "MI_LOAD_SCAN_LINES_INCL" }, + { 0x00, 0, 1, 1, "MI_NOOP" }, + { 0x11, 0x3f, 2, 2, "MI_OVERLAY_FLIP" }, + { 0x07, 0, 1, 1, "MI_REPORT_HEAD" }, + { 0x18, 0x3f, 2, 2, "MI_SET_CONTEXT", decode_MI_SET_CONTEXT }, + { 0x20, 0x3f, 3, 4, "MI_STORE_DATA_IMM" }, + { 0x21, 0x3f, 3, 4, "MI_STORE_DATA_INDEX" }, + { 0x24, 0x3f, 3, 3, "MI_STORE_REGISTER_MEM" }, + { 0x02, 0, 1, 1, "MI_USER_INTERRUPT" }, + { 0x03, 0, 1, 1, "MI_WAIT_FOR_EVENT", decode_MI_WAIT_FOR_EVENT }, + { 0x16, 0x7f, 3, 3, "MI_SEMAPHORE_MBOX" }, + { 0x26, 0x1f, 3, 4, "MI_FLUSH_DW" }, + { 0x28, 0x3f, 3, 3, "MI_REPORT_PERF_COUNT" }, + { 0x29, 0xff, 3, 3, "MI_LOAD_REGISTER_MEM" }, + { 0x0b, 0, 1, 1, "MI_SUSPEND_FLUSH"}, + }, *opcode_mi = NULL; + + /* check instruction length */ + for (opcode = 0; opcode < sizeof(opcodes_mi) / sizeof(opcodes_mi[0]); + opcode++) { + if ((data[0] & 0x1f800000) >> 23 == opcodes_mi[opcode].opcode) { + len = 1; + if (opcodes_mi[opcode].max_len > 1) { + len = + (data[0] & opcodes_mi[opcode].len_mask) + 2; + if (len < opcodes_mi[opcode].min_len + || len > opcodes_mi[opcode].max_len) { + fprintf(out, + "Bad length (%d) in %s, [%d, %d]\n", + len, opcodes_mi[opcode].name, + opcodes_mi[opcode].min_len, + opcodes_mi[opcode].max_len); + } + } + opcode_mi = &opcodes_mi[opcode]; + break; + } + } + + if (opcode_mi && opcode_mi->func) + return opcode_mi->func(ctx); + + switch ((data[0] & 0x1f800000) >> 23) { + case 0x0a: + instr_out(ctx, 0, "MI_BATCH_BUFFER_END\n"); + return -1; + case 0x16: + instr_out(ctx, 0, "MI_SEMAPHORE_MBOX%s%s%s%s %u\n", + data[0] & (1 << 22) ? " global gtt," : "", + data[0] & (1 << 21) ? " update semaphore," : "", + data[0] & (1 << 20) ? " compare semaphore," : "", + data[0] & (1 << 18) ? " use compare reg" : "", + (data[0] & (0x3 << 16)) >> 16); + instr_out(ctx, 1, "value\n"); + instr_out(ctx, 2, "address\n"); + return len; + case 0x21: + instr_out(ctx, 0, "MI_STORE_DATA_INDEX%s\n", + data[0] & (1 << 21) ? " use per-process HWS," : ""); + instr_out(ctx, 1, "index\n"); + instr_out(ctx, 2, "dword\n"); + if (len == 4) + instr_out(ctx, 3, "upper dword\n"); + return len; + case 0x00: + if (data[0] & (1 << 22)) + instr_out(ctx, 0, + "MI_NOOP write NOPID reg, val=0x%x\n", + data[0] & ((1 << 22) - 1)); + else + instr_out(ctx, 0, "MI_NOOP\n"); + return len; + case 0x26: + switch (data[0] & (0x3 << 14)) { + case (0 << 14): + post_sync_op = "no write"; + break; + case (1 << 14): + post_sync_op = "write data"; + break; + case (2 << 14): + post_sync_op = "reserved"; + break; + case (3 << 14): + post_sync_op = "write TIMESTAMP"; + break; + } + instr_out(ctx, 0, + "MI_FLUSH_DW%s%s%s%s post_sync_op='%s' %s%s\n", + data[0] & (1 << 22) ? + " enable protected mem (BCS-only)," : "", + data[0] & (1 << 21) ? " store in hws," : "", + data[0] & (1 << 18) ? " invalidate tlb," : "", + data[0] & (1 << 17) ? " flush gfdt," : "", + post_sync_op, + data[0] & (1 << 8) ? " enable notify interrupt," : "", + data[0] & (1 << 7) ? + " invalidate video state (BCS-only)," : ""); + if (data[0] & (1 << 21)) + instr_out(ctx, 1, "hws index\n"); + else + instr_out(ctx, 1, "address\n"); + instr_out(ctx, 2, "dword\n"); + if (len == 4) + instr_out(ctx, 3, "upper dword\n"); + return len; + } + + for (opcode = 0; opcode < sizeof(opcodes_mi) / sizeof(opcodes_mi[0]); + opcode++) { + if ((data[0] & 0x1f800000) >> 23 == opcodes_mi[opcode].opcode) { + unsigned int i; + + instr_out(ctx, 0, "%s\n", + opcodes_mi[opcode].name); + for (i = 1; i < len; i++) { + instr_out(ctx, i, "dword %d\n", i); + } + + return len; + } + } + + instr_out(ctx, 0, "MI UNKNOWN\n"); + return 1; +} + +static void +decode_2d_br00(struct drm_intel_decode *ctx, const char *cmd) +{ + instr_out(ctx, 0, + "%s (rgb %sabled, alpha %sabled, src tile %d, dst tile %d)\n", + cmd, + (ctx->data[0] & (1 << 20)) ? "en" : "dis", + (ctx->data[0] & (1 << 21)) ? "en" : "dis", + (ctx->data[0] >> 15) & 1, + (ctx->data[0] >> 11) & 1); +} + +static void +decode_2d_br01(struct drm_intel_decode *ctx) +{ + const char *format; + switch ((ctx->data[1] >> 24) & 0x3) { + case 0: + format = "8"; + break; + case 1: + format = "565"; + break; + case 2: + format = "1555"; + break; + case 3: + format = "8888"; + break; + } + + instr_out(ctx, 1, + "format %s, pitch %d, rop 0x%02x, " + "clipping %sabled, %s%s \n", + format, + (short)(ctx->data[1] & 0xffff), + (ctx->data[1] >> 16) & 0xff, + ctx->data[1] & (1 << 30) ? "en" : "dis", + ctx->data[1] & (1 << 31) ? "solid pattern enabled, " : "", + ctx->data[1] & (1 << 31) ? + "mono pattern transparency enabled, " : ""); + +} + +static int +decode_2d(struct drm_intel_decode *ctx) +{ + unsigned int opcode, len; + uint32_t *data = ctx->data; + + struct { + uint32_t opcode; + unsigned int min_len; + unsigned int max_len; + const char *name; + } opcodes_2d[] = { + { 0x40, 5, 5, "COLOR_BLT" }, + { 0x43, 6, 6, "SRC_COPY_BLT" }, + { 0x01, 8, 8, "XY_SETUP_BLT" }, + { 0x11, 9, 9, "XY_SETUP_MONO_PATTERN_SL_BLT" }, + { 0x03, 3, 3, "XY_SETUP_CLIP_BLT" }, + { 0x24, 2, 2, "XY_PIXEL_BLT" }, + { 0x25, 3, 3, "XY_SCANLINES_BLT" }, + { 0x26, 4, 4, "Y_TEXT_BLT" }, + { 0x31, 5, 134, "XY_TEXT_IMMEDIATE_BLT" }, + { 0x50, 6, 6, "XY_COLOR_BLT" }, + { 0x51, 6, 6, "XY_PAT_BLT" }, + { 0x76, 8, 8, "XY_PAT_CHROMA_BLT" }, + { 0x72, 7, 135, "XY_PAT_BLT_IMMEDIATE" }, + { 0x77, 9, 137, "XY_PAT_CHROMA_BLT_IMMEDIATE" }, + { 0x52, 9, 9, "XY_MONO_PAT_BLT" }, + { 0x59, 7, 7, "XY_MONO_PAT_FIXED_BLT" }, + { 0x53, 8, 8, "XY_SRC_COPY_BLT" }, + { 0x54, 8, 8, "XY_MONO_SRC_COPY_BLT" }, + { 0x71, 9, 137, "XY_MONO_SRC_COPY_IMMEDIATE_BLT" }, + { 0x55, 9, 9, "XY_FULL_BLT" }, + { 0x55, 9, 137, "XY_FULL_IMMEDIATE_PATTERN_BLT" }, + { 0x56, 9, 9, "XY_FULL_MONO_SRC_BLT" }, + { 0x75, 10, 138, "XY_FULL_MONO_SRC_IMMEDIATE_PATTERN_BLT" }, + { 0x57, 12, 12, "XY_FULL_MONO_PATTERN_BLT" }, + { 0x58, 12, 12, "XY_FULL_MONO_PATTERN_MONO_SRC_BLT"}, + }; + + switch ((data[0] & 0x1fc00000) >> 22) { + case 0x25: + instr_out(ctx, 0, + "XY_SCANLINES_BLT (pattern seed (%d, %d), dst tile %d)\n", + (data[0] >> 12) & 0x8, + (data[0] >> 8) & 0x8, (data[0] >> 11) & 1); + + len = (data[0] & 0x000000ff) + 2; + if (len != 3) + fprintf(out, "Bad count in XY_SCANLINES_BLT\n"); + + instr_out(ctx, 1, "dest (%d,%d)\n", + data[1] & 0xffff, data[1] >> 16); + instr_out(ctx, 2, "dest (%d,%d)\n", + data[2] & 0xffff, data[2] >> 16); + return len; + case 0x01: + decode_2d_br00(ctx, "XY_SETUP_BLT"); + + len = (data[0] & 0x000000ff) + 2; + if (len != 8) + fprintf(out, "Bad count in XY_SETUP_BLT\n"); + + decode_2d_br01(ctx); + instr_out(ctx, 2, "cliprect (%d,%d)\n", + data[2] & 0xffff, data[2] >> 16); + instr_out(ctx, 3, "cliprect (%d,%d)\n", + data[3] & 0xffff, data[3] >> 16); + instr_out(ctx, 4, "setup dst offset 0x%08x\n", + data[4]); + instr_out(ctx, 5, "setup background color\n"); + instr_out(ctx, 6, "setup foreground color\n"); + instr_out(ctx, 7, "color pattern offset\n"); + return len; + case 0x03: + decode_2d_br00(ctx, "XY_SETUP_CLIP_BLT"); + + len = (data[0] & 0x000000ff) + 2; + if (len != 3) + fprintf(out, "Bad count in XY_SETUP_CLIP_BLT\n"); + + instr_out(ctx, 1, "cliprect (%d,%d)\n", + data[1] & 0xffff, data[2] >> 16); + instr_out(ctx, 2, "cliprect (%d,%d)\n", + data[2] & 0xffff, data[3] >> 16); + return len; + case 0x11: + decode_2d_br00(ctx, "XY_SETUP_MONO_PATTERN_SL_BLT"); + + len = (data[0] & 0x000000ff) + 2; + if (len != 9) + fprintf(out, + "Bad count in XY_SETUP_MONO_PATTERN_SL_BLT\n"); + + decode_2d_br01(ctx); + instr_out(ctx, 2, "cliprect (%d,%d)\n", + data[2] & 0xffff, data[2] >> 16); + instr_out(ctx, 3, "cliprect (%d,%d)\n", + data[3] & 0xffff, data[3] >> 16); + instr_out(ctx, 4, "setup dst offset 0x%08x\n", + data[4]); + instr_out(ctx, 5, "setup background color\n"); + instr_out(ctx, 6, "setup foreground color\n"); + instr_out(ctx, 7, "mono pattern dw0\n"); + instr_out(ctx, 8, "mono pattern dw1\n"); + return len; + case 0x50: + decode_2d_br00(ctx, "XY_COLOR_BLT"); + + len = (data[0] & 0x000000ff) + 2; + if (len != 6) + fprintf(out, "Bad count in XY_COLOR_BLT\n"); + + decode_2d_br01(ctx); + instr_out(ctx, 2, "(%d,%d)\n", + data[2] & 0xffff, data[2] >> 16); + instr_out(ctx, 3, "(%d,%d)\n", + data[3] & 0xffff, data[3] >> 16); + instr_out(ctx, 4, "offset 0x%08x\n", data[4]); + instr_out(ctx, 5, "color\n"); + return len; + case 0x53: + decode_2d_br00(ctx, "XY_SRC_COPY_BLT"); + + len = (data[0] & 0x000000ff) + 2; + if (len != 8) + fprintf(out, "Bad count in XY_SRC_COPY_BLT\n"); + + decode_2d_br01(ctx); + instr_out(ctx, 2, "dst (%d,%d)\n", + data[2] & 0xffff, data[2] >> 16); + instr_out(ctx, 3, "dst (%d,%d)\n", + data[3] & 0xffff, data[3] >> 16); + instr_out(ctx, 4, "dst offset 0x%08x\n", data[4]); + instr_out(ctx, 5, "src (%d,%d)\n", + data[5] & 0xffff, data[5] >> 16); + instr_out(ctx, 6, "src pitch %d\n", + (short)(data[6] & 0xffff)); + instr_out(ctx, 7, "src offset 0x%08x\n", data[7]); + return len; + } + + for (opcode = 0; opcode < sizeof(opcodes_2d) / sizeof(opcodes_2d[0]); + opcode++) { + if ((data[0] & 0x1fc00000) >> 22 == opcodes_2d[opcode].opcode) { + unsigned int i; + + len = 1; + instr_out(ctx, 0, "%s\n", + opcodes_2d[opcode].name); + if (opcodes_2d[opcode].max_len > 1) { + len = (data[0] & 0x000000ff) + 2; + if (len < opcodes_2d[opcode].min_len || + len > opcodes_2d[opcode].max_len) { + fprintf(out, "Bad count in %s\n", + opcodes_2d[opcode].name); + } + } + + for (i = 1; i < len; i++) { + instr_out(ctx, i, "dword %d\n", i); + } + + return len; + } + } + + instr_out(ctx, 0, "2D UNKNOWN\n"); + return 1; +} + +static int +decode_3d_1c(struct drm_intel_decode *ctx) +{ + uint32_t *data = ctx->data; + uint32_t opcode; + + opcode = (data[0] & 0x00f80000) >> 19; + + switch (opcode) { + case 0x11: + instr_out(ctx, 0, + "3DSTATE_DEPTH_SUBRECTANGLE_DISABLE\n"); + return 1; + case 0x10: + instr_out(ctx, 0, "3DSTATE_SCISSOR_ENABLE %s\n", + data[0] & 1 ? "enabled" : "disabled"); + return 1; + case 0x01: + instr_out(ctx, 0, "3DSTATE_MAP_COORD_SET_I830\n"); + return 1; + case 0x0a: + instr_out(ctx, 0, "3DSTATE_MAP_CUBE_I830\n"); + return 1; + case 0x05: + instr_out(ctx, 0, "3DSTATE_MAP_TEX_STREAM_I830\n"); + return 1; + } + + instr_out(ctx, 0, "3D UNKNOWN: 3d_1c opcode = 0x%x\n", + opcode); + return 1; +} + +/** Sets the string dstname to describe the destination of the PS instruction */ +static void +i915_get_instruction_dst(uint32_t *data, int i, char *dstname, int do_mask) +{ + uint32_t a0 = data[i]; + int dst_nr = (a0 >> 14) & 0xf; + char dstmask[8]; + const char *sat; + + if (do_mask) { + if (((a0 >> 10) & 0xf) == 0xf) { + dstmask[0] = 0; + } else { + int dstmask_index = 0; + + dstmask[dstmask_index++] = '.'; + if (a0 & (1 << 10)) + dstmask[dstmask_index++] = 'x'; + if (a0 & (1 << 11)) + dstmask[dstmask_index++] = 'y'; + if (a0 & (1 << 12)) + dstmask[dstmask_index++] = 'z'; + if (a0 & (1 << 13)) + dstmask[dstmask_index++] = 'w'; + dstmask[dstmask_index++] = 0; + } + + if (a0 & (1 << 22)) + sat = ".sat"; + else + sat = ""; + } else { + dstmask[0] = 0; + sat = ""; + } + + switch ((a0 >> 19) & 0x7) { + case 0: + if (dst_nr > 15) + fprintf(out, "bad destination reg R%d\n", dst_nr); + sprintf(dstname, "R%d%s%s", dst_nr, dstmask, sat); + break; + case 4: + if (dst_nr > 0) + fprintf(out, "bad destination reg oC%d\n", dst_nr); + sprintf(dstname, "oC%s%s", dstmask, sat); + break; + case 5: + if (dst_nr > 0) + fprintf(out, "bad destination reg oD%d\n", dst_nr); + sprintf(dstname, "oD%s%s", dstmask, sat); + break; + case 6: + if (dst_nr > 3) + fprintf(out, "bad destination reg U%d\n", dst_nr); + sprintf(dstname, "U%d%s%s", dst_nr, dstmask, sat); + break; + default: + sprintf(dstname, "RESERVED"); + break; + } +} + +static const char * +i915_get_channel_swizzle(uint32_t select) +{ + switch (select & 0x7) { + case 0: + return (select & 8) ? "-x" : "x"; + case 1: + return (select & 8) ? "-y" : "y"; + case 2: + return (select & 8) ? "-z" : "z"; + case 3: + return (select & 8) ? "-w" : "w"; + case 4: + return (select & 8) ? "-0" : "0"; + case 5: + return (select & 8) ? "-1" : "1"; + default: + return (select & 8) ? "-bad" : "bad"; + } +} + +static void +i915_get_instruction_src_name(uint32_t src_type, uint32_t src_nr, char *name) +{ + switch (src_type) { + case 0: + sprintf(name, "R%d", src_nr); + if (src_nr > 15) + fprintf(out, "bad src reg %s\n", name); + break; + case 1: + if (src_nr < 8) + sprintf(name, "T%d", src_nr); + else if (src_nr == 8) + sprintf(name, "DIFFUSE"); + else if (src_nr == 9) + sprintf(name, "SPECULAR"); + else if (src_nr == 10) + sprintf(name, "FOG"); + else { + fprintf(out, "bad src reg T%d\n", src_nr); + sprintf(name, "RESERVED"); + } + break; + case 2: + sprintf(name, "C%d", src_nr); + if (src_nr > 31) + fprintf(out, "bad src reg %s\n", name); + break; + case 4: + sprintf(name, "oC"); + if (src_nr > 0) + fprintf(out, "bad src reg oC%d\n", src_nr); + break; + case 5: + sprintf(name, "oD"); + if (src_nr > 0) + fprintf(out, "bad src reg oD%d\n", src_nr); + break; + case 6: + sprintf(name, "U%d", src_nr); + if (src_nr > 3) + fprintf(out, "bad src reg %s\n", name); + break; + default: + fprintf(out, "bad src reg type %d\n", src_type); + sprintf(name, "RESERVED"); + break; + } +} + +static void i915_get_instruction_src0(uint32_t *data, int i, char *srcname) +{ + uint32_t a0 = data[i]; + uint32_t a1 = data[i + 1]; + int src_nr = (a0 >> 2) & 0x1f; + const char *swizzle_x = i915_get_channel_swizzle((a1 >> 28) & 0xf); + const char *swizzle_y = i915_get_channel_swizzle((a1 >> 24) & 0xf); + const char *swizzle_z = i915_get_channel_swizzle((a1 >> 20) & 0xf); + const char *swizzle_w = i915_get_channel_swizzle((a1 >> 16) & 0xf); + char swizzle[100]; + + i915_get_instruction_src_name((a0 >> 7) & 0x7, src_nr, srcname); + sprintf(swizzle, ".%s%s%s%s", swizzle_x, swizzle_y, swizzle_z, + swizzle_w); + if (strcmp(swizzle, ".xyzw") != 0) + strcat(srcname, swizzle); +} + +static void i915_get_instruction_src1(uint32_t *data, int i, char *srcname) +{ + uint32_t a1 = data[i + 1]; + uint32_t a2 = data[i + 2]; + int src_nr = (a1 >> 8) & 0x1f; + const char *swizzle_x = i915_get_channel_swizzle((a1 >> 4) & 0xf); + const char *swizzle_y = i915_get_channel_swizzle((a1 >> 0) & 0xf); + const char *swizzle_z = i915_get_channel_swizzle((a2 >> 28) & 0xf); + const char *swizzle_w = i915_get_channel_swizzle((a2 >> 24) & 0xf); + char swizzle[100]; + + i915_get_instruction_src_name((a1 >> 13) & 0x7, src_nr, srcname); + sprintf(swizzle, ".%s%s%s%s", swizzle_x, swizzle_y, swizzle_z, + swizzle_w); + if (strcmp(swizzle, ".xyzw") != 0) + strcat(srcname, swizzle); +} + +static void i915_get_instruction_src2(uint32_t *data, int i, char *srcname) +{ + uint32_t a2 = data[i + 2]; + int src_nr = (a2 >> 16) & 0x1f; + const char *swizzle_x = i915_get_channel_swizzle((a2 >> 12) & 0xf); + const char *swizzle_y = i915_get_channel_swizzle((a2 >> 8) & 0xf); + const char *swizzle_z = i915_get_channel_swizzle((a2 >> 4) & 0xf); + const char *swizzle_w = i915_get_channel_swizzle((a2 >> 0) & 0xf); + char swizzle[100]; + + i915_get_instruction_src_name((a2 >> 21) & 0x7, src_nr, srcname); + sprintf(swizzle, ".%s%s%s%s", swizzle_x, swizzle_y, swizzle_z, + swizzle_w); + if (strcmp(swizzle, ".xyzw") != 0) + strcat(srcname, swizzle); +} + +static void +i915_get_instruction_addr(uint32_t src_type, uint32_t src_nr, char *name) +{ + switch (src_type) { + case 0: + sprintf(name, "R%d", src_nr); + if (src_nr > 15) + fprintf(out, "bad src reg %s\n", name); + break; + case 1: + if (src_nr < 8) + sprintf(name, "T%d", src_nr); + else if (src_nr == 8) + sprintf(name, "DIFFUSE"); + else if (src_nr == 9) + sprintf(name, "SPECULAR"); + else if (src_nr == 10) + sprintf(name, "FOG"); + else { + fprintf(out, "bad src reg T%d\n", src_nr); + sprintf(name, "RESERVED"); + } + break; + case 4: + sprintf(name, "oC"); + if (src_nr > 0) + fprintf(out, "bad src reg oC%d\n", src_nr); + break; + case 5: + sprintf(name, "oD"); + if (src_nr > 0) + fprintf(out, "bad src reg oD%d\n", src_nr); + break; + default: + fprintf(out, "bad src reg type %d\n", src_type); + sprintf(name, "RESERVED"); + break; + } +} + +static void +i915_decode_alu1(struct drm_intel_decode *ctx, + int i, char *instr_prefix, const char *op_name) +{ + char dst[100], src0[100]; + + i915_get_instruction_dst(ctx->data, i, dst, 1); + i915_get_instruction_src0(ctx->data, i, src0); + + instr_out(ctx, i++, "%s: %s %s, %s\n", instr_prefix, + op_name, dst, src0); + instr_out(ctx, i++, "%s\n", instr_prefix); + instr_out(ctx, i++, "%s\n", instr_prefix); +} + +static void +i915_decode_alu2(struct drm_intel_decode *ctx, + int i, char *instr_prefix, const char *op_name) +{ + char dst[100], src0[100], src1[100]; + + i915_get_instruction_dst(ctx->data, i, dst, 1); + i915_get_instruction_src0(ctx->data, i, src0); + i915_get_instruction_src1(ctx->data, i, src1); + + instr_out(ctx, i++, "%s: %s %s, %s, %s\n", instr_prefix, + op_name, dst, src0, src1); + instr_out(ctx, i++, "%s\n", instr_prefix); + instr_out(ctx, i++, "%s\n", instr_prefix); +} + +static void +i915_decode_alu3(struct drm_intel_decode *ctx, + int i, char *instr_prefix, const char *op_name) +{ + char dst[100], src0[100], src1[100], src2[100]; + + i915_get_instruction_dst(ctx->data, i, dst, 1); + i915_get_instruction_src0(ctx->data, i, src0); + i915_get_instruction_src1(ctx->data, i, src1); + i915_get_instruction_src2(ctx->data, i, src2); + + instr_out(ctx, i++, "%s: %s %s, %s, %s, %s\n", instr_prefix, + op_name, dst, src0, src1, src2); + instr_out(ctx, i++, "%s\n", instr_prefix); + instr_out(ctx, i++, "%s\n", instr_prefix); +} + +static void +i915_decode_tex(struct drm_intel_decode *ctx, int i, + const char *instr_prefix, const char *tex_name) +{ + uint32_t t0 = ctx->data[i]; + uint32_t t1 = ctx->data[i + 1]; + char dst_name[100]; + char addr_name[100]; + int sampler_nr; + + i915_get_instruction_dst(ctx->data, i, dst_name, 0); + i915_get_instruction_addr((t1 >> 24) & 0x7, + (t1 >> 17) & 0xf, addr_name); + sampler_nr = t0 & 0xf; + + instr_out(ctx, i++, "%s: %s %s, S%d, %s\n", instr_prefix, + tex_name, dst_name, sampler_nr, addr_name); + instr_out(ctx, i++, "%s\n", instr_prefix); + instr_out(ctx, i++, "%s\n", instr_prefix); +} + +static void +i915_decode_dcl(struct drm_intel_decode *ctx, int i, char *instr_prefix) +{ + uint32_t d0 = ctx->data[i]; + const char *sampletype; + int dcl_nr = (d0 >> 14) & 0xf; + const char *dcl_x = d0 & (1 << 10) ? "x" : ""; + const char *dcl_y = d0 & (1 << 11) ? "y" : ""; + const char *dcl_z = d0 & (1 << 12) ? "z" : ""; + const char *dcl_w = d0 & (1 << 13) ? "w" : ""; + char dcl_mask[10]; + + switch ((d0 >> 19) & 0x3) { + case 1: + sprintf(dcl_mask, ".%s%s%s%s", dcl_x, dcl_y, dcl_z, dcl_w); + if (strcmp(dcl_mask, ".") == 0) + fprintf(out, "bad (empty) dcl mask\n"); + + if (dcl_nr > 10) + fprintf(out, "bad T%d dcl register number\n", dcl_nr); + if (dcl_nr < 8) { + if (strcmp(dcl_mask, ".x") != 0 && + strcmp(dcl_mask, ".xy") != 0 && + strcmp(dcl_mask, ".xz") != 0 && + strcmp(dcl_mask, ".w") != 0 && + strcmp(dcl_mask, ".xyzw") != 0) { + fprintf(out, "bad T%d.%s dcl mask\n", dcl_nr, + dcl_mask); + } + instr_out(ctx, i++, "%s: DCL T%d%s\n", + instr_prefix, dcl_nr, dcl_mask); + } else { + if (strcmp(dcl_mask, ".xz") == 0) + fprintf(out, "errataed bad dcl mask %s\n", + dcl_mask); + else if (strcmp(dcl_mask, ".xw") == 0) + fprintf(out, "errataed bad dcl mask %s\n", + dcl_mask); + else if (strcmp(dcl_mask, ".xzw") == 0) + fprintf(out, "errataed bad dcl mask %s\n", + dcl_mask); + + if (dcl_nr == 8) { + instr_out(ctx, i++, + "%s: DCL DIFFUSE%s\n", instr_prefix, + dcl_mask); + } else if (dcl_nr == 9) { + instr_out(ctx, i++, + "%s: DCL SPECULAR%s\n", instr_prefix, + dcl_mask); + } else if (dcl_nr == 10) { + instr_out(ctx, i++, + "%s: DCL FOG%s\n", instr_prefix, + dcl_mask); + } + } + instr_out(ctx, i++, "%s\n", instr_prefix); + instr_out(ctx, i++, "%s\n", instr_prefix); + break; + case 3: + switch ((d0 >> 22) & 0x3) { + case 0: + sampletype = "2D"; + break; + case 1: + sampletype = "CUBE"; + break; + case 2: + sampletype = "3D"; + break; + default: + sampletype = "RESERVED"; + break; + } + if (dcl_nr > 15) + fprintf(out, "bad S%d dcl register number\n", dcl_nr); + instr_out(ctx, i++, "%s: DCL S%d %s\n", + instr_prefix, dcl_nr, sampletype); + instr_out(ctx, i++, "%s\n", instr_prefix); + instr_out(ctx, i++, "%s\n", instr_prefix); + break; + default: + instr_out(ctx, i++, "%s: DCL RESERVED%d\n", + instr_prefix, dcl_nr); + instr_out(ctx, i++, "%s\n", instr_prefix); + instr_out(ctx, i++, "%s\n", instr_prefix); + } +} + +static void +i915_decode_instruction(struct drm_intel_decode *ctx, + int i, char *instr_prefix) +{ + switch ((ctx->data[i] >> 24) & 0x1f) { + case 0x0: + instr_out(ctx, i++, "%s: NOP\n", instr_prefix); + instr_out(ctx, i++, "%s\n", instr_prefix); + instr_out(ctx, i++, "%s\n", instr_prefix); + break; + case 0x01: + i915_decode_alu2(ctx, i, instr_prefix, "ADD"); + break; + case 0x02: + i915_decode_alu1(ctx, i, instr_prefix, "MOV"); + break; + case 0x03: + i915_decode_alu2(ctx, i, instr_prefix, "MUL"); + break; + case 0x04: + i915_decode_alu3(ctx, i, instr_prefix, "MAD"); + break; + case 0x05: + i915_decode_alu3(ctx, i, instr_prefix, "DP2ADD"); + break; + case 0x06: + i915_decode_alu2(ctx, i, instr_prefix, "DP3"); + break; + case 0x07: + i915_decode_alu2(ctx, i, instr_prefix, "DP4"); + break; + case 0x08: + i915_decode_alu1(ctx, i, instr_prefix, "FRC"); + break; + case 0x09: + i915_decode_alu1(ctx, i, instr_prefix, "RCP"); + break; + case 0x0a: + i915_decode_alu1(ctx, i, instr_prefix, "RSQ"); + break; + case 0x0b: + i915_decode_alu1(ctx, i, instr_prefix, "EXP"); + break; + case 0x0c: + i915_decode_alu1(ctx, i, instr_prefix, "LOG"); + break; + case 0x0d: + i915_decode_alu2(ctx, i, instr_prefix, "CMP"); + break; + case 0x0e: + i915_decode_alu2(ctx, i, instr_prefix, "MIN"); + break; + case 0x0f: + i915_decode_alu2(ctx, i, instr_prefix, "MAX"); + break; + case 0x10: + i915_decode_alu1(ctx, i, instr_prefix, "FLR"); + break; + case 0x11: + i915_decode_alu1(ctx, i, instr_prefix, "MOD"); + break; + case 0x12: + i915_decode_alu1(ctx, i, instr_prefix, "TRC"); + break; + case 0x13: + i915_decode_alu2(ctx, i, instr_prefix, "SGE"); + break; + case 0x14: + i915_decode_alu2(ctx, i, instr_prefix, "SLT"); + break; + case 0x15: + i915_decode_tex(ctx, i, instr_prefix, "TEXLD"); + break; + case 0x16: + i915_decode_tex(ctx, i, instr_prefix, "TEXLDP"); + break; + case 0x17: + i915_decode_tex(ctx, i, instr_prefix, "TEXLDB"); + break; + case 0x19: + i915_decode_dcl(ctx, i, instr_prefix); + break; + default: + instr_out(ctx, i++, "%s: unknown\n", instr_prefix); + instr_out(ctx, i++, "%s\n", instr_prefix); + instr_out(ctx, i++, "%s\n", instr_prefix); + break; + } +} + +static const char * +decode_compare_func(uint32_t op) +{ + switch (op & 0x7) { + case 0: + return "always"; + case 1: + return "never"; + case 2: + return "less"; + case 3: + return "equal"; + case 4: + return "lequal"; + case 5: + return "greater"; + case 6: + return "notequal"; + case 7: + return "gequal"; + } + return ""; +} + +static const char * +decode_stencil_op(uint32_t op) +{ + switch (op & 0x7) { + case 0: + return "keep"; + case 1: + return "zero"; + case 2: + return "replace"; + case 3: + return "incr_sat"; + case 4: + return "decr_sat"; + case 5: + return "greater"; + case 6: + return "incr"; + case 7: + return "decr"; + } + return ""; +} + +#if 0 +static const char * +decode_logic_op(uint32_t op) +{ + switch (op & 0xf) { + case 0: + return "clear"; + case 1: + return "nor"; + case 2: + return "and_inv"; + case 3: + return "copy_inv"; + case 4: + return "and_rvrse"; + case 5: + return "inv"; + case 6: + return "xor"; + case 7: + return "nand"; + case 8: + return "and"; + case 9: + return "equiv"; + case 10: + return "noop"; + case 11: + return "or_inv"; + case 12: + return "copy"; + case 13: + return "or_rvrse"; + case 14: + return "or"; + case 15: + return "set"; + } + return ""; +} +#endif + +static const char * +decode_blend_fact(uint32_t op) +{ + switch (op & 0xf) { + case 1: + return "zero"; + case 2: + return "one"; + case 3: + return "src_colr"; + case 4: + return "inv_src_colr"; + case 5: + return "src_alpha"; + case 6: + return "inv_src_alpha"; + case 7: + return "dst_alpha"; + case 8: + return "inv_dst_alpha"; + case 9: + return "dst_colr"; + case 10: + return "inv_dst_colr"; + case 11: + return "src_alpha_sat"; + case 12: + return "cnst_colr"; + case 13: + return "inv_cnst_colr"; + case 14: + return "cnst_alpha"; + case 15: + return "inv_const_alpha"; + } + return ""; +} + +static const char * +decode_tex_coord_mode(uint32_t mode) +{ + switch (mode & 0x7) { + case 0: + return "wrap"; + case 1: + return "mirror"; + case 2: + return "clamp_edge"; + case 3: + return "cube"; + case 4: + return "clamp_border"; + case 5: + return "mirror_once"; + } + return ""; +} + +static const char * +decode_sample_filter(uint32_t mode) +{ + switch (mode & 0x7) { + case 0: + return "nearest"; + case 1: + return "linear"; + case 2: + return "anisotropic"; + case 3: + return "4x4_1"; + case 4: + return "4x4_2"; + case 5: + return "4x4_flat"; + case 6: + return "6x5_mono"; + } + return ""; +} + +static int +decode_3d_1d(struct drm_intel_decode *ctx) +{ + unsigned int len, i, c, idx, word, map, sampler, instr; + const char *format, *zformat, *type; + uint32_t opcode; + uint32_t *data = ctx->data; + uint32_t devid = ctx->devid; + + struct { + uint32_t opcode; + int i830_only; + unsigned int min_len; + unsigned int max_len; + const char *name; + } opcodes_3d_1d[] = { + { 0x86, 0, 4, 4, "3DSTATE_CHROMA_KEY" }, + { 0x88, 0, 2, 2, "3DSTATE_CONSTANT_BLEND_COLOR" }, + { 0x99, 0, 2, 2, "3DSTATE_DEFAULT_DIFFUSE" }, + { 0x9a, 0, 2, 2, "3DSTATE_DEFAULT_SPECULAR" }, + { 0x98, 0, 2, 2, "3DSTATE_DEFAULT_Z" }, + { 0x97, 0, 2, 2, "3DSTATE_DEPTH_OFFSET_SCALE" }, + { 0x9d, 0, 65, 65, "3DSTATE_FILTER_COEFFICIENTS_4X4" }, + { 0x9e, 0, 4, 4, "3DSTATE_MONO_FILTER" }, + { 0x89, 0, 4, 4, "3DSTATE_FOG_MODE" }, + { 0x8f, 0, 2, 16, "3DSTATE_MAP_PALLETE_LOAD_32" }, + { 0x83, 0, 2, 2, "3DSTATE_SPAN_STIPPLE" }, + { 0x8c, 1, 2, 2, "3DSTATE_MAP_COORD_TRANSFORM_I830" }, + { 0x8b, 1, 2, 2, "3DSTATE_MAP_VERTEX_TRANSFORM_I830" }, + { 0x8d, 1, 3, 3, "3DSTATE_W_STATE_I830" }, + { 0x01, 1, 2, 2, "3DSTATE_COLOR_FACTOR_I830" }, + { 0x02, 1, 2, 2, "3DSTATE_MAP_COORD_SETBIND_I830"}, + }, *opcode_3d_1d; + + opcode = (data[0] & 0x00ff0000) >> 16; + + switch (opcode) { + case 0x07: + /* This instruction is unusual. A 0 length means just + * 1 DWORD instead of 2. The 0 length is specified in + * one place to be unsupported, but stated to be + * required in another, and 0 length LOAD_INDIRECTs + * appear to cause no harm at least. + */ + instr_out(ctx, 0, "3DSTATE_LOAD_INDIRECT\n"); + len = (data[0] & 0x000000ff) + 1; + i = 1; + if (data[0] & (0x01 << 8)) { + instr_out(ctx, i++, "SIS.0\n"); + instr_out(ctx, i++, "SIS.1\n"); + } + if (data[0] & (0x02 << 8)) { + instr_out(ctx, i++, "DIS.0\n"); + } + if (data[0] & (0x04 << 8)) { + instr_out(ctx, i++, "SSB.0\n"); + instr_out(ctx, i++, "SSB.1\n"); + } + if (data[0] & (0x08 << 8)) { + instr_out(ctx, i++, "MSB.0\n"); + instr_out(ctx, i++, "MSB.1\n"); + } + if (data[0] & (0x10 << 8)) { + instr_out(ctx, i++, "PSP.0\n"); + instr_out(ctx, i++, "PSP.1\n"); + } + if (data[0] & (0x20 << 8)) { + instr_out(ctx, i++, "PSC.0\n"); + instr_out(ctx, i++, "PSC.1\n"); + } + if (len != i) { + fprintf(out, "Bad count in 3DSTATE_LOAD_INDIRECT\n"); + return len; + } + return len; + case 0x04: + instr_out(ctx, 0, + "3DSTATE_LOAD_STATE_IMMEDIATE_1\n"); + len = (data[0] & 0x0000000f) + 2; + i = 1; + for (word = 0; word <= 8; word++) { + if (data[0] & (1 << (4 + word))) { + /* save vertex state for decode */ + if (!IS_GEN2(devid)) { + int tex_num; + + if (word == 2) { + saved_s2_set = 1; + saved_s2 = data[i]; + } + if (word == 4) { + saved_s4_set = 1; + saved_s4 = data[i]; + } + + switch (word) { + case 0: + instr_out(ctx, i, + "S0: vbo offset: 0x%08x%s\n", + data[i] & (~1), + data[i] & 1 ? + ", auto cache invalidate disabled" + : ""); + break; + case 1: + instr_out(ctx, i, + "S1: vertex width: %i, vertex pitch: %i\n", + (data[i] >> 24) & + 0x3f, + (data[i] >> 16) & + 0x3f); + break; + case 2: + instr_out(ctx, i, + "S2: texcoord formats: "); + for (tex_num = 0; + tex_num < 8; tex_num++) { + switch ((data[i] >> + tex_num * + 4) & 0xf) { + case 0: + fprintf(out, + "%i=2D ", + tex_num); + break; + case 1: + fprintf(out, + "%i=3D ", + tex_num); + break; + case 2: + fprintf(out, + "%i=4D ", + tex_num); + break; + case 3: + fprintf(out, + "%i=1D ", + tex_num); + break; + case 4: + fprintf(out, + "%i=2D_16 ", + tex_num); + break; + case 5: + fprintf(out, + "%i=4D_16 ", + tex_num); + break; + case 0xf: + fprintf(out, + "%i=NP ", + tex_num); + break; + } + } + fprintf(out, "\n"); + + break; + case 3: + instr_out(ctx, i, + "S3: not documented\n"); + break; + case 4: + { + const char *cullmode = ""; + const char *vfmt_xyzw = ""; + switch ((data[i] >> 13) + & 0x3) { + case 0: + cullmode = + "both"; + break; + case 1: + cullmode = + "none"; + break; + case 2: + cullmode = "cw"; + break; + case 3: + cullmode = + "ccw"; + break; + } + switch (data[i] & + (7 << 6 | 1 << + 2)) { + case 1 << 6: + vfmt_xyzw = + "XYZ,"; + break; + case 2 << 6: + vfmt_xyzw = + "XYZW,"; + break; + case 3 << 6: + vfmt_xyzw = + "XY,"; + break; + case 4 << 6: + vfmt_xyzw = + "XYW,"; + break; + case 1 << 6 | 1 << 2: + vfmt_xyzw = + "XYZF,"; + break; + case 2 << 6 | 1 << 2: + vfmt_xyzw = + "XYZWF,"; + break; + case 3 << 6 | 1 << 2: + vfmt_xyzw = + "XYF,"; + break; + case 4 << 6 | 1 << 2: + vfmt_xyzw = + "XYWF,"; + break; + } + instr_out(ctx, i, + "S4: point_width=%i, line_width=%.1f," + "%s%s%s%s%s cullmode=%s, vfmt=%s%s%s%s%s%s " + "%s%s%s%s%s\n", + (data[i] >> + 23) & 0x1ff, + ((data[i] >> + 19) & 0xf) / + 2.0, + data[i] & (0xf + << + 15) + ? + " flatshade=" + : "", + data[i] & (1 + << + 18) + ? "Alpha," : + "", + data[i] & (1 + << + 17) + ? "Fog," : "", + data[i] & (1 + << + 16) + ? "Specular," + : "", + data[i] & (1 + << + 15) + ? "Color," : + "", cullmode, + data[i] & (1 + << + 12) + ? + "PointWidth," + : "", + data[i] & (1 + << + 11) + ? "SpecFog," : + "", + data[i] & (1 + << + 10) + ? "Color," : + "", + data[i] & (1 + << + 9) + ? "DepthOfs," + : "", + vfmt_xyzw, + data[i] & (1 + << + 9) + ? "FogParam," + : "", + data[i] & (1 + << + 5) + ? + "force default diffuse, " + : "", + data[i] & (1 + << + 4) + ? + "force default specular, " + : "", + data[i] & (1 + << + 3) + ? + "local depth ofs enable, " + : "", + data[i] & (1 + << + 1) + ? + "point sprite enable, " + : "", + data[i] & (1 + << + 0) + ? + "line AA enable, " + : ""); + break; + } + case 5: + { + instr_out(ctx, i, + "S5:%s%s%s%s%s" + "%s%s%s%s stencil_ref=0x%x, stencil_test=%s, " + "stencil_fail=%s, stencil_pass_z_fail=%s, " + "stencil_pass_z_pass=%s, %s%s%s%s\n", + data[i] & (0xf + << + 28) + ? + " write_disable=" + : "", + data[i] & (1 + << + 31) + ? "Alpha," : + "", + data[i] & (1 + << + 30) + ? "Red," : "", + data[i] & (1 + << + 29) + ? "Green," : + "", + data[i] & (1 + << + 28) + ? "Blue," : + "", + data[i] & (1 + << + 27) + ? + " force default point size," + : "", + data[i] & (1 + << + 26) + ? + " last pixel enable," + : "", + data[i] & (1 + << + 25) + ? + " global depth ofs enable," + : "", + data[i] & (1 + << + 24) + ? + " fog enable," + : "", + (data[i] >> + 16) & 0xff, + decode_compare_func + (data[i] >> + 13), + decode_stencil_op + (data[i] >> + 10), + decode_stencil_op + (data[i] >> + 7), + decode_stencil_op + (data[i] >> + 4), + data[i] & (1 + << + 3) + ? + "stencil write enable, " + : "", + data[i] & (1 + << + 2) + ? + "stencil test enable, " + : "", + data[i] & (1 + << + 1) + ? + "color dither enable, " + : "", + data[i] & (1 + << + 0) + ? + "logicop enable, " + : ""); + } + break; + case 6: + instr_out(ctx, i, + "S6: %salpha_test=%s, alpha_ref=0x%x, " + "depth_test=%s, %ssrc_blnd_fct=%s, dst_blnd_fct=%s, " + "%s%stristrip_provoking_vertex=%i\n", + data[i] & (1 << 31) ? + "alpha test enable, " + : "", + decode_compare_func + (data[i] >> 28), + data[i] & (0xff << + 20), + decode_compare_func + (data[i] >> 16), + data[i] & (1 << 15) ? + "cbuf blend enable, " + : "", + decode_blend_fact(data + [i] + >> + 8), + decode_blend_fact(data + [i] + >> + 4), + data[i] & (1 << 3) ? + "depth write enable, " + : "", + data[i] & (1 << 2) ? + "cbuf write enable, " + : "", + data[i] & (0x3)); + break; + case 7: + instr_out(ctx, i, + "S7: depth offset constant: 0x%08x\n", + data[i]); + break; + } + } else { + instr_out(ctx, i, + "S%d: 0x%08x\n", word, data[i]); + } + i++; + } + } + if (len != i) { + fprintf(out, + "Bad count in 3DSTATE_LOAD_STATE_IMMEDIATE_1\n"); + } + return len; + case 0x03: + instr_out(ctx, 0, + "3DSTATE_LOAD_STATE_IMMEDIATE_2\n"); + len = (data[0] & 0x0000000f) + 2; + i = 1; + for (word = 6; word <= 14; word++) { + if (data[0] & (1 << word)) { + if (word == 6) + instr_out(ctx, i++, + "TBCF\n"); + else if (word >= 7 && word <= 10) { + instr_out(ctx, i++, + "TB%dC\n", word - 7); + instr_out(ctx, i++, + "TB%dA\n", word - 7); + } else if (word >= 11 && word <= 14) { + instr_out(ctx, i, + "TM%dS0: offset=0x%08x, %s\n", + word - 11, + data[i] & 0xfffffffe, + data[i] & 1 ? "use fence" : + ""); + i++; + instr_out(ctx, i, + "TM%dS1: height=%i, width=%i, %s\n", + word - 11, data[i] >> 21, + (data[i] >> 10) & 0x3ff, + data[i] & 2 ? (data[i] & 1 ? + "y-tiled" : + "x-tiled") : + ""); + i++; + instr_out(ctx, i, + "TM%dS2: pitch=%i, \n", + word - 11, + ((data[i] >> 21) + 1) * 4); + i++; + instr_out(ctx, i++, + "TM%dS3\n", word - 11); + instr_out(ctx, i++, + "TM%dS4: dflt color\n", + word - 11); + } + } + } + if (len != i) { + fprintf(out, + "Bad count in 3DSTATE_LOAD_STATE_IMMEDIATE_2\n"); + } + return len; + case 0x00: + instr_out(ctx, 0, "3DSTATE_MAP_STATE\n"); + len = (data[0] & 0x0000003f) + 2; + instr_out(ctx, 1, "mask\n"); + + i = 2; + for (map = 0; map <= 15; map++) { + if (data[1] & (1 << map)) { + int width, height, pitch, dword; + const char *tiling; + + dword = data[i]; + instr_out(ctx, i++, + "map %d MS2 %s%s%s\n", map, + dword & (1 << 31) ? + "untrusted surface, " : "", + dword & (1 << 1) ? + "vertical line stride enable, " : "", + dword & (1 << 0) ? + "vertical ofs enable, " : ""); + + dword = data[i]; + width = ((dword >> 10) & ((1 << 11) - 1)) + 1; + height = ((dword >> 21) & ((1 << 11) - 1)) + 1; + + tiling = "none"; + if (dword & (1 << 2)) + tiling = "fenced"; + else if (dword & (1 << 1)) + tiling = dword & (1 << 0) ? "Y" : "X"; + type = " BAD"; + format = "BAD"; + switch ((dword >> 7) & 0x7) { + case 1: + type = "8b"; + switch ((dword >> 3) & 0xf) { + case 0: + format = "I"; + break; + case 1: + format = "L"; + break; + case 4: + format = "A"; + break; + case 5: + format = " mono"; + break; + } + break; + case 2: + type = "16b"; + switch ((dword >> 3) & 0xf) { + case 0: + format = " rgb565"; + break; + case 1: + format = " argb1555"; + break; + case 2: + format = " argb4444"; + break; + case 5: + format = " ay88"; + break; + case 6: + format = " bump655"; + break; + case 7: + format = "I"; + break; + case 8: + format = "L"; + break; + case 9: + format = "A"; + break; + } + break; + case 3: + type = "32b"; + switch ((dword >> 3) & 0xf) { + case 0: + format = " argb8888"; + break; + case 1: + format = " abgr8888"; + break; + case 2: + format = " xrgb8888"; + break; + case 3: + format = " xbgr8888"; + break; + case 4: + format = " qwvu8888"; + break; + case 5: + format = " axvu8888"; + break; + case 6: + format = " lxvu8888"; + break; + case 7: + format = " xlvu8888"; + break; + case 8: + format = " argb2101010"; + break; + case 9: + format = " abgr2101010"; + break; + case 10: + format = " awvu2101010"; + break; + case 11: + format = " gr1616"; + break; + case 12: + format = " vu1616"; + break; + case 13: + format = " xI824"; + break; + case 14: + format = " xA824"; + break; + case 15: + format = " xL824"; + break; + } + break; + case 5: + type = "422"; + switch ((dword >> 3) & 0xf) { + case 0: + format = " yuv_swapy"; + break; + case 1: + format = " yuv"; + break; + case 2: + format = " yuv_swapuv"; + break; + case 3: + format = " yuv_swapuvy"; + break; + } + break; + case 6: + type = "compressed"; + switch ((dword >> 3) & 0x7) { + case 0: + format = " dxt1"; + break; + case 1: + format = " dxt2_3"; + break; + case 2: + format = " dxt4_5"; + break; + case 3: + format = " fxt1"; + break; + case 4: + format = " dxt1_rb"; + break; + } + break; + case 7: + type = "4b indexed"; + switch ((dword >> 3) & 0xf) { + case 7: + format = " argb8888"; + break; + } + break; + } + dword = data[i]; + instr_out(ctx, i++, + "map %d MS3 [width=%d, height=%d, format=%s%s, tiling=%s%s]\n", + map, width, height, type, format, + tiling, + dword & (1 << 9) ? " palette select" : + ""); + + dword = data[i]; + pitch = + 4 * (((dword >> 21) & ((1 << 11) - 1)) + 1); + instr_out(ctx, i++, + "map %d MS4 [pitch=%d, max_lod=%i, vol_depth=%i, cube_face_ena=%x, %s]\n", + map, pitch, (dword >> 9) & 0x3f, + dword & 0xff, (dword >> 15) & 0x3f, + dword & (1 << 8) ? "miplayout legacy" + : "miplayout right"); + } + } + if (len != i) { + fprintf(out, "Bad count in 3DSTATE_MAP_STATE\n"); + return len; + } + return len; + case 0x06: + instr_out(ctx, 0, + "3DSTATE_PIXEL_SHADER_CONSTANTS\n"); + len = (data[0] & 0x000000ff) + 2; + + i = 2; + for (c = 0; c <= 31; c++) { + if (data[1] & (1 << c)) { + instr_out(ctx, i, "C%d.X = %f\n", c, + int_as_float(data[i])); + i++; + instr_out(ctx, i, "C%d.Y = %f\n", + c, int_as_float(data[i])); + i++; + instr_out(ctx, i, "C%d.Z = %f\n", + c, int_as_float(data[i])); + i++; + instr_out(ctx, i, "C%d.W = %f\n", + c, int_as_float(data[i])); + i++; + } + } + if (len != i) { + fprintf(out, + "Bad count in 3DSTATE_PIXEL_SHADER_CONSTANTS\n"); + } + return len; + case 0x05: + instr_out(ctx, 0, "3DSTATE_PIXEL_SHADER_PROGRAM\n"); + len = (data[0] & 0x000000ff) + 2; + if ((len - 1) % 3 != 0 || len > 370) { + fprintf(out, + "Bad count in 3DSTATE_PIXEL_SHADER_PROGRAM\n"); + } + i = 1; + for (instr = 0; instr < (len - 1) / 3; instr++) { + char instr_prefix[10]; + + sprintf(instr_prefix, "PS%03d", instr); + i915_decode_instruction(ctx, i, + instr_prefix); + i += 3; + } + return len; + case 0x01: + if (IS_GEN2(devid)) + break; + instr_out(ctx, 0, "3DSTATE_SAMPLER_STATE\n"); + instr_out(ctx, 1, "mask\n"); + len = (data[0] & 0x0000003f) + 2; + i = 2; + for (sampler = 0; sampler <= 15; sampler++) { + if (data[1] & (1 << sampler)) { + uint32_t dword; + const char *mip_filter = ""; + + dword = data[i]; + switch ((dword >> 20) & 0x3) { + case 0: + mip_filter = "none"; + break; + case 1: + mip_filter = "nearest"; + break; + case 3: + mip_filter = "linear"; + break; + } + instr_out(ctx, i++, + "sampler %d SS2:%s%s%s " + "base_mip_level=%i, mip_filter=%s, mag_filter=%s, min_filter=%s " + "lod_bias=%.2f,%s max_aniso=%i, shadow_func=%s\n", + sampler, + dword & (1 << 31) ? " reverse gamma," + : "", + dword & (1 << 30) ? " packed2planar," + : "", + dword & (1 << 29) ? + " colorspace conversion," : "", + (dword >> 22) & 0x1f, mip_filter, + decode_sample_filter(dword >> 17), + decode_sample_filter(dword >> 14), + ((dword >> 5) & 0x1ff) / (0x10 * 1.0), + dword & (1 << 4) ? " shadow," : "", + dword & (1 << 3) ? 4 : 2, + decode_compare_func(dword)); + dword = data[i]; + instr_out(ctx, i++, + "sampler %d SS3: min_lod=%.2f,%s " + "tcmode_x=%s, tcmode_y=%s, tcmode_z=%s,%s texmap_idx=%i,%s\n", + sampler, + ((dword >> 24) & 0xff) / (0x10 * 1.0), + dword & (1 << 17) ? + " kill pixel enable," : "", + decode_tex_coord_mode(dword >> 12), + decode_tex_coord_mode(dword >> 9), + decode_tex_coord_mode(dword >> 6), + dword & (1 << 5) ? + " normalized coords," : "", + (dword >> 1) & 0xf, + dword & (1 << 0) ? " deinterlacer," : + ""); + dword = data[i]; + instr_out(ctx, i++, + "sampler %d SS4: border color\n", + sampler); + } + } + if (len != i) { + fprintf(out, "Bad count in 3DSTATE_SAMPLER_STATE\n"); + } + return len; + case 0x85: + len = (data[0] & 0x0000000f) + 2; + + if (len != 2) + fprintf(out, + "Bad count in 3DSTATE_DEST_BUFFER_VARIABLES\n"); + + instr_out(ctx, 0, + "3DSTATE_DEST_BUFFER_VARIABLES\n"); + + switch ((data[1] >> 8) & 0xf) { + case 0x0: + format = "g8"; + break; + case 0x1: + format = "x1r5g5b5"; + break; + case 0x2: + format = "r5g6b5"; + break; + case 0x3: + format = "a8r8g8b8"; + break; + case 0x4: + format = "ycrcb_swapy"; + break; + case 0x5: + format = "ycrcb_normal"; + break; + case 0x6: + format = "ycrcb_swapuv"; + break; + case 0x7: + format = "ycrcb_swapuvy"; + break; + case 0x8: + format = "a4r4g4b4"; + break; + case 0x9: + format = "a1r5g5b5"; + break; + case 0xa: + format = "a2r10g10b10"; + break; + default: + format = "BAD"; + break; + } + switch ((data[1] >> 2) & 0x3) { + case 0x0: + zformat = "u16"; + break; + case 0x1: + zformat = "f16"; + break; + case 0x2: + zformat = "u24x8"; + break; + default: + zformat = "BAD"; + break; + } + instr_out(ctx, 1, + "%s format, %s depth format, early Z %sabled\n", + format, zformat, + (data[1] & (1 << 31)) ? "en" : "dis"); + return len; + + case 0x8e: + { + const char *name, *tiling; + + len = (data[0] & 0x0000000f) + 2; + if (len != 3) + fprintf(out, + "Bad count in 3DSTATE_BUFFER_INFO\n"); + + switch ((data[1] >> 24) & 0x7) { + case 0x3: + name = "color"; + break; + case 0x7: + name = "depth"; + break; + default: + name = "unknown"; + break; + } + + tiling = "none"; + if (data[1] & (1 << 23)) + tiling = "fenced"; + else if (data[1] & (1 << 22)) + tiling = data[1] & (1 << 21) ? "Y" : "X"; + + instr_out(ctx, 0, "3DSTATE_BUFFER_INFO\n"); + instr_out(ctx, 1, + "%s, tiling = %s, pitch=%d\n", name, tiling, + data[1] & 0xffff); + + instr_out(ctx, 2, "address\n"); + return len; + } + case 0x81: + len = (data[0] & 0x0000000f) + 2; + + if (len != 3) + fprintf(out, + "Bad count in 3DSTATE_SCISSOR_RECTANGLE\n"); + + instr_out(ctx, 0, "3DSTATE_SCISSOR_RECTANGLE\n"); + instr_out(ctx, 1, "(%d,%d)\n", + data[1] & 0xffff, data[1] >> 16); + instr_out(ctx, 2, "(%d,%d)\n", + data[2] & 0xffff, data[2] >> 16); + + return len; + case 0x80: + len = (data[0] & 0x0000000f) + 2; + + if (len != 5) + fprintf(out, + "Bad count in 3DSTATE_DRAWING_RECTANGLE\n"); + + instr_out(ctx, 0, "3DSTATE_DRAWING_RECTANGLE\n"); + instr_out(ctx, 1, "%s\n", + data[1] & (1 << 30) ? "depth ofs disabled " : ""); + instr_out(ctx, 2, "(%d,%d)\n", + data[2] & 0xffff, data[2] >> 16); + instr_out(ctx, 3, "(%d,%d)\n", + data[3] & 0xffff, data[3] >> 16); + instr_out(ctx, 4, "(%d,%d)\n", + data[4] & 0xffff, data[4] >> 16); + + return len; + case 0x9c: + len = (data[0] & 0x0000000f) + 2; + + if (len != 7) + fprintf(out, "Bad count in 3DSTATE_CLEAR_PARAMETERS\n"); + + instr_out(ctx, 0, "3DSTATE_CLEAR_PARAMETERS\n"); + instr_out(ctx, 1, "prim_type=%s, clear=%s%s%s\n", + data[1] & (1 << 16) ? "CLEAR_RECT" : "ZONE_INIT", + data[1] & (1 << 2) ? "color," : "", + data[1] & (1 << 1) ? "depth," : "", + data[1] & (1 << 0) ? "stencil," : ""); + instr_out(ctx, 2, "clear color\n"); + instr_out(ctx, 3, "clear depth/stencil\n"); + instr_out(ctx, 4, "color value (rgba8888)\n"); + instr_out(ctx, 5, "depth value %f\n", + int_as_float(data[5])); + instr_out(ctx, 6, "clear stencil\n"); + return len; + } + + for (idx = 0; idx < ARRAY_SIZE(opcodes_3d_1d); idx++) { + opcode_3d_1d = &opcodes_3d_1d[idx]; + if (opcode_3d_1d->i830_only && !IS_GEN2(devid)) + continue; + + if (((data[0] & 0x00ff0000) >> 16) == opcode_3d_1d->opcode) { + len = 1; + + instr_out(ctx, 0, "%s\n", + opcode_3d_1d->name); + if (opcode_3d_1d->max_len > 1) { + len = (data[0] & 0x0000ffff) + 2; + if (len < opcode_3d_1d->min_len || + len > opcode_3d_1d->max_len) { + fprintf(out, "Bad count in %s\n", + opcode_3d_1d->name); + } + } + + for (i = 1; i < len; i++) { + instr_out(ctx, i, "dword %d\n", i); + } + + return len; + } + } + + instr_out(ctx, 0, "3D UNKNOWN: 3d_1d opcode = 0x%x\n", + opcode); + return 1; +} + +static int +decode_3d_primitive(struct drm_intel_decode *ctx) +{ + uint32_t *data = ctx->data; + uint32_t count = ctx->count; + char immediate = (data[0] & (1 << 23)) == 0; + unsigned int len, i, j, ret; + const char *primtype; + int original_s2 = saved_s2; + int original_s4 = saved_s4; + + switch ((data[0] >> 18) & 0xf) { + case 0x0: + primtype = "TRILIST"; + break; + case 0x1: + primtype = "TRISTRIP"; + break; + case 0x2: + primtype = "TRISTRIP_REVERSE"; + break; + case 0x3: + primtype = "TRIFAN"; + break; + case 0x4: + primtype = "POLYGON"; + break; + case 0x5: + primtype = "LINELIST"; + break; + case 0x6: + primtype = "LINESTRIP"; + break; + case 0x7: + primtype = "RECTLIST"; + break; + case 0x8: + primtype = "POINTLIST"; + break; + case 0x9: + primtype = "DIB"; + break; + case 0xa: + primtype = "CLEAR_RECT"; + saved_s4 = 3 << 6; + saved_s2 = ~0; + break; + default: + primtype = "unknown"; + break; + } + + /* XXX: 3DPRIM_DIB not supported */ + if (immediate) { + len = (data[0] & 0x0003ffff) + 2; + instr_out(ctx, 0, "3DPRIMITIVE inline %s\n", + primtype); + if (count < len) + BUFFER_FAIL(count, len, "3DPRIMITIVE inline"); + if (!saved_s2_set || !saved_s4_set) { + fprintf(out, "unknown vertex format\n"); + for (i = 1; i < len; i++) { + instr_out(ctx, i, + " vertex data (%f float)\n", + int_as_float(data[i])); + } + } else { + unsigned int vertex = 0; + for (i = 1; i < len;) { + unsigned int tc; + +#define VERTEX_OUT(fmt, ...) do { \ + if (i < len) \ + instr_out(ctx, i, " V%d."fmt"\n", vertex, __VA_ARGS__); \ + else \ + fprintf(out, " missing data in V%d\n", vertex); \ + i++; \ +} while (0) + + VERTEX_OUT("X = %f", int_as_float(data[i])); + VERTEX_OUT("Y = %f", int_as_float(data[i])); + switch (saved_s4 >> 6 & 0x7) { + case 0x1: + VERTEX_OUT("Z = %f", + int_as_float(data[i])); + break; + case 0x2: + VERTEX_OUT("Z = %f", + int_as_float(data[i])); + VERTEX_OUT("W = %f", + int_as_float(data[i])); + break; + case 0x3: + break; + case 0x4: + VERTEX_OUT("W = %f", + int_as_float(data[i])); + break; + default: + fprintf(out, "bad S4 position mask\n"); + } + + if (saved_s4 & (1 << 10)) { + VERTEX_OUT + ("color = (A=0x%02x, R=0x%02x, G=0x%02x, " + "B=0x%02x)", data[i] >> 24, + (data[i] >> 16) & 0xff, + (data[i] >> 8) & 0xff, + data[i] & 0xff); + } + if (saved_s4 & (1 << 11)) { + VERTEX_OUT + ("spec = (A=0x%02x, R=0x%02x, G=0x%02x, " + "B=0x%02x)", data[i] >> 24, + (data[i] >> 16) & 0xff, + (data[i] >> 8) & 0xff, + data[i] & 0xff); + } + if (saved_s4 & (1 << 12)) + VERTEX_OUT("width = 0x%08x)", data[i]); + + for (tc = 0; tc <= 7; tc++) { + switch ((saved_s2 >> (tc * 4)) & 0xf) { + case 0x0: + VERTEX_OUT("T%d.X = %f", tc, + int_as_float(data + [i])); + VERTEX_OUT("T%d.Y = %f", tc, + int_as_float(data + [i])); + break; + case 0x1: + VERTEX_OUT("T%d.X = %f", tc, + int_as_float(data + [i])); + VERTEX_OUT("T%d.Y = %f", tc, + int_as_float(data + [i])); + VERTEX_OUT("T%d.Z = %f", tc, + int_as_float(data + [i])); + break; + case 0x2: + VERTEX_OUT("T%d.X = %f", tc, + int_as_float(data + [i])); + VERTEX_OUT("T%d.Y = %f", tc, + int_as_float(data + [i])); + VERTEX_OUT("T%d.Z = %f", tc, + int_as_float(data + [i])); + VERTEX_OUT("T%d.W = %f", tc, + int_as_float(data + [i])); + break; + case 0x3: + VERTEX_OUT("T%d.X = %f", tc, + int_as_float(data + [i])); + break; + case 0x4: + VERTEX_OUT + ("T%d.XY = 0x%08x half-float", + tc, data[i]); + break; + case 0x5: + VERTEX_OUT + ("T%d.XY = 0x%08x half-float", + tc, data[i]); + VERTEX_OUT + ("T%d.ZW = 0x%08x half-float", + tc, data[i]); + break; + case 0xf: + break; + default: + fprintf(out, + "bad S2.T%d format\n", + tc); + } + } + vertex++; + } + } + + ret = len; + } else { + /* indirect vertices */ + len = data[0] & 0x0000ffff; /* index count */ + if (data[0] & (1 << 17)) { + /* random vertex access */ + if (count < (len + 1) / 2 + 1) { + BUFFER_FAIL(count, (len + 1) / 2 + 1, + "3DPRIMITIVE random indirect"); + } + instr_out(ctx, 0, + "3DPRIMITIVE random indirect %s (%d)\n", + primtype, len); + if (len == 0) { + /* vertex indices continue until 0xffff is + * found + */ + for (i = 1; i < count; i++) { + if ((data[i] & 0xffff) == 0xffff) { + instr_out(ctx, i, + " indices: (terminator)\n"); + ret = i; + goto out; + } else if ((data[i] >> 16) == 0xffff) { + instr_out(ctx, i, + " indices: 0x%04x, (terminator)\n", + data[i] & 0xffff); + ret = i; + goto out; + } else { + instr_out(ctx, i, + " indices: 0x%04x, 0x%04x\n", + data[i] & 0xffff, + data[i] >> 16); + } + } + fprintf(out, + "3DPRIMITIVE: no terminator found in index buffer\n"); + ret = count; + goto out; + } else { + /* fixed size vertex index buffer */ + for (j = 1, i = 0; i < len; i += 2, j++) { + if (i * 2 == len - 1) { + instr_out(ctx, j, + " indices: 0x%04x\n", + data[j] & 0xffff); + } else { + instr_out(ctx, j, + " indices: 0x%04x, 0x%04x\n", + data[j] & 0xffff, + data[j] >> 16); + } + } + } + ret = (len + 1) / 2 + 1; + goto out; + } else { + /* sequential vertex access */ + instr_out(ctx, 0, + "3DPRIMITIVE sequential indirect %s, %d starting from " + "%d\n", primtype, len, data[1] & 0xffff); + instr_out(ctx, 1, " start\n"); + ret = 2; + goto out; + } + } + +out: + saved_s2 = original_s2; + saved_s4 = original_s4; + return ret; +} + +static int +decode_3d(struct drm_intel_decode *ctx) +{ + uint32_t opcode; + unsigned int idx; + uint32_t *data = ctx->data; + + struct { + uint32_t opcode; + unsigned int min_len; + unsigned int max_len; + const char *name; + } opcodes_3d[] = { + { 0x06, 1, 1, "3DSTATE_ANTI_ALIASING" }, + { 0x08, 1, 1, "3DSTATE_BACKFACE_STENCIL_OPS" }, + { 0x09, 1, 1, "3DSTATE_BACKFACE_STENCIL_MASKS" }, + { 0x16, 1, 1, "3DSTATE_COORD_SET_BINDINGS" }, + { 0x15, 1, 1, "3DSTATE_FOG_COLOR" }, + { 0x0b, 1, 1, "3DSTATE_INDEPENDENT_ALPHA_BLEND" }, + { 0x0d, 1, 1, "3DSTATE_MODES_4" }, + { 0x0c, 1, 1, "3DSTATE_MODES_5" }, + { 0x07, 1, 1, "3DSTATE_RASTERIZATION_RULES"}, + }, *opcode_3d; + + opcode = (data[0] & 0x1f000000) >> 24; + + switch (opcode) { + case 0x1f: + return decode_3d_primitive(ctx); + case 0x1d: + return decode_3d_1d(ctx); + case 0x1c: + return decode_3d_1c(ctx); + } + + for (idx = 0; idx < ARRAY_SIZE(opcodes_3d); idx++) { + opcode_3d = &opcodes_3d[idx]; + if (opcode == opcode_3d->opcode) { + unsigned int len = 1, i; + + instr_out(ctx, 0, "%s\n", opcode_3d->name); + if (opcode_3d->max_len > 1) { + len = (data[0] & 0xff) + 2; + if (len < opcode_3d->min_len || + len > opcode_3d->max_len) { + fprintf(out, "Bad count in %s\n", + opcode_3d->name); + } + } + + for (i = 1; i < len; i++) { + instr_out(ctx, i, "dword %d\n", i); + } + return len; + } + } + + instr_out(ctx, 0, "3D UNKNOWN: 3d opcode = 0x%x\n", opcode); + return 1; +} + +static const char *get_965_surfacetype(unsigned int surfacetype) +{ + switch (surfacetype) { + case 0: + return "1D"; + case 1: + return "2D"; + case 2: + return "3D"; + case 3: + return "CUBE"; + case 4: + return "BUFFER"; + case 7: + return "NULL"; + default: + return "unknown"; + } +} + +static const char *get_965_depthformat(unsigned int depthformat) +{ + switch (depthformat) { + case 0: + return "s8_z24float"; + case 1: + return "z32float"; + case 2: + return "z24s8"; + case 5: + return "z16"; + default: + return "unknown"; + } +} + +static const char *get_965_element_component(uint32_t data, int component) +{ + uint32_t component_control = (data >> (16 + (3 - component) * 4)) & 0x7; + + switch (component_control) { + case 0: + return "nostore"; + case 1: + switch (component) { + case 0: + return "X"; + case 1: + return "Y"; + case 2: + return "Z"; + case 3: + return "W"; + default: + return "fail"; + } + case 2: + return "0.0"; + case 3: + return "1.0"; + case 4: + return "0x1"; + case 5: + return "VID"; + default: + return "fail"; + } +} + +static const char *get_965_prim_type(uint32_t primtype) +{ + switch (primtype) { + case 0x01: + return "point list"; + case 0x02: + return "line list"; + case 0x03: + return "line strip"; + case 0x04: + return "tri list"; + case 0x05: + return "tri strip"; + case 0x06: + return "tri fan"; + case 0x07: + return "quad list"; + case 0x08: + return "quad strip"; + case 0x09: + return "line list adj"; + case 0x0a: + return "line strip adj"; + case 0x0b: + return "tri list adj"; + case 0x0c: + return "tri strip adj"; + case 0x0d: + return "tri strip reverse"; + case 0x0e: + return "polygon"; + case 0x0f: + return "rect list"; + case 0x10: + return "line loop"; + case 0x11: + return "point list bf"; + case 0x12: + return "line strip cont"; + case 0x13: + return "line strip bf"; + case 0x14: + return "line strip cont bf"; + case 0x15: + return "tri fan no stipple"; + default: + return "fail"; + } +} + +static int +i965_decode_urb_fence(struct drm_intel_decode *ctx, int len) +{ + uint32_t vs_fence, clip_fence, gs_fence, sf_fence, vfe_fence, cs_fence; + uint32_t *data = ctx->data; + + if (len != 3) + fprintf(out, "Bad count in URB_FENCE\n"); + + vs_fence = data[1] & 0x3ff; + gs_fence = (data[1] >> 10) & 0x3ff; + clip_fence = (data[1] >> 20) & 0x3ff; + sf_fence = data[2] & 0x3ff; + vfe_fence = (data[2] >> 10) & 0x3ff; + cs_fence = (data[2] >> 20) & 0x7ff; + + instr_out(ctx, 0, "URB_FENCE: %s%s%s%s%s%s\n", + (data[0] >> 13) & 1 ? "cs " : "", + (data[0] >> 12) & 1 ? "vfe " : "", + (data[0] >> 11) & 1 ? "sf " : "", + (data[0] >> 10) & 1 ? "clip " : "", + (data[0] >> 9) & 1 ? "gs " : "", + (data[0] >> 8) & 1 ? "vs " : ""); + instr_out(ctx, 1, + "vs fence: %d, clip_fence: %d, gs_fence: %d\n", + vs_fence, clip_fence, gs_fence); + instr_out(ctx, 2, + "sf fence: %d, vfe_fence: %d, cs_fence: %d\n", + sf_fence, vfe_fence, cs_fence); + if (gs_fence < vs_fence) + fprintf(out, "gs fence < vs fence!\n"); + if (clip_fence < gs_fence) + fprintf(out, "clip fence < gs fence!\n"); + if (sf_fence < clip_fence) + fprintf(out, "sf fence < clip fence!\n"); + if (cs_fence < sf_fence) + fprintf(out, "cs fence < sf fence!\n"); + + return len; +} + +static void +state_base_out(struct drm_intel_decode *ctx, unsigned int index, + const char *name) +{ + if (ctx->data[index] & 1) { + instr_out(ctx, index, + "%s state base address 0x%08x\n", name, + ctx->data[index] & ~1); + } else { + instr_out(ctx, index, "%s state base not updated\n", + name); + } +} + +static void +state_max_out(struct drm_intel_decode *ctx, unsigned int index, + const char *name) +{ + if (ctx->data[index] & 1) { + if (ctx->data[index] == 1) { + instr_out(ctx, index, + "%s state upper bound disabled\n", name); + } else { + instr_out(ctx, index, + "%s state upper bound 0x%08x\n", name, + ctx->data[index] & ~1); + } + } else { + instr_out(ctx, index, + "%s state upper bound not updated\n", name); + } +} + +static int +gen7_3DSTATE_VIEWPORT_STATE_POINTERS_CC(struct drm_intel_decode *ctx) +{ + instr_out(ctx, 0, "3DSTATE_VIEWPORT_STATE_POINTERS_CC\n"); + instr_out(ctx, 1, "pointer to CC viewport\n"); + + return 2; +} + +static int +gen7_3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP(struct drm_intel_decode *ctx) +{ + instr_out(ctx, 0, "3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP\n"); + instr_out(ctx, 1, "pointer to SF_CLIP viewport\n"); + + return 2; +} + +static int +gen7_3DSTATE_BLEND_STATE_POINTERS(struct drm_intel_decode *ctx) +{ + instr_out(ctx, 0, "3DSTATE_BLEND_STATE_POINTERS\n"); + instr_out(ctx, 1, "pointer to BLEND_STATE at 0x%08x (%s)\n", + ctx->data[1] & ~1, + (ctx->data[1] & 1) ? "changed" : "unchanged"); + + return 2; +} + +static int +gen7_3DSTATE_DEPTH_STENCIL_STATE_POINTERS(struct drm_intel_decode *ctx) +{ + instr_out(ctx, 0, "3DSTATE_DEPTH_STENCIL_STATE_POINTERS\n"); + instr_out(ctx, 1, + "pointer to DEPTH_STENCIL_STATE at 0x%08x (%s)\n", + ctx->data[1] & ~1, + (ctx->data[1] & 1) ? "changed" : "unchanged"); + + return 2; +} + +static int +gen7_3DSTATE_HIER_DEPTH_BUFFER(struct drm_intel_decode *ctx) +{ + instr_out(ctx, 0, "3DSTATE_HIER_DEPTH_BUFFER\n"); + instr_out(ctx, 1, "pitch %db\n", + (ctx->data[1] & 0x1ffff) + 1); + instr_out(ctx, 2, "pointer to HiZ buffer\n"); + + return 3; +} + +static int +gen6_3DSTATE_CC_STATE_POINTERS(struct drm_intel_decode *ctx) +{ + instr_out(ctx, 0, "3DSTATE_CC_STATE_POINTERS\n"); + instr_out(ctx, 1, "blend change %d\n", ctx->data[1] & 1); + instr_out(ctx, 2, "depth stencil change %d\n", + ctx->data[2] & 1); + instr_out(ctx, 3, "cc change %d\n", ctx->data[3] & 1); + + return 4; +} + +static int +gen7_3DSTATE_CC_STATE_POINTERS(struct drm_intel_decode *ctx) +{ + instr_out(ctx, 0, "3DSTATE_CC_STATE_POINTERS\n"); + instr_out(ctx, 1, "pointer to COLOR_CALC_STATE at 0x%08x " + "(%s)\n", + ctx->data[1] & ~1, + (ctx->data[1] & 1) ? "changed" : "unchanged"); + + return 2; +} + +static int +gen7_3DSTATE_URB_unit(struct drm_intel_decode *ctx, const char *unit) +{ + int start_kb = ((ctx->data[1] >> 25) & 0x3f) * 8; + /* the field is # of 512-bit rows - 1, we print bytes */ + int entry_size = (((ctx->data[1] >> 16) & 0x1ff) + 1); + int nr_entries = ctx->data[1] & 0xffff; + + instr_out(ctx, 0, "3DSTATE_URB_%s\n", unit); + instr_out(ctx, 1, + "%dKB start, size=%d 64B rows, nr_entries=%d, total size %dB\n", + start_kb, entry_size, nr_entries, nr_entries * 64 * entry_size); + + return 2; +} + +static int +gen7_3DSTATE_URB_VS(struct drm_intel_decode *ctx) +{ + return gen7_3DSTATE_URB_unit(ctx, "VS"); +} + +static int +gen7_3DSTATE_URB_HS(struct drm_intel_decode *ctx) +{ + return gen7_3DSTATE_URB_unit(ctx, "HS"); +} + +static int +gen7_3DSTATE_URB_DS(struct drm_intel_decode *ctx) +{ + return gen7_3DSTATE_URB_unit(ctx, "DS"); +} + +static int +gen7_3DSTATE_URB_GS(struct drm_intel_decode *ctx) +{ + return gen7_3DSTATE_URB_unit(ctx, "GS"); +} + +static int +gen7_3DSTATE_CONSTANT(struct drm_intel_decode *ctx, const char *unit) +{ + int rlen[4]; + + rlen[0] = (ctx->data[1] >> 0) & 0xffff; + rlen[1] = (ctx->data[1] >> 16) & 0xffff; + rlen[2] = (ctx->data[2] >> 0) & 0xffff; + rlen[3] = (ctx->data[2] >> 16) & 0xffff; + + instr_out(ctx, 0, "3DSTATE_CONSTANT_%s\n", unit); + instr_out(ctx, 1, "len 0 = %d, len 1 = %d\n", rlen[0], rlen[1]); + instr_out(ctx, 2, "len 2 = %d, len 3 = %d\n", rlen[2], rlen[3]); + instr_out(ctx, 3, "pointer to constbuf 0\n"); + instr_out(ctx, 4, "pointer to constbuf 1\n"); + instr_out(ctx, 5, "pointer to constbuf 2\n"); + instr_out(ctx, 6, "pointer to constbuf 3\n"); + + return 7; +} + +static int +gen7_3DSTATE_CONSTANT_VS(struct drm_intel_decode *ctx) +{ + return gen7_3DSTATE_CONSTANT(ctx, "VS"); +} + +static int +gen7_3DSTATE_CONSTANT_GS(struct drm_intel_decode *ctx) +{ + return gen7_3DSTATE_CONSTANT(ctx, "GS"); +} + +static int +gen7_3DSTATE_CONSTANT_PS(struct drm_intel_decode *ctx) +{ + return gen7_3DSTATE_CONSTANT(ctx, "PS"); +} + +static int +gen7_3DSTATE_CONSTANT_DS(struct drm_intel_decode *ctx) +{ + return gen7_3DSTATE_CONSTANT(ctx, "DS"); +} + +static int +gen7_3DSTATE_CONSTANT_HS(struct drm_intel_decode *ctx) +{ + return gen7_3DSTATE_CONSTANT(ctx, "HS"); +} + + +static int +gen6_3DSTATE_WM(struct drm_intel_decode *ctx) +{ + instr_out(ctx, 0, "3DSTATE_WM\n"); + instr_out(ctx, 1, "kernel start pointer 0\n"); + instr_out(ctx, 2, + "SPF=%d, VME=%d, Sampler Count %d, " + "Binding table count %d\n", + (ctx->data[2] >> 31) & 1, + (ctx->data[2] >> 30) & 1, + (ctx->data[2] >> 27) & 7, + (ctx->data[2] >> 18) & 0xff); + instr_out(ctx, 3, "scratch offset\n"); + instr_out(ctx, 4, + "Depth Clear %d, Depth Resolve %d, HiZ Resolve %d, " + "Dispatch GRF start[0] %d, start[1] %d, start[2] %d\n", + (ctx->data[4] & (1 << 30)) != 0, + (ctx->data[4] & (1 << 28)) != 0, + (ctx->data[4] & (1 << 27)) != 0, + (ctx->data[4] >> 16) & 0x7f, + (ctx->data[4] >> 8) & 0x7f, + (ctx->data[4] & 0x7f)); + instr_out(ctx, 5, + "MaxThreads %d, PS KillPixel %d, PS computed Z %d, " + "PS use sourceZ %d, Thread Dispatch %d, PS use sourceW %d, " + "Dispatch32 %d, Dispatch16 %d, Dispatch8 %d\n", + ((ctx->data[5] >> 25) & 0x7f) + 1, + (ctx->data[5] & (1 << 22)) != 0, + (ctx->data[5] & (1 << 21)) != 0, + (ctx->data[5] & (1 << 20)) != 0, + (ctx->data[5] & (1 << 19)) != 0, + (ctx->data[5] & (1 << 8)) != 0, + (ctx->data[5] & (1 << 2)) != 0, + (ctx->data[5] & (1 << 1)) != 0, + (ctx->data[5] & (1 << 0)) != 0); + instr_out(ctx, 6, + "Num SF output %d, Pos XY offset %d, ZW interp mode %d , " + "Barycentric interp mode 0x%x, Point raster rule %d, " + "Multisample mode %d, " + "Multisample Dispatch mode %d\n", + (ctx->data[6] >> 20) & 0x3f, + (ctx->data[6] >> 18) & 3, + (ctx->data[6] >> 16) & 3, + (ctx->data[6] >> 10) & 0x3f, + (ctx->data[6] & (1 << 9)) != 0, + (ctx->data[6] >> 1) & 3, + (ctx->data[6] & 1)); + instr_out(ctx, 7, "kernel start pointer 1\n"); + instr_out(ctx, 8, "kernel start pointer 2\n"); + + return 9; +} + +static int +gen7_3DSTATE_WM(struct drm_intel_decode *ctx) +{ + const char *computed_depth = ""; + const char *early_depth = ""; + const char *zw_interp = ""; + + switch ((ctx->data[1] >> 23) & 0x3) { + case 0: + computed_depth = ""; + break; + case 1: + computed_depth = "computed depth"; + break; + case 2: + computed_depth = "computed depth >="; + break; + case 3: + computed_depth = "computed depth <="; + break; + } + + switch ((ctx->data[1] >> 21) & 0x3) { + case 0: + early_depth = ""; + break; + case 1: + early_depth = ", EDSC_PSEXEC"; + break; + case 2: + early_depth = ", EDSC_PREPS"; + break; + case 3: + early_depth = ", BAD EDSC"; + break; + } + + switch ((ctx->data[1] >> 17) & 0x3) { + case 0: + early_depth = ""; + break; + case 1: + early_depth = ", BAD ZW interp"; + break; + case 2: + early_depth = ", ZW centroid"; + break; + case 3: + early_depth = ", ZW sample"; + break; + } + + instr_out(ctx, 0, "3DSTATE_WM\n"); + instr_out(ctx, 1, "(%s%s%s%s%s%s)%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + (ctx->data[1] & (1 << 11)) ? "PP " : "", + (ctx->data[1] & (1 << 12)) ? "PC " : "", + (ctx->data[1] & (1 << 13)) ? "PS " : "", + (ctx->data[1] & (1 << 14)) ? "NPP " : "", + (ctx->data[1] & (1 << 15)) ? "NPC " : "", + (ctx->data[1] & (1 << 16)) ? "NPS " : "", + (ctx->data[1] & (1 << 30)) ? ", depth clear" : "", + (ctx->data[1] & (1 << 29)) ? "" : ", disabled", + (ctx->data[1] & (1 << 28)) ? ", depth resolve" : "", + (ctx->data[1] & (1 << 27)) ? ", hiz resolve" : "", + (ctx->data[1] & (1 << 25)) ? ", kill" : "", + computed_depth, + early_depth, + zw_interp, + (ctx->data[1] & (1 << 20)) ? ", source depth" : "", + (ctx->data[1] & (1 << 19)) ? ", source W" : "", + (ctx->data[1] & (1 << 10)) ? ", coverage" : "", + (ctx->data[1] & (1 << 4)) ? ", poly stipple" : "", + (ctx->data[1] & (1 << 3)) ? ", line stipple" : "", + (ctx->data[1] & (1 << 2)) ? ", point UL" : ", point UR" + ); + instr_out(ctx, 2, "MS\n"); + + return 3; +} + +static int +gen4_3DPRIMITIVE(struct drm_intel_decode *ctx) +{ + instr_out(ctx, 0, + "3DPRIMITIVE: %s %s\n", + get_965_prim_type((ctx->data[0] >> 10) & 0x1f), + (ctx->data[0] & (1 << 15)) ? "random" : "sequential"); + instr_out(ctx, 1, "vertex count\n"); + instr_out(ctx, 2, "start vertex\n"); + instr_out(ctx, 3, "instance count\n"); + instr_out(ctx, 4, "start instance\n"); + instr_out(ctx, 5, "index bias\n"); + + return 6; +} + +static int +gen7_3DPRIMITIVE(struct drm_intel_decode *ctx) +{ + bool indirect = !!(ctx->data[0] & (1 << 10)); + + instr_out(ctx, 0, + "3DPRIMITIVE: %s%s\n", + indirect ? " indirect" : "", + (ctx->data[0] & (1 << 8)) ? " predicated" : ""); + instr_out(ctx, 1, "%s %s\n", + get_965_prim_type(ctx->data[1] & 0x3f), + (ctx->data[1] & (1 << 8)) ? "random" : "sequential"); + instr_out(ctx, 2, indirect ? "ignored" : "vertex count\n"); + instr_out(ctx, 3, indirect ? "ignored" : "start vertex\n"); + instr_out(ctx, 4, indirect ? "ignored" : "instance count\n"); + instr_out(ctx, 5, indirect ? "ignored" : "start instance\n"); + instr_out(ctx, 6, indirect ? "ignored" : "index bias\n"); + + return 7; +} + +static int +decode_3d_965(struct drm_intel_decode *ctx) +{ + uint32_t opcode; + unsigned int len; + unsigned int i, j, sba_len; + const char *desc1 = NULL; + uint32_t *data = ctx->data; + uint32_t devid = ctx->devid; + + struct { + uint32_t opcode; + uint32_t len_mask; + int unsigned min_len; + int unsigned max_len; + const char *name; + int gen; + int (*func)(struct drm_intel_decode *ctx); + } opcodes_3d[] = { + { 0x6000, 0x00ff, 3, 3, "URB_FENCE" }, + { 0x6001, 0xffff, 2, 2, "CS_URB_STATE" }, + { 0x6002, 0x00ff, 2, 2, "CONSTANT_BUFFER" }, + { 0x6101, 0xffff, 6, 10, "STATE_BASE_ADDRESS" }, + { 0x6102, 0xffff, 2, 2, "STATE_SIP" }, + { 0x6104, 0xffff, 1, 1, "3DSTATE_PIPELINE_SELECT" }, + { 0x680b, 0xffff, 1, 1, "3DSTATE_VF_STATISTICS" }, + { 0x6904, 0xffff, 1, 1, "3DSTATE_PIPELINE_SELECT" }, + { 0x7800, 0xffff, 7, 7, "3DSTATE_PIPELINED_POINTERS" }, + { 0x7801, 0x00ff, 4, 6, "3DSTATE_BINDING_TABLE_POINTERS" }, + { 0x7802, 0x00ff, 4, 4, "3DSTATE_SAMPLER_STATE_POINTERS" }, + { 0x7805, 0x00ff, 7, 7, "3DSTATE_DEPTH_BUFFER", 7 }, + { 0x7805, 0x00ff, 3, 3, "3DSTATE_URB" }, + { 0x7804, 0x00ff, 3, 3, "3DSTATE_CLEAR_PARAMS" }, + { 0x7806, 0x00ff, 3, 3, "3DSTATE_STENCIL_BUFFER" }, + { 0x790f, 0x00ff, 3, 3, "3DSTATE_HIER_DEPTH_BUFFER", 6 }, + { 0x7807, 0x00ff, 3, 3, "3DSTATE_HIER_DEPTH_BUFFER", 7, gen7_3DSTATE_HIER_DEPTH_BUFFER }, + { 0x7808, 0x00ff, 5, 257, "3DSTATE_VERTEX_BUFFERS" }, + { 0x7809, 0x00ff, 3, 256, "3DSTATE_VERTEX_ELEMENTS" }, + { 0x780a, 0x00ff, 3, 3, "3DSTATE_INDEX_BUFFER" }, + { 0x780b, 0xffff, 1, 1, "3DSTATE_VF_STATISTICS" }, + { 0x780d, 0x00ff, 4, 4, "3DSTATE_VIEWPORT_STATE_POINTERS" }, + { 0x780e, 0xffff, 4, 4, NULL, 6, gen6_3DSTATE_CC_STATE_POINTERS }, + { 0x780e, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_CC_STATE_POINTERS }, + { 0x780f, 0x00ff, 2, 2, "3DSTATE_SCISSOR_POINTERS" }, + { 0x7810, 0x00ff, 6, 6, "3DSTATE_VS" }, + { 0x7811, 0x00ff, 7, 7, "3DSTATE_GS" }, + { 0x7812, 0x00ff, 4, 4, "3DSTATE_CLIP" }, + { 0x7813, 0x00ff, 20, 20, "3DSTATE_SF", 6 }, + { 0x7813, 0x00ff, 7, 7, "3DSTATE_SF", 7 }, + { 0x7814, 0x00ff, 3, 3, "3DSTATE_WM", 7, gen7_3DSTATE_WM }, + { 0x7814, 0x00ff, 9, 9, "3DSTATE_WM", 6, gen6_3DSTATE_WM }, + { 0x7815, 0x00ff, 5, 5, "3DSTATE_CONSTANT_VS_STATE", 6 }, + { 0x7815, 0x00ff, 7, 7, "3DSTATE_CONSTANT_VS", 7, gen7_3DSTATE_CONSTANT_VS }, + { 0x7816, 0x00ff, 5, 5, "3DSTATE_CONSTANT_GS_STATE", 6 }, + { 0x7816, 0x00ff, 7, 7, "3DSTATE_CONSTANT_GS", 7, gen7_3DSTATE_CONSTANT_GS }, + { 0x7817, 0x00ff, 5, 5, "3DSTATE_CONSTANT_PS_STATE", 6 }, + { 0x7817, 0x00ff, 7, 7, "3DSTATE_CONSTANT_PS", 7, gen7_3DSTATE_CONSTANT_PS }, + { 0x7818, 0xffff, 2, 2, "3DSTATE_SAMPLE_MASK" }, + { 0x7819, 0x00ff, 7, 7, "3DSTATE_CONSTANT_HS", 7, gen7_3DSTATE_CONSTANT_HS }, + { 0x781a, 0x00ff, 7, 7, "3DSTATE_CONSTANT_DS", 7, gen7_3DSTATE_CONSTANT_DS }, + { 0x781b, 0x00ff, 7, 7, "3DSTATE_HS" }, + { 0x781c, 0x00ff, 4, 4, "3DSTATE_TE" }, + { 0x781d, 0x00ff, 6, 6, "3DSTATE_DS" }, + { 0x781e, 0x00ff, 3, 3, "3DSTATE_STREAMOUT" }, + { 0x781f, 0x00ff, 14, 14, "3DSTATE_SBE" }, + { 0x7820, 0x00ff, 8, 8, "3DSTATE_PS" }, + { 0x7821, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP }, + { 0x7823, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_VIEWPORT_STATE_POINTERS_CC }, + { 0x7824, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_BLEND_STATE_POINTERS }, + { 0x7825, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_DEPTH_STENCIL_STATE_POINTERS }, + { 0x7826, 0x00ff, 2, 2, "3DSTATE_BINDING_TABLE_POINTERS_VS" }, + { 0x7827, 0x00ff, 2, 2, "3DSTATE_BINDING_TABLE_POINTERS_HS" }, + { 0x7828, 0x00ff, 2, 2, "3DSTATE_BINDING_TABLE_POINTERS_DS" }, + { 0x7829, 0x00ff, 2, 2, "3DSTATE_BINDING_TABLE_POINTERS_GS" }, + { 0x782a, 0x00ff, 2, 2, "3DSTATE_BINDING_TABLE_POINTERS_PS" }, + { 0x782b, 0x00ff, 2, 2, "3DSTATE_SAMPLER_STATE_POINTERS_VS" }, + { 0x782c, 0x00ff, 2, 2, "3DSTATE_SAMPLER_STATE_POINTERS_HS" }, + { 0x782d, 0x00ff, 2, 2, "3DSTATE_SAMPLER_STATE_POINTERS_DS" }, + { 0x782e, 0x00ff, 2, 2, "3DSTATE_SAMPLER_STATE_POINTERS_GS" }, + { 0x782f, 0x00ff, 2, 2, "3DSTATE_SAMPLER_STATE_POINTERS_PS" }, + { 0x7830, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_URB_VS }, + { 0x7831, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_URB_HS }, + { 0x7832, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_URB_DS }, + { 0x7833, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_URB_GS }, + { 0x7900, 0xffff, 4, 4, "3DSTATE_DRAWING_RECTANGLE" }, + { 0x7901, 0xffff, 5, 5, "3DSTATE_CONSTANT_COLOR" }, + { 0x7905, 0xffff, 5, 7, "3DSTATE_DEPTH_BUFFER" }, + { 0x7906, 0xffff, 2, 2, "3DSTATE_POLY_STIPPLE_OFFSET" }, + { 0x7907, 0xffff, 33, 33, "3DSTATE_POLY_STIPPLE_PATTERN" }, + { 0x7908, 0xffff, 3, 3, "3DSTATE_LINE_STIPPLE" }, + { 0x7909, 0xffff, 2, 2, "3DSTATE_GLOBAL_DEPTH_OFFSET_CLAMP" }, + { 0x7909, 0xffff, 2, 2, "3DSTATE_CLEAR_PARAMS" }, + { 0x790a, 0xffff, 3, 3, "3DSTATE_AA_LINE_PARAMETERS" }, + { 0x790b, 0xffff, 4, 4, "3DSTATE_GS_SVB_INDEX" }, + { 0x790d, 0xffff, 3, 3, "3DSTATE_MULTISAMPLE", 6 }, + { 0x790d, 0xffff, 4, 4, "3DSTATE_MULTISAMPLE", 7 }, + { 0x7910, 0x00ff, 2, 2, "3DSTATE_CLEAR_PARAMS" }, + { 0x7912, 0x00ff, 2, 2, "3DSTATE_PUSH_CONSTANT_ALLOC_VS" }, + { 0x7913, 0x00ff, 2, 2, "3DSTATE_PUSH_CONSTANT_ALLOC_HS" }, + { 0x7914, 0x00ff, 2, 2, "3DSTATE_PUSH_CONSTANT_ALLOC_DS" }, + { 0x7915, 0x00ff, 2, 2, "3DSTATE_PUSH_CONSTANT_ALLOC_GS" }, + { 0x7916, 0x00ff, 2, 2, "3DSTATE_PUSH_CONSTANT_ALLOC_PS" }, + { 0x7917, 0x00ff, 2, 2+128*2, "3DSTATE_SO_DECL_LIST" }, + { 0x7918, 0x00ff, 4, 4, "3DSTATE_SO_BUFFER" }, + { 0x7a00, 0x00ff, 4, 6, "PIPE_CONTROL" }, + { 0x7b00, 0x00ff, 7, 7, NULL, 7, gen7_3DPRIMITIVE }, + { 0x7b00, 0x00ff, 6, 6, NULL, 0, gen4_3DPRIMITIVE }, + }, *opcode_3d = NULL; + + opcode = (data[0] & 0xffff0000) >> 16; + + for (i = 0; i < ARRAY_SIZE(opcodes_3d); i++) { + if (opcode != opcodes_3d[i].opcode) + continue; + + /* If it's marked as not our gen, skip. */ + if (opcodes_3d[i].gen && opcodes_3d[i].gen != ctx->gen) + continue; + + opcode_3d = &opcodes_3d[i]; + break; + } + + if (opcode_3d) { + if (opcode_3d->max_len == 1) + len = 1; + else + len = (data[0] & opcode_3d->len_mask) + 2; + + if (len < opcode_3d->min_len || + len > opcode_3d->max_len) { + fprintf(out, "Bad length %d in %s, expected %d-%d\n", + len, opcode_3d->name, + opcode_3d->min_len, opcode_3d->max_len); + } + } else { + len = (data[0] & 0x0000ffff) + 2; + } + + switch (opcode) { + case 0x6000: + return i965_decode_urb_fence(ctx, len); + case 0x6001: + instr_out(ctx, 0, "CS_URB_STATE\n"); + instr_out(ctx, 1, + "entry_size: %d [%d bytes], n_entries: %d\n", + (data[1] >> 4) & 0x1f, + (((data[1] >> 4) & 0x1f) + 1) * 64, data[1] & 0x7); + return len; + case 0x6002: + instr_out(ctx, 0, "CONSTANT_BUFFER: %s\n", + (data[0] >> 8) & 1 ? "valid" : "invalid"); + instr_out(ctx, 1, + "offset: 0x%08x, length: %d bytes\n", data[1] & ~0x3f, + ((data[1] & 0x3f) + 1) * 64); + return len; + case 0x6101: + i = 0; + instr_out(ctx, 0, "STATE_BASE_ADDRESS\n"); + i++; + + if (IS_GEN6(devid) || IS_GEN7(devid)) + sba_len = 10; + else if (IS_GEN5(devid)) + sba_len = 8; + else + sba_len = 6; + if (len != sba_len) + fprintf(out, "Bad count in STATE_BASE_ADDRESS\n"); + + state_base_out(ctx, i++, "general"); + state_base_out(ctx, i++, "surface"); + if (IS_GEN6(devid) || IS_GEN7(devid)) + state_base_out(ctx, i++, "dynamic"); + state_base_out(ctx, i++, "indirect"); + if (IS_GEN5(devid) || IS_GEN6(devid) || IS_GEN7(devid)) + state_base_out(ctx, i++, "instruction"); + + state_max_out(ctx, i++, "general"); + if (IS_GEN6(devid) || IS_GEN7(devid)) + state_max_out(ctx, i++, "dynamic"); + state_max_out(ctx, i++, "indirect"); + if (IS_GEN5(devid) || IS_GEN6(devid) || IS_GEN7(devid)) + state_max_out(ctx, i++, "instruction"); + + return len; + case 0x7800: + instr_out(ctx, 0, "3DSTATE_PIPELINED_POINTERS\n"); + instr_out(ctx, 1, "VS state\n"); + instr_out(ctx, 2, "GS state\n"); + instr_out(ctx, 3, "Clip state\n"); + instr_out(ctx, 4, "SF state\n"); + instr_out(ctx, 5, "WM state\n"); + instr_out(ctx, 6, "CC state\n"); + return len; + case 0x7801: + if (len != 6 && len != 4) + fprintf(out, + "Bad count in 3DSTATE_BINDING_TABLE_POINTERS\n"); + if (len == 6) { + instr_out(ctx, 0, + "3DSTATE_BINDING_TABLE_POINTERS\n"); + instr_out(ctx, 1, "VS binding table\n"); + instr_out(ctx, 2, "GS binding table\n"); + instr_out(ctx, 3, "Clip binding table\n"); + instr_out(ctx, 4, "SF binding table\n"); + instr_out(ctx, 5, "WM binding table\n"); + } else { + instr_out(ctx, 0, + "3DSTATE_BINDING_TABLE_POINTERS: VS mod %d, " + "GS mod %d, PS mod %d\n", + (data[0] & (1 << 8)) != 0, + (data[0] & (1 << 9)) != 0, + (data[0] & (1 << 12)) != 0); + instr_out(ctx, 1, "VS binding table\n"); + instr_out(ctx, 2, "GS binding table\n"); + instr_out(ctx, 3, "WM binding table\n"); + } + + return len; + case 0x7802: + instr_out(ctx, 0, + "3DSTATE_SAMPLER_STATE_POINTERS: VS mod %d, " + "GS mod %d, PS mod %d\n", (data[0] & (1 << 8)) != 0, + (data[0] & (1 << 9)) != 0, + (data[0] & (1 << 12)) != 0); + instr_out(ctx, 1, "VS sampler state\n"); + instr_out(ctx, 2, "GS sampler state\n"); + instr_out(ctx, 3, "WM sampler state\n"); + return len; + case 0x7805: + /* Actually 3DSTATE_DEPTH_BUFFER on gen7. */ + if (ctx->gen == 7) + break; + + instr_out(ctx, 0, "3DSTATE_URB\n"); + instr_out(ctx, 1, + "VS entries %d, alloc size %d (1024bit row)\n", + data[1] & 0xffff, ((data[1] >> 16) & 0x07f) + 1); + instr_out(ctx, 2, + "GS entries %d, alloc size %d (1024bit row)\n", + (data[2] >> 8) & 0x3ff, (data[2] & 7) + 1); + return len; + + case 0x7808: + if ((len - 1) % 4 != 0) + fprintf(out, "Bad count in 3DSTATE_VERTEX_BUFFERS\n"); + instr_out(ctx, 0, "3DSTATE_VERTEX_BUFFERS\n"); + + for (i = 1; i < len;) { + int idx, access; + if (IS_GEN6(devid)) { + idx = 26; + access = 20; + } else { + idx = 27; + access = 26; + } + instr_out(ctx, i, + "buffer %d: %s, pitch %db\n", data[i] >> idx, + data[i] & (1 << access) ? "random" : + "sequential", data[i] & 0x07ff); + i++; + instr_out(ctx, i++, "buffer address\n"); + instr_out(ctx, i++, "max index\n"); + instr_out(ctx, i++, "mbz\n"); + } + return len; + + case 0x7809: + if ((len + 1) % 2 != 0) + fprintf(out, "Bad count in 3DSTATE_VERTEX_ELEMENTS\n"); + instr_out(ctx, 0, "3DSTATE_VERTEX_ELEMENTS\n"); + + for (i = 1; i < len;) { + instr_out(ctx, i, + "buffer %d: %svalid, type 0x%04x, " + "src offset 0x%04x bytes\n", + data[i] >> ((IS_GEN6(devid) || IS_GEN7(devid)) ? 26 : 27), + data[i] & (1 << ((IS_GEN6(devid) || IS_GEN7(devid)) ? 25 : 26)) ? + "" : "in", (data[i] >> 16) & 0x1ff, + data[i] & 0x07ff); + i++; + instr_out(ctx, i, "(%s, %s, %s, %s), " + "dst offset 0x%02x bytes\n", + get_965_element_component(data[i], 0), + get_965_element_component(data[i], 1), + get_965_element_component(data[i], 2), + get_965_element_component(data[i], 3), + (data[i] & 0xff) * 4); + i++; + } + return len; + + case 0x780d: + instr_out(ctx, 0, + "3DSTATE_VIEWPORT_STATE_POINTERS\n"); + instr_out(ctx, 1, "clip\n"); + instr_out(ctx, 2, "sf\n"); + instr_out(ctx, 3, "cc\n"); + return len; + + case 0x780a: + instr_out(ctx, 0, "3DSTATE_INDEX_BUFFER\n"); + instr_out(ctx, 1, "beginning buffer address\n"); + instr_out(ctx, 2, "ending buffer address\n"); + return len; + + case 0x780f: + instr_out(ctx, 0, "3DSTATE_SCISSOR_POINTERS\n"); + instr_out(ctx, 1, "scissor rect offset\n"); + return len; + + case 0x7810: + instr_out(ctx, 0, "3DSTATE_VS\n"); + instr_out(ctx, 1, "kernel pointer\n"); + instr_out(ctx, 2, + "SPF=%d, VME=%d, Sampler Count %d, " + "Binding table count %d\n", (data[2] >> 31) & 1, + (data[2] >> 30) & 1, (data[2] >> 27) & 7, + (data[2] >> 18) & 0xff); + instr_out(ctx, 3, "scratch offset\n"); + instr_out(ctx, 4, + "Dispatch GRF start %d, VUE read length %d, " + "VUE read offset %d\n", (data[4] >> 20) & 0x1f, + (data[4] >> 11) & 0x3f, (data[4] >> 4) & 0x3f); + instr_out(ctx, 5, + "Max Threads %d, Vertex Cache %sable, " + "VS func %sable\n", ((data[5] >> 25) & 0x7f) + 1, + (data[5] & (1 << 1)) != 0 ? "dis" : "en", + (data[5] & 1) != 0 ? "en" : "dis"); + return len; + + case 0x7811: + instr_out(ctx, 0, "3DSTATE_GS\n"); + instr_out(ctx, 1, "kernel pointer\n"); + instr_out(ctx, 2, + "SPF=%d, VME=%d, Sampler Count %d, " + "Binding table count %d\n", (data[2] >> 31) & 1, + (data[2] >> 30) & 1, (data[2] >> 27) & 7, + (data[2] >> 18) & 0xff); + instr_out(ctx, 3, "scratch offset\n"); + instr_out(ctx, 4, + "Dispatch GRF start %d, VUE read length %d, " + "VUE read offset %d\n", (data[4] & 0xf), + (data[4] >> 11) & 0x3f, (data[4] >> 4) & 0x3f); + instr_out(ctx, 5, + "Max Threads %d, Rendering %sable\n", + ((data[5] >> 25) & 0x7f) + 1, + (data[5] & (1 << 8)) != 0 ? "en" : "dis"); + instr_out(ctx, 6, + "Reorder %sable, Discard Adjaceny %sable, " + "GS %sable\n", + (data[6] & (1 << 30)) != 0 ? "en" : "dis", + (data[6] & (1 << 29)) != 0 ? "en" : "dis", + (data[6] & (1 << 15)) != 0 ? "en" : "dis"); + return len; + + case 0x7812: + instr_out(ctx, 0, "3DSTATE_CLIP\n"); + instr_out(ctx, 1, + "UserClip distance cull test mask 0x%x\n", + data[1] & 0xff); + instr_out(ctx, 2, + "Clip %sable, API mode %s, Viewport XY test %sable, " + "Viewport Z test %sable, Guardband test %sable, Clip mode %d, " + "Perspective Divide %sable, Non-Perspective Barycentric %sable, " + "Tri Provoking %d, Line Provoking %d, Trifan Provoking %d\n", + (data[2] & (1 << 31)) != 0 ? "en" : "dis", + (data[2] & (1 << 30)) != 0 ? "D3D" : "OGL", + (data[2] & (1 << 28)) != 0 ? "en" : "dis", + (data[2] & (1 << 27)) != 0 ? "en" : "dis", + (data[2] & (1 << 26)) != 0 ? "en" : "dis", + (data[2] >> 13) & 7, + (data[2] & (1 << 9)) != 0 ? "dis" : "en", + (data[2] & (1 << 8)) != 0 ? "en" : "dis", + (data[2] >> 4) & 3, (data[2] >> 2) & 3, + (data[2] & 3)); + instr_out(ctx, 3, + "Min PointWidth %d, Max PointWidth %d, " + "Force Zero RTAIndex %sable, Max VPIndex %d\n", + (data[3] >> 17) & 0x7ff, (data[3] >> 6) & 0x7ff, + (data[3] & (1 << 5)) != 0 ? "en" : "dis", + (data[3] & 0xf)); + return len; + + case 0x7813: + if (ctx->gen == 7) + break; + + instr_out(ctx, 0, "3DSTATE_SF\n"); + instr_out(ctx, 1, + "Attrib Out %d, Attrib Swizzle %sable, VUE read length %d, " + "VUE read offset %d\n", (data[1] >> 22) & 0x3f, + (data[1] & (1 << 21)) != 0 ? "en" : "dis", + (data[1] >> 11) & 0x1f, (data[1] >> 4) & 0x3f); + instr_out(ctx, 2, + "Legacy Global DepthBias %sable, FrontFace fill %d, BF fill %d, " + "VP transform %sable, FrontWinding_%s\n", + (data[2] & (1 << 11)) != 0 ? "en" : "dis", + (data[2] >> 5) & 3, (data[2] >> 3) & 3, + (data[2] & (1 << 1)) != 0 ? "en" : "dis", + (data[2] & 1) != 0 ? "CCW" : "CW"); + instr_out(ctx, 3, + "AA %sable, CullMode %d, Scissor %sable, Multisample m ode %d\n", + (data[3] & (1 << 31)) != 0 ? "en" : "dis", + (data[3] >> 29) & 3, + (data[3] & (1 << 11)) != 0 ? "en" : "dis", + (data[3] >> 8) & 3); + instr_out(ctx, 4, + "Last Pixel %sable, SubPixel Precision %d, Use PixelWidth %d\n", + (data[4] & (1 << 31)) != 0 ? "en" : "dis", + (data[4] & (1 << 12)) != 0 ? 4 : 8, + (data[4] & (1 << 11)) != 0); + instr_out(ctx, 5, + "Global Depth Offset Constant %f\n", + *(float *)(&data[5])); + instr_out(ctx, 6, "Global Depth Offset Scale %f\n", + *(float *)(&data[6])); + instr_out(ctx, 7, "Global Depth Offset Clamp %f\n", + *(float *)(&data[7])); + + for (i = 0, j = 0; i < 8; i++, j += 2) + instr_out(ctx, i + 8, + "Attrib %d (Override %s%s%s%s, Const Source %d, Swizzle Select %d, " + "Source %d); Attrib %d (Override %s%s%s%s, Const Source %d, Swizzle Select %d, Source %d)\n", + j + 1, + (data[8 + i] & (1 << 31)) != 0 ? "W" : "", + (data[8 + i] & (1 << 30)) != 0 ? "Z" : "", + (data[8 + i] & (1 << 29)) != 0 ? "Y" : "", + (data[8 + i] & (1 << 28)) != 0 ? "X" : "", + (data[8 + i] >> 25) & 3, + (data[8 + i] >> 22) & 3, + (data[8 + i] >> 16) & 0x1f, j, + (data[8 + i] & (1 << 15)) != 0 ? "W" : "", + (data[8 + i] & (1 << 14)) != 0 ? "Z" : "", + (data[8 + i] & (1 << 13)) != 0 ? "Y" : "", + (data[8 + i] & (1 << 12)) != 0 ? "X" : "", + (data[8 + i] >> 9) & 3, + (data[8 + i] >> 6) & 3, (data[8 + i] & 0x1f)); + instr_out(ctx, 16, + "Point Sprite TexCoord Enable\n"); + instr_out(ctx, 17, "Const Interp Enable\n"); + instr_out(ctx, 18, + "Attrib 7-0 WrapShortest Enable\n"); + instr_out(ctx, 19, + "Attrib 15-8 WrapShortest Enable\n"); + + return len; + + case 0x7900: + instr_out(ctx, 0, "3DSTATE_DRAWING_RECTANGLE\n"); + instr_out(ctx, 1, "top left: %d,%d\n", + data[1] & 0xffff, (data[1] >> 16) & 0xffff); + instr_out(ctx, 2, "bottom right: %d,%d\n", + data[2] & 0xffff, (data[2] >> 16) & 0xffff); + instr_out(ctx, 3, "origin: %d,%d\n", + (int)data[3] & 0xffff, ((int)data[3] >> 16) & 0xffff); + + return len; + + case 0x7905: + instr_out(ctx, 0, "3DSTATE_DEPTH_BUFFER\n"); + if (IS_GEN5(devid) || IS_GEN6(devid)) + instr_out(ctx, 1, + "%s, %s, pitch = %d bytes, %stiled, HiZ %d, Separate Stencil %d\n", + get_965_surfacetype(data[1] >> 29), + get_965_depthformat((data[1] >> 18) & 0x7), + (data[1] & 0x0001ffff) + 1, + data[1] & (1 << 27) ? "" : "not ", + (data[1] & (1 << 22)) != 0, + (data[1] & (1 << 21)) != 0); + else + instr_out(ctx, 1, + "%s, %s, pitch = %d bytes, %stiled\n", + get_965_surfacetype(data[1] >> 29), + get_965_depthformat((data[1] >> 18) & 0x7), + (data[1] & 0x0001ffff) + 1, + data[1] & (1 << 27) ? "" : "not "); + instr_out(ctx, 2, "depth offset\n"); + instr_out(ctx, 3, "%dx%d\n", + ((data[3] & 0x0007ffc0) >> 6) + 1, + ((data[3] & 0xfff80000) >> 19) + 1); + instr_out(ctx, 4, "volume depth\n"); + if (len >= 6) + instr_out(ctx, 5, "\n"); + if (len >= 7) { + if (IS_GEN6(devid)) + instr_out(ctx, 6, "\n"); + else + instr_out(ctx, 6, + "render target view extent\n"); + } + + return len; + + case 0x7a00: + if (IS_GEN6(devid) || IS_GEN7(devid)) { + if (len != 4 && len != 5) + fprintf(out, "Bad count in PIPE_CONTROL\n"); + + switch ((data[1] >> 14) & 0x3) { + case 0: + desc1 = "no write"; + break; + case 1: + desc1 = "qword write"; + break; + case 2: + desc1 = "PS_DEPTH_COUNT write"; + break; + case 3: + desc1 = "TIMESTAMP write"; + break; + } + instr_out(ctx, 0, "PIPE_CONTROL\n"); + instr_out(ctx, 1, + "%s, %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + desc1, + data[1] & (1 << 20) ? "cs stall, " : "", + data[1] & (1 << 19) ? + "global snapshot count reset, " : "", + data[1] & (1 << 18) ? "tlb invalidate, " : "", + data[1] & (1 << 17) ? "gfdt flush, " : "", + data[1] & (1 << 17) ? "media state clear, " : + "", + data[1] & (1 << 13) ? "depth stall, " : "", + data[1] & (1 << 12) ? + "render target cache flush, " : "", + data[1] & (1 << 11) ? + "instruction cache invalidate, " : "", + data[1] & (1 << 10) ? + "texture cache invalidate, " : "", + data[1] & (1 << 9) ? + "indirect state invalidate, " : "", + data[1] & (1 << 8) ? "notify irq, " : "", + data[1] & (1 << 7) ? "PIPE_CONTROL flush, " : + "", + data[1] & (1 << 6) ? "protect mem app_id, " : + "", data[1] & (1 << 5) ? "DC flush, " : "", + data[1] & (1 << 4) ? "vf fetch invalidate, " : + "", + data[1] & (1 << 3) ? + "constant cache invalidate, " : "", + data[1] & (1 << 2) ? + "state cache invalidate, " : "", + data[1] & (1 << 1) ? "stall at scoreboard, " : + "", + data[1] & (1 << 0) ? "depth cache flush, " : + ""); + if (len == 5) { + instr_out(ctx, 2, + "destination address\n"); + instr_out(ctx, 3, + "immediate dword low\n"); + instr_out(ctx, 4, + "immediate dword high\n"); + } else { + for (i = 2; i < len; i++) { + instr_out(ctx, i, "\n"); + } + } + return len; + } else { + if (len != 4) + fprintf(out, "Bad count in PIPE_CONTROL\n"); + + switch ((data[0] >> 14) & 0x3) { + case 0: + desc1 = "no write"; + break; + case 1: + desc1 = "qword write"; + break; + case 2: + desc1 = "PS_DEPTH_COUNT write"; + break; + case 3: + desc1 = "TIMESTAMP write"; + break; + } + instr_out(ctx, 0, + "PIPE_CONTROL: %s, %sdepth stall, %sRC write flush, " + "%sinst flush\n", + desc1, + data[0] & (1 << 13) ? "" : "no ", + data[0] & (1 << 12) ? "" : "no ", + data[0] & (1 << 11) ? "" : "no "); + instr_out(ctx, 1, "destination address\n"); + instr_out(ctx, 2, "immediate dword low\n"); + instr_out(ctx, 3, "immediate dword high\n"); + return len; + } + } + + if (opcode_3d) { + if (opcode_3d->func) { + return opcode_3d->func(ctx); + } else { + instr_out(ctx, 0, "%s\n", opcode_3d->name); + + for (i = 1; i < len; i++) { + instr_out(ctx, i, "dword %d\n", i); + } + return len; + } + } + + instr_out(ctx, 0, "3D UNKNOWN: 3d_965 opcode = 0x%x\n", + opcode); + return 1; +} + +static int +decode_3d_i830(struct drm_intel_decode *ctx) +{ + unsigned int idx; + uint32_t opcode; + uint32_t *data = ctx->data; + + struct { + uint32_t opcode; + unsigned int min_len; + unsigned int max_len; + const char *name; + } opcodes_3d[] = { + { 0x02, 1, 1, "3DSTATE_MODES_3" }, + { 0x03, 1, 1, "3DSTATE_ENABLES_1" }, + { 0x04, 1, 1, "3DSTATE_ENABLES_2" }, + { 0x05, 1, 1, "3DSTATE_VFT0" }, + { 0x06, 1, 1, "3DSTATE_AA" }, + { 0x07, 1, 1, "3DSTATE_RASTERIZATION_RULES" }, + { 0x08, 1, 1, "3DSTATE_MODES_1" }, + { 0x09, 1, 1, "3DSTATE_STENCIL_TEST" }, + { 0x0a, 1, 1, "3DSTATE_VFT1" }, + { 0x0b, 1, 1, "3DSTATE_INDPT_ALPHA_BLEND" }, + { 0x0c, 1, 1, "3DSTATE_MODES_5" }, + { 0x0d, 1, 1, "3DSTATE_MAP_BLEND_OP" }, + { 0x0e, 1, 1, "3DSTATE_MAP_BLEND_ARG" }, + { 0x0f, 1, 1, "3DSTATE_MODES_2" }, + { 0x15, 1, 1, "3DSTATE_FOG_COLOR" }, + { 0x16, 1, 1, "3DSTATE_MODES_4"}, + }, *opcode_3d; + + opcode = (data[0] & 0x1f000000) >> 24; + + switch (opcode) { + case 0x1f: + return decode_3d_primitive(ctx); + case 0x1d: + return decode_3d_1d(ctx); + case 0x1c: + return decode_3d_1c(ctx); + } + + for (idx = 0; idx < ARRAY_SIZE(opcodes_3d); idx++) { + opcode_3d = &opcodes_3d[idx]; + if ((data[0] & 0x1f000000) >> 24 == opcode_3d->opcode) { + unsigned int len = 1, i; + + instr_out(ctx, 0, "%s\n", opcode_3d->name); + if (opcode_3d->max_len > 1) { + len = (data[0] & 0xff) + 2; + if (len < opcode_3d->min_len || + len > opcode_3d->max_len) { + fprintf(out, "Bad count in %s\n", + opcode_3d->name); + } + } + + for (i = 1; i < len; i++) { + instr_out(ctx, i, "dword %d\n", i); + } + return len; + } + } + + instr_out(ctx, 0, "3D UNKNOWN: 3d_i830 opcode = 0x%x\n", + opcode); + return 1; +} + +drm_public struct drm_intel_decode * +drm_intel_decode_context_alloc(uint32_t devid) +{ + struct drm_intel_decode *ctx; + int gen = 0; + + if (intel_get_genx(devid, &gen)) + ; + else if (IS_GEN8(devid)) + gen = 8; + else if (IS_GEN7(devid)) + gen = 7; + else if (IS_GEN6(devid)) + gen = 6; + else if (IS_GEN5(devid)) + gen = 5; + else if (IS_GEN4(devid)) + gen = 4; + else if (IS_9XX(devid)) + gen = 3; + else if (IS_GEN2(devid)) + gen = 2; + + if (!gen) + return NULL; + + ctx = calloc(1, sizeof(struct drm_intel_decode)); + if (!ctx) + return NULL; + + ctx->devid = devid; + ctx->gen = gen; + ctx->out = stdout; + + return ctx; +} + +drm_public void +drm_intel_decode_context_free(struct drm_intel_decode *ctx) +{ + free(ctx); +} + +drm_public void +drm_intel_decode_set_dump_past_end(struct drm_intel_decode *ctx, + int dump_past_end) +{ + ctx->dump_past_end = !!dump_past_end; +} + +drm_public void +drm_intel_decode_set_batch_pointer(struct drm_intel_decode *ctx, + void *data, uint32_t hw_offset, int count) +{ + ctx->base_data = data; + ctx->base_hw_offset = hw_offset; + ctx->base_count = count; +} + +drm_public void +drm_intel_decode_set_head_tail(struct drm_intel_decode *ctx, + uint32_t head, uint32_t tail) +{ + ctx->head = head; + ctx->tail = tail; +} + +drm_public void +drm_intel_decode_set_output_file(struct drm_intel_decode *ctx, + FILE *output) +{ + ctx->out = output; +} + +/** + * Decodes an i830-i915 batch buffer, writing the output to stdout. + * + * \param data batch buffer contents + * \param count number of DWORDs to decode in the batch buffer + * \param hw_offset hardware address for the buffer + */ +drm_public void +drm_intel_decode(struct drm_intel_decode *ctx) +{ + int ret; + unsigned int index = 0; + uint32_t devid; + int size; + void *temp; + + if (!ctx) + return; + + /* Put a scratch page full of obviously undefined data after + * the batchbuffer. This lets us avoid a bunch of length + * checking in statically sized packets. + */ + size = ctx->base_count * 4; + temp = malloc(size + 4096); + memcpy(temp, ctx->base_data, size); + memset((char *)temp + size, 0xd0, 4096); + ctx->data = temp; + + ctx->hw_offset = ctx->base_hw_offset; + ctx->count = ctx->base_count; + + devid = ctx->devid; + head_offset = ctx->head; + tail_offset = ctx->tail; + out = ctx->out; + + saved_s2_set = 0; + saved_s4_set = 1; + + while (ctx->count > 0) { + index = 0; + + switch ((ctx->data[index] & 0xe0000000) >> 29) { + case 0x0: + ret = decode_mi(ctx); + + /* If MI_BATCHBUFFER_END happened, then dump + * the rest of the output in case we some day + * want it in debugging, but don't decode it + * since it'll just confuse in the common + * case. + */ + if (ret == -1) { + if (ctx->dump_past_end) { + index++; + } else { + for (index = index + 1; index < ctx->count; + index++) { + instr_out(ctx, index, "\n"); + } + } + } else + index += ret; + break; + case 0x2: + index += decode_2d(ctx); + break; + case 0x3: + if (IS_9XX(devid) && !IS_GEN3(devid)) { + index += + decode_3d_965(ctx); + } else if (IS_GEN3(devid)) { + index += decode_3d(ctx); + } else { + index += + decode_3d_i830(ctx); + } + break; + default: + instr_out(ctx, index, "UNKNOWN\n"); + index++; + break; + } + fflush(out); + + if (ctx->count < index) + break; + + ctx->count -= index; + ctx->data += index; + ctx->hw_offset += 4 * index; + } + + free(temp); +} diff --git a/intel/libdrm_intel.pc.in b/intel/libdrm_intel.pc.in new file mode 100644 index 0000000..670e4fe --- /dev/null +++ b/intel/libdrm_intel.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libdrm_intel +Description: Userspace interface to intel kernel DRM services +Version: @PACKAGE_VERSION@ +Requires: libdrm +Libs: -L${libdir} -ldrm_intel +Cflags: -I${includedir} -I${includedir}/libdrm diff --git a/intel/meson.build b/intel/meson.build new file mode 100644 index 0000000..e6550da --- /dev/null +++ b/intel/meson.build @@ -0,0 +1,109 @@ +# Copyright © 2017-2018 Intel Corporation + +# 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. + +libdrm_intel = library( + 'drm_intel', + [ + files( + 'intel_bufmgr.c', 'intel_bufmgr_fake.c', 'intel_bufmgr_gem.c', + 'intel_decode.c', 'mm.c', 'intel_chipset.c', + ), + config_file, + ], + include_directories : [inc_root, inc_drm], + link_with : libdrm, + dependencies : [dep_pciaccess, dep_pthread_stubs, dep_rt, dep_valgrind, dep_atomic_ops], + c_args : libdrm_c_args, + gnu_symbol_visibility : 'hidden', + version : '1.0.0', + install : true, +) + +ext_libdrm_intel = declare_dependency( + link_with : [libdrm, libdrm_intel], + include_directories : [inc_drm, include_directories('.')], +) + +if meson.version().version_compare('>= 0.54.0') + meson.override_dependency('libdrm_intel', ext_libdrm_intel) +endif + +install_headers( + 'intel_bufmgr.h', 'intel_aub.h', 'intel_debug.h', + subdir : 'libdrm', +) + +pkg.generate( + libdrm_intel, + name : 'libdrm_intel', + subdirs : ['.', 'libdrm'], + requires : 'libdrm', + description : 'Userspace interface to intel kernel DRM services', +) + +test_decode = executable( + 'test_decode', + files('test_decode.c'), + include_directories : [inc_root, inc_drm], + link_with : [libdrm, libdrm_intel], + c_args : libdrm_c_args, + gnu_symbol_visibility : 'hidden', +) + +test( + 'gen4-3d.batch', + find_program('tests/gen4-3d.batch.sh'), + workdir : meson.current_build_dir(), +) +test( + 'gen45-3d.batch', + find_program('tests/gm45-3d.batch.sh'), + workdir : meson.current_build_dir(), +) +test( + 'gen5-3d.batch', + find_program('tests/gen5-3d.batch.sh'), + workdir : meson.current_build_dir(), +) +test( + 'gen6-3d.batch', + find_program('tests/gen6-3d.batch.sh'), + workdir : meson.current_build_dir(), +) +test( + 'gen7-3d.batch', + find_program('tests/gen7-3d.batch.sh'), + workdir : meson.current_build_dir(), +) +test( + 'gen7-2d-copy.batch', + find_program('tests/gen7-2d-copy.batch.sh'), + workdir : meson.current_build_dir(), +) + +test( + 'intel-symbols-check', + symbols_check, + args : [ + '--lib', libdrm_intel, + '--symbols-file', files('intel-symbols.txt'), + '--nm', prog_nm.path(), + ], +) diff --git a/intel/mm.c b/intel/mm.c new file mode 100644 index 0000000..79d8719 --- /dev/null +++ b/intel/mm.c @@ -0,0 +1,260 @@ +/* + * GLX Hardware Device Driver common code + * Copyright (C) 1999 Wittawat Yamwong + * + * 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 + * WITTAWAT YAMWONG, OR ANY OTHER CONTRIBUTORS 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. + * + */ + +#include +#include + +#include "xf86drm.h" +#include "libdrm_macros.h" +#include "mm.h" + +drm_private void mmDumpMemInfo(const struct mem_block *heap) +{ + drmMsg("Memory heap %p:\n", (void *)heap); + if (heap == 0) { + drmMsg(" heap == 0\n"); + } else { + const struct mem_block *p; + + for (p = heap->next; p != heap; p = p->next) { + drmMsg(" Offset:%08x, Size:%08x, %c%c\n", p->ofs, + p->size, p->free ? 'F' : '.', + p->reserved ? 'R' : '.'); + } + + drmMsg("\nFree list:\n"); + + for (p = heap->next_free; p != heap; p = p->next_free) { + drmMsg(" FREE Offset:%08x, Size:%08x, %c%c\n", p->ofs, + p->size, p->free ? 'F' : '.', + p->reserved ? 'R' : '.'); + } + + } + drmMsg("End of memory blocks\n"); +} + +drm_private struct mem_block *mmInit(int ofs, int size) +{ + struct mem_block *heap, *block; + + if (size <= 0) + return NULL; + + heap = (struct mem_block *)calloc(1, sizeof(struct mem_block)); + if (!heap) + return NULL; + + block = (struct mem_block *)calloc(1, sizeof(struct mem_block)); + if (!block) { + free(heap); + return NULL; + } + + heap->next = block; + heap->prev = block; + heap->next_free = block; + heap->prev_free = block; + + block->heap = heap; + block->next = heap; + block->prev = heap; + block->next_free = heap; + block->prev_free = heap; + + block->ofs = ofs; + block->size = size; + block->free = 1; + + return heap; +} + +static struct mem_block *SliceBlock(struct mem_block *p, + int startofs, int size, + int reserved, int alignment) +{ + struct mem_block *newblock; + + /* break left [p, newblock, p->next], then p = newblock */ + if (startofs > p->ofs) { + newblock = + (struct mem_block *)calloc(1, sizeof(struct mem_block)); + if (!newblock) + return NULL; + newblock->ofs = startofs; + newblock->size = p->size - (startofs - p->ofs); + newblock->free = 1; + newblock->heap = p->heap; + + newblock->next = p->next; + newblock->prev = p; + p->next->prev = newblock; + p->next = newblock; + + newblock->next_free = p->next_free; + newblock->prev_free = p; + p->next_free->prev_free = newblock; + p->next_free = newblock; + + p->size -= newblock->size; + p = newblock; + } + + /* break right, also [p, newblock, p->next] */ + if (size < p->size) { + newblock = + (struct mem_block *)calloc(1, sizeof(struct mem_block)); + if (!newblock) + return NULL; + newblock->ofs = startofs + size; + newblock->size = p->size - size; + newblock->free = 1; + newblock->heap = p->heap; + + newblock->next = p->next; + newblock->prev = p; + p->next->prev = newblock; + p->next = newblock; + + newblock->next_free = p->next_free; + newblock->prev_free = p; + p->next_free->prev_free = newblock; + p->next_free = newblock; + + p->size = size; + } + + /* p = middle block */ + p->free = 0; + + /* Remove p from the free list: + */ + p->next_free->prev_free = p->prev_free; + p->prev_free->next_free = p->next_free; + + p->next_free = 0; + p->prev_free = 0; + + p->reserved = reserved; + return p; +} + +drm_private struct mem_block *mmAllocMem(struct mem_block *heap, int size, + int align2, int startSearch) +{ + struct mem_block *p; + const int mask = (1 << align2) - 1; + int startofs = 0; + int endofs; + + if (!heap || align2 < 0 || size <= 0) + return NULL; + + for (p = heap->next_free; p != heap; p = p->next_free) { + assert(p->free); + + startofs = (p->ofs + mask) & ~mask; + if (startofs < startSearch) { + startofs = startSearch; + } + endofs = startofs + size; + if (endofs <= (p->ofs + p->size)) + break; + } + + if (p == heap) + return NULL; + + assert(p->free); + p = SliceBlock(p, startofs, size, 0, mask + 1); + + return p; +} + +static int Join2Blocks(struct mem_block *p) +{ + /* XXX there should be some assertions here */ + + /* NOTE: heap->free == 0 */ + + if (p->free && p->next->free) { + struct mem_block *q = p->next; + + assert(p->ofs + p->size == q->ofs); + p->size += q->size; + + p->next = q->next; + q->next->prev = p; + + q->next_free->prev_free = q->prev_free; + q->prev_free->next_free = q->next_free; + + free(q); + return 1; + } + return 0; +} + +drm_private int mmFreeMem(struct mem_block *b) +{ + if (!b) + return 0; + + if (b->free) { + drmMsg("block already free\n"); + return -1; + } + if (b->reserved) { + drmMsg("block is reserved\n"); + return -1; + } + + b->free = 1; + b->next_free = b->heap->next_free; + b->prev_free = b->heap; + b->next_free->prev_free = b; + b->prev_free->next_free = b; + + Join2Blocks(b); + if (b->prev != b->heap) + Join2Blocks(b->prev); + + return 0; +} + +drm_private void mmDestroy(struct mem_block *heap) +{ + struct mem_block *p; + + if (!heap) + return; + + for (p = heap->next; p != heap;) { + struct mem_block *next = p->next; + free(p); + p = next; + } + + free(heap); +} diff --git a/intel/mm.h b/intel/mm.h new file mode 100644 index 0000000..be3d90d --- /dev/null +++ b/intel/mm.h @@ -0,0 +1,80 @@ +/* + * GLX Hardware Device Driver common code + * Copyright (C) 1999 Wittawat Yamwong + * + * 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 + * KEITH WHITWELL, OR ANY OTHER CONTRIBUTORS 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. + */ + +/** + * Memory manager code. Primarily used by device drivers to manage texture + * heaps, etc. + */ + +#ifndef MM_H +#define MM_H + +#include "libdrm_macros.h" + +struct mem_block { + struct mem_block *next, *prev; + struct mem_block *next_free, *prev_free; + struct mem_block *heap; + int ofs, size; + unsigned int free:1; + unsigned int reserved:1; +}; + +/** + * input: total size in bytes + * return: a heap pointer if OK, NULL if error + */ +drm_private extern struct mem_block *mmInit(int ofs, int size); + +/** + * Allocate 'size' bytes with 2^align2 bytes alignment, + * restrict the search to free memory after 'startSearch' + * depth and back buffers should be in different 4mb banks + * to get better page hits if possible + * input: size = size of block + * align2 = 2^align2 bytes alignment + * startSearch = linear offset from start of heap to begin search + * return: pointer to the allocated block, 0 if error + */ +drm_private extern struct mem_block *mmAllocMem(struct mem_block *heap, + int size, int align2, + int startSearch); + +/** + * Free block starts at offset + * input: pointer to a block + * return: 0 if OK, -1 if error + */ +drm_private extern int mmFreeMem(struct mem_block *b); + +/** + * destroy MM + */ +drm_private extern void mmDestroy(struct mem_block *mmInit); + +/** + * For debugging purpose. + */ +drm_private extern void mmDumpMemInfo(const struct mem_block *mmInit); + +#endif diff --git a/intel/test_decode.c b/intel/test_decode.c new file mode 100644 index 0000000..c47752c --- /dev/null +++ b/intel/test_decode.c @@ -0,0 +1,195 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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 (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 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libdrm_macros.h" +#include "intel_bufmgr.h" +#include "intel_chipset.h" + +#define HW_OFFSET 0x12300000 + +static void +usage(void) +{ + fprintf(stderr, "usage:\n"); + fprintf(stderr, " test_decode \n"); + fprintf(stderr, " test_decode -dump\n"); + exit(1); +} + +static void +read_file(const char *filename, void **ptr, size_t *size) +{ + int fd, ret; + struct stat st; + + fd = open(filename, O_RDONLY); + if (fd < 0) + errx(1, "couldn't open `%s'", filename); + + ret = fstat(fd, &st); + if (ret) + errx(1, "couldn't stat `%s'", filename); + + *size = st.st_size; + *ptr = drm_mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (*ptr == MAP_FAILED) + errx(1, "couldn't map `%s'", filename); + + close(fd); +} + +static void +dump_batch(struct drm_intel_decode *ctx, const char *batch_filename) +{ + void *batch_ptr; + size_t batch_size; + + read_file(batch_filename, &batch_ptr, &batch_size); + + drm_intel_decode_set_batch_pointer(ctx, batch_ptr, HW_OFFSET, + batch_size / 4); + drm_intel_decode_set_output_file(ctx, stdout); + + drm_intel_decode(ctx); +} + +static void +compare_batch(struct drm_intel_decode *ctx, const char *batch_filename) +{ + FILE *out = NULL; + char *ptr; + void *ref_ptr, *batch_ptr; +#if HAVE_OPEN_MEMSTREAM + size_t size; +#endif + size_t ref_size, batch_size; + const char *ref_suffix = "-ref.txt"; + char *ref_filename; + + ref_filename = malloc(strlen(batch_filename) + strlen(ref_suffix) + 1); + sprintf(ref_filename, "%s%s", batch_filename, ref_suffix); + + /* Read the batch and reference. */ + read_file(batch_filename, &batch_ptr, &batch_size); + read_file(ref_filename, &ref_ptr, &ref_size); + + /* Set up our decode output in memory, because I don't want to + * figure out how to output to a file in a safe and sane way + * inside of an automake project's test infrastructure. + */ +#if HAVE_OPEN_MEMSTREAM + out = open_memstream(&ptr, &size); +#else + fprintf(stderr, "platform lacks open_memstream, skipping.\n"); + exit(77); +#endif + + drm_intel_decode_set_batch_pointer(ctx, batch_ptr, HW_OFFSET, + batch_size / 4); + drm_intel_decode_set_output_file(ctx, out); + + drm_intel_decode(ctx); + + if (strcmp(ref_ptr, ptr) != 0) { + fprintf(stderr, "Decode mismatch with reference `%s'.\n", + ref_filename); + fprintf(stderr, "You can dump the new output using:\n"); + fprintf(stderr, " test_decode \"%s\" -dump\n", batch_filename); + exit(1); + } + + fclose(out); + free(ref_filename); + free(ptr); +} + +static uint16_t +infer_devid(const char *batch_filename) +{ + struct { + const char *name; + uint16_t devid; + } chipsets[] = { + { "830", 0x3577}, + { "855", 0x3582}, + { "945", 0x2772}, + { "gen4", 0x2a02 }, + { "gm45", 0x2a42 }, + { "gen5", PCI_CHIP_ILD_G }, + { "gen6", PCI_CHIP_SANDYBRIDGE_GT2 }, + { "gen7", PCI_CHIP_IVYBRIDGE_GT2 }, + { "gen8", 0x1616 }, + { NULL, 0 }, + }; + int i; + + for (i = 0; chipsets[i].name != NULL; i++) { + if (strstr(batch_filename, chipsets[i].name)) + return chipsets[i].devid; + } + + fprintf(stderr, "Couldn't guess chipset id from batch filename `%s'.\n", + batch_filename); + fprintf(stderr, "Must be contain one of:\n"); + for (i = 0; chipsets[i].name != NULL; i++) { + fprintf(stderr, " %s\n", chipsets[i].name); + } + exit(1); +} + +int +main(int argc, char **argv) +{ + uint16_t devid; + struct drm_intel_decode *ctx; + + if (argc < 2) + usage(); + + + devid = infer_devid(argv[1]); + + ctx = drm_intel_decode_context_alloc(devid); + + if (argc == 3) { + if (strcmp(argv[2], "-dump") == 0) + dump_batch(ctx, argv[1]); + else + usage(); + } else { + compare_batch(ctx, argv[1]); + } + + drm_intel_decode_context_free(ctx); + + return 0; +} diff --git a/intel/tests/.gitignore b/intel/tests/.gitignore new file mode 100644 index 0000000..e9d01ec --- /dev/null +++ b/intel/tests/.gitignore @@ -0,0 +1 @@ +*-new.txt diff --git a/intel/tests/gen4-3d.batch b/intel/tests/gen4-3d.batch new file mode 100644 index 0000000..e6911a4 Binary files /dev/null and b/intel/tests/gen4-3d.batch differ diff --git a/intel/tests/gen4-3d.batch-ref.txt b/intel/tests/gen4-3d.batch-ref.txt new file mode 100644 index 0000000..20aa1d4 --- /dev/null +++ b/intel/tests/gen4-3d.batch-ref.txt @@ -0,0 +1,488 @@ +0x12300000: 0x61040000: 3DSTATE_PIPELINE_SELECT +0x12300004: 0x79090000: 3DSTATE_GLOBAL_DEPTH_OFFSET_CLAMP +0x12300008: 0x00000000: dword 1 +0x1230000c: 0x61020000: STATE_SIP +0x12300010: 0x00000000: dword 1 +0x12300014: 0x780b0000: 3DSTATE_VF_STATISTICS +0x12300018: 0x61010004: STATE_BASE_ADDRESS +0x1230001c: 0x00000001: general state base address 0x00000000 +0x12300020: 0x00000001: surface state base address 0x00000000 +0x12300024: 0x00000001: indirect state base address 0x00000000 +0x12300028: 0x00000001: general state upper bound disabled +0x1230002c: 0x00000001: indirect state upper bound disabled +0x12300030: 0x78010004: 3DSTATE_BINDING_TABLE_POINTERS +0x12300034: 0x00007e20: VS binding table +0x12300038: 0x00000000: GS binding table +0x1230003c: 0x00000000: Clip binding table +0x12300040: 0x00000000: SF binding table +0x12300044: 0x00007e20: WM binding table +0x12300048: 0x79010003: 3DSTATE_CONSTANT_COLOR +0x1230004c: 0x00000000: dword 1 +0x12300050: 0x00000000: dword 2 +0x12300054: 0x00000000: dword 3 +0x12300058: 0x00000000: dword 4 +0x1230005c: 0x79050003: 3DSTATE_DEPTH_BUFFER +0x12300060: 0x2c0805ff: 2D, z24s8, pitch = 1536 bytes, tiled +0x12300064: 0x00000000: depth offset +0x12300068: 0x09584ac0: 300x300 +0x1230006c: 0x00000000: volume depth +0x12300070: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300074: 0x00007d60: VS state +0x12300078: 0x00000000: GS state +0x1230007c: 0x00007d21: Clip state +0x12300080: 0x00007d80: SF state +0x12300084: 0x00007de0: WM state +0x12300088: 0x00007fc0: CC state +0x1230008c: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300090: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300094: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x12300098: 0x60010000: CS_URB_STATE +0x1230009c: 0x00000024: entry_size: 2 [192 bytes], n_entries: 4 +0x123000a0: 0x79000002: 3DSTATE_DRAWING_RECTANGLE +0x123000a4: 0x00000000: top left: 0,0 +0x123000a8: 0x012b012b: bottom right: 299,299 +0x123000ac: 0x00000000: origin: 0,0 +0x123000b0: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x123000b4: 0x0000000c: buffer 0: sequential, pitch 12b +0x123000b8: 0x00000000: buffer address +0x123000bc: 0x00000000: max index +0x123000c0: 0x00000000: mbz +0x123000c4: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x123000c8: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123000cc: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123000d0: 0x60020100: CONSTANT_BUFFER: valid +0x123000d4: 0x00000001: offset: 0x00000000, length: 128 bytes +0x123000d8: 0x7b001804: 3DPRIMITIVE: tri fan sequential +0x123000dc: 0x00000004: vertex count +0x123000e0: 0x00000000: start vertex +0x123000e4: 0x00000001: instance count +0x123000e8: 0x00000000: start instance +0x123000ec: 0x00000000: index bias +0x123000f0: 0x78010004: 3DSTATE_BINDING_TABLE_POINTERS +0x123000f4: 0x00007b40: VS binding table +0x123000f8: 0x00000000: GS binding table +0x123000fc: 0x00000000: Clip binding table +0x12300100: 0x00000000: SF binding table +0x12300104: 0x00007b40: WM binding table +0x12300108: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x1230010c: 0x00007aa0: VS state +0x12300110: 0x00007a41: GS state +0x12300114: 0x00007a61: Clip state +0x12300118: 0x00007ac0: SF state +0x1230011c: 0x00007b00: WM state +0x12300120: 0x00007cc0: CC state +0x12300124: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300128: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x1230012c: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x12300130: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300134: 0x0000000c: buffer 0: sequential, pitch 12b +0x12300138: 0x00000000: buffer address +0x1230013c: 0x00000000: max index +0x12300140: 0x00000000: mbz +0x12300144: 0x60020100: CONSTANT_BUFFER: valid +0x12300148: 0x00000082: offset: 0x00000080, length: 192 bytes +0x1230014c: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300150: 0x00000052: vertex count +0x12300154: 0x00000000: start vertex +0x12300158: 0x00000001: instance count +0x1230015c: 0x00000000: start instance +0x12300160: 0x00000000: index bias +0x12300164: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300168: 0x00007aa0: VS state +0x1230016c: 0x00007a21: GS state +0x12300170: 0x00007a61: Clip state +0x12300174: 0x00007ac0: SF state +0x12300178: 0x00007b00: WM state +0x1230017c: 0x00007cc0: CC state +0x12300180: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300184: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300188: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x1230018c: 0x60020100: CONSTANT_BUFFER: valid +0x12300190: 0x00000082: offset: 0x00000080, length: 192 bytes +0x12300194: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300198: 0x00000050: vertex count +0x1230019c: 0x00000052: start vertex +0x123001a0: 0x00000001: instance count +0x123001a4: 0x00000000: start instance +0x123001a8: 0x00000000: index bias +0x123001ac: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123001b0: 0x00007aa0: VS state +0x123001b4: 0x00007a01: GS state +0x123001b8: 0x00007a61: Clip state +0x123001bc: 0x00007ac0: SF state +0x123001c0: 0x00007b00: WM state +0x123001c4: 0x00007cc0: CC state +0x123001c8: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123001cc: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x123001d0: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x123001d4: 0x60020100: CONSTANT_BUFFER: valid +0x123001d8: 0x00000142: offset: 0x00000140, length: 192 bytes +0x123001dc: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123001e0: 0x00000052: vertex count +0x123001e4: 0x000000a2: start vertex +0x123001e8: 0x00000001: instance count +0x123001ec: 0x00000000: start instance +0x123001f0: 0x00000000: index bias +0x123001f4: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123001f8: 0x00007aa0: VS state +0x123001fc: 0x000079e1: GS state +0x12300200: 0x00007a61: Clip state +0x12300204: 0x00007ac0: SF state +0x12300208: 0x00007b00: WM state +0x1230020c: 0x00007cc0: CC state +0x12300210: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300214: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300218: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x1230021c: 0x60020100: CONSTANT_BUFFER: valid +0x12300220: 0x00000142: offset: 0x00000140, length: 192 bytes +0x12300224: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300228: 0x00000050: vertex count +0x1230022c: 0x000000f4: start vertex +0x12300230: 0x00000001: instance count +0x12300234: 0x00000000: start instance +0x12300238: 0x00000000: index bias +0x1230023c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300240: 0x00007aa0: VS state +0x12300244: 0x000079c1: GS state +0x12300248: 0x00007a61: Clip state +0x1230024c: 0x00007ac0: SF state +0x12300250: 0x00007b00: WM state +0x12300254: 0x00007cc0: CC state +0x12300258: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x1230025c: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300260: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x12300264: 0x60020100: CONSTANT_BUFFER: valid +0x12300268: 0x00000142: offset: 0x00000140, length: 192 bytes +0x1230026c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300270: 0x000079a0: VS state +0x12300274: 0x000079c1: GS state +0x12300278: 0x00007a61: Clip state +0x1230027c: 0x00007ac0: SF state +0x12300280: 0x00007b00: WM state +0x12300284: 0x00007cc0: CC state +0x12300288: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x1230028c: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300290: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x12300294: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300298: 0x00000018: buffer 0: sequential, pitch 24b +0x1230029c: 0x00000f48: buffer address +0x123002a0: 0x00000000: max index +0x123002a4: 0x00000000: mbz +0x123002a8: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x123002ac: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123002b0: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123002b4: 0x0440000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x123002b8: 0x11130004: (X, Y, Z, 1.0), dst offset 0x10 bytes +0x123002bc: 0x60020100: CONSTANT_BUFFER: valid +0x123002c0: 0x00000202: offset: 0x00000200, length: 192 bytes +0x123002c4: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123002c8: 0x000000a2: vertex count +0x123002cc: 0x00000000: start vertex +0x123002d0: 0x00000001: instance count +0x123002d4: 0x00000000: start instance +0x123002d8: 0x00000000: index bias +0x123002dc: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123002e0: 0x000079a0: VS state +0x123002e4: 0x00000000: GS state +0x123002e8: 0x00007901: Clip state +0x123002ec: 0x00007940: SF state +0x123002f0: 0x00007960: WM state +0x123002f4: 0x00007cc0: CC state +0x123002f8: 0x00000000: MI_NOOP +0x123002fc: 0x00000000: MI_NOOP +0x12300300: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300304: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300308: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x1230030c: 0x60020100: CONSTANT_BUFFER: valid +0x12300310: 0x00000202: offset: 0x00000200, length: 192 bytes +0x12300314: 0x7b001404: 3DPRIMITIVE: tri strip sequential +0x12300318: 0x0000002a: vertex count +0x1230031c: 0x000000a2: start vertex +0x12300320: 0x00000001: instance count +0x12300324: 0x00000000: start instance +0x12300328: 0x00000000: index bias +0x1230032c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300330: 0x00007860: VS state +0x12300334: 0x00007801: GS state +0x12300338: 0x00007821: Clip state +0x1230033c: 0x00007880: SF state +0x12300340: 0x000078a0: WM state +0x12300344: 0x00007cc0: CC state +0x12300348: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x1230034c: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300350: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x12300354: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300358: 0x0000000c: buffer 0: sequential, pitch 12b +0x1230035c: 0x00002268: buffer address +0x12300360: 0x00000000: max index +0x12300364: 0x00000000: mbz +0x12300368: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x1230036c: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x12300370: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300374: 0x60020100: CONSTANT_BUFFER: valid +0x12300378: 0x000002c2: offset: 0x000002c0, length: 192 bytes +0x1230037c: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300380: 0x0000002a: vertex count +0x12300384: 0x00000000: start vertex +0x12300388: 0x00000001: instance count +0x1230038c: 0x00000000: start instance +0x12300390: 0x00000000: index bias +0x12300394: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300398: 0x00007860: VS state +0x1230039c: 0x000077e1: GS state +0x123003a0: 0x00007821: Clip state +0x123003a4: 0x00007880: SF state +0x123003a8: 0x000078a0: WM state +0x123003ac: 0x00007cc0: CC state +0x123003b0: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123003b4: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x123003b8: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x123003bc: 0x60020100: CONSTANT_BUFFER: valid +0x123003c0: 0x000002c2: offset: 0x000002c0, length: 192 bytes +0x123003c4: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x123003c8: 0x00000028: vertex count +0x123003cc: 0x0000002a: start vertex +0x123003d0: 0x00000001: instance count +0x123003d4: 0x00000000: start instance +0x123003d8: 0x00000000: index bias +0x123003dc: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123003e0: 0x00007860: VS state +0x123003e4: 0x000077c1: GS state +0x123003e8: 0x00007821: Clip state +0x123003ec: 0x00007880: SF state +0x123003f0: 0x000078a0: WM state +0x123003f4: 0x00007cc0: CC state +0x123003f8: 0x00000000: MI_NOOP +0x123003fc: 0x00000000: MI_NOOP +0x12300400: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300404: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300408: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x1230040c: 0x60020100: CONSTANT_BUFFER: valid +0x12300410: 0x00000382: offset: 0x00000380, length: 192 bytes +0x12300414: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300418: 0x0000002a: vertex count +0x1230041c: 0x00000052: start vertex +0x12300420: 0x00000001: instance count +0x12300424: 0x00000000: start instance +0x12300428: 0x00000000: index bias +0x1230042c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300430: 0x00007860: VS state +0x12300434: 0x000077a1: GS state +0x12300438: 0x00007821: Clip state +0x1230043c: 0x00007880: SF state +0x12300440: 0x000078a0: WM state +0x12300444: 0x00007cc0: CC state +0x12300448: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x1230044c: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300450: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x12300454: 0x60020100: CONSTANT_BUFFER: valid +0x12300458: 0x00000382: offset: 0x00000380, length: 192 bytes +0x1230045c: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300460: 0x00000028: vertex count +0x12300464: 0x0000007c: start vertex +0x12300468: 0x00000001: instance count +0x1230046c: 0x00000000: start instance +0x12300470: 0x00000000: index bias +0x12300474: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300478: 0x00007860: VS state +0x1230047c: 0x00007781: GS state +0x12300480: 0x00007821: Clip state +0x12300484: 0x00007880: SF state +0x12300488: 0x000078a0: WM state +0x1230048c: 0x00007cc0: CC state +0x12300490: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300494: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300498: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x1230049c: 0x60020100: CONSTANT_BUFFER: valid +0x123004a0: 0x00000382: offset: 0x00000380, length: 192 bytes +0x123004a4: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123004a8: 0x00007760: VS state +0x123004ac: 0x00007781: GS state +0x123004b0: 0x00007821: Clip state +0x123004b4: 0x00007880: SF state +0x123004b8: 0x000078a0: WM state +0x123004bc: 0x00007cc0: CC state +0x123004c0: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123004c4: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x123004c8: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x123004cc: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x123004d0: 0x00000018: buffer 0: sequential, pitch 24b +0x123004d4: 0x00002a30: buffer address +0x123004d8: 0x00000000: max index +0x123004dc: 0x00000000: mbz +0x123004e0: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x123004e4: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123004e8: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123004ec: 0x0440000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x123004f0: 0x11130004: (X, Y, Z, 1.0), dst offset 0x10 bytes +0x123004f4: 0x60020100: CONSTANT_BUFFER: valid +0x123004f8: 0x00000442: offset: 0x00000440, length: 192 bytes +0x123004fc: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300500: 0x00000052: vertex count +0x12300504: 0x00000000: start vertex +0x12300508: 0x00000001: instance count +0x1230050c: 0x00000000: start instance +0x12300510: 0x00000000: index bias +0x12300514: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300518: 0x00007760: VS state +0x1230051c: 0x00000000: GS state +0x12300520: 0x000076c1: Clip state +0x12300524: 0x00007700: SF state +0x12300528: 0x00007720: WM state +0x1230052c: 0x00007cc0: CC state +0x12300530: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300534: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300538: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x1230053c: 0x60020100: CONSTANT_BUFFER: valid +0x12300540: 0x00000442: offset: 0x00000440, length: 192 bytes +0x12300544: 0x7b001404: 3DPRIMITIVE: tri strip sequential +0x12300548: 0x00000016: vertex count +0x1230054c: 0x00000052: start vertex +0x12300550: 0x00000001: instance count +0x12300554: 0x00000000: start instance +0x12300558: 0x00000000: index bias +0x1230055c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300560: 0x00007620: VS state +0x12300564: 0x000075c1: GS state +0x12300568: 0x000075e1: Clip state +0x1230056c: 0x00007640: SF state +0x12300570: 0x00007660: WM state +0x12300574: 0x00007cc0: CC state +0x12300578: 0x00000000: MI_NOOP +0x1230057c: 0x00000000: MI_NOOP +0x12300580: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300584: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300588: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x1230058c: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300590: 0x0000000c: buffer 0: sequential, pitch 12b +0x12300594: 0x000033f0: buffer address +0x12300598: 0x00000000: max index +0x1230059c: 0x00000000: mbz +0x123005a0: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x123005a4: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123005a8: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123005ac: 0x60020100: CONSTANT_BUFFER: valid +0x123005b0: 0x00000502: offset: 0x00000500, length: 192 bytes +0x123005b4: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123005b8: 0x0000002a: vertex count +0x123005bc: 0x00000000: start vertex +0x123005c0: 0x00000001: instance count +0x123005c4: 0x00000000: start instance +0x123005c8: 0x00000000: index bias +0x123005cc: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123005d0: 0x00007620: VS state +0x123005d4: 0x000075a1: GS state +0x123005d8: 0x000075e1: Clip state +0x123005dc: 0x00007640: SF state +0x123005e0: 0x00007660: WM state +0x123005e4: 0x00007cc0: CC state +0x123005e8: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123005ec: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x123005f0: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x123005f4: 0x60020100: CONSTANT_BUFFER: valid +0x123005f8: 0x00000502: offset: 0x00000500, length: 192 bytes +0x123005fc: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300600: 0x00000028: vertex count +0x12300604: 0x0000002a: start vertex +0x12300608: 0x00000001: instance count +0x1230060c: 0x00000000: start instance +0x12300610: 0x00000000: index bias +0x12300614: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300618: 0x00007620: VS state +0x1230061c: 0x00007581: GS state +0x12300620: 0x000075e1: Clip state +0x12300624: 0x00007640: SF state +0x12300628: 0x00007660: WM state +0x1230062c: 0x00007cc0: CC state +0x12300630: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300634: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300638: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x1230063c: 0x60020100: CONSTANT_BUFFER: valid +0x12300640: 0x000005c2: offset: 0x000005c0, length: 192 bytes +0x12300644: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300648: 0x0000002a: vertex count +0x1230064c: 0x00000052: start vertex +0x12300650: 0x00000001: instance count +0x12300654: 0x00000000: start instance +0x12300658: 0x00000000: index bias +0x1230065c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300660: 0x00007620: VS state +0x12300664: 0x00007561: GS state +0x12300668: 0x000075e1: Clip state +0x1230066c: 0x00007640: SF state +0x12300670: 0x00007660: WM state +0x12300674: 0x00007cc0: CC state +0x12300678: 0x00000000: MI_NOOP +0x1230067c: 0x00000000: MI_NOOP +0x12300680: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300684: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300688: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x1230068c: 0x60020100: CONSTANT_BUFFER: valid +0x12300690: 0x000005c2: offset: 0x000005c0, length: 192 bytes +0x12300694: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300698: 0x00000028: vertex count +0x1230069c: 0x0000007c: start vertex +0x123006a0: 0x00000001: instance count +0x123006a4: 0x00000000: start instance +0x123006a8: 0x00000000: index bias +0x123006ac: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123006b0: 0x00007620: VS state +0x123006b4: 0x00007541: GS state +0x123006b8: 0x000075e1: Clip state +0x123006bc: 0x00007640: SF state +0x123006c0: 0x00007660: WM state +0x123006c4: 0x00007cc0: CC state +0x123006c8: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123006cc: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x123006d0: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x123006d4: 0x60020100: CONSTANT_BUFFER: valid +0x123006d8: 0x000005c2: offset: 0x000005c0, length: 192 bytes +0x123006dc: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123006e0: 0x00007520: VS state +0x123006e4: 0x00007541: GS state +0x123006e8: 0x000075e1: Clip state +0x123006ec: 0x00007640: SF state +0x123006f0: 0x00007660: WM state +0x123006f4: 0x00007cc0: CC state +0x123006f8: 0x00000000: MI_NOOP +0x123006fc: 0x00000000: MI_NOOP +0x12300700: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300704: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300708: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x1230070c: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300710: 0x00000018: buffer 0: sequential, pitch 24b +0x12300714: 0x00003bb8: buffer address +0x12300718: 0x00000000: max index +0x1230071c: 0x00000000: mbz +0x12300720: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x12300724: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x12300728: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x1230072c: 0x0440000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x12300730: 0x11130004: (X, Y, Z, 1.0), dst offset 0x10 bytes +0x12300734: 0x60020100: CONSTANT_BUFFER: valid +0x12300738: 0x00000682: offset: 0x00000680, length: 192 bytes +0x1230073c: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300740: 0x00000052: vertex count +0x12300744: 0x00000000: start vertex +0x12300748: 0x00000001: instance count +0x1230074c: 0x00000000: start instance +0x12300750: 0x00000000: index bias +0x12300754: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300758: 0x00007520: VS state +0x1230075c: 0x00000000: GS state +0x12300760: 0x00007481: Clip state +0x12300764: 0x000074c0: SF state +0x12300768: 0x000074e0: WM state +0x1230076c: 0x00007cc0: CC state +0x12300770: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300774: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300778: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x1230077c: 0x60020100: CONSTANT_BUFFER: valid +0x12300780: 0x00000682: offset: 0x00000680, length: 192 bytes +0x12300784: 0x7b001404: 3DPRIMITIVE: tri strip sequential +0x12300788: 0x00000016: vertex count +0x1230078c: 0x00000052: start vertex +0x12300790: 0x00000001: instance count +0x12300794: 0x00000000: start instance +0x12300798: 0x00000000: index bias +0x1230079c: 0x05000000: MI_BATCH_BUFFER_END diff --git a/intel/tests/gen4-3d.batch.sh b/intel/tests/gen4-3d.batch.sh new file mode 120000 index 0000000..796ca5f --- /dev/null +++ b/intel/tests/gen4-3d.batch.sh @@ -0,0 +1 @@ +test-batch.sh \ No newline at end of file diff --git a/intel/tests/gen5-3d.batch b/intel/tests/gen5-3d.batch new file mode 100644 index 0000000..cf9d8d8 Binary files /dev/null and b/intel/tests/gen5-3d.batch differ diff --git a/intel/tests/gen5-3d.batch-ref.txt b/intel/tests/gen5-3d.batch-ref.txt new file mode 100644 index 0000000..51dd85f --- /dev/null +++ b/intel/tests/gen5-3d.batch-ref.txt @@ -0,0 +1,512 @@ +0x12300000: 0x69040000: 3DSTATE_PIPELINE_SELECT +0x12300004: 0x79090000: 3DSTATE_GLOBAL_DEPTH_OFFSET_CLAMP +0x12300008: 0x00000000: dword 1 +0x1230000c: 0x61020000: STATE_SIP +0x12300010: 0x00000000: dword 1 +0x12300014: 0x680b0000: 3DSTATE_VF_STATISTICS +0x12300018: 0x61010006: STATE_BASE_ADDRESS +0x1230001c: 0x00000001: general state base address 0x00000000 +0x12300020: 0x00000001: surface state base address 0x00000000 +0x12300024: 0x00000001: indirect state base address 0x00000000 +0x12300028: 0x00000001: instruction state base address 0x00000000 +0x1230002c: 0x00000001: general state upper bound disabled +0x12300030: 0x00000001: indirect state upper bound disabled +0x12300034: 0x00000001: instruction state upper bound disabled +0x12300038: 0x78010004: 3DSTATE_BINDING_TABLE_POINTERS +0x1230003c: 0x00007e20: VS binding table +0x12300040: 0x00000000: GS binding table +0x12300044: 0x00000000: Clip binding table +0x12300048: 0x00000000: SF binding table +0x1230004c: 0x00007e20: WM binding table +0x12300050: 0x79010003: 3DSTATE_CONSTANT_COLOR +0x12300054: 0x00000000: dword 1 +0x12300058: 0x00000000: dword 2 +0x1230005c: 0x00000000: dword 3 +0x12300060: 0x00000000: dword 4 +0x12300064: 0x79050004: 3DSTATE_DEPTH_BUFFER +0x12300068: 0x2c0805ff: 2D, z24s8, pitch = 1536 bytes, tiled, HiZ 0, Separate Stencil 0 +0x1230006c: 0x00000000: depth offset +0x12300070: 0x09584ac0: 300x300 +0x12300074: 0x00000000: volume depth +0x12300078: 0x00000000: +0x1230007c: 0x02000000: MI_FLUSH +0x12300080: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300084: 0x00007d60: VS state +0x12300088: 0x00000000: GS state +0x1230008c: 0x00007d21: Clip state +0x12300090: 0x00007d80: SF state +0x12300094: 0x00007de0: WM state +0x12300098: 0x00007fc0: CC state +0x1230009c: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123000a0: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x123000a4: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x123000a8: 0x60010000: CS_URB_STATE +0x123000ac: 0x00000024: entry_size: 2 [192 bytes], n_entries: 4 +0x123000b0: 0x79000002: 3DSTATE_DRAWING_RECTANGLE +0x123000b4: 0x00000000: top left: 0,0 +0x123000b8: 0x012b012b: bottom right: 299,299 +0x123000bc: 0x00000000: origin: 0,0 +0x123000c0: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x123000c4: 0x0000000c: buffer 0: sequential, pitch 12b +0x123000c8: 0x00000000: buffer address +0x123000cc: 0x0000ffff: max index +0x123000d0: 0x00000000: mbz +0x123000d4: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x123000d8: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123000dc: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123000e0: 0x60020100: CONSTANT_BUFFER: valid +0x123000e4: 0x00000001: offset: 0x00000000, length: 128 bytes +0x123000e8: 0x7b001804: 3DPRIMITIVE: tri fan sequential +0x123000ec: 0x00000004: vertex count +0x123000f0: 0x00000000: start vertex +0x123000f4: 0x00000001: instance count +0x123000f8: 0x00000000: start instance +0x123000fc: 0x00000000: index bias +0x12300100: 0x78010004: 3DSTATE_BINDING_TABLE_POINTERS +0x12300104: 0x00007b40: VS binding table +0x12300108: 0x00000000: GS binding table +0x1230010c: 0x00000000: Clip binding table +0x12300110: 0x00000000: SF binding table +0x12300114: 0x00007b40: WM binding table +0x12300118: 0x02000000: MI_FLUSH +0x1230011c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300120: 0x00007aa0: VS state +0x12300124: 0x00007a41: GS state +0x12300128: 0x00007a61: Clip state +0x1230012c: 0x00007ac0: SF state +0x12300130: 0x00007b00: WM state +0x12300134: 0x00007cc0: CC state +0x12300138: 0x00000000: MI_NOOP +0x1230013c: 0x00000000: MI_NOOP +0x12300140: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300144: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300148: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x1230014c: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300150: 0x0000000c: buffer 0: sequential, pitch 12b +0x12300154: 0x00000000: buffer address +0x12300158: 0x00007fff: max index +0x1230015c: 0x00000000: mbz +0x12300160: 0x60020100: CONSTANT_BUFFER: valid +0x12300164: 0x00000082: offset: 0x00000080, length: 192 bytes +0x12300168: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x1230016c: 0x00000052: vertex count +0x12300170: 0x00000000: start vertex +0x12300174: 0x00000001: instance count +0x12300178: 0x00000000: start instance +0x1230017c: 0x00000000: index bias +0x12300180: 0x02000000: MI_FLUSH +0x12300184: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300188: 0x00007aa0: VS state +0x1230018c: 0x00007a21: GS state +0x12300190: 0x00007a61: Clip state +0x12300194: 0x00007ac0: SF state +0x12300198: 0x00007b00: WM state +0x1230019c: 0x00007cc0: CC state +0x123001a0: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123001a4: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x123001a8: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x123001ac: 0x60020100: CONSTANT_BUFFER: valid +0x123001b0: 0x00000082: offset: 0x00000080, length: 192 bytes +0x123001b4: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x123001b8: 0x00000050: vertex count +0x123001bc: 0x00000052: start vertex +0x123001c0: 0x00000001: instance count +0x123001c4: 0x00000000: start instance +0x123001c8: 0x00000000: index bias +0x123001cc: 0x02000000: MI_FLUSH +0x123001d0: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123001d4: 0x00007aa0: VS state +0x123001d8: 0x00007a01: GS state +0x123001dc: 0x00007a61: Clip state +0x123001e0: 0x00007ac0: SF state +0x123001e4: 0x00007b00: WM state +0x123001e8: 0x00007cc0: CC state +0x123001ec: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123001f0: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x123001f4: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x123001f8: 0x60020100: CONSTANT_BUFFER: valid +0x123001fc: 0x00000142: offset: 0x00000140, length: 192 bytes +0x12300200: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300204: 0x00000052: vertex count +0x12300208: 0x000000a2: start vertex +0x1230020c: 0x00000001: instance count +0x12300210: 0x00000000: start instance +0x12300214: 0x00000000: index bias +0x12300218: 0x02000000: MI_FLUSH +0x1230021c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300220: 0x00007aa0: VS state +0x12300224: 0x000079e1: GS state +0x12300228: 0x00007a61: Clip state +0x1230022c: 0x00007ac0: SF state +0x12300230: 0x00007b00: WM state +0x12300234: 0x00007cc0: CC state +0x12300238: 0x00000000: MI_NOOP +0x1230023c: 0x00000000: MI_NOOP +0x12300240: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300244: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300248: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x1230024c: 0x60020100: CONSTANT_BUFFER: valid +0x12300250: 0x00000142: offset: 0x00000140, length: 192 bytes +0x12300254: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300258: 0x00000050: vertex count +0x1230025c: 0x000000f4: start vertex +0x12300260: 0x00000001: instance count +0x12300264: 0x00000000: start instance +0x12300268: 0x00000000: index bias +0x1230026c: 0x02000000: MI_FLUSH +0x12300270: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300274: 0x00007aa0: VS state +0x12300278: 0x000079c1: GS state +0x1230027c: 0x00007a61: Clip state +0x12300280: 0x00007ac0: SF state +0x12300284: 0x00007b00: WM state +0x12300288: 0x00007cc0: CC state +0x1230028c: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300290: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300294: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x12300298: 0x60020100: CONSTANT_BUFFER: valid +0x1230029c: 0x00000142: offset: 0x00000140, length: 192 bytes +0x123002a0: 0x02000000: MI_FLUSH +0x123002a4: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123002a8: 0x000079a0: VS state +0x123002ac: 0x000079c1: GS state +0x123002b0: 0x00007a61: Clip state +0x123002b4: 0x00007ac0: SF state +0x123002b8: 0x00007b00: WM state +0x123002bc: 0x00007cc0: CC state +0x123002c0: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123002c4: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x123002c8: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x123002cc: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x123002d0: 0x00000018: buffer 0: sequential, pitch 24b +0x123002d4: 0x00000f48: buffer address +0x123002d8: 0x00007fff: max index +0x123002dc: 0x00000000: mbz +0x123002e0: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x123002e4: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123002e8: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123002ec: 0x0440000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x123002f0: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123002f4: 0x60020100: CONSTANT_BUFFER: valid +0x123002f8: 0x00000202: offset: 0x00000200, length: 192 bytes +0x123002fc: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300300: 0x000000a2: vertex count +0x12300304: 0x00000000: start vertex +0x12300308: 0x00000001: instance count +0x1230030c: 0x00000000: start instance +0x12300310: 0x00000000: index bias +0x12300314: 0x02000000: MI_FLUSH +0x12300318: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x1230031c: 0x000079a0: VS state +0x12300320: 0x00000000: GS state +0x12300324: 0x00007901: Clip state +0x12300328: 0x00007940: SF state +0x1230032c: 0x00007960: WM state +0x12300330: 0x00007cc0: CC state +0x12300334: 0x00000000: MI_NOOP +0x12300338: 0x00000000: MI_NOOP +0x1230033c: 0x00000000: MI_NOOP +0x12300340: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300344: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300348: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x1230034c: 0x60020100: CONSTANT_BUFFER: valid +0x12300350: 0x00000202: offset: 0x00000200, length: 192 bytes +0x12300354: 0x7b001404: 3DPRIMITIVE: tri strip sequential +0x12300358: 0x0000002a: vertex count +0x1230035c: 0x000000a2: start vertex +0x12300360: 0x00000001: instance count +0x12300364: 0x00000000: start instance +0x12300368: 0x00000000: index bias +0x1230036c: 0x02000000: MI_FLUSH +0x12300370: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300374: 0x00007860: VS state +0x12300378: 0x00007801: GS state +0x1230037c: 0x00007821: Clip state +0x12300380: 0x00007880: SF state +0x12300384: 0x000078a0: WM state +0x12300388: 0x00007cc0: CC state +0x1230038c: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300390: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300394: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x12300398: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x1230039c: 0x0000000c: buffer 0: sequential, pitch 12b +0x123003a0: 0x00002268: buffer address +0x123003a4: 0x00007fff: max index +0x123003a8: 0x00000000: mbz +0x123003ac: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x123003b0: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123003b4: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123003b8: 0x60020100: CONSTANT_BUFFER: valid +0x123003bc: 0x000002c2: offset: 0x000002c0, length: 192 bytes +0x123003c0: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123003c4: 0x0000002a: vertex count +0x123003c8: 0x00000000: start vertex +0x123003cc: 0x00000001: instance count +0x123003d0: 0x00000000: start instance +0x123003d4: 0x00000000: index bias +0x123003d8: 0x02000000: MI_FLUSH +0x123003dc: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123003e0: 0x00007860: VS state +0x123003e4: 0x000077e1: GS state +0x123003e8: 0x00007821: Clip state +0x123003ec: 0x00007880: SF state +0x123003f0: 0x000078a0: WM state +0x123003f4: 0x00007cc0: CC state +0x123003f8: 0x00000000: MI_NOOP +0x123003fc: 0x00000000: MI_NOOP +0x12300400: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300404: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300408: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x1230040c: 0x60020100: CONSTANT_BUFFER: valid +0x12300410: 0x000002c2: offset: 0x000002c0, length: 192 bytes +0x12300414: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300418: 0x00000028: vertex count +0x1230041c: 0x0000002a: start vertex +0x12300420: 0x00000001: instance count +0x12300424: 0x00000000: start instance +0x12300428: 0x00000000: index bias +0x1230042c: 0x02000000: MI_FLUSH +0x12300430: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300434: 0x00007860: VS state +0x12300438: 0x000077c1: GS state +0x1230043c: 0x00007821: Clip state +0x12300440: 0x00007880: SF state +0x12300444: 0x000078a0: WM state +0x12300448: 0x00007cc0: CC state +0x1230044c: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300450: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300454: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x12300458: 0x60020100: CONSTANT_BUFFER: valid +0x1230045c: 0x00000382: offset: 0x00000380, length: 192 bytes +0x12300460: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300464: 0x0000002a: vertex count +0x12300468: 0x00000052: start vertex +0x1230046c: 0x00000001: instance count +0x12300470: 0x00000000: start instance +0x12300474: 0x00000000: index bias +0x12300478: 0x02000000: MI_FLUSH +0x1230047c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300480: 0x00007860: VS state +0x12300484: 0x000077a1: GS state +0x12300488: 0x00007821: Clip state +0x1230048c: 0x00007880: SF state +0x12300490: 0x000078a0: WM state +0x12300494: 0x00007cc0: CC state +0x12300498: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x1230049c: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x123004a0: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x123004a4: 0x60020100: CONSTANT_BUFFER: valid +0x123004a8: 0x00000382: offset: 0x00000380, length: 192 bytes +0x123004ac: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x123004b0: 0x00000028: vertex count +0x123004b4: 0x0000007c: start vertex +0x123004b8: 0x00000001: instance count +0x123004bc: 0x00000000: start instance +0x123004c0: 0x00000000: index bias +0x123004c4: 0x02000000: MI_FLUSH +0x123004c8: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123004cc: 0x00007860: VS state +0x123004d0: 0x00007781: GS state +0x123004d4: 0x00007821: Clip state +0x123004d8: 0x00007880: SF state +0x123004dc: 0x000078a0: WM state +0x123004e0: 0x00007cc0: CC state +0x123004e4: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123004e8: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x123004ec: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x123004f0: 0x60020100: CONSTANT_BUFFER: valid +0x123004f4: 0x00000382: offset: 0x00000380, length: 192 bytes +0x123004f8: 0x02000000: MI_FLUSH +0x123004fc: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300500: 0x00007760: VS state +0x12300504: 0x00007781: GS state +0x12300508: 0x00007821: Clip state +0x1230050c: 0x00007880: SF state +0x12300510: 0x000078a0: WM state +0x12300514: 0x00007cc0: CC state +0x12300518: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x1230051c: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300520: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x12300524: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300528: 0x00000018: buffer 0: sequential, pitch 24b +0x1230052c: 0x00002a30: buffer address +0x12300530: 0x00007fff: max index +0x12300534: 0x00000000: mbz +0x12300538: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x1230053c: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x12300540: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300544: 0x0440000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x12300548: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x1230054c: 0x60020100: CONSTANT_BUFFER: valid +0x12300550: 0x00000442: offset: 0x00000440, length: 192 bytes +0x12300554: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300558: 0x00000052: vertex count +0x1230055c: 0x00000000: start vertex +0x12300560: 0x00000001: instance count +0x12300564: 0x00000000: start instance +0x12300568: 0x00000000: index bias +0x1230056c: 0x02000000: MI_FLUSH +0x12300570: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300574: 0x00007760: VS state +0x12300578: 0x00000000: GS state +0x1230057c: 0x000076c1: Clip state +0x12300580: 0x00007700: SF state +0x12300584: 0x00007720: WM state +0x12300588: 0x00007cc0: CC state +0x1230058c: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300590: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300594: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x12300598: 0x60020100: CONSTANT_BUFFER: valid +0x1230059c: 0x00000442: offset: 0x00000440, length: 192 bytes +0x123005a0: 0x7b001404: 3DPRIMITIVE: tri strip sequential +0x123005a4: 0x00000016: vertex count +0x123005a8: 0x00000052: start vertex +0x123005ac: 0x00000001: instance count +0x123005b0: 0x00000000: start instance +0x123005b4: 0x00000000: index bias +0x123005b8: 0x02000000: MI_FLUSH +0x123005bc: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123005c0: 0x00007620: VS state +0x123005c4: 0x000075c1: GS state +0x123005c8: 0x000075e1: Clip state +0x123005cc: 0x00007640: SF state +0x123005d0: 0x00007660: WM state +0x123005d4: 0x00007cc0: CC state +0x123005d8: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123005dc: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x123005e0: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x123005e4: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x123005e8: 0x0000000c: buffer 0: sequential, pitch 12b +0x123005ec: 0x000033f0: buffer address +0x123005f0: 0x00007fff: max index +0x123005f4: 0x00000000: mbz +0x123005f8: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x123005fc: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x12300600: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300604: 0x60020100: CONSTANT_BUFFER: valid +0x12300608: 0x00000502: offset: 0x00000500, length: 192 bytes +0x1230060c: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300610: 0x0000002a: vertex count +0x12300614: 0x00000000: start vertex +0x12300618: 0x00000001: instance count +0x1230061c: 0x00000000: start instance +0x12300620: 0x00000000: index bias +0x12300624: 0x02000000: MI_FLUSH +0x12300628: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x1230062c: 0x00007620: VS state +0x12300630: 0x000075a1: GS state +0x12300634: 0x000075e1: Clip state +0x12300638: 0x00007640: SF state +0x1230063c: 0x00007660: WM state +0x12300640: 0x00007cc0: CC state +0x12300644: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300648: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x1230064c: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x12300650: 0x60020100: CONSTANT_BUFFER: valid +0x12300654: 0x00000502: offset: 0x00000500, length: 192 bytes +0x12300658: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x1230065c: 0x00000028: vertex count +0x12300660: 0x0000002a: start vertex +0x12300664: 0x00000001: instance count +0x12300668: 0x00000000: start instance +0x1230066c: 0x00000000: index bias +0x12300670: 0x02000000: MI_FLUSH +0x12300674: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300678: 0x00007620: VS state +0x1230067c: 0x00007581: GS state +0x12300680: 0x000075e1: Clip state +0x12300684: 0x00007640: SF state +0x12300688: 0x00007660: WM state +0x1230068c: 0x00007cc0: CC state +0x12300690: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300694: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300698: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x1230069c: 0x60020100: CONSTANT_BUFFER: valid +0x123006a0: 0x000005c2: offset: 0x000005c0, length: 192 bytes +0x123006a4: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123006a8: 0x0000002a: vertex count +0x123006ac: 0x00000052: start vertex +0x123006b0: 0x00000001: instance count +0x123006b4: 0x00000000: start instance +0x123006b8: 0x00000000: index bias +0x123006bc: 0x02000000: MI_FLUSH +0x123006c0: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123006c4: 0x00007620: VS state +0x123006c8: 0x00007561: GS state +0x123006cc: 0x000075e1: Clip state +0x123006d0: 0x00007640: SF state +0x123006d4: 0x00007660: WM state +0x123006d8: 0x00007cc0: CC state +0x123006dc: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123006e0: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x123006e4: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x123006e8: 0x60020100: CONSTANT_BUFFER: valid +0x123006ec: 0x000005c2: offset: 0x000005c0, length: 192 bytes +0x123006f0: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x123006f4: 0x00000028: vertex count +0x123006f8: 0x0000007c: start vertex +0x123006fc: 0x00000001: instance count +0x12300700: 0x00000000: start instance +0x12300704: 0x00000000: index bias +0x12300708: 0x02000000: MI_FLUSH +0x1230070c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300710: 0x00007620: VS state +0x12300714: 0x00007541: GS state +0x12300718: 0x000075e1: Clip state +0x1230071c: 0x00007640: SF state +0x12300720: 0x00007660: WM state +0x12300724: 0x00007cc0: CC state +0x12300728: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x1230072c: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300730: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x12300734: 0x60020100: CONSTANT_BUFFER: valid +0x12300738: 0x000005c2: offset: 0x000005c0, length: 192 bytes +0x1230073c: 0x02000000: MI_FLUSH +0x12300740: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300744: 0x00007520: VS state +0x12300748: 0x00007541: GS state +0x1230074c: 0x000075e1: Clip state +0x12300750: 0x00007640: SF state +0x12300754: 0x00007660: WM state +0x12300758: 0x00007cc0: CC state +0x1230075c: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300760: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300764: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x12300768: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x1230076c: 0x00000018: buffer 0: sequential, pitch 24b +0x12300770: 0x00003bb8: buffer address +0x12300774: 0x00007fff: max index +0x12300778: 0x00000000: mbz +0x1230077c: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x12300780: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x12300784: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300788: 0x0440000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x1230078c: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300790: 0x60020100: CONSTANT_BUFFER: valid +0x12300794: 0x00000682: offset: 0x00000680, length: 192 bytes +0x12300798: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x1230079c: 0x00000052: vertex count +0x123007a0: 0x00000000: start vertex +0x123007a4: 0x00000001: instance count +0x123007a8: 0x00000000: start instance +0x123007ac: 0x00000000: index bias +0x123007b0: 0x02000000: MI_FLUSH +0x123007b4: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123007b8: 0x00007520: VS state +0x123007bc: 0x00000000: GS state +0x123007c0: 0x00007481: Clip state +0x123007c4: 0x000074c0: SF state +0x123007c8: 0x000074e0: WM state +0x123007cc: 0x00007cc0: CC state +0x123007d0: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123007d4: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x123007d8: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x123007dc: 0x60020100: CONSTANT_BUFFER: valid +0x123007e0: 0x00000682: offset: 0x00000680, length: 192 bytes +0x123007e4: 0x7b001404: 3DPRIMITIVE: tri strip sequential +0x123007e8: 0x00000016: vertex count +0x123007ec: 0x00000052: start vertex +0x123007f0: 0x00000001: instance count +0x123007f4: 0x00000000: start instance +0x123007f8: 0x00000000: index bias +0x123007fc: 0x05000000: MI_BATCH_BUFFER_END diff --git a/intel/tests/gen5-3d.batch.sh b/intel/tests/gen5-3d.batch.sh new file mode 120000 index 0000000..796ca5f --- /dev/null +++ b/intel/tests/gen5-3d.batch.sh @@ -0,0 +1 @@ +test-batch.sh \ No newline at end of file diff --git a/intel/tests/gen6-3d.batch b/intel/tests/gen6-3d.batch new file mode 100644 index 0000000..d57147e Binary files /dev/null and b/intel/tests/gen6-3d.batch differ diff --git a/intel/tests/gen6-3d.batch-ref.txt b/intel/tests/gen6-3d.batch-ref.txt new file mode 100644 index 0000000..04cbddc --- /dev/null +++ b/intel/tests/gen6-3d.batch-ref.txt @@ -0,0 +1,990 @@ +0x12300000: 0x7a000002: PIPE_CONTROL +0x12300004: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300008: 0x00000000: +0x1230000c: 0x00000000: +0x12300010: 0x7a000002: PIPE_CONTROL +0x12300014: 0x00004000: qword write, +0x12300018: 0x00000000: +0x1230001c: 0x00000000: +0x12300020: 0x69040000: 3DSTATE_PIPELINE_SELECT +0x12300024: 0x790d0001: 3DSTATE_MULTISAMPLE +0x12300028: 0x00000000: dword 1 +0x1230002c: 0x00000000: dword 2 +0x12300030: 0x78180000: 3DSTATE_SAMPLE_MASK +0x12300034: 0x00000001: dword 1 +0x12300038: 0x790b0002: 3DSTATE_GS_SVB_INDEX +0x1230003c: 0x00000000: dword 1 +0x12300040: 0x00000000: dword 2 +0x12300044: 0xffffffff: dword 3 +0x12300048: 0x790b0002: 3DSTATE_GS_SVB_INDEX +0x1230004c: 0x20000000: dword 1 +0x12300050: 0x00000000: dword 2 +0x12300054: 0xffffffff: dword 3 +0x12300058: 0x790b0002: 3DSTATE_GS_SVB_INDEX +0x1230005c: 0x40000000: dword 1 +0x12300060: 0x00000000: dword 2 +0x12300064: 0xffffffff: dword 3 +0x12300068: 0x790b0002: 3DSTATE_GS_SVB_INDEX +0x1230006c: 0x60000000: dword 1 +0x12300070: 0x00000000: dword 2 +0x12300074: 0xffffffff: dword 3 +0x12300078: 0x61020000: STATE_SIP +0x1230007c: 0x00000000: dword 1 +0x12300080: 0x680b0000: 3DSTATE_VF_STATISTICS +0x12300084: 0x61010008: STATE_BASE_ADDRESS +0x12300088: 0x00000001: general state base address 0x00000000 +0x1230008c: 0x00000001: surface state base address 0x00000000 +0x12300090: 0x00000001: dynamic state base address 0x00000000 +0x12300094: 0x00000001: indirect state base address 0x00000000 +0x12300098: 0x00000001: instruction state base address 0x00000000 +0x1230009c: 0x00000001: general state upper bound disabled +0x123000a0: 0x00000001: dynamic state upper bound disabled +0x123000a4: 0x00000001: indirect state upper bound disabled +0x123000a8: 0x00000001: instruction state upper bound disabled +0x123000ac: 0x780d1c02: 3DSTATE_VIEWPORT_STATE_POINTERS +0x123000b0: 0x00007fe0: clip +0x123000b4: 0x00007fc0: sf +0x123000b8: 0x00007fa0: cc +0x123000bc: 0x78050001: 3DSTATE_URB +0x123000c0: 0x00000100: VS entries 256, alloc size 1 (1024bit row) +0x123000c4: 0x00000000: GS entries 0, alloc size 1 (1024bit row) +0x123000c8: 0x780e0002: 3DSTATE_CC_STATE_POINTERS +0x123000cc: 0x00007f81: blend change 1 +0x123000d0: 0x00007f01: depth stencil change 1 +0x123000d4: 0x00007f41: cc change 1 +0x123000d8: 0x78021302: 3DSTATE_SAMPLER_STATE_POINTERS: VS mod 1, GS mod 1, PS mod 1 +0x123000dc: 0x00000000: VS sampler state +0x123000e0: 0x00000000: GS sampler state +0x123000e4: 0x00000000: WM sampler state +0x123000e8: 0x78150003: 3DSTATE_CONSTANT_VS_STATE +0x123000ec: 0x00000000: dword 1 +0x123000f0: 0x00000000: dword 2 +0x123000f4: 0x00000000: dword 3 +0x123000f8: 0x00000000: dword 4 +0x123000fc: 0x78100004: 3DSTATE_VS +0x12300100: 0x00000000: kernel pointer +0x12300104: 0x00000000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300108: 0x00000000: scratch offset +0x1230010c: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x12300110: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300114: 0x7a000002: PIPE_CONTROL +0x12300118: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x1230011c: 0x00000000: +0x12300120: 0x00000000: +0x12300124: 0x78160003: 3DSTATE_CONSTANT_GS_STATE +0x12300128: 0x00000000: dword 1 +0x1230012c: 0x00000000: dword 2 +0x12300130: 0x00000000: dword 3 +0x12300134: 0x00000000: dword 4 +0x12300138: 0x78110005: 3DSTATE_GS +0x1230013c: 0x00000000: kernel pointer +0x12300140: 0x00000000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300144: 0x00000000: scratch offset +0x12300148: 0x00000001: Dispatch GRF start 1, VUE read length 0, VUE read offset 0 +0x1230014c: 0x00000500: Max Threads 1, Rendering enable +0x12300150: 0x00000000: Reorder disable, Discard Adjaceny disable, GS disable +0x12300154: 0x78120002: 3DSTATE_CLIP +0x12300158: 0x00000400: UserClip distance cull test mask 0x0 +0x1230015c: 0x98000026: Clip enable, API mode OGL, Viewport XY test enable, Viewport Z test enable, Guardband test disable, Clip mode 0, Perspective Divide enable, Non-Perspective Barycentric disable, Tri Provoking 2, Line Provoking 1, Trifan Provoking 2 +0x12300160: 0x0003ffe0: Min PointWidth 1, Max PointWidth 2047, Force Zero RTAIndex enable, Max VPIndex 0 +0x12300164: 0x78130012: 3DSTATE_SF +0x12300168: 0x00200810: Attrib Out 0, Attrib Swizzle enable, VUE read length 1, VUE read offset 1 +0x1230016c: 0x00000403: Legacy Global DepthBias disable, FrontFace fill 0, BF fill 0, VP transform enable, FrontWinding_CCW +0x12300170: 0x22000000: AA disable, CullMode 1, Scissor disable, Multisample m ode 0 +0x12300174: 0x4c000808: Last Pixel disable, SubPixel Precision 8, Use PixelWidth 1 +0x12300178: 0x00000000: Global Depth Offset Constant 0.000000 +0x1230017c: 0x00000000: Global Depth Offset Scale 0.000000 +0x12300180: 0x00000000: Global Depth Offset Clamp 0.000000 +0x12300184: 0x00000000: Attrib 1 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 0 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300188: 0x00000000: Attrib 3 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 2 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x1230018c: 0x00000000: Attrib 5 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 4 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300190: 0x00000000: Attrib 7 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 6 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300194: 0x00000000: Attrib 9 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 8 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300198: 0x00000000: Attrib 11 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 10 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x1230019c: 0x00000000: Attrib 13 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 12 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123001a0: 0x00000000: Attrib 15 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 14 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123001a4: 0x00000000: Point Sprite TexCoord Enable +0x123001a8: 0x00000000: Const Interp Enable +0x123001ac: 0x00000000: Attrib 7-0 WrapShortest Enable +0x123001b0: 0x00000000: Attrib 15-8 WrapShortest Enable +0x123001b4: 0x78171003: 3DSTATE_CONSTANT_PS_STATE +0x123001b8: 0x00007ee0: dword 1 +0x123001bc: 0x00000000: dword 2 +0x123001c0: 0x00000000: dword 3 +0x123001c4: 0x00000000: dword 4 +0x123001c8: 0x78140007: 3DSTATE_WM +0x123001cc: 0x000000c0: kernel start pointer 0 +0x123001d0: 0x00000000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x123001d4: 0x00000000: scratch offset +0x123001d8: 0x80020002: Depth Clear 0, Depth Resolve 0, HiZ Resolve 0, Dispatch GRF start[0] 2, start[1] 0, start[2] 2 +0x123001dc: 0x4e084003: MaxThreads 40, PS KillPixel 0, PS computed Z 0, PS use sourceZ 0, Thread Dispatch 1, PS use sourceW 0, Dispatch32 0, Dispatch16 1, Dispatch8 1 +0x123001e0: 0x00000000: Num SF output 0, Pos XY offset 0, ZW interp mode 0 , Barycentric interp mode 0x0, Point raster rule 0, Multisample mode 0, Multisample Dispatch mode 0 +0x123001e4: 0x00000000: kernel start pointer 1 +0x123001e8: 0x00000140: kernel start pointer 2 +0x123001ec: 0x780f0000: 3DSTATE_SCISSOR_POINTERS +0x123001f0: 0x00007d20: scissor rect offset +0x123001f4: 0x78011302: 3DSTATE_BINDING_TABLE_POINTERS: VS mod 1, GS mod 1, PS mod 1 +0x123001f8: 0x00007d40: VS binding table +0x123001fc: 0x00007d40: GS binding table +0x12300200: 0x00007d40: WM binding table +0x12300204: 0x7a000002: PIPE_CONTROL +0x12300208: 0x00002000: no write, depth stall, +0x1230020c: 0x00000000: +0x12300210: 0x00000000: +0x12300214: 0x7a000002: PIPE_CONTROL +0x12300218: 0x00000001: no write, depth cache flush, +0x1230021c: 0x00000000: +0x12300220: 0x00000000: +0x12300224: 0x7a000002: PIPE_CONTROL +0x12300228: 0x00002000: no write, depth stall, +0x1230022c: 0x00000000: +0x12300230: 0x00000000: +0x12300234: 0x79050005: 3DSTATE_DEPTH_BUFFER +0x12300238: 0x2c6c05ff: 2D, unknown, pitch = 1536 bytes, tiled, HiZ 1, Separate Stencil 1 +0x1230023c: 0x00000000: depth offset +0x12300240: 0x09584ac0: 300x300 +0x12300244: 0x00000000: volume depth +0x12300248: 0x00000000: +0x1230024c: 0x00000000: +0x12300250: 0x790f0001: 3DSTATE_HIER_DEPTH_BUFFER +0x12300254: 0x000005ff: dword 1 +0x12300258: 0x00000000: dword 2 +0x1230025c: 0x790e0001: 3D UNKNOWN: 3d_965 opcode = 0x790e +0x12300260: 0x0000027f: MI_NOOP +0x12300264: 0x00000000: MI_NOOP +0x12300268: 0x79100000: 3DSTATE_CLEAR_PARAMS +0x1230026c: 0x00000000: dword 1 +0x12300270: 0x79000002: 3DSTATE_DRAWING_RECTANGLE +0x12300274: 0x00000000: top left: 0,0 +0x12300278: 0x012b012b: bottom right: 299,299 +0x1230027c: 0x00000000: origin: 0,0 +0x12300280: 0x790b0002: 3DSTATE_GS_SVB_INDEX +0x12300284: 0x00000000: dword 1 +0x12300288: 0x00000000: dword 2 +0x1230028c: 0x00000000: dword 3 +0x12300290: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300294: 0x0000000c: buffer 0: sequential, pitch 12b +0x12300298: 0x00000000: buffer address +0x1230029c: 0x0000ffff: max index +0x123002a0: 0x00000000: mbz +0x123002a4: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x123002a8: 0x02400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123002ac: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123002b0: 0x7b001804: 3DPRIMITIVE: tri fan sequential +0x123002b4: 0x00000004: vertex count +0x123002b8: 0x00000000: start vertex +0x123002bc: 0x00000001: instance count +0x123002c0: 0x00000000: start instance +0x123002c4: 0x00000000: index bias +0x123002c8: 0x78050001: 3DSTATE_URB +0x123002cc: 0x00000100: VS entries 256, alloc size 1 (1024bit row) +0x123002d0: 0x00000000: GS entries 0, alloc size 1 (1024bit row) +0x123002d4: 0x780e0002: 3DSTATE_CC_STATE_POINTERS +0x123002d8: 0x00007f81: blend change 1 +0x123002dc: 0x00007cc1: depth stencil change 1 +0x123002e0: 0x00007d01: cc change 1 +0x123002e4: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x123002e8: 0x00007b85: dword 1 +0x123002ec: 0x00000000: dword 2 +0x123002f0: 0x00000000: dword 3 +0x123002f4: 0x00000000: dword 4 +0x123002f8: 0x78100004: 3DSTATE_VS +0x123002fc: 0x00000240: kernel pointer +0x12300300: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300304: 0x00000000: scratch offset +0x12300308: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x1230030c: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300310: 0x7a000002: PIPE_CONTROL +0x12300314: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300318: 0x00000000: +0x1230031c: 0x00000000: +0x12300320: 0x7a000002: PIPE_CONTROL +0x12300324: 0x00004000: qword write, +0x12300328: 0x00000000: +0x1230032c: 0x00000000: +0x12300330: 0x7a000002: PIPE_CONTROL +0x12300334: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x12300338: 0x00000000: +0x1230033c: 0x00000000: +0x12300340: 0x78120002: 3DSTATE_CLIP +0x12300344: 0x00000400: UserClip distance cull test mask 0x0 +0x12300348: 0x98000026: Clip enable, API mode OGL, Viewport XY test enable, Viewport Z test enable, Guardband test disable, Clip mode 0, Perspective Divide enable, Non-Perspective Barycentric disable, Tri Provoking 2, Line Provoking 1, Trifan Provoking 2 +0x1230034c: 0x0003ffe0: Min PointWidth 1, Max PointWidth 2047, Force Zero RTAIndex enable, Max VPIndex 0 +0x12300350: 0x78130012: 3DSTATE_SF +0x12300354: 0x00600810: Attrib Out 1, Attrib Swizzle enable, VUE read length 1, VUE read offset 1 +0x12300358: 0x00000403: Legacy Global DepthBias disable, FrontFace fill 0, BF fill 0, VP transform enable, FrontWinding_CCW +0x1230035c: 0x62000000: AA disable, CullMode 3, Scissor disable, Multisample m ode 0 +0x12300360: 0x4c000808: Last Pixel disable, SubPixel Precision 8, Use PixelWidth 1 +0x12300364: 0x00000000: Global Depth Offset Constant 0.000000 +0x12300368: 0x00000000: Global Depth Offset Scale 0.000000 +0x1230036c: 0x00000000: Global Depth Offset Clamp 0.000000 +0x12300370: 0x00000000: Attrib 1 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 0 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300374: 0x00000000: Attrib 3 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 2 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300378: 0x00000000: Attrib 5 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 4 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x1230037c: 0x00000000: Attrib 7 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 6 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300380: 0x00000000: Attrib 9 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 8 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300384: 0x00000000: Attrib 11 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 10 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300388: 0x00000000: Attrib 13 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 12 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x1230038c: 0x00000000: Attrib 15 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 14 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300390: 0x00000000: Point Sprite TexCoord Enable +0x12300394: 0x00000001: Const Interp Enable +0x12300398: 0x00000000: Attrib 7-0 WrapShortest Enable +0x1230039c: 0x00000000: Attrib 15-8 WrapShortest Enable +0x123003a0: 0x78170003: 3DSTATE_CONSTANT_PS_STATE +0x123003a4: 0x00000000: dword 1 +0x123003a8: 0x00000000: dword 2 +0x123003ac: 0x00000000: dword 3 +0x123003b0: 0x00000000: dword 4 +0x123003b4: 0x78140007: 3DSTATE_WM +0x123003b8: 0x00000500: kernel start pointer 0 +0x123003bc: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x123003c0: 0x00000000: scratch offset +0x123003c4: 0x80020000: Depth Clear 0, Depth Resolve 0, HiZ Resolve 0, Dispatch GRF start[0] 2, start[1] 0, start[2] 0 +0x123003c8: 0x4e084002: MaxThreads 40, PS KillPixel 0, PS computed Z 0, PS use sourceZ 0, Thread Dispatch 1, PS use sourceW 0, Dispatch32 0, Dispatch16 1, Dispatch8 0 +0x123003cc: 0x00100000: Num SF output 1, Pos XY offset 0, ZW interp mode 0 , Barycentric interp mode 0x0, Point raster rule 0, Multisample mode 0, Multisample Dispatch mode 0 +0x123003d0: 0x00000000: kernel start pointer 1 +0x123003d4: 0x00000500: kernel start pointer 2 +0x123003d8: 0x78011302: 3DSTATE_BINDING_TABLE_POINTERS: VS mod 1, GS mod 1, PS mod 1 +0x123003dc: 0x00007a00: VS binding table +0x123003e0: 0x00007a00: GS binding table +0x123003e4: 0x00007a00: WM binding table +0x123003e8: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x123003ec: 0x0000000c: buffer 0: sequential, pitch 12b +0x123003f0: 0x00000000: buffer address +0x123003f4: 0x00007fff: max index +0x123003f8: 0x00000000: mbz +0x123003fc: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300400: 0x00000052: vertex count +0x12300404: 0x00000000: start vertex +0x12300408: 0x00000001: instance count +0x1230040c: 0x00000000: start instance +0x12300410: 0x00000000: index bias +0x12300414: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300418: 0x00000050: vertex count +0x1230041c: 0x00000052: start vertex +0x12300420: 0x00000001: instance count +0x12300424: 0x00000000: start instance +0x12300428: 0x00000000: index bias +0x1230042c: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x12300430: 0x000078c5: dword 1 +0x12300434: 0x00000000: dword 2 +0x12300438: 0x00000000: dword 3 +0x1230043c: 0x00000000: dword 4 +0x12300440: 0x78100004: 3DSTATE_VS +0x12300444: 0x00000240: kernel pointer +0x12300448: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x1230044c: 0x00000000: scratch offset +0x12300450: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x12300454: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300458: 0x7a000002: PIPE_CONTROL +0x1230045c: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300460: 0x00000000: +0x12300464: 0x00000000: +0x12300468: 0x7a000002: PIPE_CONTROL +0x1230046c: 0x00004000: qword write, +0x12300470: 0x00000000: +0x12300474: 0x00000000: +0x12300478: 0x7a000002: PIPE_CONTROL +0x1230047c: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x12300480: 0x00000000: +0x12300484: 0x00000000: +0x12300488: 0x78170003: 3DSTATE_CONSTANT_PS_STATE +0x1230048c: 0x00000000: dword 1 +0x12300490: 0x00000000: dword 2 +0x12300494: 0x00000000: dword 3 +0x12300498: 0x00000000: dword 4 +0x1230049c: 0x78140007: 3DSTATE_WM +0x123004a0: 0x00000500: kernel start pointer 0 +0x123004a4: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x123004a8: 0x00000000: scratch offset +0x123004ac: 0x80020000: Depth Clear 0, Depth Resolve 0, HiZ Resolve 0, Dispatch GRF start[0] 2, start[1] 0, start[2] 0 +0x123004b0: 0x4e084002: MaxThreads 40, PS KillPixel 0, PS computed Z 0, PS use sourceZ 0, Thread Dispatch 1, PS use sourceW 0, Dispatch32 0, Dispatch16 1, Dispatch8 0 +0x123004b4: 0x00100000: Num SF output 1, Pos XY offset 0, ZW interp mode 0 , Barycentric interp mode 0x0, Point raster rule 0, Multisample mode 0, Multisample Dispatch mode 0 +0x123004b8: 0x00000000: kernel start pointer 1 +0x123004bc: 0x00000500: kernel start pointer 2 +0x123004c0: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123004c4: 0x00000052: vertex count +0x123004c8: 0x000000a2: start vertex +0x123004cc: 0x00000001: instance count +0x123004d0: 0x00000000: start instance +0x123004d4: 0x00000000: index bias +0x123004d8: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x123004dc: 0x00000050: vertex count +0x123004e0: 0x000000f4: start vertex +0x123004e4: 0x00000001: instance count +0x123004e8: 0x00000000: start instance +0x123004ec: 0x00000000: index bias +0x123004f0: 0x78050001: 3DSTATE_URB +0x123004f4: 0x00000100: VS entries 256, alloc size 1 (1024bit row) +0x123004f8: 0x00000000: GS entries 0, alloc size 1 (1024bit row) +0x123004fc: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x12300500: 0x00007785: dword 1 +0x12300504: 0x00000000: dword 2 +0x12300508: 0x00000000: dword 3 +0x1230050c: 0x00000000: dword 4 +0x12300510: 0x78100004: 3DSTATE_VS +0x12300514: 0x00000640: kernel pointer +0x12300518: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x1230051c: 0x00000000: scratch offset +0x12300520: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x12300524: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300528: 0x7a000002: PIPE_CONTROL +0x1230052c: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300530: 0x00000000: +0x12300534: 0x00000000: +0x12300538: 0x7a000002: PIPE_CONTROL +0x1230053c: 0x00004000: qword write, +0x12300540: 0x00000000: +0x12300544: 0x00000000: +0x12300548: 0x7a000002: PIPE_CONTROL +0x1230054c: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x12300550: 0x00000000: +0x12300554: 0x00000000: +0x12300558: 0x78130012: 3DSTATE_SF +0x1230055c: 0x00600810: Attrib Out 1, Attrib Swizzle enable, VUE read length 1, VUE read offset 1 +0x12300560: 0x00000403: Legacy Global DepthBias disable, FrontFace fill 0, BF fill 0, VP transform enable, FrontWinding_CCW +0x12300564: 0x62000000: AA disable, CullMode 3, Scissor disable, Multisample m ode 0 +0x12300568: 0x4c000808: Last Pixel disable, SubPixel Precision 8, Use PixelWidth 1 +0x1230056c: 0x00000000: Global Depth Offset Constant 0.000000 +0x12300570: 0x00000000: Global Depth Offset Scale 0.000000 +0x12300574: 0x00000000: Global Depth Offset Clamp 0.000000 +0x12300578: 0x00000000: Attrib 1 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 0 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x1230057c: 0x00000000: Attrib 3 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 2 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300580: 0x00000000: Attrib 5 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 4 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300584: 0x00000000: Attrib 7 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 6 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300588: 0x00000000: Attrib 9 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 8 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x1230058c: 0x00000000: Attrib 11 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 10 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300590: 0x00000000: Attrib 13 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 12 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300594: 0x00000000: Attrib 15 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 14 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300598: 0x00000000: Point Sprite TexCoord Enable +0x1230059c: 0x00000001: Const Interp Enable +0x123005a0: 0x00000000: Attrib 7-0 WrapShortest Enable +0x123005a4: 0x00000000: Attrib 15-8 WrapShortest Enable +0x123005a8: 0x78011302: 3DSTATE_BINDING_TABLE_POINTERS: VS mod 1, GS mod 1, PS mod 1 +0x123005ac: 0x00007600: VS binding table +0x123005b0: 0x00007600: GS binding table +0x123005b4: 0x00007600: WM binding table +0x123005b8: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x123005bc: 0x00000018: buffer 0: sequential, pitch 24b +0x123005c0: 0x00000f48: buffer address +0x123005c4: 0x00007fff: max index +0x123005c8: 0x00000000: mbz +0x123005cc: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x123005d0: 0x02400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123005d4: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123005d8: 0x0240000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x123005dc: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123005e0: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123005e4: 0x000000a2: vertex count +0x123005e8: 0x00000000: start vertex +0x123005ec: 0x00000001: instance count +0x123005f0: 0x00000000: start instance +0x123005f4: 0x00000000: index bias +0x123005f8: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x123005fc: 0x000074c5: dword 1 +0x12300600: 0x00000000: dword 2 +0x12300604: 0x00000000: dword 3 +0x12300608: 0x00000000: dword 4 +0x1230060c: 0x78100004: 3DSTATE_VS +0x12300610: 0x00000640: kernel pointer +0x12300614: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300618: 0x00000000: scratch offset +0x1230061c: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x12300620: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300624: 0x7a000002: PIPE_CONTROL +0x12300628: 0x00100002: no write, cs stall, stall at scoreboard, +0x1230062c: 0x00000000: +0x12300630: 0x00000000: +0x12300634: 0x7a000002: PIPE_CONTROL +0x12300638: 0x00004000: qword write, +0x1230063c: 0x00000000: +0x12300640: 0x00000000: +0x12300644: 0x7a000002: PIPE_CONTROL +0x12300648: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x1230064c: 0x00000000: +0x12300650: 0x00000000: +0x12300654: 0x78120002: 3DSTATE_CLIP +0x12300658: 0x00000400: UserClip distance cull test mask 0x0 +0x1230065c: 0x98000026: Clip enable, API mode OGL, Viewport XY test enable, Viewport Z test enable, Guardband test disable, Clip mode 0, Perspective Divide enable, Non-Perspective Barycentric disable, Tri Provoking 2, Line Provoking 1, Trifan Provoking 2 +0x12300660: 0x0003ffe0: Min PointWidth 1, Max PointWidth 2047, Force Zero RTAIndex enable, Max VPIndex 0 +0x12300664: 0x78130012: 3DSTATE_SF +0x12300668: 0x00600810: Attrib Out 1, Attrib Swizzle enable, VUE read length 1, VUE read offset 1 +0x1230066c: 0x00000403: Legacy Global DepthBias disable, FrontFace fill 0, BF fill 0, VP transform enable, FrontWinding_CCW +0x12300670: 0x62000000: AA disable, CullMode 3, Scissor disable, Multisample m ode 0 +0x12300674: 0x4c000808: Last Pixel disable, SubPixel Precision 8, Use PixelWidth 1 +0x12300678: 0x00000000: Global Depth Offset Constant 0.000000 +0x1230067c: 0x00000000: Global Depth Offset Scale 0.000000 +0x12300680: 0x00000000: Global Depth Offset Clamp 0.000000 +0x12300684: 0x00000000: Attrib 1 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 0 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300688: 0x00000000: Attrib 3 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 2 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x1230068c: 0x00000000: Attrib 5 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 4 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300690: 0x00000000: Attrib 7 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 6 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300694: 0x00000000: Attrib 9 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 8 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300698: 0x00000000: Attrib 11 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 10 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x1230069c: 0x00000000: Attrib 13 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 12 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123006a0: 0x00000000: Attrib 15 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 14 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123006a4: 0x00000000: Point Sprite TexCoord Enable +0x123006a8: 0x00000000: Const Interp Enable +0x123006ac: 0x00000000: Attrib 7-0 WrapShortest Enable +0x123006b0: 0x00000000: Attrib 15-8 WrapShortest Enable +0x123006b4: 0x78170003: 3DSTATE_CONSTANT_PS_STATE +0x123006b8: 0x00000000: dword 1 +0x123006bc: 0x00000000: dword 2 +0x123006c0: 0x00000000: dword 3 +0x123006c4: 0x00000000: dword 4 +0x123006c8: 0x78140007: 3DSTATE_WM +0x123006cc: 0x00000900: kernel start pointer 0 +0x123006d0: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x123006d4: 0x00000000: scratch offset +0x123006d8: 0x80060000: Depth Clear 0, Depth Resolve 0, HiZ Resolve 0, Dispatch GRF start[0] 6, start[1] 0, start[2] 0 +0x123006dc: 0x4e084002: MaxThreads 40, PS KillPixel 0, PS computed Z 0, PS use sourceZ 0, Thread Dispatch 1, PS use sourceW 0, Dispatch32 0, Dispatch16 1, Dispatch8 0 +0x123006e0: 0x00100400: Num SF output 1, Pos XY offset 0, ZW interp mode 0 , Barycentric interp mode 0x1, Point raster rule 0, Multisample mode 0, Multisample Dispatch mode 0 +0x123006e4: 0x00000000: kernel start pointer 1 +0x123006e8: 0x00000900: kernel start pointer 2 +0x123006ec: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123006f0: 0x0000002a: vertex count +0x123006f4: 0x000000a2: start vertex +0x123006f8: 0x00000001: instance count +0x123006fc: 0x00000000: start instance +0x12300700: 0x00000000: index bias +0x12300704: 0x78050001: 3DSTATE_URB +0x12300708: 0x00000100: VS entries 256, alloc size 1 (1024bit row) +0x1230070c: 0x00000000: GS entries 0, alloc size 1 (1024bit row) +0x12300710: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x12300714: 0x00007385: dword 1 +0x12300718: 0x00000000: dword 2 +0x1230071c: 0x00000000: dword 3 +0x12300720: 0x00000000: dword 4 +0x12300724: 0x78100004: 3DSTATE_VS +0x12300728: 0x00000240: kernel pointer +0x1230072c: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300730: 0x00000000: scratch offset +0x12300734: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x12300738: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x1230073c: 0x7a000002: PIPE_CONTROL +0x12300740: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300744: 0x00000000: +0x12300748: 0x00000000: +0x1230074c: 0x7a000002: PIPE_CONTROL +0x12300750: 0x00004000: qword write, +0x12300754: 0x00000000: +0x12300758: 0x00000000: +0x1230075c: 0x7a000002: PIPE_CONTROL +0x12300760: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x12300764: 0x00000000: +0x12300768: 0x00000000: +0x1230076c: 0x78120002: 3DSTATE_CLIP +0x12300770: 0x00000400: UserClip distance cull test mask 0x0 +0x12300774: 0x98000026: Clip enable, API mode OGL, Viewport XY test enable, Viewport Z test enable, Guardband test disable, Clip mode 0, Perspective Divide enable, Non-Perspective Barycentric disable, Tri Provoking 2, Line Provoking 1, Trifan Provoking 2 +0x12300778: 0x0003ffe0: Min PointWidth 1, Max PointWidth 2047, Force Zero RTAIndex enable, Max VPIndex 0 +0x1230077c: 0x78130012: 3DSTATE_SF +0x12300780: 0x00600810: Attrib Out 1, Attrib Swizzle enable, VUE read length 1, VUE read offset 1 +0x12300784: 0x00000403: Legacy Global DepthBias disable, FrontFace fill 0, BF fill 0, VP transform enable, FrontWinding_CCW +0x12300788: 0x62000000: AA disable, CullMode 3, Scissor disable, Multisample m ode 0 +0x1230078c: 0x4c000808: Last Pixel disable, SubPixel Precision 8, Use PixelWidth 1 +0x12300790: 0x00000000: Global Depth Offset Constant 0.000000 +0x12300794: 0x00000000: Global Depth Offset Scale 0.000000 +0x12300798: 0x00000000: Global Depth Offset Clamp 0.000000 +0x1230079c: 0x00000000: Attrib 1 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 0 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123007a0: 0x00000000: Attrib 3 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 2 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123007a4: 0x00000000: Attrib 5 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 4 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123007a8: 0x00000000: Attrib 7 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 6 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123007ac: 0x00000000: Attrib 9 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 8 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123007b0: 0x00000000: Attrib 11 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 10 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123007b4: 0x00000000: Attrib 13 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 12 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123007b8: 0x00000000: Attrib 15 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 14 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123007bc: 0x00000000: Point Sprite TexCoord Enable +0x123007c0: 0x00000001: Const Interp Enable +0x123007c4: 0x00000000: Attrib 7-0 WrapShortest Enable +0x123007c8: 0x00000000: Attrib 15-8 WrapShortest Enable +0x123007cc: 0x78170003: 3DSTATE_CONSTANT_PS_STATE +0x123007d0: 0x00000000: dword 1 +0x123007d4: 0x00000000: dword 2 +0x123007d8: 0x00000000: dword 3 +0x123007dc: 0x00000000: dword 4 +0x123007e0: 0x78140007: 3DSTATE_WM +0x123007e4: 0x00000500: kernel start pointer 0 +0x123007e8: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x123007ec: 0x00000000: scratch offset +0x123007f0: 0x80020000: Depth Clear 0, Depth Resolve 0, HiZ Resolve 0, Dispatch GRF start[0] 2, start[1] 0, start[2] 0 +0x123007f4: 0x4e084002: MaxThreads 40, PS KillPixel 0, PS computed Z 0, PS use sourceZ 0, Thread Dispatch 1, PS use sourceW 0, Dispatch32 0, Dispatch16 1, Dispatch8 0 +0x123007f8: 0x00100000: Num SF output 1, Pos XY offset 0, ZW interp mode 0 , Barycentric interp mode 0x0, Point raster rule 0, Multisample mode 0, Multisample Dispatch mode 0 +0x123007fc: 0x00000000: kernel start pointer 1 +0x12300800: 0x00000500: kernel start pointer 2 +0x12300804: 0x78011302: 3DSTATE_BINDING_TABLE_POINTERS: VS mod 1, GS mod 1, PS mod 1 +0x12300808: 0x00007200: VS binding table +0x1230080c: 0x00007200: GS binding table +0x12300810: 0x00007200: WM binding table +0x12300814: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300818: 0x0000000c: buffer 0: sequential, pitch 12b +0x1230081c: 0x00002268: buffer address +0x12300820: 0x00007fff: max index +0x12300824: 0x00000000: mbz +0x12300828: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x1230082c: 0x02400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x12300830: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300834: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300838: 0x0000002a: vertex count +0x1230083c: 0x00000000: start vertex +0x12300840: 0x00000001: instance count +0x12300844: 0x00000000: start instance +0x12300848: 0x00000000: index bias +0x1230084c: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300850: 0x00000028: vertex count +0x12300854: 0x0000002a: start vertex +0x12300858: 0x00000001: instance count +0x1230085c: 0x00000000: start instance +0x12300860: 0x00000000: index bias +0x12300864: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x12300868: 0x000070c5: dword 1 +0x1230086c: 0x00000000: dword 2 +0x12300870: 0x00000000: dword 3 +0x12300874: 0x00000000: dword 4 +0x12300878: 0x78100004: 3DSTATE_VS +0x1230087c: 0x00000240: kernel pointer +0x12300880: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300884: 0x00000000: scratch offset +0x12300888: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x1230088c: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300890: 0x7a000002: PIPE_CONTROL +0x12300894: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300898: 0x00000000: +0x1230089c: 0x00000000: +0x123008a0: 0x7a000002: PIPE_CONTROL +0x123008a4: 0x00004000: qword write, +0x123008a8: 0x00000000: +0x123008ac: 0x00000000: +0x123008b0: 0x7a000002: PIPE_CONTROL +0x123008b4: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x123008b8: 0x00000000: +0x123008bc: 0x00000000: +0x123008c0: 0x78170003: 3DSTATE_CONSTANT_PS_STATE +0x123008c4: 0x00000000: dword 1 +0x123008c8: 0x00000000: dword 2 +0x123008cc: 0x00000000: dword 3 +0x123008d0: 0x00000000: dword 4 +0x123008d4: 0x78140007: 3DSTATE_WM +0x123008d8: 0x00000500: kernel start pointer 0 +0x123008dc: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x123008e0: 0x00000000: scratch offset +0x123008e4: 0x80020000: Depth Clear 0, Depth Resolve 0, HiZ Resolve 0, Dispatch GRF start[0] 2, start[1] 0, start[2] 0 +0x123008e8: 0x4e084002: MaxThreads 40, PS KillPixel 0, PS computed Z 0, PS use sourceZ 0, Thread Dispatch 1, PS use sourceW 0, Dispatch32 0, Dispatch16 1, Dispatch8 0 +0x123008ec: 0x00100000: Num SF output 1, Pos XY offset 0, ZW interp mode 0 , Barycentric interp mode 0x0, Point raster rule 0, Multisample mode 0, Multisample Dispatch mode 0 +0x123008f0: 0x00000000: kernel start pointer 1 +0x123008f4: 0x00000500: kernel start pointer 2 +0x123008f8: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123008fc: 0x0000002a: vertex count +0x12300900: 0x00000052: start vertex +0x12300904: 0x00000001: instance count +0x12300908: 0x00000000: start instance +0x1230090c: 0x00000000: index bias +0x12300910: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300914: 0x00000028: vertex count +0x12300918: 0x0000007c: start vertex +0x1230091c: 0x00000001: instance count +0x12300920: 0x00000000: start instance +0x12300924: 0x00000000: index bias +0x12300928: 0x78050001: 3DSTATE_URB +0x1230092c: 0x00000100: VS entries 256, alloc size 1 (1024bit row) +0x12300930: 0x00000000: GS entries 0, alloc size 1 (1024bit row) +0x12300934: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x12300938: 0x00006f85: dword 1 +0x1230093c: 0x00000000: dword 2 +0x12300940: 0x00000000: dword 3 +0x12300944: 0x00000000: dword 4 +0x12300948: 0x78100004: 3DSTATE_VS +0x1230094c: 0x00000640: kernel pointer +0x12300950: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300954: 0x00000000: scratch offset +0x12300958: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x1230095c: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300960: 0x7a000002: PIPE_CONTROL +0x12300964: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300968: 0x00000000: +0x1230096c: 0x00000000: +0x12300970: 0x7a000002: PIPE_CONTROL +0x12300974: 0x00004000: qword write, +0x12300978: 0x00000000: +0x1230097c: 0x00000000: +0x12300980: 0x7a000002: PIPE_CONTROL +0x12300984: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x12300988: 0x00000000: +0x1230098c: 0x00000000: +0x12300990: 0x78130012: 3DSTATE_SF +0x12300994: 0x00600810: Attrib Out 1, Attrib Swizzle enable, VUE read length 1, VUE read offset 1 +0x12300998: 0x00000403: Legacy Global DepthBias disable, FrontFace fill 0, BF fill 0, VP transform enable, FrontWinding_CCW +0x1230099c: 0x62000000: AA disable, CullMode 3, Scissor disable, Multisample m ode 0 +0x123009a0: 0x4c000808: Last Pixel disable, SubPixel Precision 8, Use PixelWidth 1 +0x123009a4: 0x00000000: Global Depth Offset Constant 0.000000 +0x123009a8: 0x00000000: Global Depth Offset Scale 0.000000 +0x123009ac: 0x00000000: Global Depth Offset Clamp 0.000000 +0x123009b0: 0x00000000: Attrib 1 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 0 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123009b4: 0x00000000: Attrib 3 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 2 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123009b8: 0x00000000: Attrib 5 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 4 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123009bc: 0x00000000: Attrib 7 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 6 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123009c0: 0x00000000: Attrib 9 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 8 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123009c4: 0x00000000: Attrib 11 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 10 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123009c8: 0x00000000: Attrib 13 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 12 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123009cc: 0x00000000: Attrib 15 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 14 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123009d0: 0x00000000: Point Sprite TexCoord Enable +0x123009d4: 0x00000001: Const Interp Enable +0x123009d8: 0x00000000: Attrib 7-0 WrapShortest Enable +0x123009dc: 0x00000000: Attrib 15-8 WrapShortest Enable +0x123009e0: 0x78011302: 3DSTATE_BINDING_TABLE_POINTERS: VS mod 1, GS mod 1, PS mod 1 +0x123009e4: 0x00006e00: VS binding table +0x123009e8: 0x00006e00: GS binding table +0x123009ec: 0x00006e00: WM binding table +0x123009f0: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x123009f4: 0x00000018: buffer 0: sequential, pitch 24b +0x123009f8: 0x00002a30: buffer address +0x123009fc: 0x00007fff: max index +0x12300a00: 0x00000000: mbz +0x12300a04: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x12300a08: 0x02400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x12300a0c: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300a10: 0x0240000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x12300a14: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300a18: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300a1c: 0x00000052: vertex count +0x12300a20: 0x00000000: start vertex +0x12300a24: 0x00000001: instance count +0x12300a28: 0x00000000: start instance +0x12300a2c: 0x00000000: index bias +0x12300a30: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x12300a34: 0x00006cc5: dword 1 +0x12300a38: 0x00000000: dword 2 +0x12300a3c: 0x00000000: dword 3 +0x12300a40: 0x00000000: dword 4 +0x12300a44: 0x78100004: 3DSTATE_VS +0x12300a48: 0x00000640: kernel pointer +0x12300a4c: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300a50: 0x00000000: scratch offset +0x12300a54: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x12300a58: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300a5c: 0x7a000002: PIPE_CONTROL +0x12300a60: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300a64: 0x00000000: +0x12300a68: 0x00000000: +0x12300a6c: 0x7a000002: PIPE_CONTROL +0x12300a70: 0x00004000: qword write, +0x12300a74: 0x00000000: +0x12300a78: 0x00000000: +0x12300a7c: 0x7a000002: PIPE_CONTROL +0x12300a80: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x12300a84: 0x00000000: +0x12300a88: 0x00000000: +0x12300a8c: 0x78120002: 3DSTATE_CLIP +0x12300a90: 0x00000400: UserClip distance cull test mask 0x0 +0x12300a94: 0x98000026: Clip enable, API mode OGL, Viewport XY test enable, Viewport Z test enable, Guardband test disable, Clip mode 0, Perspective Divide enable, Non-Perspective Barycentric disable, Tri Provoking 2, Line Provoking 1, Trifan Provoking 2 +0x12300a98: 0x0003ffe0: Min PointWidth 1, Max PointWidth 2047, Force Zero RTAIndex enable, Max VPIndex 0 +0x12300a9c: 0x78130012: 3DSTATE_SF +0x12300aa0: 0x00600810: Attrib Out 1, Attrib Swizzle enable, VUE read length 1, VUE read offset 1 +0x12300aa4: 0x00000403: Legacy Global DepthBias disable, FrontFace fill 0, BF fill 0, VP transform enable, FrontWinding_CCW +0x12300aa8: 0x62000000: AA disable, CullMode 3, Scissor disable, Multisample m ode 0 +0x12300aac: 0x4c000808: Last Pixel disable, SubPixel Precision 8, Use PixelWidth 1 +0x12300ab0: 0x00000000: Global Depth Offset Constant 0.000000 +0x12300ab4: 0x00000000: Global Depth Offset Scale 0.000000 +0x12300ab8: 0x00000000: Global Depth Offset Clamp 0.000000 +0x12300abc: 0x00000000: Attrib 1 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 0 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300ac0: 0x00000000: Attrib 3 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 2 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300ac4: 0x00000000: Attrib 5 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 4 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300ac8: 0x00000000: Attrib 7 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 6 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300acc: 0x00000000: Attrib 9 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 8 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300ad0: 0x00000000: Attrib 11 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 10 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300ad4: 0x00000000: Attrib 13 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 12 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300ad8: 0x00000000: Attrib 15 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 14 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300adc: 0x00000000: Point Sprite TexCoord Enable +0x12300ae0: 0x00000000: Const Interp Enable +0x12300ae4: 0x00000000: Attrib 7-0 WrapShortest Enable +0x12300ae8: 0x00000000: Attrib 15-8 WrapShortest Enable +0x12300aec: 0x78170003: 3DSTATE_CONSTANT_PS_STATE +0x12300af0: 0x00000000: dword 1 +0x12300af4: 0x00000000: dword 2 +0x12300af8: 0x00000000: dword 3 +0x12300afc: 0x00000000: dword 4 +0x12300b00: 0x78140007: 3DSTATE_WM +0x12300b04: 0x00000900: kernel start pointer 0 +0x12300b08: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300b0c: 0x00000000: scratch offset +0x12300b10: 0x80060000: Depth Clear 0, Depth Resolve 0, HiZ Resolve 0, Dispatch GRF start[0] 6, start[1] 0, start[2] 0 +0x12300b14: 0x4e084002: MaxThreads 40, PS KillPixel 0, PS computed Z 0, PS use sourceZ 0, Thread Dispatch 1, PS use sourceW 0, Dispatch32 0, Dispatch16 1, Dispatch8 0 +0x12300b18: 0x00100400: Num SF output 1, Pos XY offset 0, ZW interp mode 0 , Barycentric interp mode 0x1, Point raster rule 0, Multisample mode 0, Multisample Dispatch mode 0 +0x12300b1c: 0x00000000: kernel start pointer 1 +0x12300b20: 0x00000900: kernel start pointer 2 +0x12300b24: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300b28: 0x00000016: vertex count +0x12300b2c: 0x00000052: start vertex +0x12300b30: 0x00000001: instance count +0x12300b34: 0x00000000: start instance +0x12300b38: 0x00000000: index bias +0x12300b3c: 0x78050001: 3DSTATE_URB +0x12300b40: 0x00000100: VS entries 256, alloc size 1 (1024bit row) +0x12300b44: 0x00000000: GS entries 0, alloc size 1 (1024bit row) +0x12300b48: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x12300b4c: 0x00006b85: dword 1 +0x12300b50: 0x00000000: dword 2 +0x12300b54: 0x00000000: dword 3 +0x12300b58: 0x00000000: dword 4 +0x12300b5c: 0x78100004: 3DSTATE_VS +0x12300b60: 0x00000240: kernel pointer +0x12300b64: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300b68: 0x00000000: scratch offset +0x12300b6c: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x12300b70: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300b74: 0x7a000002: PIPE_CONTROL +0x12300b78: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300b7c: 0x00000000: +0x12300b80: 0x00000000: +0x12300b84: 0x7a000002: PIPE_CONTROL +0x12300b88: 0x00004000: qword write, +0x12300b8c: 0x00000000: +0x12300b90: 0x00000000: +0x12300b94: 0x7a000002: PIPE_CONTROL +0x12300b98: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x12300b9c: 0x00000000: +0x12300ba0: 0x00000000: +0x12300ba4: 0x78120002: 3DSTATE_CLIP +0x12300ba8: 0x00000400: UserClip distance cull test mask 0x0 +0x12300bac: 0x98000026: Clip enable, API mode OGL, Viewport XY test enable, Viewport Z test enable, Guardband test disable, Clip mode 0, Perspective Divide enable, Non-Perspective Barycentric disable, Tri Provoking 2, Line Provoking 1, Trifan Provoking 2 +0x12300bb0: 0x0003ffe0: Min PointWidth 1, Max PointWidth 2047, Force Zero RTAIndex enable, Max VPIndex 0 +0x12300bb4: 0x78130012: 3DSTATE_SF +0x12300bb8: 0x00600810: Attrib Out 1, Attrib Swizzle enable, VUE read length 1, VUE read offset 1 +0x12300bbc: 0x00000403: Legacy Global DepthBias disable, FrontFace fill 0, BF fill 0, VP transform enable, FrontWinding_CCW +0x12300bc0: 0x62000000: AA disable, CullMode 3, Scissor disable, Multisample m ode 0 +0x12300bc4: 0x4c000808: Last Pixel disable, SubPixel Precision 8, Use PixelWidth 1 +0x12300bc8: 0x00000000: Global Depth Offset Constant 0.000000 +0x12300bcc: 0x00000000: Global Depth Offset Scale 0.000000 +0x12300bd0: 0x00000000: Global Depth Offset Clamp 0.000000 +0x12300bd4: 0x00000000: Attrib 1 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 0 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300bd8: 0x00000000: Attrib 3 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 2 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300bdc: 0x00000000: Attrib 5 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 4 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300be0: 0x00000000: Attrib 7 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 6 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300be4: 0x00000000: Attrib 9 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 8 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300be8: 0x00000000: Attrib 11 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 10 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300bec: 0x00000000: Attrib 13 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 12 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300bf0: 0x00000000: Attrib 15 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 14 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300bf4: 0x00000000: Point Sprite TexCoord Enable +0x12300bf8: 0x00000001: Const Interp Enable +0x12300bfc: 0x00000000: Attrib 7-0 WrapShortest Enable +0x12300c00: 0x00000000: Attrib 15-8 WrapShortest Enable +0x12300c04: 0x78170003: 3DSTATE_CONSTANT_PS_STATE +0x12300c08: 0x00000000: dword 1 +0x12300c0c: 0x00000000: dword 2 +0x12300c10: 0x00000000: dword 3 +0x12300c14: 0x00000000: dword 4 +0x12300c18: 0x78140007: 3DSTATE_WM +0x12300c1c: 0x00000500: kernel start pointer 0 +0x12300c20: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300c24: 0x00000000: scratch offset +0x12300c28: 0x80020000: Depth Clear 0, Depth Resolve 0, HiZ Resolve 0, Dispatch GRF start[0] 2, start[1] 0, start[2] 0 +0x12300c2c: 0x4e084002: MaxThreads 40, PS KillPixel 0, PS computed Z 0, PS use sourceZ 0, Thread Dispatch 1, PS use sourceW 0, Dispatch32 0, Dispatch16 1, Dispatch8 0 +0x12300c30: 0x00100000: Num SF output 1, Pos XY offset 0, ZW interp mode 0 , Barycentric interp mode 0x0, Point raster rule 0, Multisample mode 0, Multisample Dispatch mode 0 +0x12300c34: 0x00000000: kernel start pointer 1 +0x12300c38: 0x00000500: kernel start pointer 2 +0x12300c3c: 0x78011302: 3DSTATE_BINDING_TABLE_POINTERS: VS mod 1, GS mod 1, PS mod 1 +0x12300c40: 0x00006a00: VS binding table +0x12300c44: 0x00006a00: GS binding table +0x12300c48: 0x00006a00: WM binding table +0x12300c4c: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300c50: 0x0000000c: buffer 0: sequential, pitch 12b +0x12300c54: 0x000033f0: buffer address +0x12300c58: 0x00007fff: max index +0x12300c5c: 0x00000000: mbz +0x12300c60: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x12300c64: 0x02400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x12300c68: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300c6c: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300c70: 0x0000002a: vertex count +0x12300c74: 0x00000000: start vertex +0x12300c78: 0x00000001: instance count +0x12300c7c: 0x00000000: start instance +0x12300c80: 0x00000000: index bias +0x12300c84: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300c88: 0x00000028: vertex count +0x12300c8c: 0x0000002a: start vertex +0x12300c90: 0x00000001: instance count +0x12300c94: 0x00000000: start instance +0x12300c98: 0x00000000: index bias +0x12300c9c: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x12300ca0: 0x000068c5: dword 1 +0x12300ca4: 0x00000000: dword 2 +0x12300ca8: 0x00000000: dword 3 +0x12300cac: 0x00000000: dword 4 +0x12300cb0: 0x78100004: 3DSTATE_VS +0x12300cb4: 0x00000240: kernel pointer +0x12300cb8: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300cbc: 0x00000000: scratch offset +0x12300cc0: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x12300cc4: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300cc8: 0x7a000002: PIPE_CONTROL +0x12300ccc: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300cd0: 0x00000000: +0x12300cd4: 0x00000000: +0x12300cd8: 0x7a000002: PIPE_CONTROL +0x12300cdc: 0x00004000: qword write, +0x12300ce0: 0x00000000: +0x12300ce4: 0x00000000: +0x12300ce8: 0x7a000002: PIPE_CONTROL +0x12300cec: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x12300cf0: 0x00000000: +0x12300cf4: 0x00000000: +0x12300cf8: 0x78170003: 3DSTATE_CONSTANT_PS_STATE +0x12300cfc: 0x00000000: dword 1 +0x12300d00: 0x00000000: dword 2 +0x12300d04: 0x00000000: dword 3 +0x12300d08: 0x00000000: dword 4 +0x12300d0c: 0x78140007: 3DSTATE_WM +0x12300d10: 0x00000500: kernel start pointer 0 +0x12300d14: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300d18: 0x00000000: scratch offset +0x12300d1c: 0x80020000: Depth Clear 0, Depth Resolve 0, HiZ Resolve 0, Dispatch GRF start[0] 2, start[1] 0, start[2] 0 +0x12300d20: 0x4e084002: MaxThreads 40, PS KillPixel 0, PS computed Z 0, PS use sourceZ 0, Thread Dispatch 1, PS use sourceW 0, Dispatch32 0, Dispatch16 1, Dispatch8 0 +0x12300d24: 0x00100000: Num SF output 1, Pos XY offset 0, ZW interp mode 0 , Barycentric interp mode 0x0, Point raster rule 0, Multisample mode 0, Multisample Dispatch mode 0 +0x12300d28: 0x00000000: kernel start pointer 1 +0x12300d2c: 0x00000500: kernel start pointer 2 +0x12300d30: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300d34: 0x0000002a: vertex count +0x12300d38: 0x00000052: start vertex +0x12300d3c: 0x00000001: instance count +0x12300d40: 0x00000000: start instance +0x12300d44: 0x00000000: index bias +0x12300d48: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300d4c: 0x00000028: vertex count +0x12300d50: 0x0000007c: start vertex +0x12300d54: 0x00000001: instance count +0x12300d58: 0x00000000: start instance +0x12300d5c: 0x00000000: index bias +0x12300d60: 0x78050001: 3DSTATE_URB +0x12300d64: 0x00000100: VS entries 256, alloc size 1 (1024bit row) +0x12300d68: 0x00000000: GS entries 0, alloc size 1 (1024bit row) +0x12300d6c: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x12300d70: 0x00006785: dword 1 +0x12300d74: 0x00000000: dword 2 +0x12300d78: 0x00000000: dword 3 +0x12300d7c: 0x00000000: dword 4 +0x12300d80: 0x78100004: 3DSTATE_VS +0x12300d84: 0x00000640: kernel pointer +0x12300d88: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300d8c: 0x00000000: scratch offset +0x12300d90: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x12300d94: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300d98: 0x7a000002: PIPE_CONTROL +0x12300d9c: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300da0: 0x00000000: +0x12300da4: 0x00000000: +0x12300da8: 0x7a000002: PIPE_CONTROL +0x12300dac: 0x00004000: qword write, +0x12300db0: 0x00000000: +0x12300db4: 0x00000000: +0x12300db8: 0x7a000002: PIPE_CONTROL +0x12300dbc: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x12300dc0: 0x00000000: +0x12300dc4: 0x00000000: +0x12300dc8: 0x78130012: 3DSTATE_SF +0x12300dcc: 0x00600810: Attrib Out 1, Attrib Swizzle enable, VUE read length 1, VUE read offset 1 +0x12300dd0: 0x00000403: Legacy Global DepthBias disable, FrontFace fill 0, BF fill 0, VP transform enable, FrontWinding_CCW +0x12300dd4: 0x62000000: AA disable, CullMode 3, Scissor disable, Multisample m ode 0 +0x12300dd8: 0x4c000808: Last Pixel disable, SubPixel Precision 8, Use PixelWidth 1 +0x12300ddc: 0x00000000: Global Depth Offset Constant 0.000000 +0x12300de0: 0x00000000: Global Depth Offset Scale 0.000000 +0x12300de4: 0x00000000: Global Depth Offset Clamp 0.000000 +0x12300de8: 0x00000000: Attrib 1 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 0 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300dec: 0x00000000: Attrib 3 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 2 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300df0: 0x00000000: Attrib 5 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 4 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300df4: 0x00000000: Attrib 7 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 6 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300df8: 0x00000000: Attrib 9 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 8 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300dfc: 0x00000000: Attrib 11 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 10 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300e00: 0x00000000: Attrib 13 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 12 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300e04: 0x00000000: Attrib 15 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 14 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300e08: 0x00000000: Point Sprite TexCoord Enable +0x12300e0c: 0x00000001: Const Interp Enable +0x12300e10: 0x00000000: Attrib 7-0 WrapShortest Enable +0x12300e14: 0x00000000: Attrib 15-8 WrapShortest Enable +0x12300e18: 0x78011302: 3DSTATE_BINDING_TABLE_POINTERS: VS mod 1, GS mod 1, PS mod 1 +0x12300e1c: 0x00006600: VS binding table +0x12300e20: 0x00006600: GS binding table +0x12300e24: 0x00006600: WM binding table +0x12300e28: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300e2c: 0x00000018: buffer 0: sequential, pitch 24b +0x12300e30: 0x00003bb8: buffer address +0x12300e34: 0x00007fff: max index +0x12300e38: 0x00000000: mbz +0x12300e3c: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x12300e40: 0x02400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x12300e44: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300e48: 0x0240000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x12300e4c: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300e50: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300e54: 0x00000052: vertex count +0x12300e58: 0x00000000: start vertex +0x12300e5c: 0x00000001: instance count +0x12300e60: 0x00000000: start instance +0x12300e64: 0x00000000: index bias +0x12300e68: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x12300e6c: 0x000064c5: dword 1 +0x12300e70: 0x00000000: dword 2 +0x12300e74: 0x00000000: dword 3 +0x12300e78: 0x00000000: dword 4 +0x12300e7c: 0x78100004: 3DSTATE_VS +0x12300e80: 0x00000640: kernel pointer +0x12300e84: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300e88: 0x00000000: scratch offset +0x12300e8c: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x12300e90: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300e94: 0x7a000002: PIPE_CONTROL +0x12300e98: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300e9c: 0x00000000: +0x12300ea0: 0x00000000: +0x12300ea4: 0x7a000002: PIPE_CONTROL +0x12300ea8: 0x00004000: qword write, +0x12300eac: 0x00000000: +0x12300eb0: 0x00000000: +0x12300eb4: 0x7a000002: PIPE_CONTROL +0x12300eb8: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x12300ebc: 0x00000000: +0x12300ec0: 0x00000000: +0x12300ec4: 0x78120002: 3DSTATE_CLIP +0x12300ec8: 0x00000400: UserClip distance cull test mask 0x0 +0x12300ecc: 0x98000026: Clip enable, API mode OGL, Viewport XY test enable, Viewport Z test enable, Guardband test disable, Clip mode 0, Perspective Divide enable, Non-Perspective Barycentric disable, Tri Provoking 2, Line Provoking 1, Trifan Provoking 2 +0x12300ed0: 0x0003ffe0: Min PointWidth 1, Max PointWidth 2047, Force Zero RTAIndex enable, Max VPIndex 0 +0x12300ed4: 0x78130012: 3DSTATE_SF +0x12300ed8: 0x00600810: Attrib Out 1, Attrib Swizzle enable, VUE read length 1, VUE read offset 1 +0x12300edc: 0x00000403: Legacy Global DepthBias disable, FrontFace fill 0, BF fill 0, VP transform enable, FrontWinding_CCW +0x12300ee0: 0x62000000: AA disable, CullMode 3, Scissor disable, Multisample m ode 0 +0x12300ee4: 0x4c000808: Last Pixel disable, SubPixel Precision 8, Use PixelWidth 1 +0x12300ee8: 0x00000000: Global Depth Offset Constant 0.000000 +0x12300eec: 0x00000000: Global Depth Offset Scale 0.000000 +0x12300ef0: 0x00000000: Global Depth Offset Clamp 0.000000 +0x12300ef4: 0x00000000: Attrib 1 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 0 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300ef8: 0x00000000: Attrib 3 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 2 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300efc: 0x00000000: Attrib 5 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 4 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300f00: 0x00000000: Attrib 7 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 6 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300f04: 0x00000000: Attrib 9 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 8 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300f08: 0x00000000: Attrib 11 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 10 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300f0c: 0x00000000: Attrib 13 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 12 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300f10: 0x00000000: Attrib 15 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 14 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300f14: 0x00000000: Point Sprite TexCoord Enable +0x12300f18: 0x00000000: Const Interp Enable +0x12300f1c: 0x00000000: Attrib 7-0 WrapShortest Enable +0x12300f20: 0x00000000: Attrib 15-8 WrapShortest Enable +0x12300f24: 0x78170003: 3DSTATE_CONSTANT_PS_STATE +0x12300f28: 0x00000000: dword 1 +0x12300f2c: 0x00000000: dword 2 +0x12300f30: 0x00000000: dword 3 +0x12300f34: 0x00000000: dword 4 +0x12300f38: 0x78140007: 3DSTATE_WM +0x12300f3c: 0x00000900: kernel start pointer 0 +0x12300f40: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300f44: 0x00000000: scratch offset +0x12300f48: 0x80060000: Depth Clear 0, Depth Resolve 0, HiZ Resolve 0, Dispatch GRF start[0] 6, start[1] 0, start[2] 0 +0x12300f4c: 0x4e084002: MaxThreads 40, PS KillPixel 0, PS computed Z 0, PS use sourceZ 0, Thread Dispatch 1, PS use sourceW 0, Dispatch32 0, Dispatch16 1, Dispatch8 0 +0x12300f50: 0x00100400: Num SF output 1, Pos XY offset 0, ZW interp mode 0 , Barycentric interp mode 0x1, Point raster rule 0, Multisample mode 0, Multisample Dispatch mode 0 +0x12300f54: 0x00000000: kernel start pointer 1 +0x12300f58: 0x00000900: kernel start pointer 2 +0x12300f5c: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300f60: 0x00000016: vertex count +0x12300f64: 0x00000052: start vertex +0x12300f68: 0x00000001: instance count +0x12300f6c: 0x00000000: start instance +0x12300f70: 0x00000000: index bias +0x12300f74: 0x05000000: MI_BATCH_BUFFER_END diff --git a/intel/tests/gen6-3d.batch.sh b/intel/tests/gen6-3d.batch.sh new file mode 120000 index 0000000..796ca5f --- /dev/null +++ b/intel/tests/gen6-3d.batch.sh @@ -0,0 +1 @@ +test-batch.sh \ No newline at end of file diff --git a/intel/tests/gen7-2d-copy.batch b/intel/tests/gen7-2d-copy.batch new file mode 100644 index 0000000..ce7fc29 Binary files /dev/null and b/intel/tests/gen7-2d-copy.batch differ diff --git a/intel/tests/gen7-2d-copy.batch-ref.txt b/intel/tests/gen7-2d-copy.batch-ref.txt new file mode 100644 index 0000000..0d621d3 --- /dev/null +++ b/intel/tests/gen7-2d-copy.batch-ref.txt @@ -0,0 +1,14 @@ +0x12300000: 0x54f08006: XY_SRC_COPY_BLT (rgb enabled, alpha enabled, src tile 1, dst tile 0) +0x12300004: 0x03cc0190: format 8888, pitch 400, rop 0xcc, clipping disabled, +0x12300008: 0x00000000: dst (0,0) +0x1230000c: 0x00640064: dst (100,100) +0x12300010: 0x122e9000: dst offset 0x122e9000 +0x12300014: 0x00000000: src (0,0) +0x12300018: 0x00000080: src pitch 128 +0x1230001c: 0x02ff1000: src offset 0x02ff1000 +0x12300020: 0x13000002: MI_FLUSH_DW post_sync_op='no write' +0x12300024: 0x00000000: address +0x12300028: 0x00000000: dword +0x1230002c: 0x00000000: upper dword +0x12300030: 0x05000000: MI_BATCH_BUFFER_END +0x12300034: 0x00000000: diff --git a/intel/tests/gen7-2d-copy.batch.sh b/intel/tests/gen7-2d-copy.batch.sh new file mode 120000 index 0000000..796ca5f --- /dev/null +++ b/intel/tests/gen7-2d-copy.batch.sh @@ -0,0 +1 @@ +test-batch.sh \ No newline at end of file diff --git a/intel/tests/gen7-3d.batch b/intel/tests/gen7-3d.batch new file mode 100644 index 0000000..328ec88 Binary files /dev/null and b/intel/tests/gen7-3d.batch differ diff --git a/intel/tests/gen7-3d.batch-ref.txt b/intel/tests/gen7-3d.batch-ref.txt new file mode 100644 index 0000000..cd2dfc4 --- /dev/null +++ b/intel/tests/gen7-3d.batch-ref.txt @@ -0,0 +1,212 @@ +0x12300000: 0x69040000: 3DSTATE_PIPELINE_SELECT +0x12300004: 0x790d0002: 3DSTATE_MULTISAMPLE +0x12300008: 0x00000000: dword 1 +0x1230000c: 0x00000000: dword 2 +0x12300010: 0x00000000: dword 3 +0x12300014: 0x78180000: 3DSTATE_SAMPLE_MASK +0x12300018: 0x00000001: dword 1 +0x1230001c: 0x61020000: STATE_SIP +0x12300020: 0x00000000: dword 1 +0x12300024: 0x680b0000: 3DSTATE_VF_STATISTICS +0x12300028: 0x61010008: STATE_BASE_ADDRESS +0x1230002c: 0x00000001: general state base address 0x00000000 +0x12300030: 0x091ba001: surface state base address 0x091ba000 +0x12300034: 0x091ba001: dynamic state base address 0x091ba000 +0x12300038: 0x00000001: indirect state base address 0x00000000 +0x1230003c: 0x091c2001: instruction state base address 0x091c2000 +0x12300040: 0x00000001: general state upper bound disabled +0x12300044: 0x091c2001: dynamic state upper bound 0x091c2000 +0x12300048: 0x00000001: indirect state upper bound disabled +0x1230004c: 0x00000001: instruction state upper bound disabled +0x12300050: 0x78230000: 3DSTATE_VIEWPORT_STATE_POINTERS_CC +0x12300054: 0x00007fe0: pointer to CC viewport +0x12300058: 0x78210000: 3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP +0x1230005c: 0x00007f80: pointer to SF_CLIP viewport +0x12300060: 0x78300000: 3DSTATE_URB_VS +0x12300064: 0x040002c0: 16KB start, size=1 64B rows, nr_entries=704, total size 45056B +0x12300068: 0x78330000: 3DSTATE_URB_GS +0x1230006c: 0x04000000: 16KB start, size=1 64B rows, nr_entries=0, total size 0B +0x12300070: 0x78310000: 3DSTATE_URB_HS +0x12300074: 0x04000000: 16KB start, size=1 64B rows, nr_entries=0, total size 0B +0x12300078: 0x78320000: 3DSTATE_URB_DS +0x1230007c: 0x04000000: 16KB start, size=1 64B rows, nr_entries=0, total size 0B +0x12300080: 0x78240000: 3DSTATE_BLEND_STATE_POINTERS +0x12300084: 0x00007f41: pointer to BLEND_STATE at 0x00007f40 (changed) +0x12300088: 0x780e0000: 3DSTATE_CC_STATE_POINTERS +0x1230008c: 0x00007f01: pointer to COLOR_CALC_STATE at 0x00007f00 (changed) +0x12300090: 0x78250000: 3DSTATE_DEPTH_STENCIL_STATE_POINTERS +0x12300094: 0x00007ec1: pointer to DEPTH_STENCIL_STATE at 0x00007ec0 (changed) +0x12300098: 0x78160005: 3DSTATE_CONSTANT_GS +0x1230009c: 0x00000000: len 0 = 0, len 1 = 0 +0x123000a0: 0x00000000: len 2 = 0, len 3 = 0 +0x123000a4: 0x00000000: pointer to constbuf 0 +0x123000a8: 0x00000000: pointer to constbuf 1 +0x123000ac: 0x00000000: pointer to constbuf 2 +0x123000b0: 0x00000000: pointer to constbuf 3 +0x123000b4: 0x78110005: 3DSTATE_GS +0x123000b8: 0x00000000: kernel pointer +0x123000bc: 0x00000000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x123000c0: 0x00000000: scratch offset +0x123000c4: 0x00000401: Dispatch GRF start 1, VUE read length 0, VUE read offset 0 +0x123000c8: 0x00000400: Max Threads 1, Rendering disable +0x123000cc: 0x00000000: Reorder disable, Discard Adjaceny disable, GS disable +0x123000d0: 0x78290000: 3DSTATE_BINDING_TABLE_POINTERS_GS +0x123000d4: 0x00000000: dword 1 +0x123000d8: 0x78190005: 3DSTATE_CONSTANT_HS +0x123000dc: 0x00000000: len 0 = 0, len 1 = 0 +0x123000e0: 0x00000000: len 2 = 0, len 3 = 0 +0x123000e4: 0x00000000: pointer to constbuf 0 +0x123000e8: 0x00000000: pointer to constbuf 1 +0x123000ec: 0x00000000: pointer to constbuf 2 +0x123000f0: 0x00000000: pointer to constbuf 3 +0x123000f4: 0x781b0005: 3DSTATE_HS +0x123000f8: 0x00000000: dword 1 +0x123000fc: 0x00000000: dword 2 +0x12300100: 0x00000000: dword 3 +0x12300104: 0x00000000: dword 4 +0x12300108: 0x00000000: dword 5 +0x1230010c: 0x00000000: dword 6 +0x12300110: 0x78270000: 3DSTATE_BINDING_TABLE_POINTERS_HS +0x12300114: 0x00000000: dword 1 +0x12300118: 0x781c0002: 3DSTATE_TE +0x1230011c: 0x00000000: dword 1 +0x12300120: 0x00000000: dword 2 +0x12300124: 0x00000000: dword 3 +0x12300128: 0x781a0005: 3DSTATE_CONSTANT_DS +0x1230012c: 0x00000000: len 0 = 0, len 1 = 0 +0x12300130: 0x00000000: len 2 = 0, len 3 = 0 +0x12300134: 0x00000000: pointer to constbuf 0 +0x12300138: 0x00000000: pointer to constbuf 1 +0x1230013c: 0x00000000: pointer to constbuf 2 +0x12300140: 0x00000000: pointer to constbuf 3 +0x12300144: 0x781d0004: 3DSTATE_DS +0x12300148: 0x00000000: dword 1 +0x1230014c: 0x00000000: dword 2 +0x12300150: 0x00000000: dword 3 +0x12300154: 0x00000000: dword 4 +0x12300158: 0x00000000: dword 5 +0x1230015c: 0x78280000: 3DSTATE_BINDING_TABLE_POINTERS_DS +0x12300160: 0x00000000: dword 1 +0x12300164: 0x78260000: 3DSTATE_BINDING_TABLE_POINTERS_VS +0x12300168: 0x00007c40: dword 1 +0x1230016c: 0x782b0000: 3DSTATE_SAMPLER_STATE_POINTERS_VS +0x12300170: 0x00007c20: dword 1 +0x12300174: 0x79120000: 3DSTATE_PUSH_CONSTANT_ALLOC_VS +0x12300178: 0x00000008: dword 1 +0x1230017c: 0x78150005: 3DSTATE_CONSTANT_VS +0x12300180: 0x00000002: len 0 = 2, len 1 = 0 +0x12300184: 0x00000000: len 2 = 0, len 3 = 0 +0x12300188: 0x00007e00: pointer to constbuf 0 +0x1230018c: 0x00000000: pointer to constbuf 1 +0x12300190: 0x00000000: pointer to constbuf 2 +0x12300194: 0x00000000: pointer to constbuf 3 +0x12300198: 0x78100004: 3DSTATE_VS +0x1230019c: 0x00000000: kernel pointer +0x123001a0: 0x08000000: SPF=0, VME=0, Sampler Count 1, Binding table count 0 +0x123001a4: 0x00000000: scratch offset +0x123001a8: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x123001ac: 0xfe000401: Max Threads 128, Vertex Cache enable, VS func enable +0x123001b0: 0x781e0001: 3DSTATE_STREAMOUT +0x123001b4: 0x00000000: dword 1 +0x123001b8: 0x00000000: dword 2 +0x123001bc: 0x78120002: 3DSTATE_CLIP +0x123001c0: 0x00150400: UserClip distance cull test mask 0x0 +0x123001c4: 0x98000026: Clip enable, API mode OGL, Viewport XY test enable, Viewport Z test enable, Guardband test disable, Clip mode 0, Perspective Divide enable, Non-Perspective Barycentric disable, Tri Provoking 2, Line Provoking 1, Trifan Provoking 2 +0x123001c8: 0x0003ffe0: Min PointWidth 1, Max PointWidth 2047, Force Zero RTAIndex enable, Max VPIndex 0 +0x123001cc: 0x781f000c: 3DSTATE_SBE +0x123001d0: 0x00600810: dword 1 +0x123001d4: 0x00000000: dword 2 +0x123001d8: 0x00000000: dword 3 +0x123001dc: 0x00000000: dword 4 +0x123001e0: 0x00000000: dword 5 +0x123001e4: 0x00000000: dword 6 +0x123001e8: 0x00000000: dword 7 +0x123001ec: 0x00000000: dword 8 +0x123001f0: 0x00000000: dword 9 +0x123001f4: 0x00000000: dword 10 +0x123001f8: 0x00000000: dword 11 +0x123001fc: 0x00000000: dword 12 +0x12300200: 0x00000000: dword 13 +0x12300204: 0x78130005: 3DSTATE_SF +0x12300208: 0x00001403: dword 1 +0x1230020c: 0x22000000: dword 2 +0x12300210: 0x4c000808: dword 3 +0x12300214: 0x00000000: dword 4 +0x12300218: 0x00000000: dword 5 +0x1230021c: 0x00000000: dword 6 +0x12300220: 0x78140001: 3DSTATE_WM +0x12300224: 0xa0000840: (PP ), point UR +0x12300228: 0x00000000: MS +0x1230022c: 0x782a0000: 3DSTATE_BINDING_TABLE_POINTERS_PS +0x12300230: 0x00007c40: dword 1 +0x12300234: 0x782f0000: 3DSTATE_SAMPLER_STATE_POINTERS_PS +0x12300238: 0x00007c20: dword 1 +0x1230023c: 0x79160000: 3DSTATE_PUSH_CONSTANT_ALLOC_PS +0x12300240: 0x00080008: dword 1 +0x12300244: 0x78170005: 3DSTATE_CONSTANT_PS +0x12300248: 0x00000000: len 0 = 0, len 1 = 0 +0x1230024c: 0x00000000: len 2 = 0, len 3 = 0 +0x12300250: 0x00000000: pointer to constbuf 0 +0x12300254: 0x00000000: pointer to constbuf 1 +0x12300258: 0x00000000: pointer to constbuf 2 +0x1230025c: 0x00000000: pointer to constbuf 3 +0x12300260: 0x78200006: 3DSTATE_PS +0x12300264: 0x00000140: dword 1 +0x12300268: 0x08000000: dword 2 +0x1230026c: 0x00000000: dword 3 +0x12300270: 0x55000403: dword 4 +0x12300274: 0x00040006: dword 5 +0x12300278: 0x00000000: dword 6 +0x1230027c: 0x00000240: dword 7 +0x12300280: 0x780f0000: 3DSTATE_SCISSOR_POINTERS +0x12300284: 0x00007be0: scissor rect offset +0x12300288: 0x7a000002: PIPE_CONTROL +0x1230028c: 0x00002000: no write, depth stall, +0x12300290: 0x00000000: +0x12300294: 0x00000000: +0x12300298: 0x7a000002: PIPE_CONTROL +0x1230029c: 0x00000001: no write, depth cache flush, +0x123002a0: 0x00000000: +0x123002a4: 0x00000000: +0x123002a8: 0x7a000002: PIPE_CONTROL +0x123002ac: 0x00002000: no write, depth stall, +0x123002b0: 0x00000000: +0x123002b4: 0x00000000: +0x123002b8: 0x78050005: 3DSTATE_DEPTH_BUFFER +0x123002bc: 0xe0040000: dword 1 +0x123002c0: 0x00000000: dword 2 +0x123002c4: 0x00000000: dword 3 +0x123002c8: 0x00000000: dword 4 +0x123002cc: 0x00000000: dword 5 +0x123002d0: 0x00000000: dword 6 +0x123002d4: 0x78070001: 3DSTATE_HIER_DEPTH_BUFFER +0x123002d8: 0x00000000: pitch 1b +0x123002dc: 0x00000000: pointer to HiZ buffer +0x123002e0: 0x78060001: 3DSTATE_STENCIL_BUFFER +0x123002e4: 0x00000000: dword 1 +0x123002e8: 0x00000000: dword 2 +0x123002ec: 0x78040001: 3DSTATE_CLEAR_PARAMS +0x123002f0: 0x00000000: dword 1 +0x123002f4: 0x00000000: dword 2 +0x123002f8: 0x79000002: 3DSTATE_DRAWING_RECTANGLE +0x123002fc: 0x00000000: top left: 0,0 +0x12300300: 0x00130077: bottom right: 119,19 +0x12300304: 0x00000000: origin: 0,0 +0x12300308: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x1230030c: 0x00004014: buffer 0: sequential, pitch 20b +0x12300310: 0x158b3000: buffer address +0x12300314: 0x158c2fff: max index +0x12300318: 0x00000000: mbz +0x1230031c: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x12300320: 0x02850000: buffer 0: valid, type 0x0085, src offset 0x0000 bytes +0x12300324: 0x11230000: (X, Y, 0.0, 1.0), dst offset 0x00 bytes +0x12300328: 0x02400008: buffer 0: valid, type 0x0040, src offset 0x0008 bytes +0x1230032c: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300330: 0x7b000005: 3DPRIMITIVE: +0x12300334: 0x00000007: quad list sequential +0x12300338: 0x00000004: vertex count +0x1230033c: 0x00000000: start vertex +0x12300340: 0x00000001: instance count +0x12300344: 0x00000000: start instance +0x12300348: 0x00000000: index bias +0x1230034c: 0x05000000: MI_BATCH_BUFFER_END diff --git a/intel/tests/gen7-3d.batch.sh b/intel/tests/gen7-3d.batch.sh new file mode 120000 index 0000000..796ca5f --- /dev/null +++ b/intel/tests/gen7-3d.batch.sh @@ -0,0 +1 @@ +test-batch.sh \ No newline at end of file diff --git a/intel/tests/gm45-3d.batch b/intel/tests/gm45-3d.batch new file mode 100644 index 0000000..549608b Binary files /dev/null and b/intel/tests/gm45-3d.batch differ diff --git a/intel/tests/gm45-3d.batch-ref.txt b/intel/tests/gm45-3d.batch-ref.txt new file mode 100644 index 0000000..5a47d77 --- /dev/null +++ b/intel/tests/gm45-3d.batch-ref.txt @@ -0,0 +1,488 @@ +0x12300000: 0x69040000: 3DSTATE_PIPELINE_SELECT +0x12300004: 0x79090000: 3DSTATE_GLOBAL_DEPTH_OFFSET_CLAMP +0x12300008: 0x00000000: dword 1 +0x1230000c: 0x61020000: STATE_SIP +0x12300010: 0x00000000: dword 1 +0x12300014: 0x680b0000: 3DSTATE_VF_STATISTICS +0x12300018: 0x61010004: STATE_BASE_ADDRESS +0x1230001c: 0x00000001: general state base address 0x00000000 +0x12300020: 0x00000001: surface state base address 0x00000000 +0x12300024: 0x00000001: indirect state base address 0x00000000 +0x12300028: 0x00000001: general state upper bound disabled +0x1230002c: 0x00000001: indirect state upper bound disabled +0x12300030: 0x78010004: 3DSTATE_BINDING_TABLE_POINTERS +0x12300034: 0x00007e20: VS binding table +0x12300038: 0x00000000: GS binding table +0x1230003c: 0x00000000: Clip binding table +0x12300040: 0x00000000: SF binding table +0x12300044: 0x00007e20: WM binding table +0x12300048: 0x79010003: 3DSTATE_CONSTANT_COLOR +0x1230004c: 0x00000000: dword 1 +0x12300050: 0x00000000: dword 2 +0x12300054: 0x00000000: dword 3 +0x12300058: 0x00000000: dword 4 +0x1230005c: 0x79050004: 3DSTATE_DEPTH_BUFFER +0x12300060: 0x2c0805ff: 2D, z24s8, pitch = 1536 bytes, tiled +0x12300064: 0x00000000: depth offset +0x12300068: 0x09584ac0: 300x300 +0x1230006c: 0x00000000: volume depth +0x12300070: 0x00000000: +0x12300074: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300078: 0x00007d60: VS state +0x1230007c: 0x00000000: GS state +0x12300080: 0x00007d21: Clip state +0x12300084: 0x00007d80: SF state +0x12300088: 0x00007de0: WM state +0x1230008c: 0x00007fc0: CC state +0x12300090: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300094: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300098: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x1230009c: 0x60010000: CS_URB_STATE +0x123000a0: 0x00000024: entry_size: 2 [192 bytes], n_entries: 4 +0x123000a4: 0x79000002: 3DSTATE_DRAWING_RECTANGLE +0x123000a8: 0x00000000: top left: 0,0 +0x123000ac: 0x012b012b: bottom right: 299,299 +0x123000b0: 0x00000000: origin: 0,0 +0x123000b4: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x123000b8: 0x0000000c: buffer 0: sequential, pitch 12b +0x123000bc: 0x00000000: buffer address +0x123000c0: 0x00000000: max index +0x123000c4: 0x00000000: mbz +0x123000c8: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x123000cc: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123000d0: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123000d4: 0x60020100: CONSTANT_BUFFER: valid +0x123000d8: 0x00000001: offset: 0x00000000, length: 128 bytes +0x123000dc: 0x7b001804: 3DPRIMITIVE: tri fan sequential +0x123000e0: 0x00000004: vertex count +0x123000e4: 0x00000000: start vertex +0x123000e8: 0x00000001: instance count +0x123000ec: 0x00000000: start instance +0x123000f0: 0x00000000: index bias +0x123000f4: 0x78010004: 3DSTATE_BINDING_TABLE_POINTERS +0x123000f8: 0x00007b40: VS binding table +0x123000fc: 0x00000000: GS binding table +0x12300100: 0x00000000: Clip binding table +0x12300104: 0x00000000: SF binding table +0x12300108: 0x00007b40: WM binding table +0x1230010c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300110: 0x00007aa0: VS state +0x12300114: 0x00007a41: GS state +0x12300118: 0x00007a61: Clip state +0x1230011c: 0x00007ac0: SF state +0x12300120: 0x00007b00: WM state +0x12300124: 0x00007cc0: CC state +0x12300128: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x1230012c: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300130: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x12300134: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300138: 0x0000000c: buffer 0: sequential, pitch 12b +0x1230013c: 0x00000000: buffer address +0x12300140: 0x00000000: max index +0x12300144: 0x00000000: mbz +0x12300148: 0x60020100: CONSTANT_BUFFER: valid +0x1230014c: 0x00000082: offset: 0x00000080, length: 192 bytes +0x12300150: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300154: 0x00000052: vertex count +0x12300158: 0x00000000: start vertex +0x1230015c: 0x00000001: instance count +0x12300160: 0x00000000: start instance +0x12300164: 0x00000000: index bias +0x12300168: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x1230016c: 0x00007aa0: VS state +0x12300170: 0x00007a21: GS state +0x12300174: 0x00007a61: Clip state +0x12300178: 0x00007ac0: SF state +0x1230017c: 0x00007b00: WM state +0x12300180: 0x00007cc0: CC state +0x12300184: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300188: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x1230018c: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x12300190: 0x60020100: CONSTANT_BUFFER: valid +0x12300194: 0x00000082: offset: 0x00000080, length: 192 bytes +0x12300198: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x1230019c: 0x00000050: vertex count +0x123001a0: 0x00000052: start vertex +0x123001a4: 0x00000001: instance count +0x123001a8: 0x00000000: start instance +0x123001ac: 0x00000000: index bias +0x123001b0: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123001b4: 0x00007aa0: VS state +0x123001b8: 0x00007a01: GS state +0x123001bc: 0x00007a61: Clip state +0x123001c0: 0x00007ac0: SF state +0x123001c4: 0x00007b00: WM state +0x123001c8: 0x00007cc0: CC state +0x123001cc: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123001d0: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x123001d4: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x123001d8: 0x60020100: CONSTANT_BUFFER: valid +0x123001dc: 0x00000142: offset: 0x00000140, length: 192 bytes +0x123001e0: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123001e4: 0x00000052: vertex count +0x123001e8: 0x000000a2: start vertex +0x123001ec: 0x00000001: instance count +0x123001f0: 0x00000000: start instance +0x123001f4: 0x00000000: index bias +0x123001f8: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123001fc: 0x00007aa0: VS state +0x12300200: 0x000079e1: GS state +0x12300204: 0x00007a61: Clip state +0x12300208: 0x00007ac0: SF state +0x1230020c: 0x00007b00: WM state +0x12300210: 0x00007cc0: CC state +0x12300214: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300218: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x1230021c: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x12300220: 0x60020100: CONSTANT_BUFFER: valid +0x12300224: 0x00000142: offset: 0x00000140, length: 192 bytes +0x12300228: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x1230022c: 0x00000050: vertex count +0x12300230: 0x000000f4: start vertex +0x12300234: 0x00000001: instance count +0x12300238: 0x00000000: start instance +0x1230023c: 0x00000000: index bias +0x12300240: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300244: 0x00007aa0: VS state +0x12300248: 0x000079c1: GS state +0x1230024c: 0x00007a61: Clip state +0x12300250: 0x00007ac0: SF state +0x12300254: 0x00007b00: WM state +0x12300258: 0x00007cc0: CC state +0x1230025c: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300260: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300264: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x12300268: 0x60020100: CONSTANT_BUFFER: valid +0x1230026c: 0x00000142: offset: 0x00000140, length: 192 bytes +0x12300270: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300274: 0x000079a0: VS state +0x12300278: 0x000079c1: GS state +0x1230027c: 0x00007a61: Clip state +0x12300280: 0x00007ac0: SF state +0x12300284: 0x00007b00: WM state +0x12300288: 0x00007cc0: CC state +0x1230028c: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300290: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300294: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x12300298: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x1230029c: 0x00000018: buffer 0: sequential, pitch 24b +0x123002a0: 0x00000f48: buffer address +0x123002a4: 0x00000000: max index +0x123002a8: 0x00000000: mbz +0x123002ac: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x123002b0: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123002b4: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123002b8: 0x0440000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x123002bc: 0x11130004: (X, Y, Z, 1.0), dst offset 0x10 bytes +0x123002c0: 0x60020100: CONSTANT_BUFFER: valid +0x123002c4: 0x00000202: offset: 0x00000200, length: 192 bytes +0x123002c8: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123002cc: 0x000000a2: vertex count +0x123002d0: 0x00000000: start vertex +0x123002d4: 0x00000001: instance count +0x123002d8: 0x00000000: start instance +0x123002dc: 0x00000000: index bias +0x123002e0: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123002e4: 0x000079a0: VS state +0x123002e8: 0x00000000: GS state +0x123002ec: 0x00007901: Clip state +0x123002f0: 0x00007940: SF state +0x123002f4: 0x00007960: WM state +0x123002f8: 0x00007cc0: CC state +0x123002fc: 0x00000000: MI_NOOP +0x12300300: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300304: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300308: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x1230030c: 0x60020100: CONSTANT_BUFFER: valid +0x12300310: 0x00000202: offset: 0x00000200, length: 192 bytes +0x12300314: 0x7b001404: 3DPRIMITIVE: tri strip sequential +0x12300318: 0x0000002a: vertex count +0x1230031c: 0x000000a2: start vertex +0x12300320: 0x00000001: instance count +0x12300324: 0x00000000: start instance +0x12300328: 0x00000000: index bias +0x1230032c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300330: 0x00007860: VS state +0x12300334: 0x00007801: GS state +0x12300338: 0x00007821: Clip state +0x1230033c: 0x00007880: SF state +0x12300340: 0x000078a0: WM state +0x12300344: 0x00007cc0: CC state +0x12300348: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x1230034c: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300350: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x12300354: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300358: 0x0000000c: buffer 0: sequential, pitch 12b +0x1230035c: 0x00002268: buffer address +0x12300360: 0x00000000: max index +0x12300364: 0x00000000: mbz +0x12300368: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x1230036c: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x12300370: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300374: 0x60020100: CONSTANT_BUFFER: valid +0x12300378: 0x000002c2: offset: 0x000002c0, length: 192 bytes +0x1230037c: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300380: 0x0000002a: vertex count +0x12300384: 0x00000000: start vertex +0x12300388: 0x00000001: instance count +0x1230038c: 0x00000000: start instance +0x12300390: 0x00000000: index bias +0x12300394: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300398: 0x00007860: VS state +0x1230039c: 0x000077e1: GS state +0x123003a0: 0x00007821: Clip state +0x123003a4: 0x00007880: SF state +0x123003a8: 0x000078a0: WM state +0x123003ac: 0x00007cc0: CC state +0x123003b0: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123003b4: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x123003b8: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x123003bc: 0x60020100: CONSTANT_BUFFER: valid +0x123003c0: 0x000002c2: offset: 0x000002c0, length: 192 bytes +0x123003c4: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x123003c8: 0x00000028: vertex count +0x123003cc: 0x0000002a: start vertex +0x123003d0: 0x00000001: instance count +0x123003d4: 0x00000000: start instance +0x123003d8: 0x00000000: index bias +0x123003dc: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123003e0: 0x00007860: VS state +0x123003e4: 0x000077c1: GS state +0x123003e8: 0x00007821: Clip state +0x123003ec: 0x00007880: SF state +0x123003f0: 0x000078a0: WM state +0x123003f4: 0x00007cc0: CC state +0x123003f8: 0x00000000: MI_NOOP +0x123003fc: 0x00000000: MI_NOOP +0x12300400: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300404: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300408: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x1230040c: 0x60020100: CONSTANT_BUFFER: valid +0x12300410: 0x00000382: offset: 0x00000380, length: 192 bytes +0x12300414: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300418: 0x0000002a: vertex count +0x1230041c: 0x00000052: start vertex +0x12300420: 0x00000001: instance count +0x12300424: 0x00000000: start instance +0x12300428: 0x00000000: index bias +0x1230042c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300430: 0x00007860: VS state +0x12300434: 0x000077a1: GS state +0x12300438: 0x00007821: Clip state +0x1230043c: 0x00007880: SF state +0x12300440: 0x000078a0: WM state +0x12300444: 0x00007cc0: CC state +0x12300448: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x1230044c: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300450: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x12300454: 0x60020100: CONSTANT_BUFFER: valid +0x12300458: 0x00000382: offset: 0x00000380, length: 192 bytes +0x1230045c: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300460: 0x00000028: vertex count +0x12300464: 0x0000007c: start vertex +0x12300468: 0x00000001: instance count +0x1230046c: 0x00000000: start instance +0x12300470: 0x00000000: index bias +0x12300474: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300478: 0x00007860: VS state +0x1230047c: 0x00007781: GS state +0x12300480: 0x00007821: Clip state +0x12300484: 0x00007880: SF state +0x12300488: 0x000078a0: WM state +0x1230048c: 0x00007cc0: CC state +0x12300490: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300494: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300498: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x1230049c: 0x60020100: CONSTANT_BUFFER: valid +0x123004a0: 0x00000382: offset: 0x00000380, length: 192 bytes +0x123004a4: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123004a8: 0x00007760: VS state +0x123004ac: 0x00007781: GS state +0x123004b0: 0x00007821: Clip state +0x123004b4: 0x00007880: SF state +0x123004b8: 0x000078a0: WM state +0x123004bc: 0x00007cc0: CC state +0x123004c0: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123004c4: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x123004c8: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x123004cc: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x123004d0: 0x00000018: buffer 0: sequential, pitch 24b +0x123004d4: 0x00002a30: buffer address +0x123004d8: 0x00000000: max index +0x123004dc: 0x00000000: mbz +0x123004e0: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x123004e4: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123004e8: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123004ec: 0x0440000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x123004f0: 0x11130004: (X, Y, Z, 1.0), dst offset 0x10 bytes +0x123004f4: 0x60020100: CONSTANT_BUFFER: valid +0x123004f8: 0x00000442: offset: 0x00000440, length: 192 bytes +0x123004fc: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300500: 0x00000052: vertex count +0x12300504: 0x00000000: start vertex +0x12300508: 0x00000001: instance count +0x1230050c: 0x00000000: start instance +0x12300510: 0x00000000: index bias +0x12300514: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300518: 0x00007760: VS state +0x1230051c: 0x00000000: GS state +0x12300520: 0x000076c1: Clip state +0x12300524: 0x00007700: SF state +0x12300528: 0x00007720: WM state +0x1230052c: 0x00007cc0: CC state +0x12300530: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300534: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300538: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x1230053c: 0x60020100: CONSTANT_BUFFER: valid +0x12300540: 0x00000442: offset: 0x00000440, length: 192 bytes +0x12300544: 0x7b001404: 3DPRIMITIVE: tri strip sequential +0x12300548: 0x00000016: vertex count +0x1230054c: 0x00000052: start vertex +0x12300550: 0x00000001: instance count +0x12300554: 0x00000000: start instance +0x12300558: 0x00000000: index bias +0x1230055c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300560: 0x00007620: VS state +0x12300564: 0x000075c1: GS state +0x12300568: 0x000075e1: Clip state +0x1230056c: 0x00007640: SF state +0x12300570: 0x00007660: WM state +0x12300574: 0x00007cc0: CC state +0x12300578: 0x00000000: MI_NOOP +0x1230057c: 0x00000000: MI_NOOP +0x12300580: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300584: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300588: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x1230058c: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300590: 0x0000000c: buffer 0: sequential, pitch 12b +0x12300594: 0x000033f0: buffer address +0x12300598: 0x00000000: max index +0x1230059c: 0x00000000: mbz +0x123005a0: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x123005a4: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123005a8: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123005ac: 0x60020100: CONSTANT_BUFFER: valid +0x123005b0: 0x00000502: offset: 0x00000500, length: 192 bytes +0x123005b4: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123005b8: 0x0000002a: vertex count +0x123005bc: 0x00000000: start vertex +0x123005c0: 0x00000001: instance count +0x123005c4: 0x00000000: start instance +0x123005c8: 0x00000000: index bias +0x123005cc: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123005d0: 0x00007620: VS state +0x123005d4: 0x000075a1: GS state +0x123005d8: 0x000075e1: Clip state +0x123005dc: 0x00007640: SF state +0x123005e0: 0x00007660: WM state +0x123005e4: 0x00007cc0: CC state +0x123005e8: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123005ec: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x123005f0: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x123005f4: 0x60020100: CONSTANT_BUFFER: valid +0x123005f8: 0x00000502: offset: 0x00000500, length: 192 bytes +0x123005fc: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300600: 0x00000028: vertex count +0x12300604: 0x0000002a: start vertex +0x12300608: 0x00000001: instance count +0x1230060c: 0x00000000: start instance +0x12300610: 0x00000000: index bias +0x12300614: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300618: 0x00007620: VS state +0x1230061c: 0x00007581: GS state +0x12300620: 0x000075e1: Clip state +0x12300624: 0x00007640: SF state +0x12300628: 0x00007660: WM state +0x1230062c: 0x00007cc0: CC state +0x12300630: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300634: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300638: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x1230063c: 0x60020100: CONSTANT_BUFFER: valid +0x12300640: 0x000005c2: offset: 0x000005c0, length: 192 bytes +0x12300644: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300648: 0x0000002a: vertex count +0x1230064c: 0x00000052: start vertex +0x12300650: 0x00000001: instance count +0x12300654: 0x00000000: start instance +0x12300658: 0x00000000: index bias +0x1230065c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300660: 0x00007620: VS state +0x12300664: 0x00007561: GS state +0x12300668: 0x000075e1: Clip state +0x1230066c: 0x00007640: SF state +0x12300670: 0x00007660: WM state +0x12300674: 0x00007cc0: CC state +0x12300678: 0x00000000: MI_NOOP +0x1230067c: 0x00000000: MI_NOOP +0x12300680: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300684: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300688: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x1230068c: 0x60020100: CONSTANT_BUFFER: valid +0x12300690: 0x000005c2: offset: 0x000005c0, length: 192 bytes +0x12300694: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300698: 0x00000028: vertex count +0x1230069c: 0x0000007c: start vertex +0x123006a0: 0x00000001: instance count +0x123006a4: 0x00000000: start instance +0x123006a8: 0x00000000: index bias +0x123006ac: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123006b0: 0x00007620: VS state +0x123006b4: 0x00007541: GS state +0x123006b8: 0x000075e1: Clip state +0x123006bc: 0x00007640: SF state +0x123006c0: 0x00007660: WM state +0x123006c4: 0x00007cc0: CC state +0x123006c8: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123006cc: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x123006d0: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x123006d4: 0x60020100: CONSTANT_BUFFER: valid +0x123006d8: 0x000005c2: offset: 0x000005c0, length: 192 bytes +0x123006dc: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123006e0: 0x00007520: VS state +0x123006e4: 0x00007541: GS state +0x123006e8: 0x000075e1: Clip state +0x123006ec: 0x00007640: SF state +0x123006f0: 0x00007660: WM state +0x123006f4: 0x00007cc0: CC state +0x123006f8: 0x00000000: MI_NOOP +0x123006fc: 0x00000000: MI_NOOP +0x12300700: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300704: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300708: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x1230070c: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300710: 0x00000018: buffer 0: sequential, pitch 24b +0x12300714: 0x00003bb8: buffer address +0x12300718: 0x00000000: max index +0x1230071c: 0x00000000: mbz +0x12300720: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x12300724: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x12300728: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x1230072c: 0x0440000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x12300730: 0x11130004: (X, Y, Z, 1.0), dst offset 0x10 bytes +0x12300734: 0x60020100: CONSTANT_BUFFER: valid +0x12300738: 0x00000682: offset: 0x00000680, length: 192 bytes +0x1230073c: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300740: 0x00000052: vertex count +0x12300744: 0x00000000: start vertex +0x12300748: 0x00000001: instance count +0x1230074c: 0x00000000: start instance +0x12300750: 0x00000000: index bias +0x12300754: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300758: 0x00007520: VS state +0x1230075c: 0x00000000: GS state +0x12300760: 0x00007481: Clip state +0x12300764: 0x000074c0: SF state +0x12300768: 0x000074e0: WM state +0x1230076c: 0x00007cc0: CC state +0x12300770: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300774: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300778: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x1230077c: 0x60020100: CONSTANT_BUFFER: valid +0x12300780: 0x00000682: offset: 0x00000680, length: 192 bytes +0x12300784: 0x7b001404: 3DPRIMITIVE: tri strip sequential +0x12300788: 0x00000016: vertex count +0x1230078c: 0x00000052: start vertex +0x12300790: 0x00000001: instance count +0x12300794: 0x00000000: start instance +0x12300798: 0x00000000: index bias +0x1230079c: 0x05000000: MI_BATCH_BUFFER_END diff --git a/intel/tests/gm45-3d.batch.sh b/intel/tests/gm45-3d.batch.sh new file mode 120000 index 0000000..796ca5f --- /dev/null +++ b/intel/tests/gm45-3d.batch.sh @@ -0,0 +1 @@ +test-batch.sh \ No newline at end of file diff --git a/intel/tests/test-batch.sh b/intel/tests/test-batch.sh new file mode 100755 index 0000000..b85f639 --- /dev/null +++ b/intel/tests/test-batch.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +TEST_FILENAME=`echo "$0" | sed 's|\.sh$||'` +./test_decode $TEST_FILENAME + +ret=$? + +# pretty-print a diff showing what happened, and leave the dumped +# around for possibly moving over the ref. +if test $ret = 1; then + REF_FILENAME="$TEST_FILENAME-ref.txt" + NEW_FILENAME="$TEST_FILENAME-new.txt" + ./test_decode $TEST_FILENAME -dump > $NEW_FILENAME + if test $? = 0; then + echo "Differences:" + diff -u $REF_FILENAME $NEW_FILENAME + fi +fi + +exit $ret diff --git a/intel/uthash.h b/intel/uthash.h new file mode 100644 index 0000000..45d1f9f --- /dev/null +++ b/intel/uthash.h @@ -0,0 +1,1074 @@ +/* +Copyright (c) 2003-2016, Troy D. Hanson http://troydhanson.github.com/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef UTHASH_H +#define UTHASH_H + +#define UTHASH_VERSION 2.0.1 + +#include /* memcmp,strlen */ +#include /* ptrdiff_t */ +#include /* exit() */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#if defined(_MSC_VER) /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define DECLTYPE(x) (decltype(x)) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#define DECLTYPE(x) +#endif +#elif defined(__BORLANDC__) || defined(__LCC__) || defined(__WATCOMC__) +#define NO_DECLTYPE +#define DECLTYPE(x) +#else /* GNU, Sun and other compilers */ +#define DECLTYPE(x) (__typeof(x)) +#endif + +#ifdef NO_DECLTYPE +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + char **_da_dst = (char**)(&(dst)); \ + *_da_dst = (char*)(src); \ +} while (0) +#else +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + (dst) = DECLTYPE(dst)(src); \ +} while (0) +#endif + +/* a number of the hash function use uint32_t which isn't defined on Pre VS2010 */ +#if defined(_WIN32) +#if defined(_MSC_VER) && _MSC_VER >= 1600 +#include +#elif defined(__WATCOMC__) || defined(__MINGW32__) || defined(__CYGWIN__) +#include +#else +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#endif +#elif defined(__GNUC__) && !defined(__VXWORKS__) +#include +#else +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#endif + +#ifndef uthash_fatal +#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */ +#endif +#ifndef uthash_malloc +#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ +#endif +#ifndef uthash_free +#define uthash_free(ptr,sz) free(ptr) /* free fcn */ +#endif +#ifndef uthash_strlen +#define uthash_strlen(s) strlen(s) +#endif +#ifndef uthash_memcmp +#define uthash_memcmp(a,b,n) memcmp(a,b,n) +#endif + +#ifndef uthash_noexpand_fyi +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#endif +#ifndef uthash_expand_fyi +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ +#endif + +/* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS 32U /* initial number of buckets */ +#define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* lg2 of initial number of buckets */ +#define HASH_BKT_CAPACITY_THRESH 10U /* expand when bucket count reaches */ + +/* calculate the element whose hash handle address is hhp */ +#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) +/* calculate the hash handle from element address elp */ +#define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle *)(((char*)(elp)) + ((tbl)->hho))) + +#define HASH_VALUE(keyptr,keylen,hashv) \ +do { \ + HASH_FCN(keyptr, keylen, hashv); \ +} while (0) + +#define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out) \ +do { \ + (out) = NULL; \ + if (head) { \ + unsigned _hf_bkt; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \ + if (HASH_BLOOM_TEST((head)->hh.tbl, hashval) != 0) { \ + HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \ + } \ + } \ +} while (0) + +#define HASH_FIND(hh,head,keyptr,keylen,out) \ +do { \ + unsigned _hf_hashv; \ + HASH_VALUE(keyptr, keylen, _hf_hashv); \ + HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \ +} while (0) + +#ifdef HASH_BLOOM +#define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM) +#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8UL) + (((HASH_BLOOM_BITLEN%8UL)!=0UL) ? 1UL : 0UL) +#define HASH_BLOOM_MAKE(tbl) \ +do { \ + (tbl)->bloom_nbits = HASH_BLOOM; \ + (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ + if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ + memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ + (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ +} while (0) + +#define HASH_BLOOM_FREE(tbl) \ +do { \ + uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ +} while (0) + +#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8U] |= (1U << ((idx)%8U))) +#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8U] & (1U << ((idx)%8U))) + +#define HASH_BLOOM_ADD(tbl,hashv) \ + HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1U))) + +#define HASH_BLOOM_TEST(tbl,hashv) \ + HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1U))) + +#else +#define HASH_BLOOM_MAKE(tbl) +#define HASH_BLOOM_FREE(tbl) +#define HASH_BLOOM_ADD(tbl,hashv) +#define HASH_BLOOM_TEST(tbl,hashv) (1) +#define HASH_BLOOM_BYTELEN 0U +#endif + +#define HASH_MAKE_TABLE(hh,head) \ +do { \ + (head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ + sizeof(UT_hash_table)); \ + if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ + (head)->hh.tbl->tail = &((head)->hh); \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ + (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ + (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \ + memset((head)->hh.tbl->buckets, 0, \ + HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_MAKE((head)->hh.tbl); \ + (head)->hh.tbl->signature = HASH_SIGNATURE; \ +} while (0) + +#define HASH_REPLACE_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,replaced,cmpfcn) \ +do { \ + (replaced) = NULL; \ + HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ + if (replaced) { \ + HASH_DELETE(hh, head, replaced); \ + } \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn); \ +} while (0) + +#define HASH_REPLACE_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add,replaced) \ +do { \ + (replaced) = NULL; \ + HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ + if (replaced) { \ + HASH_DELETE(hh, head, replaced); \ + } \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add); \ +} while (0) + +#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ +do { \ + unsigned _hr_hashv; \ + HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ + HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced); \ +} while (0) + +#define HASH_REPLACE_INORDER(hh,head,fieldname,keylen_in,add,replaced,cmpfcn) \ +do { \ + unsigned _hr_hashv; \ + HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ + HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced, cmpfcn); \ +} while (0) + +#define HASH_APPEND_LIST(hh, head, add) \ +do { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ + (head)->hh.tbl->tail->next = (add); \ + (head)->hh.tbl->tail = &((add)->hh); \ +} while (0) + +#define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh,head,keyptr,keylen_in,hashval,add,cmpfcn) \ +do { \ + unsigned _ha_bkt; \ + (add)->hh.hashv = (hashval); \ + (add)->hh.key = (char*) (keyptr); \ + (add)->hh.keylen = (unsigned) (keylen_in); \ + if (!(head)) { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = NULL; \ + (head) = (add); \ + HASH_MAKE_TABLE(hh, head); \ + } else { \ + struct UT_hash_handle *_hs_iter = &(head)->hh; \ + (add)->hh.tbl = (head)->hh.tbl; \ + do { \ + if (cmpfcn(DECLTYPE(head) ELMT_FROM_HH((head)->hh.tbl, _hs_iter), add) > 0) \ + break; \ + } while ((_hs_iter = _hs_iter->next)); \ + if (_hs_iter) { \ + (add)->hh.next = _hs_iter; \ + if (((add)->hh.prev = _hs_iter->prev)) { \ + HH_FROM_ELMT((head)->hh.tbl, _hs_iter->prev)->next = (add); \ + } else { \ + (head) = (add); \ + } \ + _hs_iter->prev = (add); \ + } else { \ + HASH_APPEND_LIST(hh, head, add); \ + } \ + } \ + (head)->hh.tbl->num_items++; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], &(add)->hh); \ + HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ + HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ + HASH_FSCK(hh, head); \ +} while (0) + +#define HASH_ADD_KEYPTR_INORDER(hh,head,keyptr,keylen_in,add,cmpfcn) \ +do { \ + unsigned _hs_hashv; \ + HASH_VALUE(keyptr, keylen_in, _hs_hashv); \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, _hs_hashv, add, cmpfcn); \ +} while (0) + +#define HASH_ADD_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,cmpfcn) \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn) + +#define HASH_ADD_INORDER(hh,head,fieldname,keylen_in,add,cmpfcn) \ + HASH_ADD_KEYPTR_INORDER(hh, head, &((add)->fieldname), keylen_in, add, cmpfcn) + +#define HASH_ADD_KEYPTR_BYHASHVALUE(hh,head,keyptr,keylen_in,hashval,add) \ +do { \ + unsigned _ha_bkt; \ + (add)->hh.hashv = (hashval); \ + (add)->hh.key = (char*) (keyptr); \ + (add)->hh.keylen = (unsigned) (keylen_in); \ + if (!(head)) { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = NULL; \ + (head) = (add); \ + HASH_MAKE_TABLE(hh, head); \ + } else { \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_APPEND_LIST(hh, head, add); \ + } \ + (head)->hh.tbl->num_items++; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ + HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], &(add)->hh); \ + HASH_BLOOM_ADD((head)->hh.tbl, hashval); \ + HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \ + HASH_FSCK(hh, head); \ +} while (0) + +#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ +do { \ + unsigned _ha_hashv; \ + HASH_VALUE(keyptr, keylen_in, _ha_hashv); \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add); \ +} while (0) + +#define HASH_ADD_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add) \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add) + +#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ + HASH_ADD_KEYPTR(hh, head, &((add)->fieldname), keylen_in, add) + +#define HASH_TO_BKT(hashv,num_bkts,bkt) \ +do { \ + bkt = ((hashv) & ((num_bkts) - 1U)); \ +} while (0) + +/* delete "delptr" from the hash table. + * "the usual" patch-up process for the app-order doubly-linked-list. + * The use of _hd_hh_del below deserves special explanation. + * These used to be expressed using (delptr) but that led to a bug + * if someone used the same symbol for the head and deletee, like + * HASH_DELETE(hh,users,users); + * We want that to work, but by changing the head (users) below + * we were forfeiting our ability to further refer to the deletee (users) + * in the patch-up process. Solution: use scratch space to + * copy the deletee pointer, then the latter references are via that + * scratch pointer rather than through the repointed (users) symbol. + */ +#define HASH_DELETE(hh,head,delptr) \ +do { \ + struct UT_hash_handle *_hd_hh_del; \ + if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + head = NULL; \ + } else { \ + unsigned _hd_bkt; \ + _hd_hh_del = &((delptr)->hh); \ + if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ + (head)->hh.tbl->tail = \ + (UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho); \ + } \ + if ((delptr)->hh.prev != NULL) { \ + ((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ + (head)->hh.tbl->hho))->next = (delptr)->hh.next; \ + } else { \ + DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ + } \ + if (_hd_hh_del->next != NULL) { \ + ((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next + \ + (head)->hh.tbl->hho))->prev = \ + _hd_hh_del->prev; \ + } \ + HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ + (head)->hh.tbl->num_items--; \ + } \ + HASH_FSCK(hh,head); \ +} while (0) + + +/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ +#define HASH_FIND_STR(head,findstr,out) \ + HASH_FIND(hh,head,findstr,(unsigned)uthash_strlen(findstr),out) +#define HASH_ADD_STR(head,strfield,add) \ + HASH_ADD(hh,head,strfield[0],(unsigned)uthash_strlen(add->strfield),add) +#define HASH_REPLACE_STR(head,strfield,add,replaced) \ + HASH_REPLACE(hh,head,strfield[0],(unsigned)uthash_strlen(add->strfield),add,replaced) +#define HASH_FIND_INT(head,findint,out) \ + HASH_FIND(hh,head,findint,sizeof(int),out) +#define HASH_ADD_INT(head,intfield,add) \ + HASH_ADD(hh,head,intfield,sizeof(int),add) +#define HASH_REPLACE_INT(head,intfield,add,replaced) \ + HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) +#define HASH_FIND_PTR(head,findptr,out) \ + HASH_FIND(hh,head,findptr,sizeof(void *),out) +#define HASH_ADD_PTR(head,ptrfield,add) \ + HASH_ADD(hh,head,ptrfield,sizeof(void *),add) +#define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \ + HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) +#define HASH_DEL(head,delptr) \ + HASH_DELETE(hh,head,delptr) + +/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. + * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. + */ +#ifdef HASH_DEBUG +#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) +#define HASH_FSCK(hh,head) \ +do { \ + struct UT_hash_handle *_thh; \ + if (head) { \ + unsigned _bkt_i; \ + unsigned _count; \ + char *_prev; \ + _count = 0; \ + for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \ + unsigned _bkt_count = 0; \ + _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ + _prev = NULL; \ + while (_thh) { \ + if (_prev != (char*)(_thh->hh_prev)) { \ + HASH_OOPS("invalid hh_prev %p, actual %p\n", \ + _thh->hh_prev, _prev ); \ + } \ + _bkt_count++; \ + _prev = (char*)(_thh); \ + _thh = _thh->hh_next; \ + } \ + _count += _bkt_count; \ + if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ + HASH_OOPS("invalid bucket count %u, actual %u\n", \ + (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ + } \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid hh item count %u, actual %u\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + /* traverse hh in app order; check next/prev integrity, count */ \ + _count = 0; \ + _prev = NULL; \ + _thh = &(head)->hh; \ + while (_thh) { \ + _count++; \ + if (_prev !=(char*)(_thh->prev)) { \ + HASH_OOPS("invalid prev %p, actual %p\n", \ + _thh->prev, _prev ); \ + } \ + _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ + _thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ + (head)->hh.tbl->hho) : NULL ); \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("invalid app item count %u, actual %u\n", \ + (head)->hh.tbl->num_items, _count ); \ + } \ + } \ +} while (0) +#else +#define HASH_FSCK(hh,head) +#endif + +/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to + * the descriptor to which this macro is defined for tuning the hash function. + * The app can #include to get the prototype for write(2). */ +#ifdef HASH_EMIT_KEYS +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ +do { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \ +} while (0) +#else +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#endif + +/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ +#ifdef HASH_FUNCTION +#define HASH_FCN HASH_FUNCTION +#else +#define HASH_FCN HASH_JEN +#endif + +/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ +#define HASH_BER(key,keylen,hashv) \ +do { \ + unsigned _hb_keylen=(unsigned)keylen; \ + const unsigned char *_hb_key=(const unsigned char*)(key); \ + (hashv) = 0; \ + while (_hb_keylen-- != 0U) { \ + (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \ + } \ +} while (0) + + +/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ +#define HASH_SAX(key,keylen,hashv) \ +do { \ + unsigned _sx_i; \ + const unsigned char *_hs_key=(const unsigned char*)(key); \ + hashv = 0; \ + for(_sx_i=0; _sx_i < keylen; _sx_i++) { \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + } \ +} while (0) +/* FNV-1a variation */ +#define HASH_FNV(key,keylen,hashv) \ +do { \ + unsigned _fn_i; \ + const unsigned char *_hf_key=(const unsigned char*)(key); \ + hashv = 2166136261U; \ + for(_fn_i=0; _fn_i < keylen; _fn_i++) { \ + hashv = hashv ^ _hf_key[_fn_i]; \ + hashv = hashv * 16777619U; \ + } \ +} while (0) + +#define HASH_OAT(key,keylen,hashv) \ +do { \ + unsigned _ho_i; \ + const unsigned char *_ho_key=(const unsigned char*)(key); \ + hashv = 0; \ + for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ +} while (0) + +#define HASH_JEN_MIX(a,b,c) \ +do { \ + a -= b; a -= c; a ^= ( c >> 13 ); \ + b -= c; b -= a; b ^= ( a << 8 ); \ + c -= a; c -= b; c ^= ( b >> 13 ); \ + a -= b; a -= c; a ^= ( c >> 12 ); \ + b -= c; b -= a; b ^= ( a << 16 ); \ + c -= a; c -= b; c ^= ( b >> 5 ); \ + a -= b; a -= c; a ^= ( c >> 3 ); \ + b -= c; b -= a; b ^= ( a << 10 ); \ + c -= a; c -= b; c ^= ( b >> 15 ); \ +} while (0) + +#define HASH_JEN(key,keylen,hashv) \ +do { \ + unsigned _hj_i,_hj_j,_hj_k; \ + unsigned const char *_hj_key=(unsigned const char*)(key); \ + hashv = 0xfeedbeefu; \ + _hj_i = _hj_j = 0x9e3779b9u; \ + _hj_k = (unsigned)(keylen); \ + while (_hj_k >= 12U) { \ + _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + + ( (unsigned)_hj_key[2] << 16 ) \ + + ( (unsigned)_hj_key[3] << 24 ) ); \ + _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + + ( (unsigned)_hj_key[6] << 16 ) \ + + ( (unsigned)_hj_key[7] << 24 ) ); \ + hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + + ( (unsigned)_hj_key[10] << 16 ) \ + + ( (unsigned)_hj_key[11] << 24 ) ); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12U; \ + } \ + hashv += (unsigned)(keylen); \ + switch ( _hj_k ) { \ + case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); /* FALLTHROUGH */ \ + case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); /* FALLTHROUGH */ \ + case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); /* FALLTHROUGH */ \ + case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); /* FALLTHROUGH */ \ + case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); /* FALLTHROUGH */ \ + case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); /* FALLTHROUGH */ \ + case 5: _hj_j += _hj_key[4]; /* FALLTHROUGH */ \ + case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); /* FALLTHROUGH */ \ + case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); /* FALLTHROUGH */ \ + case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); /* FALLTHROUGH */ \ + case 1: _hj_i += _hj_key[0]; \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ +} while (0) + +/* The Paul Hsieh hash function */ +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif +#define HASH_SFH(key,keylen,hashv) \ +do { \ + unsigned const char *_sfh_key=(unsigned const char*)(key); \ + uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \ + \ + unsigned _sfh_rem = _sfh_len & 3U; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabeu; \ + \ + /* Main loop */ \ + for (;_sfh_len > 0U; _sfh_len--) { \ + hashv += get16bits (_sfh_key); \ + _sfh_tmp = ((uint32_t)(get16bits (_sfh_key+2)) << 11) ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2U*sizeof (uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) { \ + case 3: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)]) << 18; \ + hashv += hashv >> 11; \ + break; \ + case 2: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ +} while (0) + +#ifdef HASH_USING_NO_STRICT_ALIASING +/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. + * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. + * MurmurHash uses the faster approach only on CPU's where we know it's safe. + * + * Note the preprocessor built-in defines can be emitted using: + * + * gcc -m64 -dM -E - < /dev/null (on gcc) + * cc -## a.c (where a.c is a simple test file) (Sun Studio) + */ +#if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86)) +#define MUR_GETBLOCK(p,i) p[i] +#else /* non intel */ +#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 3UL) == 0UL) +#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 3UL) == 1UL) +#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 3UL) == 2UL) +#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 3UL) == 3UL) +#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) +#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) +#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) +#else /* assume little endian non-intel */ +#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) +#endif +#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ + (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ + (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ + MUR_ONE_THREE(p)))) +#endif +#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +#define MUR_FMIX(_h) \ +do { \ + _h ^= _h >> 16; \ + _h *= 0x85ebca6bu; \ + _h ^= _h >> 13; \ + _h *= 0xc2b2ae35u; \ + _h ^= _h >> 16; \ +} while (0) + +#define HASH_MUR(key,keylen,hashv) \ +do { \ + const uint8_t *_mur_data = (const uint8_t*)(key); \ + const int _mur_nblocks = (int)(keylen) / 4; \ + uint32_t _mur_h1 = 0xf88D5353u; \ + uint32_t _mur_c1 = 0xcc9e2d51u; \ + uint32_t _mur_c2 = 0x1b873593u; \ + uint32_t _mur_k1 = 0; \ + const uint8_t *_mur_tail; \ + const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+(_mur_nblocks*4)); \ + int _mur_i; \ + for(_mur_i = -_mur_nblocks; _mur_i!=0; _mur_i++) { \ + _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + \ + _mur_h1 ^= _mur_k1; \ + _mur_h1 = MUR_ROTL32(_mur_h1,13); \ + _mur_h1 = (_mur_h1*5U) + 0xe6546b64u; \ + } \ + _mur_tail = (const uint8_t*)(_mur_data + (_mur_nblocks*4)); \ + _mur_k1=0; \ + switch((keylen) & 3U) { \ + case 3: _mur_k1 ^= (uint32_t)_mur_tail[2] << 16; /* FALLTHROUGH */ \ + case 2: _mur_k1 ^= (uint32_t)_mur_tail[1] << 8; /* FALLTHROUGH */ \ + case 1: _mur_k1 ^= (uint32_t)_mur_tail[0]; \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + _mur_h1 ^= _mur_k1; \ + } \ + _mur_h1 ^= (uint32_t)(keylen); \ + MUR_FMIX(_mur_h1); \ + hashv = _mur_h1; \ +} while (0) +#endif /* HASH_USING_NO_STRICT_ALIASING */ + +/* iterate over items in a known bucket to find desired item */ +#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out) \ +do { \ + if ((head).hh_head != NULL) { \ + DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head)); \ + } else { \ + (out) = NULL; \ + } \ + while ((out) != NULL) { \ + if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \ + if (uthash_memcmp((out)->hh.key, keyptr, keylen_in) == 0) { \ + break; \ + } \ + } \ + if ((out)->hh.hh_next != NULL) { \ + DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \ + } else { \ + (out) = NULL; \ + } \ + } \ +} while (0) + +/* add an item to a bucket */ +#define HASH_ADD_TO_BKT(head,addhh) \ +do { \ + head.count++; \ + (addhh)->hh_next = head.hh_head; \ + (addhh)->hh_prev = NULL; \ + if (head.hh_head != NULL) { (head).hh_head->hh_prev = (addhh); } \ + (head).hh_head=addhh; \ + if ((head.count >= ((head.expand_mult+1U) * HASH_BKT_CAPACITY_THRESH)) \ + && ((addhh)->tbl->noexpand != 1U)) { \ + HASH_EXPAND_BUCKETS((addhh)->tbl); \ + } \ +} while (0) + +/* remove an item from a given bucket */ +#define HASH_DEL_IN_BKT(hh,head,hh_del) \ + (head).count--; \ + if ((head).hh_head == hh_del) { \ + (head).hh_head = hh_del->hh_next; \ + } \ + if (hh_del->hh_prev) { \ + hh_del->hh_prev->hh_next = hh_del->hh_next; \ + } \ + if (hh_del->hh_next) { \ + hh_del->hh_next->hh_prev = hh_del->hh_prev; \ + } + +/* Bucket expansion has the effect of doubling the number of buckets + * and redistributing the items into the new buckets. Ideally the + * items will distribute more or less evenly into the new buckets + * (the extent to which this is true is a measure of the quality of + * the hash function as it applies to the key domain). + * + * With the items distributed into more buckets, the chain length + * (item count) in each bucket is reduced. Thus by expanding buckets + * the hash keeps a bound on the chain length. This bounded chain + * length is the essence of how a hash provides constant time lookup. + * + * The calculation of tbl->ideal_chain_maxlen below deserves some + * explanation. First, keep in mind that we're calculating the ideal + * maximum chain length based on the *new* (doubled) bucket count. + * In fractions this is just n/b (n=number of items,b=new num buckets). + * Since the ideal chain length is an integer, we want to calculate + * ceil(n/b). We don't depend on floating point arithmetic in this + * hash, so to calculate ceil(n/b) with integers we could write + * + * ceil(n/b) = (n/b) + ((n%b)?1:0) + * + * and in fact a previous version of this hash did just that. + * But now we have improved things a bit by recognizing that b is + * always a power of two. We keep its base 2 log handy (call it lb), + * so now we can write this with a bit shift and logical AND: + * + * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) + * + */ +#define HASH_EXPAND_BUCKETS(tbl) \ +do { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ + 2UL * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ + memset(_he_new_buckets, 0, \ + 2UL * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ + tbl->ideal_chain_maxlen = \ + (tbl->num_items >> (tbl->log2_num_buckets+1U)) + \ + (((tbl->num_items & ((tbl->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \ + tbl->nonideal_items = 0; \ + for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ + { \ + _he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ + while (_he_thh != NULL) { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2U, _he_bkt); \ + _he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ + if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ + tbl->nonideal_items++; \ + _he_newbkt->expand_mult = _he_newbkt->count / \ + tbl->ideal_chain_maxlen; \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head != NULL) { _he_newbkt->hh_head->hh_prev = \ + _he_thh; } \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ + tbl->num_buckets *= 2U; \ + tbl->log2_num_buckets++; \ + tbl->buckets = _he_new_buckets; \ + tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ + (tbl->ineff_expands+1U) : 0U; \ + if (tbl->ineff_expands > 1U) { \ + tbl->noexpand=1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ +} while (0) + + +/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ +/* Note that HASH_SORT assumes the hash handle name to be hh. + * HASH_SRT was added to allow the hash handle name to be passed in. */ +#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) +#define HASH_SRT(hh,head,cmpfcn) \ +do { \ + unsigned _hs_i; \ + unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head != NULL) { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping != 0U) { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p != NULL) { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ + _hs_psize++; \ + _hs_q = (UT_hash_handle*)((_hs_q->next != NULL) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + if (! (_hs_q) ) { break; } \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize > 0U) || ((_hs_qsize > 0U) && (_hs_q != NULL))) {\ + if (_hs_psize == 0U) { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next != NULL) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } else if ( (_hs_qsize == 0U) || (_hs_q == NULL) ) { \ + _hs_e = _hs_p; \ + if (_hs_p != NULL){ \ + _hs_p = (UT_hash_handle*)((_hs_p->next != NULL) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + } \ + _hs_psize--; \ + } else if (( \ + cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ + ) <= 0) { \ + _hs_e = _hs_p; \ + if (_hs_p != NULL){ \ + _hs_p = (UT_hash_handle*)((_hs_p->next != NULL) ? \ + ((void*)((char*)(_hs_p->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + } \ + _hs_psize--; \ + } else { \ + _hs_e = _hs_q; \ + _hs_q = (UT_hash_handle*)((_hs_q->next != NULL) ? \ + ((void*)((char*)(_hs_q->next) + \ + (head)->hh.tbl->hho)) : NULL); \ + _hs_qsize--; \ + } \ + if ( _hs_tail != NULL ) { \ + _hs_tail->next = ((_hs_e != NULL) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ + } else { \ + _hs_list = _hs_e; \ + } \ + if (_hs_e != NULL) { \ + _hs_e->prev = ((_hs_tail != NULL) ? \ + ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ + } \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + if (_hs_tail != NULL){ \ + _hs_tail->next = NULL; \ + } \ + if ( _hs_nmerges <= 1U ) { \ + _hs_looping=0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2U; \ + } \ + HASH_FSCK(hh,head); \ + } \ +} while (0) + +/* This function selects items from one hash into another hash. + * The end result is that the selected items have dual presence + * in both hashes. There is no copy of the items made; rather + * they are added into the new hash through a secondary hash + * hash handle that must be present in the structure. */ +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ +do { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt=NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ + ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ + if (src != NULL) { \ + for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ + for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ + _src_hh != NULL; \ + _src_hh = _src_hh->hh_next) { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) { \ + _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh != NULL) { _last_elt_hh->next = _elt; } \ + if (dst == NULL) { \ + DECLTYPE_ASSIGN(dst,_elt); \ + HASH_MAKE_TABLE(hh_dst,dst); \ + } else { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ + (dst)->hh_dst.tbl->num_items++; \ + _last_elt = _elt; \ + _last_elt_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst,dst); \ +} while (0) + +#define HASH_CLEAR(hh,head) \ +do { \ + if (head != NULL) { \ + uthash_free((head)->hh.tbl->buckets, \ + (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ + HASH_BLOOM_FREE((head)->hh.tbl); \ + uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head)=NULL; \ + } \ +} while (0) + +#define HASH_OVERHEAD(hh,head) \ + ((head != NULL) ? ( \ + (size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ + ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ + sizeof(UT_hash_table) + \ + (HASH_BLOOM_BYTELEN))) : 0U) + +#ifdef NO_DECLTYPE +#define HASH_ITER(hh,head,el,tmp) \ +for(((el)=(head)), ((*(char**)(&(tmp)))=(char*)((head!=NULL)?(head)->hh.next:NULL)); \ + (el) != NULL; ((el)=(tmp)), ((*(char**)(&(tmp)))=(char*)((tmp!=NULL)?(tmp)->hh.next:NULL))) +#else +#define HASH_ITER(hh,head,el,tmp) \ +for(((el)=(head)), ((tmp)=DECLTYPE(el)((head!=NULL)?(head)->hh.next:NULL)); \ + (el) != NULL; ((el)=(tmp)), ((tmp)=DECLTYPE(el)((tmp!=NULL)?(tmp)->hh.next:NULL))) +#endif + +/* obtain a count of items in the hash */ +#define HASH_COUNT(head) HASH_CNT(hh,head) +#define HASH_CNT(hh,head) ((head != NULL)?((head)->hh.tbl->num_items):0U) + +typedef struct UT_hash_bucket { + struct UT_hash_handle *hh_head; + unsigned count; + + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; + +} UT_hash_bucket; + +/* random signature used only to find hash tables in external analysis */ +#define HASH_SIGNATURE 0xa0111fe1u +#define HASH_BLOOM_SIGNATURE 0xb12220f2u + +typedef struct UT_hash_table { + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ + + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; + + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; + + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; + + uint32_t signature; /* used only to find hash tables in external analysis */ +#ifdef HASH_BLOOM + uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + uint8_t bloom_nbits; +#endif + +} UT_hash_table; + +typedef struct UT_hash_handle { + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ +} UT_hash_handle; + +#endif /* UTHASH_H */ diff --git a/libdrm.pc.in b/libdrm.pc.in new file mode 100644 index 0000000..b46e2a6 --- /dev/null +++ b/libdrm.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libdrm +Description: Userspace interface to kernel DRM services +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -ldrm +Cflags: -I${includedir} -I${includedir}/libdrm diff --git a/libdrm_lists.h b/libdrm_lists.h new file mode 100644 index 0000000..7f55fc0 --- /dev/null +++ b/libdrm_lists.h @@ -0,0 +1,118 @@ +/************************************************************************** + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA. + * 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 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 + * THE COPYRIGHT HOLDERS, AUTHORS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ + +/* + * List macros heavily inspired by the Linux kernel + * list handling. No list looping yet. + */ + +#include + +typedef struct _drmMMListHead +{ + struct _drmMMListHead *prev; + struct _drmMMListHead *next; +} drmMMListHead; + +#define DRMINITLISTHEAD(__item) \ + do{ \ + (__item)->prev = (__item); \ + (__item)->next = (__item); \ + } while (0) + +#define DRMLISTADD(__item, __list) \ + do { \ + (__item)->prev = (__list); \ + (__item)->next = (__list)->next; \ + (__list)->next->prev = (__item); \ + (__list)->next = (__item); \ + } while (0) + +#define DRMLISTADDTAIL(__item, __list) \ + do { \ + (__item)->next = (__list); \ + (__item)->prev = (__list)->prev; \ + (__list)->prev->next = (__item); \ + (__list)->prev = (__item); \ + } while(0) + +#define DRMLISTDEL(__item) \ + do { \ + (__item)->prev->next = (__item)->next; \ + (__item)->next->prev = (__item)->prev; \ + } while(0) + +#define DRMLISTDELINIT(__item) \ + do { \ + (__item)->prev->next = (__item)->next; \ + (__item)->next->prev = (__item)->prev; \ + (__item)->next = (__item); \ + (__item)->prev = (__item); \ + } while(0) + +#define DRMLISTENTRY(__type, __item, __field) \ + ((__type *)(((char *) (__item)) - offsetof(__type, __field))) + +#define DRMLISTEMPTY(__item) ((__item)->next == (__item)) + +#define DRMLISTSINGLE(__list) \ + (!DRMLISTEMPTY(__list) && ((__list)->next == (__list)->prev)) + +#define DRMLISTFOREACH(__item, __list) \ + for ((__item) = (__list)->next; \ + (__item) != (__list); (__item) = (__item)->next) + +#define DRMLISTFOREACHSAFE(__item, __temp, __list) \ + for ((__item) = (__list)->next, (__temp) = (__item)->next; \ + (__item) != (__list); \ + (__item) = (__temp), (__temp) = (__item)->next) + +#define DRMLISTFOREACHSAFEREVERSE(__item, __temp, __list) \ + for ((__item) = (__list)->prev, (__temp) = (__item)->prev; \ + (__item) != (__list); \ + (__item) = (__temp), (__temp) = (__item)->prev) + +#define DRMLISTFOREACHENTRY(__item, __list, __head) \ + for ((__item) = DRMLISTENTRY(__typeof__(*__item), (__list)->next, __head); \ + &(__item)->__head != (__list); \ + (__item) = DRMLISTENTRY(__typeof__(*__item), \ + (__item)->__head.next, __head)) + +#define DRMLISTFOREACHENTRYSAFE(__item, __temp, __list, __head) \ + for ((__item) = DRMLISTENTRY(__typeof__(*__item), (__list)->next, __head), \ + (__temp) = DRMLISTENTRY(__typeof__(*__item), \ + (__item)->__head.next, __head); \ + &(__item)->__head != (__list); \ + (__item) = (__temp), \ + (__temp) = DRMLISTENTRY(__typeof__(*__item), \ + (__temp)->__head.next, __head)) + +#define DRMLISTJOIN(__list, __join) if (!DRMLISTEMPTY(__list)) { \ + (__list)->next->prev = (__join); \ + (__list)->prev->next = (__join)->next; \ + (__join)->next->prev = (__list)->prev; \ + (__join)->next = (__list)->next; \ +} diff --git a/libdrm_macros.h b/libdrm_macros.h new file mode 100644 index 0000000..0dca827 --- /dev/null +++ b/libdrm_macros.h @@ -0,0 +1,87 @@ +/* + * Copyright © 2014 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 LIBDRM_LIBDRM_H +#define LIBDRM_LIBDRM_H + +#if HAVE_VISIBILITY +# define drm_private __attribute__((visibility("hidden"))) +# define drm_public __attribute__((visibility("default"))) +#else +# define drm_private +# define drm_public +#endif + + +/** + * Static (compile-time) assertion. + * Basically, use COND to dimension an array. If COND is false/zero the + * array size will be -1 and we'll get a compilation error. + */ +#define STATIC_ASSERT(COND) \ + do { \ + (void) sizeof(char [1 - 2*!(COND)]); \ + } while (0) + + +#include + +#if defined(ANDROID) && !defined(__LP64__) +#include /* for EINVAL */ + +static inline void *drm_mmap(void *addr, size_t length, int prot, int flags, + int fd, loff_t offset) +{ + /* offset must be aligned to 4096 (not necessarily the page size) */ + if (offset & 4095) { + errno = EINVAL; + return MAP_FAILED; + } + + return mmap64(addr, length, prot, flags, fd, offset); +} + +# define drm_munmap(addr, length) \ + munmap(addr, length) + + +#else + +/* assume large file support exists */ +# define drm_mmap(addr, length, prot, flags, fd, offset) \ + mmap(addr, length, prot, flags, fd, offset) + + +static inline int drm_munmap(void *addr, size_t length) +{ + /* Copied from configure code generated by AC_SYS_LARGEFILE */ +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + \ + (((off_t) 1 << 31) << 31)) + STATIC_ASSERT(LARGE_OFF_T % 2147483629 == 721 && + LARGE_OFF_T % 2147483647 == 1); +#undef LARGE_OFF_T + + return munmap(addr, length); +} +#endif + +#endif diff --git a/libsync.h b/libsync.h new file mode 100644 index 0000000..f1a2f96 --- /dev/null +++ b/libsync.h @@ -0,0 +1,148 @@ +/* + * sync abstraction + * Copyright 2015-2016 Collabora Ltd. + * + * Based on the implementation from the Android Open Source Project, + * + * Copyright 2012 Google, Inc + * + * 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. + */ + +#ifndef _LIBSYNC_H +#define _LIBSYNC_H + +#include +#include +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +#ifndef SYNC_IOC_MERGE +/* duplicated from linux/sync_file.h to avoid build-time dependency + * on new (v4.7) kernel headers. Once distro's are mostly using + * something newer than v4.7 drop this and #include + * instead. + */ +struct sync_merge_data { + char name[32]; + int32_t fd2; + int32_t fence; + uint32_t flags; + uint32_t pad; +}; +#define SYNC_IOC_MAGIC '>' +#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data) +#endif + + +static inline int sync_wait(int fd, int timeout) +{ + struct pollfd fds = {0}; + int ret; + + fds.fd = fd; + fds.events = POLLIN; + + do { + ret = poll(&fds, 1, timeout); + if (ret > 0) { + if (fds.revents & (POLLERR | POLLNVAL)) { + errno = EINVAL; + return -1; + } + return 0; + } else if (ret == 0) { + errno = ETIME; + return -1; + } + } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); + + return ret; +} + +static inline int sync_merge(const char *name, int fd1, int fd2) +{ + struct sync_merge_data data = {0}; + int ret; + + data.fd2 = fd2; + strncpy(data.name, name, sizeof(data.name)); + + do { + ret = ioctl(fd1, SYNC_IOC_MERGE, &data); + } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); + + if (ret < 0) + return ret; + + return data.fence; +} + +/* accumulate fd2 into fd1. If *fd1 is not a valid fd then dup fd2, + * otherwise sync_merge() and close the old *fd1. This can be used + * to implement the pattern: + * + * init() + * { + * batch.fence_fd = -1; + * } + * + * // does *NOT* take ownership of fd + * server_sync(int fd) + * { + * if (sync_accumulate("foo", &batch.fence_fd, fd)) { + * ... error ... + * } + * } + */ +static inline int sync_accumulate(const char *name, int *fd1, int fd2) +{ + int ret; + + assert(fd2 >= 0); + + if (*fd1 < 0) { + *fd1 = dup(fd2); + return 0; + } + + ret = sync_merge(name, *fd1, fd2); + if (ret < 0) { + /* leave *fd1 as it is */ + return ret; + } + + close(*fd1); + *fd1 = ret; + + return 0; +} + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/man/drm-kms.7.rst b/man/drm-kms.7.rst new file mode 100644 index 0000000..587d7eb --- /dev/null +++ b/man/drm-kms.7.rst @@ -0,0 +1,229 @@ +======= +drm-kms +======= + +------------------- +Kernel Mode-Setting +------------------- + +:Date: September 2012 +:Manual section: 7 +:Manual group: Direct Rendering Manager + +Synopsis +======== + +``#include `` + +``#include `` + +Description +=========== + +Each DRM device provides access to manage which monitors and displays are +currently used and what frames to be displayed. This task is called *Kernel +Mode-Setting* (KMS). Historically, this was done in user-space and called +*User-space Mode-Setting* (UMS). Almost all open-source drivers now provide the +KMS kernel API to do this in the kernel, however, many non-open-source binary +drivers from different vendors still do not support this. You can use +**drmModeSettingSupported**\ (3) to check whether your driver supports this. To +understand how KMS works, we need to introduce 5 objects: *CRTCs*, *Planes*, +*Encoders*, *Connectors* and *Framebuffers*. + +CRTCs + A *CRTC* short for *CRT Controller* is an abstraction representing a part of + the chip that contains a pointer to a scanout buffer. Therefore, the number + of CRTCs available determines how many independent scanout buffers can be + active at any given time. The CRTC structure contains several fields to + support this: a pointer to some video memory (abstracted as a frame-buffer + object), a list of driven connectors, a display mode and an (x, y) offset + into the video memory to support panning or configurations where one piece + of video memory spans multiple CRTCs. A CRTC is the central point where + configuration of displays happens. You select which objects to use, which + modes and which parameters and then configure each CRTC via + **drmModeCrtcSet**\ (3) to drive the display devices. + +Planes + A *plane* respresents an image source that can be blended with or overlayed + on top of a CRTC during the scanout process. Planes are associated with a + frame-buffer to crop a portion of the image memory (source) and optionally + scale it to a destination size. The result is then blended with or overlayed + on top of a CRTC. Planes are not provided by all hardware and the number of + available planes is limited. If planes are not available or if not enough + planes are available, the user should fall back to normal software blending + (via GPU or CPU). + +Encoders + An *encoder* takes pixel data from a CRTC and converts it to a format + suitable for any attached connectors. On some devices, it may be possible to + have a CRTC send data to more than one encoder. In that case, both encoders + would receive data from the same scanout buffer, resulting in a *cloned* + display configuration across the connectors attached to each encoder. + +Connectors + A *connector* is the final destination of pixel-data on a device, and + usually connects directly to an external display device like a monitor or + laptop panel. A connector can only be attached to one encoder at a time. The + connector is also the structure where information about the attached display + is kept, so it contains fields for display data, *EDID* data, *DPMS* and + *connection status*, and information about modes supported on the attached + displays. + +Framebuffers + *Framebuffers* are abstract memory objects that provide a source of pixel + data to scanout to a CRTC. Applications explicitly request the creation of + framebuffers and can control their behavior. Framebuffers rely on the + underneath memory manager for low-level memory operations. When creating a + framebuffer, applications pass a memory handle through the API which is used + as backing storage. The framebuffer itself is only an abstract object with + no data. It just refers to memory buffers that must be created with the + **drm-memory**\ (7) API. + +Mode-Setting +------------ + +Before mode-setting can be performed, an application needs to call +**drmSetMaster**\ (3) to become *DRM-Master*. It then has exclusive access to +the KMS API. A call to **drmModeGetResources**\ (3) returns a list of *CRTCs*, +*Connectors*, *Encoders* and *Planes*. + +Normal procedure now includes: First, you select which connectors you want to +use. Users are mostly interested in which monitor or display-panel is active so +you need to make sure to arrange them in the correct logical order and select +the correct ones to use. For each connector, you need to find a CRTC to drive +this connector. If you want to clone output to two or more connectors, you may +use a single CRTC for all cloned connectors (if the hardware supports this). To +find a suitable CRTC, you need to iterate over the list of encoders that are +available for each connector. Each encoder contains a list of CRTCs that it can +work with and you simply select one of these CRTCs. If you later program the +CRTC to control a connector, it automatically selects the best encoder. +However, this procedure is needed so your CRTC has at least one working encoder +for the selected connector. See the *Examples* section below for more +information. + +All valid modes for a connector can be retrieved with a call to +**drmModeGetConnector**\ (3) You need to select the mode you want to use and save it. +The first mode in the list is the default mode with the highest resolution +possible and often a suitable choice. + +After you have a working connector+CRTC+mode combination, you need to create a +framebuffer that is used for scanout. Memory buffer allocation is +driver-dependent and described in **drm-memory**\ (7). You need to create a +buffer big enough for your selected mode. Now you can create a framebuffer +object that uses your memory-buffer as scanout buffer. You can do this with +**drmModeAddFB**\ (3) and **drmModeAddFB2**\ (3). + +As a last step, you want to program your CRTC to drive your selected connector. +You can do this with a call to **drmModeSetCrtc**\ (3). + +Page-Flipping +------------- + +A call to **drmModeSetCrtc**\ (3) is executed immediately and forces the CRTC +to use the new scanout buffer. If you want smooth-transitions without tearing, +you probably use double-buffering. You need to create one framebuffer object +for each buffer you use. You can then call **drmModeSetCrtc**\ (3) on the next +buffer to flip. If you want to synchronize your flips with *vertical-blanks*, +you can use **drmModePageFlip**\ (3) which schedules your page-flip for the +next *vblank*. + +Planes +------ + +Planes are controlled independently from CRTCs. That is, a call to +**drmModeSetCrtc**\ (3) does not affect planes. Instead, you need to call +**drmModeSetPlane**\ (3) to configure a plane. This requires the plane ID, a +CRTC, a framebuffer and offsets into the plane-framebuffer and the +CRTC-framebuffer. The CRTC then blends the content from the plane over the CRTC +framebuffer buffer during scanout. As this does not involve any +software-blending, it is way faster than traditional blending. However, plane +resources are limited. See **drmModeGetPlaneResources**\ (3) for more +information. + +Cursors +------- + +Similar to planes, many hardware also supports cursors. A cursor is a very +small buffer with an image that is blended over the CRTC framebuffer. You can +set a different cursor for each CRTC with **drmModeSetCursor**\ (3) and move it +on the screen with **drmModeMoveCursor**\ (3). This allows to move the cursor +on the screen without rerendering. If no hardware cursors are supported, you +need to rerender for each frame the cursor is moved. + +Examples +======== + +Some examples of how basic mode-setting can be done. See the man-page of each +DRM function for more information. + +CRTC/Encoder Selection +---------------------- + +If you retrieved all display configuration information via +**drmModeGetResources**\ (3) as ``drmModeRes *res``, selected a connector from +the list in ``res->connectors`` and retrieved the connector-information as +``drmModeConnector *conn`` via **drmModeGetConnector**\ (3) then this example +shows, how you can find a suitable CRTC id to drive this connector. This +function takes a file-descriptor to the DRM device (see **drmOpen**\ (3)) as +``fd``, a pointer to the retrieved resources as ``res`` and a pointer to the +selected connector as ``conn``. It returns an integer smaller than 0 on +failure, otherwise, a valid CRTC id is returned. + +:: + + static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn) + { + drmModeEncoder *enc; + unsigned int i, j; + + /* iterate all encoders of this connector */ + for (i = 0; i < conn->count_encoders; ++i) { + enc = drmModeGetEncoder(fd, conn->encoders[i]); + if (!enc) { + /* cannot retrieve encoder, ignoring... */ + continue; + } + + /* iterate all global CRTCs */ + for (j = 0; j < res->count_crtcs; ++j) { + /* check whether this CRTC works with the encoder */ + if (!(enc->possible_crtcs & (1 << j))) + continue; + + + /* Here you need to check that no other connector + * currently uses the CRTC with id "crtc". If you intend + * to drive one connector only, then you can skip this + * step. Otherwise, simply scan your list of configured + * connectors and CRTCs whether this CRTC is already + * used. If it is, then simply continue the search here. */ + if (res->crtcs[j] "is unused") { + drmModeFreeEncoder(enc); + return res->crtcs[j]; + } + } + + drmModeFreeEncoder(enc); + } + + /* cannot find a suitable CRTC */ + return -ENOENT; + } + +Reporting Bugs +============== + +Bugs in this manual should be reported to +https://gitlab.freedesktop.org/mesa/drm/-/issues + +See Also +======== + +**drm**\ (7), **drm-memory**\ (7), **drmModeGetResources**\ (3), +**drmModeGetConnector**\ (3), **drmModeGetEncoder**\ (3), +**drmModeGetCrtc**\ (3), **drmModeSetCrtc**\ (3), **drmModeGetFB**\ (3), +**drmModeAddFB**\ (3), **drmModeAddFB2**\ (3), **drmModeRmFB**\ (3), +**drmModePageFlip**\ (3), **drmModeGetPlaneResources**\ (3), +**drmModeGetPlane**\ (3), **drmModeSetPlane**\ (3), **drmModeSetCursor**\ (3), +**drmModeMoveCursor**\ (3), **drmSetMaster**\ (3), **drmAvailable**\ (3), +**drmCheckModesettingSupported**\ (3), **drmOpen**\ (3) diff --git a/man/drm-memory.7.rst b/man/drm-memory.7.rst new file mode 100644 index 0000000..7d09eeb --- /dev/null +++ b/man/drm-memory.7.rst @@ -0,0 +1,313 @@ +========== +drm-memory +========== + +--------------------- +DRM Memory Management +--------------------- + +:Date: September 2012 +:Manual section: 7 +:Manual group: Direct Rendering Manager + +Synopsis +======== + +``#include `` + +Description +=========== + +Many modern high-end GPUs come with their own memory managers. They even +include several different caches that need to be synchronized during access. +Textures, framebuffers, command buffers and more need to be stored in memory +that can be accessed quickly by the GPU. Therefore, memory management on GPUs +is highly driver- and hardware-dependent. + +However, there are several frameworks in the kernel that are used by more than +one driver. These can be used for trivial mode-setting without requiring +driver-dependent code. But for hardware-accelerated rendering you need to read +the manual pages for the driver you want to work with. + +Dumb-Buffers +------------ + +Almost all in-kernel DRM hardware drivers support an API called *Dumb-Buffers*. +This API allows to create buffers of arbitrary size that can be used for +scanout. These buffers can be memory mapped via **mmap**\ (2) so you can render +into them on the CPU. However, GPU access to these buffers is often not +possible. Therefore, they are fine for simple tasks but not suitable for +complex compositions and renderings. + +The ``DRM_IOCTL_MODE_CREATE_DUMB`` ioctl can be used to create a dumb buffer. +The kernel will return a 32-bit handle that can be used to manage the buffer +with the DRM API. You can create framebuffers with **drmModeAddFB**\ (3) and +use it for mode-setting and scanout. To access the buffer, you first need to +retrieve the offset of the buffer. The ``DRM_IOCTL_MODE_MAP_DUMB`` ioctl +requests the DRM subsystem to prepare the buffer for memory-mapping and returns +a fake-offset that can be used with **mmap**\ (2). + +The ``DRM_IOCTL_MODE_CREATE_DUMB`` ioctl takes as argument a structure of type +``struct drm_mode_create_dumb``: + +:: + + struct drm_mode_create_dumb { + __u32 height; + __u32 width; + __u32 bpp; + __u32 flags; + + __u32 handle; + __u32 pitch; + __u64 size; + }; + +The fields *height*, *width*, *bpp* and *flags* have to be provided by the +caller. The other fields are filled by the kernel with the return values. +*height* and *width* are the dimensions of the rectangular buffer that is +created. *bpp* is the number of bits-per-pixel and must be a multiple of 8. You +most commonly want to pass 32 here. The flags field is currently unused and +must be zeroed. Different flags to modify the behavior may be added in the +future. After calling the ioctl, the handle, pitch and size fields are filled +by the kernel. *handle* is a 32-bit gem handle that identifies the buffer. This +is used by several other calls that take a gem-handle or memory-buffer as +argument. The *pitch* field is the pitch (or stride) of the new buffer. Most +drivers use 32-bit or 64-bit aligned stride-values. The size field contains the +absolute size in bytes of the buffer. This can normally also be computed with +``(height * pitch + width) * bpp / 4``. + +To prepare the buffer for **mmap**\ (2) you need to use the +``DRM_IOCTL_MODE_MAP_DUMB`` ioctl. It takes as argument a structure of type +``struct drm_mode_map_dumb``: + +:: + + struct drm_mode_map_dumb { + __u32 handle; + __u32 pad; + + __u64 offset; + }; + +You need to put the gem-handle that was previously retrieved via +``DRM_IOCTL_MODE_CREATE_DUMB`` into the *handle* field. The *pad* field is +unused padding and must be zeroed. After completion, the *offset* field will +contain an offset that can be used with **mmap**\ (2) on the DRM +file-descriptor. + +If you don't need your dumb-buffer, anymore, you have to destroy it with +``DRM_IOCTL_MODE_DESTROY_DUMB``. If you close the DRM file-descriptor, all open +dumb-buffers are automatically destroyed. This ioctl takes as argument a +structure of type ``struct drm_mode_destroy_dumb``: + +:: + + struct drm_mode_destroy_dumb { + __u32 handle; + }; + +You only need to put your handle into the *handle* field. After this call, the +handle is invalid and may be reused for new buffers by the dumb-API. + +TTM +--- + +*TTM* stands for *Translation Table Manager* and is a generic memory-manager +provided by the kernel. It does not provide a common user-space API so you need +to look at each driver interface if you want to use it. See for instance the +radeon man pages for more information on memory-management with radeon and TTM. + +GEM +--- + +*GEM* stands for *Graphics Execution Manager* and is a generic DRM +memory-management framework in the kernel, that is used by many different +drivers. GEM is designed to manage graphics memory, control access to the +graphics device execution context and handle essentially NUMA environment +unique to modern graphics hardware. GEM allows multiple applications to share +graphics device resources without the need to constantly reload the entire +graphics card. Data may be shared between multiple applications with gem +ensuring that the correct memory synchronization occurs. + +GEM provides simple mechanisms to manage graphics data and control execution +flow within the linux DRM subsystem. However, GEM is not a complete framework +that is fully driver independent. Instead, if provides many functions that are +shared between many drivers, but each driver has to implement most of +memory-management with driver-dependent ioctls. This manpage tries to describe +the semantics (and if it applies, the syntax) that is shared between all +drivers that use GEM. + +All GEM APIs are defined as **ioctl**\ (2) on the DRM file descriptor. An +application must be authorized via **drmAuthMagic**\ (3) to the current +DRM-Master to access the GEM subsystem. A driver that does not support GEM will +return ``ENODEV`` for all these ioctls. Invalid object handles return +``EINVAL`` and invalid object names return ``ENOENT``. + +Gem provides explicit memory management primitives. System pages are allocated +when the object is created, either as the fundamental storage for hardware +where system memory is used by the graphics processor directly, or as backing +store for graphics-processor resident memory. + +Objects are referenced from user-space using handles. These are, for all +intents and purposes, equivalent to file descriptors but avoid the overhead. +Newer kernel drivers also support the **drm-prime** (7) infrastructure which +can return real file-descriptor for GEM-handles using the linux DMA-BUF API. +Objects may be published with a name so that other applications and processes +can access them. The name remains valid as long as the object exists. +GEM-objects are reference counted in the kernel. The object is only destroyed +when all handles from user-space were closed. + +GEM-buffers cannot be created with a generic API. Each driver provides its own +API to create GEM-buffers. See for example ``DRM_I915_GEM_CREATE``, +``DRM_NOUVEAU_GEM_NEW`` or ``DRM_RADEON_GEM_CREATE``. Each of these ioctls +returns a GEM-handle that can be passed to different generic ioctls. The +*libgbm* library from the *mesa3D* distribution tries to provide a +driver-independent API to create GBM buffers and retrieve a GBM-handle to them. +It allows to create buffers for different use-cases including scanout, +rendering, cursors and CPU-access. See the libgbm library for more information +or look at the driver-dependent man-pages (for example **drm-intel**\ (7) or +**drm-radeon**\ (7)). + +GEM-buffers can be closed with **drmCloseBufferHandle**\ (3). It takes as +argument the GEM-handle to be closed. After this call the GEM handle cannot be +used by this process anymore and may be reused for new GEM objects by the GEM +API. + +If you want to share GEM-objects between different processes, you can create a +name for them and pass this name to other processes which can then open this +GEM-object. Names are currently 32-bit integer IDs and have no special +protection. That is, if you put a name on your GEM-object, every other client +that has access to the DRM device and is authenticated via +**drmAuthMagic**\ (3) to the current DRM-Master, can *guess* the name and open +or access the GEM-object. If you want more fine-grained access control, you can +use the new **drm-prime**\ (7) API to retrieve file-descriptors for +GEM-handles. To create a name for a GEM-handle, you use the +``DRM_IOCTL_GEM_FLINK`` ioctl. It takes as argument a structure of type +``struct drm_gem_flink``: + +:: + + struct drm_gem_flink { + __u32 handle; + __u32 name; + }; + +You have to put your handle into the *handle* field. After completion, the +kernel has put the new unique name into the name field. You can now pass +this name to other processes which can then import the name with the +``DRM_IOCTL_GEM_OPEN`` ioctl. It takes as argument a structure of type +``struct drm_gem_open``: + +:: + + struct drm_gem_open { + __u32 name; + + __u32 handle; + __u32 size; + }; + +You have to fill in the *name* field with the name of the GEM-object that you +want to open. The kernel will fill in the *handle* and *size* fields with the +new handle and size of the GEM-object. You can now access the GEM-object via +the handle as if you created it with the GEM API. + +Besides generic buffer management, the GEM API does not provide any generic +access. Each driver implements its own functionality on top of this API. This +includes execution-buffers, GTT management, context creation, CPU access, GPU +I/O and more. The next higher-level API is *OpenGL*. So if you want to use more +GPU features, you should use the *mesa3D* library to create OpenGL contexts on +DRM devices. This does *not* require any windowing-system like X11, but can +also be done on raw DRM devices. However, this is beyond the scope of this +man-page. You may have a look at other mesa3D man pages, including libgbm and +libEGL. 2D software-rendering (rendering with the CPU) can be achieved with the +dumb-buffer-API in a driver-independent fashion, however, for +hardware-accelerated 2D or 3D rendering you must use OpenGL. Any other API that +tries to abstract the driver-internals to access GEM-execution-buffers and +other GPU internals, would simply reinvent OpenGL so it is not provided. But if +you need more detailed information for a specific driver, you may have a look +into the driver-manpages, including **drm-intel**\ (7), **drm-radeon**\ (7) and +**drm-nouveau**\ (7). However, the **drm-prime**\ (7) infrastructure and the +generic GEM API as described here allow display-managers to handle +graphics-buffers and render-clients without any deeper knowledge of the GPU +that is used. Moreover, it allows to move objects between GPUs and implement +complex display-servers that don't do any rendering on their own. See its +man-page for more information. + +Examples +======== + +This section includes examples for basic memory-management tasks. + +Dumb-Buffers +------------ + +This examples shows how to create a dumb-buffer via the generic DRM API. +This is driver-independent (as long as the driver supports dumb-buffers) +and provides memory-mapped buffers that can be used for scanout. This +example creates a full-HD 1920x1080 buffer with 32 bits-per-pixel and a +color-depth of 24 bits. The buffer is then bound to a framebuffer which +can be used for scanout with the KMS API (see **drm-kms**\ (7)). + +:: + + struct drm_mode_create_dumb creq; + struct drm_mode_destroy_dumb dreq; + struct drm_mode_map_dumb mreq; + uint32_t fb; + int ret; + void *map; + + /* create dumb buffer */ + memset(&creq, 0, sizeof(creq)); + creq.width = 1920; + creq.height = 1080; + creq.bpp = 32; + ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &creq); + if (ret < 0) { + /* buffer creation failed; see "errno" for more error codes */ + ... + } + /* creq.pitch, creq.handle and creq.size are filled by this ioctl with + * the requested values and can be used now. */ + + /* create framebuffer object for the dumb-buffer */ + ret = drmModeAddFB(fd, 1920, 1080, 24, 32, creq.pitch, creq.handle, &fb); + if (ret) { + /* frame buffer creation failed; see "errno" */ + ... + } + /* the framebuffer "fb" can now used for scanout with KMS */ + + /* prepare buffer for memory mapping */ + memset(&mreq, 0, sizeof(mreq)); + mreq.handle = creq.handle; + ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq); + if (ret) { + /* DRM buffer preparation failed; see "errno" */ + ... + } + /* mreq.offset now contains the new offset that can be used with mmap() */ + + /* perform actual memory mapping */ + map = mmap(0, creq.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mreq.offset); + if (map == MAP_FAILED) { + /* memory-mapping failed; see "errno" */ + ... + } + + /* clear the framebuffer to 0 */ + memset(map, 0, creq.size); + +Reporting Bugs +============== + +Bugs in this manual should be reported to +https://gitlab.freedesktop.org/mesa/drm/-/issues + +See Also +======== + +**drm**\ (7), **drm-kms**\ (7), **drm-prime**\ (7), **drmAvailable**\ (3), +**drmOpen**\ (3), **drm-intel**\ (7), **drm-radeon**\ (7), **drm-nouveau**\ (7) diff --git a/man/drm.7.rst b/man/drm.7.rst new file mode 100644 index 0000000..df2c1c7 --- /dev/null +++ b/man/drm.7.rst @@ -0,0 +1,91 @@ +=== +drm +=== + +------------------------ +Direct Rendering Manager +------------------------ + +:Date: September 2012 +:Manual section: 7 +:Manual group: Direct Rendering Manager + +Synopsis +======== + +``#include `` + +Description +=========== + +The *Direct Rendering Manager* (DRM) is a framework to manage *Graphics +Processing Units* (GPUs). It is designed to support the needs of complex +graphics devices, usually containing programmable pipelines well suited +to 3D graphics acceleration. Furthermore, it is responsible for memory +management, interrupt handling and DMA to provide a uniform interface to +applications. + +In earlier days, the kernel framework was solely used to provide raw +hardware access to privileged user-space processes which implement all +the hardware abstraction layers. But more and more tasks were moved into +the kernel. All these interfaces are based on **ioctl**\ (2) commands on +the DRM character device. The *libdrm* library provides wrappers for these +system-calls and many helpers to simplify the API. + +When a GPU is detected, the DRM system loads a driver for the detected +hardware type. Each connected GPU is then presented to user-space via a +character-device that is usually available as ``/dev/dri/card0`` and can +be accessed with **open**\ (2) and **close**\ (2). However, it still +depends on the graphics driver which interfaces are available on these +devices. If an interface is not available, the syscalls will fail with +``EINVAL``. + +Authentication +-------------- + +All DRM devices provide authentication mechanisms. Only a DRM master is +allowed to perform mode-setting or modify core state and only one user +can be DRM master at a time. See **drmSetMaster**\ (3) for information +on how to become DRM master and what the limitations are. Other DRM users +can be authenticated to the DRM-Master via **drmAuthMagic**\ (3) so they +can perform buffer allocations and rendering. + +Mode-Setting +------------ + +Managing connected monitors and displays and changing the current modes +is called *Mode-Setting*. This is restricted to the current DRM master. +Historically, this was implemented in user-space, but new DRM drivers +implement a kernel interface to perform mode-setting called *Kernel Mode +Setting* (KMS). If your hardware-driver supports it, you can use the KMS +API provided by DRM. This includes allocating framebuffers, selecting +modes and managing CRTCs and encoders. See **drm-kms**\ (7) for more. + +Memory Management +----------------- + +The most sophisticated tasks for GPUs today is managing memory objects. +Textures, framebuffers, command-buffers and all other kinds of commands +for the GPU have to be stored in memory. The DRM driver takes care of +managing all memory objects, flushing caches, synchronizing access and +providing CPU access to GPU memory. All memory management is hardware +driver dependent. However, two generic frameworks are available that are +used by most DRM drivers. These are the *Translation Table Manager* +(TTM) and the *Graphics Execution Manager* (GEM). They provide generic +APIs to create, destroy and access buffers from user-space. However, +there are still many differences between the drivers so driver-dependent +code is still needed. Many helpers are provided in *libgbm* (Graphics +Buffer Manager) from the *Mesa* project. For more information on DRM +memory management, see **drm-memory**\ (7). + +Reporting Bugs +============== + +Bugs in this manual should be reported to +https://gitlab.freedesktop.org/mesa/drm/-/issues. + +See Also +======== + +**drm-kms**\ (7), **drm-memory**\ (7), **drmSetMaster**\ (3), +**drmAuthMagic**\ (3), **drmAvailable**\ (3), **drmOpen**\ (3) diff --git a/man/drmAvailable.3.rst b/man/drmAvailable.3.rst new file mode 100644 index 0000000..5da77be --- /dev/null +++ b/man/drmAvailable.3.rst @@ -0,0 +1,41 @@ +============ +drmAvailable +============ + +----------------------------------------------------- +determine whether a DRM kernel driver has been loaded +----------------------------------------------------- + +:Date: September 2012 +:Manual section: 3 +:Manual group: Direct Rendering Manager + +Synopsis +======== + +``#include `` + +``int drmAvailable(void);`` + +Description +=========== + +``drmAvailable`` allows the caller to determine whether a kernel DRM +driver is loaded. + +Return Value +============ + +``drmAvailable`` returns 1 if a DRM driver is currently loaded. +Otherwise 0 is returned. + +Reporting Bugs +============== + +Bugs in this function should be reported to +https://gitlab.freedesktop.org/mesa/drm/-/issues + +See Also +======== + +**drm**\ (7), **drmOpen**\ (3) diff --git a/man/drmHandleEvent.3.rst b/man/drmHandleEvent.3.rst new file mode 100644 index 0000000..ecc63ed --- /dev/null +++ b/man/drmHandleEvent.3.rst @@ -0,0 +1,62 @@ +============== +drmHandleEvent +============== + +----------------------------------- +read and process pending DRM events +----------------------------------- + +:Date: September 2012 +:Manual section: 3 +:Manual group: Direct Rendering Manager + +Synopsis +======== + +``#include `` + +``int drmHandleEvent(int fd, drmEventContextPtr evctx);`` + +Description +=========== + +``drmHandleEvent`` processes outstanding DRM events on the DRM +file-descriptor passed as ``fd``. This function should be called after +the DRM file-descriptor has polled readable; it will read the events and +use the passed-in ``evctx`` structure to call function pointers with the +parameters noted below: + +:: + + typedef struct _drmEventContext { + int version; + void (*vblank_handler) (int fd, + unsigned int sequence, + unsigned int tv_sec, + unsigned int tv_usec, + void *user_data) + void (*page_flip_handler) (int fd, + unsigned int sequence, + unsigned int tv_sec, + unsigned int tv_usec, + void *user_data) + } drmEventContext, *drmEventContextPtr; + +Return Value +============ + +``drmHandleEvent`` returns 0 on success, or if there is no data to +read from the file-descriptor. Returns -1 if the read on the +file-descriptor fails or returns less than a full event record. + +Reporting Bugs +============== + +Bugs in this function should be reported to +https://gitlab.freedesktop.org/mesa/drm/-/issues + +See Also +======== + +**drm**\ (7), **drm-kms**\ (7), **drmModePageFlip**\ (3), +**drmWaitVBlank**\ (3) diff --git a/man/drmModeGetResources.3.rst b/man/drmModeGetResources.3.rst new file mode 100644 index 0000000..d1358d2 --- /dev/null +++ b/man/drmModeGetResources.3.rst @@ -0,0 +1,92 @@ +=================== +drmModeGetResources +=================== + +-------------------------------------------------- +retrieve current display configuration information +-------------------------------------------------- + +:Date: September 2012 +:Manual section: 3 +:Manual group: Direct Rendering Manager + +Synopsis +======== + +``#include `` + +``#include `` + +``drmModeResPtr drmModeGetResources(int fd);`` + +Description +=========== + +``drmModeGetResources`` allocates, populates, and returns a drmModeRes +structure containing information about the current display +configuration. The structure contains the following fields: + +:: + + typedef struct _drmModeRes { + int count_fbs; + uint32_t *fbs; + + int count_crtcs; + uint32_t *crtcs; + + int count_connectors; + uint32_t *connectors; + + int count_encoders; + uint32_t *encoders; + + uint32_t min_width, max_width; + uint32_t min_height, max_height; + } drmModeRes, *drmModeResPtr; + +The *count_fbs* and *fbs* fields indicate the number of currently allocated +framebuffer objects (i.e., objects that can be attached to a given CRTC +or sprite for display). + +The *count_crtcs* and *crtcs* fields list the available CRTCs in the +configuration. A CRTC is simply an object that can scan out a +framebuffer to a display sink, and contains mode timing and relative +position information. CRTCs drive encoders, which are responsible for +converting the pixel stream into a specific display protocol (e.g., MIPI +or HDMI). + +The *count_connectors* and *connectors* fields list the available physical +connectors on the system. Note that some of these may not be exposed +from the chassis (e.g., LVDS or eDP). Connectors are attached to +encoders and contain information about the attached display sink (e.g., +width and height in mm, subpixel ordering, and various other +properties). + +The *count_encoders* and *encoders* fields list the available encoders on +the device. Each encoder may be associated with a CRTC, and may be used +to drive a particular encoder. + +The *min_\** and *max_\** fields indicate the maximum size of a framebuffer +for this device (i.e., the scanout size limit). + +Return Value +============ + +``drmModeGetResources`` returns a drmModeRes structure pointer on +success, NULL on failure. The returned structure must be freed with +**drmModeFreeResources**\ (3). + +Reporting Bugs +============== + +Bugs in this function should be reported to +https://gitlab.freedesktop.org/mesa/drm/-/issues + +See Also +======== + +**drm**\ (7), **drm-kms**\ (7), **drmModeGetFB**\ (3), **drmModeAddFB**\ (3), +**drmModeAddFB2**\ (3), **drmModeRmFB**\ (3), **drmModeDirtyFB**\ (3), +**drmModeGetCrtc**\ (3), **drmModeSetCrtc** (3), **drmModeGetEncoder** (3), +**drmModeGetConnector**\ (3) diff --git a/man/meson.build b/man/meson.build new file mode 100644 index 0000000..92a4c37 --- /dev/null +++ b/man/meson.build @@ -0,0 +1,40 @@ +# Copyright © 2017-2018 Intel Corporation + +# 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. + +rst_pages = [ + ['drm', '7'], + ['drm-kms', '7'], + ['drm-memory', '7'], + ['drmAvailable', '3'], + ['drmHandleEvent', '3'], + ['drmModeGetResources', '3'], +] +foreach page : rst_pages + name = page[0] + '.' + page[1] + rst = files(name + '.rst') + custom_target( + name, + input : rst, + output : name, + command : [prog_rst2man, '@INPUT@', '@OUTPUT@'], + install : true, + install_dir : join_paths(get_option('mandir'), 'man' + page[1]), + ) +endforeach diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..3ff6bfa --- /dev/null +++ b/meson.build @@ -0,0 +1,395 @@ +# Copyright © 2017-2018 Intel Corporation + +# 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. + +project( + 'libdrm', + ['c'], + version : '2.4.114', + license : 'MIT', + meson_version : '>= 0.53', + default_options : ['buildtype=debugoptimized', 'c_std=c11'], +) + +if ['windows', 'darwin'].contains(host_machine.system()) + error('unsupported OS: @0@'.format(host_machine.system())) +endif + +pkg = import('pkgconfig') + +config = configuration_data() + +config.set10('UDEV', get_option('udev')) +with_freedreno_kgsl = get_option('freedreno-kgsl') +with_install_tests = get_option('install-test-programs') +with_tests = get_option('tests') + +if ['freebsd', 'dragonfly', 'netbsd'].contains(host_machine.system()) + dep_pthread_stubs = dependency('pthread-stubs', version : '>= 0.4') +else + dep_pthread_stubs = [] +endif +dep_threads = dependency('threads') + +cc = meson.get_compiler('c') + +android = cc.compiles('''int func() { return __ANDROID__; }''') + +symbols_check = find_program('symbols-check.py') +prog_nm = find_program('nm') + +# Check for atomics +intel_atomics = false +lib_atomics = false + +python3 = import('python').find_installation() +format_mod_static_table = custom_target( + 'format_mod_static_table', + output : 'generated_static_table_fourcc.h', + input : 'include/drm/drm_fourcc.h', + command : [python3, files('gen_table_fourcc.py'), '@INPUT@', '@OUTPUT@']) + +dep_atomic_ops = dependency('atomic_ops', required : false) +if cc.links(''' + int atomic_add(int *i) { return __sync_add_and_fetch (i, 1); } + int atomic_cmpxchg(int *i, int j, int k) { return __sync_val_compare_and_swap (i, j, k); } + int main() { } + ''', + name : 'Intel Atomics') + intel_atomics = true + with_atomics = true + dep_atomic_ops = [] +elif dep_atomic_ops.found() + lib_atomics = true + with_atomics = true +elif cc.has_function('atomic_cas_uint') + with_atomics = true +else + with_atomics = false +endif + +config.set10('HAVE_LIBDRM_ATOMIC_PRIMITIVES', intel_atomics) +config.set10('HAVE_LIB_ATOMIC_OPS', lib_atomics) + +dep_pciaccess = dependency('pciaccess', version : '>= 0.10', required : get_option('intel')) + +with_intel = false +_intel = get_option('intel') +if not _intel.disabled() + if _intel.enabled() and not with_atomics + error('libdrm_intel requires atomics.') + else + with_intel = (_intel.enabled() or host_machine.cpu_family().startswith('x86')) and with_atomics and dep_pciaccess.found() + endif +endif +summary('Intel', with_intel) + +with_radeon = false +_radeon = get_option('radeon') +if not _radeon.disabled() + if _radeon.enabled() and not with_atomics + error('libdrm_radeon requires atomics.') + endif + with_radeon = with_atomics +endif +summary('Radeon', with_radeon) + +with_amdgpu = false +_amdgpu = get_option('amdgpu') +if not _amdgpu.disabled() + if _amdgpu.enabled() and not with_atomics + error('libdrm_amdgpu requires atomics.') + endif + with_amdgpu = with_atomics +endif +summary('AMDGPU', with_amdgpu) + +with_nouveau = false +_nouveau = get_option('nouveau') +if not _nouveau.disabled() + if _nouveau.enabled() and not with_atomics + error('libdrm_nouveau requires atomics.') + endif + with_nouveau = with_atomics +endif +summary('Nouveau', with_nouveau) + +with_vmwgfx = false +_vmwgfx = get_option('vmwgfx') +if not _vmwgfx.disabled() + with_vmwgfx = true +endif +summary('vmwgfx', with_vmwgfx) + +with_omap = false +_omap = get_option('omap') +if _omap.enabled() + if not with_atomics + error('libdrm_omap requires atomics.') + endif + with_omap = true +endif +summary('OMAP', with_omap) + +with_freedreno = false +_freedreno = get_option('freedreno') +if not _freedreno.disabled() + if _freedreno.enabled() and not with_atomics + error('libdrm_freedreno requires atomics.') + else + with_freedreno = (_freedreno.enabled() or ['arm', 'aarch64'].contains(host_machine.cpu_family())) and with_atomics + endif +endif +summary('Freedreno', with_freedreno) +summary('Freedreon-kgsl', with_freedreno_kgsl) + +with_tegra = false +_tegra = get_option('tegra') +if _tegra.enabled() + if not with_atomics + error('libdrm_tegra requires atomics.') + endif + with_tegra = true +endif +summary('Tegra', with_tegra) + +with_etnaviv = false +_etnaviv = get_option('etnaviv') +if not _etnaviv.disabled() + if _etnaviv.enabled() and not with_atomics + error('libdrm_etnaviv requires atomics.') + endif + with_etnaviv = _etnaviv.enabled() or ( + with_atomics and [ + 'loongarch64', 'mips', 'mips64', + 'arm', 'aarch64', 'arc', + ].contains(host_machine.cpu_family()) + ) +endif +summary('Etnaviv', with_etnaviv) + +with_exynos = get_option('exynos').enabled() +summary('EXYNOS', with_exynos) + +with_vc4 = false +_vc4 = get_option('vc4') +if not _vc4.disabled() + with_vc4 = _vc4.enabled() or ['arm', 'aarch64'].contains(host_machine.cpu_family()) +endif +summary('VC4', with_vc4) + +# Among others FreeBSD does not have a separate dl library. +if not cc.has_function('dlsym') + dep_dl = cc.find_library('dl', required : with_nouveau) +else + dep_dl = [] +endif +# clock_gettime might require -rt, or it might not. find out +if not cc.has_function('clock_gettime', prefix : '#define _GNU_SOURCE\n#include ') + # XXX: untested + dep_rt = cc.find_library('rt') +else + dep_rt = [] +endif +dep_m = cc.find_library('m', required : false) + +# The header is not required on Linux, and is in fact deprecated in glibc 2.30+ +if ['linux'].contains(host_machine.system()) + config.set10('HAVE_SYS_SYSCTL_H', false) +else + # From Niclas Zeising: + # FreeBSD requires sys/types.h for sys/sysctl.h, so add it as part of + # the includes when checking for headers. + config.set10('HAVE_SYS_SYSCTL_H', + cc.compiles('#include \n#include ', name : 'sys/sysctl.h works')) +endif + +foreach header : ['sys/select.h', 'alloca.h'] + config.set10('HAVE_' + header.underscorify().to_upper(), cc.check_header(header)) +endforeach + +if (cc.has_header_symbol('sys/sysmacros.h', 'major') and + cc.has_header_symbol('sys/sysmacros.h', 'minor') and + cc.has_header_symbol('sys/sysmacros.h', 'makedev')) + config.set10('MAJOR_IN_SYSMACROS', true) +endif +if (cc.has_header_symbol('sys/mkdev.h', 'major') and + cc.has_header_symbol('sys/mkdev.h', 'minor') and + cc.has_header_symbol('sys/mkdev.h', 'makedev')) + config.set10('MAJOR_IN_MKDEV', true) +endif +config.set10('HAVE_OPEN_MEMSTREAM', cc.has_function('open_memstream')) + +libdrm_c_args = cc.get_supported_arguments([ + '-Wsign-compare', '-Werror=undef', '-Werror=implicit-function-declaration', + '-Wpointer-arith', '-Wwrite-strings', '-Wstrict-prototypes', + '-Wmissing-prototypes', '-Wmissing-declarations', '-Wnested-externs', + '-Wpacked', '-Wswitch-enum', '-Wmissing-format-attribute', + '-Wstrict-aliasing=2', '-Winit-self', '-Winline', '-Wshadow', + '-Wdeclaration-after-statement', '-Wold-style-definition', + '-Wno-unused-parameter', '-Wno-attributes', '-Wno-long-long', + '-Wno-missing-field-initializers']) + +dep_cunit = dependency('cunit', version : '>= 2.1', required : false) +dep_cairo = dependency('cairo', required : get_option('cairo-tests')) +with_cairo_tests = dep_cairo.found() + +valgrind_version = [] +if with_freedreno + valgrind_version = '>=3.10.0' +endif +dep_valgrind = dependency('valgrind', required : get_option('valgrind'), version : valgrind_version) +with_valgrind = dep_valgrind.found() + +prog_rst2man = find_program('rst2man', 'rst2man.py', required: get_option('man-pages')) +with_man_pages = prog_rst2man.found() + +config.set10('HAVE_VISIBILITY', cc.has_function_attribute('visibility:hidden')) + +foreach t : [ + [with_exynos, 'EXYNOS'], + [with_freedreno_kgsl, 'FREEDRENO_KGSL'], + [with_intel, 'INTEL'], + [with_nouveau, 'NOUVEAU'], + [with_radeon, 'RADEON'], + [with_vc4, 'VC4'], + [with_vmwgfx, 'VMWGFX'], + [with_cairo_tests, 'CAIRO'], + [with_valgrind, 'VALGRIND'], + ] + config.set10('HAVE_@0@'.format(t[1]), t[0]) +endforeach +if with_freedreno_kgsl and not with_freedreno + error('cannot enable freedreno-kgsl without freedreno support') +endif +config.set10('_GNU_SOURCE', true) +config_file = configure_file( + configuration : config, + output : 'config.h', +) +add_project_arguments('-include', '@0@'.format(config_file), language : 'c') + +inc_root = include_directories('.') +inc_drm = include_directories('include/drm') + +libdrm_files = [files( + 'xf86drm.c', 'xf86drmHash.c', 'xf86drmRandom.c', 'xf86drmSL.c', + 'xf86drmMode.c' + ), + config_file, format_mod_static_table +] + +# Build an unversioned so on android +if android + libdrm_kw = {} +else + libdrm_kw = {'version' : '2.4.0'} +endif + +libdrm = library( + 'drm', + libdrm_files, + c_args : libdrm_c_args, + dependencies : [dep_valgrind, dep_rt, dep_m], + include_directories : inc_drm, + install : true, + kwargs : libdrm_kw, + gnu_symbol_visibility : 'hidden', +) + +test( + 'core-symbols-check', + symbols_check, + args : [ + '--lib', libdrm, + '--symbols-file', files('core-symbols.txt'), + '--nm', prog_nm.path(), + ], +) + +ext_libdrm = declare_dependency( + link_with : libdrm, + include_directories : [inc_root, inc_drm], +) + +if meson.version().version_compare('>= 0.54.0') + meson.override_dependency('libdrm', ext_libdrm) +endif + +install_headers('libsync.h', 'xf86drm.h', 'xf86drmMode.h') +install_headers( + 'include/drm/drm.h', 'include/drm/drm_fourcc.h', 'include/drm/drm_mode.h', + 'include/drm/drm_sarea.h', 'include/drm/i915_drm.h', + 'include/drm/mach64_drm.h', 'include/drm/mga_drm.h', + 'include/drm/msm_drm.h', 'include/drm/nouveau_drm.h', + 'include/drm/qxl_drm.h', 'include/drm/r128_drm.h', + 'include/drm/radeon_drm.h', 'include/drm/amdgpu_drm.h', + 'include/drm/savage_drm.h', 'include/drm/sis_drm.h', + 'include/drm/tegra_drm.h', 'include/drm/vc4_drm.h', + 'include/drm/via_drm.h', 'include/drm/virtgpu_drm.h', + subdir : 'libdrm', +) +if with_vmwgfx + install_headers('include/drm/vmwgfx_drm.h', subdir : 'libdrm') +endif + +pkg.generate( + libdrm, + name : 'libdrm', + subdirs : ['.', 'libdrm'], + description : 'Userspace interface to kernel DRM services', +) + +if with_intel + subdir('intel') +endif +if with_nouveau + subdir('nouveau') +endif +if with_radeon + subdir('radeon') +endif +if with_amdgpu + subdir('amdgpu') +endif +if with_omap + subdir('omap') +endif +if with_exynos + subdir('exynos') +endif +if with_freedreno + subdir('freedreno') +endif +if with_tegra + subdir('tegra') +endif +if with_vc4 + subdir('vc4') +endif +if with_etnaviv + subdir('etnaviv') +endif +if with_man_pages + subdir('man') +endif +subdir('data') +if with_tests + subdir('tests') +endif diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..e80d79e --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,117 @@ +# Copyright © 2017 Intel Corporation + +# 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. + +option( + 'intel', + type : 'feature', + description : '''Enable support for Intel's KMS API.''', +) +option( + 'radeon', + type : 'feature', + description : '''Enable support for radeons's KMS API.''', +) +option( + 'amdgpu', + type : 'feature', + description : '''Enable support for amdgpu's KMS API.''', +) +option( + 'nouveau', + type : 'feature', + description : '''Enable support for nouveau's KMS API.''', +) +option( + 'vmwgfx', + type : 'feature', + description : '''Enable support for vmgfx's KMS API.''', +) +option( + 'omap', + type : 'feature', + value : 'disabled', + description : '''Enable support for OMAP's experimental KMS API.''', +) +option( + 'exynos', + type : 'feature', + value : 'disabled', + description : '''Enable support for EXYNOS's experimental KMS API.''', +) +option( + 'freedreno', + type : 'feature', + description : '''Enable support for freedreno's KMS API.''', +) +option( + 'tegra', + type : 'feature', + value : 'disabled', + description : '''Enable support for Tegra's experimental KMS API.''', +) +option( + 'vc4', + type : 'feature', + description : '''Enable support for vc4's KMS API.''', +) +option( + 'etnaviv', + type : 'feature', + description : '''Enable support for etnaviv's KMS API.''', +) +option( + 'cairo-tests', + type : 'feature', + description : 'Enable support for Cairo rendering in tests.', +) +option( + 'man-pages', + type : 'feature', + description : 'Enable manpage generation and installation.', +) +option( + 'valgrind', + type : 'feature', + description : 'Build libdrm with valgrind support.', +) +option( + 'freedreno-kgsl', + type : 'boolean', + value : false, + description : 'Enable support for freedreno to use downstream android kernel API.', +) +option( + 'install-test-programs', + type : 'boolean', + value : false, + description : 'Install test programs.', +) +option( + 'udev', + type : 'boolean', + value : false, + description : 'Enable support for using udev instead of mknod.', +) +option( + 'tests', + type : 'boolean', + value : true, + description : 'Build test programs.', +) diff --git a/nouveau/Android.mk b/nouveau/Android.mk new file mode 100644 index 0000000..b430af4 --- /dev/null +++ b/nouveau/Android.mk @@ -0,0 +1,14 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +# Import variables LIBDRM_NOUVEAU_FILES, LIBDRM_NOUVEAU_H_FILES +include $(LOCAL_PATH)/Makefile.sources + +LOCAL_MODULE := libdrm_nouveau + +LOCAL_SHARED_LIBRARIES := libdrm + +LOCAL_SRC_FILES := $(LIBDRM_NOUVEAU_FILES) + +include $(LIBDRM_COMMON_MK) +include $(BUILD_SHARED_LIBRARY) diff --git a/nouveau/Makefile.sources b/nouveau/Makefile.sources new file mode 100644 index 0000000..89f2a2b --- /dev/null +++ b/nouveau/Makefile.sources @@ -0,0 +1,9 @@ +LIBDRM_NOUVEAU_FILES := \ + nouveau.c \ + pushbuf.c \ + bufctx.c \ + abi16.c \ + private.h + +LIBDRM_NOUVEAU_H_FILES := \ + nouveau.h diff --git a/nouveau/abi16.c b/nouveau/abi16.c new file mode 100644 index 0000000..ba2501e --- /dev/null +++ b/nouveau/abi16.c @@ -0,0 +1,359 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + * Authors: Ben Skeggs + */ + +#include +#include +#include +#include + +#include "private.h" + +#include "nvif/class.h" + +static int +abi16_chan_nv04(struct nouveau_object *obj) +{ + struct nouveau_drm *drm = nouveau_drm(obj); + struct nv04_fifo *nv04 = obj->data; + struct drm_nouveau_channel_alloc req = { + .fb_ctxdma_handle = nv04->vram, + .tt_ctxdma_handle = nv04->gart + }; + int ret; + + ret = drmCommandWriteRead(drm->fd, DRM_NOUVEAU_CHANNEL_ALLOC, + &req, sizeof(req)); + if (ret) + return ret; + + nv04->base.channel = req.channel; + nv04->base.pushbuf = req.pushbuf_domains; + nv04->notify = req.notifier_handle; + nv04->base.object->handle = req.channel; + nv04->base.object->length = sizeof(*nv04); + return 0; +} + +static int +abi16_chan_nvc0(struct nouveau_object *obj) +{ + struct nouveau_drm *drm = nouveau_drm(obj); + struct drm_nouveau_channel_alloc req = {}; + struct nvc0_fifo *nvc0 = obj->data; + int ret; + + ret = drmCommandWriteRead(drm->fd, DRM_NOUVEAU_CHANNEL_ALLOC, + &req, sizeof(req)); + if (ret) + return ret; + + nvc0->base.channel = req.channel; + nvc0->base.pushbuf = req.pushbuf_domains; + nvc0->notify = req.notifier_handle; + nvc0->base.object->handle = req.channel; + nvc0->base.object->length = sizeof(*nvc0); + return 0; +} + +static int +abi16_chan_nve0(struct nouveau_object *obj) +{ + struct nouveau_drm *drm = nouveau_drm(obj); + struct drm_nouveau_channel_alloc req = {}; + struct nve0_fifo *nve0 = obj->data; + int ret; + + if (obj->length > offsetof(struct nve0_fifo, engine)) { + req.fb_ctxdma_handle = 0xffffffff; + req.tt_ctxdma_handle = nve0->engine; + } + + ret = drmCommandWriteRead(drm->fd, DRM_NOUVEAU_CHANNEL_ALLOC, + &req, sizeof(req)); + if (ret) + return ret; + + nve0->base.channel = req.channel; + nve0->base.pushbuf = req.pushbuf_domains; + nve0->notify = req.notifier_handle; + nve0->base.object->handle = req.channel; + nve0->base.object->length = sizeof(*nve0); + return 0; +} + +static int +abi16_engobj(struct nouveau_object *obj) +{ + struct nouveau_drm *drm = nouveau_drm(obj); + struct drm_nouveau_grobj_alloc req = { + .channel = obj->parent->handle, + .handle = obj->handle, + .class = obj->oclass, + }; + int ret; + + /* Older kernel versions did not have the concept of nouveau- + * specific classes and abused some NVIDIA-assigned ones for + * a SW class. The ABI16 layer has compatibility in place to + * translate these older identifiers to the newer ones. + * + * Clients that have been updated to use NVIF are required to + * use the newer class identifiers, which means that they'll + * break if running on an older kernel. + * + * To handle this case, when using ABI16, we translate to the + * older values which work on any kernel. + */ + switch (req.class) { + case NVIF_CLASS_SW_NV04 : req.class = 0x006e; break; + case NVIF_CLASS_SW_NV10 : req.class = 0x016e; break; + case NVIF_CLASS_SW_NV50 : req.class = 0x506e; break; + case NVIF_CLASS_SW_GF100: req.class = 0x906e; break; + default: + break; + } + + ret = drmCommandWrite(drm->fd, DRM_NOUVEAU_GROBJ_ALLOC, + &req, sizeof(req)); + if (ret) + return ret; + + obj->length = sizeof(struct nouveau_object *); + return 0; +} + +static int +abi16_ntfy(struct nouveau_object *obj) +{ + struct nouveau_drm *drm = nouveau_drm(obj); + struct nv04_notify *ntfy = obj->data; + struct drm_nouveau_notifierobj_alloc req = { + .channel = obj->parent->handle, + .handle = ntfy->object->handle, + .size = ntfy->length, + }; + int ret; + + ret = drmCommandWriteRead(drm->fd, DRM_NOUVEAU_NOTIFIEROBJ_ALLOC, + &req, sizeof(req)); + if (ret) + return ret; + + ntfy->offset = req.offset; + ntfy->object->length = sizeof(*ntfy); + return 0; +} + +drm_private int +abi16_sclass(struct nouveau_object *obj, struct nouveau_sclass **psclass) +{ + struct nouveau_sclass *sclass; + struct nouveau_device *dev; + + if (!(sclass = calloc(8, sizeof(*sclass)))) + return -ENOMEM; + *psclass = sclass; + + switch (obj->oclass) { + case NOUVEAU_FIFO_CHANNEL_CLASS: + /* Older kernel versions were exposing the wrong video engine + * classes on certain G98:GF100 boards. This has since been + * corrected, but ABI16 has compatibility in place to avoid + * breaking older userspace. + * + * Clients that have been updated to use NVIF are required to + * use the correct classes, which means that they'll break if + * running on an older kernel. + * + * To handle this issue, if using the older kernel interfaces, + * we'll magic up a list containing the vdec classes that the + * kernel will accept for these boards. Clients should make + * use of this information instead of hardcoding classes for + * specific chipsets. + */ + dev = (struct nouveau_device *)obj->parent; + if (dev->chipset >= 0x98 && + dev->chipset != 0xa0 && + dev->chipset < 0xc0) { + *sclass++ = (struct nouveau_sclass){ + GT212_MSVLD, -1, -1 + }; + *sclass++ = (struct nouveau_sclass){ + GT212_MSPDEC, -1, -1 + }; + *sclass++ = (struct nouveau_sclass){ + GT212_MSPPP, -1, -1 + }; + } + break; + default: + break; + } + + return sclass - *psclass; +} + +drm_private void +abi16_delete(struct nouveau_object *obj) +{ + struct nouveau_drm *drm = nouveau_drm(obj); + if (obj->oclass == NOUVEAU_FIFO_CHANNEL_CLASS) { + struct drm_nouveau_channel_free req; + req.channel = obj->handle; + drmCommandWrite(drm->fd, DRM_NOUVEAU_CHANNEL_FREE, + &req, sizeof(req)); + } else { + struct drm_nouveau_gpuobj_free req; + req.channel = obj->parent->handle; + req.handle = obj->handle; + drmCommandWrite(drm->fd, DRM_NOUVEAU_GPUOBJ_FREE, + &req, sizeof(req)); + } +} + +drm_private bool +abi16_object(struct nouveau_object *obj, int (**func)(struct nouveau_object *)) +{ + struct nouveau_object *parent = obj->parent; + + /* nouveau_object::length is (ab)used to determine whether the + * object is a legacy object (!=0), or a real NVIF object. + */ + if ((parent->length != 0 && parent->oclass == NOUVEAU_DEVICE_CLASS) || + (parent->length == 0 && parent->oclass == NV_DEVICE)) { + if (obj->oclass == NOUVEAU_FIFO_CHANNEL_CLASS) { + struct nouveau_device *dev = (void *)parent; + if (dev->chipset < 0xc0) + *func = abi16_chan_nv04; + else + if (dev->chipset < 0xe0) + *func = abi16_chan_nvc0; + else + *func = abi16_chan_nve0; + return true; + } + } else + if ((parent->length != 0 && + parent->oclass == NOUVEAU_FIFO_CHANNEL_CLASS)) { + if (obj->oclass == NOUVEAU_NOTIFIER_CLASS) { + *func = abi16_ntfy; + return true; + } + + *func = abi16_engobj; + return false; /* try NVIF, if supported, before calling func */ + } + + *func = NULL; + return false; +} + +drm_private void +abi16_bo_info(struct nouveau_bo *bo, struct drm_nouveau_gem_info *info) +{ + struct nouveau_bo_priv *nvbo = nouveau_bo(bo); + + nvbo->map_handle = info->map_handle; + bo->handle = info->handle; + bo->size = info->size; + bo->offset = info->offset; + + bo->flags = 0; + if (info->domain & NOUVEAU_GEM_DOMAIN_VRAM) + bo->flags |= NOUVEAU_BO_VRAM; + if (info->domain & NOUVEAU_GEM_DOMAIN_GART) + bo->flags |= NOUVEAU_BO_GART; + if (!(info->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG)) + bo->flags |= NOUVEAU_BO_CONTIG; + if (nvbo->map_handle) + bo->flags |= NOUVEAU_BO_MAP; + + if (bo->device->chipset >= 0xc0) { + bo->config.nvc0.memtype = (info->tile_flags & 0xff00) >> 8; + bo->config.nvc0.tile_mode = info->tile_mode; + } else + if (bo->device->chipset >= 0x80 || bo->device->chipset == 0x50) { + bo->config.nv50.memtype = (info->tile_flags & 0x07f00) >> 8 | + (info->tile_flags & 0x30000) >> 9; + bo->config.nv50.tile_mode = info->tile_mode << 4; + } else { + bo->config.nv04.surf_flags = info->tile_flags & 7; + bo->config.nv04.surf_pitch = info->tile_mode; + } +} + +drm_private int +abi16_bo_init(struct nouveau_bo *bo, uint32_t alignment, + union nouveau_bo_config *config) +{ + struct nouveau_device *dev = bo->device; + struct nouveau_drm *drm = nouveau_drm(&dev->object); + struct drm_nouveau_gem_new req = {}; + struct drm_nouveau_gem_info *info = &req.info; + int ret; + + if (bo->flags & NOUVEAU_BO_VRAM) + info->domain |= NOUVEAU_GEM_DOMAIN_VRAM; + if (bo->flags & NOUVEAU_BO_GART) + info->domain |= NOUVEAU_GEM_DOMAIN_GART; + if (!info->domain) + info->domain |= NOUVEAU_GEM_DOMAIN_VRAM | + NOUVEAU_GEM_DOMAIN_GART; + + if (bo->flags & NOUVEAU_BO_MAP) + info->domain |= NOUVEAU_GEM_DOMAIN_MAPPABLE; + + if (bo->flags & NOUVEAU_BO_COHERENT) + info->domain |= NOUVEAU_GEM_DOMAIN_COHERENT; + + if (!(bo->flags & NOUVEAU_BO_CONTIG)) + info->tile_flags = NOUVEAU_GEM_TILE_NONCONTIG; + + info->size = bo->size; + req.align = alignment; + + if (config) { + if (dev->chipset >= 0xc0) { + info->tile_flags = (config->nvc0.memtype & 0xff) << 8; + info->tile_mode = config->nvc0.tile_mode; + } else + if (dev->chipset >= 0x80 || dev->chipset == 0x50) { + info->tile_flags = (config->nv50.memtype & 0x07f) << 8 | + (config->nv50.memtype & 0x180) << 9; + info->tile_mode = config->nv50.tile_mode >> 4; + } else { + info->tile_flags = config->nv04.surf_flags & 7; + info->tile_mode = config->nv04.surf_pitch; + } + } + + if (!nouveau_device(dev)->have_bo_usage) + info->tile_flags &= 0x0000ff00; + + ret = drmCommandWriteRead(drm->fd, DRM_NOUVEAU_GEM_NEW, + &req, sizeof(req)); + if (ret == 0) + abi16_bo_info(bo, &req.info); + return ret; +} diff --git a/nouveau/bufctx.c b/nouveau/bufctx.c new file mode 100644 index 0000000..00924b3 --- /dev/null +++ b/nouveau/bufctx.c @@ -0,0 +1,160 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + * Authors: Ben Skeggs + */ + +#include +#include +#include +#include +#include +#include + +#include "libdrm_lists.h" + +#include "nouveau.h" +#include "private.h" + +struct nouveau_bufref_priv { + struct nouveau_bufref base; + struct nouveau_bufref_priv *next; + struct nouveau_bufctx *bufctx; +}; + +struct nouveau_bufbin_priv { + struct nouveau_bufref_priv *list; + int relocs; +}; + +struct nouveau_bufctx_priv { + struct nouveau_bufctx base; + struct nouveau_bufref_priv *free; + int nr_bins; + struct nouveau_bufbin_priv bins[]; +}; + +static inline struct nouveau_bufctx_priv * +nouveau_bufctx(struct nouveau_bufctx *bctx) +{ + return (struct nouveau_bufctx_priv *)bctx; +} + +drm_public int +nouveau_bufctx_new(struct nouveau_client *client, int bins, + struct nouveau_bufctx **pbctx) +{ + struct nouveau_bufctx_priv *priv; + + priv = calloc(1, sizeof(*priv) + sizeof(priv->bins[0]) * bins); + if (priv) { + DRMINITLISTHEAD(&priv->base.head); + DRMINITLISTHEAD(&priv->base.pending); + DRMINITLISTHEAD(&priv->base.current); + priv->base.client = client; + priv->nr_bins = bins; + *pbctx = &priv->base; + return 0; + } + + return -ENOMEM; +} + +drm_public void +nouveau_bufctx_del(struct nouveau_bufctx **pbctx) +{ + struct nouveau_bufctx_priv *pctx = nouveau_bufctx(*pbctx); + struct nouveau_bufref_priv *pref; + if (pctx) { + while (pctx->nr_bins--) + nouveau_bufctx_reset(&pctx->base, pctx->nr_bins); + while ((pref = pctx->free)) { + pctx->free = pref->next; + free(pref); + } + free(pctx); + *pbctx = NULL; + } +} + +drm_public void +nouveau_bufctx_reset(struct nouveau_bufctx *bctx, int bin) +{ + struct nouveau_bufctx_priv *pctx = nouveau_bufctx(bctx); + struct nouveau_bufbin_priv *pbin = &pctx->bins[bin]; + struct nouveau_bufref_priv *pref; + + while ((pref = pbin->list)) { + DRMLISTDELINIT(&pref->base.thead); + pbin->list = pref->next; + pref->next = pctx->free; + pctx->free = pref; + } + + bctx->relocs -= pbin->relocs; + pbin->relocs = 0; +} + +drm_public struct nouveau_bufref * +nouveau_bufctx_refn(struct nouveau_bufctx *bctx, int bin, + struct nouveau_bo *bo, uint32_t flags) +{ + struct nouveau_bufctx_priv *pctx = nouveau_bufctx(bctx); + struct nouveau_bufbin_priv *pbin = &pctx->bins[bin]; + struct nouveau_bufref_priv *pref = pctx->free; + + if (!pref) + pref = malloc(sizeof(*pref)); + else + pctx->free = pref->next; + + if (pref) { + pref->base.bo = bo; + pref->base.flags = flags; + pref->base.packet = 0; + + DRMLISTADDTAIL(&pref->base.thead, &bctx->pending); + pref->bufctx = bctx; + pref->next = pbin->list; + pbin->list = pref; + } + + return &pref->base; +} + +drm_public struct nouveau_bufref * +nouveau_bufctx_mthd(struct nouveau_bufctx *bctx, int bin, uint32_t packet, + struct nouveau_bo *bo, uint64_t data, uint32_t flags, + uint32_t vor, uint32_t tor) +{ + struct nouveau_bufctx_priv *pctx = nouveau_bufctx(bctx); + struct nouveau_bufbin_priv *pbin = &pctx->bins[bin]; + struct nouveau_bufref *bref = nouveau_bufctx_refn(bctx, bin, bo, flags); + if (bref) { + bref->packet = packet; + bref->data = data; + bref->vor = vor; + bref->tor = tor; + pbin->relocs++; + bctx->relocs++; + } + return bref; +} diff --git a/nouveau/libdrm_nouveau.pc.in b/nouveau/libdrm_nouveau.pc.in new file mode 100644 index 0000000..7d0622e --- /dev/null +++ b/nouveau/libdrm_nouveau.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libdrm_nouveau +Description: Userspace interface to nouveau kernel DRM services +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -ldrm_nouveau +Cflags: -I${includedir} -I${includedir}/libdrm -I${includedir}/libdrm/nouveau +Requires.private: libdrm diff --git a/nouveau/meson.build b/nouveau/meson.build new file mode 100644 index 0000000..350f34c --- /dev/null +++ b/nouveau/meson.build @@ -0,0 +1,65 @@ +# Copyright © 2017-2018 Intel Corporation + +# 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. + + +libdrm_nouveau = library( + 'drm_nouveau', + [files( 'nouveau.c', 'pushbuf.c', 'bufctx.c', 'abi16.c'), config_file], + c_args : libdrm_c_args, + gnu_symbol_visibility : 'hidden', + include_directories : [inc_root, inc_drm], + link_with : libdrm, + dependencies : [dep_threads, dep_atomic_ops], + version : '2.0.0', + install : true, +) + +ext_libdrm_nouveau = declare_dependency( + link_with : [libdrm, libdrm_nouveau], + include_directories : [inc_drm, include_directories('.')], +) + +if meson.version().version_compare('>= 0.54.0') + meson.override_dependency('libdrm_nouveau', ext_libdrm_nouveau) +endif + +install_headers('nouveau.h', subdir : 'libdrm/nouveau') +install_headers( + 'nvif/class.h', 'nvif/cl0080.h', 'nvif/cl9097.h', 'nvif/if0002.h', + 'nvif/if0003.h', 'nvif/ioctl.h', 'nvif/unpack.h', + subdir : 'libdrm/nouveau/nvif' +) + +pkg.generate( + libdrm_nouveau, + name : 'libdrm_nouveau', + subdirs : ['.', 'libdrm', 'libdrm/nouveau'], + description : 'Userspace interface to nouveau kernel DRM services', +) + +test( + 'nouveau-symbols-check', + symbols_check, + args : [ + '--lib', libdrm_nouveau, + '--symbols-file', files('nouveau-symbols.txt'), + '--nm', prog_nm.path(), + ], +) diff --git a/nouveau/nouveau-symbols.txt b/nouveau/nouveau-symbols.txt new file mode 100644 index 0000000..598465f --- /dev/null +++ b/nouveau/nouveau-symbols.txt @@ -0,0 +1,42 @@ +nouveau_bo_map +nouveau_bo_name_get +nouveau_bo_name_ref +nouveau_bo_new +nouveau_bo_prime_handle_ref +nouveau_bo_ref +nouveau_bo_set_prime +nouveau_bo_wait +nouveau_bo_wrap +nouveau_bufctx_del +nouveau_bufctx_mthd +nouveau_bufctx_new +nouveau_bufctx_refn +nouveau_bufctx_reset +nouveau_check_dead_channel +nouveau_client_del +nouveau_client_new +nouveau_device_del +nouveau_device_new +nouveau_device_open +nouveau_device_open_existing +nouveau_device_wrap +nouveau_drm_del +nouveau_drm_new +nouveau_getparam +nouveau_object_del +nouveau_object_mclass +nouveau_object_mthd +nouveau_object_new +nouveau_object_sclass_get +nouveau_object_sclass_put +nouveau_pushbuf_bufctx +nouveau_pushbuf_data +nouveau_pushbuf_del +nouveau_pushbuf_kick +nouveau_pushbuf_new +nouveau_pushbuf_refd +nouveau_pushbuf_refn +nouveau_pushbuf_reloc +nouveau_pushbuf_space +nouveau_pushbuf_validate +nouveau_setparam diff --git a/nouveau/nouveau.c b/nouveau/nouveau.c new file mode 100644 index 0000000..7b4efde --- /dev/null +++ b/nouveau/nouveau.c @@ -0,0 +1,887 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + * Authors: Ben Skeggs + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "libdrm_macros.h" +#include "libdrm_lists.h" +#include "nouveau_drm.h" + +#include "nouveau.h" +#include "private.h" + +#include "nvif/class.h" +#include "nvif/cl0080.h" +#include "nvif/ioctl.h" +#include "nvif/unpack.h" + +drm_private FILE *nouveau_out = NULL; +drm_private uint32_t nouveau_debug = 0; + +static void +debug_init(void) +{ + static bool once = false; + char *debug, *out; + + if (once) + return; + once = true; + + debug = getenv("NOUVEAU_LIBDRM_DEBUG"); + if (debug) { + int n = strtol(debug, NULL, 0); + if (n >= 0) + nouveau_debug = n; + + } + + nouveau_out = stderr; + out = getenv("NOUVEAU_LIBDRM_OUT"); + if (out) { + FILE *fout = fopen(out, "w"); + if (fout) + nouveau_out = fout; + } +} + +static int +nouveau_object_ioctl(struct nouveau_object *obj, void *data, uint32_t size) +{ + struct nouveau_drm *drm = nouveau_drm(obj); + union { + struct nvif_ioctl_v0 v0; + } *args = data; + uint32_t argc = size; + int ret = -ENOSYS; + + if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { + if (!obj->length) { + if (obj != &drm->client) + args->v0.object = (unsigned long)(void *)obj; + else + args->v0.object = 0; + args->v0.owner = NVIF_IOCTL_V0_OWNER_ANY; + args->v0.route = 0x00; + } else { + args->v0.route = 0xff; + args->v0.token = obj->handle; + } + } else + return ret; + + return drmCommandWriteRead(drm->fd, DRM_NOUVEAU_NVIF, args, argc); +} + +drm_public int +nouveau_object_mthd(struct nouveau_object *obj, + uint32_t mthd, void *data, uint32_t size) +{ + struct nouveau_drm *drm = nouveau_drm(obj); + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_mthd_v0 mthd; + } *args; + uint32_t argc = sizeof(*args) + size; + uint8_t stack[128]; + int ret; + + if (!drm->nvif) + return -ENOSYS; + + if (argc > sizeof(stack)) { + if (!(args = malloc(argc))) + return -ENOMEM; + } else { + args = (void *)stack; + } + args->ioctl.version = 0; + args->ioctl.type = NVIF_IOCTL_V0_MTHD; + args->mthd.version = 0; + args->mthd.method = mthd; + + memcpy(args->mthd.data, data, size); + ret = nouveau_object_ioctl(obj, args, argc); + memcpy(data, args->mthd.data, size); + if (args != (void *)stack) + free(args); + return ret; +} + +drm_public void +nouveau_object_sclass_put(struct nouveau_sclass **psclass) +{ + free(*psclass); + *psclass = NULL; +} + +drm_public int +nouveau_object_sclass_get(struct nouveau_object *obj, + struct nouveau_sclass **psclass) +{ + struct nouveau_drm *drm = nouveau_drm(obj); + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_sclass_v0 sclass; + } *args = NULL; + struct nouveau_sclass *sclass; + int ret, cnt = 0, i; + uint32_t size; + + if (!drm->nvif) + return abi16_sclass(obj, psclass); + + while (1) { + size = sizeof(*args) + cnt * sizeof(args->sclass.oclass[0]); + if (!(args = malloc(size))) + return -ENOMEM; + args->ioctl.version = 0; + args->ioctl.type = NVIF_IOCTL_V0_SCLASS; + args->sclass.version = 0; + args->sclass.count = cnt; + + ret = nouveau_object_ioctl(obj, args, size); + if (ret == 0 && args->sclass.count <= cnt) + break; + cnt = args->sclass.count; + free(args); + if (ret != 0) + return ret; + } + + if ((sclass = calloc(args->sclass.count, sizeof(*sclass)))) { + for (i = 0; i < args->sclass.count; i++) { + sclass[i].oclass = args->sclass.oclass[i].oclass; + sclass[i].minver = args->sclass.oclass[i].minver; + sclass[i].maxver = args->sclass.oclass[i].maxver; + } + *psclass = sclass; + ret = args->sclass.count; + } else { + ret = -ENOMEM; + } + + free(args); + return ret; +} + +drm_public int +nouveau_object_mclass(struct nouveau_object *obj, + const struct nouveau_mclass *mclass) +{ + struct nouveau_sclass *sclass; + int ret = -ENODEV; + int cnt, i, j; + + cnt = nouveau_object_sclass_get(obj, &sclass); + if (cnt < 0) + return cnt; + + for (i = 0; ret < 0 && mclass[i].oclass; i++) { + for (j = 0; j < cnt; j++) { + if (mclass[i].oclass == sclass[j].oclass && + mclass[i].version >= sclass[j].minver && + mclass[i].version <= sclass[j].maxver) { + ret = i; + break; + } + } + } + + nouveau_object_sclass_put(&sclass); + return ret; +} + +static void +nouveau_object_fini(struct nouveau_object *obj) +{ + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_del del; + } args = { + .ioctl.type = NVIF_IOCTL_V0_DEL, + }; + + if (obj->data) { + abi16_delete(obj); + free(obj->data); + obj->data = NULL; + return; + } + + nouveau_object_ioctl(obj, &args, sizeof(args)); +} + +static int +nouveau_object_init(struct nouveau_object *parent, uint32_t handle, + int32_t oclass, void *data, uint32_t size, + struct nouveau_object *obj) +{ + struct nouveau_drm *drm = nouveau_drm(parent); + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_new_v0 new; + } *args; + uint32_t argc = sizeof(*args) + size; + int (*func)(struct nouveau_object *); + int ret = -ENOSYS; + + obj->parent = parent; + obj->handle = handle; + obj->oclass = oclass; + obj->length = 0; + obj->data = NULL; + + if (!abi16_object(obj, &func) && drm->nvif) { + if (!(args = malloc(argc))) + return -ENOMEM; + args->ioctl.version = 0; + args->ioctl.type = NVIF_IOCTL_V0_NEW; + args->new.version = 0; + args->new.route = NVIF_IOCTL_V0_ROUTE_NVIF; + args->new.token = (unsigned long)(void *)obj; + args->new.object = (unsigned long)(void *)obj; + args->new.handle = handle; + args->new.oclass = oclass; + memcpy(args->new.data, data, size); + ret = nouveau_object_ioctl(parent, args, argc); + memcpy(data, args->new.data, size); + free(args); + } else + if (func) { + obj->length = size ? size : sizeof(struct nouveau_object *); + if (!(obj->data = malloc(obj->length))) + return -ENOMEM; + if (data) + memcpy(obj->data, data, obj->length); + *(struct nouveau_object **)obj->data = obj; + + ret = func(obj); + } + + if (ret) { + nouveau_object_fini(obj); + return ret; + } + + return 0; +} + +drm_public int +nouveau_object_new(struct nouveau_object *parent, uint64_t handle, + uint32_t oclass, void *data, uint32_t length, + struct nouveau_object **pobj) +{ + struct nouveau_object *obj; + int ret; + + if (!(obj = malloc(sizeof(*obj)))) + return -ENOMEM; + + ret = nouveau_object_init(parent, handle, oclass, data, length, obj); + if (ret) { + free(obj); + return ret; + } + + *pobj = obj; + return 0; +} + +drm_public void +nouveau_object_del(struct nouveau_object **pobj) +{ + struct nouveau_object *obj = *pobj; + if (obj) { + nouveau_object_fini(obj); + free(obj); + *pobj = NULL; + } +} + +drm_public void +nouveau_drm_del(struct nouveau_drm **pdrm) +{ + free(*pdrm); + *pdrm = NULL; +} + +drm_public int +nouveau_drm_new(int fd, struct nouveau_drm **pdrm) +{ + struct nouveau_drm *drm; + drmVersionPtr ver; + + debug_init(); + + if (!(drm = calloc(1, sizeof(*drm)))) + return -ENOMEM; + drm->fd = fd; + + if (!(ver = drmGetVersion(fd))) { + nouveau_drm_del(&drm); + return -EINVAL; + } + *pdrm = drm; + + drm->version = (ver->version_major << 24) | + (ver->version_minor << 8) | + ver->version_patchlevel; + drm->nvif = (drm->version >= 0x01000301); + drmFreeVersion(ver); + return 0; +} + +/* this is the old libdrm's version of nouveau_device_wrap(), the symbol + * is kept here to prevent AIGLX from crashing if the DDX is linked against + * the new libdrm, but the DRI driver against the old + */ +drm_public int +nouveau_device_open_existing(struct nouveau_device **pdev, int close, int fd, + drm_context_t ctx) +{ + return -EACCES; +} + +drm_public int +nouveau_device_new(struct nouveau_object *parent, int32_t oclass, + void *data, uint32_t size, struct nouveau_device **pdev) +{ + struct nv_device_info_v0 info = {}; + union { + struct nv_device_v0 v0; + } *args = data; + uint32_t argc = size; + struct nouveau_drm *drm = nouveau_drm(parent); + struct nouveau_device_priv *nvdev; + struct nouveau_device *dev; + uint64_t v; + char *tmp; + int ret = -ENOSYS; + + if (oclass != NV_DEVICE || + nvif_unpack(ret, &data, &size, args->v0, 0, 0, false)) + return ret; + + if (!(nvdev = calloc(1, sizeof(*nvdev)))) + return -ENOMEM; + dev = *pdev = &nvdev->base; + dev->fd = -1; + + if (drm->nvif) { + ret = nouveau_object_init(parent, 0, oclass, args, argc, + &dev->object); + if (ret) + goto done; + + info.version = 0; + + ret = nouveau_object_mthd(&dev->object, NV_DEVICE_V0_INFO, + &info, sizeof(info)); + if (ret) + goto done; + + nvdev->base.chipset = info.chipset; + nvdev->have_bo_usage = true; + } else + if (args->v0.device == ~0ULL) { + nvdev->base.object.parent = &drm->client; + nvdev->base.object.handle = ~0ULL; + nvdev->base.object.oclass = NOUVEAU_DEVICE_CLASS; + nvdev->base.object.length = ~0; + + ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_CHIPSET_ID, &v); + if (ret) + goto done; + nvdev->base.chipset = v; + + ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_HAS_BO_USAGE, &v); + if (ret == 0) + nvdev->have_bo_usage = (v != 0); + } else + return -ENOSYS; + + ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_FB_SIZE, &v); + if (ret) + goto done; + nvdev->base.vram_size = v; + + ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_AGP_SIZE, &v); + if (ret) + goto done; + nvdev->base.gart_size = v; + + tmp = getenv("NOUVEAU_LIBDRM_VRAM_LIMIT_PERCENT"); + if (tmp) + nvdev->vram_limit_percent = atoi(tmp); + else + nvdev->vram_limit_percent = 80; + + nvdev->base.vram_limit = + (nvdev->base.vram_size * nvdev->vram_limit_percent) / 100; + + tmp = getenv("NOUVEAU_LIBDRM_GART_LIMIT_PERCENT"); + if (tmp) + nvdev->gart_limit_percent = atoi(tmp); + else + nvdev->gart_limit_percent = 80; + + nvdev->base.gart_limit = + (nvdev->base.gart_size * nvdev->gart_limit_percent) / 100; + + ret = pthread_mutex_init(&nvdev->lock, NULL); + DRMINITLISTHEAD(&nvdev->bo_list); +done: + if (ret) + nouveau_device_del(pdev); + return ret; +} + +drm_public int +nouveau_device_wrap(int fd, int close, struct nouveau_device **pdev) +{ + struct nouveau_drm *drm; + struct nouveau_device_priv *nvdev; + int ret; + + ret = nouveau_drm_new(fd, &drm); + if (ret) + return ret; + drm->nvif = false; + + ret = nouveau_device_new(&drm->client, NV_DEVICE, + &(struct nv_device_v0) { + .device = ~0ULL, + }, sizeof(struct nv_device_v0), pdev); + if (ret) { + nouveau_drm_del(&drm); + return ret; + } + + nvdev = nouveau_device(*pdev); + nvdev->base.fd = drm->fd; + nvdev->base.drm_version = drm->version; + nvdev->close = close; + return 0; +} + +drm_public int +nouveau_device_open(const char *busid, struct nouveau_device **pdev) +{ + int ret = -ENODEV, fd = drmOpen("nouveau", busid); + if (fd >= 0) { + ret = nouveau_device_wrap(fd, 1, pdev); + if (ret) + drmClose(fd); + } + return ret; +} + +drm_public void +nouveau_device_del(struct nouveau_device **pdev) +{ + struct nouveau_device_priv *nvdev = nouveau_device(*pdev); + if (nvdev) { + free(nvdev->client); + pthread_mutex_destroy(&nvdev->lock); + if (nvdev->base.fd >= 0) { + struct nouveau_drm *drm = + nouveau_drm(&nvdev->base.object); + nouveau_drm_del(&drm); + if (nvdev->close) + drmClose(nvdev->base.fd); + } + free(nvdev); + *pdev = NULL; + } +} + +drm_public int +nouveau_getparam(struct nouveau_device *dev, uint64_t param, uint64_t *value) +{ + struct nouveau_drm *drm = nouveau_drm(&dev->object); + struct drm_nouveau_getparam r = { .param = param }; + int fd = drm->fd, ret = + drmCommandWriteRead(fd, DRM_NOUVEAU_GETPARAM, &r, sizeof(r)); + *value = r.value; + return ret; +} + +drm_public int +nouveau_setparam(struct nouveau_device *dev, uint64_t param, uint64_t value) +{ + struct nouveau_drm *drm = nouveau_drm(&dev->object); + struct drm_nouveau_setparam r = { .param = param, .value = value }; + return drmCommandWrite(drm->fd, DRM_NOUVEAU_SETPARAM, &r, sizeof(r)); +} + +drm_public int +nouveau_client_new(struct nouveau_device *dev, struct nouveau_client **pclient) +{ + struct nouveau_device_priv *nvdev = nouveau_device(dev); + struct nouveau_client_priv *pcli; + int id = 0, i, ret = -ENOMEM; + uint32_t *clients; + + pthread_mutex_lock(&nvdev->lock); + + for (i = 0; i < nvdev->nr_client; i++) { + id = ffs(nvdev->client[i]) - 1; + if (id >= 0) + goto out; + } + + clients = realloc(nvdev->client, sizeof(uint32_t) * (i + 1)); + if (!clients) + goto unlock; + nvdev->client = clients; + nvdev->client[i] = 0; + nvdev->nr_client++; + +out: + pcli = calloc(1, sizeof(*pcli)); + if (pcli) { + nvdev->client[i] |= (1 << id); + pcli->base.device = dev; + pcli->base.id = (i * 32) + id; + ret = 0; + } + + *pclient = &pcli->base; + +unlock: + pthread_mutex_unlock(&nvdev->lock); + return ret; +} + +drm_public void +nouveau_client_del(struct nouveau_client **pclient) +{ + struct nouveau_client_priv *pcli = nouveau_client(*pclient); + struct nouveau_device_priv *nvdev; + if (pcli) { + int id = pcli->base.id; + nvdev = nouveau_device(pcli->base.device); + pthread_mutex_lock(&nvdev->lock); + nvdev->client[id / 32] &= ~(1 << (id % 32)); + pthread_mutex_unlock(&nvdev->lock); + free(pcli->kref); + free(pcli); + } +} + +static void +nouveau_bo_del(struct nouveau_bo *bo) +{ + struct nouveau_drm *drm = nouveau_drm(&bo->device->object); + struct nouveau_device_priv *nvdev = nouveau_device(bo->device); + struct nouveau_bo_priv *nvbo = nouveau_bo(bo); + + if (nvbo->head.next) { + pthread_mutex_lock(&nvdev->lock); + if (atomic_read(&nvbo->refcnt) == 0) { + DRMLISTDEL(&nvbo->head); + /* + * This bo has to be closed with the lock held because + * gem handles are not refcounted. If a shared bo is + * closed and re-opened in another thread a race + * against DRM_IOCTL_GEM_OPEN or drmPrimeFDToHandle + * might cause the bo to be closed accidentally while + * re-importing. + */ + drmCloseBufferHandle(drm->fd, bo->handle); + } + pthread_mutex_unlock(&nvdev->lock); + } else { + drmCloseBufferHandle(drm->fd, bo->handle); + } + if (bo->map) + drm_munmap(bo->map, bo->size); + free(nvbo); +} + +drm_public int +nouveau_bo_new(struct nouveau_device *dev, uint32_t flags, uint32_t align, + uint64_t size, union nouveau_bo_config *config, + struct nouveau_bo **pbo) +{ + struct nouveau_bo_priv *nvbo = calloc(1, sizeof(*nvbo)); + struct nouveau_bo *bo = &nvbo->base; + int ret; + + if (!nvbo) + return -ENOMEM; + atomic_set(&nvbo->refcnt, 1); + bo->device = dev; + bo->flags = flags; + bo->size = size; + + ret = abi16_bo_init(bo, align, config); + if (ret) { + free(nvbo); + return ret; + } + + *pbo = bo; + return 0; +} + +static int +nouveau_bo_wrap_locked(struct nouveau_device *dev, uint32_t handle, + struct nouveau_bo **pbo, int name) +{ + struct nouveau_drm *drm = nouveau_drm(&dev->object); + struct nouveau_device_priv *nvdev = nouveau_device(dev); + struct drm_nouveau_gem_info req = { .handle = handle }; + struct nouveau_bo_priv *nvbo; + int ret; + + DRMLISTFOREACHENTRY(nvbo, &nvdev->bo_list, head) { + if (nvbo->base.handle == handle) { + if (atomic_inc_return(&nvbo->refcnt) == 1) { + /* + * Uh oh, this bo is dead and someone else + * will free it, but because refcnt is + * now non-zero fortunately they won't + * call the ioctl to close the bo. + * + * Remove this bo from the list so other + * calls to nouveau_bo_wrap_locked will + * see our replacement nvbo. + */ + DRMLISTDEL(&nvbo->head); + if (!name) + name = nvbo->name; + break; + } + + *pbo = &nvbo->base; + return 0; + } + } + + ret = drmCommandWriteRead(drm->fd, DRM_NOUVEAU_GEM_INFO, + &req, sizeof(req)); + if (ret) + return ret; + + nvbo = calloc(1, sizeof(*nvbo)); + if (nvbo) { + atomic_set(&nvbo->refcnt, 1); + nvbo->base.device = dev; + abi16_bo_info(&nvbo->base, &req); + nvbo->name = name; + DRMLISTADD(&nvbo->head, &nvdev->bo_list); + *pbo = &nvbo->base; + return 0; + } + + return -ENOMEM; +} + +static void +nouveau_bo_make_global(struct nouveau_bo_priv *nvbo) +{ + if (!nvbo->head.next) { + struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device); + pthread_mutex_lock(&nvdev->lock); + if (!nvbo->head.next) + DRMLISTADD(&nvbo->head, &nvdev->bo_list); + pthread_mutex_unlock(&nvdev->lock); + } +} + +drm_public int +nouveau_bo_wrap(struct nouveau_device *dev, uint32_t handle, + struct nouveau_bo **pbo) +{ + struct nouveau_device_priv *nvdev = nouveau_device(dev); + int ret; + pthread_mutex_lock(&nvdev->lock); + ret = nouveau_bo_wrap_locked(dev, handle, pbo, 0); + pthread_mutex_unlock(&nvdev->lock); + return ret; +} + +drm_public int +nouveau_bo_name_ref(struct nouveau_device *dev, uint32_t name, + struct nouveau_bo **pbo) +{ + struct nouveau_drm *drm = nouveau_drm(&dev->object); + struct nouveau_device_priv *nvdev = nouveau_device(dev); + struct nouveau_bo_priv *nvbo; + struct drm_gem_open req = { .name = name }; + int ret; + + pthread_mutex_lock(&nvdev->lock); + DRMLISTFOREACHENTRY(nvbo, &nvdev->bo_list, head) { + if (nvbo->name == name) { + ret = nouveau_bo_wrap_locked(dev, nvbo->base.handle, + pbo, name); + pthread_mutex_unlock(&nvdev->lock); + return ret; + } + } + + ret = drmIoctl(drm->fd, DRM_IOCTL_GEM_OPEN, &req); + if (ret == 0) { + ret = nouveau_bo_wrap_locked(dev, req.handle, pbo, name); + } + + pthread_mutex_unlock(&nvdev->lock); + return ret; +} + +drm_public int +nouveau_bo_name_get(struct nouveau_bo *bo, uint32_t *name) +{ + struct drm_gem_flink req = { .handle = bo->handle }; + struct nouveau_drm *drm = nouveau_drm(&bo->device->object); + struct nouveau_bo_priv *nvbo = nouveau_bo(bo); + + *name = nvbo->name; + if (!*name) { + int ret = drmIoctl(drm->fd, DRM_IOCTL_GEM_FLINK, &req); + + if (ret) { + *name = 0; + return ret; + } + nvbo->name = *name = req.name; + + nouveau_bo_make_global(nvbo); + } + return 0; +} + +drm_public void +nouveau_bo_ref(struct nouveau_bo *bo, struct nouveau_bo **pref) +{ + struct nouveau_bo *ref = *pref; + if (bo) { + atomic_inc(&nouveau_bo(bo)->refcnt); + } + if (ref) { + if (atomic_dec_and_test(&nouveau_bo(ref)->refcnt)) + nouveau_bo_del(ref); + } + *pref = bo; +} + +drm_public int +nouveau_bo_prime_handle_ref(struct nouveau_device *dev, int prime_fd, + struct nouveau_bo **bo) +{ + struct nouveau_drm *drm = nouveau_drm(&dev->object); + struct nouveau_device_priv *nvdev = nouveau_device(dev); + int ret; + unsigned int handle; + + nouveau_bo_ref(NULL, bo); + + pthread_mutex_lock(&nvdev->lock); + ret = drmPrimeFDToHandle(drm->fd, prime_fd, &handle); + if (ret == 0) { + ret = nouveau_bo_wrap_locked(dev, handle, bo, 0); + } + pthread_mutex_unlock(&nvdev->lock); + return ret; +} + +drm_public int +nouveau_bo_set_prime(struct nouveau_bo *bo, int *prime_fd) +{ + struct nouveau_drm *drm = nouveau_drm(&bo->device->object); + struct nouveau_bo_priv *nvbo = nouveau_bo(bo); + int ret; + + ret = drmPrimeHandleToFD(drm->fd, nvbo->base.handle, DRM_CLOEXEC, prime_fd); + if (ret) + return ret; + + nouveau_bo_make_global(nvbo); + return 0; +} + +drm_public int +nouveau_bo_wait(struct nouveau_bo *bo, uint32_t access, + struct nouveau_client *client) +{ + struct nouveau_drm *drm = nouveau_drm(&bo->device->object); + struct nouveau_bo_priv *nvbo = nouveau_bo(bo); + struct drm_nouveau_gem_cpu_prep req; + struct nouveau_pushbuf *push; + int ret = 0; + + if (!(access & NOUVEAU_BO_RDWR)) + return 0; + + push = cli_push_get(client, bo); + if (push && push->channel) + nouveau_pushbuf_kick(push, push->channel); + + if (!nvbo->head.next && !(nvbo->access & NOUVEAU_BO_WR) && + !(access & NOUVEAU_BO_WR)) + return 0; + + req.handle = bo->handle; + req.flags = 0; + if (access & NOUVEAU_BO_WR) + req.flags |= NOUVEAU_GEM_CPU_PREP_WRITE; + if (access & NOUVEAU_BO_NOBLOCK) + req.flags |= NOUVEAU_GEM_CPU_PREP_NOWAIT; + + ret = drmCommandWrite(drm->fd, DRM_NOUVEAU_GEM_CPU_PREP, + &req, sizeof(req)); + if (ret == 0) + nvbo->access = 0; + return ret; +} + +drm_public int +nouveau_bo_map(struct nouveau_bo *bo, uint32_t access, + struct nouveau_client *client) +{ + struct nouveau_drm *drm = nouveau_drm(&bo->device->object); + struct nouveau_bo_priv *nvbo = nouveau_bo(bo); + if (bo->map == NULL) { + bo->map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, + MAP_SHARED, drm->fd, nvbo->map_handle); + if (bo->map == MAP_FAILED) { + bo->map = NULL; + return -errno; + } + } + return nouveau_bo_wait(bo, access, client); +} diff --git a/nouveau/nouveau.h b/nouveau/nouveau.h new file mode 100644 index 0000000..0c632fe --- /dev/null +++ b/nouveau/nouveau.h @@ -0,0 +1,280 @@ +#ifndef __NOUVEAU_H__ +#define __NOUVEAU_H__ + +#include +#include + +/* Supported class information, provided by the kernel */ +struct nouveau_sclass { + int32_t oclass; + int minver; + int maxver; +}; + +/* Client-provided array describing class versions that are desired. + * + * These are used to match against the kernel's list of supported classes. + */ +struct nouveau_mclass { + int32_t oclass; + int version; + void *data; +}; + +struct nouveau_object { + struct nouveau_object *parent; + uint64_t handle; + uint32_t oclass; + uint32_t length; /* deprecated */ + void *data; /* deprecated */ +}; + +int nouveau_object_new(struct nouveau_object *parent, uint64_t handle, + uint32_t oclass, void *data, uint32_t length, + struct nouveau_object **); +void nouveau_object_del(struct nouveau_object **); +int nouveau_object_mthd(struct nouveau_object *, uint32_t mthd, + void *data, uint32_t size); +int nouveau_object_sclass_get(struct nouveau_object *, + struct nouveau_sclass **); +void nouveau_object_sclass_put(struct nouveau_sclass **); +int nouveau_object_mclass(struct nouveau_object *, + const struct nouveau_mclass *); + +struct nouveau_drm { + struct nouveau_object client; + int fd; + uint32_t version; + bool nvif; +}; + +static inline struct nouveau_drm * +nouveau_drm(struct nouveau_object *obj) +{ + while (obj && obj->parent) + obj = obj->parent; + return (struct nouveau_drm *)obj; +} + +int nouveau_drm_new(int fd, struct nouveau_drm **); +void nouveau_drm_del(struct nouveau_drm **); + +struct nouveau_device { + struct nouveau_object object; + int fd; /* deprecated */ + uint32_t lib_version; /* deprecated */ + uint32_t drm_version; /* deprecated */ + uint32_t chipset; + uint64_t vram_size; + uint64_t gart_size; + uint64_t vram_limit; + uint64_t gart_limit; +}; + +int nouveau_device_new(struct nouveau_object *parent, int32_t oclass, + void *data, uint32_t size, struct nouveau_device **); +void nouveau_device_del(struct nouveau_device **); + +int nouveau_getparam(struct nouveau_device *, uint64_t param, uint64_t *value); +int nouveau_setparam(struct nouveau_device *, uint64_t param, uint64_t value); + +/* deprecated */ +int nouveau_device_wrap(int fd, int close, struct nouveau_device **); +int nouveau_device_open(const char *busid, struct nouveau_device **); + +struct nouveau_client { + struct nouveau_device *device; + int id; +}; + +int nouveau_client_new(struct nouveau_device *, struct nouveau_client **); +void nouveau_client_del(struct nouveau_client **); + +union nouveau_bo_config { + struct { +#define NV04_BO_16BPP 0x00000001 +#define NV04_BO_32BPP 0x00000002 +#define NV04_BO_ZETA 0x00000004 + uint32_t surf_flags; + uint32_t surf_pitch; + } nv04; + struct { + uint32_t memtype; + uint32_t tile_mode; + } nv50; + struct { + uint32_t memtype; + uint32_t tile_mode; + } nvc0; + uint32_t data[8]; +}; + +#define NOUVEAU_BO_VRAM 0x00000001 +#define NOUVEAU_BO_GART 0x00000002 +#define NOUVEAU_BO_APER (NOUVEAU_BO_VRAM | NOUVEAU_BO_GART) +#define NOUVEAU_BO_RD 0x00000100 +#define NOUVEAU_BO_WR 0x00000200 +#define NOUVEAU_BO_RDWR (NOUVEAU_BO_RD | NOUVEAU_BO_WR) +#define NOUVEAU_BO_NOBLOCK 0x00000400 +#define NOUVEAU_BO_LOW 0x00001000 +#define NOUVEAU_BO_HIGH 0x00002000 +#define NOUVEAU_BO_OR 0x00004000 +#define NOUVEAU_BO_MAP 0x80000000 +#define NOUVEAU_BO_CONTIG 0x40000000 +#define NOUVEAU_BO_NOSNOOP 0x20000000 +#define NOUVEAU_BO_COHERENT 0x10000000 + +struct nouveau_bo { + struct nouveau_device *device; + uint32_t handle; + uint64_t size; + uint32_t flags; + uint64_t offset; + void *map; + union nouveau_bo_config config; +}; + +int nouveau_bo_new(struct nouveau_device *, uint32_t flags, uint32_t align, + uint64_t size, union nouveau_bo_config *, + struct nouveau_bo **); +int nouveau_bo_wrap(struct nouveau_device *, uint32_t handle, + struct nouveau_bo **); +int nouveau_bo_name_ref(struct nouveau_device *v, uint32_t name, + struct nouveau_bo **); +int nouveau_bo_name_get(struct nouveau_bo *, uint32_t *name); +void nouveau_bo_ref(struct nouveau_bo *, struct nouveau_bo **); +int nouveau_bo_map(struct nouveau_bo *, uint32_t access, + struct nouveau_client *); +int nouveau_bo_wait(struct nouveau_bo *, uint32_t access, + struct nouveau_client *); +int nouveau_bo_prime_handle_ref(struct nouveau_device *, int prime_fd, + struct nouveau_bo **); +int nouveau_bo_set_prime(struct nouveau_bo *, int *prime_fd); + +struct nouveau_list { + struct nouveau_list *prev; + struct nouveau_list *next; +}; + +struct nouveau_bufref { + struct nouveau_list thead; + struct nouveau_bo *bo; + uint32_t packet; + uint32_t flags; + uint32_t data; + uint32_t vor; + uint32_t tor; + uint32_t priv_data; + void *priv; +}; + +struct nouveau_bufctx { + struct nouveau_client *client; + struct nouveau_list head; + struct nouveau_list pending; + struct nouveau_list current; + int relocs; +}; + +int nouveau_bufctx_new(struct nouveau_client *, int bins, + struct nouveau_bufctx **); +void nouveau_bufctx_del(struct nouveau_bufctx **); +struct nouveau_bufref * +nouveau_bufctx_refn(struct nouveau_bufctx *, int bin, + struct nouveau_bo *, uint32_t flags); +struct nouveau_bufref * +nouveau_bufctx_mthd(struct nouveau_bufctx *, int bin, uint32_t packet, + struct nouveau_bo *, uint64_t data, uint32_t flags, + uint32_t vor, uint32_t tor); +void nouveau_bufctx_reset(struct nouveau_bufctx *, int bin); + +struct nouveau_pushbuf_krec; +struct nouveau_pushbuf { + struct nouveau_client *client; + struct nouveau_object *channel; + struct nouveau_bufctx *bufctx; + void (*kick_notify)(struct nouveau_pushbuf *); + void *user_priv; + uint32_t rsvd_kick; + uint32_t flags; + uint32_t *cur; + uint32_t *end; +}; + +struct nouveau_pushbuf_refn { + struct nouveau_bo *bo; + uint32_t flags; +}; + +int nouveau_pushbuf_new(struct nouveau_client *, struct nouveau_object *chan, + int nr, uint32_t size, bool immediate, + struct nouveau_pushbuf **); +void nouveau_pushbuf_del(struct nouveau_pushbuf **); +int nouveau_pushbuf_space(struct nouveau_pushbuf *, uint32_t dwords, + uint32_t relocs, uint32_t pushes); +void nouveau_pushbuf_data(struct nouveau_pushbuf *, struct nouveau_bo *, + uint64_t offset, uint64_t length); +int nouveau_pushbuf_refn(struct nouveau_pushbuf *, + struct nouveau_pushbuf_refn *, int nr); +/* Emits a reloc into the push buffer at the current position, you *must* + * have previously added the referenced buffer to a buffer context, and + * validated it against the current push buffer. + */ +void nouveau_pushbuf_reloc(struct nouveau_pushbuf *, struct nouveau_bo *, + uint32_t data, uint32_t flags, + uint32_t vor, uint32_t tor); +int nouveau_pushbuf_validate(struct nouveau_pushbuf *); +uint32_t nouveau_pushbuf_refd(struct nouveau_pushbuf *, struct nouveau_bo *); +int nouveau_pushbuf_kick(struct nouveau_pushbuf *, struct nouveau_object *chan); +struct nouveau_bufctx * +nouveau_pushbuf_bufctx(struct nouveau_pushbuf *, struct nouveau_bufctx *); + +#define NOUVEAU_DEVICE_CLASS 0x80000000 +#define NOUVEAU_FIFO_CHANNEL_CLASS 0x80000001 +#define NOUVEAU_NOTIFIER_CLASS 0x80000002 + +struct nouveau_fifo { + struct nouveau_object *object; + uint32_t channel; + uint32_t pushbuf; + uint64_t unused1[3]; +}; + +struct nv04_fifo { + struct nouveau_fifo base; + uint32_t vram; + uint32_t gart; + uint32_t notify; +}; + +struct nvc0_fifo { + struct nouveau_fifo base; + uint32_t notify; +}; + +#define NVE0_FIFO_ENGINE_GR 0x00000001 +#define NVE0_FIFO_ENGINE_VP 0x00000002 +#define NVE0_FIFO_ENGINE_PPP 0x00000004 +#define NVE0_FIFO_ENGINE_BSP 0x00000008 +#define NVE0_FIFO_ENGINE_CE0 0x00000010 +#define NVE0_FIFO_ENGINE_CE1 0x00000020 +#define NVE0_FIFO_ENGINE_ENC 0x00000040 + +struct nve0_fifo { + struct { + struct nouveau_fifo base; + uint32_t notify; + }; + uint32_t engine; +}; + +struct nv04_notify { + struct nouveau_object *object; + uint32_t offset; + uint32_t length; +}; + +bool +nouveau_check_dead_channel(struct nouveau_drm *, struct nouveau_object *chan); + +#endif diff --git a/nouveau/nvif/cl0080.h b/nouveau/nvif/cl0080.h new file mode 100644 index 0000000..331620a --- /dev/null +++ b/nouveau/nvif/cl0080.h @@ -0,0 +1,45 @@ +#ifndef __NVIF_CL0080_H__ +#define __NVIF_CL0080_H__ + +struct nv_device_v0 { + __u8 version; + __u8 pad01[7]; + __u64 device; /* device identifier, ~0 for client default */ +}; + +#define NV_DEVICE_V0_INFO 0x00 +#define NV_DEVICE_V0_TIME 0x01 + +struct nv_device_info_v0 { + __u8 version; +#define NV_DEVICE_INFO_V0_IGP 0x00 +#define NV_DEVICE_INFO_V0_PCI 0x01 +#define NV_DEVICE_INFO_V0_AGP 0x02 +#define NV_DEVICE_INFO_V0_PCIE 0x03 +#define NV_DEVICE_INFO_V0_SOC 0x04 + __u8 platform; + __u16 chipset; /* from NV_PMC_BOOT_0 */ + __u8 revision; /* from NV_PMC_BOOT_0 */ +#define NV_DEVICE_INFO_V0_TNT 0x01 +#define NV_DEVICE_INFO_V0_CELSIUS 0x02 +#define NV_DEVICE_INFO_V0_KELVIN 0x03 +#define NV_DEVICE_INFO_V0_RANKINE 0x04 +#define NV_DEVICE_INFO_V0_CURIE 0x05 +#define NV_DEVICE_INFO_V0_TESLA 0x06 +#define NV_DEVICE_INFO_V0_FERMI 0x07 +#define NV_DEVICE_INFO_V0_KEPLER 0x08 +#define NV_DEVICE_INFO_V0_MAXWELL 0x09 + __u8 family; + __u8 pad06[2]; + __u64 ram_size; + __u64 ram_user; + char chip[16]; + char name[64]; +}; + +struct nv_device_time_v0 { + __u8 version; + __u8 pad01[7]; + __u64 time; +}; +#endif diff --git a/nouveau/nvif/cl9097.h b/nouveau/nvif/cl9097.h new file mode 100644 index 0000000..4057676 --- /dev/null +++ b/nouveau/nvif/cl9097.h @@ -0,0 +1,44 @@ +#ifndef __NVIF_CL9097_H__ +#define __NVIF_CL9097_H__ + +#define FERMI_A_ZBC_COLOR 0x00 +#define FERMI_A_ZBC_DEPTH 0x01 + +struct fermi_a_zbc_color_v0 { + __u8 version; +#define FERMI_A_ZBC_COLOR_V0_FMT_ZERO 0x01 +#define FERMI_A_ZBC_COLOR_V0_FMT_UNORM_ONE 0x02 +#define FERMI_A_ZBC_COLOR_V0_FMT_RF32_GF32_BF32_AF32 0x04 +#define FERMI_A_ZBC_COLOR_V0_FMT_R16_G16_B16_A16 0x08 +#define FERMI_A_ZBC_COLOR_V0_FMT_RN16_GN16_BN16_AN16 0x0c +#define FERMI_A_ZBC_COLOR_V0_FMT_RS16_GS16_BS16_AS16 0x10 +#define FERMI_A_ZBC_COLOR_V0_FMT_RU16_GU16_BU16_AU16 0x14 +#define FERMI_A_ZBC_COLOR_V0_FMT_RF16_GF16_BF16_AF16 0x16 +#define FERMI_A_ZBC_COLOR_V0_FMT_A8R8G8B8 0x18 +#define FERMI_A_ZBC_COLOR_V0_FMT_A8RL8GL8BL8 0x1c +#define FERMI_A_ZBC_COLOR_V0_FMT_A2B10G10R10 0x20 +#define FERMI_A_ZBC_COLOR_V0_FMT_AU2BU10GU10RU10 0x24 +#define FERMI_A_ZBC_COLOR_V0_FMT_A8B8G8R8 0x28 +#define FERMI_A_ZBC_COLOR_V0_FMT_A8BL8GL8RL8 0x2c +#define FERMI_A_ZBC_COLOR_V0_FMT_AN8BN8GN8RN8 0x30 +#define FERMI_A_ZBC_COLOR_V0_FMT_AS8BS8GS8RS8 0x34 +#define FERMI_A_ZBC_COLOR_V0_FMT_AU8BU8GU8RU8 0x38 +#define FERMI_A_ZBC_COLOR_V0_FMT_A2R10G10B10 0x3c +#define FERMI_A_ZBC_COLOR_V0_FMT_BF10GF11RF11 0x40 + __u8 format; + __u8 index; + __u8 pad03[5]; + __u32 ds[4]; + __u32 l2[4]; +}; + +struct fermi_a_zbc_depth_v0 { + __u8 version; +#define FERMI_A_ZBC_DEPTH_V0_FMT_FP32 0x01 + __u8 format; + __u8 index; + __u8 pad03[5]; + __u32 ds; + __u32 l2; +}; +#endif diff --git a/nouveau/nvif/class.h b/nouveau/nvif/class.h new file mode 100644 index 0000000..4179cd6 --- /dev/null +++ b/nouveau/nvif/class.h @@ -0,0 +1,141 @@ +#ifndef __NVIF_CLASS_H__ +#define __NVIF_CLASS_H__ + +/* these class numbers are made up by us, and not nvidia-assigned */ +#define NVIF_CLASS_CONTROL /* if0001.h */ -1 +#define NVIF_CLASS_PERFMON /* if0002.h */ -2 +#define NVIF_CLASS_PERFDOM /* if0003.h */ -3 +#define NVIF_CLASS_SW_NV04 /* if0004.h */ -4 +#define NVIF_CLASS_SW_NV10 /* if0005.h */ -5 +#define NVIF_CLASS_SW_NV50 /* if0005.h */ -6 +#define NVIF_CLASS_SW_GF100 /* if0005.h */ -7 + +/* the below match nvidia-assigned (either in hw, or sw) class numbers */ +#define NV_DEVICE /* cl0080.h */ 0x00000080 + +#define NV_DMA_FROM_MEMORY /* cl0002.h */ 0x00000002 +#define NV_DMA_TO_MEMORY /* cl0002.h */ 0x00000003 +#define NV_DMA_IN_MEMORY /* cl0002.h */ 0x0000003d + +#define FERMI_TWOD_A 0x0000902d + +#define FERMI_MEMORY_TO_MEMORY_FORMAT_A 0x00009039 + +#define KEPLER_INLINE_TO_MEMORY_A 0x0000a040 +#define KEPLER_INLINE_TO_MEMORY_B 0x0000a140 + +#define NV04_DISP /* cl0046.h */ 0x00000046 + +#define NV03_CHANNEL_DMA /* cl506b.h */ 0x0000006b +#define NV10_CHANNEL_DMA /* cl506b.h */ 0x0000006e +#define NV17_CHANNEL_DMA /* cl506b.h */ 0x0000176e +#define NV40_CHANNEL_DMA /* cl506b.h */ 0x0000406e +#define NV50_CHANNEL_DMA /* cl506e.h */ 0x0000506e +#define G82_CHANNEL_DMA /* cl826e.h */ 0x0000826e + +#define NV50_CHANNEL_GPFIFO /* cl506f.h */ 0x0000506f +#define G82_CHANNEL_GPFIFO /* cl826f.h */ 0x0000826f +#define FERMI_CHANNEL_GPFIFO /* cl906f.h */ 0x0000906f +#define KEPLER_CHANNEL_GPFIFO_A /* cla06f.h */ 0x0000a06f +#define MAXWELL_CHANNEL_GPFIFO_A /* cla06f.h */ 0x0000b06f + +#define NV50_DISP /* cl5070.h */ 0x00005070 +#define G82_DISP /* cl5070.h */ 0x00008270 +#define GT200_DISP /* cl5070.h */ 0x00008370 +#define GT214_DISP /* cl5070.h */ 0x00008570 +#define GT206_DISP /* cl5070.h */ 0x00008870 +#define GF110_DISP /* cl5070.h */ 0x00009070 +#define GK104_DISP /* cl5070.h */ 0x00009170 +#define GK110_DISP /* cl5070.h */ 0x00009270 +#define GM107_DISP /* cl5070.h */ 0x00009470 +#define GM204_DISP /* cl5070.h */ 0x00009570 + +#define NV31_MPEG 0x00003174 +#define G82_MPEG 0x00008274 + +#define NV74_VP2 0x00007476 + +#define NV50_DISP_CURSOR /* cl507a.h */ 0x0000507a +#define G82_DISP_CURSOR /* cl507a.h */ 0x0000827a +#define GT214_DISP_CURSOR /* cl507a.h */ 0x0000857a +#define GF110_DISP_CURSOR /* cl507a.h */ 0x0000907a +#define GK104_DISP_CURSOR /* cl507a.h */ 0x0000917a + +#define NV50_DISP_OVERLAY /* cl507b.h */ 0x0000507b +#define G82_DISP_OVERLAY /* cl507b.h */ 0x0000827b +#define GT214_DISP_OVERLAY /* cl507b.h */ 0x0000857b +#define GF110_DISP_OVERLAY /* cl507b.h */ 0x0000907b +#define GK104_DISP_OVERLAY /* cl507b.h */ 0x0000917b + +#define NV50_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000507c +#define G82_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000827c +#define GT200_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000837c +#define GT214_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000857c +#define GF110_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000907c +#define GK104_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000917c +#define GK110_DISP_BASE_CHANNEL_DMA /* cl507c.h */ 0x0000927c + +#define NV50_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000507d +#define G82_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000827d +#define GT200_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000837d +#define GT214_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000857d +#define GT206_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000887d +#define GF110_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000907d +#define GK104_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000917d +#define GK110_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000927d +#define GM107_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000947d +#define GM204_DISP_CORE_CHANNEL_DMA /* cl507d.h */ 0x0000957d + +#define NV50_DISP_OVERLAY_CHANNEL_DMA /* cl507e.h */ 0x0000507e +#define G82_DISP_OVERLAY_CHANNEL_DMA /* cl507e.h */ 0x0000827e +#define GT200_DISP_OVERLAY_CHANNEL_DMA /* cl507e.h */ 0x0000837e +#define GT214_DISP_OVERLAY_CHANNEL_DMA /* cl507e.h */ 0x0000857e +#define GF110_DISP_OVERLAY_CONTROL_DMA /* cl507e.h */ 0x0000907e +#define GK104_DISP_OVERLAY_CONTROL_DMA /* cl507e.h */ 0x0000917e + +#define FERMI_A /* cl9097.h */ 0x00009097 +#define FERMI_B /* cl9097.h */ 0x00009197 +#define FERMI_C /* cl9097.h */ 0x00009297 + +#define KEPLER_A /* cl9097.h */ 0x0000a097 +#define KEPLER_B /* cl9097.h */ 0x0000a197 +#define KEPLER_C /* cl9097.h */ 0x0000a297 + +#define MAXWELL_A /* cl9097.h */ 0x0000b097 +#define MAXWELL_B /* cl9097.h */ 0x0000b197 + +#define NV74_BSP 0x000074b0 + +#define GT212_MSVLD 0x000085b1 +#define IGT21A_MSVLD 0x000086b1 +#define G98_MSVLD 0x000088b1 +#define GF100_MSVLD 0x000090b1 +#define GK104_MSVLD 0x000095b1 + +#define GT212_MSPDEC 0x000085b2 +#define G98_MSPDEC 0x000088b2 +#define GF100_MSPDEC 0x000090b2 +#define GK104_MSPDEC 0x000095b2 + +#define GT212_MSPPP 0x000085b3 +#define G98_MSPPP 0x000088b3 +#define GF100_MSPPP 0x000090b3 + +#define G98_SEC 0x000088b4 + +#define GT212_DMA 0x000085b5 +#define FERMI_DMA 0x000090b5 +#define KEPLER_DMA_COPY_A 0x0000a0b5 +#define MAXWELL_DMA_COPY_A 0x0000b0b5 + +#define FERMI_DECOMPRESS 0x000090b8 + +#define FERMI_COMPUTE_A 0x000090c0 +#define FERMI_COMPUTE_B 0x000091c0 +#define KEPLER_COMPUTE_A 0x0000a0c0 +#define KEPLER_COMPUTE_B 0x0000a1c0 +#define MAXWELL_COMPUTE_A 0x0000b0c0 +#define MAXWELL_COMPUTE_B 0x0000b1c0 + +#define NV74_CIPHER 0x000074c1 +#endif diff --git a/nouveau/nvif/if0002.h b/nouveau/nvif/if0002.h new file mode 100644 index 0000000..c04c91d --- /dev/null +++ b/nouveau/nvif/if0002.h @@ -0,0 +1,38 @@ +#ifndef __NVIF_IF0002_H__ +#define __NVIF_IF0002_H__ + +#define NVIF_PERFMON_V0_QUERY_DOMAIN 0x00 +#define NVIF_PERFMON_V0_QUERY_SIGNAL 0x01 +#define NVIF_PERFMON_V0_QUERY_SOURCE 0x02 + +struct nvif_perfmon_query_domain_v0 { + __u8 version; + __u8 id; + __u8 counter_nr; + __u8 iter; + __u16 signal_nr; + __u8 pad05[2]; + char name[64]; +}; + +struct nvif_perfmon_query_signal_v0 { + __u8 version; + __u8 domain; + __u16 iter; + __u8 signal; + __u8 source_nr; + __u8 pad05[2]; + char name[64]; +}; + +struct nvif_perfmon_query_source_v0 { + __u8 version; + __u8 domain; + __u8 signal; + __u8 iter; + __u8 pad04[4]; + __u32 source; + __u32 mask; + char name[64]; +}; +#endif diff --git a/nouveau/nvif/if0003.h b/nouveau/nvif/if0003.h new file mode 100644 index 0000000..0cd03ef --- /dev/null +++ b/nouveau/nvif/if0003.h @@ -0,0 +1,33 @@ +#ifndef __NVIF_IF0003_H__ +#define __NVIF_IF0003_H__ + +struct nvif_perfdom_v0 { + __u8 version; + __u8 domain; + __u8 mode; + __u8 pad03[1]; + struct { + __u8 signal[4]; + __u64 source[4][8]; + __u16 logic_op; + } ctr[4]; +}; + +#define NVIF_PERFDOM_V0_INIT 0x00 +#define NVIF_PERFDOM_V0_SAMPLE 0x01 +#define NVIF_PERFDOM_V0_READ 0x02 + +struct nvif_perfdom_init { +}; + +struct nvif_perfdom_sample { +}; + +struct nvif_perfdom_read_v0 { + __u8 version; + __u8 pad01[7]; + __u32 ctr[4]; + __u32 clk; + __u8 pad04[4]; +}; +#endif diff --git a/nouveau/nvif/ioctl.h b/nouveau/nvif/ioctl.h new file mode 100644 index 0000000..c5f5eb8 --- /dev/null +++ b/nouveau/nvif/ioctl.h @@ -0,0 +1,132 @@ +#ifndef __NVIF_IOCTL_H__ +#define __NVIF_IOCTL_H__ + +#define NVIF_VERSION_LATEST 0x0000000000000000ULL + +struct nvif_ioctl_v0 { + __u8 version; +#define NVIF_IOCTL_V0_NOP 0x00 +#define NVIF_IOCTL_V0_SCLASS 0x01 +#define NVIF_IOCTL_V0_NEW 0x02 +#define NVIF_IOCTL_V0_DEL 0x03 +#define NVIF_IOCTL_V0_MTHD 0x04 +#define NVIF_IOCTL_V0_RD 0x05 +#define NVIF_IOCTL_V0_WR 0x06 +#define NVIF_IOCTL_V0_MAP 0x07 +#define NVIF_IOCTL_V0_UNMAP 0x08 +#define NVIF_IOCTL_V0_NTFY_NEW 0x09 +#define NVIF_IOCTL_V0_NTFY_DEL 0x0a +#define NVIF_IOCTL_V0_NTFY_GET 0x0b +#define NVIF_IOCTL_V0_NTFY_PUT 0x0c + __u8 type; + __u8 pad02[4]; +#define NVIF_IOCTL_V0_OWNER_NVIF 0x00 +#define NVIF_IOCTL_V0_OWNER_ANY 0xff + __u8 owner; +#define NVIF_IOCTL_V0_ROUTE_NVIF 0x00 +#define NVIF_IOCTL_V0_ROUTE_HIDDEN 0xff + __u8 route; + __u64 token; + __u64 object; + __u8 data[]; /* ioctl data (below) */ +}; + +struct nvif_ioctl_nop_v0 { + __u64 version; +}; + +struct nvif_ioctl_sclass_v0 { + /* nvif_ioctl ... */ + __u8 version; + __u8 count; + __u8 pad02[6]; + struct nvif_ioctl_sclass_oclass_v0 { + __s32 oclass; + __s16 minver; + __s16 maxver; + } oclass[]; +}; + +struct nvif_ioctl_new_v0 { + /* nvif_ioctl ... */ + __u8 version; + __u8 pad01[6]; + __u8 route; + __u64 token; + __u64 object; + __u32 handle; + __s32 oclass; + __u8 data[]; /* class data (class.h) */ +}; + +struct nvif_ioctl_del { +}; + +struct nvif_ioctl_rd_v0 { + /* nvif_ioctl ... */ + __u8 version; + __u8 size; + __u8 pad02[2]; + __u32 data; + __u64 addr; +}; + +struct nvif_ioctl_wr_v0 { + /* nvif_ioctl ... */ + __u8 version; + __u8 size; + __u8 pad02[2]; + __u32 data; + __u64 addr; +}; + +struct nvif_ioctl_map_v0 { + /* nvif_ioctl ... */ + __u8 version; + __u8 pad01[3]; + __u32 length; + __u64 handle; +}; + +struct nvif_ioctl_unmap { +}; + +struct nvif_ioctl_ntfy_new_v0 { + /* nvif_ioctl ... */ + __u8 version; + __u8 event; + __u8 index; + __u8 pad03[5]; + __u8 data[]; /* event request data (event.h) */ +}; + +struct nvif_ioctl_ntfy_del_v0 { + /* nvif_ioctl ... */ + __u8 version; + __u8 index; + __u8 pad02[6]; +}; + +struct nvif_ioctl_ntfy_get_v0 { + /* nvif_ioctl ... */ + __u8 version; + __u8 index; + __u8 pad02[6]; +}; + +struct nvif_ioctl_ntfy_put_v0 { + /* nvif_ioctl ... */ + __u8 version; + __u8 index; + __u8 pad02[6]; +}; + +struct nvif_ioctl_mthd_v0 { + /* nvif_ioctl ... */ + __u8 version; + __u8 method; + __u8 pad02[6]; + __u8 data[]; /* method data (class.h) */ +}; + +#endif diff --git a/nouveau/nvif/unpack.h b/nouveau/nvif/unpack.h new file mode 100644 index 0000000..751bcf4 --- /dev/null +++ b/nouveau/nvif/unpack.h @@ -0,0 +1,28 @@ +#ifndef __NVIF_UNPACK_H__ +#define __NVIF_UNPACK_H__ + +#define nvif_unvers(r,d,s,m) ({ \ + void **_data = (d); __u32 *_size = (s); int _ret = (r); \ + if (_ret == -ENOSYS && *_size == sizeof(m)) { \ + *_data = NULL; \ + *_size = _ret = 0; \ + } \ + _ret; \ +}) + +#define nvif_unpack(r,d,s,m,vl,vh,x) ({ \ + void **_data = (d); __u32 *_size = (s); \ + int _ret = (r), _vl = (vl), _vh = (vh); \ + if (_ret == -ENOSYS && *_size >= sizeof(m) && \ + (m).version >= _vl && (m).version <= _vh) { \ + *_data = (__u8 *)*_data + sizeof(m); \ + *_size = *_size - sizeof(m); \ + if (_ret = 0, !(x)) { \ + _ret = *_size ? -E2BIG : 0; \ + *_data = NULL; \ + *_size = 0; \ + } \ + } \ + _ret; \ +}) +#endif diff --git a/nouveau/private.h b/nouveau/private.h new file mode 100644 index 0000000..b81d4b1 --- /dev/null +++ b/nouveau/private.h @@ -0,0 +1,127 @@ +#ifndef __NOUVEAU_LIBDRM_PRIVATE_H__ +#define __NOUVEAU_LIBDRM_PRIVATE_H__ + +#include + +#include +#include +#include +#include +#include "nouveau_drm.h" + +#include "nouveau.h" + +/* + * 0x00000001 dump all pushbuffers + * 0x00000002 submit pushbuffers synchronously + * 0x80000000 if compiled with SIMULATE return -EINVAL for all pb submissions + */ +drm_private extern uint32_t nouveau_debug; +drm_private extern FILE *nouveau_out; +#define dbg_on(lvl) (nouveau_debug & (1 << lvl)) +#define dbg(lvl, fmt, args...) do { \ + if (dbg_on((lvl))) \ + fprintf(nouveau_out, "nouveau: "fmt, ##args); \ +} while(0) +#define err(fmt, args...) fprintf(nouveau_out, "nouveau: "fmt, ##args) + +struct nouveau_client_kref { + struct drm_nouveau_gem_pushbuf_bo *kref; + struct nouveau_pushbuf *push; +}; + +struct nouveau_client_priv { + struct nouveau_client base; + struct nouveau_client_kref *kref; + unsigned kref_nr; +}; + +static inline struct nouveau_client_priv * +nouveau_client(struct nouveau_client *client) +{ + return (struct nouveau_client_priv *)client; +} + +static inline struct drm_nouveau_gem_pushbuf_bo * +cli_kref_get(struct nouveau_client *client, struct nouveau_bo *bo) +{ + struct nouveau_client_priv *pcli = nouveau_client(client); + struct drm_nouveau_gem_pushbuf_bo *kref = NULL; + if (pcli->kref_nr > bo->handle) + kref = pcli->kref[bo->handle].kref; + return kref; +} + +static inline struct nouveau_pushbuf * +cli_push_get(struct nouveau_client *client, struct nouveau_bo *bo) +{ + struct nouveau_client_priv *pcli = nouveau_client(client); + struct nouveau_pushbuf *push = NULL; + if (pcli->kref_nr > bo->handle) + push = pcli->kref[bo->handle].push; + return push; +} + +static inline void +cli_kref_set(struct nouveau_client *client, struct nouveau_bo *bo, + struct drm_nouveau_gem_pushbuf_bo *kref, + struct nouveau_pushbuf *push) +{ + struct nouveau_client_priv *pcli = nouveau_client(client); + if (pcli->kref_nr <= bo->handle) { + pcli->kref = realloc(pcli->kref, + sizeof(*pcli->kref) * bo->handle * 2); + while (pcli->kref_nr < bo->handle * 2) { + pcli->kref[pcli->kref_nr].kref = NULL; + pcli->kref[pcli->kref_nr].push = NULL; + pcli->kref_nr++; + } + } + pcli->kref[bo->handle].kref = kref; + pcli->kref[bo->handle].push = push; +} + +struct nouveau_bo_priv { + struct nouveau_bo base; + struct nouveau_list head; + atomic_t refcnt; + uint64_t map_handle; + uint32_t name; + uint32_t access; +}; + +static inline struct nouveau_bo_priv * +nouveau_bo(struct nouveau_bo *bo) +{ + return (struct nouveau_bo_priv *)bo; +} + +struct nouveau_device_priv { + struct nouveau_device base; + int close; + pthread_mutex_t lock; + struct nouveau_list bo_list; + uint32_t *client; + int nr_client; + bool have_bo_usage; + int gart_limit_percent, vram_limit_percent; +}; + +static inline struct nouveau_device_priv * +nouveau_device(struct nouveau_device *dev) +{ + return (struct nouveau_device_priv *)dev; +} + +int +nouveau_device_open_existing(struct nouveau_device **, int, int, drm_context_t); + +/* abi16.c */ +drm_private bool abi16_object(struct nouveau_object *, int (**)(struct nouveau_object *)); +drm_private void abi16_delete(struct nouveau_object *); +drm_private int abi16_sclass(struct nouveau_object *, struct nouveau_sclass **); +drm_private void abi16_bo_info(struct nouveau_bo *, struct drm_nouveau_gem_info *); +drm_private int abi16_bo_init(struct nouveau_bo *, uint32_t alignment, + union nouveau_bo_config *); + +#endif diff --git a/nouveau/pushbuf.c b/nouveau/pushbuf.c new file mode 100644 index 0000000..5d54f21 --- /dev/null +++ b/nouveau/pushbuf.c @@ -0,0 +1,800 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + * Authors: Ben Skeggs + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "libdrm_lists.h" +#include "nouveau_drm.h" + +#include "nouveau.h" +#include "private.h" + +struct nouveau_pushbuf_krec { + struct nouveau_pushbuf_krec *next; + struct drm_nouveau_gem_pushbuf_bo buffer[NOUVEAU_GEM_MAX_BUFFERS]; + struct drm_nouveau_gem_pushbuf_reloc reloc[NOUVEAU_GEM_MAX_RELOCS]; + struct drm_nouveau_gem_pushbuf_push push[NOUVEAU_GEM_MAX_PUSH]; + int nr_buffer; + int nr_reloc; + int nr_push; + uint64_t vram_used; + uint64_t gart_used; +}; + +struct nouveau_pushbuf_priv { + struct nouveau_pushbuf base; + struct nouveau_pushbuf_krec *list; + struct nouveau_pushbuf_krec *krec; + struct nouveau_list bctx_list; + struct nouveau_bo *bo; + uint32_t type; + uint32_t suffix0; + uint32_t suffix1; + uint32_t *ptr; + uint32_t *bgn; + int bo_next; + int bo_nr; + struct nouveau_bo *bos[]; +}; + +static inline struct nouveau_pushbuf_priv * +nouveau_pushbuf(struct nouveau_pushbuf *push) +{ + return (struct nouveau_pushbuf_priv *)push; +} + +static int pushbuf_validate(struct nouveau_pushbuf *, bool); +static int pushbuf_flush(struct nouveau_pushbuf *); + +static bool +pushbuf_kref_fits(struct nouveau_pushbuf *push, struct nouveau_bo *bo, + uint32_t *domains) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push); + struct nouveau_pushbuf_krec *krec = nvpb->krec; + struct nouveau_device *dev = push->client->device; + struct nouveau_bo *kbo; + struct drm_nouveau_gem_pushbuf_bo *kref; + int i; + + /* VRAM is the only valid domain. GART and VRAM|GART buffers + * are all accounted to GART, so if this doesn't fit in VRAM + * straight up, a flush is needed. + */ + if (*domains == NOUVEAU_GEM_DOMAIN_VRAM) { + if (krec->vram_used + bo->size > dev->vram_limit) + return false; + krec->vram_used += bo->size; + return true; + } + + /* GART or VRAM|GART buffer. Account both of these buffer types + * to GART only for the moment, which simplifies things. If the + * buffer can fit already, we're done here. + */ + if (krec->gart_used + bo->size <= dev->gart_limit) { + krec->gart_used += bo->size; + return true; + } + + /* Ran out of GART space, if it's a VRAM|GART buffer and it'll + * fit into available VRAM, turn it into a VRAM buffer + */ + if ((*domains & NOUVEAU_GEM_DOMAIN_VRAM) && + krec->vram_used + bo->size <= dev->vram_limit) { + *domains &= NOUVEAU_GEM_DOMAIN_VRAM; + krec->vram_used += bo->size; + return true; + } + + /* Still couldn't fit the buffer in anywhere, so as a last resort; + * scan the buffer list for VRAM|GART buffers and turn them into + * VRAM buffers until we have enough space in GART for this one + */ + kref = krec->buffer; + for (i = 0; i < krec->nr_buffer; i++, kref++) { + if (!(kref->valid_domains & NOUVEAU_GEM_DOMAIN_GART)) + continue; + + kbo = (void *)(unsigned long)kref->user_priv; + if (!(kref->valid_domains & NOUVEAU_GEM_DOMAIN_VRAM) || + krec->vram_used + kbo->size > dev->vram_limit) + continue; + + kref->valid_domains &= NOUVEAU_GEM_DOMAIN_VRAM; + krec->gart_used -= kbo->size; + krec->vram_used += kbo->size; + if (krec->gart_used + bo->size <= dev->gart_limit) { + krec->gart_used += bo->size; + return true; + } + } + + /* Couldn't resolve a placement, need to force a flush */ + return false; +} + +static struct drm_nouveau_gem_pushbuf_bo * +pushbuf_kref(struct nouveau_pushbuf *push, struct nouveau_bo *bo, + uint32_t flags) +{ + struct nouveau_device *dev = push->client->device; + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push); + struct nouveau_pushbuf_krec *krec = nvpb->krec; + struct nouveau_pushbuf *fpush; + struct drm_nouveau_gem_pushbuf_bo *kref; + uint32_t domains, domains_wr, domains_rd; + + domains = 0; + if (flags & NOUVEAU_BO_VRAM) + domains |= NOUVEAU_GEM_DOMAIN_VRAM; + if (flags & NOUVEAU_BO_GART) + domains |= NOUVEAU_GEM_DOMAIN_GART; + domains_wr = domains * !!(flags & NOUVEAU_BO_WR); + domains_rd = domains * !!(flags & NOUVEAU_BO_RD); + + /* if buffer is referenced on another pushbuf that is owned by the + * same client, we need to flush the other pushbuf first to ensure + * the correct ordering of commands + */ + fpush = cli_push_get(push->client, bo); + if (fpush && fpush != push) + pushbuf_flush(fpush); + + kref = cli_kref_get(push->client, bo); + if (kref) { + /* possible conflict in memory types - flush and retry */ + if (!(kref->valid_domains & domains)) + return NULL; + + /* VRAM|GART buffer turning into a VRAM buffer. Make sure + * it'll fit in VRAM and force a flush if not. + */ + if ((kref->valid_domains & NOUVEAU_GEM_DOMAIN_GART) && + ( domains == NOUVEAU_GEM_DOMAIN_VRAM)) { + if (krec->vram_used + bo->size > dev->vram_limit) + return NULL; + krec->vram_used += bo->size; + krec->gart_used -= bo->size; + } + + kref->valid_domains &= domains; + kref->write_domains |= domains_wr; + kref->read_domains |= domains_rd; + } else { + if (krec->nr_buffer == NOUVEAU_GEM_MAX_BUFFERS || + !pushbuf_kref_fits(push, bo, &domains)) + return NULL; + + kref = &krec->buffer[krec->nr_buffer++]; + kref->user_priv = (unsigned long)bo; + kref->handle = bo->handle; + kref->valid_domains = domains; + kref->write_domains = domains_wr; + kref->read_domains = domains_rd; + kref->presumed.valid = 1; + kref->presumed.offset = bo->offset; + if (bo->flags & NOUVEAU_BO_VRAM) + kref->presumed.domain = NOUVEAU_GEM_DOMAIN_VRAM; + else + kref->presumed.domain = NOUVEAU_GEM_DOMAIN_GART; + + cli_kref_set(push->client, bo, kref, push); + atomic_inc(&nouveau_bo(bo)->refcnt); + } + + return kref; +} + +static uint32_t +pushbuf_krel(struct nouveau_pushbuf *push, struct nouveau_bo *bo, + uint32_t data, uint32_t flags, uint32_t vor, uint32_t tor) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push); + struct nouveau_pushbuf_krec *krec = nvpb->krec; + struct drm_nouveau_gem_pushbuf_reloc *krel; + struct drm_nouveau_gem_pushbuf_bo *pkref; + struct drm_nouveau_gem_pushbuf_bo *bkref; + uint32_t reloc = data; + + pkref = cli_kref_get(push->client, nvpb->bo); + bkref = cli_kref_get(push->client, bo); + krel = &krec->reloc[krec->nr_reloc++]; + + assert(pkref); + assert(bkref); + krel->reloc_bo_index = pkref - krec->buffer; + krel->reloc_bo_offset = (push->cur - nvpb->ptr) * 4; + krel->bo_index = bkref - krec->buffer; + krel->flags = 0; + krel->data = data; + krel->vor = vor; + krel->tor = tor; + + if (flags & NOUVEAU_BO_LOW) { + reloc = (bkref->presumed.offset + data); + krel->flags |= NOUVEAU_GEM_RELOC_LOW; + } else + if (flags & NOUVEAU_BO_HIGH) { + reloc = (bkref->presumed.offset + data) >> 32; + krel->flags |= NOUVEAU_GEM_RELOC_HIGH; + } + if (flags & NOUVEAU_BO_OR) { + if (bkref->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM) + reloc |= vor; + else + reloc |= tor; + krel->flags |= NOUVEAU_GEM_RELOC_OR; + } + + return reloc; +} + +static void +pushbuf_dump(struct nouveau_pushbuf_krec *krec, int krec_id, int chid) +{ + struct drm_nouveau_gem_pushbuf_reloc *krel; + struct drm_nouveau_gem_pushbuf_push *kpsh; + struct drm_nouveau_gem_pushbuf_bo *kref; + struct nouveau_bo *bo; + uint32_t *bgn, *end; + int i; + + err("ch%d: krec %d pushes %d bufs %d relocs %d\n", chid, + krec_id, krec->nr_push, krec->nr_buffer, krec->nr_reloc); + + kref = krec->buffer; + for (i = 0; i < krec->nr_buffer; i++, kref++) { + bo = (void *)(uintptr_t)kref->user_priv; + err("ch%d: buf %08x %08x %08x %08x %08x %p 0x%"PRIx64" 0x%"PRIx64"\n", chid, i, + kref->handle, kref->valid_domains, + kref->read_domains, kref->write_domains, bo->map, bo->offset, bo->size); + } + + krel = krec->reloc; + for (i = 0; i < krec->nr_reloc; i++, krel++) { + err("ch%d: rel %08x %08x %08x %08x %08x %08x %08x\n", + chid, krel->reloc_bo_index, krel->reloc_bo_offset, + krel->bo_index, krel->flags, krel->data, + krel->vor, krel->tor); + } + + kpsh = krec->push; + for (i = 0; i < krec->nr_push; i++, kpsh++) { + kref = krec->buffer + kpsh->bo_index; + bo = (void *)(unsigned long)kref->user_priv; + bgn = (uint32_t *)((char *)bo->map + kpsh->offset); + end = bgn + ((kpsh->length & 0x7fffff) /4); + + err("ch%d: psh %s%08x %010llx %010llx\n", chid, + bo->map ? "" : "(unmapped) ", kpsh->bo_index, + (unsigned long long)kpsh->offset, + (unsigned long long)(kpsh->offset + kpsh->length)); + if (!bo->map) + continue; + while (bgn < end) + err("\t0x%08x\n", *bgn++); + } +} + +static int +pushbuf_submit(struct nouveau_pushbuf *push, struct nouveau_object *chan) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push); + struct nouveau_pushbuf_krec *krec = nvpb->list; + struct nouveau_device *dev = push->client->device; + struct nouveau_drm *drm = nouveau_drm(&dev->object); + struct drm_nouveau_gem_pushbuf_bo_presumed *info; + struct drm_nouveau_gem_pushbuf_bo *kref; + struct drm_nouveau_gem_pushbuf req; + struct nouveau_fifo *fifo = chan->data; + struct nouveau_bo *bo; + int krec_id = 0; + int ret = 0, i; + + if (chan->oclass != NOUVEAU_FIFO_CHANNEL_CLASS) + return -EINVAL; + + if (push->kick_notify) + push->kick_notify(push); + + nouveau_pushbuf_data(push, NULL, 0, 0); + + while (krec && krec->nr_push) { + req.channel = fifo->channel; + req.nr_buffers = krec->nr_buffer; + req.buffers = (uint64_t)(unsigned long)krec->buffer; + req.nr_relocs = krec->nr_reloc; + req.nr_push = krec->nr_push; + req.relocs = (uint64_t)(unsigned long)krec->reloc; + req.push = (uint64_t)(unsigned long)krec->push; + req.suffix0 = nvpb->suffix0; + req.suffix1 = nvpb->suffix1; + req.vram_available = 0; /* for valgrind */ + if (dbg_on(1)) + req.vram_available |= NOUVEAU_GEM_PUSHBUF_SYNC; + req.gart_available = 0; + + if (dbg_on(0)) + pushbuf_dump(krec, krec_id++, fifo->channel); + +#ifndef SIMULATE + ret = drmCommandWriteRead(drm->fd, DRM_NOUVEAU_GEM_PUSHBUF, + &req, sizeof(req)); + nvpb->suffix0 = req.suffix0; + nvpb->suffix1 = req.suffix1; + dev->vram_limit = (req.vram_available * + nouveau_device(dev)->vram_limit_percent) / 100; + dev->gart_limit = (req.gart_available * + nouveau_device(dev)->gart_limit_percent) / 100; +#else + if (dbg_on(31)) + ret = -EINVAL; +#endif + + if (ret) { + err("kernel rejected pushbuf: %s\n", strerror(-ret)); + pushbuf_dump(krec, krec_id++, fifo->channel); + break; + } + + kref = krec->buffer; + for (i = 0; i < krec->nr_buffer; i++, kref++) { + bo = (void *)(unsigned long)kref->user_priv; + + info = &kref->presumed; + if (!info->valid) { + bo->flags &= ~NOUVEAU_BO_APER; + if (info->domain == NOUVEAU_GEM_DOMAIN_VRAM) + bo->flags |= NOUVEAU_BO_VRAM; + else + bo->flags |= NOUVEAU_BO_GART; + bo->offset = info->offset; + } + + if (kref->write_domains) + nouveau_bo(bo)->access |= NOUVEAU_BO_WR; + if (kref->read_domains) + nouveau_bo(bo)->access |= NOUVEAU_BO_RD; + } + + krec = krec->next; + } + + return ret; +} + +static int +pushbuf_flush(struct nouveau_pushbuf *push) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push); + struct nouveau_pushbuf_krec *krec = nvpb->krec; + struct drm_nouveau_gem_pushbuf_bo *kref; + struct nouveau_bufctx *bctx, *btmp; + struct nouveau_bo *bo; + int ret = 0, i; + + if (push->channel) { + ret = pushbuf_submit(push, push->channel); + } else { + nouveau_pushbuf_data(push, NULL, 0, 0); + krec->next = malloc(sizeof(*krec)); + nvpb->krec = krec->next; + } + + kref = krec->buffer; + for (i = 0; i < krec->nr_buffer; i++, kref++) { + bo = (void *)(unsigned long)kref->user_priv; + cli_kref_set(push->client, bo, NULL, NULL); + if (push->channel) + nouveau_bo_ref(NULL, &bo); + } + + krec = nvpb->krec; + krec->vram_used = 0; + krec->gart_used = 0; + krec->nr_buffer = 0; + krec->nr_reloc = 0; + krec->nr_push = 0; + + DRMLISTFOREACHENTRYSAFE(bctx, btmp, &nvpb->bctx_list, head) { + DRMLISTJOIN(&bctx->current, &bctx->pending); + DRMINITLISTHEAD(&bctx->current); + DRMLISTDELINIT(&bctx->head); + } + + return ret; +} + +static void +pushbuf_refn_fail(struct nouveau_pushbuf *push, int sref, int srel) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push); + struct nouveau_pushbuf_krec *krec = nvpb->krec; + struct drm_nouveau_gem_pushbuf_bo *kref; + + kref = krec->buffer + sref; + while (krec->nr_buffer-- > sref) { + struct nouveau_bo *bo = (void *)(unsigned long)kref->user_priv; + cli_kref_set(push->client, bo, NULL, NULL); + nouveau_bo_ref(NULL, &bo); + kref++; + } + krec->nr_buffer = sref; + krec->nr_reloc = srel; +} + +static int +pushbuf_refn(struct nouveau_pushbuf *push, bool retry, + struct nouveau_pushbuf_refn *refs, int nr) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push); + struct nouveau_pushbuf_krec *krec = nvpb->krec; + struct drm_nouveau_gem_pushbuf_bo *kref; + int sref = krec->nr_buffer; + int ret = 0, i; + + for (i = 0; i < nr; i++) { + kref = pushbuf_kref(push, refs[i].bo, refs[i].flags); + if (!kref) { + ret = -ENOSPC; + break; + } + } + + if (ret) { + pushbuf_refn_fail(push, sref, krec->nr_reloc); + if (retry) { + pushbuf_flush(push); + nouveau_pushbuf_space(push, 0, 0, 0); + return pushbuf_refn(push, false, refs, nr); + } + } + + return ret; +} + +static int +pushbuf_validate(struct nouveau_pushbuf *push, bool retry) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push); + struct nouveau_pushbuf_krec *krec = nvpb->krec; + struct drm_nouveau_gem_pushbuf_bo *kref; + struct nouveau_bufctx *bctx = push->bufctx; + struct nouveau_bufref *bref; + int relocs = bctx ? bctx->relocs * 2: 0; + int sref, srel, ret; + + ret = nouveau_pushbuf_space(push, relocs, relocs, 0); + if (ret || bctx == NULL) + return ret; + + sref = krec->nr_buffer; + srel = krec->nr_reloc; + + DRMLISTDEL(&bctx->head); + DRMLISTADD(&bctx->head, &nvpb->bctx_list); + + DRMLISTFOREACHENTRY(bref, &bctx->pending, thead) { + kref = pushbuf_kref(push, bref->bo, bref->flags); + if (!kref) { + ret = -ENOSPC; + break; + } + + if (bref->packet) { + pushbuf_krel(push, bref->bo, bref->packet, 0, 0, 0); + *push->cur++ = 0; + pushbuf_krel(push, bref->bo, bref->data, bref->flags, + bref->vor, bref->tor); + *push->cur++ = 0; + } + } + + DRMLISTJOIN(&bctx->pending, &bctx->current); + DRMINITLISTHEAD(&bctx->pending); + + if (ret) { + pushbuf_refn_fail(push, sref, srel); + if (retry) { + pushbuf_flush(push); + return pushbuf_validate(push, false); + } + } + + return ret; +} + +drm_public int +nouveau_pushbuf_new(struct nouveau_client *client, struct nouveau_object *chan, + int nr, uint32_t size, bool immediate, + struct nouveau_pushbuf **ppush) +{ + struct nouveau_drm *drm = nouveau_drm(&client->device->object); + struct nouveau_fifo *fifo = chan->data; + struct nouveau_pushbuf_priv *nvpb; + struct nouveau_pushbuf *push; + struct drm_nouveau_gem_pushbuf req = {}; + int ret; + + if (chan->oclass != NOUVEAU_FIFO_CHANNEL_CLASS) + return -EINVAL; + + /* nop pushbuf call, to get the current "return to main" sequence + * we need to append to the pushbuf on early chipsets + */ + req.channel = fifo->channel; + req.nr_push = 0; + ret = drmCommandWriteRead(drm->fd, DRM_NOUVEAU_GEM_PUSHBUF, + &req, sizeof(req)); + if (ret) + return ret; + + nvpb = calloc(1, sizeof(*nvpb) + nr * sizeof(*nvpb->bos)); + if (!nvpb) + return -ENOMEM; + +#ifndef SIMULATE + nvpb->suffix0 = req.suffix0; + nvpb->suffix1 = req.suffix1; +#else + nvpb->suffix0 = 0xffffffff; + nvpb->suffix1 = 0xffffffff; +#endif + nvpb->krec = calloc(1, sizeof(*nvpb->krec)); + nvpb->list = nvpb->krec; + if (!nvpb->krec) { + free(nvpb); + return -ENOMEM; + } + + push = &nvpb->base; + push->client = client; + push->channel = immediate ? chan : NULL; + push->flags = NOUVEAU_BO_RD; + if (fifo->pushbuf & NOUVEAU_GEM_DOMAIN_GART) { + push->flags |= NOUVEAU_BO_GART; + nvpb->type = NOUVEAU_BO_GART; + } else + if (fifo->pushbuf & NOUVEAU_GEM_DOMAIN_VRAM) { + push->flags |= NOUVEAU_BO_VRAM; + nvpb->type = NOUVEAU_BO_VRAM; + } + nvpb->type |= NOUVEAU_BO_MAP; + + for (nvpb->bo_nr = 0; nvpb->bo_nr < nr; nvpb->bo_nr++) { + ret = nouveau_bo_new(client->device, nvpb->type, 0, size, + NULL, &nvpb->bos[nvpb->bo_nr]); + if (ret) { + nouveau_pushbuf_del(&push); + return ret; + } + } + + DRMINITLISTHEAD(&nvpb->bctx_list); + *ppush = push; + return 0; +} + +drm_public void +nouveau_pushbuf_del(struct nouveau_pushbuf **ppush) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(*ppush); + if (nvpb) { + struct drm_nouveau_gem_pushbuf_bo *kref; + struct nouveau_pushbuf_krec *krec; + while ((krec = nvpb->list)) { + kref = krec->buffer; + while (krec->nr_buffer--) { + unsigned long priv = kref++->user_priv; + struct nouveau_bo *bo = (void *)priv; + cli_kref_set(nvpb->base.client, bo, NULL, NULL); + nouveau_bo_ref(NULL, &bo); + } + nvpb->list = krec->next; + free(krec); + } + while (nvpb->bo_nr--) + nouveau_bo_ref(NULL, &nvpb->bos[nvpb->bo_nr]); + nouveau_bo_ref(NULL, &nvpb->bo); + free(nvpb); + } + *ppush = NULL; +} + +drm_public struct nouveau_bufctx * +nouveau_pushbuf_bufctx(struct nouveau_pushbuf *push, struct nouveau_bufctx *ctx) +{ + struct nouveau_bufctx *prev = push->bufctx; + push->bufctx = ctx; + return prev; +} + +drm_public int +nouveau_pushbuf_space(struct nouveau_pushbuf *push, + uint32_t dwords, uint32_t relocs, uint32_t pushes) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push); + struct nouveau_pushbuf_krec *krec = nvpb->krec; + struct nouveau_client *client = push->client; + struct nouveau_bo *bo = NULL; + bool flushed = false; + int ret = 0; + + /* switch to next buffer if insufficient space in the current one */ + if (push->cur + dwords >= push->end) { + if (nvpb->bo_next < nvpb->bo_nr) { + nouveau_bo_ref(nvpb->bos[nvpb->bo_next++], &bo); + if (nvpb->bo_next == nvpb->bo_nr && push->channel) + nvpb->bo_next = 0; + } else { + ret = nouveau_bo_new(client->device, nvpb->type, 0, + nvpb->bos[0]->size, NULL, &bo); + if (ret) + return ret; + } + } + + /* make sure there's always enough space to queue up the pending + * data in the pushbuf proper + */ + pushes++; + + /* need to flush if we've run out of space on an immediate pushbuf, + * if the new buffer won't fit, or if the kernel push/reloc limits + * have been hit + */ + if ((bo && ( push->channel || + !pushbuf_kref(push, bo, push->flags))) || + krec->nr_reloc + relocs >= NOUVEAU_GEM_MAX_RELOCS || + krec->nr_push + pushes >= NOUVEAU_GEM_MAX_PUSH) { + if (nvpb->bo && krec->nr_buffer) + pushbuf_flush(push); + flushed = true; + } + + /* if necessary, switch to new buffer */ + if (bo) { + ret = nouveau_bo_map(bo, NOUVEAU_BO_WR, push->client); + if (ret) + return ret; + + nouveau_pushbuf_data(push, NULL, 0, 0); + nouveau_bo_ref(bo, &nvpb->bo); + nouveau_bo_ref(NULL, &bo); + + nvpb->bgn = nvpb->bo->map; + nvpb->ptr = nvpb->bgn; + push->cur = nvpb->bgn; + push->end = push->cur + (nvpb->bo->size / 4); + push->end -= 2 + push->rsvd_kick; /* space for suffix */ + } + + pushbuf_kref(push, nvpb->bo, push->flags); + return flushed ? pushbuf_validate(push, false) : 0; +} + +drm_public void +nouveau_pushbuf_data(struct nouveau_pushbuf *push, struct nouveau_bo *bo, + uint64_t offset, uint64_t length) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push); + struct nouveau_pushbuf_krec *krec = nvpb->krec; + struct drm_nouveau_gem_pushbuf_push *kpsh; + struct drm_nouveau_gem_pushbuf_bo *kref; + + if (bo != nvpb->bo && nvpb->bgn != push->cur) { + if (nvpb->suffix0 || nvpb->suffix1) { + *push->cur++ = nvpb->suffix0; + *push->cur++ = nvpb->suffix1; + } + + nouveau_pushbuf_data(push, nvpb->bo, + (nvpb->bgn - nvpb->ptr) * 4, + (push->cur - nvpb->bgn) * 4); + nvpb->bgn = push->cur; + } + + if (bo) { + kref = cli_kref_get(push->client, bo); + assert(kref); + kpsh = &krec->push[krec->nr_push++]; + kpsh->bo_index = kref - krec->buffer; + kpsh->offset = offset; + kpsh->length = length; + } +} + +drm_public int +nouveau_pushbuf_refn(struct nouveau_pushbuf *push, + struct nouveau_pushbuf_refn *refs, int nr) +{ + return pushbuf_refn(push, true, refs, nr); +} + +drm_public void +nouveau_pushbuf_reloc(struct nouveau_pushbuf *push, struct nouveau_bo *bo, + uint32_t data, uint32_t flags, uint32_t vor, uint32_t tor) +{ + *push->cur = pushbuf_krel(push, bo, data, flags, vor, tor); + push->cur++; +} + +drm_public int +nouveau_pushbuf_validate(struct nouveau_pushbuf *push) +{ + return pushbuf_validate(push, true); +} + +drm_public uint32_t +nouveau_pushbuf_refd(struct nouveau_pushbuf *push, struct nouveau_bo *bo) +{ + struct drm_nouveau_gem_pushbuf_bo *kref; + uint32_t flags = 0; + + if (cli_push_get(push->client, bo) == push) { + kref = cli_kref_get(push->client, bo); + assert(kref); + if (kref->read_domains) + flags |= NOUVEAU_BO_RD; + if (kref->write_domains) + flags |= NOUVEAU_BO_WR; + } + + return flags; +} + +drm_public int +nouveau_pushbuf_kick(struct nouveau_pushbuf *push, struct nouveau_object *chan) +{ + if (!push->channel) + return pushbuf_submit(push, chan); + pushbuf_flush(push); + return pushbuf_validate(push, false); +} + +drm_public bool +nouveau_check_dead_channel(struct nouveau_drm *drm, struct nouveau_object *chan) +{ + struct drm_nouveau_gem_pushbuf req = {}; + struct nouveau_fifo *fifo = chan->data; + int ret; + + req.channel = fifo->channel; + req.nr_push = 0; + + ret = drmCommandWriteRead(drm->fd, DRM_NOUVEAU_GEM_PUSHBUF, + &req, sizeof(req)); + /* nouveau returns ENODEV once the channel was killed */ + return ret == -ENODEV; +} diff --git a/omap/Android.mk b/omap/Android.mk new file mode 100644 index 0000000..b25cca1 --- /dev/null +++ b/omap/Android.mk @@ -0,0 +1,13 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE := libdrm_omap +LOCAL_VENDOR_MODULE := true + +LOCAL_SRC_FILES := omap_drm.c + +LOCAL_SHARED_LIBRARIES := libdrm + +include $(LIBDRM_COMMON_MK) + +include $(BUILD_SHARED_LIBRARY) diff --git a/omap/libdrm_omap.pc.in b/omap/libdrm_omap.pc.in new file mode 100644 index 0000000..024533b --- /dev/null +++ b/omap/libdrm_omap.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libdrm_omap +Description: Userspace interface to omap kernel DRM services +Version: 0.6 +Libs: -L${libdir} -ldrm_omap +Cflags: -I${includedir} -I${includedir}/libdrm -I${includedir}/omap +Requires.private: libdrm diff --git a/omap/meson.build b/omap/meson.build new file mode 100644 index 0000000..2215918 --- /dev/null +++ b/omap/meson.build @@ -0,0 +1,61 @@ +# Copyright © 2017 Intel Corporation + +# 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. + +libdrm_omap = library( + 'drm_omap', + [files('omap_drm.c'), config_file], + include_directories : [inc_root, inc_drm], + c_args : libdrm_c_args, + gnu_symbol_visibility : 'hidden', + link_with : libdrm, + dependencies : [dep_pthread_stubs, dep_atomic_ops], + version : '1.0.0', + install : true, +) + +ext_libdrm_omap = declare_dependency( + link_with : [libdrm, libdrm_omap], + include_directories : [inc_drm, include_directories('.')], +) + +if meson.version().version_compare('>= 0.54.0') + meson.override_dependency('libdrm_omap', ext_libdrm_omap) +endif + +install_headers('omap_drmif.h', subdir : 'libdrm') +install_headers('omap_drm.h', subdir : 'omap') + +pkg.generate( + libdrm_omap, + name : 'libdrm_omap', + subdirs : ['.', 'libdrm', 'omap'], + version : '0.6', + description : 'Userspace interface to omap kernel DRM services', +) + +test( + 'omap-symbols-check', + symbols_check, + args : [ + '--lib', libdrm_omap, + '--symbols-file', files('omap-symbols.txt'), + '--nm', prog_nm.path(), + ], +) diff --git a/omap/omap-symbols.txt b/omap/omap-symbols.txt new file mode 100644 index 0000000..749d0f7 --- /dev/null +++ b/omap/omap-symbols.txt @@ -0,0 +1,18 @@ +omap_bo_cpu_fini +omap_bo_cpu_prep +omap_bo_del +omap_bo_dmabuf +omap_bo_from_dmabuf +omap_bo_from_name +omap_bo_get_name +omap_bo_handle +omap_bo_map +omap_bo_new +omap_bo_new_tiled +omap_bo_ref +omap_bo_size +omap_device_del +omap_device_new +omap_device_ref +omap_get_param +omap_set_param diff --git a/omap/omap_drm.c b/omap/omap_drm.c new file mode 100644 index 0000000..aa27366 --- /dev/null +++ b/omap/omap_drm.c @@ -0,0 +1,468 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2011 Texas Instruments, Inc + * + * 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 (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 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. + * + * Authors: + * Rob Clark + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "omap_drm.h" +#include "omap_drmif.h" + +#define __round_mask(x, y) ((__typeof__(x))((y)-1)) +#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) +#define PAGE_SIZE 4096 + +static pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER; +static void * dev_table; + +struct omap_device { + int fd; + atomic_t refcnt; + + /* The handle_table is used to track GEM bo handles associated w/ + * this fd. This is needed, in particular, when importing + * dmabuf's because we don't want multiple 'struct omap_bo's + * floating around with the same handle. Otherwise, when the + * first one is omap_bo_del()'d the handle becomes no longer + * valid, and the remaining 'struct omap_bo's are left pointing + * to an invalid handle (and possible a GEM bo that is already + * free'd). + */ + void *handle_table; +}; + +/* a GEM buffer object allocated from the DRM device */ +struct omap_bo { + struct omap_device *dev; + void *map; /* userspace mmap'ing (if there is one) */ + uint32_t size; + uint32_t handle; + uint32_t name; /* flink global handle (DRI2 name) */ + uint64_t offset; /* offset to mmap() */ + int fd; /* dmabuf handle */ + atomic_t refcnt; +}; + +static struct omap_device * omap_device_new_impl(int fd) +{ + struct omap_device *dev = calloc(sizeof(*dev), 1); + if (!dev) + return NULL; + dev->fd = fd; + atomic_set(&dev->refcnt, 1); + dev->handle_table = drmHashCreate(); + return dev; +} + +drm_public struct omap_device * omap_device_new(int fd) +{ + struct omap_device *dev = NULL; + + pthread_mutex_lock(&table_lock); + + if (!dev_table) + dev_table = drmHashCreate(); + + if (drmHashLookup(dev_table, fd, (void **)&dev)) { + /* not found, create new device */ + dev = omap_device_new_impl(fd); + drmHashInsert(dev_table, fd, dev); + } else { + /* found, just incr refcnt */ + dev = omap_device_ref(dev); + } + + pthread_mutex_unlock(&table_lock); + + return dev; +} + +drm_public struct omap_device * omap_device_ref(struct omap_device *dev) +{ + atomic_inc(&dev->refcnt); + return dev; +} + +drm_public void omap_device_del(struct omap_device *dev) +{ + if (!atomic_dec_and_test(&dev->refcnt)) + return; + pthread_mutex_lock(&table_lock); + drmHashDestroy(dev->handle_table); + drmHashDelete(dev_table, dev->fd); + pthread_mutex_unlock(&table_lock); + free(dev); +} + +drm_public int +omap_get_param(struct omap_device *dev, uint64_t param, uint64_t *value) +{ + struct drm_omap_param req = { + .param = param, + }; + int ret; + + ret = drmCommandWriteRead(dev->fd, DRM_OMAP_GET_PARAM, &req, sizeof(req)); + if (ret) { + return ret; + } + + *value = req.value; + + return 0; +} + +drm_public int +omap_set_param(struct omap_device *dev, uint64_t param, uint64_t value) +{ + struct drm_omap_param req = { + .param = param, + .value = value, + }; + return drmCommandWrite(dev->fd, DRM_OMAP_SET_PARAM, &req, sizeof(req)); +} + +/* lookup a buffer from it's handle, call w/ table_lock held: */ +static struct omap_bo * lookup_bo(struct omap_device *dev, + uint32_t handle) +{ + struct omap_bo *bo = NULL; + if (!drmHashLookup(dev->handle_table, handle, (void **)&bo)) { + /* found, incr refcnt and return: */ + bo = omap_bo_ref(bo); + } + return bo; +} + +/* allocate a new buffer object, call w/ table_lock held */ +static struct omap_bo * bo_from_handle(struct omap_device *dev, + uint32_t handle) +{ + struct omap_bo *bo = calloc(sizeof(*bo), 1); + if (!bo) { + drmCloseBufferHandle(dev->fd, handle); + return NULL; + } + bo->dev = omap_device_ref(dev); + bo->handle = handle; + bo->fd = -1; + atomic_set(&bo->refcnt, 1); + /* add ourselves to the handle table: */ + drmHashInsert(dev->handle_table, handle, bo); + return bo; +} + +/* allocate a new buffer object */ +static struct omap_bo * omap_bo_new_impl(struct omap_device *dev, + union omap_gem_size size, uint32_t flags) +{ + struct omap_bo *bo = NULL; + struct drm_omap_gem_new req = { + .size = size, + .flags = flags, + }; + + if (size.bytes == 0) { + goto fail; + } + + if (drmCommandWriteRead(dev->fd, DRM_OMAP_GEM_NEW, &req, sizeof(req))) { + goto fail; + } + + pthread_mutex_lock(&table_lock); + bo = bo_from_handle(dev, req.handle); + pthread_mutex_unlock(&table_lock); + + if (flags & OMAP_BO_TILED) { + bo->size = round_up(size.tiled.width, PAGE_SIZE) * size.tiled.height; + } else { + bo->size = size.bytes; + } + + return bo; + +fail: + free(bo); + return NULL; +} + + +/* allocate a new (un-tiled) buffer object */ +drm_public struct omap_bo * +omap_bo_new(struct omap_device *dev, uint32_t size, uint32_t flags) +{ + union omap_gem_size gsize = { + .bytes = size, + }; + if (flags & OMAP_BO_TILED) { + return NULL; + } + return omap_bo_new_impl(dev, gsize, flags); +} + +/* allocate a new buffer object */ +drm_public struct omap_bo * +omap_bo_new_tiled(struct omap_device *dev, uint32_t width, + uint32_t height, uint32_t flags) +{ + union omap_gem_size gsize = { + .tiled = { + .width = width, + .height = height, + }, + }; + if (!(flags & OMAP_BO_TILED)) { + return NULL; + } + return omap_bo_new_impl(dev, gsize, flags); +} + +drm_public struct omap_bo *omap_bo_ref(struct omap_bo *bo) +{ + atomic_inc(&bo->refcnt); + return bo; +} + +/* get buffer info */ +static int get_buffer_info(struct omap_bo *bo) +{ + struct drm_omap_gem_info req = { + .handle = bo->handle, + }; + int ret = drmCommandWriteRead(bo->dev->fd, DRM_OMAP_GEM_INFO, + &req, sizeof(req)); + if (ret) { + return ret; + } + + /* really all we need for now is mmap offset */ + bo->offset = req.offset; + bo->size = req.size; + + return 0; +} + +/* import a buffer object from DRI2 name */ +drm_public struct omap_bo * +omap_bo_from_name(struct omap_device *dev, uint32_t name) +{ + struct omap_bo *bo = NULL; + struct drm_gem_open req = { + .name = name, + }; + + pthread_mutex_lock(&table_lock); + + if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) { + goto fail; + } + + bo = lookup_bo(dev, req.handle); + if (!bo) { + bo = bo_from_handle(dev, req.handle); + bo->name = name; + } + + pthread_mutex_unlock(&table_lock); + + return bo; + +fail: + pthread_mutex_unlock(&table_lock); + free(bo); + return NULL; +} + +/* import a buffer from dmabuf fd, does not take ownership of the + * fd so caller should close() the fd when it is otherwise done + * with it (even if it is still using the 'struct omap_bo *') + */ +drm_public struct omap_bo * +omap_bo_from_dmabuf(struct omap_device *dev, int fd) +{ + struct omap_bo *bo = NULL; + struct drm_prime_handle req = { + .fd = fd, + }; + int ret; + + pthread_mutex_lock(&table_lock); + + ret = drmIoctl(dev->fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &req); + if (ret) { + goto fail; + } + + bo = lookup_bo(dev, req.handle); + if (!bo) { + bo = bo_from_handle(dev, req.handle); + } + + pthread_mutex_unlock(&table_lock); + + return bo; + +fail: + pthread_mutex_unlock(&table_lock); + free(bo); + return NULL; +} + +/* destroy a buffer object */ +drm_public void omap_bo_del(struct omap_bo *bo) +{ + if (!bo) { + return; + } + + if (!atomic_dec_and_test(&bo->refcnt)) + return; + + if (bo->map) { + munmap(bo->map, bo->size); + } + + if (bo->fd >= 0) { + close(bo->fd); + } + + if (bo->handle) { + pthread_mutex_lock(&table_lock); + drmHashDelete(bo->dev->handle_table, bo->handle); + drmCloseBufferHandle(bo->dev->fd, bo->handle); + pthread_mutex_unlock(&table_lock); + } + + omap_device_del(bo->dev); + + free(bo); +} + +/* get the global flink/DRI2 buffer name */ +drm_public int omap_bo_get_name(struct omap_bo *bo, uint32_t *name) +{ + if (!bo->name) { + struct drm_gem_flink req = { + .handle = bo->handle, + }; + int ret; + + ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req); + if (ret) { + return ret; + } + + bo->name = req.name; + } + + *name = bo->name; + + return 0; +} + +drm_public uint32_t omap_bo_handle(struct omap_bo *bo) +{ + return bo->handle; +} + +/* caller owns the dmabuf fd that is returned and is responsible + * to close() it when done + */ +drm_public int omap_bo_dmabuf(struct omap_bo *bo) +{ + if (bo->fd < 0) { + struct drm_prime_handle req = { + .handle = bo->handle, + .flags = DRM_CLOEXEC | DRM_RDWR, + }; + int ret; + + ret = drmIoctl(bo->dev->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &req); + if (ret) { + return ret; + } + + bo->fd = req.fd; + } + return dup(bo->fd); +} + +drm_public uint32_t omap_bo_size(struct omap_bo *bo) +{ + if (!bo->size) { + get_buffer_info(bo); + } + return bo->size; +} + +drm_public void *omap_bo_map(struct omap_bo *bo) +{ + if (!bo->map) { + if (!bo->offset) { + get_buffer_info(bo); + } + + bo->map = mmap(0, bo->size, PROT_READ | PROT_WRITE, + MAP_SHARED, bo->dev->fd, bo->offset); + if (bo->map == MAP_FAILED) { + bo->map = NULL; + } + } + return bo->map; +} + +drm_public int omap_bo_cpu_prep(struct omap_bo *bo, enum omap_gem_op op) +{ + struct drm_omap_gem_cpu_prep req = { + .handle = bo->handle, + .op = op, + }; + return drmCommandWrite(bo->dev->fd, + DRM_OMAP_GEM_CPU_PREP, &req, sizeof(req)); +} + +drm_public int omap_bo_cpu_fini(struct omap_bo *bo, enum omap_gem_op op) +{ + struct drm_omap_gem_cpu_fini req = { + .handle = bo->handle, + .op = op, + .nregions = 0, + }; + return drmCommandWrite(bo->dev->fd, + DRM_OMAP_GEM_CPU_FINI, &req, sizeof(req)); +} diff --git a/omap/omap_drm.h b/omap/omap_drm.h new file mode 100644 index 0000000..9c6c0e4 --- /dev/null +++ b/omap/omap_drm.h @@ -0,0 +1,135 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2011 Texas Instruments, Inc + * + * 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 (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 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. + * + * Authors: + * Rob Clark + */ + +#ifndef __OMAP_DRM_H__ +#define __OMAP_DRM_H__ + +#include +#include + +/* Please note that modifications to all structs defined here are + * subject to backwards-compatibility constraints. + */ + +#define OMAP_PARAM_CHIPSET_ID 1 /* ie. 0x3430, 0x4430, etc */ + +struct drm_omap_param { + uint64_t param; /* in */ + uint64_t value; /* in (set_param), out (get_param) */ +}; + +struct drm_omap_get_base { + char plugin_name[64]; /* in */ + uint32_t ioctl_base; /* out */ + uint32_t __pad; +}; + +#define OMAP_BO_SCANOUT 0x00000001 /* scanout capable (phys contiguous) */ +#define OMAP_BO_CACHE_MASK 0x00000006 /* cache type mask, see cache modes */ +#define OMAP_BO_TILED_MASK 0x00000f00 /* tiled mapping mask, see tiled modes */ + +/* cache modes */ +#define OMAP_BO_CACHED 0x00000000 /* default */ +#define OMAP_BO_WC 0x00000002 /* write-combine */ +#define OMAP_BO_UNCACHED 0x00000004 /* strongly-ordered (uncached) */ + +/* tiled modes */ +#define OMAP_BO_TILED_8 0x00000100 +#define OMAP_BO_TILED_16 0x00000200 +#define OMAP_BO_TILED_32 0x00000300 +#define OMAP_BO_TILED (OMAP_BO_TILED_8 | OMAP_BO_TILED_16 | OMAP_BO_TILED_32) + +union omap_gem_size { + uint32_t bytes; /* (for non-tiled formats) */ + struct { + uint16_t width; + uint16_t height; + } tiled; /* (for tiled formats) */ +}; + +struct drm_omap_gem_new { + union omap_gem_size size; /* in */ + uint32_t flags; /* in */ + uint32_t handle; /* out */ + uint32_t __pad; +}; + +/* mask of operations: */ +enum omap_gem_op { + OMAP_GEM_READ = 0x01, + OMAP_GEM_WRITE = 0x02, +}; + +struct drm_omap_gem_cpu_prep { + uint32_t handle; /* buffer handle (in) */ + uint32_t op; /* mask of omap_gem_op (in) */ +}; + +struct drm_omap_gem_cpu_fini { + uint32_t handle; /* buffer handle (in) */ + uint32_t op; /* mask of omap_gem_op (in) */ + /* TODO maybe here we pass down info about what regions are touched + * by sw so we can be clever about cache ops? For now a placeholder, + * set to zero and we just do full buffer flush.. + */ + uint32_t nregions; + uint32_t __pad; +}; + +struct drm_omap_gem_info { + uint32_t handle; /* buffer handle (in) */ + uint32_t pad; + uint64_t offset; /* mmap offset (out) */ + /* note: in case of tiled buffers, the user virtual size can be + * different from the physical size (ie. how many pages are needed + * to back the object) which is returned in DRM_IOCTL_GEM_OPEN.. + * This size here is the one that should be used if you want to + * mmap() the buffer: + */ + uint32_t size; /* virtual size for mmap'ing (out) */ + uint32_t __pad; +}; + +#define DRM_OMAP_GET_PARAM 0x00 +#define DRM_OMAP_SET_PARAM 0x01 +#define DRM_OMAP_GET_BASE 0x02 +#define DRM_OMAP_GEM_NEW 0x03 +#define DRM_OMAP_GEM_CPU_PREP 0x04 +#define DRM_OMAP_GEM_CPU_FINI 0x05 +#define DRM_OMAP_GEM_INFO 0x06 +#define DRM_OMAP_NUM_IOCTLS 0x07 + +#define DRM_IOCTL_OMAP_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_OMAP_GET_PARAM, struct drm_omap_param) +#define DRM_IOCTL_OMAP_SET_PARAM DRM_IOW (DRM_COMMAND_BASE + DRM_OMAP_SET_PARAM, struct drm_omap_param) +#define DRM_IOCTL_OMAP_GET_BASE DRM_IOWR(DRM_COMMAND_BASE + DRM_OMAP_GET_BASE, struct drm_omap_get_base) +#define DRM_IOCTL_OMAP_GEM_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_OMAP_GEM_NEW, struct drm_omap_gem_new) +#define DRM_IOCTL_OMAP_GEM_CPU_PREP DRM_IOW (DRM_COMMAND_BASE + DRM_OMAP_GEM_CPU_PREP, struct drm_omap_gem_cpu_prep) +#define DRM_IOCTL_OMAP_GEM_CPU_FINI DRM_IOW (DRM_COMMAND_BASE + DRM_OMAP_GEM_CPU_FINI, struct drm_omap_gem_cpu_fini) +#define DRM_IOCTL_OMAP_GEM_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_OMAP_GEM_INFO, struct drm_omap_gem_info) + +#endif /* __OMAP_DRM_H__ */ diff --git a/omap/omap_drmif.h b/omap/omap_drmif.h new file mode 100644 index 0000000..e62d127 --- /dev/null +++ b/omap/omap_drmif.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2011 Texas Instruments, Inc + * + * 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 (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 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. + * + * Authors: + * Rob Clark + */ + +#ifndef OMAP_DRMIF_H_ +#define OMAP_DRMIF_H_ + +#include +#include +#include + +struct omap_bo; +struct omap_device; + +/* device related functions: + */ + +struct omap_device * omap_device_new(int fd); +struct omap_device * omap_device_ref(struct omap_device *dev); +void omap_device_del(struct omap_device *dev); +int omap_get_param(struct omap_device *dev, uint64_t param, uint64_t *value); +int omap_set_param(struct omap_device *dev, uint64_t param, uint64_t value); + +/* buffer-object related functions: + */ + +struct omap_bo * omap_bo_new(struct omap_device *dev, + uint32_t size, uint32_t flags); +struct omap_bo * omap_bo_new_tiled(struct omap_device *dev, + uint32_t width, uint32_t height, uint32_t flags); +struct omap_bo * omap_bo_ref(struct omap_bo *bo); +struct omap_bo * omap_bo_from_name(struct omap_device *dev, uint32_t name); +struct omap_bo * omap_bo_from_dmabuf(struct omap_device *dev, int fd); +void omap_bo_del(struct omap_bo *bo); +int omap_bo_get_name(struct omap_bo *bo, uint32_t *name); +uint32_t omap_bo_handle(struct omap_bo *bo); +int omap_bo_dmabuf(struct omap_bo *bo); +uint32_t omap_bo_size(struct omap_bo *bo); +void * omap_bo_map(struct omap_bo *bo); +int omap_bo_cpu_prep(struct omap_bo *bo, enum omap_gem_op op); +int omap_bo_cpu_fini(struct omap_bo *bo, enum omap_gem_op op); + +#endif /* OMAP_DRMIF_H_ */ diff --git a/radeon/Android.mk b/radeon/Android.mk new file mode 100644 index 0000000..71040da --- /dev/null +++ b/radeon/Android.mk @@ -0,0 +1,14 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +# Import variables LIBDRM_RADEON_FILES, LIBDRM_RADEON_H_FILES +include $(LOCAL_PATH)/Makefile.sources + +LOCAL_MODULE := libdrm_radeon + +LOCAL_SHARED_LIBRARIES := libdrm + +LOCAL_SRC_FILES := $(LIBDRM_RADEON_FILES) + +include $(LIBDRM_COMMON_MK) +include $(BUILD_SHARED_LIBRARY) diff --git a/radeon/Makefile.sources b/radeon/Makefile.sources new file mode 100644 index 0000000..1cf482a --- /dev/null +++ b/radeon/Makefile.sources @@ -0,0 +1,21 @@ +LIBDRM_RADEON_FILES := \ + radeon_bo_gem.c \ + radeon_cs_gem.c \ + radeon_cs_space.c \ + radeon_bo.c \ + radeon_cs.c \ + radeon_surface.c + +LIBDRM_RADEON_H_FILES := \ + radeon_bo.h \ + radeon_cs.h \ + radeon_surface.h \ + radeon_bo_gem.h \ + radeon_cs_gem.h \ + radeon_bo_int.h \ + radeon_cs_int.h \ + r600_pci_ids.h + +LIBDRM_RADEON_BOF_FILES := \ + bof.c \ + bof.h diff --git a/radeon/bof.c b/radeon/bof.c new file mode 100644 index 0000000..0598cc6 --- /dev/null +++ b/radeon/bof.c @@ -0,0 +1,477 @@ +/* + * Copyright 2010 Jerome Glisse + * + * 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 + * on 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 + * THE AUTHOR(S) AND/OR THEIR 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. + * + * Authors: + * Jerome Glisse + */ +#include +#include +#include +#include "bof.h" + +/* + * helpers + */ +static int bof_entry_grow(bof_t *bof) +{ + bof_t **array; + + if (bof->array_size < bof->nentry) + return 0; + array = realloc(bof->array, (bof->nentry + 16) * sizeof(void*)); + if (array == NULL) + return -ENOMEM; + bof->array = array; + bof->nentry += 16; + return 0; +} + +/* + * object + */ +bof_t *bof_object(void) +{ + bof_t *object; + + object = calloc(1, sizeof(bof_t)); + if (object == NULL) + return NULL; + object->refcount = 1; + object->type = BOF_TYPE_OBJECT; + object->size = 12; + return object; +} + +bof_t *bof_object_get(bof_t *object, const char *keyname) +{ + unsigned i; + + for (i = 0; i < object->array_size; i += 2) { + if (!strcmp(object->array[i]->value, keyname)) { + return object->array[i + 1]; + } + } + return NULL; +} + +int bof_object_set(bof_t *object, const char *keyname, bof_t *value) +{ + bof_t *key; + int r; + + if (object->type != BOF_TYPE_OBJECT) + return -EINVAL; + r = bof_entry_grow(object); + if (r) + return r; + key = bof_string(keyname); + if (key == NULL) + return -ENOMEM; + object->array[object->array_size++] = key; + object->array[object->array_size++] = value; + object->size += value->size; + object->size += key->size; + bof_incref(value); + return 0; +} + +/* + * array + */ +bof_t *bof_array(void) +{ + bof_t *array = bof_object(); + + if (array == NULL) + return NULL; + array->type = BOF_TYPE_ARRAY; + array->size = 12; + return array; +} + +int bof_array_append(bof_t *array, bof_t *value) +{ + int r; + if (array->type != BOF_TYPE_ARRAY) + return -EINVAL; + r = bof_entry_grow(array); + if (r) + return r; + array->array[array->array_size++] = value; + array->size += value->size; + bof_incref(value); + return 0; +} + +bof_t *bof_array_get(bof_t *bof, unsigned i) +{ + if (!bof_is_array(bof) || i >= bof->array_size) + return NULL; + return bof->array[i]; +} + +unsigned bof_array_size(bof_t *bof) +{ + if (!bof_is_array(bof)) + return 0; + return bof->array_size; +} + +/* + * blob + */ +bof_t *bof_blob(unsigned size, void *value) +{ + bof_t *blob = bof_object(); + + if (blob == NULL) + return NULL; + blob->type = BOF_TYPE_BLOB; + blob->value = calloc(1, size); + if (blob->value == NULL) { + bof_decref(blob); + return NULL; + } + blob->size = size; + memcpy(blob->value, value, size); + blob->size += 12; + return blob; +} + +unsigned bof_blob_size(bof_t *bof) +{ + if (!bof_is_blob(bof)) + return 0; + return bof->size - 12; +} + +void *bof_blob_value(bof_t *bof) +{ + if (!bof_is_blob(bof)) + return NULL; + return bof->value; +} + +/* + * string + */ +bof_t *bof_string(const char *value) +{ + bof_t *string = bof_object(); + + if (string == NULL) + return NULL; + string->type = BOF_TYPE_STRING; + string->size = strlen(value) + 1; + string->value = calloc(1, string->size); + if (string->value == NULL) { + bof_decref(string); + return NULL; + } + strcpy(string->value, value); + string->size += 12; + return string; +} + +/* + * int32 + */ +bof_t *bof_int32(int32_t value) +{ + bof_t *int32 = bof_object(); + + if (int32 == NULL) + return NULL; + int32->type = BOF_TYPE_INT32; + int32->size = 4; + int32->value = calloc(1, int32->size); + if (int32->value == NULL) { + bof_decref(int32); + return NULL; + } + memcpy(int32->value, &value, 4); + int32->size += 12; + return int32; +} + +int32_t bof_int32_value(bof_t *bof) +{ + return *((uint32_t*)bof->value); +} + +/* + * common + */ +static void bof_indent(int level) +{ + int i; + + for (i = 0; i < level; i++) + fprintf(stderr, " "); +} + +static void bof_print_bof(bof_t *bof, int level, int entry) +{ + bof_indent(level); + if (bof == NULL) { + fprintf(stderr, "--NULL-- for entry %d\n", entry); + return; + } + switch (bof->type) { + case BOF_TYPE_STRING: + fprintf(stderr, "%p string [%s %d]\n", bof, (char*)bof->value, bof->size); + break; + case BOF_TYPE_INT32: + fprintf(stderr, "%p int32 [%d %d]\n", bof, *(int*)bof->value, bof->size); + break; + case BOF_TYPE_BLOB: + fprintf(stderr, "%p blob [%d]\n", bof, bof->size); + break; + case BOF_TYPE_NULL: + fprintf(stderr, "%p null [%d]\n", bof, bof->size); + break; + case BOF_TYPE_OBJECT: + fprintf(stderr, "%p object [%d %d]\n", bof, bof->array_size / 2, bof->size); + break; + case BOF_TYPE_ARRAY: + fprintf(stderr, "%p array [%d %d]\n", bof, bof->array_size, bof->size); + break; + default: + fprintf(stderr, "%p unknown [%d]\n", bof, bof->type); + return; + } +} + +static void bof_print_rec(bof_t *bof, int level, int entry) +{ + unsigned i; + + bof_print_bof(bof, level, entry); + for (i = 0; i < bof->array_size; i++) { + bof_print_rec(bof->array[i], level + 2, i); + } +} + +void bof_print(bof_t *bof) +{ + bof_print_rec(bof, 0, 0); +} + +static int bof_read(bof_t *root, FILE *file, long end, int level) +{ + bof_t *bof = NULL; + int r; + + if (ftell(file) >= end) { + return 0; + } + r = bof_entry_grow(root); + if (r) + return r; + bof = bof_object(); + if (bof == NULL) + return -ENOMEM; + bof->offset = ftell(file); + r = fread(&bof->type, 4, 1, file); + if (r != 1) + goto out_err; + r = fread(&bof->size, 4, 1, file); + if (r != 1) + goto out_err; + r = fread(&bof->array_size, 4, 1, file); + if (r != 1) + goto out_err; + switch (bof->type) { + case BOF_TYPE_STRING: + case BOF_TYPE_INT32: + case BOF_TYPE_BLOB: + bof->value = calloc(1, bof->size - 12); + if (bof->value == NULL) { + goto out_err; + } + r = fread(bof->value, bof->size - 12, 1, file); + if (r != 1) { + fprintf(stderr, "error reading %d\n", bof->size - 12); + goto out_err; + } + break; + case BOF_TYPE_NULL: + return 0; + case BOF_TYPE_OBJECT: + case BOF_TYPE_ARRAY: + r = bof_read(bof, file, bof->offset + bof->size, level + 2); + if (r) + goto out_err; + break; + default: + fprintf(stderr, "invalid type %d\n", bof->type); + goto out_err; + } + root->array[root->centry++] = bof; + return bof_read(root, file, end, level); +out_err: + bof_decref(bof); + return -EINVAL; +} + +bof_t *bof_load_file(const char *filename) +{ + bof_t *root = bof_object(); + int r; + + if (root == NULL) { + fprintf(stderr, "%s failed to create root object\n", __func__); + return NULL; + } + root->file = fopen(filename, "r"); + if (root->file == NULL) + goto out_err; + r = fseek(root->file, 0L, SEEK_SET); + if (r) { + fprintf(stderr, "%s failed to seek into file %s\n", __func__, filename); + goto out_err; + } + root->offset = ftell(root->file); + r = fread(&root->type, 4, 1, root->file); + if (r != 1) + goto out_err; + r = fread(&root->size, 4, 1, root->file); + if (r != 1) + goto out_err; + r = fread(&root->array_size, 4, 1, root->file); + if (r != 1) + goto out_err; + r = bof_read(root, root->file, root->offset + root->size, 2); + if (r) + goto out_err; + return root; +out_err: + bof_decref(root); + return NULL; +} + +void bof_incref(bof_t *bof) +{ + bof->refcount++; +} + +void bof_decref(bof_t *bof) +{ + unsigned i; + + if (bof == NULL) + return; + if (--bof->refcount > 0) + return; + for (i = 0; i < bof->array_size; i++) { + bof_decref(bof->array[i]); + bof->array[i] = NULL; + } + bof->array_size = 0; + if (bof->file) { + fclose(bof->file); + bof->file = NULL; + } + free(bof->array); + free(bof->value); + free(bof); +} + +static int bof_file_write(bof_t *bof, FILE *file) +{ + unsigned i; + int r; + + r = fwrite(&bof->type, 4, 1, file); + if (r != 1) + return -EINVAL; + r = fwrite(&bof->size, 4, 1, file); + if (r != 1) + return -EINVAL; + r = fwrite(&bof->array_size, 4, 1, file); + if (r != 1) + return -EINVAL; + switch (bof->type) { + case BOF_TYPE_NULL: + if (bof->size) + return -EINVAL; + break; + case BOF_TYPE_STRING: + case BOF_TYPE_INT32: + case BOF_TYPE_BLOB: + r = fwrite(bof->value, bof->size - 12, 1, file); + if (r != 1) + return -EINVAL; + break; + case BOF_TYPE_OBJECT: + case BOF_TYPE_ARRAY: + for (i = 0; i < bof->array_size; i++) { + r = bof_file_write(bof->array[i], file); + if (r) + return r; + } + break; + default: + return -EINVAL; + } + return 0; +} + +int bof_dump_file(bof_t *bof, const char *filename) +{ + unsigned i; + int r = 0; + + if (bof->file) { + fclose(bof->file); + bof->file = NULL; + } + bof->file = fopen(filename, "w"); + if (bof->file == NULL) { + fprintf(stderr, "%s failed to open file %s\n", __func__, filename); + r = -EINVAL; + goto out_err; + } + r = fseek(bof->file, 0L, SEEK_SET); + if (r) { + fprintf(stderr, "%s failed to seek into file %s\n", __func__, filename); + goto out_err; + } + r = fwrite(&bof->type, 4, 1, bof->file); + if (r != 1) + goto out_err; + r = fwrite(&bof->size, 4, 1, bof->file); + if (r != 1) + goto out_err; + r = fwrite(&bof->array_size, 4, 1, bof->file); + if (r != 1) + goto out_err; + for (i = 0; i < bof->array_size; i++) { + r = bof_file_write(bof->array[i], bof->file); + if (r) + return r; + } +out_err: + fclose(bof->file); + bof->file = NULL; + return r; +} diff --git a/radeon/bof.h b/radeon/bof.h new file mode 100644 index 0000000..014affb --- /dev/null +++ b/radeon/bof.h @@ -0,0 +1,90 @@ +/* + * Copyright 2010 Jerome Glisse + * + * 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 + * on 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 + * THE AUTHOR(S) AND/OR THEIR 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. + * + * Authors: + * Jerome Glisse + */ +#ifndef BOF_H +#define BOF_H + +#include +#include + +#define BOF_TYPE_STRING 0 +#define BOF_TYPE_NULL 1 +#define BOF_TYPE_BLOB 2 +#define BOF_TYPE_OBJECT 3 +#define BOF_TYPE_ARRAY 4 +#define BOF_TYPE_INT32 5 + +struct bof; + +typedef struct bof { + struct bof **array; + unsigned centry; + unsigned nentry; + unsigned refcount; + FILE *file; + uint32_t type; + uint32_t size; + uint32_t array_size; + void *value; + long offset; +} bof_t; + +extern int bof_file_flush(bof_t *root); +extern bof_t *bof_file_new(const char *filename); +extern int bof_object_dump(bof_t *object, const char *filename); + +/* object */ +extern bof_t *bof_object(void); +extern bof_t *bof_object_get(bof_t *object, const char *keyname); +extern int bof_object_set(bof_t *object, const char *keyname, bof_t *value); +/* array */ +extern bof_t *bof_array(void); +extern int bof_array_append(bof_t *array, bof_t *value); +extern bof_t *bof_array_get(bof_t *bof, unsigned i); +extern unsigned bof_array_size(bof_t *bof); +/* blob */ +extern bof_t *bof_blob(unsigned size, void *value); +extern unsigned bof_blob_size(bof_t *bof); +extern void *bof_blob_value(bof_t *bof); +/* string */ +extern bof_t *bof_string(const char *value); +/* int32 */ +extern bof_t *bof_int32(int32_t value); +extern int32_t bof_int32_value(bof_t *bof); +/* common functions */ +extern void bof_decref(bof_t *bof); +extern void bof_incref(bof_t *bof); +extern bof_t *bof_load_file(const char *filename); +extern int bof_dump_file(bof_t *bof, const char *filename); +extern void bof_print(bof_t *bof); + +static inline int bof_is_object(bof_t *bof){return (bof->type == BOF_TYPE_OBJECT);} +static inline int bof_is_blob(bof_t *bof){return (bof->type == BOF_TYPE_BLOB);} +static inline int bof_is_null(bof_t *bof){return (bof->type == BOF_TYPE_NULL);} +static inline int bof_is_int32(bof_t *bof){return (bof->type == BOF_TYPE_INT32);} +static inline int bof_is_array(bof_t *bof){return (bof->type == BOF_TYPE_ARRAY);} +static inline int bof_is_string(bof_t *bof){return (bof->type == BOF_TYPE_STRING);} + +#endif diff --git a/radeon/libdrm_radeon.pc.in b/radeon/libdrm_radeon.pc.in new file mode 100644 index 0000000..432993a --- /dev/null +++ b/radeon/libdrm_radeon.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libdrm_radeon +Description: Userspace interface to kernel DRM services for radeon +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -ldrm_radeon +Cflags: -I${includedir} -I${includedir}/libdrm +Requires.private: libdrm diff --git a/radeon/meson.build b/radeon/meson.build new file mode 100644 index 0000000..4c1c71e --- /dev/null +++ b/radeon/meson.build @@ -0,0 +1,70 @@ +# Copyright © 2017-2018 Intel Corporation + +# 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. + + +libdrm_radeon = library( + 'drm_radeon', + [ + files( + 'radeon_bo_gem.c', 'radeon_cs_gem.c', 'radeon_cs_space.c', 'radeon_bo.c', + 'radeon_cs.c', 'radeon_surface.c', + ), + config_file, + ], + c_args : libdrm_c_args, + gnu_symbol_visibility : 'hidden', + include_directories : [inc_root, inc_drm], + link_with : libdrm, + dependencies : [dep_pthread_stubs, dep_atomic_ops], + version : '1.0.1', + install : true, +) + +ext_libdrm_radeon = declare_dependency( + link_with : [libdrm, libdrm_radeon], + include_directories : [inc_drm, include_directories('.')], +) + +if meson.version().version_compare('>= 0.54.0') + meson.override_dependency('libdrm_radeon', ext_libdrm_radeon) +endif + +install_headers( + 'radeon_bo.h', 'radeon_cs.h', 'radeon_surface.h', 'radeon_bo_gem.h', + 'radeon_cs_gem.h', 'radeon_bo_int.h', 'radeon_cs_int.h', 'r600_pci_ids.h', + subdir : 'libdrm' +) + +pkg.generate( + libdrm_radeon, + name : 'libdrm_radeon', + subdirs : ['.', 'libdrm'], + description : 'Userspace interface to kernel DRM services for radeon', +) + +test( + 'radeon-symbols-check', + symbols_check, + args : [ + '--lib', libdrm_radeon, + '--symbols-file', files('radeon-symbols.txt'), + '--nm', prog_nm.path(), + ], +) diff --git a/radeon/r600_pci_ids.h b/radeon/r600_pci_ids.h new file mode 100644 index 0000000..a3b2eac --- /dev/null +++ b/radeon/r600_pci_ids.h @@ -0,0 +1,487 @@ +CHIPSET(0x9400, R600_9400, R600) +CHIPSET(0x9401, R600_9401, R600) +CHIPSET(0x9402, R600_9402, R600) +CHIPSET(0x9403, R600_9403, R600) +CHIPSET(0x9405, R600_9405, R600) +CHIPSET(0x940A, R600_940A, R600) +CHIPSET(0x940B, R600_940B, R600) +CHIPSET(0x940F, R600_940F, R600) + +CHIPSET(0x94C0, RV610_94C0, RV610) +CHIPSET(0x94C1, RV610_94C1, RV610) +CHIPSET(0x94C3, RV610_94C3, RV610) +CHIPSET(0x94C4, RV610_94C4, RV610) +CHIPSET(0x94C5, RV610_94C5, RV610) +CHIPSET(0x94C6, RV610_94C6, RV610) +CHIPSET(0x94C7, RV610_94C7, RV610) +CHIPSET(0x94C8, RV610_94C8, RV610) +CHIPSET(0x94C9, RV610_94C9, RV610) +CHIPSET(0x94CB, RV610_94CB, RV610) +CHIPSET(0x94CC, RV610_94CC, RV610) +CHIPSET(0x94CD, RV610_94CD, RV610) + +CHIPSET(0x9580, RV630_9580, RV630) +CHIPSET(0x9581, RV630_9581, RV630) +CHIPSET(0x9583, RV630_9583, RV630) +CHIPSET(0x9586, RV630_9586, RV630) +CHIPSET(0x9587, RV630_9587, RV630) +CHIPSET(0x9588, RV630_9588, RV630) +CHIPSET(0x9589, RV630_9589, RV630) +CHIPSET(0x958A, RV630_958A, RV630) +CHIPSET(0x958B, RV630_958B, RV630) +CHIPSET(0x958C, RV630_958C, RV630) +CHIPSET(0x958D, RV630_958D, RV630) +CHIPSET(0x958E, RV630_958E, RV630) +CHIPSET(0x958F, RV630_958F, RV630) + +CHIPSET(0x9500, RV670_9500, RV670) +CHIPSET(0x9501, RV670_9501, RV670) +CHIPSET(0x9504, RV670_9504, RV670) +CHIPSET(0x9505, RV670_9505, RV670) +CHIPSET(0x9506, RV670_9506, RV670) +CHIPSET(0x9507, RV670_9507, RV670) +CHIPSET(0x9508, RV670_9508, RV670) +CHIPSET(0x9509, RV670_9509, RV670) +CHIPSET(0x950F, RV670_950F, RV670) +CHIPSET(0x9511, RV670_9511, RV670) +CHIPSET(0x9515, RV670_9515, RV670) +CHIPSET(0x9517, RV670_9517, RV670) +CHIPSET(0x9519, RV670_9519, RV670) + +CHIPSET(0x95C0, RV620_95C0, RV620) +CHIPSET(0x95C2, RV620_95C2, RV620) +CHIPSET(0x95C4, RV620_95C4, RV620) +CHIPSET(0x95C5, RV620_95C5, RV620) +CHIPSET(0x95C6, RV620_95C6, RV620) +CHIPSET(0x95C7, RV620_95C7, RV620) +CHIPSET(0x95C9, RV620_95C9, RV620) +CHIPSET(0x95CC, RV620_95CC, RV620) +CHIPSET(0x95CD, RV620_95CD, RV620) +CHIPSET(0x95CE, RV620_95CE, RV620) +CHIPSET(0x95CF, RV620_95CF, RV620) + +CHIPSET(0x9590, RV635_9590, RV635) +CHIPSET(0x9591, RV635_9591, RV635) +CHIPSET(0x9593, RV635_9593, RV635) +CHIPSET(0x9595, RV635_9595, RV635) +CHIPSET(0x9596, RV635_9596, RV635) +CHIPSET(0x9597, RV635_9597, RV635) +CHIPSET(0x9598, RV635_9598, RV635) +CHIPSET(0x9599, RV635_9599, RV635) +CHIPSET(0x959B, RV635_959B, RV635) + +CHIPSET(0x9610, RS780_9610, RS780) +CHIPSET(0x9611, RS780_9611, RS780) +CHIPSET(0x9612, RS780_9612, RS780) +CHIPSET(0x9613, RS780_9613, RS780) +CHIPSET(0x9614, RS780_9614, RS780) +CHIPSET(0x9615, RS780_9615, RS780) +CHIPSET(0x9616, RS780_9616, RS780) + +CHIPSET(0x9710, RS880_9710, RS880) +CHIPSET(0x9711, RS880_9711, RS880) +CHIPSET(0x9712, RS880_9712, RS880) +CHIPSET(0x9713, RS880_9713, RS880) +CHIPSET(0x9714, RS880_9714, RS880) +CHIPSET(0x9715, RS880_9715, RS880) + +CHIPSET(0x9440, RV770_9440, RV770) +CHIPSET(0x9441, RV770_9441, RV770) +CHIPSET(0x9442, RV770_9442, RV770) +CHIPSET(0x9443, RV770_9443, RV770) +CHIPSET(0x9444, RV770_9444, RV770) +CHIPSET(0x9446, RV770_9446, RV770) +CHIPSET(0x944A, RV770_944A, RV770) +CHIPSET(0x944B, RV770_944B, RV770) +CHIPSET(0x944C, RV770_944C, RV770) +CHIPSET(0x944E, RV770_944E, RV770) +CHIPSET(0x9450, RV770_9450, RV770) +CHIPSET(0x9452, RV770_9452, RV770) +CHIPSET(0x9456, RV770_9456, RV770) +CHIPSET(0x945A, RV770_945A, RV770) +CHIPSET(0x945B, RV770_945B, RV770) +CHIPSET(0x945E, RV770_945E, RV770) +CHIPSET(0x9460, RV790_9460, RV770) +CHIPSET(0x9462, RV790_9462, RV770) +CHIPSET(0x946A, RV770_946A, RV770) +CHIPSET(0x946B, RV770_946B, RV770) +CHIPSET(0x947A, RV770_947A, RV770) +CHIPSET(0x947B, RV770_947B, RV770) + +CHIPSET(0x9480, RV730_9480, RV730) +CHIPSET(0x9487, RV730_9487, RV730) +CHIPSET(0x9488, RV730_9488, RV730) +CHIPSET(0x9489, RV730_9489, RV730) +CHIPSET(0x948A, RV730_948A, RV730) +CHIPSET(0x948F, RV730_948F, RV730) +CHIPSET(0x9490, RV730_9490, RV730) +CHIPSET(0x9491, RV730_9491, RV730) +CHIPSET(0x9495, RV730_9495, RV730) +CHIPSET(0x9498, RV730_9498, RV730) +CHIPSET(0x949C, RV730_949C, RV730) +CHIPSET(0x949E, RV730_949E, RV730) +CHIPSET(0x949F, RV730_949F, RV730) + +CHIPSET(0x9540, RV710_9540, RV710) +CHIPSET(0x9541, RV710_9541, RV710) +CHIPSET(0x9542, RV710_9542, RV710) +CHIPSET(0x954E, RV710_954E, RV710) +CHIPSET(0x954F, RV710_954F, RV710) +CHIPSET(0x9552, RV710_9552, RV710) +CHIPSET(0x9553, RV710_9553, RV710) +CHIPSET(0x9555, RV710_9555, RV710) +CHIPSET(0x9557, RV710_9557, RV710) +CHIPSET(0x955F, RV710_955F, RV710) + +CHIPSET(0x94A0, RV740_94A0, RV740) +CHIPSET(0x94A1, RV740_94A1, RV740) +CHIPSET(0x94A3, RV740_94A3, RV740) +CHIPSET(0x94B1, RV740_94B1, RV740) +CHIPSET(0x94B3, RV740_94B3, RV740) +CHIPSET(0x94B4, RV740_94B4, RV740) +CHIPSET(0x94B5, RV740_94B5, RV740) +CHIPSET(0x94B9, RV740_94B9, RV740) + +CHIPSET(0x68E0, CEDAR_68E0, CEDAR) +CHIPSET(0x68E1, CEDAR_68E1, CEDAR) +CHIPSET(0x68E4, CEDAR_68E4, CEDAR) +CHIPSET(0x68E5, CEDAR_68E5, CEDAR) +CHIPSET(0x68E8, CEDAR_68E8, CEDAR) +CHIPSET(0x68E9, CEDAR_68E9, CEDAR) +CHIPSET(0x68F1, CEDAR_68F1, CEDAR) +CHIPSET(0x68F2, CEDAR_68F2, CEDAR) +CHIPSET(0x68F8, CEDAR_68F8, CEDAR) +CHIPSET(0x68F9, CEDAR_68F9, CEDAR) +CHIPSET(0x68FA, CEDAR_68FA, CEDAR) +CHIPSET(0x68FE, CEDAR_68FE, CEDAR) + +CHIPSET(0x68C0, REDWOOD_68C0, REDWOOD) +CHIPSET(0x68C1, REDWOOD_68C1, REDWOOD) +CHIPSET(0x68C7, REDWOOD_68C7, REDWOOD) +CHIPSET(0x68C8, REDWOOD_68C8, REDWOOD) +CHIPSET(0x68C9, REDWOOD_68C9, REDWOOD) +CHIPSET(0x68D8, REDWOOD_68D8, REDWOOD) +CHIPSET(0x68D9, REDWOOD_68D9, REDWOOD) +CHIPSET(0x68DA, REDWOOD_68DA, REDWOOD) +CHIPSET(0x68DE, REDWOOD_68DE, REDWOOD) + +CHIPSET(0x68A0, JUNIPER_68A0, JUNIPER) +CHIPSET(0x68A1, JUNIPER_68A1, JUNIPER) +CHIPSET(0x68A8, JUNIPER_68A8, JUNIPER) +CHIPSET(0x68A9, JUNIPER_68A9, JUNIPER) +CHIPSET(0x68B0, JUNIPER_68B0, JUNIPER) +CHIPSET(0x68B8, JUNIPER_68B8, JUNIPER) +CHIPSET(0x68B9, JUNIPER_68B9, JUNIPER) +CHIPSET(0x68BA, JUNIPER_68BA, JUNIPER) +CHIPSET(0x68BE, JUNIPER_68BE, JUNIPER) +CHIPSET(0x68BF, JUNIPER_68BF, JUNIPER) + +CHIPSET(0x6880, CYPRESS_6880, CYPRESS) +CHIPSET(0x6888, CYPRESS_6888, CYPRESS) +CHIPSET(0x6889, CYPRESS_6889, CYPRESS) +CHIPSET(0x688A, CYPRESS_688A, CYPRESS) +CHIPSET(0x688C, CYPRESS_688C, CYPRESS) +CHIPSET(0x688D, CYPRESS_688D, CYPRESS) +CHIPSET(0x6898, CYPRESS_6898, CYPRESS) +CHIPSET(0x6899, CYPRESS_6899, CYPRESS) +CHIPSET(0x689B, CYPRESS_689B, CYPRESS) +CHIPSET(0x689E, CYPRESS_689E, CYPRESS) + +CHIPSET(0x689C, HEMLOCK_689C, HEMLOCK) +CHIPSET(0x689D, HEMLOCK_689D, HEMLOCK) + +CHIPSET(0x9802, PALM_9802, PALM) +CHIPSET(0x9803, PALM_9803, PALM) +CHIPSET(0x9804, PALM_9804, PALM) +CHIPSET(0x9805, PALM_9805, PALM) +CHIPSET(0x9806, PALM_9806, PALM) +CHIPSET(0x9807, PALM_9807, PALM) +CHIPSET(0x9808, PALM_9808, PALM) +CHIPSET(0x9809, PALM_9809, PALM) +CHIPSET(0x980A, PALM_980A, PALM) + +CHIPSET(0x9640, SUMO_9640, SUMO) +CHIPSET(0x9641, SUMO_9641, SUMO) +CHIPSET(0x9642, SUMO2_9642, SUMO2) +CHIPSET(0x9643, SUMO2_9643, SUMO2) +CHIPSET(0x9644, SUMO2_9644, SUMO2) +CHIPSET(0x9645, SUMO2_9645, SUMO2) +CHIPSET(0x9647, SUMO_9647, SUMO) +CHIPSET(0x9648, SUMO_9648, SUMO) +CHIPSET(0x9649, SUMO2_9649, SUMO2) +CHIPSET(0x964a, SUMO_964A, SUMO) +CHIPSET(0x964b, SUMO_964B, SUMO) +CHIPSET(0x964c, SUMO_964C, SUMO) +CHIPSET(0x964e, SUMO_964E, SUMO) +CHIPSET(0x964f, SUMO_964F, SUMO) + +CHIPSET(0x6700, CAYMAN_6700, CAYMAN) +CHIPSET(0x6701, CAYMAN_6701, CAYMAN) +CHIPSET(0x6702, CAYMAN_6702, CAYMAN) +CHIPSET(0x6703, CAYMAN_6703, CAYMAN) +CHIPSET(0x6704, CAYMAN_6704, CAYMAN) +CHIPSET(0x6705, CAYMAN_6705, CAYMAN) +CHIPSET(0x6706, CAYMAN_6706, CAYMAN) +CHIPSET(0x6707, CAYMAN_6707, CAYMAN) +CHIPSET(0x6708, CAYMAN_6708, CAYMAN) +CHIPSET(0x6709, CAYMAN_6709, CAYMAN) +CHIPSET(0x6718, CAYMAN_6718, CAYMAN) +CHIPSET(0x6719, CAYMAN_6719, CAYMAN) +CHIPSET(0x671C, CAYMAN_671C, CAYMAN) +CHIPSET(0x671D, CAYMAN_671D, CAYMAN) +CHIPSET(0x671F, CAYMAN_671F, CAYMAN) + +CHIPSET(0x6720, BARTS_6720, BARTS) +CHIPSET(0x6721, BARTS_6721, BARTS) +CHIPSET(0x6722, BARTS_6722, BARTS) +CHIPSET(0x6723, BARTS_6723, BARTS) +CHIPSET(0x6724, BARTS_6724, BARTS) +CHIPSET(0x6725, BARTS_6725, BARTS) +CHIPSET(0x6726, BARTS_6726, BARTS) +CHIPSET(0x6727, BARTS_6727, BARTS) +CHIPSET(0x6728, BARTS_6728, BARTS) +CHIPSET(0x6729, BARTS_6729, BARTS) +CHIPSET(0x6738, BARTS_6738, BARTS) +CHIPSET(0x6739, BARTS_6739, BARTS) +CHIPSET(0x673E, BARTS_673E, BARTS) + +CHIPSET(0x6740, TURKS_6740, TURKS) +CHIPSET(0x6741, TURKS_6741, TURKS) +CHIPSET(0x6742, TURKS_6742, TURKS) +CHIPSET(0x6743, TURKS_6743, TURKS) +CHIPSET(0x6744, TURKS_6744, TURKS) +CHIPSET(0x6745, TURKS_6745, TURKS) +CHIPSET(0x6746, TURKS_6746, TURKS) +CHIPSET(0x6747, TURKS_6747, TURKS) +CHIPSET(0x6748, TURKS_6748, TURKS) +CHIPSET(0x6749, TURKS_6749, TURKS) +CHIPSET(0x674A, TURKS_674A, TURKS) +CHIPSET(0x6750, TURKS_6750, TURKS) +CHIPSET(0x6751, TURKS_6751, TURKS) +CHIPSET(0x6758, TURKS_6758, TURKS) +CHIPSET(0x6759, TURKS_6759, TURKS) +CHIPSET(0x675B, TURKS_675B, TURKS) +CHIPSET(0x675D, TURKS_675D, TURKS) +CHIPSET(0x675F, TURKS_675F, TURKS) +CHIPSET(0x6840, TURKS_6840, TURKS) +CHIPSET(0x6841, TURKS_6841, TURKS) +CHIPSET(0x6842, TURKS_6842, TURKS) +CHIPSET(0x6843, TURKS_6843, TURKS) +CHIPSET(0x6849, TURKS_6849, TURKS) +CHIPSET(0x6850, TURKS_6850, TURKS) +CHIPSET(0x6858, TURKS_6858, TURKS) +CHIPSET(0x6859, TURKS_6859, TURKS) + +CHIPSET(0x6760, CAICOS_6760, CAICOS) +CHIPSET(0x6761, CAICOS_6761, CAICOS) +CHIPSET(0x6762, CAICOS_6762, CAICOS) +CHIPSET(0x6763, CAICOS_6763, CAICOS) +CHIPSET(0x6764, CAICOS_6764, CAICOS) +CHIPSET(0x6765, CAICOS_6765, CAICOS) +CHIPSET(0x6766, CAICOS_6766, CAICOS) +CHIPSET(0x6767, CAICOS_6767, CAICOS) +CHIPSET(0x6768, CAICOS_6768, CAICOS) +CHIPSET(0x6770, CAICOS_6770, CAICOS) +CHIPSET(0x6771, CAICOS_6771, CAICOS) +CHIPSET(0x6772, CAICOS_6772, CAICOS) +CHIPSET(0x6778, CAICOS_6778, CAICOS) +CHIPSET(0x6779, CAICOS_6779, CAICOS) +CHIPSET(0x677B, CAICOS_677B, CAICOS) + +CHIPSET(0x9900, ARUBA_9900, ARUBA) +CHIPSET(0x9901, ARUBA_9901, ARUBA) +CHIPSET(0x9903, ARUBA_9903, ARUBA) +CHIPSET(0x9904, ARUBA_9904, ARUBA) +CHIPSET(0x9905, ARUBA_9905, ARUBA) +CHIPSET(0x9906, ARUBA_9906, ARUBA) +CHIPSET(0x9907, ARUBA_9907, ARUBA) +CHIPSET(0x9908, ARUBA_9908, ARUBA) +CHIPSET(0x9909, ARUBA_9909, ARUBA) +CHIPSET(0x990A, ARUBA_990A, ARUBA) +CHIPSET(0x990B, ARUBA_990B, ARUBA) +CHIPSET(0x990C, ARUBA_990C, ARUBA) +CHIPSET(0x990D, ARUBA_990D, ARUBA) +CHIPSET(0x990E, ARUBA_990E, ARUBA) +CHIPSET(0x990F, ARUBA_990F, ARUBA) +CHIPSET(0x9910, ARUBA_9910, ARUBA) +CHIPSET(0x9913, ARUBA_9913, ARUBA) +CHIPSET(0x9917, ARUBA_9917, ARUBA) +CHIPSET(0x9918, ARUBA_9918, ARUBA) +CHIPSET(0x9919, ARUBA_9919, ARUBA) +CHIPSET(0x9990, ARUBA_9990, ARUBA) +CHIPSET(0x9991, ARUBA_9991, ARUBA) +CHIPSET(0x9992, ARUBA_9992, ARUBA) +CHIPSET(0x9993, ARUBA_9993, ARUBA) +CHIPSET(0x9994, ARUBA_9994, ARUBA) +CHIPSET(0x9995, ARUBA_9995, ARUBA) +CHIPSET(0x9996, ARUBA_9996, ARUBA) +CHIPSET(0x9997, ARUBA_9997, ARUBA) +CHIPSET(0x9998, ARUBA_9998, ARUBA) +CHIPSET(0x9999, ARUBA_9999, ARUBA) +CHIPSET(0x999A, ARUBA_999A, ARUBA) +CHIPSET(0x999B, ARUBA_999B, ARUBA) +CHIPSET(0x999C, ARUBA_999C, ARUBA) +CHIPSET(0x999D, ARUBA_999D, ARUBA) +CHIPSET(0x99A0, ARUBA_99A0, ARUBA) +CHIPSET(0x99A2, ARUBA_99A2, ARUBA) +CHIPSET(0x99A4, ARUBA_99A4, ARUBA) + +CHIPSET(0x6780, TAHITI_6780, TAHITI) +CHIPSET(0x6784, TAHITI_6784, TAHITI) +CHIPSET(0x6788, TAHITI_6788, TAHITI) +CHIPSET(0x678A, TAHITI_678A, TAHITI) +CHIPSET(0x6790, TAHITI_6790, TAHITI) +CHIPSET(0x6791, TAHITI_6791, TAHITI) +CHIPSET(0x6792, TAHITI_6792, TAHITI) +CHIPSET(0x6798, TAHITI_6798, TAHITI) +CHIPSET(0x6799, TAHITI_6799, TAHITI) +CHIPSET(0x679A, TAHITI_679A, TAHITI) +CHIPSET(0x679B, TAHITI_679B, TAHITI) +CHIPSET(0x679E, TAHITI_679E, TAHITI) +CHIPSET(0x679F, TAHITI_679F, TAHITI) + +CHIPSET(0x6800, PITCAIRN_6800, PITCAIRN) +CHIPSET(0x6801, PITCAIRN_6801, PITCAIRN) +CHIPSET(0x6802, PITCAIRN_6802, PITCAIRN) +CHIPSET(0x6806, PITCAIRN_6806, PITCAIRN) +CHIPSET(0x6808, PITCAIRN_6808, PITCAIRN) +CHIPSET(0x6809, PITCAIRN_6809, PITCAIRN) +CHIPSET(0x6810, PITCAIRN_6810, PITCAIRN) +CHIPSET(0x6811, PITCAIRN_6811, PITCAIRN) +CHIPSET(0x6816, PITCAIRN_6816, PITCAIRN) +CHIPSET(0x6817, PITCAIRN_6817, PITCAIRN) +CHIPSET(0x6818, PITCAIRN_6818, PITCAIRN) +CHIPSET(0x6819, PITCAIRN_6819, PITCAIRN) +CHIPSET(0x684C, PITCAIRN_684C, PITCAIRN) + +CHIPSET(0x6820, VERDE_6820, VERDE) +CHIPSET(0x6821, VERDE_6821, VERDE) +CHIPSET(0x6822, VERDE_6822, VERDE) +CHIPSET(0x6823, VERDE_6823, VERDE) +CHIPSET(0x6824, VERDE_6824, VERDE) +CHIPSET(0x6825, VERDE_6825, VERDE) +CHIPSET(0x6826, VERDE_6826, VERDE) +CHIPSET(0x6827, VERDE_6827, VERDE) +CHIPSET(0x6828, VERDE_6828, VERDE) +CHIPSET(0x6829, VERDE_6829, VERDE) +CHIPSET(0x682A, VERDE_682A, VERDE) +CHIPSET(0x682B, VERDE_682B, VERDE) +CHIPSET(0x682C, VERDE_682C, VERDE) +CHIPSET(0x682D, VERDE_682D, VERDE) +CHIPSET(0x682F, VERDE_682F, VERDE) +CHIPSET(0x6830, VERDE_6830, VERDE) +CHIPSET(0x6831, VERDE_6831, VERDE) +CHIPSET(0x6835, VERDE_6835, VERDE) +CHIPSET(0x6837, VERDE_6837, VERDE) +CHIPSET(0x6838, VERDE_6838, VERDE) +CHIPSET(0x6839, VERDE_6839, VERDE) +CHIPSET(0x683B, VERDE_683B, VERDE) +CHIPSET(0x683D, VERDE_683D, VERDE) +CHIPSET(0x683F, VERDE_683F, VERDE) + +CHIPSET(0x6600, OLAND_6600, OLAND) +CHIPSET(0x6601, OLAND_6601, OLAND) +CHIPSET(0x6602, OLAND_6602, OLAND) +CHIPSET(0x6603, OLAND_6603, OLAND) +CHIPSET(0x6604, OLAND_6604, OLAND) +CHIPSET(0x6605, OLAND_6605, OLAND) +CHIPSET(0x6606, OLAND_6606, OLAND) +CHIPSET(0x6607, OLAND_6607, OLAND) +CHIPSET(0x6608, OLAND_6608, OLAND) +CHIPSET(0x6610, OLAND_6610, OLAND) +CHIPSET(0x6611, OLAND_6611, OLAND) +CHIPSET(0x6613, OLAND_6613, OLAND) +CHIPSET(0x6617, OLAND_6617, OLAND) +CHIPSET(0x6620, OLAND_6620, OLAND) +CHIPSET(0x6621, OLAND_6621, OLAND) +CHIPSET(0x6623, OLAND_6623, OLAND) +CHIPSET(0x6631, OLAND_6631, OLAND) + +CHIPSET(0x6660, HAINAN_6660, HAINAN) +CHIPSET(0x6663, HAINAN_6663, HAINAN) +CHIPSET(0x6664, HAINAN_6664, HAINAN) +CHIPSET(0x6665, HAINAN_6665, HAINAN) +CHIPSET(0x6667, HAINAN_6667, HAINAN) +CHIPSET(0x666F, HAINAN_666F, HAINAN) + +CHIPSET(0x6640, BONAIRE_6640, BONAIRE) +CHIPSET(0x6641, BONAIRE_6641, BONAIRE) +CHIPSET(0x6646, BONAIRE_6646, BONAIRE) +CHIPSET(0x6647, BONAIRE_6647, BONAIRE) +CHIPSET(0x6649, BONAIRE_6649, BONAIRE) +CHIPSET(0x6650, BONAIRE_6650, BONAIRE) +CHIPSET(0x6651, BONAIRE_6651, BONAIRE) +CHIPSET(0x6658, BONAIRE_6658, BONAIRE) +CHIPSET(0x665C, BONAIRE_665C, BONAIRE) +CHIPSET(0x665D, BONAIRE_665D, BONAIRE) +CHIPSET(0x665F, BONAIRE_665F, BONAIRE) + +CHIPSET(0x9830, KABINI_9830, KABINI) +CHIPSET(0x9831, KABINI_9831, KABINI) +CHIPSET(0x9832, KABINI_9832, KABINI) +CHIPSET(0x9833, KABINI_9833, KABINI) +CHIPSET(0x9834, KABINI_9834, KABINI) +CHIPSET(0x9835, KABINI_9835, KABINI) +CHIPSET(0x9836, KABINI_9836, KABINI) +CHIPSET(0x9837, KABINI_9837, KABINI) +CHIPSET(0x9838, KABINI_9838, KABINI) +CHIPSET(0x9839, KABINI_9839, KABINI) +CHIPSET(0x983A, KABINI_983A, KABINI) +CHIPSET(0x983B, KABINI_983B, KABINI) +CHIPSET(0x983C, KABINI_983C, KABINI) +CHIPSET(0x983D, KABINI_983D, KABINI) +CHIPSET(0x983E, KABINI_983E, KABINI) +CHIPSET(0x983F, KABINI_983F, KABINI) + +CHIPSET(0x9850, MULLINS_9850, MULLINS) +CHIPSET(0x9851, MULLINS_9851, MULLINS) +CHIPSET(0x9852, MULLINS_9852, MULLINS) +CHIPSET(0x9853, MULLINS_9853, MULLINS) +CHIPSET(0x9854, MULLINS_9854, MULLINS) +CHIPSET(0x9855, MULLINS_9855, MULLINS) +CHIPSET(0x9856, MULLINS_9856, MULLINS) +CHIPSET(0x9857, MULLINS_9857, MULLINS) +CHIPSET(0x9858, MULLINS_9858, MULLINS) +CHIPSET(0x9859, MULLINS_9859, MULLINS) +CHIPSET(0x985A, MULLINS_985A, MULLINS) +CHIPSET(0x985B, MULLINS_985B, MULLINS) +CHIPSET(0x985C, MULLINS_985C, MULLINS) +CHIPSET(0x985D, MULLINS_985D, MULLINS) +CHIPSET(0x985E, MULLINS_985E, MULLINS) +CHIPSET(0x985F, MULLINS_985F, MULLINS) + +CHIPSET(0x1304, KAVERI_1304, KAVERI) +CHIPSET(0x1305, KAVERI_1305, KAVERI) +CHIPSET(0x1306, KAVERI_1306, KAVERI) +CHIPSET(0x1307, KAVERI_1307, KAVERI) +CHIPSET(0x1309, KAVERI_1309, KAVERI) +CHIPSET(0x130A, KAVERI_130A, KAVERI) +CHIPSET(0x130B, KAVERI_130B, KAVERI) +CHIPSET(0x130C, KAVERI_130C, KAVERI) +CHIPSET(0x130D, KAVERI_130D, KAVERI) +CHIPSET(0x130E, KAVERI_130E, KAVERI) +CHIPSET(0x130F, KAVERI_130F, KAVERI) +CHIPSET(0x1310, KAVERI_1310, KAVERI) +CHIPSET(0x1311, KAVERI_1311, KAVERI) +CHIPSET(0x1312, KAVERI_1312, KAVERI) +CHIPSET(0x1313, KAVERI_1313, KAVERI) +CHIPSET(0x1315, KAVERI_1315, KAVERI) +CHIPSET(0x1316, KAVERI_1316, KAVERI) +CHIPSET(0x1317, KAVERI_1317, KAVERI) +CHIPSET(0x1318, KAVERI_1318, KAVERI) +CHIPSET(0x131B, KAVERI_131B, KAVERI) +CHIPSET(0x131C, KAVERI_131C, KAVERI) +CHIPSET(0x131D, KAVERI_131D, KAVERI) + +CHIPSET(0x67A0, HAWAII_67A0, HAWAII) +CHIPSET(0x67A1, HAWAII_67A1, HAWAII) +CHIPSET(0x67A2, HAWAII_67A2, HAWAII) +CHIPSET(0x67A8, HAWAII_67A8, HAWAII) +CHIPSET(0x67A9, HAWAII_67A9, HAWAII) +CHIPSET(0x67AA, HAWAII_67AA, HAWAII) +CHIPSET(0x67B0, HAWAII_67B0, HAWAII) +CHIPSET(0x67B1, HAWAII_67B1, HAWAII) +CHIPSET(0x67B8, HAWAII_67B8, HAWAII) +CHIPSET(0x67B9, HAWAII_67B9, HAWAII) +CHIPSET(0x67BA, HAWAII_67BA, HAWAII) +CHIPSET(0x67BE, HAWAII_67BE, HAWAII) diff --git a/radeon/radeon-symbols.txt b/radeon/radeon-symbols.txt new file mode 100644 index 0000000..5a532d8 --- /dev/null +++ b/radeon/radeon-symbols.txt @@ -0,0 +1,44 @@ +radeon_bo_debug +radeon_bo_get_handle +radeon_bo_get_src_domain +radeon_bo_get_tiling +radeon_bo_is_busy +radeon_bo_is_referenced_by_cs +radeon_bo_is_static +radeon_bo_manager_gem_ctor +radeon_bo_manager_gem_dtor +radeon_bo_map +radeon_bo_open +radeon_bo_ref +radeon_bo_set_tiling +radeon_bo_unmap +radeon_bo_unref +radeon_bo_wait +radeon_cs_begin +radeon_cs_create +radeon_cs_destroy +radeon_cs_emit +radeon_cs_end +radeon_cs_erase +radeon_cs_get_id +radeon_cs_manager_gem_ctor +radeon_cs_manager_gem_dtor +radeon_cs_need_flush +radeon_cs_print +radeon_cs_set_limit +radeon_cs_space_add_persistent_bo +radeon_cs_space_check +radeon_cs_space_check_with_bo +radeon_cs_space_reset_bos +radeon_cs_space_set_flush +radeon_cs_write_reloc +radeon_gem_bo_open_prime +radeon_gem_get_kernel_name +radeon_gem_get_reloc_in_cs +radeon_gem_name_bo +radeon_gem_prime_share_bo +radeon_gem_set_domain +radeon_surface_best +radeon_surface_init +radeon_surface_manager_free +radeon_surface_manager_new diff --git a/radeon/radeon_bo.c b/radeon/radeon_bo.c new file mode 100644 index 0000000..9192953 --- /dev/null +++ b/radeon/radeon_bo.c @@ -0,0 +1,142 @@ +/* + * Copyright © 2008 Dave Airlie + * Copyright © 2008 Jérôme Glisse + * 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 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 THE COPYRIGHT HOLDERS, AUTHORS + * 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Dave Airlie + * Jérôme Glisse + */ +#include +#include +#include + +drm_public void radeon_bo_debug(struct radeon_bo *bo, const char *op) +{ + struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; + + fprintf(stderr, "%s %p 0x%08X 0x%08X 0x%08X\n", + op, bo, bo->handle, boi->size, boi->cref); +} + +drm_public struct radeon_bo * +radeon_bo_open(struct radeon_bo_manager *bom, uint32_t handle, uint32_t size, + uint32_t alignment, uint32_t domains, uint32_t flags) +{ + struct radeon_bo *bo; + bo = bom->funcs->bo_open(bom, handle, size, alignment, domains, flags); + return bo; +} + +drm_public void radeon_bo_ref(struct radeon_bo *bo) +{ + struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; + boi->cref++; + boi->bom->funcs->bo_ref(boi); +} + +drm_public struct radeon_bo *radeon_bo_unref(struct radeon_bo *bo) +{ + struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; + if (bo == NULL) + return NULL; + + boi->cref--; + return boi->bom->funcs->bo_unref(boi); +} + +drm_public int radeon_bo_map(struct radeon_bo *bo, int write) +{ + struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; + return boi->bom->funcs->bo_map(boi, write); +} + +drm_public int radeon_bo_unmap(struct radeon_bo *bo) +{ + struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; + return boi->bom->funcs->bo_unmap(boi); +} + +drm_public int radeon_bo_wait(struct radeon_bo *bo) +{ + struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; + if (!boi->bom->funcs->bo_wait) + return 0; + return boi->bom->funcs->bo_wait(boi); +} + +drm_public int radeon_bo_is_busy(struct radeon_bo *bo, uint32_t *domain) +{ + struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; + return boi->bom->funcs->bo_is_busy(boi, domain); +} + +drm_public int +radeon_bo_set_tiling(struct radeon_bo *bo, + uint32_t tiling_flags, uint32_t pitch) +{ + struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; + return boi->bom->funcs->bo_set_tiling(boi, tiling_flags, pitch); +} + +drm_public int +radeon_bo_get_tiling(struct radeon_bo *bo, + uint32_t *tiling_flags, uint32_t *pitch) +{ + struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; + return boi->bom->funcs->bo_get_tiling(boi, tiling_flags, pitch); +} + +drm_public int radeon_bo_is_static(struct radeon_bo *bo) +{ + struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; + if (boi->bom->funcs->bo_is_static) + return boi->bom->funcs->bo_is_static(boi); + return 0; +} + +drm_public int +radeon_bo_is_referenced_by_cs(struct radeon_bo *bo, struct radeon_cs *cs) +{ + struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; + return boi->cref > 1; +} + +drm_public uint32_t radeon_bo_get_handle(struct radeon_bo *bo) +{ + return bo->handle; +} + +drm_public uint32_t radeon_bo_get_src_domain(struct radeon_bo *bo) +{ + struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; + uint32_t src_domain; + + src_domain = boi->space_accounted & 0xffff; + if (!src_domain) + src_domain = boi->space_accounted >> 16; + + return src_domain; +} diff --git a/radeon/radeon_bo.h b/radeon/radeon_bo.h new file mode 100644 index 0000000..6e20c6c --- /dev/null +++ b/radeon/radeon_bo.h @@ -0,0 +1,73 @@ +/* + * Copyright © 2008 Jérôme Glisse + * 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 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 THE COPYRIGHT HOLDERS, AUTHORS + * 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Jérôme Glisse + */ +#ifndef RADEON_BO_H +#define RADEON_BO_H + +#include +#include + +/* bo object */ +#define RADEON_BO_FLAGS_MACRO_TILE 1 +#define RADEON_BO_FLAGS_MICRO_TILE 2 +#define RADEON_BO_FLAGS_MICRO_TILE_SQUARE 0x20 + +struct radeon_bo_manager; +struct radeon_cs; + +struct radeon_bo { + void *ptr; + uint32_t flags; + uint32_t handle; + uint32_t size; +}; + + +void radeon_bo_debug(struct radeon_bo *bo, const char *op); + +struct radeon_bo *radeon_bo_open(struct radeon_bo_manager *bom, + uint32_t handle, + uint32_t size, + uint32_t alignment, + uint32_t domains, + uint32_t flags); + +void radeon_bo_ref(struct radeon_bo *bo); +struct radeon_bo *radeon_bo_unref(struct radeon_bo *bo); +int radeon_bo_map(struct radeon_bo *bo, int write); +int radeon_bo_unmap(struct radeon_bo *bo); +int radeon_bo_wait(struct radeon_bo *bo); +int radeon_bo_is_busy(struct radeon_bo *bo, uint32_t *domain); +int radeon_bo_set_tiling(struct radeon_bo *bo, uint32_t tiling_flags, uint32_t pitch); +int radeon_bo_get_tiling(struct radeon_bo *bo, uint32_t *tiling_flags, uint32_t *pitch); +int radeon_bo_is_static(struct radeon_bo *bo); +int radeon_bo_is_referenced_by_cs(struct radeon_bo *bo, struct radeon_cs *cs); +uint32_t radeon_bo_get_handle(struct radeon_bo *bo); +uint32_t radeon_bo_get_src_domain(struct radeon_bo *bo); +#endif diff --git a/radeon/radeon_bo_gem.c b/radeon/radeon_bo_gem.c new file mode 100644 index 0000000..bbe72ce --- /dev/null +++ b/radeon/radeon_bo_gem.c @@ -0,0 +1,399 @@ +/* + * Copyright © 2008 Dave Airlie + * Copyright © 2008 Jérôme Glisse + * 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 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 THE COPYRIGHT HOLDERS, AUTHORS + * 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Dave Airlie + * Jérôme Glisse + */ +#include +#include +#include +#include +#include +#include "libdrm_macros.h" +#include "xf86drm.h" +#include "xf86atomic.h" +#include "drm.h" +#include "radeon_drm.h" +#include "radeon_bo.h" +#include "radeon_bo_int.h" +#include "radeon_bo_gem.h" +#include +struct radeon_bo_gem { + struct radeon_bo_int base; + uint32_t name; + int map_count; + atomic_t reloc_in_cs; + void *priv_ptr; +}; + +struct bo_manager_gem { + struct radeon_bo_manager base; +}; + +static int bo_wait(struct radeon_bo_int *boi); + +static struct radeon_bo *bo_open(struct radeon_bo_manager *bom, + uint32_t handle, + uint32_t size, + uint32_t alignment, + uint32_t domains, + uint32_t flags) +{ + struct radeon_bo_gem *bo; + int r; + + bo = (struct radeon_bo_gem*)calloc(1, sizeof(struct radeon_bo_gem)); + if (bo == NULL) { + return NULL; + } + + bo->base.bom = bom; + bo->base.handle = 0; + bo->base.size = size; + bo->base.alignment = alignment; + bo->base.domains = domains; + bo->base.flags = flags; + bo->base.ptr = NULL; + atomic_set(&bo->reloc_in_cs, 0); + bo->map_count = 0; + if (handle) { + struct drm_gem_open open_arg; + + memset(&open_arg, 0, sizeof(open_arg)); + open_arg.name = handle; + r = drmIoctl(bom->fd, DRM_IOCTL_GEM_OPEN, &open_arg); + if (r != 0) { + free(bo); + return NULL; + } + bo->base.handle = open_arg.handle; + bo->base.size = open_arg.size; + bo->name = handle; + } else { + struct drm_radeon_gem_create args; + + args.size = size; + args.alignment = alignment; + args.initial_domain = bo->base.domains; + args.flags = flags; + args.handle = 0; + r = drmCommandWriteRead(bom->fd, DRM_RADEON_GEM_CREATE, + &args, sizeof(args)); + bo->base.handle = args.handle; + if (r) { + fprintf(stderr, "Failed to allocate :\n"); + fprintf(stderr, " size : %d bytes\n", size); + fprintf(stderr, " alignment : %d bytes\n", alignment); + fprintf(stderr, " domains : %d\n", bo->base.domains); + free(bo); + return NULL; + } + } + radeon_bo_ref((struct radeon_bo*)bo); + return (struct radeon_bo*)bo; +} + +static void bo_ref(struct radeon_bo_int *boi) +{ +} + +static struct radeon_bo *bo_unref(struct radeon_bo_int *boi) +{ + struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)boi; + + if (boi->cref) { + return (struct radeon_bo *)boi; + } + if (bo_gem->priv_ptr) { + drm_munmap(bo_gem->priv_ptr, boi->size); + } + + /* close object */ + drmCloseBufferHandle(boi->bom->fd, boi->handle); + memset(bo_gem, 0, sizeof(struct radeon_bo_gem)); + free(bo_gem); + return NULL; +} + +static int bo_map(struct radeon_bo_int *boi, int write) +{ + struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)boi; + struct drm_radeon_gem_mmap args; + int r; + void *ptr; + + if (bo_gem->map_count++ != 0) { + return 0; + } + if (bo_gem->priv_ptr) { + goto wait; + } + + boi->ptr = NULL; + + /* Zero out args to make valgrind happy */ + memset(&args, 0, sizeof(args)); + args.handle = boi->handle; + args.offset = 0; + args.size = (uint64_t)boi->size; + r = drmCommandWriteRead(boi->bom->fd, + DRM_RADEON_GEM_MMAP, + &args, + sizeof(args)); + if (r) { + fprintf(stderr, "error mapping %p 0x%08X (error = %d)\n", + boi, boi->handle, r); + return r; + } + ptr = drm_mmap(0, args.size, PROT_READ|PROT_WRITE, MAP_SHARED, boi->bom->fd, args.addr_ptr); + if (ptr == MAP_FAILED) + return -errno; + bo_gem->priv_ptr = ptr; +wait: + boi->ptr = bo_gem->priv_ptr; + r = bo_wait(boi); + if (r) + return r; + return 0; +} + +static int bo_unmap(struct radeon_bo_int *boi) +{ + struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)boi; + + if (--bo_gem->map_count > 0) { + return 0; + } + //drm_munmap(bo->ptr, bo->size); + boi->ptr = NULL; + return 0; +} + +static int bo_wait(struct radeon_bo_int *boi) +{ + struct drm_radeon_gem_wait_idle args; + int ret; + + /* Zero out args to make valgrind happy */ + memset(&args, 0, sizeof(args)); + args.handle = boi->handle; + do { + ret = drmCommandWrite(boi->bom->fd, DRM_RADEON_GEM_WAIT_IDLE, + &args, sizeof(args)); + } while (ret == -EBUSY); + return ret; +} + +static int bo_is_busy(struct radeon_bo_int *boi, uint32_t *domain) +{ + struct drm_radeon_gem_busy args; + int ret; + + args.handle = boi->handle; + args.domain = 0; + + ret = drmCommandWriteRead(boi->bom->fd, DRM_RADEON_GEM_BUSY, + &args, sizeof(args)); + + *domain = args.domain; + return ret; +} + +static int bo_set_tiling(struct radeon_bo_int *boi, uint32_t tiling_flags, + uint32_t pitch) +{ + struct drm_radeon_gem_set_tiling args; + int r; + + args.handle = boi->handle; + args.tiling_flags = tiling_flags; + args.pitch = pitch; + + r = drmCommandWriteRead(boi->bom->fd, + DRM_RADEON_GEM_SET_TILING, + &args, + sizeof(args)); + return r; +} + +static int bo_get_tiling(struct radeon_bo_int *boi, uint32_t *tiling_flags, + uint32_t *pitch) +{ + struct drm_radeon_gem_set_tiling args = {}; + int r; + + args.handle = boi->handle; + + r = drmCommandWriteRead(boi->bom->fd, + DRM_RADEON_GEM_GET_TILING, + &args, + sizeof(args)); + + if (r) + return r; + + *tiling_flags = args.tiling_flags; + *pitch = args.pitch; + return r; +} + +static const struct radeon_bo_funcs bo_gem_funcs = { + .bo_open = bo_open, + .bo_ref = bo_ref, + .bo_unref = bo_unref, + .bo_map = bo_map, + .bo_unmap = bo_unmap, + .bo_wait = bo_wait, + .bo_is_static = NULL, + .bo_set_tiling = bo_set_tiling, + .bo_get_tiling = bo_get_tiling, + .bo_is_busy = bo_is_busy, + .bo_is_referenced_by_cs = NULL, +}; + +drm_public struct radeon_bo_manager *radeon_bo_manager_gem_ctor(int fd) +{ + struct bo_manager_gem *bomg; + + bomg = (struct bo_manager_gem*)calloc(1, sizeof(struct bo_manager_gem)); + if (bomg == NULL) { + return NULL; + } + bomg->base.funcs = &bo_gem_funcs; + bomg->base.fd = fd; + return (struct radeon_bo_manager*)bomg; +} + +drm_public void radeon_bo_manager_gem_dtor(struct radeon_bo_manager *bom) +{ + struct bo_manager_gem *bomg = (struct bo_manager_gem*)bom; + + if (bom == NULL) { + return; + } + free(bomg); +} + +drm_public uint32_t +radeon_gem_name_bo(struct radeon_bo *bo) +{ + struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; + return bo_gem->name; +} + +drm_public void * +radeon_gem_get_reloc_in_cs(struct radeon_bo *bo) +{ + struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; + return &bo_gem->reloc_in_cs; +} + +drm_public int +radeon_gem_get_kernel_name(struct radeon_bo *bo, uint32_t *name) +{ + struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; + struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; + struct drm_gem_flink flink; + int r; + + if (bo_gem->name) { + *name = bo_gem->name; + return 0; + } + flink.handle = bo->handle; + r = drmIoctl(boi->bom->fd, DRM_IOCTL_GEM_FLINK, &flink); + if (r) { + return r; + } + bo_gem->name = flink.name; + *name = flink.name; + return 0; +} + +drm_public int +radeon_gem_set_domain(struct radeon_bo *bo, uint32_t read_domains, uint32_t write_domain) +{ + struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; + struct drm_radeon_gem_set_domain args; + int r; + + args.handle = bo->handle; + args.read_domains = read_domains; + args.write_domain = write_domain; + + r = drmCommandWriteRead(boi->bom->fd, + DRM_RADEON_GEM_SET_DOMAIN, + &args, + sizeof(args)); + return r; +} + +drm_public int radeon_gem_prime_share_bo(struct radeon_bo *bo, int *handle) +{ + struct radeon_bo_gem *bo_gem = (struct radeon_bo_gem*)bo; + int ret; + + ret = drmPrimeHandleToFD(bo_gem->base.bom->fd, bo->handle, DRM_CLOEXEC, handle); + return ret; +} + +drm_public struct radeon_bo * +radeon_gem_bo_open_prime(struct radeon_bo_manager *bom, int fd_handle, uint32_t size) +{ + struct radeon_bo_gem *bo; + int r; + uint32_t handle; + + bo = (struct radeon_bo_gem*)calloc(1, sizeof(struct radeon_bo_gem)); + if (bo == NULL) { + return NULL; + } + + bo->base.bom = bom; + bo->base.handle = 0; + bo->base.size = size; + bo->base.alignment = 0; + bo->base.domains = RADEON_GEM_DOMAIN_GTT; + bo->base.flags = 0; + bo->base.ptr = NULL; + atomic_set(&bo->reloc_in_cs, 0); + bo->map_count = 0; + + r = drmPrimeFDToHandle(bom->fd, fd_handle, &handle); + if (r != 0) { + free(bo); + return NULL; + } + + bo->base.handle = handle; + bo->name = handle; + + radeon_bo_ref((struct radeon_bo *)bo); + return (struct radeon_bo *)bo; + +} diff --git a/radeon/radeon_bo_gem.h b/radeon/radeon_bo_gem.h new file mode 100644 index 0000000..08965f3 --- /dev/null +++ b/radeon/radeon_bo_gem.h @@ -0,0 +1,48 @@ +/* + * Copyright © 2008 Dave Airlie + * Copyright © 2008 Jérôme Glisse + * 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 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 THE COPYRIGHT HOLDERS, AUTHORS + * 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Dave Airlie + * Jérôme Glisse + */ +#ifndef RADEON_BO_GEM_H +#define RADEON_BO_GEM_H + +#include "radeon_bo.h" + +struct radeon_bo_manager *radeon_bo_manager_gem_ctor(int fd); +void radeon_bo_manager_gem_dtor(struct radeon_bo_manager *bom); + +uint32_t radeon_gem_name_bo(struct radeon_bo *bo); +void *radeon_gem_get_reloc_in_cs(struct radeon_bo *bo); +int radeon_gem_set_domain(struct radeon_bo *bo, uint32_t read_domains, uint32_t write_domain); +int radeon_gem_get_kernel_name(struct radeon_bo *bo, uint32_t *name); +int radeon_gem_prime_share_bo(struct radeon_bo *bo, int *handle); +struct radeon_bo *radeon_gem_bo_open_prime(struct radeon_bo_manager *bom, + int fd_handle, + uint32_t size); +#endif diff --git a/radeon/radeon_bo_int.h b/radeon/radeon_bo_int.h new file mode 100644 index 0000000..de981b0 --- /dev/null +++ b/radeon/radeon_bo_int.h @@ -0,0 +1,45 @@ +#ifndef RADEON_BO_INT +#define RADEON_BO_INT + +struct radeon_bo_manager { + const struct radeon_bo_funcs *funcs; + int fd; +}; + +struct radeon_bo_int { + void *ptr; + uint32_t flags; + uint32_t handle; + uint32_t size; + /* private members */ + uint32_t alignment; + uint32_t domains; + unsigned cref; + struct radeon_bo_manager *bom; + uint32_t space_accounted; + uint32_t referenced_in_cs; +}; + +/* bo functions */ +struct radeon_bo_funcs { + struct radeon_bo *(*bo_open)(struct radeon_bo_manager *bom, + uint32_t handle, + uint32_t size, + uint32_t alignment, + uint32_t domains, + uint32_t flags); + void (*bo_ref)(struct radeon_bo_int *bo); + struct radeon_bo *(*bo_unref)(struct radeon_bo_int *bo); + int (*bo_map)(struct radeon_bo_int *bo, int write); + int (*bo_unmap)(struct radeon_bo_int *bo); + int (*bo_wait)(struct radeon_bo_int *bo); + int (*bo_is_static)(struct radeon_bo_int *bo); + int (*bo_set_tiling)(struct radeon_bo_int *bo, uint32_t tiling_flags, + uint32_t pitch); + int (*bo_get_tiling)(struct radeon_bo_int *bo, uint32_t *tiling_flags, + uint32_t *pitch); + int (*bo_is_busy)(struct radeon_bo_int *bo, uint32_t *domain); + int (*bo_is_referenced_by_cs)(struct radeon_bo_int *bo, struct radeon_cs *cs); +}; + +#endif diff --git a/radeon/radeon_cs.c b/radeon/radeon_cs.c new file mode 100644 index 0000000..1132d06 --- /dev/null +++ b/radeon/radeon_cs.c @@ -0,0 +1,95 @@ +#include "libdrm_macros.h" +#include +#include "radeon_cs.h" +#include "radeon_cs_int.h" + +drm_public struct radeon_cs * +radeon_cs_create(struct radeon_cs_manager *csm, uint32_t ndw) +{ + struct radeon_cs_int *csi = csm->funcs->cs_create(csm, ndw); + return (struct radeon_cs *)csi; +} + +drm_public int +radeon_cs_write_reloc(struct radeon_cs *cs, struct radeon_bo *bo, + uint32_t read_domain, uint32_t write_domain, + uint32_t flags) +{ + struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; + + return csi->csm->funcs->cs_write_reloc(csi, + bo, + read_domain, + write_domain, + flags); +} + +drm_public int +radeon_cs_begin(struct radeon_cs *cs, uint32_t ndw, + const char *file, const char *func, int line) +{ + struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; + return csi->csm->funcs->cs_begin(csi, ndw, file, func, line); +} + +drm_public int +radeon_cs_end(struct radeon_cs *cs, + const char *file, const char *func, int line) +{ + struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; + return csi->csm->funcs->cs_end(csi, file, func, line); +} + +drm_public int radeon_cs_emit(struct radeon_cs *cs) +{ + struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; + return csi->csm->funcs->cs_emit(csi); +} + +drm_public int radeon_cs_destroy(struct radeon_cs *cs) +{ + struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; + return csi->csm->funcs->cs_destroy(csi); +} + +drm_public int radeon_cs_erase(struct radeon_cs *cs) +{ + struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; + return csi->csm->funcs->cs_erase(csi); +} + +drm_public int radeon_cs_need_flush(struct radeon_cs *cs) +{ + struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; + return csi->csm->funcs->cs_need_flush(csi); +} + +drm_public void radeon_cs_print(struct radeon_cs *cs, FILE *file) +{ + struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; + csi->csm->funcs->cs_print(csi, file); +} + +drm_public void +radeon_cs_set_limit(struct radeon_cs *cs, uint32_t domain, uint32_t limit) +{ + struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; + if (domain == RADEON_GEM_DOMAIN_VRAM) + csi->csm->vram_limit = limit; + else + csi->csm->gart_limit = limit; +} + +drm_public void radeon_cs_space_set_flush(struct radeon_cs *cs, + void (*fn)(void *), void *data) +{ + struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; + csi->space_flush_fn = fn; + csi->space_flush_data = data; +} + +drm_public uint32_t radeon_cs_get_id(struct radeon_cs *cs) +{ + struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; + return csi->id; +} diff --git a/radeon/radeon_cs.h b/radeon/radeon_cs.h new file mode 100644 index 0000000..f68a624 --- /dev/null +++ b/radeon/radeon_cs.h @@ -0,0 +1,141 @@ +/* + * Copyright © 2008 Nicolai Haehnle + * Copyright © 2008 Jérôme Glisse + * 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 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 + * THE COPYRIGHT HOLDERS, AUTHORS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Aapo Tahkola + * Nicolai Haehnle + * Jérôme Glisse + */ +#ifndef RADEON_CS_H +#define RADEON_CS_H + +#include +#include +#include "drm.h" +#include "radeon_drm.h" +#include "radeon_bo.h" + +struct radeon_cs_reloc { + struct radeon_bo *bo; + uint32_t read_domain; + uint32_t write_domain; + uint32_t flags; +}; + + +#define RADEON_CS_SPACE_OK 0 +#define RADEON_CS_SPACE_OP_TO_BIG 1 +#define RADEON_CS_SPACE_FLUSH 2 + +struct radeon_cs { + uint32_t *packets; + unsigned cdw; + unsigned ndw; + unsigned section_ndw; + unsigned section_cdw; +}; + +#define MAX_SPACE_BOS (32) + +struct radeon_cs_manager; + +extern struct radeon_cs *radeon_cs_create(struct radeon_cs_manager *csm, + uint32_t ndw); + +extern int radeon_cs_begin(struct radeon_cs *cs, + uint32_t ndw, + const char *file, + const char *func, int line); +extern int radeon_cs_end(struct radeon_cs *cs, + const char *file, + const char *func, + int line); +extern int radeon_cs_emit(struct radeon_cs *cs); +extern int radeon_cs_destroy(struct radeon_cs *cs); +extern int radeon_cs_erase(struct radeon_cs *cs); +extern int radeon_cs_need_flush(struct radeon_cs *cs); +extern void radeon_cs_print(struct radeon_cs *cs, FILE *file); +extern void radeon_cs_set_limit(struct radeon_cs *cs, uint32_t domain, uint32_t limit); +extern void radeon_cs_space_set_flush(struct radeon_cs *cs, void (*fn)(void *), void *data); +extern int radeon_cs_write_reloc(struct radeon_cs *cs, + struct radeon_bo *bo, + uint32_t read_domain, + uint32_t write_domain, + uint32_t flags); +extern uint32_t radeon_cs_get_id(struct radeon_cs *cs); +/* + * add a persistent BO to the list + * a persistent BO is one that will be referenced across flushes, + * i.e. colorbuffer, textures etc. + * They get reset when a new "operation" happens, where an operation + * is a state emission with a color/textures etc followed by a bunch of vertices. + */ +void radeon_cs_space_add_persistent_bo(struct radeon_cs *cs, + struct radeon_bo *bo, + uint32_t read_domains, + uint32_t write_domain); + +/* reset the persistent BO list */ +void radeon_cs_space_reset_bos(struct radeon_cs *cs); + +/* do a space check with the current persistent BO list */ +int radeon_cs_space_check(struct radeon_cs *cs); + +/* do a space check with the current persistent BO list and a temporary BO + * a temporary BO is like a DMA buffer, which gets flushed with the + * command buffer */ +int radeon_cs_space_check_with_bo(struct radeon_cs *cs, + struct radeon_bo *bo, + uint32_t read_domains, + uint32_t write_domain); + +static inline void radeon_cs_write_dword(struct radeon_cs *cs, uint32_t dword) +{ + cs->packets[cs->cdw++] = dword; + if (cs->section_ndw) { + cs->section_cdw++; + } +} + +static inline void radeon_cs_write_qword(struct radeon_cs *cs, uint64_t qword) +{ + memcpy(cs->packets + cs->cdw, &qword, sizeof(uint64_t)); + cs->cdw += 2; + if (cs->section_ndw) { + cs->section_cdw += 2; + } +} + +static inline void radeon_cs_write_table(struct radeon_cs *cs, + const void *data, uint32_t size) +{ + memcpy(cs->packets + cs->cdw, data, size * 4); + cs->cdw += size; + if (cs->section_ndw) { + cs->section_cdw += size; + } +} +#endif diff --git a/radeon/radeon_cs_gem.c b/radeon/radeon_cs_gem.c new file mode 100644 index 0000000..ef070c6 --- /dev/null +++ b/radeon/radeon_cs_gem.c @@ -0,0 +1,556 @@ +/* + * Copyright © 2008 Jérôme Glisse + * 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 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 THE COPYRIGHT HOLDERS, AUTHORS + * 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Aapo Tahkola + * Nicolai Haehnle + * Jérôme Glisse + */ +#include +#include +#include +#include +#include +#include +#include "radeon_cs.h" +#include "radeon_cs_int.h" +#include "radeon_bo_int.h" +#include "radeon_cs_gem.h" +#include "radeon_bo_gem.h" +#include "drm.h" +#include "libdrm_macros.h" +#include "xf86drm.h" +#include "xf86atomic.h" +#include "radeon_drm.h" + +/* Add LIBDRM_RADEON_BOF_FILES to libdrm_radeon_la_SOURCES when building with BOF_DUMP */ +#define CS_BOF_DUMP 0 +#if CS_BOF_DUMP +#include "bof.h" +#endif + +struct radeon_cs_manager_gem { + struct radeon_cs_manager base; + uint32_t device_id; + unsigned nbof; +}; + +#pragma pack(1) +struct cs_reloc_gem { + uint32_t handle; + uint32_t read_domain; + uint32_t write_domain; + uint32_t flags; +}; + +#pragma pack() +#define RELOC_SIZE (sizeof(struct cs_reloc_gem) / sizeof(uint32_t)) + +struct cs_gem { + struct radeon_cs_int base; + struct drm_radeon_cs cs; + struct drm_radeon_cs_chunk chunks[2]; + unsigned nrelocs; + uint32_t *relocs; + struct radeon_bo_int **relocs_bo; +}; + +static pthread_mutex_t id_mutex = PTHREAD_MUTEX_INITIALIZER; +static uint32_t cs_id_source = 0; + +/** + * result is undefined if called with ~0 + */ +static uint32_t get_first_zero(const uint32_t n) +{ + /* __builtin_ctz returns number of trailing zeros. */ + return 1 << __builtin_ctz(~n); +} + +/** + * Returns a free id for cs. + * If there is no free id we return zero + **/ +static uint32_t generate_id(void) +{ + uint32_t r = 0; + pthread_mutex_lock( &id_mutex ); + /* check for free ids */ + if (cs_id_source != ~r) { + /* find first zero bit */ + r = get_first_zero(cs_id_source); + + /* set id as reserved */ + cs_id_source |= r; + } + pthread_mutex_unlock( &id_mutex ); + return r; +} + +/** + * Free the id for later reuse + **/ +static void free_id(uint32_t id) +{ + pthread_mutex_lock( &id_mutex ); + + cs_id_source &= ~id; + + pthread_mutex_unlock( &id_mutex ); +} + +static struct radeon_cs_int *cs_gem_create(struct radeon_cs_manager *csm, + uint32_t ndw) +{ + struct cs_gem *csg; + + /* max cmd buffer size is 64Kb */ + if (ndw > (64 * 1024 / 4)) { + return NULL; + } + csg = (struct cs_gem*)calloc(1, sizeof(struct cs_gem)); + if (csg == NULL) { + return NULL; + } + csg->base.csm = csm; + csg->base.ndw = 64 * 1024 / 4; + csg->base.packets = (uint32_t*)calloc(1, 64 * 1024); + if (csg->base.packets == NULL) { + free(csg); + return NULL; + } + csg->base.relocs_total_size = 0; + csg->base.crelocs = 0; + csg->base.id = generate_id(); + csg->nrelocs = 4096 / (4 * 4) ; + csg->relocs_bo = (struct radeon_bo_int**)calloc(1, + csg->nrelocs*sizeof(void*)); + if (csg->relocs_bo == NULL) { + free(csg->base.packets); + free(csg); + return NULL; + } + csg->base.relocs = csg->relocs = (uint32_t*)calloc(1, 4096); + if (csg->relocs == NULL) { + free(csg->relocs_bo); + free(csg->base.packets); + free(csg); + return NULL; + } + csg->chunks[0].chunk_id = RADEON_CHUNK_ID_IB; + csg->chunks[0].length_dw = 0; + csg->chunks[0].chunk_data = (uint64_t)(uintptr_t)csg->base.packets; + csg->chunks[1].chunk_id = RADEON_CHUNK_ID_RELOCS; + csg->chunks[1].length_dw = 0; + csg->chunks[1].chunk_data = (uint64_t)(uintptr_t)csg->relocs; + return (struct radeon_cs_int*)csg; +} + +static int cs_gem_write_reloc(struct radeon_cs_int *cs, + struct radeon_bo *bo, + uint32_t read_domain, + uint32_t write_domain, + uint32_t flags) +{ + struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; + struct cs_gem *csg = (struct cs_gem*)cs; + struct cs_reloc_gem *reloc; + uint32_t idx; + unsigned i; + + assert(boi->space_accounted); + + /* check domains */ + if ((read_domain && write_domain) || (!read_domain && !write_domain)) { + /* in one CS a bo can only be in read or write domain but not + * in read & write domain at the same time + */ + return -EINVAL; + } + if (read_domain == RADEON_GEM_DOMAIN_CPU) { + return -EINVAL; + } + if (write_domain == RADEON_GEM_DOMAIN_CPU) { + return -EINVAL; + } + /* use bit field hash function to determine + if this bo is for sure not in this cs.*/ + if ((atomic_read((atomic_t *)radeon_gem_get_reloc_in_cs(bo)) & cs->id)) { + /* check if bo is already referenced. + * Scanning from end to begin reduces cycles with mesa because + * it often relocates same shared dma bo again. */ + for(i = cs->crelocs; i != 0;) { + --i; + idx = i * RELOC_SIZE; + reloc = (struct cs_reloc_gem*)&csg->relocs[idx]; + if (reloc->handle == bo->handle) { + /* Check domains must be in read or write. As we check already + * checked that in argument one of the read or write domain was + * set we only need to check that if previous reloc as the read + * domain set then the read_domain should also be set for this + * new relocation. + */ + /* the DDX expects to read and write from same pixmap */ + if (write_domain && (reloc->read_domain & write_domain)) { + reloc->read_domain = 0; + reloc->write_domain = write_domain; + } else if (read_domain & reloc->write_domain) { + reloc->read_domain = 0; + } else { + if (write_domain != reloc->write_domain) + return -EINVAL; + if (read_domain != reloc->read_domain) + return -EINVAL; + } + + reloc->read_domain |= read_domain; + reloc->write_domain |= write_domain; + /* update flags */ + reloc->flags |= (flags & reloc->flags); + /* write relocation packet */ + radeon_cs_write_dword((struct radeon_cs *)cs, 0xc0001000); + radeon_cs_write_dword((struct radeon_cs *)cs, idx); + return 0; + } + } + } + /* new relocation */ + if (csg->base.crelocs >= csg->nrelocs) { + /* allocate more memory (TODO: should use a slab allocator maybe) */ + uint32_t *tmp, size; + size = ((csg->nrelocs + 1) * sizeof(struct radeon_bo*)); + tmp = (uint32_t*)realloc(csg->relocs_bo, size); + if (tmp == NULL) { + return -ENOMEM; + } + csg->relocs_bo = (struct radeon_bo_int **)tmp; + size = ((csg->nrelocs + 1) * RELOC_SIZE * 4); + tmp = (uint32_t*)realloc(csg->relocs, size); + if (tmp == NULL) { + return -ENOMEM; + } + cs->relocs = csg->relocs = tmp; + csg->nrelocs += 1; + csg->chunks[1].chunk_data = (uint64_t)(uintptr_t)csg->relocs; + } + csg->relocs_bo[csg->base.crelocs] = boi; + idx = (csg->base.crelocs++) * RELOC_SIZE; + reloc = (struct cs_reloc_gem*)&csg->relocs[idx]; + reloc->handle = bo->handle; + reloc->read_domain = read_domain; + reloc->write_domain = write_domain; + reloc->flags = flags; + csg->chunks[1].length_dw += RELOC_SIZE; + radeon_bo_ref(bo); + /* bo might be referenced from another context so have to use atomic operations */ + atomic_add((atomic_t *)radeon_gem_get_reloc_in_cs(bo), cs->id); + cs->relocs_total_size += boi->size; + radeon_cs_write_dword((struct radeon_cs *)cs, 0xc0001000); + radeon_cs_write_dword((struct radeon_cs *)cs, idx); + return 0; +} + +static int cs_gem_begin(struct radeon_cs_int *cs, + uint32_t ndw, + const char *file, + const char *func, + int line) +{ + + if (cs->section_ndw) { + fprintf(stderr, "CS already in a section(%s,%s,%d)\n", + cs->section_file, cs->section_func, cs->section_line); + fprintf(stderr, "CS can't start section(%s,%s,%d)\n", + file, func, line); + return -EPIPE; + } + cs->section_ndw = ndw; + cs->section_cdw = 0; + cs->section_file = file; + cs->section_func = func; + cs->section_line = line; + + if (cs->cdw + ndw > cs->ndw) { + uint32_t tmp, *ptr; + + /* round up the required size to a multiple of 1024 */ + tmp = (cs->cdw + ndw + 0x3FF) & (~0x3FF); + ptr = (uint32_t*)realloc(cs->packets, 4 * tmp); + if (ptr == NULL) { + return -ENOMEM; + } + cs->packets = ptr; + cs->ndw = tmp; + } + return 0; +} + +static int cs_gem_end(struct radeon_cs_int *cs, + const char *file, + const char *func, + int line) + +{ + if (!cs->section_ndw) { + fprintf(stderr, "CS no section to end at (%s,%s,%d)\n", + file, func, line); + return -EPIPE; + } + if (cs->section_ndw != cs->section_cdw) { + fprintf(stderr, "CS section size mismatch start at (%s,%s,%d) %d vs %d\n", + cs->section_file, cs->section_func, cs->section_line, cs->section_ndw, cs->section_cdw); + fprintf(stderr, "CS section end at (%s,%s,%d)\n", + file, func, line); + + /* We must reset the section even when there is error. */ + cs->section_ndw = 0; + return -EPIPE; + } + cs->section_ndw = 0; + return 0; +} + +#if CS_BOF_DUMP +static void cs_gem_dump_bof(struct radeon_cs_int *cs) +{ + struct cs_gem *csg = (struct cs_gem*)cs; + struct radeon_cs_manager_gem *csm; + bof_t *bcs, *blob, *array, *bo, *size, *handle, *device_id, *root; + char tmp[256]; + unsigned i; + + csm = (struct radeon_cs_manager_gem *)cs->csm; + root = device_id = bcs = blob = array = bo = size = handle = NULL; + root = bof_object(); + if (root == NULL) + goto out_err; + device_id = bof_int32(csm->device_id); + if (device_id == NULL) + return; + if (bof_object_set(root, "device_id", device_id)) + goto out_err; + bof_decref(device_id); + device_id = NULL; + /* dump relocs */ + blob = bof_blob(csg->nrelocs * 16, csg->relocs); + if (blob == NULL) + goto out_err; + if (bof_object_set(root, "reloc", blob)) + goto out_err; + bof_decref(blob); + blob = NULL; + /* dump cs */ + blob = bof_blob(cs->cdw * 4, cs->packets); + if (blob == NULL) + goto out_err; + if (bof_object_set(root, "pm4", blob)) + goto out_err; + bof_decref(blob); + blob = NULL; + /* dump bo */ + array = bof_array(); + if (array == NULL) + goto out_err; + for (i = 0; i < csg->base.crelocs; i++) { + bo = bof_object(); + if (bo == NULL) + goto out_err; + size = bof_int32(csg->relocs_bo[i]->size); + if (size == NULL) + goto out_err; + if (bof_object_set(bo, "size", size)) + goto out_err; + bof_decref(size); + size = NULL; + handle = bof_int32(csg->relocs_bo[i]->handle); + if (handle == NULL) + goto out_err; + if (bof_object_set(bo, "handle", handle)) + goto out_err; + bof_decref(handle); + handle = NULL; + radeon_bo_map((struct radeon_bo*)csg->relocs_bo[i], 0); + blob = bof_blob(csg->relocs_bo[i]->size, csg->relocs_bo[i]->ptr); + radeon_bo_unmap((struct radeon_bo*)csg->relocs_bo[i]); + if (blob == NULL) + goto out_err; + if (bof_object_set(bo, "data", blob)) + goto out_err; + bof_decref(blob); + blob = NULL; + if (bof_array_append(array, bo)) + goto out_err; + bof_decref(bo); + bo = NULL; + } + if (bof_object_set(root, "bo", array)) + goto out_err; + sprintf(tmp, "d-0x%04X-%08d.bof", csm->device_id, csm->nbof++); + bof_dump_file(root, tmp); +out_err: + bof_decref(blob); + bof_decref(array); + bof_decref(bo); + bof_decref(size); + bof_decref(handle); + bof_decref(device_id); + bof_decref(root); +} +#endif + +static int cs_gem_emit(struct radeon_cs_int *cs) +{ + struct cs_gem *csg = (struct cs_gem*)cs; + uint64_t chunk_array[2]; + unsigned i; + int r; + + while (cs->cdw & 7) + radeon_cs_write_dword((struct radeon_cs *)cs, 0x80000000); + +#if CS_BOF_DUMP + cs_gem_dump_bof(cs); +#endif + csg->chunks[0].length_dw = cs->cdw; + + chunk_array[0] = (uint64_t)(uintptr_t)&csg->chunks[0]; + chunk_array[1] = (uint64_t)(uintptr_t)&csg->chunks[1]; + + csg->cs.num_chunks = 2; + csg->cs.chunks = (uint64_t)(uintptr_t)chunk_array; + + r = drmCommandWriteRead(cs->csm->fd, DRM_RADEON_CS, + &csg->cs, sizeof(struct drm_radeon_cs)); + for (i = 0; i < csg->base.crelocs; i++) { + csg->relocs_bo[i]->space_accounted = 0; + /* bo might be referenced from another context so have to use atomic operations */ + atomic_dec((atomic_t *)radeon_gem_get_reloc_in_cs((struct radeon_bo*)csg->relocs_bo[i]), cs->id); + radeon_bo_unref((struct radeon_bo *)csg->relocs_bo[i]); + csg->relocs_bo[i] = NULL; + } + + cs->csm->read_used = 0; + cs->csm->vram_write_used = 0; + cs->csm->gart_write_used = 0; + return r; +} + +static int cs_gem_destroy(struct radeon_cs_int *cs) +{ + struct cs_gem *csg = (struct cs_gem*)cs; + + free_id(cs->id); + free(csg->relocs_bo); + free(cs->relocs); + free(cs->packets); + free(cs); + return 0; +} + +static int cs_gem_erase(struct radeon_cs_int *cs) +{ + struct cs_gem *csg = (struct cs_gem*)cs; + unsigned i; + + if (csg->relocs_bo) { + for (i = 0; i < csg->base.crelocs; i++) { + if (csg->relocs_bo[i]) { + /* bo might be referenced from another context so have to use atomic operations */ + atomic_dec((atomic_t *)radeon_gem_get_reloc_in_cs((struct radeon_bo*)csg->relocs_bo[i]), cs->id); + radeon_bo_unref((struct radeon_bo *)csg->relocs_bo[i]); + csg->relocs_bo[i] = NULL; + } + } + } + cs->relocs_total_size = 0; + cs->cdw = 0; + cs->section_ndw = 0; + cs->crelocs = 0; + csg->chunks[0].length_dw = 0; + csg->chunks[1].length_dw = 0; + return 0; +} + +static int cs_gem_need_flush(struct radeon_cs_int *cs) +{ + return 0; //(cs->relocs_total_size > (32*1024*1024)); +} + +static void cs_gem_print(struct radeon_cs_int *cs, FILE *file) +{ + struct radeon_cs_manager_gem *csm; + unsigned int i; + + csm = (struct radeon_cs_manager_gem *)cs->csm; + fprintf(file, "VENDORID:DEVICEID 0x%04X:0x%04X\n", 0x1002, csm->device_id); + for (i = 0; i < cs->cdw; i++) { + fprintf(file, "0x%08X\n", cs->packets[i]); + } +} + +static const struct radeon_cs_funcs radeon_cs_gem_funcs = { + .cs_create = cs_gem_create, + .cs_write_reloc = cs_gem_write_reloc, + .cs_begin = cs_gem_begin, + .cs_end = cs_gem_end, + .cs_emit = cs_gem_emit, + .cs_destroy = cs_gem_destroy, + .cs_erase = cs_gem_erase, + .cs_need_flush = cs_gem_need_flush, + .cs_print = cs_gem_print, +}; + +static int radeon_get_device_id(int fd, uint32_t *device_id) +{ + struct drm_radeon_info info = {}; + int r; + + *device_id = 0; + info.request = RADEON_INFO_DEVICE_ID; + info.value = (uintptr_t)device_id; + r = drmCommandWriteRead(fd, DRM_RADEON_INFO, &info, + sizeof(struct drm_radeon_info)); + return r; +} + +drm_public struct radeon_cs_manager *radeon_cs_manager_gem_ctor(int fd) +{ + struct radeon_cs_manager_gem *csm; + + csm = calloc(1, sizeof(struct radeon_cs_manager_gem)); + if (csm == NULL) { + return NULL; + } + csm->base.funcs = &radeon_cs_gem_funcs; + csm->base.fd = fd; + radeon_get_device_id(fd, &csm->device_id); + return &csm->base; +} + +drm_public void radeon_cs_manager_gem_dtor(struct radeon_cs_manager *csm) +{ + free(csm); +} diff --git a/radeon/radeon_cs_gem.h b/radeon/radeon_cs_gem.h new file mode 100644 index 0000000..5dea38a --- /dev/null +++ b/radeon/radeon_cs_gem.h @@ -0,0 +1,41 @@ +/* + * Copyright © 2008 Nicolai Haehnle + * Copyright © 2008 Jérôme Glisse + * 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 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 THE COPYRIGHT HOLDERS, AUTHORS + * 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Aapo Tahkola + * Nicolai Haehnle + * Jérôme Glisse + */ +#ifndef RADEON_CS_GEM_H +#define RADEON_CS_GEM_H + +#include "radeon_cs.h" + +struct radeon_cs_manager *radeon_cs_manager_gem_ctor(int fd); +void radeon_cs_manager_gem_dtor(struct radeon_cs_manager *csm); + +#endif diff --git a/radeon/radeon_cs_int.h b/radeon/radeon_cs_int.h new file mode 100644 index 0000000..d906ad4 --- /dev/null +++ b/radeon/radeon_cs_int.h @@ -0,0 +1,67 @@ + +#ifndef _RADEON_CS_INT_H_ +#define _RADEON_CS_INT_H_ + +struct radeon_cs_space_check { + struct radeon_bo_int *bo; + uint32_t read_domains; + uint32_t write_domain; + uint32_t new_accounted; +}; + +struct radeon_cs_int { + /* keep first two in same place */ + uint32_t *packets; + unsigned cdw; + unsigned ndw; + unsigned section_ndw; + unsigned section_cdw; + /* private members */ + struct radeon_cs_manager *csm; + void *relocs; + unsigned crelocs; + unsigned relocs_total_size; + const char *section_file; + const char *section_func; + int section_line; + struct radeon_cs_space_check bos[MAX_SPACE_BOS]; + int bo_count; + void (*space_flush_fn)(void *); + void *space_flush_data; + uint32_t id; +}; + +/* cs functions */ +struct radeon_cs_funcs { + struct radeon_cs_int *(*cs_create)(struct radeon_cs_manager *csm, + uint32_t ndw); + int (*cs_write_reloc)(struct radeon_cs_int *cs, + struct radeon_bo *bo, + uint32_t read_domain, + uint32_t write_domain, + uint32_t flags); + int (*cs_begin)(struct radeon_cs_int *cs, + uint32_t ndw, + const char *file, + const char *func, + int line); + int (*cs_end)(struct radeon_cs_int *cs, + const char *file, const char *func, + int line); + + + int (*cs_emit)(struct radeon_cs_int *cs); + int (*cs_destroy)(struct radeon_cs_int *cs); + int (*cs_erase)(struct radeon_cs_int *cs); + int (*cs_need_flush)(struct radeon_cs_int *cs); + void (*cs_print)(struct radeon_cs_int *cs, FILE *file); +}; + +struct radeon_cs_manager { + const struct radeon_cs_funcs *funcs; + int fd; + int32_t vram_limit, gart_limit; + int32_t vram_write_used, gart_write_used; + int32_t read_used; +}; +#endif diff --git a/radeon/radeon_cs_space.c b/radeon/radeon_cs_space.c new file mode 100644 index 0000000..039b041 --- /dev/null +++ b/radeon/radeon_cs_space.c @@ -0,0 +1,248 @@ +/* + * Copyright © 2009 Red Hat Inc. + * 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 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 THE COPYRIGHT HOLDERS, AUTHORS + * 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + */ +#include +#include +#include +#include "libdrm_macros.h" +#include "radeon_cs.h" +#include "radeon_bo_int.h" +#include "radeon_cs_int.h" + +struct rad_sizes { + int32_t op_read; + int32_t op_gart_write; + int32_t op_vram_write; +}; + +static inline int radeon_cs_setup_bo(struct radeon_cs_space_check *sc, struct rad_sizes *sizes) +{ + uint32_t read_domains, write_domain; + struct radeon_bo_int *bo; + + bo = sc->bo; + sc->new_accounted = 0; + read_domains = sc->read_domains; + write_domain = sc->write_domain; + + /* legacy needs a static check */ + if (radeon_bo_is_static((struct radeon_bo *)sc->bo)) { + bo->space_accounted = sc->new_accounted = (read_domains << 16) | write_domain; + return 0; + } + + /* already accounted this bo */ + if (write_domain && (write_domain == bo->space_accounted)) { + sc->new_accounted = bo->space_accounted; + return 0; + } + if (read_domains && ((read_domains << 16) == bo->space_accounted)) { + sc->new_accounted = bo->space_accounted; + return 0; + } + + if (bo->space_accounted == 0) { + if (write_domain) { + if (write_domain == RADEON_GEM_DOMAIN_VRAM) + sizes->op_vram_write += bo->size; + else if (write_domain == RADEON_GEM_DOMAIN_GTT) + sizes->op_gart_write += bo->size; + sc->new_accounted = write_domain; + } else { + sizes->op_read += bo->size; + sc->new_accounted = read_domains << 16; + } + } else { + uint16_t old_read, old_write; + + old_read = bo->space_accounted >> 16; + old_write = bo->space_accounted & 0xffff; + + if (write_domain && (old_read & write_domain)) { + sc->new_accounted = write_domain; + /* moving from read to a write domain */ + if (write_domain == RADEON_GEM_DOMAIN_VRAM) { + sizes->op_read -= bo->size; + sizes->op_vram_write += bo->size; + } else if (write_domain == RADEON_GEM_DOMAIN_GTT) { + sizes->op_read -= bo->size; + sizes->op_gart_write += bo->size; + } + } else if (read_domains & old_write) { + sc->new_accounted = bo->space_accounted & 0xffff; + } else { + /* rewrite the domains */ + if (write_domain != old_write) + fprintf(stderr,"WRITE DOMAIN RELOC FAILURE 0x%x %d %d\n", bo->handle, write_domain, old_write); + if (read_domains != old_read) + fprintf(stderr,"READ DOMAIN RELOC FAILURE 0x%x %d %d\n", bo->handle, read_domains, old_read); + return RADEON_CS_SPACE_FLUSH; + } + } + return 0; +} + +static int radeon_cs_do_space_check(struct radeon_cs_int *cs, struct radeon_cs_space_check *new_tmp) +{ + struct radeon_cs_manager *csm = cs->csm; + int i; + struct radeon_bo_int *bo; + struct rad_sizes sizes; + int ret; + + /* check the totals for this operation */ + + if (cs->bo_count == 0 && !new_tmp) + return 0; + + memset(&sizes, 0, sizeof(struct rad_sizes)); + + /* prepare */ + for (i = 0; i < cs->bo_count; i++) { + ret = radeon_cs_setup_bo(&cs->bos[i], &sizes); + if (ret) + return ret; + } + + if (new_tmp) { + ret = radeon_cs_setup_bo(new_tmp, &sizes); + if (ret) + return ret; + } + + if (sizes.op_read < 0) + sizes.op_read = 0; + + /* check sizes - operation first */ + if ((sizes.op_read + sizes.op_gart_write > csm->gart_limit) || + (sizes.op_vram_write > csm->vram_limit)) { + return RADEON_CS_SPACE_OP_TO_BIG; + } + + if (((csm->vram_write_used + sizes.op_vram_write) > csm->vram_limit) || + ((csm->read_used + csm->gart_write_used + sizes.op_gart_write + sizes.op_read) > csm->gart_limit)) { + return RADEON_CS_SPACE_FLUSH; + } + + csm->gart_write_used += sizes.op_gart_write; + csm->vram_write_used += sizes.op_vram_write; + csm->read_used += sizes.op_read; + /* commit */ + for (i = 0; i < cs->bo_count; i++) { + bo = cs->bos[i].bo; + bo->space_accounted = cs->bos[i].new_accounted; + } + if (new_tmp) + new_tmp->bo->space_accounted = new_tmp->new_accounted; + + return RADEON_CS_SPACE_OK; +} + +drm_public void +radeon_cs_space_add_persistent_bo(struct radeon_cs *cs, struct radeon_bo *bo, + uint32_t read_domains, uint32_t write_domain) +{ + struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; + struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; + int i; + for (i = 0; i < csi->bo_count; i++) { + if (csi->bos[i].bo == boi && + csi->bos[i].read_domains == read_domains && + csi->bos[i].write_domain == write_domain) + return; + } + radeon_bo_ref(bo); + i = csi->bo_count; + csi->bos[i].bo = boi; + csi->bos[i].read_domains = read_domains; + csi->bos[i].write_domain = write_domain; + csi->bos[i].new_accounted = 0; + csi->bo_count++; + + assert(csi->bo_count < MAX_SPACE_BOS); +} + +static int radeon_cs_check_space_internal(struct radeon_cs_int *cs, + struct radeon_cs_space_check *tmp_bo) +{ + int ret; + int flushed = 0; + +again: + ret = radeon_cs_do_space_check(cs, tmp_bo); + if (ret == RADEON_CS_SPACE_OP_TO_BIG) + return -1; + if (ret == RADEON_CS_SPACE_FLUSH) { + (*cs->space_flush_fn)(cs->space_flush_data); + if (flushed) + return -1; + flushed = 1; + goto again; + } + return 0; +} + +drm_public int +radeon_cs_space_check_with_bo(struct radeon_cs *cs, struct radeon_bo *bo, + uint32_t read_domains, uint32_t write_domain) +{ + struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; + struct radeon_bo_int *boi = (struct radeon_bo_int *)bo; + struct radeon_cs_space_check temp_bo; + + int ret = 0; + + if (bo) { + temp_bo.bo = boi; + temp_bo.read_domains = read_domains; + temp_bo.write_domain = write_domain; + temp_bo.new_accounted = 0; + } + + ret = radeon_cs_check_space_internal(csi, bo ? &temp_bo : NULL); + return ret; +} + +drm_public int radeon_cs_space_check(struct radeon_cs *cs) +{ + struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; + return radeon_cs_check_space_internal(csi, NULL); +} + +drm_public void radeon_cs_space_reset_bos(struct radeon_cs *cs) +{ + struct radeon_cs_int *csi = (struct radeon_cs_int *)cs; + int i; + for (i = 0; i < csi->bo_count; i++) { + radeon_bo_unref((struct radeon_bo *)csi->bos[i].bo); + csi->bos[i].bo = NULL; + csi->bos[i].read_domains = 0; + csi->bos[i].write_domain = 0; + csi->bos[i].new_accounted = 0; + } + csi->bo_count = 0; +} diff --git a/radeon/radeon_surface.c b/radeon/radeon_surface.c new file mode 100644 index 0000000..ea0a27a --- /dev/null +++ b/radeon/radeon_surface.c @@ -0,0 +1,2566 @@ +/* + * Copyright © 2011 Red Hat 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 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 THE COPYRIGHT HOLDERS, AUTHORS + * 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Jérôme Glisse + */ +#include +#include +#include +#include +#include +#include +#include +#include "drm.h" +#include "libdrm_macros.h" +#include "xf86drm.h" +#include "radeon_drm.h" +#include "radeon_surface.h" + +#define CIK_TILE_MODE_COLOR_2D 14 +#define CIK_TILE_MODE_COLOR_2D_SCANOUT 10 +#define CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_64 0 +#define CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_128 1 +#define CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_256 2 +#define CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_512 3 +#define CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_ROW_SIZE 4 + +#define ALIGN(value, alignment) (((value) + alignment - 1) & ~(alignment - 1)) +#define MAX2(A, B) ((A) > (B) ? (A) : (B)) +#define MIN2(A, B) ((A) < (B) ? (A) : (B)) + +/* keep this private */ +enum radeon_family { + CHIP_UNKNOWN, + CHIP_R600, + CHIP_RV610, + CHIP_RV630, + CHIP_RV670, + CHIP_RV620, + CHIP_RV635, + CHIP_RS780, + CHIP_RS880, + CHIP_RV770, + CHIP_RV730, + CHIP_RV710, + CHIP_RV740, + CHIP_CEDAR, + CHIP_REDWOOD, + CHIP_JUNIPER, + CHIP_CYPRESS, + CHIP_HEMLOCK, + CHIP_PALM, + CHIP_SUMO, + CHIP_SUMO2, + CHIP_BARTS, + CHIP_TURKS, + CHIP_CAICOS, + CHIP_CAYMAN, + CHIP_ARUBA, + CHIP_TAHITI, + CHIP_PITCAIRN, + CHIP_VERDE, + CHIP_OLAND, + CHIP_HAINAN, + CHIP_BONAIRE, + CHIP_KAVERI, + CHIP_KABINI, + CHIP_HAWAII, + CHIP_MULLINS, + CHIP_LAST, +}; + +typedef int (*hw_init_surface_t)(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf); +typedef int (*hw_best_surface_t)(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf); + +struct radeon_hw_info { + /* apply to r6, eg */ + uint32_t group_bytes; + uint32_t num_banks; + uint32_t num_pipes; + /* apply to eg */ + uint32_t row_size; + unsigned allow_2d; + /* apply to si */ + uint32_t tile_mode_array[32]; + /* apply to cik */ + uint32_t macrotile_mode_array[16]; +}; + +struct radeon_surface_manager { + int fd; + uint32_t device_id; + struct radeon_hw_info hw_info; + unsigned family; + hw_init_surface_t surface_init; + hw_best_surface_t surface_best; +}; + +/* helper */ +static int radeon_get_value(int fd, unsigned req, uint32_t *value) +{ + struct drm_radeon_info info = {}; + int r; + + *value = 0; + info.request = req; + info.value = (uintptr_t)value; + r = drmCommandWriteRead(fd, DRM_RADEON_INFO, &info, + sizeof(struct drm_radeon_info)); + return r; +} + +static int radeon_get_family(struct radeon_surface_manager *surf_man) +{ + switch (surf_man->device_id) { +#define CHIPSET(pci_id, name, fam) case pci_id: surf_man->family = CHIP_##fam; break; +#include "r600_pci_ids.h" +#undef CHIPSET + default: + return -EINVAL; + } + return 0; +} + +static unsigned next_power_of_two(unsigned x) +{ + if (x <= 1) + return 1; + + return (1 << ((sizeof(unsigned) * 8) - __builtin_clz(x - 1))); +} + +static unsigned mip_minify(unsigned size, unsigned level) +{ + unsigned val; + + val = MAX2(1, size >> level); + if (level > 0) + val = next_power_of_two(val); + return val; +} + +static void surf_minify(struct radeon_surface *surf, + struct radeon_surface_level *surflevel, + unsigned bpe, unsigned level, + uint32_t xalign, uint32_t yalign, uint32_t zalign, + uint64_t offset) +{ + surflevel->npix_x = mip_minify(surf->npix_x, level); + surflevel->npix_y = mip_minify(surf->npix_y, level); + surflevel->npix_z = mip_minify(surf->npix_z, level); + surflevel->nblk_x = (surflevel->npix_x + surf->blk_w - 1) / surf->blk_w; + surflevel->nblk_y = (surflevel->npix_y + surf->blk_h - 1) / surf->blk_h; + surflevel->nblk_z = (surflevel->npix_z + surf->blk_d - 1) / surf->blk_d; + if (surf->nsamples == 1 && surflevel->mode == RADEON_SURF_MODE_2D && + !(surf->flags & RADEON_SURF_FMASK)) { + if (surflevel->nblk_x < xalign || surflevel->nblk_y < yalign) { + surflevel->mode = RADEON_SURF_MODE_1D; + return; + } + } + surflevel->nblk_x = ALIGN(surflevel->nblk_x, xalign); + surflevel->nblk_y = ALIGN(surflevel->nblk_y, yalign); + surflevel->nblk_z = ALIGN(surflevel->nblk_z, zalign); + + surflevel->offset = offset; + surflevel->pitch_bytes = surflevel->nblk_x * bpe * surf->nsamples; + surflevel->slice_size = (uint64_t)surflevel->pitch_bytes * surflevel->nblk_y; + + surf->bo_size = offset + surflevel->slice_size * surflevel->nblk_z * surf->array_size; +} + +/* =========================================================================== + * r600/r700 family + */ +static int r6_init_hw_info(struct radeon_surface_manager *surf_man) +{ + uint32_t tiling_config; + drmVersionPtr version; + int r; + + r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG, + &tiling_config); + if (r) { + return r; + } + + surf_man->hw_info.allow_2d = 0; + version = drmGetVersion(surf_man->fd); + if (version && version->version_minor >= 14) { + surf_man->hw_info.allow_2d = 1; + } + drmFreeVersion(version); + + switch ((tiling_config & 0xe) >> 1) { + case 0: + surf_man->hw_info.num_pipes = 1; + break; + case 1: + surf_man->hw_info.num_pipes = 2; + break; + case 2: + surf_man->hw_info.num_pipes = 4; + break; + case 3: + surf_man->hw_info.num_pipes = 8; + break; + default: + surf_man->hw_info.num_pipes = 8; + surf_man->hw_info.allow_2d = 0; + break; + } + + switch ((tiling_config & 0x30) >> 4) { + case 0: + surf_man->hw_info.num_banks = 4; + break; + case 1: + surf_man->hw_info.num_banks = 8; + break; + default: + surf_man->hw_info.num_banks = 8; + surf_man->hw_info.allow_2d = 0; + break; + } + + switch ((tiling_config & 0xc0) >> 6) { + case 0: + surf_man->hw_info.group_bytes = 256; + break; + case 1: + surf_man->hw_info.group_bytes = 512; + break; + default: + surf_man->hw_info.group_bytes = 256; + surf_man->hw_info.allow_2d = 0; + break; + } + return 0; +} + +static int r6_surface_init_linear(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + uint64_t offset, unsigned start_level) +{ + uint32_t xalign, yalign, zalign; + unsigned i; + + /* compute alignment */ + if (!start_level) { + surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes); + } + /* the 32 alignment is for scanout, cb or db but to allow texture to be + * easily bound as such we force this alignment to all surface + */ + xalign = MAX2(1, surf_man->hw_info.group_bytes / surf->bpe); + yalign = 1; + zalign = 1; + if (surf->flags & RADEON_SURF_SCANOUT) { + xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign); + } + + /* build mipmap tree */ + for (i = start_level; i <= surf->last_level; i++) { + surf->level[i].mode = RADEON_SURF_MODE_LINEAR; + surf_minify(surf, surf->level+i, surf->bpe, i, xalign, yalign, zalign, offset); + /* level0 and first mipmap need to have alignment */ + offset = surf->bo_size; + if (i == 0) { + offset = ALIGN(offset, surf->bo_alignment); + } + } + return 0; +} + +static int r6_surface_init_linear_aligned(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + uint64_t offset, unsigned start_level) +{ + uint32_t xalign, yalign, zalign; + unsigned i; + + /* compute alignment */ + if (!start_level) { + surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes); + } + xalign = MAX2(64, surf_man->hw_info.group_bytes / surf->bpe); + yalign = 1; + zalign = 1; + + /* build mipmap tree */ + for (i = start_level; i <= surf->last_level; i++) { + surf->level[i].mode = RADEON_SURF_MODE_LINEAR_ALIGNED; + surf_minify(surf, surf->level+i, surf->bpe, i, xalign, yalign, zalign, offset); + /* level0 and first mipmap need to have alignment */ + offset = surf->bo_size; + if (i == 0) { + offset = ALIGN(offset, surf->bo_alignment); + } + } + return 0; +} + +static int r6_surface_init_1d(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + uint64_t offset, unsigned start_level) +{ + uint32_t xalign, yalign, zalign, tilew; + unsigned i; + + /* compute alignment */ + tilew = 8; + xalign = surf_man->hw_info.group_bytes / (tilew * surf->bpe * surf->nsamples); + xalign = MAX2(tilew, xalign); + yalign = tilew; + zalign = 1; + if (surf->flags & RADEON_SURF_SCANOUT) { + xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign); + } + if (!start_level) { + surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes); + } + + /* build mipmap tree */ + for (i = start_level; i <= surf->last_level; i++) { + surf->level[i].mode = RADEON_SURF_MODE_1D; + surf_minify(surf, surf->level+i, surf->bpe, i, xalign, yalign, zalign, offset); + /* level0 and first mipmap need to have alignment */ + offset = surf->bo_size; + if (i == 0) { + offset = ALIGN(offset, surf->bo_alignment); + } + } + return 0; +} + +static int r6_surface_init_2d(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + uint64_t offset, unsigned start_level) +{ + uint32_t xalign, yalign, zalign, tilew; + unsigned i; + + /* compute alignment */ + tilew = 8; + zalign = 1; + xalign = (surf_man->hw_info.group_bytes * surf_man->hw_info.num_banks) / + (tilew * surf->bpe * surf->nsamples); + xalign = MAX2(tilew * surf_man->hw_info.num_banks, xalign); + if (surf->flags & RADEON_SURF_FMASK) + xalign = MAX2(128, xalign); + yalign = tilew * surf_man->hw_info.num_pipes; + if (surf->flags & RADEON_SURF_SCANOUT) { + xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign); + } + if (!start_level) { + surf->bo_alignment = + MAX2(surf_man->hw_info.num_pipes * + surf_man->hw_info.num_banks * + surf->nsamples * surf->bpe * 64, + xalign * yalign * surf->nsamples * surf->bpe); + } + + /* build mipmap tree */ + for (i = start_level; i <= surf->last_level; i++) { + surf->level[i].mode = RADEON_SURF_MODE_2D; + surf_minify(surf, surf->level+i, surf->bpe, i, xalign, yalign, zalign, offset); + if (surf->level[i].mode == RADEON_SURF_MODE_1D) { + return r6_surface_init_1d(surf_man, surf, offset, i); + } + /* level0 and first mipmap need to have alignment */ + offset = surf->bo_size; + if (i == 0) { + offset = ALIGN(offset, surf->bo_alignment); + } + } + return 0; +} + +static int r6_surface_init(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + unsigned mode; + int r; + + /* MSAA surfaces support the 2D mode only. */ + if (surf->nsamples > 1) { + surf->flags = RADEON_SURF_CLR(surf->flags, MODE); + surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE); + } + + /* tiling mode */ + mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK; + + if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) { + /* zbuffer only support 1D or 2D tiled surface */ + switch (mode) { + case RADEON_SURF_MODE_1D: + case RADEON_SURF_MODE_2D: + break; + default: + mode = RADEON_SURF_MODE_1D; + surf->flags = RADEON_SURF_CLR(surf->flags, MODE); + surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE); + break; + } + } + + /* force 1d on kernel that can't do 2d */ + if (!surf_man->hw_info.allow_2d && mode > RADEON_SURF_MODE_1D) { + if (surf->nsamples > 1) { + fprintf(stderr, "radeon: Cannot use 2D tiling for an MSAA surface (%i).\n", __LINE__); + return -EFAULT; + } + mode = RADEON_SURF_MODE_1D; + surf->flags = RADEON_SURF_CLR(surf->flags, MODE); + surf->flags |= RADEON_SURF_SET(mode, MODE); + } + + /* check surface dimension */ + if (surf->npix_x > 8192 || surf->npix_y > 8192 || surf->npix_z > 8192) { + return -EINVAL; + } + + /* check mipmap last_level */ + if (surf->last_level > 14) { + return -EINVAL; + } + + /* check tiling mode */ + switch (mode) { + case RADEON_SURF_MODE_LINEAR: + r = r6_surface_init_linear(surf_man, surf, 0, 0); + break; + case RADEON_SURF_MODE_LINEAR_ALIGNED: + r = r6_surface_init_linear_aligned(surf_man, surf, 0, 0); + break; + case RADEON_SURF_MODE_1D: + r = r6_surface_init_1d(surf_man, surf, 0, 0); + break; + case RADEON_SURF_MODE_2D: + r = r6_surface_init_2d(surf_man, surf, 0, 0); + break; + default: + return -EINVAL; + } + return r; +} + +static int r6_surface_best(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + /* no value to optimize for r6xx/r7xx */ + return 0; +} + + +/* =========================================================================== + * evergreen family + */ +static int eg_init_hw_info(struct radeon_surface_manager *surf_man) +{ + uint32_t tiling_config; + drmVersionPtr version; + int r; + + r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG, + &tiling_config); + if (r) { + return r; + } + + surf_man->hw_info.allow_2d = 0; + version = drmGetVersion(surf_man->fd); + if (version && version->version_minor >= 16) { + surf_man->hw_info.allow_2d = 1; + } + drmFreeVersion(version); + + switch (tiling_config & 0xf) { + case 0: + surf_man->hw_info.num_pipes = 1; + break; + case 1: + surf_man->hw_info.num_pipes = 2; + break; + case 2: + surf_man->hw_info.num_pipes = 4; + break; + case 3: + surf_man->hw_info.num_pipes = 8; + break; + default: + surf_man->hw_info.num_pipes = 8; + surf_man->hw_info.allow_2d = 0; + break; + } + + switch ((tiling_config & 0xf0) >> 4) { + case 0: + surf_man->hw_info.num_banks = 4; + break; + case 1: + surf_man->hw_info.num_banks = 8; + break; + case 2: + surf_man->hw_info.num_banks = 16; + break; + default: + surf_man->hw_info.num_banks = 8; + surf_man->hw_info.allow_2d = 0; + break; + } + + switch ((tiling_config & 0xf00) >> 8) { + case 0: + surf_man->hw_info.group_bytes = 256; + break; + case 1: + surf_man->hw_info.group_bytes = 512; + break; + default: + surf_man->hw_info.group_bytes = 256; + surf_man->hw_info.allow_2d = 0; + break; + } + + switch ((tiling_config & 0xf000) >> 12) { + case 0: + surf_man->hw_info.row_size = 1024; + break; + case 1: + surf_man->hw_info.row_size = 2048; + break; + case 2: + surf_man->hw_info.row_size = 4096; + break; + default: + surf_man->hw_info.row_size = 4096; + surf_man->hw_info.allow_2d = 0; + break; + } + return 0; +} + +static void eg_surf_minify(struct radeon_surface *surf, + struct radeon_surface_level *surflevel, + unsigned bpe, + unsigned level, + unsigned slice_pt, + unsigned mtilew, + unsigned mtileh, + unsigned mtileb, + uint64_t offset) +{ + unsigned mtile_pr, mtile_ps; + + surflevel->npix_x = mip_minify(surf->npix_x, level); + surflevel->npix_y = mip_minify(surf->npix_y, level); + surflevel->npix_z = mip_minify(surf->npix_z, level); + surflevel->nblk_x = (surflevel->npix_x + surf->blk_w - 1) / surf->blk_w; + surflevel->nblk_y = (surflevel->npix_y + surf->blk_h - 1) / surf->blk_h; + surflevel->nblk_z = (surflevel->npix_z + surf->blk_d - 1) / surf->blk_d; + if (surf->nsamples == 1 && surflevel->mode == RADEON_SURF_MODE_2D && + !(surf->flags & RADEON_SURF_FMASK)) { + if (surflevel->nblk_x < mtilew || surflevel->nblk_y < mtileh) { + surflevel->mode = RADEON_SURF_MODE_1D; + return; + } + } + surflevel->nblk_x = ALIGN(surflevel->nblk_x, mtilew); + surflevel->nblk_y = ALIGN(surflevel->nblk_y, mtileh); + surflevel->nblk_z = ALIGN(surflevel->nblk_z, 1); + + /* macro tile per row */ + mtile_pr = surflevel->nblk_x / mtilew; + /* macro tile per slice */ + mtile_ps = (mtile_pr * surflevel->nblk_y) / mtileh; + + surflevel->offset = offset; + surflevel->pitch_bytes = surflevel->nblk_x * bpe * surf->nsamples; + surflevel->slice_size = (uint64_t)mtile_ps * mtileb * slice_pt; + + surf->bo_size = offset + surflevel->slice_size * surflevel->nblk_z * surf->array_size; +} + +static int eg_surface_init_1d(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + struct radeon_surface_level *level, + unsigned bpe, + uint64_t offset, unsigned start_level) +{ + uint32_t xalign, yalign, zalign, tilew; + unsigned i; + + /* compute alignment */ + tilew = 8; + xalign = surf_man->hw_info.group_bytes / (tilew * bpe * surf->nsamples); + xalign = MAX2(tilew, xalign); + yalign = tilew; + zalign = 1; + if (surf->flags & RADEON_SURF_SCANOUT) { + xalign = MAX2((bpe == 1) ? 64 : 32, xalign); + } + + if (!start_level) { + unsigned alignment = MAX2(256, surf_man->hw_info.group_bytes); + surf->bo_alignment = MAX2(surf->bo_alignment, alignment); + + if (offset) { + offset = ALIGN(offset, alignment); + } + } + + /* build mipmap tree */ + for (i = start_level; i <= surf->last_level; i++) { + level[i].mode = RADEON_SURF_MODE_1D; + surf_minify(surf, level+i, bpe, i, xalign, yalign, zalign, offset); + /* level0 and first mipmap need to have alignment */ + offset = surf->bo_size; + if (i == 0) { + offset = ALIGN(offset, surf->bo_alignment); + } + } + return 0; +} + +static int eg_surface_init_2d(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + struct radeon_surface_level *level, + unsigned bpe, unsigned tile_split, + uint64_t offset, unsigned start_level) +{ + unsigned tilew, tileh, tileb; + unsigned mtilew, mtileh, mtileb; + unsigned slice_pt; + unsigned i; + + /* compute tile values */ + tilew = 8; + tileh = 8; + tileb = tilew * tileh * bpe * surf->nsamples; + /* slices per tile */ + slice_pt = 1; + if (tileb > tile_split && tile_split) { + slice_pt = tileb / tile_split; + } + tileb = tileb / slice_pt; + + /* macro tile width & height */ + mtilew = (tilew * surf->bankw * surf_man->hw_info.num_pipes) * surf->mtilea; + mtileh = (tileh * surf->bankh * surf_man->hw_info.num_banks) / surf->mtilea; + /* macro tile bytes */ + mtileb = (mtilew / tilew) * (mtileh / tileh) * tileb; + + if (!start_level) { + unsigned alignment = MAX2(256, mtileb); + surf->bo_alignment = MAX2(surf->bo_alignment, alignment); + + if (offset) { + offset = ALIGN(offset, alignment); + } + } + + /* build mipmap tree */ + for (i = start_level; i <= surf->last_level; i++) { + level[i].mode = RADEON_SURF_MODE_2D; + eg_surf_minify(surf, level+i, bpe, i, slice_pt, mtilew, mtileh, mtileb, offset); + if (level[i].mode == RADEON_SURF_MODE_1D) { + return eg_surface_init_1d(surf_man, surf, level, bpe, offset, i); + } + /* level0 and first mipmap need to have alignment */ + offset = surf->bo_size; + if (i == 0) { + offset = ALIGN(offset, surf->bo_alignment); + } + } + return 0; +} + +static int eg_surface_sanity(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + unsigned mode) +{ + unsigned tileb; + + /* check surface dimension */ + if (surf->npix_x > 16384 || surf->npix_y > 16384 || surf->npix_z > 16384) { + return -EINVAL; + } + + /* check mipmap last_level */ + if (surf->last_level > 15) { + return -EINVAL; + } + + /* force 1d on kernel that can't do 2d */ + if (!surf_man->hw_info.allow_2d && mode > RADEON_SURF_MODE_1D) { + if (surf->nsamples > 1) { + fprintf(stderr, "radeon: Cannot use 2D tiling for an MSAA surface (%i).\n", __LINE__); + return -EFAULT; + } + mode = RADEON_SURF_MODE_1D; + surf->flags = RADEON_SURF_CLR(surf->flags, MODE); + surf->flags |= RADEON_SURF_SET(mode, MODE); + } + + /* check tile split */ + if (mode == RADEON_SURF_MODE_2D) { + switch (surf->tile_split) { + case 64: + case 128: + case 256: + case 512: + case 1024: + case 2048: + case 4096: + break; + default: + return -EINVAL; + } + switch (surf->mtilea) { + case 1: + case 2: + case 4: + case 8: + break; + default: + return -EINVAL; + } + /* check aspect ratio */ + if (surf_man->hw_info.num_banks < surf->mtilea) { + return -EINVAL; + } + /* check bank width */ + switch (surf->bankw) { + case 1: + case 2: + case 4: + case 8: + break; + default: + return -EINVAL; + } + /* check bank height */ + switch (surf->bankh) { + case 1: + case 2: + case 4: + case 8: + break; + default: + return -EINVAL; + } + tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples); + if ((tileb * surf->bankh * surf->bankw) < surf_man->hw_info.group_bytes) { + return -EINVAL; + } + } + + return 0; +} + +static int eg_surface_init_1d_miptrees(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + unsigned zs_flags = RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER; + int r, is_depth_stencil = (surf->flags & zs_flags) == zs_flags; + /* Old libdrm_macros.headers didn't have stencil_level in it. This prevents crashes. */ + struct radeon_surface_level tmp[RADEON_SURF_MAX_LEVEL]; + struct radeon_surface_level *stencil_level = + (surf->flags & RADEON_SURF_HAS_SBUFFER_MIPTREE) ? surf->stencil_level : tmp; + + r = eg_surface_init_1d(surf_man, surf, surf->level, surf->bpe, 0, 0); + if (r) + return r; + + if (is_depth_stencil) { + r = eg_surface_init_1d(surf_man, surf, stencil_level, 1, + surf->bo_size, 0); + surf->stencil_offset = stencil_level[0].offset; + } + return r; +} + +static int eg_surface_init_2d_miptrees(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + unsigned zs_flags = RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER; + int r, is_depth_stencil = (surf->flags & zs_flags) == zs_flags; + /* Old libdrm_macros.headers didn't have stencil_level in it. This prevents crashes. */ + struct radeon_surface_level tmp[RADEON_SURF_MAX_LEVEL]; + struct radeon_surface_level *stencil_level = + (surf->flags & RADEON_SURF_HAS_SBUFFER_MIPTREE) ? surf->stencil_level : tmp; + + r = eg_surface_init_2d(surf_man, surf, surf->level, surf->bpe, + surf->tile_split, 0, 0); + if (r) + return r; + + if (is_depth_stencil) { + r = eg_surface_init_2d(surf_man, surf, stencil_level, 1, + surf->stencil_tile_split, surf->bo_size, 0); + surf->stencil_offset = stencil_level[0].offset; + } + return r; +} + +static int eg_surface_init(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + unsigned mode; + int r; + + /* MSAA surfaces support the 2D mode only. */ + if (surf->nsamples > 1) { + surf->flags = RADEON_SURF_CLR(surf->flags, MODE); + surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE); + } + + /* tiling mode */ + mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK; + + if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) { + /* zbuffer only support 1D or 2D tiled surface */ + switch (mode) { + case RADEON_SURF_MODE_1D: + case RADEON_SURF_MODE_2D: + break; + default: + mode = RADEON_SURF_MODE_1D; + surf->flags = RADEON_SURF_CLR(surf->flags, MODE); + surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE); + break; + } + } + + r = eg_surface_sanity(surf_man, surf, mode); + if (r) { + return r; + } + + surf->stencil_offset = 0; + surf->bo_alignment = 0; + + /* check tiling mode */ + switch (mode) { + case RADEON_SURF_MODE_LINEAR: + r = r6_surface_init_linear(surf_man, surf, 0, 0); + break; + case RADEON_SURF_MODE_LINEAR_ALIGNED: + r = r6_surface_init_linear_aligned(surf_man, surf, 0, 0); + break; + case RADEON_SURF_MODE_1D: + r = eg_surface_init_1d_miptrees(surf_man, surf); + break; + case RADEON_SURF_MODE_2D: + r = eg_surface_init_2d_miptrees(surf_man, surf); + break; + default: + return -EINVAL; + } + return r; +} + +static unsigned log2_int(unsigned x) +{ + unsigned l; + + if (x < 2) { + return 0; + } + for (l = 2; ; l++) { + if ((unsigned)(1 << l) > x) { + return l - 1; + } + } + return 0; +} + +/* compute best tile_split, bankw, bankh, mtilea + * depending on surface + */ +static int eg_surface_best(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + unsigned mode, tileb, h_over_w; + int r; + + /* tiling mode */ + mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK; + + /* set some default value to avoid sanity check choking on them */ + surf->tile_split = 1024; + surf->bankw = 1; + surf->bankh = 1; + surf->mtilea = surf_man->hw_info.num_banks; + tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples); + for (; surf->bankh <= 8; surf->bankh *= 2) { + if ((tileb * surf->bankh * surf->bankw) >= surf_man->hw_info.group_bytes) { + break; + } + } + if (surf->mtilea > 8) { + surf->mtilea = 8; + } + + r = eg_surface_sanity(surf_man, surf, mode); + if (r) { + return r; + } + + if (mode != RADEON_SURF_MODE_2D) { + /* nothing to do for non 2D tiled surface */ + return 0; + } + + /* Tweak TILE_SPLIT for performance here. */ + if (surf->nsamples > 1) { + if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) { + switch (surf->nsamples) { + case 2: + surf->tile_split = 128; + break; + case 4: + surf->tile_split = 128; + break; + case 8: + surf->tile_split = 256; + break; + case 16: /* cayman only */ + surf->tile_split = 512; + break; + default: + fprintf(stderr, "radeon: Wrong number of samples %i (%i)\n", + surf->nsamples, __LINE__); + return -EINVAL; + } + surf->stencil_tile_split = 64; + } else { + /* tile split must be >= 256 for colorbuffer surfaces, + * SAMPLE_SPLIT = tile_split / (bpe * 64), the optimal value is 2 + */ + surf->tile_split = MAX2(2 * surf->bpe * 64, 256); + if (surf->tile_split > 4096) + surf->tile_split = 4096; + } + } else { + /* set tile split to row size */ + surf->tile_split = surf_man->hw_info.row_size; + surf->stencil_tile_split = surf_man->hw_info.row_size / 2; + } + + /* bankw or bankh greater than 1 increase alignment requirement, not + * sure if it's worth using smaller bankw & bankh to stick with 2D + * tiling on small surface rather than falling back to 1D tiling. + * Use recommended value based on tile size for now. + * + * fmask buffer has different optimal value figure them out once we + * use it. + */ + if (surf->flags & RADEON_SURF_SBUFFER) { + /* assume 1 bytes for stencil, we optimize for stencil as stencil + * and depth shares surface values + */ + tileb = MIN2(surf->tile_split, 64 * surf->nsamples); + } else { + tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples); + } + + /* use bankw of 1 to minimize width alignment, might be interesting to + * increase it for large surface + */ + surf->bankw = 1; + switch (tileb) { + case 64: + surf->bankh = 4; + break; + case 128: + case 256: + surf->bankh = 2; + break; + default: + surf->bankh = 1; + break; + } + /* double check the constraint */ + for (; surf->bankh <= 8; surf->bankh *= 2) { + if ((tileb * surf->bankh * surf->bankw) >= surf_man->hw_info.group_bytes) { + break; + } + } + + h_over_w = (((surf->bankh * surf_man->hw_info.num_banks) << 16) / + (surf->bankw * surf_man->hw_info.num_pipes)) >> 16; + surf->mtilea = 1 << (log2_int(h_over_w) >> 1); + + return 0; +} + + +/* =========================================================================== + * Southern Islands family + */ +#define SI__GB_TILE_MODE__PIPE_CONFIG(x) (((x) >> 6) & 0x1f) +#define SI__PIPE_CONFIG__ADDR_SURF_P2 0 +#define SI__PIPE_CONFIG__ADDR_SURF_P4_8x16 4 +#define SI__PIPE_CONFIG__ADDR_SURF_P4_16x16 5 +#define SI__PIPE_CONFIG__ADDR_SURF_P4_16x32 6 +#define SI__PIPE_CONFIG__ADDR_SURF_P4_32x32 7 +#define SI__PIPE_CONFIG__ADDR_SURF_P8_16x16_8x16 8 +#define SI__PIPE_CONFIG__ADDR_SURF_P8_16x32_8x16 9 +#define SI__PIPE_CONFIG__ADDR_SURF_P8_32x32_8x16 10 +#define SI__PIPE_CONFIG__ADDR_SURF_P8_16x32_16x16 11 +#define SI__PIPE_CONFIG__ADDR_SURF_P8_32x32_16x16 12 +#define SI__PIPE_CONFIG__ADDR_SURF_P8_32x32_16x32 13 +#define SI__PIPE_CONFIG__ADDR_SURF_P8_32x64_32x32 14 +#define SI__GB_TILE_MODE__TILE_SPLIT(x) (((x) >> 11) & 0x7) +#define SI__TILE_SPLIT__64B 0 +#define SI__TILE_SPLIT__128B 1 +#define SI__TILE_SPLIT__256B 2 +#define SI__TILE_SPLIT__512B 3 +#define SI__TILE_SPLIT__1024B 4 +#define SI__TILE_SPLIT__2048B 5 +#define SI__TILE_SPLIT__4096B 6 +#define SI__GB_TILE_MODE__BANK_WIDTH(x) (((x) >> 14) & 0x3) +#define SI__BANK_WIDTH__1 0 +#define SI__BANK_WIDTH__2 1 +#define SI__BANK_WIDTH__4 2 +#define SI__BANK_WIDTH__8 3 +#define SI__GB_TILE_MODE__BANK_HEIGHT(x) (((x) >> 16) & 0x3) +#define SI__BANK_HEIGHT__1 0 +#define SI__BANK_HEIGHT__2 1 +#define SI__BANK_HEIGHT__4 2 +#define SI__BANK_HEIGHT__8 3 +#define SI__GB_TILE_MODE__MACRO_TILE_ASPECT(x) (((x) >> 18) & 0x3) +#define SI__MACRO_TILE_ASPECT__1 0 +#define SI__MACRO_TILE_ASPECT__2 1 +#define SI__MACRO_TILE_ASPECT__4 2 +#define SI__MACRO_TILE_ASPECT__8 3 +#define SI__GB_TILE_MODE__NUM_BANKS(x) (((x) >> 20) & 0x3) +#define SI__NUM_BANKS__2_BANK 0 +#define SI__NUM_BANKS__4_BANK 1 +#define SI__NUM_BANKS__8_BANK 2 +#define SI__NUM_BANKS__16_BANK 3 + + +static void si_gb_tile_mode(uint32_t gb_tile_mode, + unsigned *num_pipes, + unsigned *num_banks, + uint32_t *macro_tile_aspect, + uint32_t *bank_w, + uint32_t *bank_h, + uint32_t *tile_split) +{ + if (num_pipes) { + switch (SI__GB_TILE_MODE__PIPE_CONFIG(gb_tile_mode)) { + case SI__PIPE_CONFIG__ADDR_SURF_P2: + default: + *num_pipes = 2; + break; + case SI__PIPE_CONFIG__ADDR_SURF_P4_8x16: + case SI__PIPE_CONFIG__ADDR_SURF_P4_16x16: + case SI__PIPE_CONFIG__ADDR_SURF_P4_16x32: + case SI__PIPE_CONFIG__ADDR_SURF_P4_32x32: + *num_pipes = 4; + break; + case SI__PIPE_CONFIG__ADDR_SURF_P8_16x16_8x16: + case SI__PIPE_CONFIG__ADDR_SURF_P8_16x32_8x16: + case SI__PIPE_CONFIG__ADDR_SURF_P8_32x32_8x16: + case SI__PIPE_CONFIG__ADDR_SURF_P8_16x32_16x16: + case SI__PIPE_CONFIG__ADDR_SURF_P8_32x32_16x16: + case SI__PIPE_CONFIG__ADDR_SURF_P8_32x32_16x32: + case SI__PIPE_CONFIG__ADDR_SURF_P8_32x64_32x32: + *num_pipes = 8; + break; + } + } + if (num_banks) { + switch (SI__GB_TILE_MODE__NUM_BANKS(gb_tile_mode)) { + default: + case SI__NUM_BANKS__2_BANK: + *num_banks = 2; + break; + case SI__NUM_BANKS__4_BANK: + *num_banks = 4; + break; + case SI__NUM_BANKS__8_BANK: + *num_banks = 8; + break; + case SI__NUM_BANKS__16_BANK: + *num_banks = 16; + break; + } + } + if (macro_tile_aspect) { + switch (SI__GB_TILE_MODE__MACRO_TILE_ASPECT(gb_tile_mode)) { + default: + case SI__MACRO_TILE_ASPECT__1: + *macro_tile_aspect = 1; + break; + case SI__MACRO_TILE_ASPECT__2: + *macro_tile_aspect = 2; + break; + case SI__MACRO_TILE_ASPECT__4: + *macro_tile_aspect = 4; + break; + case SI__MACRO_TILE_ASPECT__8: + *macro_tile_aspect = 8; + break; + } + } + if (bank_w) { + switch (SI__GB_TILE_MODE__BANK_WIDTH(gb_tile_mode)) { + default: + case SI__BANK_WIDTH__1: + *bank_w = 1; + break; + case SI__BANK_WIDTH__2: + *bank_w = 2; + break; + case SI__BANK_WIDTH__4: + *bank_w = 4; + break; + case SI__BANK_WIDTH__8: + *bank_w = 8; + break; + } + } + if (bank_h) { + switch (SI__GB_TILE_MODE__BANK_HEIGHT(gb_tile_mode)) { + default: + case SI__BANK_HEIGHT__1: + *bank_h = 1; + break; + case SI__BANK_HEIGHT__2: + *bank_h = 2; + break; + case SI__BANK_HEIGHT__4: + *bank_h = 4; + break; + case SI__BANK_HEIGHT__8: + *bank_h = 8; + break; + } + } + if (tile_split) { + switch (SI__GB_TILE_MODE__TILE_SPLIT(gb_tile_mode)) { + default: + case SI__TILE_SPLIT__64B: + *tile_split = 64; + break; + case SI__TILE_SPLIT__128B: + *tile_split = 128; + break; + case SI__TILE_SPLIT__256B: + *tile_split = 256; + break; + case SI__TILE_SPLIT__512B: + *tile_split = 512; + break; + case SI__TILE_SPLIT__1024B: + *tile_split = 1024; + break; + case SI__TILE_SPLIT__2048B: + *tile_split = 2048; + break; + case SI__TILE_SPLIT__4096B: + *tile_split = 4096; + break; + } + } +} + +static int si_init_hw_info(struct radeon_surface_manager *surf_man) +{ + uint32_t tiling_config; + drmVersionPtr version; + int r; + + r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG, + &tiling_config); + if (r) { + return r; + } + + surf_man->hw_info.allow_2d = 0; + version = drmGetVersion(surf_man->fd); + if (version && version->version_minor >= 33) { + if (!radeon_get_value(surf_man->fd, RADEON_INFO_SI_TILE_MODE_ARRAY, surf_man->hw_info.tile_mode_array)) { + surf_man->hw_info.allow_2d = 1; + } + } + drmFreeVersion(version); + + switch (tiling_config & 0xf) { + case 0: + surf_man->hw_info.num_pipes = 1; + break; + case 1: + surf_man->hw_info.num_pipes = 2; + break; + case 2: + surf_man->hw_info.num_pipes = 4; + break; + case 3: + surf_man->hw_info.num_pipes = 8; + break; + default: + surf_man->hw_info.num_pipes = 8; + surf_man->hw_info.allow_2d = 0; + break; + } + + switch ((tiling_config & 0xf0) >> 4) { + case 0: + surf_man->hw_info.num_banks = 4; + break; + case 1: + surf_man->hw_info.num_banks = 8; + break; + case 2: + surf_man->hw_info.num_banks = 16; + break; + default: + surf_man->hw_info.num_banks = 8; + surf_man->hw_info.allow_2d = 0; + break; + } + + switch ((tiling_config & 0xf00) >> 8) { + case 0: + surf_man->hw_info.group_bytes = 256; + break; + case 1: + surf_man->hw_info.group_bytes = 512; + break; + default: + surf_man->hw_info.group_bytes = 256; + surf_man->hw_info.allow_2d = 0; + break; + } + + switch ((tiling_config & 0xf000) >> 12) { + case 0: + surf_man->hw_info.row_size = 1024; + break; + case 1: + surf_man->hw_info.row_size = 2048; + break; + case 2: + surf_man->hw_info.row_size = 4096; + break; + default: + surf_man->hw_info.row_size = 4096; + surf_man->hw_info.allow_2d = 0; + break; + } + return 0; +} + +static int si_surface_sanity(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + unsigned mode, unsigned *tile_mode, unsigned *stencil_tile_mode) +{ + uint32_t gb_tile_mode; + + /* check surface dimension */ + if (surf->npix_x > 16384 || surf->npix_y > 16384 || surf->npix_z > 16384) { + return -EINVAL; + } + + /* check mipmap last_level */ + if (surf->last_level > 15) { + return -EINVAL; + } + + /* force 1d on kernel that can't do 2d */ + if (mode > RADEON_SURF_MODE_1D && + (!surf_man->hw_info.allow_2d || !(surf->flags & RADEON_SURF_HAS_TILE_MODE_INDEX))) { + if (surf->nsamples > 1) { + fprintf(stderr, "radeon: Cannot use 1D tiling for an MSAA surface (%i).\n", __LINE__); + return -EFAULT; + } + mode = RADEON_SURF_MODE_1D; + surf->flags = RADEON_SURF_CLR(surf->flags, MODE); + surf->flags |= RADEON_SURF_SET(mode, MODE); + } + + if (surf->nsamples > 1 && mode != RADEON_SURF_MODE_2D) { + return -EINVAL; + } + + if (!surf->tile_split) { + /* default value */ + surf->mtilea = 1; + surf->bankw = 1; + surf->bankh = 1; + surf->tile_split = 64; + surf->stencil_tile_split = 64; + } + + switch (mode) { + case RADEON_SURF_MODE_2D: + if (surf->flags & RADEON_SURF_SBUFFER) { + switch (surf->nsamples) { + case 1: + *stencil_tile_mode = SI_TILE_MODE_DEPTH_STENCIL_2D; + break; + case 2: + *stencil_tile_mode = SI_TILE_MODE_DEPTH_STENCIL_2D_2AA; + break; + case 4: + *stencil_tile_mode = SI_TILE_MODE_DEPTH_STENCIL_2D_4AA; + break; + case 8: + *stencil_tile_mode = SI_TILE_MODE_DEPTH_STENCIL_2D_8AA; + break; + default: + return -EINVAL; + } + /* retrieve tiling mode value */ + gb_tile_mode = surf_man->hw_info.tile_mode_array[*stencil_tile_mode]; + si_gb_tile_mode(gb_tile_mode, NULL, NULL, NULL, NULL, NULL, &surf->stencil_tile_split); + } + if (surf->flags & RADEON_SURF_ZBUFFER) { + switch (surf->nsamples) { + case 1: + *tile_mode = SI_TILE_MODE_DEPTH_STENCIL_2D; + break; + case 2: + *tile_mode = SI_TILE_MODE_DEPTH_STENCIL_2D_2AA; + break; + case 4: + *tile_mode = SI_TILE_MODE_DEPTH_STENCIL_2D_4AA; + break; + case 8: + *tile_mode = SI_TILE_MODE_DEPTH_STENCIL_2D_8AA; + break; + default: + return -EINVAL; + } + } else if (surf->flags & RADEON_SURF_SCANOUT) { + switch (surf->bpe) { + case 2: + *tile_mode = SI_TILE_MODE_COLOR_2D_SCANOUT_16BPP; + break; + case 4: + *tile_mode = SI_TILE_MODE_COLOR_2D_SCANOUT_32BPP; + break; + default: + return -EINVAL; + } + } else { + switch (surf->bpe) { + case 1: + *tile_mode = SI_TILE_MODE_COLOR_2D_8BPP; + break; + case 2: + *tile_mode = SI_TILE_MODE_COLOR_2D_16BPP; + break; + case 4: + *tile_mode = SI_TILE_MODE_COLOR_2D_32BPP; + break; + case 8: + case 16: + *tile_mode = SI_TILE_MODE_COLOR_2D_64BPP; + break; + default: + return -EINVAL; + } + } + /* retrieve tiling mode value */ + gb_tile_mode = surf_man->hw_info.tile_mode_array[*tile_mode]; + si_gb_tile_mode(gb_tile_mode, NULL, NULL, &surf->mtilea, &surf->bankw, &surf->bankh, &surf->tile_split); + break; + case RADEON_SURF_MODE_1D: + if (surf->flags & RADEON_SURF_SBUFFER) { + *stencil_tile_mode = SI_TILE_MODE_DEPTH_STENCIL_1D; + } + if (surf->flags & RADEON_SURF_ZBUFFER) { + *tile_mode = SI_TILE_MODE_DEPTH_STENCIL_1D; + } else if (surf->flags & RADEON_SURF_SCANOUT) { + *tile_mode = SI_TILE_MODE_COLOR_1D_SCANOUT; + } else { + *tile_mode = SI_TILE_MODE_COLOR_1D; + } + break; + case RADEON_SURF_MODE_LINEAR_ALIGNED: + default: + *tile_mode = SI_TILE_MODE_COLOR_LINEAR_ALIGNED; + } + + return 0; +} + +static void si_surf_minify(struct radeon_surface *surf, + struct radeon_surface_level *surflevel, + unsigned bpe, unsigned level, + uint32_t xalign, uint32_t yalign, uint32_t zalign, + uint32_t slice_align, uint64_t offset) +{ + if (level == 0) { + surflevel->npix_x = surf->npix_x; + } else { + surflevel->npix_x = mip_minify(next_power_of_two(surf->npix_x), level); + } + surflevel->npix_y = mip_minify(surf->npix_y, level); + surflevel->npix_z = mip_minify(surf->npix_z, level); + + if (level == 0 && surf->last_level > 0) { + surflevel->nblk_x = (next_power_of_two(surflevel->npix_x) + surf->blk_w - 1) / surf->blk_w; + surflevel->nblk_y = (next_power_of_two(surflevel->npix_y) + surf->blk_h - 1) / surf->blk_h; + surflevel->nblk_z = (next_power_of_two(surflevel->npix_z) + surf->blk_d - 1) / surf->blk_d; + } else { + surflevel->nblk_x = (surflevel->npix_x + surf->blk_w - 1) / surf->blk_w; + surflevel->nblk_y = (surflevel->npix_y + surf->blk_h - 1) / surf->blk_h; + surflevel->nblk_z = (surflevel->npix_z + surf->blk_d - 1) / surf->blk_d; + } + + surflevel->nblk_y = ALIGN(surflevel->nblk_y, yalign); + + /* XXX: Texture sampling uses unexpectedly large pitches in some cases, + * these are just guesses for the rules behind those + */ + if (level == 0 && surf->last_level == 0) + /* Non-mipmap pitch padded to slice alignment */ + /* Using just bpe here breaks stencil blitting; surf->bpe works. */ + xalign = MAX2(xalign, slice_align / surf->bpe); + else if (surflevel->mode == RADEON_SURF_MODE_LINEAR_ALIGNED) + /* Small rows evenly distributed across slice */ + xalign = MAX2(xalign, slice_align / bpe / surflevel->nblk_y); + + surflevel->nblk_x = ALIGN(surflevel->nblk_x, xalign); + surflevel->nblk_z = ALIGN(surflevel->nblk_z, zalign); + + surflevel->offset = offset; + surflevel->pitch_bytes = surflevel->nblk_x * bpe * surf->nsamples; + surflevel->slice_size = ALIGN((uint64_t)surflevel->pitch_bytes * surflevel->nblk_y, + (uint64_t)slice_align); + + surf->bo_size = offset + surflevel->slice_size * surflevel->nblk_z * surf->array_size; +} + +static void si_surf_minify_2d(struct radeon_surface *surf, + struct radeon_surface_level *surflevel, + unsigned bpe, unsigned level, unsigned slice_pt, + uint32_t xalign, uint32_t yalign, uint32_t zalign, + unsigned mtileb, uint64_t offset) +{ + unsigned mtile_pr, mtile_ps; + + if (level == 0) { + surflevel->npix_x = surf->npix_x; + } else { + surflevel->npix_x = mip_minify(next_power_of_two(surf->npix_x), level); + } + surflevel->npix_y = mip_minify(surf->npix_y, level); + surflevel->npix_z = mip_minify(surf->npix_z, level); + + if (level == 0 && surf->last_level > 0) { + surflevel->nblk_x = (next_power_of_two(surflevel->npix_x) + surf->blk_w - 1) / surf->blk_w; + surflevel->nblk_y = (next_power_of_two(surflevel->npix_y) + surf->blk_h - 1) / surf->blk_h; + surflevel->nblk_z = (next_power_of_two(surflevel->npix_z) + surf->blk_d - 1) / surf->blk_d; + } else { + surflevel->nblk_x = (surflevel->npix_x + surf->blk_w - 1) / surf->blk_w; + surflevel->nblk_y = (surflevel->npix_y + surf->blk_h - 1) / surf->blk_h; + surflevel->nblk_z = (surflevel->npix_z + surf->blk_d - 1) / surf->blk_d; + } + + if (surf->nsamples == 1 && surflevel->mode == RADEON_SURF_MODE_2D && + !(surf->flags & RADEON_SURF_FMASK)) { + if (surflevel->nblk_x < xalign || surflevel->nblk_y < yalign) { + surflevel->mode = RADEON_SURF_MODE_1D; + return; + } + } + surflevel->nblk_x = ALIGN(surflevel->nblk_x, xalign); + surflevel->nblk_y = ALIGN(surflevel->nblk_y, yalign); + surflevel->nblk_z = ALIGN(surflevel->nblk_z, zalign); + + /* macro tile per row */ + mtile_pr = surflevel->nblk_x / xalign; + /* macro tile per slice */ + mtile_ps = (mtile_pr * surflevel->nblk_y) / yalign; + surflevel->offset = offset; + surflevel->pitch_bytes = surflevel->nblk_x * bpe * surf->nsamples; + surflevel->slice_size = (uint64_t)mtile_ps * mtileb * slice_pt; + + surf->bo_size = offset + surflevel->slice_size * surflevel->nblk_z * surf->array_size; +} + +static int si_surface_init_linear_aligned(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + unsigned tile_mode, + uint64_t offset, unsigned start_level) +{ + uint32_t xalign, yalign, zalign, slice_align; + unsigned i; + + /* compute alignment */ + if (!start_level) { + surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes); + } + xalign = MAX2(8, 64 / surf->bpe); + yalign = 1; + zalign = 1; + slice_align = MAX2(64 * surf->bpe, surf_man->hw_info.group_bytes); + + /* build mipmap tree */ + for (i = start_level; i <= surf->last_level; i++) { + surf->level[i].mode = RADEON_SURF_MODE_LINEAR_ALIGNED; + si_surf_minify(surf, surf->level+i, surf->bpe, i, xalign, yalign, zalign, slice_align, offset); + /* level0 and first mipmap need to have alignment */ + offset = surf->bo_size; + if (i == 0) { + offset = ALIGN(offset, surf->bo_alignment); + } + if (surf->flags & RADEON_SURF_HAS_TILE_MODE_INDEX) { + surf->tiling_index[i] = tile_mode; + } + } + return 0; +} + +static int si_surface_init_1d(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + struct radeon_surface_level *level, + unsigned bpe, unsigned tile_mode, + uint64_t offset, unsigned start_level) +{ + uint32_t xalign, yalign, zalign, slice_align; + unsigned alignment = MAX2(256, surf_man->hw_info.group_bytes); + unsigned i; + + /* compute alignment */ + xalign = 8; + yalign = 8; + zalign = 1; + slice_align = surf_man->hw_info.group_bytes; + if (surf->flags & RADEON_SURF_SCANOUT) { + xalign = MAX2((bpe == 1) ? 64 : 32, xalign); + } + + if (start_level <= 1) { + surf->bo_alignment = MAX2(surf->bo_alignment, alignment); + + if (offset) { + offset = ALIGN(offset, alignment); + } + } + + /* build mipmap tree */ + for (i = start_level; i <= surf->last_level; i++) { + level[i].mode = RADEON_SURF_MODE_1D; + si_surf_minify(surf, level+i, bpe, i, xalign, yalign, zalign, slice_align, offset); + /* level0 and first mipmap need to have alignment */ + offset = surf->bo_size; + if (i == 0) { + offset = ALIGN(offset, alignment); + } + if (surf->flags & RADEON_SURF_HAS_TILE_MODE_INDEX) { + if (surf->level == level) { + surf->tiling_index[i] = tile_mode; + /* it's ok because stencil is done after */ + surf->stencil_tiling_index[i] = tile_mode; + } else { + surf->stencil_tiling_index[i] = tile_mode; + } + } + } + return 0; +} + +static int si_surface_init_1d_miptrees(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + unsigned tile_mode, unsigned stencil_tile_mode) +{ + int r; + + r = si_surface_init_1d(surf_man, surf, surf->level, surf->bpe, tile_mode, 0, 0); + if (r) { + return r; + } + + if (surf->flags & RADEON_SURF_SBUFFER) { + r = si_surface_init_1d(surf_man, surf, surf->stencil_level, 1, stencil_tile_mode, surf->bo_size, 0); + surf->stencil_offset = surf->stencil_level[0].offset; + } + return r; +} + +static int si_surface_init_2d(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + struct radeon_surface_level *level, + unsigned bpe, unsigned tile_mode, + unsigned num_pipes, unsigned num_banks, + unsigned tile_split, + uint64_t offset, + unsigned start_level) +{ + uint64_t aligned_offset = offset; + unsigned tilew, tileh, tileb; + unsigned mtilew, mtileh, mtileb; + unsigned slice_pt; + unsigned i; + + /* compute tile values */ + tilew = 8; + tileh = 8; + tileb = tilew * tileh * bpe * surf->nsamples; + /* slices per tile */ + slice_pt = 1; + if (tileb > tile_split && tile_split) { + slice_pt = tileb / tile_split; + } + tileb = tileb / slice_pt; + + /* macro tile width & height */ + mtilew = (tilew * surf->bankw * num_pipes) * surf->mtilea; + mtileh = (tileh * surf->bankh * num_banks) / surf->mtilea; + + /* macro tile bytes */ + mtileb = (mtilew / tilew) * (mtileh / tileh) * tileb; + + if (start_level <= 1) { + unsigned alignment = MAX2(256, mtileb); + surf->bo_alignment = MAX2(surf->bo_alignment, alignment); + + if (aligned_offset) { + aligned_offset = ALIGN(aligned_offset, alignment); + } + } + + /* build mipmap tree */ + for (i = start_level; i <= surf->last_level; i++) { + level[i].mode = RADEON_SURF_MODE_2D; + si_surf_minify_2d(surf, level+i, bpe, i, slice_pt, mtilew, mtileh, 1, mtileb, aligned_offset); + if (level[i].mode == RADEON_SURF_MODE_1D) { + switch (tile_mode) { + case SI_TILE_MODE_COLOR_2D_8BPP: + case SI_TILE_MODE_COLOR_2D_16BPP: + case SI_TILE_MODE_COLOR_2D_32BPP: + case SI_TILE_MODE_COLOR_2D_64BPP: + tile_mode = SI_TILE_MODE_COLOR_1D; + break; + case SI_TILE_MODE_COLOR_2D_SCANOUT_16BPP: + case SI_TILE_MODE_COLOR_2D_SCANOUT_32BPP: + tile_mode = SI_TILE_MODE_COLOR_1D_SCANOUT; + break; + case SI_TILE_MODE_DEPTH_STENCIL_2D: + tile_mode = SI_TILE_MODE_DEPTH_STENCIL_1D; + break; + default: + return -EINVAL; + } + return si_surface_init_1d(surf_man, surf, level, bpe, tile_mode, offset, i); + } + /* level0 and first mipmap need to have alignment */ + aligned_offset = offset = surf->bo_size; + if (i == 0) { + aligned_offset = ALIGN(aligned_offset, surf->bo_alignment); + } + if (surf->flags & RADEON_SURF_HAS_TILE_MODE_INDEX) { + if (surf->level == level) { + surf->tiling_index[i] = tile_mode; + /* it's ok because stencil is done after */ + surf->stencil_tiling_index[i] = tile_mode; + } else { + surf->stencil_tiling_index[i] = tile_mode; + } + } + } + return 0; +} + +static int si_surface_init_2d_miptrees(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + unsigned tile_mode, unsigned stencil_tile_mode) +{ + unsigned num_pipes, num_banks; + uint32_t gb_tile_mode; + int r; + + /* retrieve tiling mode value */ + gb_tile_mode = surf_man->hw_info.tile_mode_array[tile_mode]; + si_gb_tile_mode(gb_tile_mode, &num_pipes, &num_banks, NULL, NULL, NULL, NULL); + + r = si_surface_init_2d(surf_man, surf, surf->level, surf->bpe, tile_mode, num_pipes, num_banks, surf->tile_split, 0, 0); + if (r) { + return r; + } + + if (surf->flags & RADEON_SURF_SBUFFER) { + r = si_surface_init_2d(surf_man, surf, surf->stencil_level, 1, stencil_tile_mode, num_pipes, num_banks, surf->stencil_tile_split, surf->bo_size, 0); + surf->stencil_offset = surf->stencil_level[0].offset; + } + return r; +} + +static int si_surface_init(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + unsigned mode, tile_mode, stencil_tile_mode; + int r; + + /* MSAA surfaces support the 2D mode only. */ + if (surf->nsamples > 1) { + surf->flags = RADEON_SURF_CLR(surf->flags, MODE); + surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE); + } + + /* tiling mode */ + mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK; + + if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) { + /* zbuffer only support 1D or 2D tiled surface */ + switch (mode) { + case RADEON_SURF_MODE_1D: + case RADEON_SURF_MODE_2D: + break; + default: + mode = RADEON_SURF_MODE_1D; + surf->flags = RADEON_SURF_CLR(surf->flags, MODE); + surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE); + break; + } + } + + r = si_surface_sanity(surf_man, surf, mode, &tile_mode, &stencil_tile_mode); + if (r) { + return r; + } + + surf->stencil_offset = 0; + surf->bo_alignment = 0; + + /* check tiling mode */ + switch (mode) { + case RADEON_SURF_MODE_LINEAR: + r = r6_surface_init_linear(surf_man, surf, 0, 0); + break; + case RADEON_SURF_MODE_LINEAR_ALIGNED: + r = si_surface_init_linear_aligned(surf_man, surf, tile_mode, 0, 0); + break; + case RADEON_SURF_MODE_1D: + r = si_surface_init_1d_miptrees(surf_man, surf, tile_mode, stencil_tile_mode); + break; + case RADEON_SURF_MODE_2D: + r = si_surface_init_2d_miptrees(surf_man, surf, tile_mode, stencil_tile_mode); + break; + default: + return -EINVAL; + } + return r; +} + +/* + * depending on surface + */ +static int si_surface_best(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + unsigned mode, tile_mode, stencil_tile_mode; + + /* tiling mode */ + mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK; + + if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER) && + !(surf->flags & RADEON_SURF_HAS_TILE_MODE_INDEX)) { + /* depth/stencil force 1d tiling for old mesa */ + surf->flags = RADEON_SURF_CLR(surf->flags, MODE); + surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE); + } + + return si_surface_sanity(surf_man, surf, mode, &tile_mode, &stencil_tile_mode); +} + + +/* =========================================================================== + * Sea Islands family + */ +#define CIK__GB_TILE_MODE__PIPE_CONFIG(x) (((x) >> 6) & 0x1f) +#define CIK__PIPE_CONFIG__ADDR_SURF_P2 0 +#define CIK__PIPE_CONFIG__ADDR_SURF_P4_8x16 4 +#define CIK__PIPE_CONFIG__ADDR_SURF_P4_16x16 5 +#define CIK__PIPE_CONFIG__ADDR_SURF_P4_16x32 6 +#define CIK__PIPE_CONFIG__ADDR_SURF_P4_32x32 7 +#define CIK__PIPE_CONFIG__ADDR_SURF_P8_16x16_8x16 8 +#define CIK__PIPE_CONFIG__ADDR_SURF_P8_16x32_8x16 9 +#define CIK__PIPE_CONFIG__ADDR_SURF_P8_32x32_8x16 10 +#define CIK__PIPE_CONFIG__ADDR_SURF_P8_16x32_16x16 11 +#define CIK__PIPE_CONFIG__ADDR_SURF_P8_32x32_16x16 12 +#define CIK__PIPE_CONFIG__ADDR_SURF_P8_32x32_16x32 13 +#define CIK__PIPE_CONFIG__ADDR_SURF_P8_32x64_32x32 14 +#define CIK__PIPE_CONFIG__ADDR_SURF_P16_32X32_8X16 16 +#define CIK__PIPE_CONFIG__ADDR_SURF_P16_32X32_16X16 17 +#define CIK__GB_TILE_MODE__TILE_SPLIT(x) (((x) >> 11) & 0x7) +#define CIK__TILE_SPLIT__64B 0 +#define CIK__TILE_SPLIT__128B 1 +#define CIK__TILE_SPLIT__256B 2 +#define CIK__TILE_SPLIT__512B 3 +#define CIK__TILE_SPLIT__1024B 4 +#define CIK__TILE_SPLIT__2048B 5 +#define CIK__TILE_SPLIT__4096B 6 +#define CIK__GB_TILE_MODE__SAMPLE_SPLIT(x) (((x) >> 25) & 0x3) +#define CIK__SAMPLE_SPLIT__1 0 +#define CIK__SAMPLE_SPLIT__2 1 +#define CIK__SAMPLE_SPLIT__4 2 +#define CIK__SAMPLE_SPLIT__8 3 +#define CIK__GB_MACROTILE_MODE__BANK_WIDTH(x) ((x) & 0x3) +#define CIK__BANK_WIDTH__1 0 +#define CIK__BANK_WIDTH__2 1 +#define CIK__BANK_WIDTH__4 2 +#define CIK__BANK_WIDTH__8 3 +#define CIK__GB_MACROTILE_MODE__BANK_HEIGHT(x) (((x) >> 2) & 0x3) +#define CIK__BANK_HEIGHT__1 0 +#define CIK__BANK_HEIGHT__2 1 +#define CIK__BANK_HEIGHT__4 2 +#define CIK__BANK_HEIGHT__8 3 +#define CIK__GB_MACROTILE_MODE__MACRO_TILE_ASPECT(x) (((x) >> 4) & 0x3) +#define CIK__MACRO_TILE_ASPECT__1 0 +#define CIK__MACRO_TILE_ASPECT__2 1 +#define CIK__MACRO_TILE_ASPECT__4 2 +#define CIK__MACRO_TILE_ASPECT__8 3 +#define CIK__GB_MACROTILE_MODE__NUM_BANKS(x) (((x) >> 6) & 0x3) +#define CIK__NUM_BANKS__2_BANK 0 +#define CIK__NUM_BANKS__4_BANK 1 +#define CIK__NUM_BANKS__8_BANK 2 +#define CIK__NUM_BANKS__16_BANK 3 + + +static void cik_get_2d_params(struct radeon_surface_manager *surf_man, + unsigned bpe, unsigned nsamples, bool is_color, + unsigned tile_mode, + uint32_t *num_pipes, + uint32_t *tile_split_ptr, + uint32_t *num_banks, + uint32_t *macro_tile_aspect, + uint32_t *bank_w, + uint32_t *bank_h) +{ + uint32_t gb_tile_mode = surf_man->hw_info.tile_mode_array[tile_mode]; + unsigned tileb_1x, tileb; + unsigned gb_macrotile_mode; + unsigned macrotile_index; + unsigned tile_split, sample_split; + + if (num_pipes) { + switch (CIK__GB_TILE_MODE__PIPE_CONFIG(gb_tile_mode)) { + case CIK__PIPE_CONFIG__ADDR_SURF_P2: + default: + *num_pipes = 2; + break; + case CIK__PIPE_CONFIG__ADDR_SURF_P4_8x16: + case CIK__PIPE_CONFIG__ADDR_SURF_P4_16x16: + case CIK__PIPE_CONFIG__ADDR_SURF_P4_16x32: + case CIK__PIPE_CONFIG__ADDR_SURF_P4_32x32: + *num_pipes = 4; + break; + case CIK__PIPE_CONFIG__ADDR_SURF_P8_16x16_8x16: + case CIK__PIPE_CONFIG__ADDR_SURF_P8_16x32_8x16: + case CIK__PIPE_CONFIG__ADDR_SURF_P8_32x32_8x16: + case CIK__PIPE_CONFIG__ADDR_SURF_P8_16x32_16x16: + case CIK__PIPE_CONFIG__ADDR_SURF_P8_32x32_16x16: + case CIK__PIPE_CONFIG__ADDR_SURF_P8_32x32_16x32: + case CIK__PIPE_CONFIG__ADDR_SURF_P8_32x64_32x32: + *num_pipes = 8; + break; + case CIK__PIPE_CONFIG__ADDR_SURF_P16_32X32_8X16: + case CIK__PIPE_CONFIG__ADDR_SURF_P16_32X32_16X16: + *num_pipes = 16; + break; + } + } + switch (CIK__GB_TILE_MODE__TILE_SPLIT(gb_tile_mode)) { + default: + case CIK__TILE_SPLIT__64B: + tile_split = 64; + break; + case CIK__TILE_SPLIT__128B: + tile_split = 128; + break; + case CIK__TILE_SPLIT__256B: + tile_split = 256; + break; + case CIK__TILE_SPLIT__512B: + tile_split = 512; + break; + case CIK__TILE_SPLIT__1024B: + tile_split = 1024; + break; + case CIK__TILE_SPLIT__2048B: + tile_split = 2048; + break; + case CIK__TILE_SPLIT__4096B: + tile_split = 4096; + break; + } + switch (CIK__GB_TILE_MODE__SAMPLE_SPLIT(gb_tile_mode)) { + default: + case CIK__SAMPLE_SPLIT__1: + sample_split = 1; + break; + case CIK__SAMPLE_SPLIT__2: + sample_split = 2; + break; + case CIK__SAMPLE_SPLIT__4: + sample_split = 4; + break; + case CIK__SAMPLE_SPLIT__8: + sample_split = 8; + break; + } + + /* Adjust the tile split. */ + tileb_1x = 8 * 8 * bpe; + if (is_color) { + tile_split = MAX2(256, sample_split * tileb_1x); + } + tile_split = MIN2(surf_man->hw_info.row_size, tile_split); + + /* Determine the macrotile index. */ + tileb = MIN2(tile_split, nsamples * tileb_1x); + + for (macrotile_index = 0; tileb > 64; macrotile_index++) { + tileb >>= 1; + } + gb_macrotile_mode = surf_man->hw_info.macrotile_mode_array[macrotile_index]; + + if (tile_split_ptr) { + *tile_split_ptr = tile_split; + } + if (num_banks) { + switch (CIK__GB_MACROTILE_MODE__NUM_BANKS(gb_macrotile_mode)) { + default: + case CIK__NUM_BANKS__2_BANK: + *num_banks = 2; + break; + case CIK__NUM_BANKS__4_BANK: + *num_banks = 4; + break; + case CIK__NUM_BANKS__8_BANK: + *num_banks = 8; + break; + case CIK__NUM_BANKS__16_BANK: + *num_banks = 16; + break; + } + } + if (macro_tile_aspect) { + switch (CIK__GB_MACROTILE_MODE__MACRO_TILE_ASPECT(gb_macrotile_mode)) { + default: + case CIK__MACRO_TILE_ASPECT__1: + *macro_tile_aspect = 1; + break; + case CIK__MACRO_TILE_ASPECT__2: + *macro_tile_aspect = 2; + break; + case CIK__MACRO_TILE_ASPECT__4: + *macro_tile_aspect = 4; + break; + case CIK__MACRO_TILE_ASPECT__8: + *macro_tile_aspect = 8; + break; + } + } + if (bank_w) { + switch (CIK__GB_MACROTILE_MODE__BANK_WIDTH(gb_macrotile_mode)) { + default: + case CIK__BANK_WIDTH__1: + *bank_w = 1; + break; + case CIK__BANK_WIDTH__2: + *bank_w = 2; + break; + case CIK__BANK_WIDTH__4: + *bank_w = 4; + break; + case CIK__BANK_WIDTH__8: + *bank_w = 8; + break; + } + } + if (bank_h) { + switch (CIK__GB_MACROTILE_MODE__BANK_HEIGHT(gb_macrotile_mode)) { + default: + case CIK__BANK_HEIGHT__1: + *bank_h = 1; + break; + case CIK__BANK_HEIGHT__2: + *bank_h = 2; + break; + case CIK__BANK_HEIGHT__4: + *bank_h = 4; + break; + case CIK__BANK_HEIGHT__8: + *bank_h = 8; + break; + } + } +} + +static int cik_init_hw_info(struct radeon_surface_manager *surf_man) +{ + uint32_t tiling_config; + drmVersionPtr version; + int r; + + r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG, + &tiling_config); + if (r) { + return r; + } + + surf_man->hw_info.allow_2d = 0; + version = drmGetVersion(surf_man->fd); + if (version && version->version_minor >= 35) { + if (!radeon_get_value(surf_man->fd, RADEON_INFO_SI_TILE_MODE_ARRAY, surf_man->hw_info.tile_mode_array) && + !radeon_get_value(surf_man->fd, RADEON_INFO_CIK_MACROTILE_MODE_ARRAY, surf_man->hw_info.macrotile_mode_array)) { + surf_man->hw_info.allow_2d = 1; + } + } + drmFreeVersion(version); + + switch (tiling_config & 0xf) { + case 0: + surf_man->hw_info.num_pipes = 1; + break; + case 1: + surf_man->hw_info.num_pipes = 2; + break; + case 2: + surf_man->hw_info.num_pipes = 4; + break; + case 3: + surf_man->hw_info.num_pipes = 8; + break; + default: + surf_man->hw_info.num_pipes = 8; + surf_man->hw_info.allow_2d = 0; + break; + } + + switch ((tiling_config & 0xf0) >> 4) { + case 0: + surf_man->hw_info.num_banks = 4; + break; + case 1: + surf_man->hw_info.num_banks = 8; + break; + case 2: + surf_man->hw_info.num_banks = 16; + break; + default: + surf_man->hw_info.num_banks = 8; + surf_man->hw_info.allow_2d = 0; + break; + } + + switch ((tiling_config & 0xf00) >> 8) { + case 0: + surf_man->hw_info.group_bytes = 256; + break; + case 1: + surf_man->hw_info.group_bytes = 512; + break; + default: + surf_man->hw_info.group_bytes = 256; + surf_man->hw_info.allow_2d = 0; + break; + } + + switch ((tiling_config & 0xf000) >> 12) { + case 0: + surf_man->hw_info.row_size = 1024; + break; + case 1: + surf_man->hw_info.row_size = 2048; + break; + case 2: + surf_man->hw_info.row_size = 4096; + break; + default: + surf_man->hw_info.row_size = 4096; + surf_man->hw_info.allow_2d = 0; + break; + } + return 0; +} + +static int cik_surface_sanity(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + unsigned mode, unsigned *tile_mode, unsigned *stencil_tile_mode) +{ + /* check surface dimension */ + if (surf->npix_x > 16384 || surf->npix_y > 16384 || surf->npix_z > 16384) { + return -EINVAL; + } + + /* check mipmap last_level */ + if (surf->last_level > 15) { + return -EINVAL; + } + + /* force 1d on kernel that can't do 2d */ + if (mode > RADEON_SURF_MODE_1D && + (!surf_man->hw_info.allow_2d || !(surf->flags & RADEON_SURF_HAS_TILE_MODE_INDEX))) { + if (surf->nsamples > 1) { + fprintf(stderr, "radeon: Cannot use 1D tiling for an MSAA surface (%i).\n", __LINE__); + return -EFAULT; + } + mode = RADEON_SURF_MODE_1D; + surf->flags = RADEON_SURF_CLR(surf->flags, MODE); + surf->flags |= RADEON_SURF_SET(mode, MODE); + } + + if (surf->nsamples > 1 && mode != RADEON_SURF_MODE_2D) { + return -EINVAL; + } + + if (!surf->tile_split) { + /* default value */ + surf->mtilea = 1; + surf->bankw = 1; + surf->bankh = 1; + surf->tile_split = 64; + surf->stencil_tile_split = 64; + } + + switch (mode) { + case RADEON_SURF_MODE_2D: { + if (surf->flags & RADEON_SURF_Z_OR_SBUFFER) { + switch (surf->nsamples) { + case 1: + *tile_mode = CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_64; + break; + case 2: + case 4: + *tile_mode = CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_128; + break; + case 8: + *tile_mode = CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_256; + break; + default: + return -EINVAL; + } + + if (surf->flags & RADEON_SURF_SBUFFER) { + *stencil_tile_mode = *tile_mode; + + cik_get_2d_params(surf_man, 1, surf->nsamples, false, + *stencil_tile_mode, NULL, + &surf->stencil_tile_split, + NULL, NULL, NULL, NULL); + } + } else if (surf->flags & RADEON_SURF_SCANOUT) { + *tile_mode = CIK_TILE_MODE_COLOR_2D_SCANOUT; + } else { + *tile_mode = CIK_TILE_MODE_COLOR_2D; + } + + /* retrieve tiling mode values */ + cik_get_2d_params(surf_man, surf->bpe, surf->nsamples, + !(surf->flags & RADEON_SURF_Z_OR_SBUFFER), *tile_mode, + NULL, &surf->tile_split, NULL, &surf->mtilea, + &surf->bankw, &surf->bankh); + break; + } + case RADEON_SURF_MODE_1D: + if (surf->flags & RADEON_SURF_SBUFFER) { + *stencil_tile_mode = CIK_TILE_MODE_DEPTH_STENCIL_1D; + } + if (surf->flags & RADEON_SURF_ZBUFFER) { + *tile_mode = CIK_TILE_MODE_DEPTH_STENCIL_1D; + } else if (surf->flags & RADEON_SURF_SCANOUT) { + *tile_mode = SI_TILE_MODE_COLOR_1D_SCANOUT; + } else { + *tile_mode = SI_TILE_MODE_COLOR_1D; + } + break; + case RADEON_SURF_MODE_LINEAR_ALIGNED: + default: + *tile_mode = SI_TILE_MODE_COLOR_LINEAR_ALIGNED; + } + + return 0; +} + +static int cik_surface_init_2d(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + struct radeon_surface_level *level, + unsigned bpe, unsigned tile_mode, + unsigned tile_split, + unsigned num_pipes, unsigned num_banks, + uint64_t offset, + unsigned start_level) +{ + uint64_t aligned_offset = offset; + unsigned tilew, tileh, tileb_1x, tileb; + unsigned mtilew, mtileh, mtileb; + unsigned slice_pt; + unsigned i; + + /* compute tile values */ + tilew = 8; + tileh = 8; + tileb_1x = tilew * tileh * bpe; + + tile_split = MIN2(surf_man->hw_info.row_size, tile_split); + + tileb = surf->nsamples * tileb_1x; + + /* slices per tile */ + slice_pt = 1; + if (tileb > tile_split && tile_split) { + slice_pt = tileb / tile_split; + tileb = tileb / slice_pt; + } + + /* macro tile width & height */ + mtilew = (tilew * surf->bankw * num_pipes) * surf->mtilea; + mtileh = (tileh * surf->bankh * num_banks) / surf->mtilea; + + /* macro tile bytes */ + mtileb = (mtilew / tilew) * (mtileh / tileh) * tileb; + + if (start_level <= 1) { + unsigned alignment = MAX2(256, mtileb); + surf->bo_alignment = MAX2(surf->bo_alignment, alignment); + + if (aligned_offset) { + aligned_offset = ALIGN(aligned_offset, alignment); + } + } + + /* build mipmap tree */ + for (i = start_level; i <= surf->last_level; i++) { + level[i].mode = RADEON_SURF_MODE_2D; + si_surf_minify_2d(surf, level+i, bpe, i, slice_pt, mtilew, mtileh, 1, mtileb, aligned_offset); + if (level[i].mode == RADEON_SURF_MODE_1D) { + switch (tile_mode) { + case CIK_TILE_MODE_COLOR_2D: + tile_mode = SI_TILE_MODE_COLOR_1D; + break; + case CIK_TILE_MODE_COLOR_2D_SCANOUT: + tile_mode = SI_TILE_MODE_COLOR_1D_SCANOUT; + break; + case CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_64: + case CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_128: + case CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_256: + case CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_512: + case CIK_TILE_MODE_DEPTH_STENCIL_2D_TILESPLIT_ROW_SIZE: + tile_mode = CIK_TILE_MODE_DEPTH_STENCIL_1D; + break; + default: + return -EINVAL; + } + return si_surface_init_1d(surf_man, surf, level, bpe, tile_mode, offset, i); + } + /* level0 and first mipmap need to have alignment */ + aligned_offset = offset = surf->bo_size; + if (i == 0) { + aligned_offset = ALIGN(aligned_offset, surf->bo_alignment); + } + if (surf->flags & RADEON_SURF_HAS_TILE_MODE_INDEX) { + if (surf->level == level) { + surf->tiling_index[i] = tile_mode; + /* it's ok because stencil is done after */ + surf->stencil_tiling_index[i] = tile_mode; + } else { + surf->stencil_tiling_index[i] = tile_mode; + } + } + } + return 0; +} + +static int cik_surface_init_2d_miptrees(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + unsigned tile_mode, unsigned stencil_tile_mode) +{ + int r; + uint32_t num_pipes, num_banks; + + cik_get_2d_params(surf_man, surf->bpe, surf->nsamples, + !(surf->flags & RADEON_SURF_Z_OR_SBUFFER), tile_mode, + &num_pipes, NULL, &num_banks, NULL, NULL, NULL); + + r = cik_surface_init_2d(surf_man, surf, surf->level, surf->bpe, tile_mode, + surf->tile_split, num_pipes, num_banks, 0, 0); + if (r) { + return r; + } + + if (surf->flags & RADEON_SURF_SBUFFER) { + r = cik_surface_init_2d(surf_man, surf, surf->stencil_level, 1, stencil_tile_mode, + surf->stencil_tile_split, num_pipes, num_banks, + surf->bo_size, 0); + surf->stencil_offset = surf->stencil_level[0].offset; + } + return r; +} + +static int cik_surface_init(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + unsigned mode, tile_mode, stencil_tile_mode; + int r; + + /* MSAA surfaces support the 2D mode only. */ + if (surf->nsamples > 1) { + surf->flags = RADEON_SURF_CLR(surf->flags, MODE); + surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE); + } + + /* tiling mode */ + mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK; + + if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) { + /* zbuffer only support 1D or 2D tiled surface */ + switch (mode) { + case RADEON_SURF_MODE_1D: + case RADEON_SURF_MODE_2D: + break; + default: + mode = RADEON_SURF_MODE_1D; + surf->flags = RADEON_SURF_CLR(surf->flags, MODE); + surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE); + break; + } + } + + r = cik_surface_sanity(surf_man, surf, mode, &tile_mode, &stencil_tile_mode); + if (r) { + return r; + } + + surf->stencil_offset = 0; + surf->bo_alignment = 0; + + /* check tiling mode */ + switch (mode) { + case RADEON_SURF_MODE_LINEAR: + r = r6_surface_init_linear(surf_man, surf, 0, 0); + break; + case RADEON_SURF_MODE_LINEAR_ALIGNED: + r = si_surface_init_linear_aligned(surf_man, surf, tile_mode, 0, 0); + break; + case RADEON_SURF_MODE_1D: + r = si_surface_init_1d_miptrees(surf_man, surf, tile_mode, stencil_tile_mode); + break; + case RADEON_SURF_MODE_2D: + r = cik_surface_init_2d_miptrees(surf_man, surf, tile_mode, stencil_tile_mode); + break; + default: + return -EINVAL; + } + return r; +} + +/* + * depending on surface + */ +static int cik_surface_best(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + unsigned mode, tile_mode, stencil_tile_mode; + + /* tiling mode */ + mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK; + + if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER) && + !(surf->flags & RADEON_SURF_HAS_TILE_MODE_INDEX)) { + /* depth/stencil force 1d tiling for old mesa */ + surf->flags = RADEON_SURF_CLR(surf->flags, MODE); + surf->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE); + } + + return cik_surface_sanity(surf_man, surf, mode, &tile_mode, &stencil_tile_mode); +} + + +/* =========================================================================== + * public API + */ +drm_public struct radeon_surface_manager * +radeon_surface_manager_new(int fd) +{ + struct radeon_surface_manager *surf_man; + + surf_man = calloc(1, sizeof(struct radeon_surface_manager)); + if (surf_man == NULL) { + return NULL; + } + surf_man->fd = fd; + if (radeon_get_value(fd, RADEON_INFO_DEVICE_ID, &surf_man->device_id)) { + goto out_err; + } + if (radeon_get_family(surf_man)) { + goto out_err; + } + + if (surf_man->family <= CHIP_RV740) { + if (r6_init_hw_info(surf_man)) { + goto out_err; + } + surf_man->surface_init = &r6_surface_init; + surf_man->surface_best = &r6_surface_best; + } else if (surf_man->family <= CHIP_ARUBA) { + if (eg_init_hw_info(surf_man)) { + goto out_err; + } + surf_man->surface_init = &eg_surface_init; + surf_man->surface_best = &eg_surface_best; + } else if (surf_man->family < CHIP_BONAIRE) { + if (si_init_hw_info(surf_man)) { + goto out_err; + } + surf_man->surface_init = &si_surface_init; + surf_man->surface_best = &si_surface_best; + } else { + if (cik_init_hw_info(surf_man)) { + goto out_err; + } + surf_man->surface_init = &cik_surface_init; + surf_man->surface_best = &cik_surface_best; + } + + return surf_man; +out_err: + free(surf_man); + return NULL; +} + +drm_public void +radeon_surface_manager_free(struct radeon_surface_manager *surf_man) +{ + free(surf_man); +} + +static int radeon_surface_sanity(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + unsigned type, + unsigned mode) +{ + if (surf_man == NULL || surf_man->surface_init == NULL || surf == NULL) { + return -EINVAL; + } + + /* all dimension must be at least 1 ! */ + if (!surf->npix_x || !surf->npix_y || !surf->npix_z) { + return -EINVAL; + } + if (!surf->blk_w || !surf->blk_h || !surf->blk_d) { + return -EINVAL; + } + if (!surf->array_size) { + return -EINVAL; + } + /* array size must be a power of 2 */ + surf->array_size = next_power_of_two(surf->array_size); + + switch (surf->nsamples) { + case 1: + case 2: + case 4: + case 8: + break; + default: + return -EINVAL; + } + /* check type */ + switch (type) { + case RADEON_SURF_TYPE_1D: + if (surf->npix_y > 1) { + return -EINVAL; + } + /* fallthrough */ + case RADEON_SURF_TYPE_2D: + if (surf->npix_z > 1) { + return -EINVAL; + } + break; + case RADEON_SURF_TYPE_CUBEMAP: + if (surf->npix_z > 1) { + return -EINVAL; + } + /* deal with cubemap as they were texture array */ + if (surf_man->family >= CHIP_RV770) { + surf->array_size = 8; + } else { + surf->array_size = 6; + } + break; + case RADEON_SURF_TYPE_3D: + break; + case RADEON_SURF_TYPE_1D_ARRAY: + if (surf->npix_y > 1) { + return -EINVAL; + } + case RADEON_SURF_TYPE_2D_ARRAY: + break; + default: + return -EINVAL; + } + return 0; +} + +drm_public int +radeon_surface_init(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + unsigned mode, type; + int r; + + type = RADEON_SURF_GET(surf->flags, TYPE); + mode = RADEON_SURF_GET(surf->flags, MODE); + + r = radeon_surface_sanity(surf_man, surf, type, mode); + if (r) { + return r; + } + return surf_man->surface_init(surf_man, surf); +} + +drm_public int +radeon_surface_best(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + unsigned mode, type; + int r; + + type = RADEON_SURF_GET(surf->flags, TYPE); + mode = RADEON_SURF_GET(surf->flags, MODE); + + r = radeon_surface_sanity(surf_man, surf, type, mode); + if (r) { + return r; + } + return surf_man->surface_best(surf_man, surf); +} diff --git a/radeon/radeon_surface.h b/radeon/radeon_surface.h new file mode 100644 index 0000000..af7cab6 --- /dev/null +++ b/radeon/radeon_surface.h @@ -0,0 +1,149 @@ +/* + * Copyright © 2011 Red Hat 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 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 THE COPYRIGHT HOLDERS, AUTHORS + * 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + */ +/* + * Authors: + * Jérôme Glisse + */ +#ifndef RADEON_SURFACE_H +#define RADEON_SURFACE_H + +/* Note : + * + * For texture array, the n layer are stored one after the other within each + * mipmap level. 0 value for field than can be hint is always valid. + */ + +#define RADEON_SURF_MAX_LEVEL 32 + +#define RADEON_SURF_TYPE_MASK 0xFF +#define RADEON_SURF_TYPE_SHIFT 0 +#define RADEON_SURF_TYPE_1D 0 +#define RADEON_SURF_TYPE_2D 1 +#define RADEON_SURF_TYPE_3D 2 +#define RADEON_SURF_TYPE_CUBEMAP 3 +#define RADEON_SURF_TYPE_1D_ARRAY 4 +#define RADEON_SURF_TYPE_2D_ARRAY 5 +#define RADEON_SURF_MODE_MASK 0xFF +#define RADEON_SURF_MODE_SHIFT 8 +#define RADEON_SURF_MODE_LINEAR 0 +#define RADEON_SURF_MODE_LINEAR_ALIGNED 1 +#define RADEON_SURF_MODE_1D 2 +#define RADEON_SURF_MODE_2D 3 +#define RADEON_SURF_SCANOUT (1 << 16) +#define RADEON_SURF_ZBUFFER (1 << 17) +#define RADEON_SURF_SBUFFER (1 << 18) +#define RADEON_SURF_Z_OR_SBUFFER (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER) +#define RADEON_SURF_HAS_SBUFFER_MIPTREE (1 << 19) +#define RADEON_SURF_HAS_TILE_MODE_INDEX (1 << 20) +#define RADEON_SURF_FMASK (1 << 21) + +#define RADEON_SURF_GET(v, field) (((v) >> RADEON_SURF_ ## field ## _SHIFT) & RADEON_SURF_ ## field ## _MASK) +#define RADEON_SURF_SET(v, field) (((v) & RADEON_SURF_ ## field ## _MASK) << RADEON_SURF_ ## field ## _SHIFT) +#define RADEON_SURF_CLR(v, field) ((v) & ~(RADEON_SURF_ ## field ## _MASK << RADEON_SURF_ ## field ## _SHIFT)) + +/* first field up to mode need to match r6 struct so that we can reuse + * same function for linear & linear aligned + */ +struct radeon_surface_level { + uint64_t offset; + uint64_t slice_size; + uint32_t npix_x; + uint32_t npix_y; + uint32_t npix_z; + uint32_t nblk_x; + uint32_t nblk_y; + uint32_t nblk_z; + uint32_t pitch_bytes; + uint32_t mode; +}; + +enum si_tiling_mode { + SI_TILING_AUTO = 0, + + SI_TILING_COLOR_1D, + SI_TILING_COLOR_1D_SCANOUT, + SI_TILING_COLOR_2D_8BPP, + SI_TILING_COLOR_2D_16BPP, + SI_TILING_COLOR_2D_32BPP, + SI_TILING_COLOR_2D_64BPP, + SI_TILING_COLOR_2D_SCANOUT_16BPP, + SI_TILING_COLOR_2D_SCANOUT_32BPP, + SI_TILING_COLOR_LINEAR, + + SI_TILING_STENCIL_1D, + SI_TILING_STENCIL_2D, + SI_TILING_STENCIL_2D_2AA, + SI_TILING_STENCIL_2D_4AA, + SI_TILING_STENCIL_2D_8AA, + + SI_TILING_DEPTH_1D, + SI_TILING_DEPTH_2D, + SI_TILING_DEPTH_2D_2AA, + SI_TILING_DEPTH_2D_4AA, + SI_TILING_DEPTH_2D_8AA, + + SI_TILING_LAST_MODE, +}; + +struct radeon_surface { + uint32_t npix_x; + uint32_t npix_y; + uint32_t npix_z; + uint32_t blk_w; + uint32_t blk_h; + uint32_t blk_d; + uint32_t array_size; + uint32_t last_level; + uint32_t bpe; + uint32_t nsamples; + uint32_t flags; + /* Following is updated/fill by the allocator. It's allowed to + * set some of the value but they are use as hint and can be + * overridden (things lile bankw/bankh on evergreen for + * instance). + */ + uint64_t bo_size; + uint64_t bo_alignment; + /* apply to eg */ + uint32_t bankw; + uint32_t bankh; + uint32_t mtilea; + uint32_t tile_split; + uint32_t stencil_tile_split; + uint64_t stencil_offset; + struct radeon_surface_level level[RADEON_SURF_MAX_LEVEL]; + struct radeon_surface_level stencil_level[RADEON_SURF_MAX_LEVEL]; + uint32_t tiling_index[RADEON_SURF_MAX_LEVEL]; + uint32_t stencil_tiling_index[RADEON_SURF_MAX_LEVEL]; +}; + +struct radeon_surface_manager *radeon_surface_manager_new(int fd); +void radeon_surface_manager_free(struct radeon_surface_manager *surf_man); +int radeon_surface_init(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf); +int radeon_surface_best(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf); + +#endif diff --git a/symbols-check.py b/symbols-check.py new file mode 100644 index 0000000..2e7ba68 --- /dev/null +++ b/symbols-check.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 + +import argparse +import os +import platform +import subprocess + +# This list contains symbols that _might_ be exported for some platforms +PLATFORM_SYMBOLS = [ + '__bss_end__', + '__bss_start__', + '__bss_start', + '__end__', + '_bss_end__', + '_edata', + '_end', + '_fini', + '_init', +] + + +def get_symbols(nm, lib): + ''' + List all the (non platform-specific) symbols exported by the library + ''' + symbols = [] + platform_name = platform.system() + output = subprocess.check_output([nm, '-gP', lib], + stderr=open(os.devnull, 'w')).decode("ascii") + for line in output.splitlines(): + fields = line.split() + if len(fields) == 2 or fields[1] == 'U': + continue + symbol_name = fields[0] + if platform_name == 'Linux': + if symbol_name in PLATFORM_SYMBOLS: + continue + elif platform_name == 'Darwin': + assert symbol_name[0] == '_' + symbol_name = symbol_name[1:] + symbols.append(symbol_name) + + return symbols + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--symbols-file', + action='store', + required=True, + help='path to file containing symbols') + parser.add_argument('--lib', + action='store', + required=True, + help='path to library') + parser.add_argument('--nm', + action='store', + required=True, + help='path to binary (or name in $PATH)') + args = parser.parse_args() + + try: + lib_symbols = get_symbols(args.nm, args.lib) + except: + # We can't run this test, but we haven't technically failed it either + # Return the GNU "skip" error code + exit(77) + mandatory_symbols = [] + optional_symbols = [] + with open(args.symbols_file) as symbols_file: + qualifier_optional = '(optional)' + for line in symbols_file.readlines(): + + # Strip comments + line = line.split('#')[0] + line = line.strip() + if not line: + continue + + # Line format: + # [qualifier] symbol + qualifier = None + symbol = None + + fields = line.split() + if len(fields) == 1: + symbol = fields[0] + elif len(fields) == 2: + qualifier = fields[0] + symbol = fields[1] + else: + print(args.symbols_file + ': invalid format: ' + line) + exit(1) + + # The only supported qualifier is 'optional', which means the + # symbol doesn't have to be exported by the library + if qualifier and not qualifier == qualifier_optional: + print(args.symbols_file + ': invalid qualifier: ' + qualifier) + exit(1) + + if qualifier == qualifier_optional: + optional_symbols.append(symbol) + else: + mandatory_symbols.append(symbol) + + unknown_symbols = [] + for symbol in lib_symbols: + if symbol in mandatory_symbols: + continue + if symbol in optional_symbols: + continue + unknown_symbols.append(symbol) + + missing_symbols = [ + sym for sym in mandatory_symbols if sym not in lib_symbols + ] + + for symbol in unknown_symbols: + print(args.lib + ': unknown symbol exported: ' + symbol) + + for symbol in missing_symbols: + print(args.lib + ': missing symbol: ' + symbol) + + if unknown_symbols or missing_symbols: + exit(1) + exit(0) + + +if __name__ == '__main__': + main() diff --git a/tegra/.gitignore b/tegra/.gitignore new file mode 100644 index 0000000..74cfe47 --- /dev/null +++ b/tegra/.gitignore @@ -0,0 +1 @@ +libdrm_tegra.pc diff --git a/tegra/channel.c b/tegra/channel.c new file mode 100644 index 0000000..3913620 --- /dev/null +++ b/tegra/channel.c @@ -0,0 +1,195 @@ +/* + * Copyright © 2012, 2013 Thierry Reding + * Copyright © 2013 Erik Faye-Lund + * Copyright © 2014-2021 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include + +#include "private.h" + +drm_public int +drm_tegra_channel_open(struct drm_tegra *drm, + enum drm_tegra_class client, + struct drm_tegra_channel **channelp) +{ + struct drm_tegra_channel_open args; + struct drm_tegra_channel *channel; + enum host1x_class class; + int err; + + switch (client) { + case DRM_TEGRA_HOST1X: + class = HOST1X_CLASS_HOST1X; + break; + + case DRM_TEGRA_GR2D: + class = HOST1X_CLASS_GR2D; + break; + + case DRM_TEGRA_GR3D: + class = HOST1X_CLASS_GR3D; + break; + + case DRM_TEGRA_VIC: + class = HOST1X_CLASS_VIC; + break; + + default: + return -EINVAL; + } + + channel = calloc(1, sizeof(*channel)); + if (!channel) + return -ENOMEM; + + channel->drm = drm; + + memset(&args, 0, sizeof(args)); + args.host1x_class = class; + + err = ioctl(drm->fd, DRM_IOCTL_TEGRA_CHANNEL_OPEN, &args); + if (err < 0) { + free(channel); + return -errno; + } + + channel->context = args.context; + channel->version = args.version; + channel->capabilities = args.capabilities; + channel->class = class; + + switch (channel->version) { + case 0x20: + case 0x30: + case 0x35: + case 0x40: + case 0x21: + channel->cond_shift = 8; + break; + + case 0x18: + case 0x19: + channel->cond_shift = 10; + break; + + default: + return -ENOTSUP; + } + + *channelp = channel; + + return 0; +} + +drm_public int drm_tegra_channel_close(struct drm_tegra_channel *channel) +{ + struct drm_tegra_channel_close args; + struct drm_tegra *drm; + int err; + + if (!channel) + return -EINVAL; + + drm = channel->drm; + + memset(&args, 0, sizeof(args)); + args.context = channel->context; + + err = ioctl(drm->fd, DRM_IOCTL_TEGRA_CHANNEL_CLOSE, &args); + if (err < 0) + return -errno; + + free(channel); + + return 0; +} + +drm_public unsigned int +drm_tegra_channel_get_version(struct drm_tegra_channel *channel) +{ + return channel->version; +} + +drm_public int +drm_tegra_channel_map(struct drm_tegra_channel *channel, + struct drm_tegra_bo *bo, uint32_t flags, + struct drm_tegra_mapping **mapp) +{ + struct drm_tegra *drm = channel->drm; + struct drm_tegra_channel_map args; + struct drm_tegra_mapping *map; + int err; + + if (!drm || !bo || !mapp) + return -EINVAL; + + map = calloc(1, sizeof(*map)); + if (!map) + return -ENOMEM; + + memset(&args, 0, sizeof(args)); + args.context = channel->context; + args.handle = bo->handle; + args.flags = flags; + + err = ioctl(drm->fd, DRM_IOCTL_TEGRA_CHANNEL_MAP, &args); + if (err < 0) { + free(map); + return -errno; + } + + map->channel = channel; + map->id = args.mapping; + *mapp = map; + + return 0; +} + +drm_public int +drm_tegra_channel_unmap(struct drm_tegra_mapping *map) +{ + struct drm_tegra_channel *channel = map->channel; + struct drm_tegra *drm = channel->drm; + struct drm_tegra_channel_unmap args; + int err; + + if (!channel || !map) + return -EINVAL; + + memset(&args, 0, sizeof(args)); + args.context = channel->context; + args.mapping = map->id; + + err = ioctl(drm->fd, DRM_IOCTL_TEGRA_CHANNEL_UNMAP, &args); + if (err < 0) + return -errno; + + free(map); + return 0; +} diff --git a/tegra/job.c b/tegra/job.c new file mode 100644 index 0000000..75a344f --- /dev/null +++ b/tegra/job.c @@ -0,0 +1,187 @@ +/* + * Copyright © 2012, 2013 Thierry Reding + * Copyright © 2013 Erik Faye-Lund + * Copyright © 2014 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#include "private.h" + +struct drm_tegra_submit_cmd * +drm_tegra_job_add_command(struct drm_tegra_job *job, uint32_t type, + uint32_t flags) +{ + struct drm_tegra_submit_cmd *commands, *command; + size_t size; + + size = (job->num_commands + 1) * sizeof(*commands); + + commands = realloc(job->commands, size); + if (!commands) + return NULL; + + command = &commands[job->num_commands]; + memset(command, 0, sizeof(*command)); + command->type = type; + command->flags = flags; + + job->commands = commands; + job->num_commands++; + + return command; +} + +drm_public int +drm_tegra_job_new(struct drm_tegra_channel *channel, + struct drm_tegra_job **jobp) +{ + struct drm_tegra_job *job; + + job = calloc(1, sizeof(*job)); + if (!job) + return -ENOMEM; + + job->page_size = sysconf(_SC_PAGESIZE); + job->channel = channel; + + *jobp = job; + + return 0; +} + +drm_public int drm_tegra_job_free(struct drm_tegra_job *job) +{ + if (!job) + return -EINVAL; + + if (job->pushbuf) + drm_tegra_pushbuf_free(job->pushbuf); + + if (job->commands) + free(job->commands); + + if (job->buffers) + free(job->buffers); + + free(job); + + return 0; +} + +drm_public int +drm_tegra_job_get_pushbuf(struct drm_tegra_job *job, + struct drm_tegra_pushbuf **pushbufp) +{ + struct drm_tegra_pushbuf *pushbuf; + + if (!job->pushbuf) { + pushbuf = calloc(1, sizeof(*pushbuf)); + if (!pushbuf) + return -ENOMEM; + + pushbuf->job = job; + + pushbuf->start = calloc(1, job->page_size); + if (!pushbuf->start) { + free(pushbuf); + return -ENOMEM; + } + + pushbuf->end = pushbuf->start + job->page_size / 4; + pushbuf->ptr = pushbuf->start; + + job->pushbuf = pushbuf; + } + + *pushbufp = job->pushbuf; + + return 0; +} + +drm_public int +drm_tegra_job_submit(struct drm_tegra_job *job, struct drm_tegra_fence *fence) +{ + struct drm_tegra_channel *channel = job->channel; + struct drm_tegra *drm = channel->drm; + struct drm_tegra_channel_submit args; + int err; + + memset(&args, 0, sizeof(args)); + args.context = channel->context; + args.num_bufs = job->num_buffers; + args.num_cmds = job->num_commands; + args.gather_data_words = job->pushbuf->ptr - job->pushbuf->start; + args.syncpt.id = job->syncpt.id; + args.syncpt.increments = job->syncpt.increments; + + args.bufs_ptr = (uintptr_t)job->buffers; + args.cmds_ptr = (uintptr_t)job->commands; + args.gather_data_ptr = (uintptr_t)job->pushbuf->start; + + err = ioctl(drm->fd, DRM_IOCTL_TEGRA_CHANNEL_SUBMIT, &args); + if (err < 0) + return -errno; + + job->syncpt.fence = args.syncpt.value; + + if (fence) { + fence->drm = drm; + fence->syncpt = job->syncpt.id; + fence->value = job->syncpt.fence; + } + + return 0; +} + +drm_public int +drm_tegra_job_wait(struct drm_tegra_job *job, unsigned long timeout) +{ + struct drm_tegra_channel *channel = job->channel; + struct drm_tegra *drm = channel->drm; + struct drm_tegra_syncpoint_wait args; + struct timespec ts; + int err; + + clock_gettime(CLOCK_MONOTONIC, &ts); + + memset(&args, 0, sizeof(args)); + args.timeout_ns = ts.tv_sec * 1000000000 + ts.tv_nsec + timeout; + args.id = job->syncpt.id; + args.threshold = job->syncpt.fence; + + err = ioctl(drm->fd, DRM_IOCTL_TEGRA_SYNCPOINT_WAIT, &args); + if (err < 0) + return -errno; + + return 0; +} diff --git a/tegra/libdrm_tegra.pc.in b/tegra/libdrm_tegra.pc.in new file mode 100644 index 0000000..2e06f49 --- /dev/null +++ b/tegra/libdrm_tegra.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libdrm_tegra +Description: Userspace interface to Tegra kernel DRM services +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -ldrm_tegra +Cflags: -I${includedir} -I${includedir}/libdrm +Requires.private: libdrm diff --git a/tegra/meson.build b/tegra/meson.build new file mode 100644 index 0000000..0b63d78 --- /dev/null +++ b/tegra/meson.build @@ -0,0 +1,64 @@ +# Copyright © 2017-2018 Intel Corporation + +# 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. + +libdrm_tegra = library( + 'drm_tegra', + [ + files( + 'channel.c', 'job.c', 'private.h', 'pushbuf.c', 'syncpt.c', 'tegra.c' + ), + config_file + ], + include_directories : [inc_root, inc_drm], + link_with : libdrm, + dependencies : [dep_pthread_stubs, dep_atomic_ops], + c_args : libdrm_c_args, + gnu_symbol_visibility : 'hidden', + version : '0.0.0', + install : true, +) + +ext_libdrm_tegra = declare_dependency( + link_with : [libdrm, libdrm_tegra], + include_directories : [inc_drm, include_directories('.')], +) + +if meson.version().version_compare('>= 0.54.0') + meson.override_dependency('libdrm_tegra', ext_libdrm_tegra) +endif + +install_headers('tegra.h', subdir : 'libdrm') + +pkg.generate( + libdrm_tegra, + name : 'libdrm_tegra', + subdirs : ['.', 'libdrm'], + description : 'Userspace interface to Tegra kernel DRM services', +) + +test( + 'tegra-symbols-check', + symbols_check, + args : [ + '--lib', libdrm_tegra, + '--symbols-file', files('tegra-symbols.txt'), + '--nm', prog_nm.path(), + ], +) diff --git a/tegra/private.h b/tegra/private.h new file mode 100644 index 0000000..fc204e8 --- /dev/null +++ b/tegra/private.h @@ -0,0 +1,118 @@ +/* + * Copyright © 2012, 2013 Thierry Reding + * Copyright © 2013 Erik Faye-Lund + * Copyright © 2014 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 __DRM_TEGRA_PRIVATE_H__ +#define __DRM_TEGRA_PRIVATE_H__ 1 + +#include +#include +#include + +#include +#include + +#include "tegra_drm.h" +#include "tegra.h" + +#define container_of(ptr, type, member) ({ \ + const __typeof__(((type *)0)->member) *__mptr = (ptr); \ + (type *)((char *)__mptr - offsetof(type, member)); \ + }) + +enum host1x_class { + HOST1X_CLASS_HOST1X = 0x01, + HOST1X_CLASS_GR2D = 0x51, + HOST1X_CLASS_GR2D_SB = 0x52, + HOST1X_CLASS_VIC = 0x5d, + HOST1X_CLASS_GR3D = 0x60, +}; + +struct drm_tegra { + bool close; + int fd; +}; + +struct drm_tegra_bo { + struct drm_tegra *drm; + uint32_t handle; + uint64_t offset; + uint32_t flags; + uint32_t size; + atomic_t ref; + void *map; +}; + +struct drm_tegra_channel { + struct drm_tegra *drm; + enum host1x_class class; + uint32_t capabilities; + unsigned int version; + uint64_t context; + + unsigned int cond_shift; +}; + +struct drm_tegra_mapping { + struct drm_tegra_channel *channel; + uint32_t id; +}; + +struct drm_tegra_pushbuf { + struct drm_tegra_job *job; + + uint32_t *start; + uint32_t *end; + uint32_t *ptr; +}; + +void drm_tegra_pushbuf_free(struct drm_tegra_pushbuf *pushbuf); + +struct drm_tegra_job { + struct drm_tegra_channel *channel; + struct drm_tegra_pushbuf *pushbuf; + size_t page_size; + + struct drm_tegra_submit_cmd *commands; + unsigned int num_commands; + + struct drm_tegra_submit_buf *buffers; + unsigned int num_buffers; + + struct { + uint32_t id; + uint32_t increments; + uint32_t fence; + } syncpt; +}; + +struct drm_tegra_submit_cmd * +drm_tegra_job_add_command(struct drm_tegra_job *job, uint32_t type, + uint32_t flags); + +struct drm_tegra_syncpoint { + struct drm_tegra *drm; + uint32_t id; +}; + +#endif /* __DRM_TEGRA_PRIVATE_H__ */ diff --git a/tegra/pushbuf.c b/tegra/pushbuf.c new file mode 100644 index 0000000..0c0212e --- /dev/null +++ b/tegra/pushbuf.c @@ -0,0 +1,184 @@ +/* + * Copyright © 2012, 2013 Thierry Reding + * Copyright © 2013 Erik Faye-Lund + * Copyright © 2014 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include "util_math.h" +#include "private.h" + +#define HOST1X_OPCODE_NONINCR(offset, count) \ + ((0x2 << 28) | (((offset) & 0xfff) << 16) | ((count) & 0xffff)) + +static inline unsigned int +drm_tegra_pushbuf_get_offset(struct drm_tegra_pushbuf *pushbuf, uint32_t *ptr) +{ + return ptr - pushbuf->start; +} + +void drm_tegra_pushbuf_free(struct drm_tegra_pushbuf *pushbuf) +{ + if (pushbuf->start) + free(pushbuf->start); + + free(pushbuf); +} + +/** + * drm_tegra_pushbuf_begin() - prepare push buffer for a series of pushes + * @pushbuf: push buffer + * @words: maximum number of words in series of pushes to follow + */ +drm_public int +drm_tegra_pushbuf_begin(struct drm_tegra_pushbuf *pushbuf, + unsigned int words, uint32_t **ptrp) +{ + struct drm_tegra_job *job = pushbuf->job; + unsigned long offset; + size_t size; + void *ptr; + + if (pushbuf->ptr + words >= pushbuf->end) { + words = pushbuf->end - pushbuf->start + words; + size = ALIGN(words * 4, job->page_size); + offset = pushbuf->ptr - pushbuf->start; + + ptr = realloc(pushbuf->start, size); + if (!ptr) + return -ENOMEM; + + pushbuf->start = ptr; + pushbuf->end = pushbuf->start + size / 4; + pushbuf->ptr = pushbuf->start + offset; + } + + if (ptrp) + *ptrp = pushbuf->ptr; + + return 0; +} + +drm_public int +drm_tegra_pushbuf_end(struct drm_tegra_pushbuf *pushbuf, uint32_t *ptr) +{ + struct drm_tegra_submit_cmd *command; + + command = drm_tegra_job_add_command(pushbuf->job, + DRM_TEGRA_SUBMIT_CMD_GATHER_UPTR, + 0); + if (!command) + return -ENOMEM; + + command->gather_uptr.words = ptr - pushbuf->start; + pushbuf->ptr = ptr; + + return 0; +} + +drm_public int +drm_tegra_pushbuf_wait(struct drm_tegra_pushbuf *pushbuf, + struct drm_tegra_syncpoint *syncpt, + uint32_t value) +{ + struct drm_tegra_submit_cmd *command; + + command = drm_tegra_job_add_command(pushbuf->job, + DRM_TEGRA_SUBMIT_CMD_WAIT_SYNCPT, + 0); + if (!command) + return -ENOMEM; + + command->wait_syncpt.id = syncpt->id; + command->wait_syncpt.value = value; + + return 0; +} + +drm_public int +drm_tegra_pushbuf_relocate(struct drm_tegra_pushbuf *pushbuf, uint32_t **ptrp, + struct drm_tegra_mapping *target, + unsigned long offset, unsigned int shift, + uint32_t flags) +{ + struct drm_tegra_submit_buf *buffers, *buffer; + struct drm_tegra_job *job = pushbuf->job; + size_t size; + + size = (job->num_buffers + 1) * sizeof(*buffer); + + buffers = realloc(job->buffers, size); + if (!buffers) + return -ENOMEM; + + buffer = &buffers[job->num_buffers]; + + memset(buffer, 0, sizeof(*buffer)); + buffer->mapping = target->id; + buffer->flags = flags; + buffer->reloc.target_offset = offset; + buffer->reloc.gather_offset_words = drm_tegra_pushbuf_get_offset(pushbuf, + *ptrp); + buffer->reloc.shift = shift; + + *(*ptrp)++ = 0xdeadbeef; + + job->buffers = buffers; + job->num_buffers++; + + return 0; +} + +drm_public int +drm_tegra_pushbuf_sync(struct drm_tegra_pushbuf *pushbuf, + struct drm_tegra_syncpoint *syncpt, + unsigned int count) +{ + struct drm_tegra_job *job = pushbuf->job; + + job->syncpt.increments += count; + job->syncpt.id = syncpt->id; + + return 0; +} + +drm_public int +drm_tegra_pushbuf_sync_cond(struct drm_tegra_pushbuf *pushbuf, uint32_t **ptrp, + struct drm_tegra_syncpoint *syncpt, + enum drm_tegra_sync_cond cond) +{ + struct drm_tegra_channel *channel = pushbuf->job->channel; + + if (cond >= DRM_TEGRA_SYNC_COND_MAX) + return -EINVAL; + + *(*ptrp)++ = HOST1X_OPCODE_NONINCR(0x0, 0x1); + *(*ptrp)++ = cond << channel->cond_shift | syncpt->id; + + return drm_tegra_pushbuf_sync(pushbuf, syncpt, 1); +} diff --git a/tegra/syncpt.c b/tegra/syncpt.c new file mode 100644 index 0000000..1601418 --- /dev/null +++ b/tegra/syncpt.c @@ -0,0 +1,101 @@ +/* + * Copyright © 2021 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include + +#include "private.h" + +drm_public int +drm_tegra_syncpoint_new(struct drm_tegra *drm, + struct drm_tegra_syncpoint **syncptp) +{ + struct drm_tegra_syncpoint_allocate args; + struct drm_tegra_syncpoint *syncpt; + int err; + + syncpt = calloc(1, sizeof(*syncpt)); + if (!syncpt) + return -ENOMEM; + + memset(&args, 0, sizeof(args)); + + err = ioctl(drm->fd, DRM_IOCTL_TEGRA_SYNCPOINT_ALLOCATE, &args); + if (err < 0) { + free(syncpt); + return -errno; + } + + syncpt->drm = drm; + syncpt->id = args.id; + + *syncptp = syncpt; + + return 0; +} + +drm_public int +drm_tegra_syncpoint_free(struct drm_tegra_syncpoint *syncpt) +{ + struct drm_tegra_syncpoint_free args; + struct drm_tegra *drm = syncpt->drm; + int err; + + if (!syncpt) + return -EINVAL; + + memset(&args, 0, sizeof(args)); + args.id = syncpt->id; + + err = ioctl(drm->fd, DRM_IOCTL_TEGRA_SYNCPOINT_FREE, &args); + if (err < 0) + return -errno; + + free(syncpt); + + return 0; +} + +drm_public int +drm_tegra_fence_wait(struct drm_tegra_fence *fence, unsigned long timeout) +{ + struct drm_tegra_syncpoint_wait args; + struct drm_tegra *drm = fence->drm; + int err; + + memset(&args, 0, sizeof(args)); + args.timeout_ns = 0; + args.id = fence->syncpt; + args.threshold = fence->value; + + err = ioctl(drm->fd, DRM_IOCTL_TEGRA_SYNCPOINT_WAIT, &args); + if (err < 0) + return -errno; + + return 0; +} diff --git a/tegra/tegra-symbols.txt b/tegra/tegra-symbols.txt new file mode 100644 index 0000000..1a75c3d --- /dev/null +++ b/tegra/tegra-symbols.txt @@ -0,0 +1,32 @@ +drm_tegra_bo_export +drm_tegra_bo_get_handle +drm_tegra_bo_get_name +drm_tegra_bo_import +drm_tegra_bo_map +drm_tegra_bo_new +drm_tegra_bo_open +drm_tegra_bo_ref +drm_tegra_bo_unmap +drm_tegra_bo_unref +drm_tegra_bo_wrap +drm_tegra_channel_close +drm_tegra_channel_get_version +drm_tegra_channel_map +drm_tegra_channel_open +drm_tegra_channel_unmap +drm_tegra_close +drm_tegra_fence_wait +drm_tegra_job_free +drm_tegra_job_get_pushbuf +drm_tegra_job_new +drm_tegra_job_submit +drm_tegra_job_wait +drm_tegra_new +drm_tegra_pushbuf_begin +drm_tegra_pushbuf_end +drm_tegra_pushbuf_relocate +drm_tegra_pushbuf_sync +drm_tegra_pushbuf_sync_cond +drm_tegra_pushbuf_wait +drm_tegra_syncpoint_free +drm_tegra_syncpoint_new diff --git a/tegra/tegra.c b/tegra/tegra.c new file mode 100644 index 0000000..6a51c43 --- /dev/null +++ b/tegra/tegra.c @@ -0,0 +1,354 @@ +/* + * Copyright © 2012, 2013 Thierry Reding + * Copyright © 2013 Erik Faye-Lund + * Copyright © 2014 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#include +#include +#include +#include + +#include + +#include + +#include + +#include "private.h" + +static void drm_tegra_bo_free(struct drm_tegra_bo *bo) +{ + struct drm_tegra *drm = bo->drm; + + if (bo->map) + munmap(bo->map, bo->size); + + drmCloseBufferHandle(drm->fd, bo->handle); + + free(bo); +} + +static int drm_tegra_wrap(struct drm_tegra **drmp, int fd, bool close) +{ + struct drm_tegra *drm; + + if (fd < 0 || !drmp) + return -EINVAL; + + drm = calloc(1, sizeof(*drm)); + if (!drm) + return -ENOMEM; + + drm->close = close; + drm->fd = fd; + + *drmp = drm; + + return 0; +} + +drm_public int drm_tegra_new(int fd, struct drm_tegra **drmp) +{ + bool supported = false; + drmVersionPtr version; + + version = drmGetVersion(fd); + if (!version) + return -ENOMEM; + + if (!strncmp(version->name, "tegra", version->name_len)) + supported = true; + + drmFreeVersion(version); + + if (!supported) + return -ENOTSUP; + + return drm_tegra_wrap(drmp, fd, false); +} + +drm_public void drm_tegra_close(struct drm_tegra *drm) +{ + if (!drm) + return; + + if (drm->close) + close(drm->fd); + + free(drm); +} + +static struct drm_tegra_bo *drm_tegra_bo_alloc(struct drm_tegra *drm, + uint32_t handle, + uint32_t flags, + uint32_t size) +{ + struct drm_tegra_bo *bo; + + bo = calloc(1, sizeof(*bo)); + if (!bo) + return NULL; + + atomic_set(&bo->ref, 1); + bo->handle = handle; + bo->flags = flags; + bo->size = size; + bo->drm = drm; + + return bo; +} + +drm_public int +drm_tegra_bo_new(struct drm_tegra *drm, uint32_t flags, uint32_t size, + struct drm_tegra_bo **bop) +{ + struct drm_tegra_gem_create args; + struct drm_tegra_bo *bo; + int err; + + if (!drm || size == 0 || !bop) + return -EINVAL; + + bo = drm_tegra_bo_alloc(drm, 0, flags, size); + if (!bo) + return -ENOMEM; + + memset(&args, 0, sizeof(args)); + args.flags = flags; + args.size = size; + + err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_CREATE, &args, + sizeof(args)); + if (err < 0) { + err = -errno; + free(bo); + return err; + } + + bo->handle = args.handle; + + *bop = bo; + + return 0; +} + +drm_public int +drm_tegra_bo_wrap(struct drm_tegra *drm, uint32_t handle, uint32_t flags, + uint32_t size, struct drm_tegra_bo **bop) +{ + struct drm_tegra_bo *bo; + + if (!drm || !bop) + return -EINVAL; + + bo = drm_tegra_bo_alloc(drm, handle, flags, size); + if (!bo) + return -ENOMEM; + + *bop = bo; + + return 0; +} + +drm_public struct drm_tegra_bo *drm_tegra_bo_ref(struct drm_tegra_bo *bo) +{ + if (bo) + atomic_inc(&bo->ref); + + return bo; +} + +drm_public void drm_tegra_bo_unref(struct drm_tegra_bo *bo) +{ + if (bo && atomic_dec_and_test(&bo->ref)) + drm_tegra_bo_free(bo); +} + +drm_public int +drm_tegra_bo_get_handle(struct drm_tegra_bo *bo, uint32_t *handle) +{ + if (!bo || !handle) + return -EINVAL; + + *handle = bo->handle; + + return 0; +} + +drm_public int drm_tegra_bo_map(struct drm_tegra_bo *bo, void **ptr) +{ + struct drm_tegra *drm = bo->drm; + + if (!bo->map) { + struct drm_tegra_gem_mmap args; + int err; + + memset(&args, 0, sizeof(args)); + args.handle = bo->handle; + + err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_MMAP, &args, + sizeof(args)); + if (err < 0) + return -errno; + + bo->offset = args.offset; + + bo->map = drm_mmap(NULL, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, + drm->fd, bo->offset); + if (bo->map == MAP_FAILED) { + bo->map = NULL; + return -errno; + } + } + + if (ptr) + *ptr = bo->map; + + return 0; +} + +drm_public int drm_tegra_bo_unmap(struct drm_tegra_bo *bo) +{ + if (!bo) + return -EINVAL; + + if (!bo->map) + return 0; + + if (munmap(bo->map, bo->size)) + return -errno; + + bo->map = NULL; + + return 0; +} + +drm_public int drm_tegra_bo_get_name(struct drm_tegra_bo *bo, uint32_t *name) +{ + struct drm_tegra *drm = bo->drm; + struct drm_gem_flink args; + int err; + + memset(&args, 0, sizeof(args)); + args.handle = bo->handle; + + err = drmIoctl(drm->fd, DRM_IOCTL_GEM_FLINK, &args); + if (err < 0) + return err; + + if (name) + *name = args.name; + + return 0; +} + +drm_public int +drm_tegra_bo_open(struct drm_tegra *drm, uint32_t name, uint32_t flags, + struct drm_tegra_bo **bop) +{ + struct drm_gem_open args; + struct drm_tegra_bo *bo; + int err; + + bo = drm_tegra_bo_alloc(drm, 0, flags, 0); + if (!bo) + return -ENOMEM; + + memset(&args, 0, sizeof(args)); + args.name = name; + + err = drmIoctl(drm->fd, DRM_IOCTL_GEM_OPEN, &args); + if (err < 0) + goto free; + + bo->handle = args.handle; + bo->size = args.size; + + *bop = bo; + + return 0; + +free: + free(bo); + return err; +} + +drm_public int drm_tegra_bo_export(struct drm_tegra_bo *bo, uint32_t flags) +{ + int fd, err; + + flags |= DRM_CLOEXEC; + + err = drmPrimeHandleToFD(bo->drm->fd, bo->handle, flags, &fd); + if (err < 0) + return err; + + return fd; +} + +static ssize_t fd_get_size(int fd) +{ + ssize_t size, offset; + int err; + + offset = lseek(fd, 0, SEEK_CUR); + if (offset < 0) + return -errno; + + size = lseek(fd, 0, SEEK_END); + if (size < 0) + return -errno; + + err = lseek(fd, offset, SEEK_SET); + if (err < 0) + return -errno; + + return size; +} + +drm_public int +drm_tegra_bo_import(struct drm_tegra *drm, int fd, struct drm_tegra_bo **bop) +{ + struct drm_tegra_bo *bo; + ssize_t size; + int err; + + size = fd_get_size(fd); + if (size < 0) + return size; + + bo = drm_tegra_bo_alloc(drm, 0, 0, size); + if (!bo) + return -ENOMEM; + + err = drmPrimeFDToHandle(drm->fd, fd, &bo->handle); + if (err < 0) + goto free; + + *bop = bo; + + return 0; + +free: + free(bo); + return err; +} diff --git a/tegra/tegra.h b/tegra/tegra.h new file mode 100644 index 0000000..8f3c055 --- /dev/null +++ b/tegra/tegra.h @@ -0,0 +1,127 @@ +/* + * Copyright © 2012, 2013 Thierry Reding + * Copyright © 2013 Erik Faye-Lund + * Copyright © 2014 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 __DRM_TEGRA_H__ +#define __DRM_TEGRA_H__ 1 + +#include +#include + +#include + +enum drm_tegra_class { + DRM_TEGRA_HOST1X, + DRM_TEGRA_GR2D, + DRM_TEGRA_GR3D, + DRM_TEGRA_VIC, +}; + +struct drm_tegra_bo; +struct drm_tegra; + +int drm_tegra_new(int fd, struct drm_tegra **drmp); +void drm_tegra_close(struct drm_tegra *drm); + +int drm_tegra_bo_new(struct drm_tegra *drm, uint32_t flags, uint32_t size, + struct drm_tegra_bo **bop); +int drm_tegra_bo_wrap(struct drm_tegra *drm, uint32_t handle, uint32_t flags, + uint32_t size, struct drm_tegra_bo **bop); +struct drm_tegra_bo *drm_tegra_bo_ref(struct drm_tegra_bo *bo); +void drm_tegra_bo_unref(struct drm_tegra_bo *bo); +int drm_tegra_bo_get_handle(struct drm_tegra_bo *bo, uint32_t *handle); +int drm_tegra_bo_map(struct drm_tegra_bo *bo, void **ptr); +int drm_tegra_bo_unmap(struct drm_tegra_bo *bo); + +int drm_tegra_bo_get_name(struct drm_tegra_bo *bo, uint32_t *name); +int drm_tegra_bo_open(struct drm_tegra *drm, uint32_t name, uint32_t flags, + struct drm_tegra_bo **bop); + +int drm_tegra_bo_export(struct drm_tegra_bo *bo, uint32_t flags); +int drm_tegra_bo_import(struct drm_tegra *drm, int fd, + struct drm_tegra_bo **bop); + +struct drm_tegra_channel; +struct drm_tegra_mapping; +struct drm_tegra_pushbuf; +struct drm_tegra_job; +struct drm_tegra_syncpoint; + +enum drm_tegra_sync_cond { + DRM_TEGRA_SYNC_COND_IMMEDIATE, + DRM_TEGRA_SYNC_COND_OP_DONE, + DRM_TEGRA_SYNC_COND_RD_DONE, + DRM_TEGRA_SYNC_COND_WR_SAFE, + DRM_TEGRA_SYNC_COND_MAX, + }; + +struct drm_tegra_fence { + struct drm_tegra *drm; + uint32_t syncpt; + uint32_t value; +}; + +int drm_tegra_channel_open(struct drm_tegra *drm, + enum drm_tegra_class client, + struct drm_tegra_channel **channelp); +int drm_tegra_channel_close(struct drm_tegra_channel *channel); +unsigned int drm_tegra_channel_get_version(struct drm_tegra_channel *channel); +int drm_tegra_channel_map(struct drm_tegra_channel *channel, + struct drm_tegra_bo *bo, uint32_t flags, + struct drm_tegra_mapping **mapp); +int drm_tegra_channel_unmap(struct drm_tegra_mapping *map); + +int drm_tegra_job_new(struct drm_tegra_channel *channel, + struct drm_tegra_job **jobp); +int drm_tegra_job_free(struct drm_tegra_job *job); +int drm_tegra_job_get_pushbuf(struct drm_tegra_job *job, + struct drm_tegra_pushbuf **pushbufp); +int drm_tegra_job_submit(struct drm_tegra_job *job, + struct drm_tegra_fence *fence); +int drm_tegra_job_wait(struct drm_tegra_job *job, unsigned long timeout); + +int drm_tegra_pushbuf_begin(struct drm_tegra_pushbuf *pushbuf, + unsigned int words, uint32_t **ptrp); +int drm_tegra_pushbuf_end(struct drm_tegra_pushbuf *pushbuf, uint32_t *ptr); +int drm_tegra_pushbuf_wait(struct drm_tegra_pushbuf *pushbuf, + struct drm_tegra_syncpoint *syncpt, + uint32_t value); +int drm_tegra_pushbuf_relocate(struct drm_tegra_pushbuf *pushbuf, + uint32_t **ptrp, + struct drm_tegra_mapping *target, + unsigned long offset, unsigned int shift, + uint32_t flags); +int drm_tegra_pushbuf_sync(struct drm_tegra_pushbuf *pushbuf, + struct drm_tegra_syncpoint *syncpt, + unsigned int count); +int drm_tegra_pushbuf_sync_cond(struct drm_tegra_pushbuf *pushbuf, + uint32_t **ptrp, + struct drm_tegra_syncpoint *syncpt, + enum drm_tegra_sync_cond cond); + +int drm_tegra_syncpoint_new(struct drm_tegra *drm, + struct drm_tegra_syncpoint **syncptp); +int drm_tegra_syncpoint_free(struct drm_tegra_syncpoint *syncpt); +int drm_tegra_fence_wait(struct drm_tegra_fence *fence, unsigned long timeout); + +#endif /* __DRM_TEGRA_H__ */ diff --git a/tests/Android.mk b/tests/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/tests/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/tests/amdgpu/.editorconfig b/tests/amdgpu/.editorconfig new file mode 120000 index 0000000..70734e4 --- /dev/null +++ b/tests/amdgpu/.editorconfig @@ -0,0 +1 @@ +../../amdgpu/.editorconfig \ No newline at end of file diff --git a/tests/amdgpu/amdgpu_stress.c b/tests/amdgpu/amdgpu_stress.c new file mode 100644 index 0000000..5c5c88c --- /dev/null +++ b/tests/amdgpu/amdgpu_stress.c @@ -0,0 +1,418 @@ +/* + * Copyright 2021 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "drm.h" +#include "xf86drmMode.h" +#include "xf86drm.h" +#include "amdgpu.h" +#include "amdgpu_drm.h" +#include "amdgpu_internal.h" + +#define MAX_CARDS_SUPPORTED 4 +#define NUM_BUFFER_OBJECTS 1024 + +#define SDMA_PACKET(op, sub_op, e) ((((e) & 0xFFFF) << 16) | \ + (((sub_op) & 0xFF) << 8) | \ + (((op) & 0xFF) << 0)) + +#define SDMA_OPCODE_COPY 1 +# define SDMA_COPY_SUB_OPCODE_LINEAR 0 + + +#define SDMA_PACKET_SI(op, b, t, s, cnt) ((((op) & 0xF) << 28) | \ + (((b) & 0x1) << 26) | \ + (((t) & 0x1) << 23) | \ + (((s) & 0x1) << 22) | \ + (((cnt) & 0xFFFFF) << 0)) +#define SDMA_OPCODE_COPY_SI 3 + + +/** Help string for command line parameters */ +static const char usage[] = + "Usage: %s [-?h] [-b v|g|vg size] " + "[-c from to size count]\n" + "where:\n" + " b - Allocate a BO in VRAM, GTT or VRAM|GTT of size bytes.\n" + " This flag can be used multiple times. The first bo will\n" + " have id `1`, then second id `2`, ...\n" + " c - Copy size bytes from BO (bo_id1) to BO (bo_id2), count times\n" + " h - Display this help\n" + "\n" + "Sizes can be postfixes with k, m or g for kilo, mega and gigabyte scaling\n"; + +/** Specified options strings for getopt */ +static const char options[] = "?hb:c:"; + +/* Open AMD devices. + * Returns the fd of the first device it could open. + */ +static int amdgpu_open_device(void) +{ + drmDevicePtr devices[MAX_CARDS_SUPPORTED]; + unsigned int i; + int drm_count; + + drm_count = drmGetDevices2(0, devices, MAX_CARDS_SUPPORTED); + if (drm_count < 0) { + fprintf(stderr, "drmGetDevices2() returned an error %d\n", + drm_count); + return drm_count; + } + + for (i = 0; i < drm_count; i++) { + drmVersionPtr version; + int fd; + + /* If this is not PCI device, skip*/ + if (devices[i]->bustype != DRM_BUS_PCI) + continue; + + /* If this is not AMD GPU vender ID, skip*/ + if (devices[i]->deviceinfo.pci->vendor_id != 0x1002) + continue; + + if (!(devices[i]->available_nodes & 1 << DRM_NODE_RENDER)) + continue; + + fd = open(devices[i]->nodes[DRM_NODE_RENDER], O_RDWR | O_CLOEXEC); + + /* This node is not available. */ + if (fd < 0) continue; + + version = drmGetVersion(fd); + if (!version) { + fprintf(stderr, + "Warning: Cannot get version for %s." + "Error is %s\n", + devices[i]->nodes[DRM_NODE_RENDER], + strerror(errno)); + close(fd); + continue; + } + + if (strcmp(version->name, "amdgpu")) { + /* This is not AMDGPU driver, skip.*/ + drmFreeVersion(version); + close(fd); + continue; + } + + drmFreeVersion(version); + drmFreeDevices(devices, drm_count); + return fd; + } + + return -1; +} + +amdgpu_device_handle device_handle; +amdgpu_context_handle context_handle; + +amdgpu_bo_handle resources[NUM_BUFFER_OBJECTS]; +uint64_t virtual[NUM_BUFFER_OBJECTS]; +unsigned int num_buffers; +uint32_t *pm4; + +int alloc_bo(uint32_t domain, uint64_t size) +{ + struct amdgpu_bo_alloc_request request = {}; + amdgpu_bo_handle bo; + amdgpu_va_handle va; + uint64_t addr; + int r; + + if (num_buffers >= NUM_BUFFER_OBJECTS) + return -ENOSPC; + + request.alloc_size = size; + request.phys_alignment = 0; + request.preferred_heap = domain; + request.flags = 0; + r = amdgpu_bo_alloc(device_handle, &request, &bo); + if (r) + return r; + + r = amdgpu_va_range_alloc(device_handle, amdgpu_gpu_va_range_general, + size, 0, 0, &addr, &va, 0); + if (r) + return r; + + r = amdgpu_bo_va_op_raw(device_handle, bo, 0, size, addr, + AMDGPU_VM_PAGE_READABLE | AMDGPU_VM_PAGE_WRITEABLE | + AMDGPU_VM_PAGE_EXECUTABLE, AMDGPU_VA_OP_MAP); + if (r) + return r; + + resources[num_buffers] = bo; + virtual[num_buffers] = addr; + fprintf(stdout, "Allocated BO number %u at 0x%lx, domain 0x%x, size %lu\n", + num_buffers++, addr, domain, size); + return 0; +} + +int submit_ib(uint32_t from, uint32_t to, uint64_t size, uint32_t count) +{ + struct amdgpu_cs_request ibs_request; + struct amdgpu_cs_fence fence_status; + struct amdgpu_cs_ib_info ib_info; + uint64_t copied = size, delta; + struct timespec start, stop; + + uint64_t src = virtual[from]; + uint64_t dst = virtual[to]; + uint32_t expired; + int i, r; + + i = 0; + while (size) { + uint64_t bytes = size < 0x40000 ? size : 0x40000; + + if (device_handle->info.family_id == AMDGPU_FAMILY_SI) { + pm4[i++] = SDMA_PACKET_SI(SDMA_OPCODE_COPY_SI, 0, 0, 0, + bytes); + pm4[i++] = 0xffffffff & dst; + pm4[i++] = 0xffffffff & src; + pm4[i++] = (0xffffffff00000000 & dst) >> 32; + pm4[i++] = (0xffffffff00000000 & src) >> 32; + } else { + pm4[i++] = SDMA_PACKET(SDMA_OPCODE_COPY, + SDMA_COPY_SUB_OPCODE_LINEAR, + 0); + if ( device_handle->info.family_id >= AMDGPU_FAMILY_AI) + pm4[i++] = bytes - 1; + else + pm4[i++] = bytes; + pm4[i++] = 0; + pm4[i++] = 0xffffffff & src; + pm4[i++] = (0xffffffff00000000 & src) >> 32; + pm4[i++] = 0xffffffff & dst; + pm4[i++] = (0xffffffff00000000 & dst) >> 32; + } + + size -= bytes; + src += bytes; + dst += bytes; + } + + memset(&ib_info, 0, sizeof(ib_info)); + ib_info.ib_mc_address = virtual[0]; + ib_info.size = i; + + memset(&ibs_request, 0, sizeof(ibs_request)); + ibs_request.ip_type = AMDGPU_HW_IP_DMA; + ibs_request.ring = 0; + ibs_request.number_of_ibs = 1; + ibs_request.ibs = &ib_info; + ibs_request.fence_info.handle = NULL; + + r = clock_gettime(CLOCK_MONOTONIC, &start); + if (r) + return errno; + + r = amdgpu_bo_list_create(device_handle, num_buffers, resources, NULL, + &ibs_request.resources); + if (r) + return r; + + for (i = 0; i < count; ++i) { + r = amdgpu_cs_submit(context_handle, 0, &ibs_request, 1); + if (r) + return r; + } + + r = amdgpu_bo_list_destroy(ibs_request.resources); + if (r) + return r; + + memset(&fence_status, 0, sizeof(fence_status)); + fence_status.ip_type = ibs_request.ip_type; + fence_status.ip_instance = 0; + fence_status.ring = ibs_request.ring; + fence_status.context = context_handle; + fence_status.fence = ibs_request.seq_no; + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE, + 0, &expired); + if (r) + return r; + + r = clock_gettime(CLOCK_MONOTONIC, &stop); + if (r) + return errno; + + delta = stop.tv_nsec + stop.tv_sec * 1000000000UL; + delta -= start.tv_nsec + start.tv_sec * 1000000000UL; + + fprintf(stdout, "Submitted %u IBs to copy from %u(%lx) to %u(%lx) %lu bytes took %lu usec\n", + count, from, virtual[from], to, virtual[to], copied, delta / 1000); + return 0; +} + +void next_arg(int argc, char **argv, const char *msg) +{ + optarg = argv[optind++]; + if (optind > argc || optarg[0] == '-') { + fprintf(stderr, "%s\n", msg); + exit(EXIT_FAILURE); + } +} + +uint64_t parse_size(void) +{ + uint64_t size; + char ext[2]; + + ext[0] = 0; + if (sscanf(optarg, "%li%1[kmgKMG]", &size, ext) < 1) { + fprintf(stderr, "Can't parse size arg: %s\n", optarg); + exit(EXIT_FAILURE); + } + switch (ext[0]) { + case 'k': + case 'K': + size *= 1024; + break; + case 'm': + case 'M': + size *= 1024 * 1024; + break; + case 'g': + case 'G': + size *= 1024 * 1024 * 1024; + break; + default: + break; + } + return size; +} + +int main(int argc, char **argv) +{ + uint32_t major_version, minor_version; + uint32_t domain, from, to, count; + uint64_t size; + int fd, r, c; + + fd = amdgpu_open_device(); + if (fd < 0) { + perror("Cannot open AMDGPU device"); + exit(EXIT_FAILURE); + } + + r = amdgpu_device_initialize(fd, &major_version, &minor_version, &device_handle); + if (r) { + fprintf(stderr, "amdgpu_device_initialize returned %d\n", r); + exit(EXIT_FAILURE); + } + + r = amdgpu_cs_ctx_create(device_handle, &context_handle); + if (r) { + fprintf(stderr, "amdgpu_cs_ctx_create returned %d\n", r); + exit(EXIT_FAILURE); + } + + if (argc == 1) { + fprintf(stderr, usage, argv[0]); + exit(EXIT_FAILURE); + } + + r = alloc_bo(AMDGPU_GEM_DOMAIN_GTT, 2ULL * 1024 * 1024); + if (r) { + fprintf(stderr, "Buffer allocation failed with %d\n", r); + exit(EXIT_FAILURE); + } + + r = amdgpu_bo_cpu_map(resources[0], (void **)&pm4); + if (r) { + fprintf(stderr, "Buffer mapping failed with %d\n", r); + exit(EXIT_FAILURE); + } + + opterr = 0; + while ((c = getopt(argc, argv, options)) != -1) { + switch (c) { + case 'b': + if (!strcmp(optarg, "v")) + domain = AMDGPU_GEM_DOMAIN_VRAM; + else if (!strcmp(optarg, "g")) + domain = AMDGPU_GEM_DOMAIN_GTT; + else if (!strcmp(optarg, "vg")) + domain = AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT; + else { + fprintf(stderr, "Invalid domain: %s\n", optarg); + exit(EXIT_FAILURE); + } + next_arg(argc, argv, "Missing buffer size"); + size = parse_size(); + if (size < getpagesize()) { + fprintf(stderr, "Buffer size to small %lu\n", size); + exit(EXIT_FAILURE); + } + r = alloc_bo(domain, size); + if (r) { + fprintf(stderr, "Buffer allocation failed with %d\n", r); + exit(EXIT_FAILURE); + } + break; + case 'c': + if (sscanf(optarg, "%u", &from) != 1) { + fprintf(stderr, "Can't parse from buffer: %s\n", optarg); + exit(EXIT_FAILURE); + } + next_arg(argc, argv, "Missing to buffer"); + if (sscanf(optarg, "%u", &to) != 1) { + fprintf(stderr, "Can't parse to buffer: %s\n", optarg); + exit(EXIT_FAILURE); + } + next_arg(argc, argv, "Missing size"); + size = parse_size(); + next_arg(argc, argv, "Missing count"); + count = parse_size(); + r = submit_ib(from, to, size, count); + if (r) { + fprintf(stderr, "IB submission failed with %d\n", r); + exit(EXIT_FAILURE); + } + break; + case '?': + case 'h': + fprintf(stderr, usage, argv[0]); + exit(EXIT_SUCCESS); + default: + fprintf(stderr, usage, argv[0]); + exit(EXIT_FAILURE); + } + } + + return EXIT_SUCCESS; +} diff --git a/tests/amdgpu/amdgpu_test.c b/tests/amdgpu/amdgpu_test.c new file mode 100644 index 0000000..9abe573 --- /dev/null +++ b/tests/amdgpu/amdgpu_test.c @@ -0,0 +1,830 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __linux__ +#include +#elif __FreeBSD__ +/* SPECNAMELEN in FreeBSD is defined here: */ +#include +#endif +#ifdef MAJOR_IN_MKDEV +#include +#endif +#ifdef MAJOR_IN_SYSMACROS +#include +#endif + +#include "drm.h" +#include "xf86drmMode.h" +#include "xf86drm.h" + +#include "CUnit/Basic.h" + +#include "amdgpu_test.h" +#include "amdgpu_internal.h" + +/* Test suite names */ +#define BASIC_TESTS_STR "Basic Tests" +#define BO_TESTS_STR "BO Tests" +#define CS_TESTS_STR "CS Tests" +#define VCE_TESTS_STR "VCE Tests" +#define VCN_TESTS_STR "VCN Tests" +#define JPEG_TESTS_STR "JPEG Tests" +#define UVD_ENC_TESTS_STR "UVD ENC Tests" +#define DEADLOCK_TESTS_STR "Deadlock Tests" +#define VM_TESTS_STR "VM Tests" +#define RAS_TESTS_STR "RAS Tests" +#define SYNCOBJ_TIMELINE_TESTS_STR "SYNCOBJ TIMELINE Tests" +#define SECURITY_TESTS_STR "Security Tests" +#define HOTUNPLUG_TESTS_STR "Hotunplug Tests" +#define CP_DMA_TESTS_STR "CP DMA Tests" + +/** + * Open handles for amdgpu devices + * + */ +int drm_amdgpu[MAX_CARDS_SUPPORTED]; + +/** Open render node to test */ +int open_render_node = 0; /* By default run most tests on primary node */ + +/** The table of all known test suites to run */ +static CU_SuiteInfo suites[] = { + { + .pName = BASIC_TESTS_STR, + .pInitFunc = suite_basic_tests_init, + .pCleanupFunc = suite_basic_tests_clean, + .pTests = basic_tests, + }, + { + .pName = BO_TESTS_STR, + .pInitFunc = suite_bo_tests_init, + .pCleanupFunc = suite_bo_tests_clean, + .pTests = bo_tests, + }, + { + .pName = CS_TESTS_STR, + .pInitFunc = suite_cs_tests_init, + .pCleanupFunc = suite_cs_tests_clean, + .pTests = cs_tests, + }, + { + .pName = VCE_TESTS_STR, + .pInitFunc = suite_vce_tests_init, + .pCleanupFunc = suite_vce_tests_clean, + .pTests = vce_tests, + }, + { + .pName = VCN_TESTS_STR, + .pInitFunc = suite_vcn_tests_init, + .pCleanupFunc = suite_vcn_tests_clean, + .pTests = vcn_tests, + }, + { + .pName = JPEG_TESTS_STR, + .pInitFunc = suite_jpeg_tests_init, + .pCleanupFunc = suite_jpeg_tests_clean, + .pTests = jpeg_tests, + }, + { + .pName = UVD_ENC_TESTS_STR, + .pInitFunc = suite_uvd_enc_tests_init, + .pCleanupFunc = suite_uvd_enc_tests_clean, + .pTests = uvd_enc_tests, + }, + { + .pName = DEADLOCK_TESTS_STR, + .pInitFunc = suite_deadlock_tests_init, + .pCleanupFunc = suite_deadlock_tests_clean, + .pTests = deadlock_tests, + }, + { + .pName = VM_TESTS_STR, + .pInitFunc = suite_vm_tests_init, + .pCleanupFunc = suite_vm_tests_clean, + .pTests = vm_tests, + }, + { + .pName = RAS_TESTS_STR, + .pInitFunc = suite_ras_tests_init, + .pCleanupFunc = suite_ras_tests_clean, + .pTests = ras_tests, + }, + { + .pName = SYNCOBJ_TIMELINE_TESTS_STR, + .pInitFunc = suite_syncobj_timeline_tests_init, + .pCleanupFunc = suite_syncobj_timeline_tests_clean, + .pTests = syncobj_timeline_tests, + }, + { + .pName = SECURITY_TESTS_STR, + .pInitFunc = suite_security_tests_init, + .pCleanupFunc = suite_security_tests_clean, + .pTests = security_tests, + }, + { + .pName = HOTUNPLUG_TESTS_STR, + .pInitFunc = suite_hotunplug_tests_init, + .pCleanupFunc = suite_hotunplug_tests_clean, + .pTests = hotunplug_tests, + }, + { + .pName = CP_DMA_TESTS_STR, + .pInitFunc = suite_cp_dma_tests_init, + .pCleanupFunc = suite_cp_dma_tests_clean, + .pTests = cp_dma_tests, + }, + + CU_SUITE_INFO_NULL, +}; + +typedef CU_BOOL (*active__stat_func)(void); + +typedef struct Suites_Active_Status { + char* pName; + active__stat_func pActive; +}Suites_Active_Status; + +static CU_BOOL always_active() +{ + return CU_TRUE; +} + +static Suites_Active_Status suites_active_stat[] = { + { + .pName = BASIC_TESTS_STR, + .pActive = suite_basic_tests_enable, + }, + { + .pName = BO_TESTS_STR, + .pActive = always_active, + }, + { + .pName = CS_TESTS_STR, + .pActive = suite_cs_tests_enable, + }, + { + .pName = VCE_TESTS_STR, + .pActive = suite_vce_tests_enable, + }, + { + .pName = VCN_TESTS_STR, + .pActive = suite_vcn_tests_enable, + }, + { + .pName = JPEG_TESTS_STR, + .pActive = suite_jpeg_tests_enable, + }, + { + .pName = UVD_ENC_TESTS_STR, + .pActive = suite_uvd_enc_tests_enable, + }, + { + .pName = DEADLOCK_TESTS_STR, + .pActive = suite_deadlock_tests_enable, + }, + { + .pName = VM_TESTS_STR, + .pActive = suite_vm_tests_enable, + }, + { + .pName = RAS_TESTS_STR, + .pActive = suite_ras_tests_enable, + }, + { + .pName = SYNCOBJ_TIMELINE_TESTS_STR, + .pActive = suite_syncobj_timeline_tests_enable, + }, + { + .pName = SECURITY_TESTS_STR, + .pActive = suite_security_tests_enable, + }, + { + .pName = HOTUNPLUG_TESTS_STR, + .pActive = suite_hotunplug_tests_enable, + }, + { + .pName = CP_DMA_TESTS_STR, + .pActive = suite_cp_dma_tests_enable, + }, +}; + + +/* + * Display information about all suites and their tests + * + * NOTE: Must be run after registry is initialized and suites registered. + */ +static void display_test_suites(void) +{ + int iSuite; + int iTest; + CU_pSuite pSuite = NULL; + CU_pTest pTest = NULL; + + printf("%5s: %2s: %8s: %s\n", "What", "ID", "Status", "Name"); + + for (iSuite = 0; suites[iSuite].pName != NULL; iSuite++) { + + pSuite = CU_get_suite_by_index((unsigned int) iSuite + 1, + CU_get_registry()); + + if (!pSuite) { + fprintf(stderr, "Invalid suite id : %d\n", iSuite + 1); + continue; + } + + printf("Suite: %2d: %8s: %s\n", + iSuite + 1, + pSuite->fActive ? "ENABLED" : "DISABLED", + suites[iSuite].pName); + + if (!pSuite->fActive) + continue; + + for (iTest = 0; suites[iSuite].pTests[iTest].pName != NULL; + iTest++) { + pTest = CU_get_test_by_index((unsigned int) iTest + 1, + pSuite); + if (!pTest) { + fprintf(stderr, "Invalid test id : %d\n", iTest + 1); + continue; + } + printf(" Test: %2d: %8s: %s\n", + iTest + 1, + pSuite->fActive && pTest->fActive ? "ENABLED" : "DISABLED", + suites[iSuite].pTests[iTest].pName); + } + } +} + +/** Help string for command line parameters */ +static const char usage[] = + "Usage: %s [-hlpr] [<-s > [-t ] [-f]] " + "[-b [-d ]]\n" + "where:\n" + " l - Display all suites and their tests\n" + " r - Run the tests on render node\n" + " b - Specify device's PCI bus id to run tests\n" + " d - Specify device's PCI device id to run tests (optional)\n" + " p - Display information of AMDGPU devices in system\n" + " f - Force executing inactive suite or test\n" + " h - Display this help\n"; +/** Specified options strings for getopt */ +static const char options[] = "hlrps:t:b:d:f"; + +/* Open AMD devices. + * Return the number of AMD device opened. + */ +static int amdgpu_open_devices(int open_render_node) +{ + drmDevicePtr devices[MAX_CARDS_SUPPORTED]; + int i; + int drm_node; + int amd_index = 0; + int drm_count; + int fd; + drmVersionPtr version; + + for (i = 0; i < MAX_CARDS_SUPPORTED; i++) { + drm_amdgpu[i] = -1; + } + + drm_count = drmGetDevices2(0, devices, MAX_CARDS_SUPPORTED); + + if (drm_count < 0) { + fprintf(stderr, + "drmGetDevices2() returned an error %d\n", + drm_count); + return 0; + } + + for (i = 0; i < drm_count; i++) { + /* If this is not PCI device, skip*/ + if (devices[i]->bustype != DRM_BUS_PCI) + continue; + + /* If this is not AMD GPU vender ID, skip*/ + if (devices[i]->deviceinfo.pci->vendor_id != 0x1002) + continue; + + if (open_render_node) + drm_node = DRM_NODE_RENDER; + else + drm_node = DRM_NODE_PRIMARY; + + fd = -1; + if (devices[i]->available_nodes & 1 << drm_node) + fd = open( + devices[i]->nodes[drm_node], + O_RDWR | O_CLOEXEC); + + /* This node is not available. */ + if (fd < 0) continue; + + version = drmGetVersion(fd); + if (!version) { + fprintf(stderr, + "Warning: Cannot get version for %s." + "Error is %s\n", + devices[i]->nodes[drm_node], + strerror(errno)); + close(fd); + continue; + } + + if (strcmp(version->name, "amdgpu")) { + /* This is not AMDGPU driver, skip.*/ + drmFreeVersion(version); + close(fd); + continue; + } + + drmFreeVersion(version); + + drm_amdgpu[amd_index] = fd; + amd_index++; + } + + drmFreeDevices(devices, drm_count); + return amd_index; +} + +/* Close AMD devices. + */ +void amdgpu_close_devices() +{ + int i; + for (i = 0; i < MAX_CARDS_SUPPORTED; i++) + if (drm_amdgpu[i] >=0) { + close(drm_amdgpu[i]); + } +} + +/* Print AMD devices information */ +static void amdgpu_print_devices() +{ + int i; + drmDevicePtr device; + + /* Open the first AMD device to print driver information. */ + if (drm_amdgpu[0] >=0) { + /* Display AMD driver version information.*/ + drmVersionPtr retval = drmGetVersion(drm_amdgpu[0]); + + if (retval == NULL) { + perror("Cannot get version for AMDGPU device"); + return; + } + + printf("Driver name: %s, Date: %s, Description: %s.\n", + retval->name, retval->date, retval->desc); + drmFreeVersion(retval); + } + + /* Display information of AMD devices */ + printf("Devices:\n"); + for (i = 0; i < MAX_CARDS_SUPPORTED && drm_amdgpu[i] >=0; i++) + if (drmGetDevice2(drm_amdgpu[i], + DRM_DEVICE_GET_PCI_REVISION, + &device) == 0) { + if (device->bustype == DRM_BUS_PCI) { + printf("PCI "); + printf(" domain:%04x", + device->businfo.pci->domain); + printf(" bus:%02x", + device->businfo.pci->bus); + printf(" device:%02x", + device->businfo.pci->dev); + printf(" function:%01x", + device->businfo.pci->func); + printf(" vendor_id:%04x", + device->deviceinfo.pci->vendor_id); + printf(" device_id:%04x", + device->deviceinfo.pci->device_id); + printf(" subvendor_id:%04x", + device->deviceinfo.pci->subvendor_id); + printf(" subdevice_id:%04x", + device->deviceinfo.pci->subdevice_id); + printf(" revision_id:%02x", + device->deviceinfo.pci->revision_id); + printf("\n"); + } + drmFreeDevice(&device); + } +} + +/* Find a match AMD device in PCI bus + * Return the index of the device or -1 if not found + */ +static int amdgpu_find_device(uint8_t bus, uint16_t dev) +{ + int i; + drmDevicePtr device; + + for (i = 0; i < MAX_CARDS_SUPPORTED && drm_amdgpu[i] >= 0; i++) { + if (drmGetDevice2(drm_amdgpu[i], + DRM_DEVICE_GET_PCI_REVISION, + &device) == 0) { + if (device->bustype == DRM_BUS_PCI) + if ((bus == 0xFF || device->businfo.pci->bus == bus) && + device->deviceinfo.pci->device_id == dev) { + drmFreeDevice(&device); + return i; + } + + drmFreeDevice(&device); + } + } + + return -1; +} + +static void amdgpu_disable_suites() +{ + amdgpu_device_handle device_handle; + uint32_t major_version, minor_version, family_id; + drmDevicePtr devices[MAX_CARDS_SUPPORTED]; + int i, drm_count; + int size = sizeof(suites_active_stat) / sizeof(suites_active_stat[0]); + + if (amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle)) + return; + + family_id = device_handle->info.family_id; + + if (amdgpu_device_deinitialize(device_handle)) + return; + + drm_count = drmGetDevices2(0, devices, MAX_CARDS_SUPPORTED); + + /* Set active status for suites based on their policies */ + for (i = 0; i < size; ++i) + if (amdgpu_set_suite_active(suites_active_stat[i].pName, + suites_active_stat[i].pActive())) + fprintf(stderr, "suite deactivation failed - %s\n", CU_get_error_msg()); + + /* Explicitly disable specific tests due to known bugs or preferences */ + /* + * BUG: Compute ring stalls and never recovers when the address is + * written after the command already submitted + */ + if (amdgpu_set_test_active(DEADLOCK_TESTS_STR, + "compute ring block test (set amdgpu.lockup_timeout=50)", CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); + + if (amdgpu_set_test_active(DEADLOCK_TESTS_STR, + "sdma ring block test (set amdgpu.lockup_timeout=50)", CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); + + /* This test was ran on GFX9 only */ + //if (family_id < AMDGPU_FAMILY_AI || family_id > AMDGPU_FAMILY_RV) + if (amdgpu_set_test_active(DEADLOCK_TESTS_STR, + "gfx ring bad dispatch test (set amdgpu.lockup_timeout=50)", CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); + + /* This test was ran on GFX9 only */ + //if (family_id < AMDGPU_FAMILY_AI || family_id > AMDGPU_FAMILY_RV) + if (amdgpu_set_test_active(DEADLOCK_TESTS_STR, + "compute ring bad dispatch test (set amdgpu.lockup_timeout=50,50)", CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); + + /* This test was ran on GFX9 only */ + //if (family_id < AMDGPU_FAMILY_AI || family_id > AMDGPU_FAMILY_RV) + if (amdgpu_set_test_active(DEADLOCK_TESTS_STR, + "gfx ring bad slow dispatch test (set amdgpu.lockup_timeout=50)", CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); + + /* This test was ran on GFX9 only */ + //if (family_id < AMDGPU_FAMILY_AI || family_id > AMDGPU_FAMILY_RV) + if (amdgpu_set_test_active(DEADLOCK_TESTS_STR, + "compute ring bad slow dispatch test (set amdgpu.lockup_timeout=50,50)", CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); + + //if (family_id < AMDGPU_FAMILY_AI || family_id > AMDGPU_FAMILY_RV) + if (amdgpu_set_test_active(DEADLOCK_TESTS_STR, + "gfx ring bad draw test (set amdgpu.lockup_timeout=50)", CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); + + /* This test was ran on GFX9 only */ + //if (family_id < AMDGPU_FAMILY_AI || family_id > AMDGPU_FAMILY_RV) + if (amdgpu_set_test_active(DEADLOCK_TESTS_STR, + "gfx ring slow bad draw test (set amdgpu.lockup_timeout=50)", CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); + + if (amdgpu_set_test_active(DEADLOCK_TESTS_STR, + "sdma ring corrupted header test (set amdgpu.lockup_timeout=50)", CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); + + if (amdgpu_set_test_active(DEADLOCK_TESTS_STR, + "sdma ring slow linear copy test (set amdgpu.lockup_timeout=50)", CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); + + if (amdgpu_set_test_active(BASIC_TESTS_STR, "bo eviction Test", CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); + + /* This test was ran on GFX8 and GFX9 only */ + if (family_id < AMDGPU_FAMILY_VI || family_id > AMDGPU_FAMILY_RV) + if (amdgpu_set_test_active(BASIC_TESTS_STR, "Sync dependency Test", CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); + + /* This test was ran on GFX9 only */ + if (family_id < AMDGPU_FAMILY_AI || family_id > AMDGPU_FAMILY_RV) { + if (amdgpu_set_test_active(BASIC_TESTS_STR, "Dispatch Test (GFX)", CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); + if (amdgpu_set_test_active(BASIC_TESTS_STR, "Dispatch Test (Compute)", CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); + } + + /* This test was ran on GFX9 only */ + if (family_id < AMDGPU_FAMILY_AI || family_id > AMDGPU_FAMILY_RV) + if (amdgpu_set_test_active(BASIC_TESTS_STR, "Draw Test", CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); + + /* This test was ran on GFX9 only */ + //if (family_id < AMDGPU_FAMILY_AI || family_id > AMDGPU_FAMILY_RV) + if (amdgpu_set_test_active(BASIC_TESTS_STR, "GPU reset Test", CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); + + /* You need at least 2 devices for this */ + if (drm_count < 2) + if (amdgpu_set_test_active(HOTUNPLUG_TESTS_STR, "Unplug with exported fence", CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", CU_get_error_msg()); +} + +int test_device_index; + +int amdgpu_open_device_on_test_index(int render_node) +{ + int i; + + if (amdgpu_open_devices(open_render_node) <= 0) { + perror("Cannot open AMDGPU device"); + return -1; + } + + if (test_device_index >= 0) { + /* Most tests run on device of drm_amdgpu[0]. + * Swap the chosen device to drm_amdgpu[0]. + */ + i = drm_amdgpu[0]; + drm_amdgpu[0] = drm_amdgpu[test_device_index]; + drm_amdgpu[test_device_index] = i; + } + + return 0; + + +} + + +static bool amdgpu_node_is_drm(int maj, int min) +{ +#ifdef __linux__ + char path[64]; + struct stat sbuf; + + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/drm", + maj, min); + return stat(path, &sbuf) == 0; +#elif defined(__FreeBSD__) + char name[SPECNAMELEN]; + + if (!devname_r(makedev(maj, min), S_IFCHR, name, sizeof(name))) + return 0; + /* Handle drm/ and dri/ as both are present in different FreeBSD version + * FreeBSD on amd64/i386/powerpc external kernel modules create node in + * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates + * only device nodes in /dev/dri/ */ + return (!strncmp(name, "drm/", 4) || !strncmp(name, "dri/", 4)); +#else + return maj == DRM_MAJOR; +#endif +} + +char *amdgpu_get_device_from_fd(int fd) +{ +#ifdef __linux__ + struct stat sbuf; + char path[PATH_MAX + 1]; + unsigned int maj, min; + + if (fstat(fd, &sbuf)) + return NULL; + + maj = major(sbuf.st_rdev); + min = minor(sbuf.st_rdev); + + if (!amdgpu_node_is_drm(maj, min) || !S_ISCHR(sbuf.st_mode)) + return NULL; + + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); + return strdup(path); +#else + return NULL; +#endif +} + +/* The main() function for setting up and running the tests. + * Returns a CUE_SUCCESS on successful running, another + * CUnit error code on failure. + */ +int main(int argc, char **argv) +{ + int c; /* Character received from getopt */ + int i = 0; + int suite_id = -1; /* By default run everything */ + int test_id = -1; /* By default run all tests in the suite */ + int pci_bus_id = -1; /* By default PC bus ID is not specified */ + int pci_device_id = 0; /* By default PC device ID is zero */ + int display_devices = 0;/* By default not to display devices' info */ + CU_pSuite pSuite = NULL; + CU_pTest pTest = NULL; + int display_list = 0; + int force_run = 0; + + for (i = 0; i < MAX_CARDS_SUPPORTED; i++) + drm_amdgpu[i] = -1; + + + /* Parse command line string */ + opterr = 0; /* Do not print error messages from getopt */ + while ((c = getopt(argc, argv, options)) != -1) { + switch (c) { + case 'l': + display_list = 1; + break; + case 's': + suite_id = atoi(optarg); + break; + case 't': + test_id = atoi(optarg); + break; + case 'b': + pci_bus_id = atoi(optarg); + break; + case 'd': + sscanf(optarg, "%x", &pci_device_id); + break; + case 'p': + display_devices = 1; + break; + case 'r': + open_render_node = 1; + break; + case 'f': + force_run = 1; + break; + case '?': + case 'h': + fprintf(stderr, usage, argv[0]); + exit(EXIT_SUCCESS); + default: + fprintf(stderr, usage, argv[0]); + exit(EXIT_FAILURE); + } + } + + if (amdgpu_open_devices(open_render_node) <= 0) { + perror("Cannot open AMDGPU device"); + exit(EXIT_FAILURE); + } + + if (drm_amdgpu[0] < 0) { + perror("Cannot open AMDGPU device"); + exit(EXIT_FAILURE); + } + + if (display_devices) { + amdgpu_print_devices(); + amdgpu_close_devices(); + exit(EXIT_SUCCESS); + } + + if (pci_bus_id > 0 || pci_device_id) { + /* A device was specified to run the test */ + test_device_index = amdgpu_find_device(pci_bus_id, + pci_device_id); + + if (test_device_index >= 0) { + /* Most tests run on device of drm_amdgpu[0]. + * Swap the chosen device to drm_amdgpu[0]. + */ + i = drm_amdgpu[0]; + drm_amdgpu[0] = drm_amdgpu[test_device_index]; + drm_amdgpu[test_device_index] = i; + } else { + fprintf(stderr, + "The specified GPU device does not exist.\n"); + exit(EXIT_FAILURE); + } + } + + /* Initialize test suites to run */ + + /* initialize the CUnit test registry */ + if (CUE_SUCCESS != CU_initialize_registry()) { + amdgpu_close_devices(); + return CU_get_error(); + } + + /* Register suites. */ + if (CU_register_suites(suites) != CUE_SUCCESS) { + fprintf(stderr, "suite registration failed - %s\n", + CU_get_error_msg()); + CU_cleanup_registry(); + amdgpu_close_devices(); + exit(EXIT_FAILURE); + } + + /* Run tests using the CUnit Basic interface */ + CU_basic_set_mode(CU_BRM_VERBOSE); + + /* Disable suites and individual tests based on misc. conditions */ + amdgpu_disable_suites(); + + if (display_list) { + display_test_suites(); + goto end; + } + + if (suite_id != -1) { /* If user specify particular suite? */ + pSuite = CU_get_suite_by_index((unsigned int) suite_id, + CU_get_registry()); + + if (pSuite) { + + if (force_run) + CU_set_suite_active(pSuite, CU_TRUE); + + if (test_id != -1) { /* If user specify test id */ + pTest = CU_get_test_by_index( + (unsigned int) test_id, + pSuite); + if (pTest) { + if (force_run) + CU_set_test_active(pTest, CU_TRUE); + + CU_basic_run_test(pSuite, pTest); + } + else { + fprintf(stderr, "Invalid test id: %d\n", + test_id); + CU_cleanup_registry(); + amdgpu_close_devices(); + exit(EXIT_FAILURE); + } + } else + CU_basic_run_suite(pSuite); + } else { + fprintf(stderr, "Invalid suite id : %d\n", + suite_id); + CU_cleanup_registry(); + amdgpu_close_devices(); + exit(EXIT_FAILURE); + } + } else + CU_basic_run_tests(); + +end: + CU_cleanup_registry(); + amdgpu_close_devices(); + return CU_get_error(); +} diff --git a/tests/amdgpu/amdgpu_test.h b/tests/amdgpu/amdgpu_test.h new file mode 100644 index 0000000..e2ba043 --- /dev/null +++ b/tests/amdgpu/amdgpu_test.h @@ -0,0 +1,546 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 _AMDGPU_TEST_H_ +#define _AMDGPU_TEST_H_ + +#include "amdgpu.h" +#include "amdgpu_drm.h" + +/** + * Define max. number of card in system which we are able to handle + */ +#define MAX_CARDS_SUPPORTED 128 + +/* Forward reference for array to keep "drm" handles */ +extern int drm_amdgpu[MAX_CARDS_SUPPORTED]; + +/* Global variables */ +extern int open_render_node; + +/************************* Basic test suite ********************************/ + +/* + * Define basic test suite to serve as the starting point for future testing +*/ + +/** + * Initialize basic test suite + */ +int suite_basic_tests_init(); + +/** + * Deinitialize basic test suite + */ +int suite_basic_tests_clean(); + +/** + * Decide if the suite is enabled by default or not. + */ +CU_BOOL suite_basic_tests_enable(void); + +/** + * Tests in basic test suite + */ +extern CU_TestInfo basic_tests[]; + +/** + * Initialize bo test suite + */ +int suite_bo_tests_init(); + +/** + * Deinitialize bo test suite + */ +int suite_bo_tests_clean(); + +/** + * Tests in bo test suite + */ +extern CU_TestInfo bo_tests[]; + +/** + * Initialize cs test suite + */ +int suite_cs_tests_init(); + +/** + * Deinitialize cs test suite + */ +int suite_cs_tests_clean(); + +/** + * Decide if the suite is enabled by default or not. + */ +CU_BOOL suite_cs_tests_enable(void); + +/** + * Tests in cs test suite + */ +extern CU_TestInfo cs_tests[]; + +/** + * Initialize vce test suite + */ +int suite_vce_tests_init(); + +/** + * Deinitialize vce test suite + */ +int suite_vce_tests_clean(); + +/** + * Decide if the suite is enabled by default or not. + */ +CU_BOOL suite_vce_tests_enable(void); + +/** + * Tests in vce test suite + */ +extern CU_TestInfo vce_tests[]; + +/** ++ * Initialize vcn test suite ++ */ +int suite_vcn_tests_init(); + +/** ++ * Deinitialize vcn test suite ++ */ +int suite_vcn_tests_clean(); + +/** + * Decide if the suite is enabled by default or not. + */ +CU_BOOL suite_vcn_tests_enable(void); + +/** ++ * Tests in vcn test suite ++ */ +extern CU_TestInfo vcn_tests[]; + +/** ++ * Initialize jpeg test suite ++ */ +int suite_jpeg_tests_init(); + +/** ++ * Deinitialize jpeg test suite ++ */ +int suite_jpeg_tests_clean(); + +/** + * Decide if the suite is enabled by default or not. + */ +CU_BOOL suite_jpeg_tests_enable(void); + +/** ++ * Tests in vcn test suite ++ */ +extern CU_TestInfo jpeg_tests[]; + +/** + * Initialize uvd enc test suite + */ +int suite_uvd_enc_tests_init(); + +/** + * Deinitialize uvd enc test suite + */ +int suite_uvd_enc_tests_clean(); + +/** + * Decide if the suite is enabled by default or not. + */ +CU_BOOL suite_uvd_enc_tests_enable(void); + +/** + * Tests in uvd enc test suite + */ +extern CU_TestInfo uvd_enc_tests[]; + +/** + * Initialize deadlock test suite + */ +int suite_deadlock_tests_init(); + +/** + * Deinitialize deadlock test suite + */ +int suite_deadlock_tests_clean(); + +/** + * Decide if the suite is enabled by default or not. + */ +CU_BOOL suite_deadlock_tests_enable(void); + +/** + * Tests in uvd enc test suite + */ +extern CU_TestInfo deadlock_tests[]; + +/** + * Initialize vm test suite + */ +int suite_vm_tests_init(); + +/** + * Deinitialize deadlock test suite + */ +int suite_vm_tests_clean(); + +/** + * Decide if the suite is enabled by default or not. + */ +CU_BOOL suite_vm_tests_enable(void); + +/** + * Tests in vm test suite + */ +extern CU_TestInfo vm_tests[]; + + +/** + * Initialize ras test suite + */ +int suite_ras_tests_init(); + +/** + * Deinitialize deadlock test suite + */ +int suite_ras_tests_clean(); + +/** + * Decide if the suite is enabled by default or not. + */ +CU_BOOL suite_ras_tests_enable(void); + +/** + * Tests in ras test suite + */ +extern CU_TestInfo ras_tests[]; + + +/** + * Initialize syncobj timeline test suite + */ +int suite_syncobj_timeline_tests_init(); + +/** + * Deinitialize syncobj timeline test suite + */ +int suite_syncobj_timeline_tests_clean(); + +/** + * Decide if the suite is enabled by default or not. + */ +CU_BOOL suite_syncobj_timeline_tests_enable(void); + +/** + * Tests in syncobj timeline test suite + */ +extern CU_TestInfo syncobj_timeline_tests[]; + + +/** + * Initialize cp dma test suite + */ +int suite_cp_dma_tests_init(); + +/** + * Deinitialize cp dma test suite + */ +int suite_cp_dma_tests_clean(); + +/** + * Decide if the suite is enabled by default or not. + */ +CU_BOOL suite_cp_dma_tests_enable(void); + +/** + * Tests in cp dma test suite + */ +extern CU_TestInfo cp_dma_tests[]; + +/** + * Initialize security test suite + */ +int suite_security_tests_init(); + +/** + * Deinitialize security test suite + */ +int suite_security_tests_clean(); + +/** + * Decide if the suite is enabled by default or not. + */ +CU_BOOL suite_security_tests_enable(void); + +/** + * Tests in security test suite + */ +extern CU_TestInfo security_tests[]; + +extern void +amdgpu_command_submission_write_linear_helper_with_secure(amdgpu_device_handle + device, + unsigned ip_type, + bool secure); + +extern void amdgpu_test_dispatch_helper(amdgpu_device_handle device_handle, unsigned ip); +extern void amdgpu_test_dispatch_hang_helper(amdgpu_device_handle device_handle, uint32_t ip); +extern void amdgpu_test_dispatch_hang_slow_helper(amdgpu_device_handle device_handle, uint32_t ip); +extern void amdgpu_test_draw_helper(amdgpu_device_handle device_handle); +extern void amdgpu_test_draw_hang_helper(amdgpu_device_handle device_handle); +extern void amdgpu_test_draw_hang_slow_helper(amdgpu_device_handle device_handle); + +/** + * Initialize hotunplug test suite + */ +int suite_hotunplug_tests_init(); + +/** + * Deinitialize hotunplug test suite + */ +int suite_hotunplug_tests_clean(); + +/** + * Decide if the suite is enabled by default or not. + */ +CU_BOOL suite_hotunplug_tests_enable(void); + +/** + * Tests in uvd enc test suite + */ +extern CU_TestInfo hotunplug_tests[]; + + +/** + * Helper functions + */ +static inline amdgpu_bo_handle gpu_mem_alloc( + amdgpu_device_handle device_handle, + uint64_t size, + uint64_t alignment, + uint32_t type, + uint64_t flags, + uint64_t *vmc_addr, + amdgpu_va_handle *va_handle) +{ + struct amdgpu_bo_alloc_request req = {0}; + amdgpu_bo_handle buf_handle = NULL; + int r; + + req.alloc_size = size; + req.phys_alignment = alignment; + req.preferred_heap = type; + req.flags = flags; + + r = amdgpu_bo_alloc(device_handle, &req, &buf_handle); + CU_ASSERT_EQUAL(r, 0); + if (r) + return NULL; + + if (vmc_addr && va_handle) { + r = amdgpu_va_range_alloc(device_handle, + amdgpu_gpu_va_range_general, + size, alignment, 0, vmc_addr, + va_handle, 0); + CU_ASSERT_EQUAL(r, 0); + if (r) + goto error_free_bo; + + r = amdgpu_bo_va_op(buf_handle, 0, size, *vmc_addr, 0, + AMDGPU_VA_OP_MAP); + CU_ASSERT_EQUAL(r, 0); + if (r) + goto error_free_va; + } + + return buf_handle; + +error_free_va: + r = amdgpu_va_range_free(*va_handle); + CU_ASSERT_EQUAL(r, 0); + +error_free_bo: + r = amdgpu_bo_free(buf_handle); + CU_ASSERT_EQUAL(r, 0); + + return NULL; +} + +static inline int gpu_mem_free(amdgpu_bo_handle bo, + amdgpu_va_handle va_handle, + uint64_t vmc_addr, + uint64_t size) +{ + int r; + + if (!bo) + return 0; + + if (va_handle) { + r = amdgpu_bo_va_op(bo, 0, size, vmc_addr, 0, + AMDGPU_VA_OP_UNMAP); + CU_ASSERT_EQUAL(r, 0); + if (r) + return r; + + r = amdgpu_va_range_free(va_handle); + CU_ASSERT_EQUAL(r, 0); + if (r) + return r; + } + + r = amdgpu_bo_free(bo); + CU_ASSERT_EQUAL(r, 0); + + return r; +} + +static inline int +amdgpu_bo_alloc_wrap(amdgpu_device_handle dev, unsigned size, + unsigned alignment, unsigned heap, uint64_t flags, + amdgpu_bo_handle *bo) +{ + struct amdgpu_bo_alloc_request request = {}; + amdgpu_bo_handle buf_handle; + int r; + + request.alloc_size = size; + request.phys_alignment = alignment; + request.preferred_heap = heap; + request.flags = flags; + + r = amdgpu_bo_alloc(dev, &request, &buf_handle); + if (r) + return r; + + *bo = buf_handle; + + return 0; +} + +int amdgpu_bo_alloc_and_map_raw(amdgpu_device_handle dev, unsigned size, + unsigned alignment, unsigned heap, uint64_t alloc_flags, + uint64_t mapping_flags, amdgpu_bo_handle *bo, void **cpu, + uint64_t *mc_address, + amdgpu_va_handle *va_handle); + +static inline int +amdgpu_bo_alloc_and_map(amdgpu_device_handle dev, unsigned size, + unsigned alignment, unsigned heap, uint64_t alloc_flags, + amdgpu_bo_handle *bo, void **cpu, uint64_t *mc_address, + amdgpu_va_handle *va_handle) +{ + return amdgpu_bo_alloc_and_map_raw(dev, size, alignment, heap, + alloc_flags, 0, bo, cpu, mc_address, va_handle); +} + +static inline int +amdgpu_bo_unmap_and_free(amdgpu_bo_handle bo, amdgpu_va_handle va_handle, + uint64_t mc_addr, uint64_t size) +{ + amdgpu_bo_cpu_unmap(bo); + amdgpu_bo_va_op(bo, 0, size, mc_addr, 0, AMDGPU_VA_OP_UNMAP); + amdgpu_va_range_free(va_handle); + amdgpu_bo_free(bo); + + return 0; + +} + +static inline int +amdgpu_get_bo_list(amdgpu_device_handle dev, amdgpu_bo_handle bo1, + amdgpu_bo_handle bo2, amdgpu_bo_list_handle *list) +{ + amdgpu_bo_handle resources[] = {bo1, bo2}; + + return amdgpu_bo_list_create(dev, bo2 ? 2 : 1, resources, NULL, list); +} + + +static inline CU_ErrorCode amdgpu_set_suite_active(const char *suite_name, + CU_BOOL active) +{ + CU_ErrorCode r = CU_set_suite_active(CU_get_suite(suite_name), active); + + if (r != CUE_SUCCESS) + fprintf(stderr, "Failed to obtain suite %s\n", suite_name); + + return r; +} + +static inline CU_ErrorCode amdgpu_set_test_active(const char *suite_name, + const char *test_name, CU_BOOL active) +{ + CU_ErrorCode r; + CU_pSuite pSuite = CU_get_suite(suite_name); + + if (!pSuite) { + fprintf(stderr, "Failed to obtain suite %s\n", + suite_name); + return CUE_NOSUITE; + } + + r = CU_set_test_active(CU_get_test(pSuite, test_name), active); + if (r != CUE_SUCCESS) + fprintf(stderr, "Failed to obtain test %s\n", test_name); + + return r; +} + + +static inline bool asic_is_gfx_pipe_removed(uint32_t family_id, uint32_t chip_id, uint32_t chip_rev) +{ + + if (family_id != AMDGPU_FAMILY_AI) + return false; + + switch (chip_id - chip_rev) { + /* Arcturus */ + case 0x32: + /* Aldebaran */ + case 0x3c: + return true; + default: + return false; + } +} + +void amdgpu_test_exec_cs_helper_raw(amdgpu_device_handle device_handle, + amdgpu_context_handle context_handle, + unsigned ip_type, int instance, int pm4_dw, + uint32_t *pm4_src, int res_cnt, + amdgpu_bo_handle *resources, + struct amdgpu_cs_ib_info *ib_info, + struct amdgpu_cs_request *ibs_request, + bool secure); + +void amdgpu_close_devices(); +int amdgpu_open_device_on_test_index(int render_node); +char *amdgpu_get_device_from_fd(int fd); + +#endif /* #ifdef _AMDGPU_TEST_H_ */ diff --git a/tests/amdgpu/basic_tests.c b/tests/amdgpu/basic_tests.c new file mode 100644 index 0000000..42176c0 --- /dev/null +++ b/tests/amdgpu/basic_tests.c @@ -0,0 +1,2556 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * +*/ + +#include +#include +#include +#include +#ifdef MAJOR_IN_SYSMACROS +#include +#endif +#include +#include +#if HAVE_ALLOCA_H +# include +#endif +#include + +#include "CUnit/Basic.h" + +#include "amdgpu_test.h" +#include "amdgpu_drm.h" +#include "amdgpu_internal.h" +#include "util_math.h" + +static amdgpu_device_handle device_handle; +static uint32_t major_version; +static uint32_t minor_version; +static uint32_t family_id; +static uint32_t chip_id; +static uint32_t chip_rev; + +static void amdgpu_query_info_test(void); +static void amdgpu_command_submission_gfx(void); +static void amdgpu_command_submission_compute(void); +static void amdgpu_command_submission_multi_fence(void); +static void amdgpu_command_submission_sdma(void); +static void amdgpu_userptr_test(void); +static void amdgpu_semaphore_test(void); +static void amdgpu_sync_dependency_test(void); +static void amdgpu_bo_eviction_test(void); +static void amdgpu_compute_dispatch_test(void); +static void amdgpu_gfx_dispatch_test(void); +static void amdgpu_draw_test(void); +static void amdgpu_gpu_reset_test(void); +static void amdgpu_stable_pstate_test(void); + +static void amdgpu_command_submission_write_linear_helper(unsigned ip_type); +static void amdgpu_command_submission_const_fill_helper(unsigned ip_type); +static void amdgpu_command_submission_copy_linear_helper(unsigned ip_type); +static void amdgpu_test_exec_cs_helper(amdgpu_context_handle context_handle, + unsigned ip_type, + int instance, int pm4_dw, uint32_t *pm4_src, + int res_cnt, amdgpu_bo_handle *resources, + struct amdgpu_cs_ib_info *ib_info, + struct amdgpu_cs_request *ibs_request); + +CU_TestInfo basic_tests[] = { + { "Query Info Test", amdgpu_query_info_test }, + { "Userptr Test", amdgpu_userptr_test }, + { "bo eviction Test", amdgpu_bo_eviction_test }, + { "Command submission Test (GFX)", amdgpu_command_submission_gfx }, + { "Command submission Test (Compute)", amdgpu_command_submission_compute }, + { "Command submission Test (Multi-Fence)", amdgpu_command_submission_multi_fence }, + { "Command submission Test (SDMA)", amdgpu_command_submission_sdma }, + { "SW semaphore Test", amdgpu_semaphore_test }, + { "Sync dependency Test", amdgpu_sync_dependency_test }, + { "Dispatch Test (Compute)", amdgpu_compute_dispatch_test }, + { "Dispatch Test (GFX)", amdgpu_gfx_dispatch_test }, + { "Draw Test", amdgpu_draw_test }, + { "GPU reset Test", amdgpu_gpu_reset_test }, + { "Stable pstate Test", amdgpu_stable_pstate_test }, + CU_TEST_INFO_NULL, +}; +#define BUFFER_SIZE (MAX2(8 * 1024, getpagesize())) +#define SDMA_PKT_HEADER_op_offset 0 +#define SDMA_PKT_HEADER_op_mask 0x000000FF +#define SDMA_PKT_HEADER_op_shift 0 +#define SDMA_PKT_HEADER_OP(x) (((x) & SDMA_PKT_HEADER_op_mask) << SDMA_PKT_HEADER_op_shift) +#define SDMA_OPCODE_CONSTANT_FILL 11 +# define SDMA_CONSTANT_FILL_EXTRA_SIZE(x) ((x) << 14) + /* 0 = byte fill + * 2 = DW fill + */ +#define SDMA_PACKET(op, sub_op, e) ((((e) & 0xFFFF) << 16) | \ + (((sub_op) & 0xFF) << 8) | \ + (((op) & 0xFF) << 0)) +#define SDMA_OPCODE_WRITE 2 +# define SDMA_WRITE_SUB_OPCODE_LINEAR 0 +# define SDMA_WRTIE_SUB_OPCODE_TILED 1 + +#define SDMA_OPCODE_COPY 1 +# define SDMA_COPY_SUB_OPCODE_LINEAR 0 + +#define SDMA_OPCODE_ATOMIC 10 +# define SDMA_ATOMIC_LOOP(x) ((x) << 0) + /* 0 - single_pass_atomic. + * 1 - loop_until_compare_satisfied. + */ +# define SDMA_ATOMIC_TMZ(x) ((x) << 2) + /* 0 - non-TMZ. + * 1 - TMZ. + */ +# define SDMA_ATOMIC_OPCODE(x) ((x) << 9) + /* TC_OP_ATOMIC_CMPSWAP_RTN_32 0x00000008 + * same as Packet 3 + */ + +#define GFX_COMPUTE_NOP 0xffff1000 +#define SDMA_NOP 0x0 + +/* PM4 */ +#define PACKET_TYPE0 0 +#define PACKET_TYPE1 1 +#define PACKET_TYPE2 2 +#define PACKET_TYPE3 3 + +#define CP_PACKET_GET_TYPE(h) (((h) >> 30) & 3) +#define CP_PACKET_GET_COUNT(h) (((h) >> 16) & 0x3FFF) +#define CP_PACKET0_GET_REG(h) ((h) & 0xFFFF) +#define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF) +#define PACKET0(reg, n) ((PACKET_TYPE0 << 30) | \ + ((reg) & 0xFFFF) | \ + ((n) & 0x3FFF) << 16) +#define CP_PACKET2 0x80000000 +#define PACKET2_PAD_SHIFT 0 +#define PACKET2_PAD_MASK (0x3fffffff << 0) + +#define PACKET2(v) (CP_PACKET2 | REG_SET(PACKET2_PAD, (v))) + +#define PACKET3(op, n) ((PACKET_TYPE3 << 30) | \ + (((op) & 0xFF) << 8) | \ + ((n) & 0x3FFF) << 16) +#define PACKET3_COMPUTE(op, n) PACKET3(op, n) | (1 << 1) + +/* Packet 3 types */ +#define PACKET3_NOP 0x10 + +#define PACKET3_WRITE_DATA 0x37 +#define WRITE_DATA_DST_SEL(x) ((x) << 8) + /* 0 - register + * 1 - memory (sync - via GRBM) + * 2 - gl2 + * 3 - gds + * 4 - reserved + * 5 - memory (async - direct) + */ +#define WR_ONE_ADDR (1 << 16) +#define WR_CONFIRM (1 << 20) +#define WRITE_DATA_CACHE_POLICY(x) ((x) << 25) + /* 0 - LRU + * 1 - Stream + */ +#define WRITE_DATA_ENGINE_SEL(x) ((x) << 30) + /* 0 - me + * 1 - pfp + * 2 - ce + */ + +#define PACKET3_ATOMIC_MEM 0x1E +#define TC_OP_ATOMIC_CMPSWAP_RTN_32 0x00000008 +#define ATOMIC_MEM_COMMAND(x) ((x) << 8) + /* 0 - single_pass_atomic. + * 1 - loop_until_compare_satisfied. + */ +#define ATOMIC_MEM_CACHEPOLICAY(x) ((x) << 25) + /* 0 - lru. + * 1 - stream. + */ +#define ATOMIC_MEM_ENGINESEL(x) ((x) << 30) + /* 0 - micro_engine. + */ + +#define PACKET3_DMA_DATA 0x50 +/* 1. header + * 2. CONTROL + * 3. SRC_ADDR_LO or DATA [31:0] + * 4. SRC_ADDR_HI [31:0] + * 5. DST_ADDR_LO [31:0] + * 6. DST_ADDR_HI [7:0] + * 7. COMMAND [30:21] | BYTE_COUNT [20:0] + */ +/* CONTROL */ +# define PACKET3_DMA_DATA_ENGINE(x) ((x) << 0) + /* 0 - ME + * 1 - PFP + */ +# define PACKET3_DMA_DATA_SRC_CACHE_POLICY(x) ((x) << 13) + /* 0 - LRU + * 1 - Stream + * 2 - Bypass + */ +# define PACKET3_DMA_DATA_SRC_VOLATILE (1 << 15) +# define PACKET3_DMA_DATA_DST_SEL(x) ((x) << 20) + /* 0 - DST_ADDR using DAS + * 1 - GDS + * 3 - DST_ADDR using L2 + */ +# define PACKET3_DMA_DATA_DST_CACHE_POLICY(x) ((x) << 25) + /* 0 - LRU + * 1 - Stream + * 2 - Bypass + */ +# define PACKET3_DMA_DATA_DST_VOLATILE (1 << 27) +# define PACKET3_DMA_DATA_SRC_SEL(x) ((x) << 29) + /* 0 - SRC_ADDR using SAS + * 1 - GDS + * 2 - DATA + * 3 - SRC_ADDR using L2 + */ +# define PACKET3_DMA_DATA_CP_SYNC (1 << 31) +/* COMMAND */ +# define PACKET3_DMA_DATA_DIS_WC (1 << 21) +# define PACKET3_DMA_DATA_CMD_SRC_SWAP(x) ((x) << 22) + /* 0 - none + * 1 - 8 in 16 + * 2 - 8 in 32 + * 3 - 8 in 64 + */ +# define PACKET3_DMA_DATA_CMD_DST_SWAP(x) ((x) << 24) + /* 0 - none + * 1 - 8 in 16 + * 2 - 8 in 32 + * 3 - 8 in 64 + */ +# define PACKET3_DMA_DATA_CMD_SAS (1 << 26) + /* 0 - memory + * 1 - register + */ +# define PACKET3_DMA_DATA_CMD_DAS (1 << 27) + /* 0 - memory + * 1 - register + */ +# define PACKET3_DMA_DATA_CMD_SAIC (1 << 28) +# define PACKET3_DMA_DATA_CMD_DAIC (1 << 29) +# define PACKET3_DMA_DATA_CMD_RAW_WAIT (1 << 30) + +#define SDMA_PACKET_SI(op, b, t, s, cnt) ((((op) & 0xF) << 28) | \ + (((b) & 0x1) << 26) | \ + (((t) & 0x1) << 23) | \ + (((s) & 0x1) << 22) | \ + (((cnt) & 0xFFFFF) << 0)) +#define SDMA_OPCODE_COPY_SI 3 +#define SDMA_OPCODE_CONSTANT_FILL_SI 13 +#define SDMA_NOP_SI 0xf +#define GFX_COMPUTE_NOP_SI 0x80000000 +#define PACKET3_DMA_DATA_SI 0x41 +# define PACKET3_DMA_DATA_SI_ENGINE(x) ((x) << 27) + /* 0 - ME + * 1 - PFP + */ +# define PACKET3_DMA_DATA_SI_DST_SEL(x) ((x) << 20) + /* 0 - DST_ADDR using DAS + * 1 - GDS + * 3 - DST_ADDR using L2 + */ +# define PACKET3_DMA_DATA_SI_SRC_SEL(x) ((x) << 29) + /* 0 - SRC_ADDR using SAS + * 1 - GDS + * 2 - DATA + * 3 - SRC_ADDR using L2 + */ +# define PACKET3_DMA_DATA_SI_CP_SYNC (1 << 31) + + +#define PKT3_CONTEXT_CONTROL 0x28 +#define CONTEXT_CONTROL_LOAD_ENABLE(x) (((unsigned)(x) & 0x1) << 31) +#define CONTEXT_CONTROL_LOAD_CE_RAM(x) (((unsigned)(x) & 0x1) << 28) +#define CONTEXT_CONTROL_SHADOW_ENABLE(x) (((unsigned)(x) & 0x1) << 31) + +#define PKT3_CLEAR_STATE 0x12 + +#define PKT3_SET_SH_REG 0x76 +#define PACKET3_SET_SH_REG_START 0x00002c00 + +#define PKT3_SET_SH_REG_INDEX 0x9B + +#define PACKET3_DISPATCH_DIRECT 0x15 +#define PACKET3_EVENT_WRITE 0x46 +#define PACKET3_ACQUIRE_MEM 0x58 +#define PACKET3_SET_CONTEXT_REG 0x69 +#define PACKET3_SET_UCONFIG_REG 0x79 +#define PACKET3_DRAW_INDEX_AUTO 0x2D +/* gfx 8 */ +#define mmCOMPUTE_PGM_LO 0x2e0c +#define mmCOMPUTE_PGM_RSRC1 0x2e12 +#define mmCOMPUTE_TMPRING_SIZE 0x2e18 +#define mmCOMPUTE_USER_DATA_0 0x2e40 +#define mmCOMPUTE_USER_DATA_1 0x2e41 +#define mmCOMPUTE_RESOURCE_LIMITS 0x2e15 +#define mmCOMPUTE_NUM_THREAD_X 0x2e07 + + + +#define SWAP_32(num) (((num & 0xff000000) >> 24) | \ + ((num & 0x0000ff00) << 8) | \ + ((num & 0x00ff0000) >> 8) | \ + ((num & 0x000000ff) << 24)) + + +/* Shader code + * void main() +{ + + float x = some_input; + for (unsigned i = 0; i < 1000000; i++) + x = sin(x); + + u[0] = 42u; +} +*/ + +static uint32_t shader_bin[] = { + SWAP_32(0x800082be), SWAP_32(0x02ff08bf), SWAP_32(0x7f969800), SWAP_32(0x040085bf), + SWAP_32(0x02810281), SWAP_32(0x02ff08bf), SWAP_32(0x7f969800), SWAP_32(0xfcff84bf), + SWAP_32(0xff0083be), SWAP_32(0x00f00000), SWAP_32(0xc10082be), SWAP_32(0xaa02007e), + SWAP_32(0x000070e0), SWAP_32(0x00000080), SWAP_32(0x000081bf) +}; + +#define CODE_OFFSET 512 +#define DATA_OFFSET 1024 + +enum cs_type { + CS_BUFFERCLEAR, + CS_BUFFERCOPY, + CS_HANG, + CS_HANG_SLOW +}; + +static const uint32_t bufferclear_cs_shader_gfx9[] = { + 0x260000ff, 0x000003ff, 0xd1fd0000, 0x04010c08, + 0x7e020280, 0x7e040204, 0x7e060205, 0x7e080206, + 0x7e0a0207, 0xe01c2000, 0x80000200, 0xbf8c0000, + 0xbf810000 +}; + +static const uint32_t bufferclear_cs_shader_gfx10[] = { + 0xD7460004, 0x04010C08, 0x7E000204, 0x7E020205, + 0x7E040206, 0x7E060207, 0xE01C2000, 0x80000004, + 0xBF810000 +}; + +static const uint32_t bufferclear_cs_shader_registers_gfx9[][2] = { + {0x2e12, 0x000C0041}, //{ mmCOMPUTE_PGM_RSRC1, 0x000C0041 }, + {0x2e13, 0x00000090}, //{ mmCOMPUTE_PGM_RSRC2, 0x00000090 }, + {0x2e07, 0x00000040}, //{ mmCOMPUTE_NUM_THREAD_X, 0x00000040 }, + {0x2e08, 0x00000001}, //{ mmCOMPUTE_NUM_THREAD_Y, 0x00000001 }, + {0x2e09, 0x00000001}, //{ mmCOMPUTE_NUM_THREAD_Z, 0x00000001 } +}; + +static const uint32_t bufferclear_cs_shader_registers_num_gfx9 = 5; + +static const uint32_t buffercopy_cs_shader_gfx9[] = { + 0x260000ff, 0x000003ff, 0xd1fd0000, 0x04010c08, + 0x7e020280, 0xe00c2000, 0x80000200, 0xbf8c0f70, + 0xe01c2000, 0x80010200, 0xbf810000 +}; + +static const uint32_t buffercopy_cs_shader_gfx10[] = { + 0xD7460001, 0x04010C08, 0xE00C2000, 0x80000201, + 0xBF8C3F70, 0xE01C2000, 0x80010201, 0xBF810000 +}; + +static const uint32_t preamblecache_gfx9[] = { + 0xc0026900, 0x81, 0x80000000, 0x40004000, 0xc0026900, 0x8c, 0xaa99aaaa, 0x0, + 0xc0026900, 0x90, 0x80000000, 0x40004000, 0xc0026900, 0x94, 0x80000000, 0x40004000, + 0xc0026900, 0xb4, 0x0, 0x3f800000, 0xc0016900, 0x103, 0x0, + 0xc0016900, 0x208, 0x0, 0xc0016900, 0x290, 0x0, + 0xc0016900, 0x2a1, 0x0, 0xc0026900, 0x2ad, 0x0, 0x0, + 0xc0016900, 0x2d5, 0x10000, 0xc0016900, 0x2dc, 0x0, + 0xc0066900, 0x2de, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0026900, 0x2e5, 0x0, 0x0, + 0xc0056900, 0x2f9, 0x5, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, + 0xc0036900, 0x311, 0x3, 0, 0x100000, 0xc0026900, 0x316, 0x1e, 0x20, + 0xc0016900, 0x349, 0x0, 0xc0016900, 0x358, 0x0, 0xc0016900, 0x367, 0x0, + 0xc0016900, 0x376, 0x0, 0xc0016900, 0x385, 0x0, 0xc0016900, 0x19, 0x0, + 0xc0056900, 0xe8, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xc0076900, 0x1e1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xc0026900, 0x204, 0x90000, 0x4, 0xc0046900, 0x20c, 0x0, 0x0, 0x0, 0x0, + 0xc0016900, 0x2b2, 0x0, 0xc0026900, 0x30e, 0xffffffff, 0xffffffff, + 0xc0016900, 0x314, 0x0, 0xc0016900, 0x2a6, 0, 0xc0016900, 0x210, 0, + 0xc0002f00, 0x1, 0xc0016900, 0x1, 0x1, + 0xc0016900, 0x18, 0x2, 0xc0016900, 0x206, 0x300, 0xc0017900, 0x20000243, 0x0, + 0xc0017900, 0x248, 0xffffffff, 0xc0017900, 0x249, 0x0, 0xc0017900, 0x24a, 0x0, + 0xc0017900, 0x24b, 0x0 +}; + +static const uint32_t preamblecache_gfx10[] = { + 0xc0026900, 0x81, 0x80000000, 0x40004000, 0xc0026900, 0x8c, 0xaa99aaaa, 0x0, + 0xc0026900, 0x90, 0x80000000, 0x40004000, 0xc0026900, 0x94, 0x80000000, 0x40004000, + 0xc0026900, 0xb4, 0x0, 0x3f800000, 0xc0016900, 0x103, 0x0, + 0xc0016900, 0x208, 0x0, 0xc0016900, 0x290, 0x0, + 0xc0016900, 0x2a1, 0x0, 0xc0026900, 0x2ad, 0x0, 0x0, + 0xc0016900, 0x2d5, 0x10000, 0xc0016900, 0x2dc, 0x0, + 0xc0066900, 0x2de, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0026900, 0x2e5, 0x0, 0x0, + 0xc0056900, 0x2f9, 0x5, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, + 0xc0046900, 0x310, 0, 0x3, 0, 0x100000, 0xc0026900, 0x316, 0xe, 0x20, + 0xc0016900, 0x349, 0x0, 0xc0016900, 0x358, 0x0, 0xc0016900, 0x367, 0x0, + 0xc0016900, 0x376, 0x0, 0xc0016900, 0x385, 0x0, 0xc0016900, 0x6, 0x0, + 0xc0056900, 0xe8, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xc0076900, 0x1e1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xc0026900, 0x204, 0x90000, 0x4, 0xc0046900, 0x20c, 0x0, 0x0, 0x0, 0x0, + 0xc0016900, 0x2b2, 0x0, 0xc0026900, 0x30e, 0xffffffff, 0xffffffff, + 0xc0016900, 0x314, 0x0, 0xc0016900, 0x10a, 0, 0xc0016900, 0x2a6, 0, 0xc0016900, 0x210, 0, + 0xc0016900, 0x2db, 0, 0xc0016900, 0x1d4, 0, 0xc0002f00, 0x1, 0xc0016900, 0x1, 0x1, 0xc0016900, 0xe, 0x2, + 0xc0016900, 0x206, 0x300, 0xc0016900, 0x212, 0x200, 0xc0017900, 0x7b, 0x20, 0xc0017a00, 0x20000243, 0x0, + 0xc0017900, 0x249, 0, 0xc0017900, 0x24a, 0, 0xc0017900, 0x24b, 0, 0xc0017900, 0x259, 0xffffffff, + 0xc0017900, 0x25f, 0, 0xc0017900, 0x260, 0, 0xc0017900, 0x262, 0, + 0xc0017600, 0x45, 0x0, 0xc0017600, 0x6, 0x0, + 0xc0067600, 0x70, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xc0067600, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 +}; + +enum ps_type { + PS_CONST, + PS_TEX, + PS_HANG, + PS_HANG_SLOW +}; + +static const uint32_t ps_const_shader_gfx9[] = { + 0x7E000200, 0x7E020201, 0x7E040202, 0x7E060203, + 0xD2960000, 0x00020300, 0xD2960001, 0x00020702, + 0xC4001C0F, 0x00000100, 0xBF810000 +}; + +static const uint32_t ps_const_shader_patchinfo_code_size_gfx9 = 6; + +static const uint32_t ps_const_shader_patchinfo_code_gfx9[][10][6] = { + {{ 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xC4001890, 0x00000000 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xC4001801, 0x00000000 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xC4001803, 0x00000100 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xC4001803, 0x00000300 }, + { 0xD2960000, 0x00020300, 0xD2960001, 0x00020702, 0xC4001C0F, 0x00000100 }, + { 0xD2950000, 0x00020300, 0xD2950001, 0x00020702, 0xC4001C0F, 0x00000100 }, + { 0xD2940000, 0x00020300, 0xD2940001, 0x00020702, 0xC4001C0F, 0x00000100 }, + { 0xD2970000, 0x00020300, 0xD2970001, 0x00020702, 0xC4001C0F, 0x00000100 }, + { 0xD2980000, 0x00020300, 0xD2980001, 0x00020702, 0xC4001C0F, 0x00000100 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xC400180F, 0x03020100 } + } +}; + +static const uint32_t ps_const_shader_patchinfo_offset_gfx9[] = { + 0x00000004 +}; + +static const uint32_t ps_num_sh_registers_gfx9 = 2; + +static const uint32_t ps_const_sh_registers_gfx9[][2] = { + {0x2C0A, 0x000C0040},//{ mmSPI_SHADER_PGM_RSRC1_PS, 0x000C0040 }, + {0x2C0B, 0x00000008}, //{ mmSPI_SHADER_PGM_RSRC2_PS, 0x00000008 } +}; + +static const uint32_t ps_num_context_registers_gfx9 = 7; + +static const uint32_t ps_const_context_reg_gfx9[][2] = { + {0xA1B4, 0x00000002}, //{ mmSPI_PS_INPUT_ADDR, 0x00000002 }, + {0xA1B6, 0x00000000}, //{ mmSPI_PS_IN_CONTROL, 0x00000000 }, + {0xA08F, 0x0000000F}, //{ mmCB_SHADER_MASK, 0x0000000F }, + {0xA203, 0x00000010}, //{ mmDB_SHADER_CONTROL, 0x00000010 }, + {0xA1C4, 0x00000000}, //{ mmSPI_SHADER_Z_FORMAT, 0x00000000 }, + {0xA1B8, 0x00000000}, //{ mmSPI_BARYC_CNTL, 0x00000000 /* Always 0 for now */}, + {0xA1C5, 0x00000004}, //{ mmSPI_SHADER_COL_FORMAT, 0x00000004 } +}; + +static const uint32_t ps_const_shader_gfx10[] = { + 0x7E000200, 0x7E020201, 0x7E040202, 0x7E060203, + 0x5E000300, 0x5E020702, 0xBF800000, 0xBF800000, + 0xF8001C0F, 0x00000100, 0xBF810000 +}; + +static const uint32_t ps_const_shader_patchinfo_code_size_gfx10 = 6; + +static const uint32_t ps_const_shader_patchinfo_code_gfx10[][10][6] = { + {{ 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8001890, 0x00000000 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8001801, 0x00000000 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8001803, 0x00000100 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8001803, 0x00000300 }, + { 0x5E000300, 0x5E020702, 0xBF800000, 0xBF800000, 0xF8001C0F, 0x00000100 }, + { 0xD7690000, 0x00020300, 0xD7690001, 0x00020702, 0xF8001C0F, 0x00000100 }, + { 0xD7680000, 0x00020300, 0xD7680001, 0x00020702, 0xF8001C0F, 0x00000100 }, + { 0xD76A0000, 0x00020300, 0xD76A0001, 0x00020702, 0xF8001C0F, 0x00000100 }, + { 0xD76B0000, 0x00020300, 0xD76B0001, 0x00020702, 0xF8001C0F, 0x00000100 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF800180F, 0x03020100 } + } +}; + +static const uint32_t ps_const_shader_patchinfo_offset_gfx10[] = { + 0x00000004 +}; + +static const uint32_t ps_num_sh_registers_gfx10 = 2; + +static const uint32_t ps_const_sh_registers_gfx10[][2] = { + {0x2C0A, 0x000C0000},//{ mmSPI_SHADER_PGM_RSRC1_PS, 0x000C0000 }, + {0x2C0B, 0x00000008}, //{ mmSPI_SHADER_PGM_RSRC2_PS, 0x00000008 } +}; + +static const uint32_t ps_tex_shader_gfx9[] = { + 0xBEFC000C, 0xBE8E017E, 0xBEFE077E, 0xD4180000, + 0xD4190001, 0xD41C0100, 0xD41D0101, 0xF0800F00, + 0x00400206, 0xBEFE010E, 0xBF8C0F70, 0xD2960000, + 0x00020702, 0xD2960001, 0x00020B04, 0xC4001C0F, + 0x00000100, 0xBF810000 +}; + +static const uint32_t ps_tex_shader_patchinfo_offset_gfx9[] = { + 0x0000000B +}; + +static const uint32_t ps_tex_shader_patchinfo_code_size_gfx9 = 6; + +static const uint32_t ps_tex_shader_patchinfo_code_gfx9[][10][6] = { + {{ 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xC4001890, 0x00000000 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xC4001801, 0x00000002 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xC4001803, 0x00000302 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xC4001803, 0x00000502 }, + { 0xD2960000, 0x00020702, 0xD2960001, 0x00020B04, 0xC4001C0F, 0x00000100 }, + { 0xD2950000, 0x00020702, 0xD2950001, 0x00020B04, 0xC4001C0F, 0x00000100 }, + { 0xD2940000, 0x00020702, 0xD2940001, 0x00020B04, 0xC4001C0F, 0x00000100 }, + { 0xD2970000, 0x00020702, 0xD2970001, 0x00020B04, 0xC4001C0F, 0x00000100 }, + { 0xD2980000, 0x00020702, 0xD2980001, 0x00020B04, 0xC4001C0F, 0x00000100 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xC400180F, 0x05040302 } + } +}; + +static const uint32_t ps_tex_sh_registers_gfx9[][2] = { + {0x2C0A, 0x000C0081},//{ mmSPI_SHADER_PGM_RSRC1_PS, 0x000C0081 }, + {0x2C0B, 0x00000018}, //{ mmSPI_SHADER_PGM_RSRC2_PS, 0x00000018 } +}; + +static const uint32_t ps_tex_context_reg_gfx9[][2] = { + {0xA1B4, 0x00000002}, //{ mmSPI_PS_INPUT_ADDR, 0x00000002 }, + {0xA1B6, 0x00000001}, //{ mmSPI_PS_IN_CONTROL, 0x00000001 }, + {0xA08F, 0x0000000F}, //{ mmCB_SHADER_MASK, 0x0000000F }, + {0xA203, 0x00000010}, //{ mmDB_SHADER_CONTROL, 0x00000010 }, + {0xA1C4, 0x00000000}, //{ mmSPI_SHADER_Z_FORMAT, 0x00000000 }, + {0xA1B8, 0x00000000}, //{ mmSPI_BARYC_CNTL, 0x00000000 /* Always 0 for now */}, + {0xA1C5, 0x00000004}, //{ mmSPI_SHADER_COL_FORMAT, 0x00000004 } +}; + +static const uint32_t ps_tex_shader_gfx10[] = { + 0xBEFC030C, 0xBE8E047E, 0xBEFE0A7E, 0xC8080000, + 0xC80C0100, 0xC8090001, 0xC80D0101, 0xF0800F0A, + 0x00400402, 0x00000003, 0xBEFE040E, 0xBF8C0F70, + 0x5E000B04, 0x5E020F06, 0xBF800000, 0xBF800000, + 0xF8001C0F, 0x00000100, 0xBF810000 +}; + +static const uint32_t ps_tex_shader_patchinfo_offset_gfx10[] = { + 0x0000000C +}; + +static const uint32_t ps_tex_shader_patchinfo_code_size_gfx10 = 6; + +static const uint32_t ps_tex_shader_patchinfo_code_gfx10[][10][6] = { + {{ 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8001890, 0x00000000 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8001801, 0x00000004 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8001803, 0x00000504 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8001803, 0x00000704 }, + { 0x5E000B04, 0x5E020F06, 0xBF800000, 0xBF800000, 0xF8001C0F, 0x00000100 }, + { 0xD7690000, 0x00020B04, 0xD7690001, 0x00020F06, 0xF8001C0F, 0x00000100 }, + { 0xD7680000, 0x00020B04, 0xD7680001, 0x00020F06, 0xF8001C0F, 0x00000100 }, + { 0xD76A0000, 0x00020B04, 0xD76A0001, 0x00020F06, 0xF8001C0F, 0x00000100 }, + { 0xD76B0000, 0x00020B04, 0xD76B0001, 0x00020F06, 0xF8001C0F, 0x00000100 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF800180F, 0x07060504 } + } +}; + +static const uint32_t vs_RectPosTexFast_shader_gfx9[] = { + 0x7E000B00, 0x020000F3, 0xD042000A, 0x00010100, + 0x7E020202, 0x7E040200, 0x020000F3, 0x7E060206, + 0x7E080204, 0xD1000001, 0x002A0302, 0x7C840080, + 0x7E000200, 0x7E040203, 0x7E0A0201, 0xD1000003, + 0x002A0704, 0x7E0C0207, 0x7E0E0205, 0x00000101, + 0x00020505, 0x7E040208, 0x7E0A02F2, 0x00060903, + 0x00080D07, 0x7E0C0209, 0xC40008CF, 0x05020100, + 0xC400020F, 0x05060403, 0xBF810000 +}; + +static const uint32_t vs_RectPosTexFast_shader_gfx10[] = { + 0x7E000B00, 0x060000F3, 0x7E020202, 0x7E040206, + 0x7C040080, 0x060000F3, 0xD5010001, 0x01AA0200, + 0x7E060203, 0xD5010002, 0x01AA0404, 0x7E080207, + 0x7C040080, 0xD5010000, 0x01A80101, 0xD5010001, + 0x01AA0601, 0x7E060208, 0x7E0A02F2, 0xD5010002, + 0x01A80902, 0xD5010004, 0x01AA0805, 0x7E0C0209, + 0xF80008CF, 0x05030100, 0xF800020F, 0x05060402, + 0xBF810000 +}; + +static const uint32_t cached_cmd_gfx9[] = { + 0xc0016900, 0x0, 0x0, 0xc0026900, 0x3, 0x2a, 0x0, + 0xc0046900, 0xa, 0x0, 0x0, 0x0, 0x200020, + 0xc0016900, 0x83, 0xffff, 0xc0026900, 0x8e, 0xf, 0xf, + 0xc0056900, 0x105, 0x0, 0x0, 0x0, 0x0, 0x12, + 0xc0026900, 0x10b, 0x0, 0x0, 0xc0016900, 0x1e0, 0x0, + 0xc0036900, 0x200, 0x0, 0x10000, 0xcc0011, + 0xc0026900, 0x292, 0x20, 0x60201b8, + 0xc0026900, 0x2b0, 0x0, 0x0, 0xc0016900, 0x2f8, 0x0 +}; + +static const uint32_t cached_cmd_gfx10[] = { + 0xc0016900, 0x0, 0x0, 0xc0026900, 0x3, 0x2a, 0x0, + 0xc0046900, 0xa, 0x0, 0x0, 0x0, 0x200020, + 0xc0016900, 0x83, 0xffff, 0xc0026900, 0x8e, 0xf, 0xf, + 0xc0056900, 0x105, 0x0, 0x0, 0x0, 0x0, 0x18, + 0xc0026900, 0x10b, 0x0, 0x0, 0xc0016900, 0x1e0, 0x0, + 0xc0036900, 0x200, 0x0, 0x10000, 0xcc0011, + 0xc0026900, 0x292, 0x20, 0x6020000, + 0xc0026900, 0x2b0, 0x0, 0x0, 0xc0016900, 0x2f8, 0x0 +}; + +unsigned int memcpy_ps_hang[] = { + 0xFFFFFFFF, 0xBEFE0A7E, 0xBEFC0304, 0xC0C20100, + 0xC0800300, 0xC8080000, 0xC80C0100, 0xC8090001, + 0xC80D0101, 0xBF8C007F, 0xF0800F00, 0x00010002, + 0xBEFE040C, 0xBF8C0F70, 0xBF800000, 0xBF800000, + 0xF800180F, 0x03020100, 0xBF810000 +}; + +struct amdgpu_test_shader { + uint32_t *shader; + uint32_t header_length; + uint32_t body_length; + uint32_t foot_length; +}; + +unsigned int memcpy_cs_hang_slow_ai_codes[] = { + 0xd1fd0000, 0x04010c08, 0xe00c2000, 0x80000100, + 0xbf8c0f70, 0xe01c2000, 0x80010100, 0xbf810000 +}; + +struct amdgpu_test_shader memcpy_cs_hang_slow_ai = { + memcpy_cs_hang_slow_ai_codes, + 4, + 3, + 1 +}; + +unsigned int memcpy_cs_hang_slow_rv_codes[] = { + 0x8e00860c, 0x32000000, 0xe00c2000, 0x80010100, + 0xbf8c0f70, 0xe01c2000, 0x80020100, 0xbf810000 +}; + +struct amdgpu_test_shader memcpy_cs_hang_slow_rv = { + memcpy_cs_hang_slow_rv_codes, + 4, + 3, + 1 +}; + +unsigned int memcpy_cs_hang_slow_nv_codes[] = { + 0xd7460000, 0x04010c08, 0xe00c2000, 0x80000100, + 0xbf8c0f70, 0xe01ca000, 0x80010100, 0xbf810000 +}; + +struct amdgpu_test_shader memcpy_cs_hang_slow_nv = { + memcpy_cs_hang_slow_nv_codes, + 4, + 3, + 1 +}; + +unsigned int memcpy_ps_hang_slow_ai_codes[] = { + 0xbefc000c, 0xbe8e017e, 0xbefe077e, 0xd4080000, + 0xd4090001, 0xd40c0100, 0xd40d0101, 0xf0800f00, + 0x00400002, 0xbefe010e, 0xbf8c0f70, 0xbf800000, + 0xbf800000, 0xbf800000, 0xbf800000, 0xc400180f, + 0x03020100, 0xbf810000 +}; + +struct amdgpu_test_shader memcpy_ps_hang_slow_ai = { + memcpy_ps_hang_slow_ai_codes, + 7, + 2, + 9 +}; + +int amdgpu_bo_alloc_and_map_raw(amdgpu_device_handle dev, unsigned size, + unsigned alignment, unsigned heap, uint64_t alloc_flags, + uint64_t mapping_flags, amdgpu_bo_handle *bo, void **cpu, + uint64_t *mc_address, + amdgpu_va_handle *va_handle) +{ + struct amdgpu_bo_alloc_request request = {}; + amdgpu_bo_handle buf_handle; + amdgpu_va_handle handle; + uint64_t vmc_addr; + int r; + + request.alloc_size = size; + request.phys_alignment = alignment; + request.preferred_heap = heap; + request.flags = alloc_flags; + + r = amdgpu_bo_alloc(dev, &request, &buf_handle); + if (r) + return r; + + r = amdgpu_va_range_alloc(dev, + amdgpu_gpu_va_range_general, + size, alignment, 0, &vmc_addr, + &handle, 0); + if (r) + goto error_va_alloc; + + r = amdgpu_bo_va_op_raw(dev, buf_handle, 0, ALIGN(size, getpagesize()), vmc_addr, + AMDGPU_VM_PAGE_READABLE | + AMDGPU_VM_PAGE_WRITEABLE | + AMDGPU_VM_PAGE_EXECUTABLE | + mapping_flags, + AMDGPU_VA_OP_MAP); + if (r) + goto error_va_map; + + r = amdgpu_bo_cpu_map(buf_handle, cpu); + if (r) + goto error_cpu_map; + + *bo = buf_handle; + *mc_address = vmc_addr; + *va_handle = handle; + + return 0; + + error_cpu_map: + amdgpu_bo_cpu_unmap(buf_handle); + + error_va_map: + amdgpu_bo_va_op(buf_handle, 0, size, vmc_addr, 0, AMDGPU_VA_OP_UNMAP); + + error_va_alloc: + amdgpu_bo_free(buf_handle); + return r; +} + + + +CU_BOOL suite_basic_tests_enable(void) +{ + + if (amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle)) + return CU_FALSE; + + + family_id = device_handle->info.family_id; + chip_id = device_handle->info.chip_external_rev; + chip_rev = device_handle->info.chip_rev; + + if (amdgpu_device_deinitialize(device_handle)) + return CU_FALSE; + + /* disable gfx engine basic test cases for some asics have no CPG */ + if (asic_is_gfx_pipe_removed(family_id, chip_id, chip_rev)) { + if (amdgpu_set_test_active("Basic Tests", + "Command submission Test (GFX)", + CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", + CU_get_error_msg()); + + if (amdgpu_set_test_active("Basic Tests", + "Command submission Test (Multi-Fence)", + CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", + CU_get_error_msg()); + + if (amdgpu_set_test_active("Basic Tests", + "Sync dependency Test", + CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", + CU_get_error_msg()); + } + + return CU_TRUE; +} + +int suite_basic_tests_init(void) +{ + struct amdgpu_gpu_info gpu_info = {0}; + int r; + + r = amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle); + + if (r) { + if ((r == -EACCES) && (errno == EACCES)) + printf("\n\nError:%s. " + "Hint:Try to run this test program as root.", + strerror(errno)); + return CUE_SINIT_FAILED; + } + + r = amdgpu_query_gpu_info(device_handle, &gpu_info); + if (r) + return CUE_SINIT_FAILED; + + family_id = gpu_info.family_id; + + return CUE_SUCCESS; +} + +int suite_basic_tests_clean(void) +{ + int r = amdgpu_device_deinitialize(device_handle); + + if (r == 0) + return CUE_SUCCESS; + else + return CUE_SCLEAN_FAILED; +} + +static void amdgpu_query_info_test(void) +{ + struct amdgpu_gpu_info gpu_info = {0}; + uint32_t version, feature; + int r; + + r = amdgpu_query_gpu_info(device_handle, &gpu_info); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_query_firmware_version(device_handle, AMDGPU_INFO_FW_VCE, 0, + 0, &version, &feature); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_command_submission_gfx_separate_ibs(void) +{ + amdgpu_context_handle context_handle; + amdgpu_bo_handle ib_result_handle, ib_result_ce_handle; + void *ib_result_cpu, *ib_result_ce_cpu; + uint64_t ib_result_mc_address, ib_result_ce_mc_address; + struct amdgpu_cs_request ibs_request = {0}; + struct amdgpu_cs_ib_info ib_info[2]; + struct amdgpu_cs_fence fence_status = {0}; + uint32_t *ptr; + uint32_t expired; + amdgpu_bo_list_handle bo_list; + amdgpu_va_handle va_handle, va_handle_ce; + int r, i = 0; + struct drm_amdgpu_info_hw_ip info; + + r = amdgpu_query_hw_ip_info(device_handle, AMDGPU_HW_IP_GFX, 0, &info); + CU_ASSERT_EQUAL(r, 0); + + if (info.hw_ip_version_major >= 11) + return; + + r = amdgpu_cs_ctx_create(device_handle, &context_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_alloc_and_map(device_handle, 4096, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, + &ib_result_handle, &ib_result_cpu, + &ib_result_mc_address, &va_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_alloc_and_map(device_handle, 4096, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, + &ib_result_ce_handle, &ib_result_ce_cpu, + &ib_result_ce_mc_address, &va_handle_ce); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_get_bo_list(device_handle, ib_result_handle, + ib_result_ce_handle, &bo_list); + CU_ASSERT_EQUAL(r, 0); + + memset(ib_info, 0, 2 * sizeof(struct amdgpu_cs_ib_info)); + + /* IT_SET_CE_DE_COUNTERS */ + ptr = ib_result_ce_cpu; + if (family_id != AMDGPU_FAMILY_SI) { + ptr[i++] = 0xc0008900; + ptr[i++] = 0; + } + ptr[i++] = 0xc0008400; + ptr[i++] = 1; + ib_info[0].ib_mc_address = ib_result_ce_mc_address; + ib_info[0].size = i; + ib_info[0].flags = AMDGPU_IB_FLAG_CE; + + /* IT_WAIT_ON_CE_COUNTER */ + ptr = ib_result_cpu; + ptr[0] = 0xc0008600; + ptr[1] = 0x00000001; + ib_info[1].ib_mc_address = ib_result_mc_address; + ib_info[1].size = 2; + + ibs_request.ip_type = AMDGPU_HW_IP_GFX; + ibs_request.number_of_ibs = 2; + ibs_request.ibs = ib_info; + ibs_request.resources = bo_list; + ibs_request.fence_info.handle = NULL; + + r = amdgpu_cs_submit(context_handle, 0,&ibs_request, 1); + + CU_ASSERT_EQUAL(r, 0); + + fence_status.context = context_handle; + fence_status.ip_type = AMDGPU_HW_IP_GFX; + fence_status.ip_instance = 0; + fence_status.fence = ibs_request.seq_no; + + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE, + 0, &expired); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_unmap_and_free(ib_result_handle, va_handle, + ib_result_mc_address, 4096); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_unmap_and_free(ib_result_ce_handle, va_handle_ce, + ib_result_ce_mc_address, 4096); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_list_destroy(bo_list); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); + +} + +static void amdgpu_command_submission_gfx_shared_ib(void) +{ + amdgpu_context_handle context_handle; + amdgpu_bo_handle ib_result_handle; + void *ib_result_cpu; + uint64_t ib_result_mc_address; + struct amdgpu_cs_request ibs_request = {0}; + struct amdgpu_cs_ib_info ib_info[2]; + struct amdgpu_cs_fence fence_status = {0}; + uint32_t *ptr; + uint32_t expired; + amdgpu_bo_list_handle bo_list; + amdgpu_va_handle va_handle; + int r, i = 0; + struct drm_amdgpu_info_hw_ip info; + + r = amdgpu_query_hw_ip_info(device_handle, AMDGPU_HW_IP_GFX, 0, &info); + CU_ASSERT_EQUAL(r, 0); + + if (info.hw_ip_version_major >= 11) + return; + + r = amdgpu_cs_ctx_create(device_handle, &context_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_alloc_and_map(device_handle, 4096, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, + &ib_result_handle, &ib_result_cpu, + &ib_result_mc_address, &va_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_get_bo_list(device_handle, ib_result_handle, NULL, + &bo_list); + CU_ASSERT_EQUAL(r, 0); + + memset(ib_info, 0, 2 * sizeof(struct amdgpu_cs_ib_info)); + + /* IT_SET_CE_DE_COUNTERS */ + ptr = ib_result_cpu; + if (family_id != AMDGPU_FAMILY_SI) { + ptr[i++] = 0xc0008900; + ptr[i++] = 0; + } + ptr[i++] = 0xc0008400; + ptr[i++] = 1; + ib_info[0].ib_mc_address = ib_result_mc_address; + ib_info[0].size = i; + ib_info[0].flags = AMDGPU_IB_FLAG_CE; + + ptr = (uint32_t *)ib_result_cpu + 4; + ptr[0] = 0xc0008600; + ptr[1] = 0x00000001; + ib_info[1].ib_mc_address = ib_result_mc_address + 16; + ib_info[1].size = 2; + + ibs_request.ip_type = AMDGPU_HW_IP_GFX; + ibs_request.number_of_ibs = 2; + ibs_request.ibs = ib_info; + ibs_request.resources = bo_list; + ibs_request.fence_info.handle = NULL; + + r = amdgpu_cs_submit(context_handle, 0, &ibs_request, 1); + + CU_ASSERT_EQUAL(r, 0); + + fence_status.context = context_handle; + fence_status.ip_type = AMDGPU_HW_IP_GFX; + fence_status.ip_instance = 0; + fence_status.fence = ibs_request.seq_no; + + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE, + 0, &expired); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_unmap_and_free(ib_result_handle, va_handle, + ib_result_mc_address, 4096); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_list_destroy(bo_list); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_command_submission_gfx_cp_write_data(void) +{ + amdgpu_command_submission_write_linear_helper(AMDGPU_HW_IP_GFX); +} + +static void amdgpu_command_submission_gfx_cp_const_fill(void) +{ + amdgpu_command_submission_const_fill_helper(AMDGPU_HW_IP_GFX); +} + +static void amdgpu_command_submission_gfx_cp_copy_data(void) +{ + amdgpu_command_submission_copy_linear_helper(AMDGPU_HW_IP_GFX); +} + +static void amdgpu_bo_eviction_test(void) +{ + const int sdma_write_length = 1024; + const int pm4_dw = 256; + amdgpu_context_handle context_handle; + amdgpu_bo_handle bo1, bo2, vram_max[2], gtt_max[2]; + amdgpu_bo_handle *resources; + uint32_t *pm4; + struct amdgpu_cs_ib_info *ib_info; + struct amdgpu_cs_request *ibs_request; + uint64_t bo1_mc, bo2_mc; + volatile unsigned char *bo1_cpu, *bo2_cpu; + int i, j, r, loop1, loop2; + uint64_t gtt_flags[2] = {0, AMDGPU_GEM_CREATE_CPU_GTT_USWC}; + amdgpu_va_handle bo1_va_handle, bo2_va_handle; + struct amdgpu_heap_info vram_info, gtt_info; + + pm4 = calloc(pm4_dw, sizeof(*pm4)); + CU_ASSERT_NOT_EQUAL(pm4, NULL); + + ib_info = calloc(1, sizeof(*ib_info)); + CU_ASSERT_NOT_EQUAL(ib_info, NULL); + + ibs_request = calloc(1, sizeof(*ibs_request)); + CU_ASSERT_NOT_EQUAL(ibs_request, NULL); + + r = amdgpu_cs_ctx_create(device_handle, &context_handle); + CU_ASSERT_EQUAL(r, 0); + + /* prepare resource */ + resources = calloc(4, sizeof(amdgpu_bo_handle)); + CU_ASSERT_NOT_EQUAL(resources, NULL); + + r = amdgpu_query_heap_info(device_handle, AMDGPU_GEM_DOMAIN_VRAM, + 0, &vram_info); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_alloc_wrap(device_handle, vram_info.max_allocation, 4096, + AMDGPU_GEM_DOMAIN_VRAM, 0, &vram_max[0]); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_bo_alloc_wrap(device_handle, vram_info.max_allocation, 4096, + AMDGPU_GEM_DOMAIN_VRAM, 0, &vram_max[1]); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_query_heap_info(device_handle, AMDGPU_GEM_DOMAIN_GTT, + 0, >t_info); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_alloc_wrap(device_handle, gtt_info.max_allocation, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, >t_max[0]); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_bo_alloc_wrap(device_handle, gtt_info.max_allocation, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, >t_max[1]); + CU_ASSERT_EQUAL(r, 0); + + + + loop1 = loop2 = 0; + /* run 9 circle to test all mapping combination */ + while(loop1 < 2) { + while(loop2 < 2) { + /* allocate UC bo1for sDMA use */ + r = amdgpu_bo_alloc_and_map(device_handle, + sdma_write_length, 4096, + AMDGPU_GEM_DOMAIN_GTT, + gtt_flags[loop1], &bo1, + (void**)&bo1_cpu, &bo1_mc, + &bo1_va_handle); + CU_ASSERT_EQUAL(r, 0); + + /* set bo1 */ + memset((void*)bo1_cpu, 0xaa, sdma_write_length); + + /* allocate UC bo2 for sDMA use */ + r = amdgpu_bo_alloc_and_map(device_handle, + sdma_write_length, 4096, + AMDGPU_GEM_DOMAIN_GTT, + gtt_flags[loop2], &bo2, + (void**)&bo2_cpu, &bo2_mc, + &bo2_va_handle); + CU_ASSERT_EQUAL(r, 0); + + /* clear bo2 */ + memset((void*)bo2_cpu, 0, sdma_write_length); + + resources[0] = bo1; + resources[1] = bo2; + resources[2] = vram_max[loop2]; + resources[3] = gtt_max[loop2]; + + /* fulfill PM4: test DMA copy linear */ + i = j = 0; + if (family_id == AMDGPU_FAMILY_SI) { + pm4[i++] = SDMA_PACKET_SI(SDMA_OPCODE_COPY_SI, 0, 0, 0, + sdma_write_length); + pm4[i++] = 0xffffffff & bo2_mc; + pm4[i++] = 0xffffffff & bo1_mc; + pm4[i++] = (0xffffffff00000000 & bo2_mc) >> 32; + pm4[i++] = (0xffffffff00000000 & bo1_mc) >> 32; + } else { + pm4[i++] = SDMA_PACKET(SDMA_OPCODE_COPY, SDMA_COPY_SUB_OPCODE_LINEAR, 0); + if (family_id >= AMDGPU_FAMILY_AI) + pm4[i++] = sdma_write_length - 1; + else + pm4[i++] = sdma_write_length; + pm4[i++] = 0; + pm4[i++] = 0xffffffff & bo1_mc; + pm4[i++] = (0xffffffff00000000 & bo1_mc) >> 32; + pm4[i++] = 0xffffffff & bo2_mc; + pm4[i++] = (0xffffffff00000000 & bo2_mc) >> 32; + } + + amdgpu_test_exec_cs_helper(context_handle, + AMDGPU_HW_IP_DMA, 0, + i, pm4, + 4, resources, + ib_info, ibs_request); + + /* verify if SDMA test result meets with expected */ + i = 0; + while(i < sdma_write_length) { + CU_ASSERT_EQUAL(bo2_cpu[i++], 0xaa); + } + r = amdgpu_bo_unmap_and_free(bo1, bo1_va_handle, bo1_mc, + sdma_write_length); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_bo_unmap_and_free(bo2, bo2_va_handle, bo2_mc, + sdma_write_length); + CU_ASSERT_EQUAL(r, 0); + loop2++; + } + loop2 = 0; + loop1++; + } + amdgpu_bo_free(vram_max[0]); + amdgpu_bo_free(vram_max[1]); + amdgpu_bo_free(gtt_max[0]); + amdgpu_bo_free(gtt_max[1]); + /* clean resources */ + free(resources); + free(ibs_request); + free(ib_info); + free(pm4); + + /* end of test */ + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); +} + + +static void amdgpu_command_submission_gfx(void) +{ + /* write data using the CP */ + amdgpu_command_submission_gfx_cp_write_data(); + /* const fill using the CP */ + amdgpu_command_submission_gfx_cp_const_fill(); + /* copy data using the CP */ + amdgpu_command_submission_gfx_cp_copy_data(); + /* separate IB buffers for multi-IB submission */ + amdgpu_command_submission_gfx_separate_ibs(); + /* shared IB buffer for multi-IB submission */ + amdgpu_command_submission_gfx_shared_ib(); +} + +static void amdgpu_semaphore_test(void) +{ + amdgpu_context_handle context_handle[2]; + amdgpu_semaphore_handle sem; + amdgpu_bo_handle ib_result_handle[2]; + void *ib_result_cpu[2]; + uint64_t ib_result_mc_address[2]; + struct amdgpu_cs_request ibs_request[2] = {0}; + struct amdgpu_cs_ib_info ib_info[2] = {0}; + struct amdgpu_cs_fence fence_status = {0}; + uint32_t *ptr; + uint32_t expired; + uint32_t sdma_nop, gfx_nop; + amdgpu_bo_list_handle bo_list[2]; + amdgpu_va_handle va_handle[2]; + int r, i; + struct amdgpu_gpu_info gpu_info = {0}; + unsigned gc_ip_type; + + r = amdgpu_query_gpu_info(device_handle, &gpu_info); + CU_ASSERT_EQUAL(r, 0); + + gc_ip_type = (asic_is_gfx_pipe_removed(family_id, chip_id, chip_rev)) ? + AMDGPU_HW_IP_COMPUTE : AMDGPU_HW_IP_GFX; + + if (family_id == AMDGPU_FAMILY_SI) { + sdma_nop = SDMA_PACKET_SI(SDMA_NOP_SI, 0, 0, 0, 0); + gfx_nop = GFX_COMPUTE_NOP_SI; + } else { + sdma_nop = SDMA_PKT_HEADER_OP(SDMA_NOP); + gfx_nop = GFX_COMPUTE_NOP; + } + + r = amdgpu_cs_create_semaphore(&sem); + CU_ASSERT_EQUAL(r, 0); + for (i = 0; i < 2; i++) { + r = amdgpu_cs_ctx_create(device_handle, &context_handle[i]); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_alloc_and_map(device_handle, 4096, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, + &ib_result_handle[i], &ib_result_cpu[i], + &ib_result_mc_address[i], &va_handle[i]); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_get_bo_list(device_handle, ib_result_handle[i], + NULL, &bo_list[i]); + CU_ASSERT_EQUAL(r, 0); + } + + /* 1. same context different engine */ + ptr = ib_result_cpu[0]; + ptr[0] = sdma_nop; + ib_info[0].ib_mc_address = ib_result_mc_address[0]; + ib_info[0].size = 1; + + ibs_request[0].ip_type = AMDGPU_HW_IP_DMA; + ibs_request[0].number_of_ibs = 1; + ibs_request[0].ibs = &ib_info[0]; + ibs_request[0].resources = bo_list[0]; + ibs_request[0].fence_info.handle = NULL; + r = amdgpu_cs_submit(context_handle[0], 0,&ibs_request[0], 1); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_cs_signal_semaphore(context_handle[0], AMDGPU_HW_IP_DMA, 0, 0, sem); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_wait_semaphore(context_handle[0], gc_ip_type, 0, 0, sem); + CU_ASSERT_EQUAL(r, 0); + ptr = ib_result_cpu[1]; + ptr[0] = gfx_nop; + ib_info[1].ib_mc_address = ib_result_mc_address[1]; + ib_info[1].size = 1; + + ibs_request[1].ip_type = gc_ip_type; + ibs_request[1].number_of_ibs = 1; + ibs_request[1].ibs = &ib_info[1]; + ibs_request[1].resources = bo_list[1]; + ibs_request[1].fence_info.handle = NULL; + + r = amdgpu_cs_submit(context_handle[0], 0,&ibs_request[1], 1); + CU_ASSERT_EQUAL(r, 0); + + fence_status.context = context_handle[0]; + fence_status.ip_type = gc_ip_type; + fence_status.ip_instance = 0; + fence_status.fence = ibs_request[1].seq_no; + r = amdgpu_cs_query_fence_status(&fence_status, + 500000000, 0, &expired); + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(expired, true); + + /* 2. same engine different context */ + ptr = ib_result_cpu[0]; + ptr[0] = gfx_nop; + ib_info[0].ib_mc_address = ib_result_mc_address[0]; + ib_info[0].size = 1; + + ibs_request[0].ip_type = gc_ip_type; + ibs_request[0].number_of_ibs = 1; + ibs_request[0].ibs = &ib_info[0]; + ibs_request[0].resources = bo_list[0]; + ibs_request[0].fence_info.handle = NULL; + r = amdgpu_cs_submit(context_handle[0], 0,&ibs_request[0], 1); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_cs_signal_semaphore(context_handle[0], gc_ip_type, 0, 0, sem); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_wait_semaphore(context_handle[1], gc_ip_type, 0, 0, sem); + CU_ASSERT_EQUAL(r, 0); + ptr = ib_result_cpu[1]; + ptr[0] = gfx_nop; + ib_info[1].ib_mc_address = ib_result_mc_address[1]; + ib_info[1].size = 1; + + ibs_request[1].ip_type = gc_ip_type; + ibs_request[1].number_of_ibs = 1; + ibs_request[1].ibs = &ib_info[1]; + ibs_request[1].resources = bo_list[1]; + ibs_request[1].fence_info.handle = NULL; + r = amdgpu_cs_submit(context_handle[1], 0,&ibs_request[1], 1); + + CU_ASSERT_EQUAL(r, 0); + + fence_status.context = context_handle[1]; + fence_status.ip_type = gc_ip_type; + fence_status.ip_instance = 0; + fence_status.fence = ibs_request[1].seq_no; + r = amdgpu_cs_query_fence_status(&fence_status, + 500000000, 0, &expired); + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(expired, true); + + for (i = 0; i < 2; i++) { + r = amdgpu_bo_unmap_and_free(ib_result_handle[i], va_handle[i], + ib_result_mc_address[i], 4096); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_list_destroy(bo_list[i]); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_ctx_free(context_handle[i]); + CU_ASSERT_EQUAL(r, 0); + } + + r = amdgpu_cs_destroy_semaphore(sem); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_command_submission_compute_nop(void) +{ + amdgpu_context_handle context_handle; + amdgpu_bo_handle ib_result_handle; + void *ib_result_cpu; + uint64_t ib_result_mc_address; + struct amdgpu_cs_request ibs_request; + struct amdgpu_cs_ib_info ib_info; + struct amdgpu_cs_fence fence_status; + uint32_t *ptr; + uint32_t expired; + int r, instance; + amdgpu_bo_list_handle bo_list; + amdgpu_va_handle va_handle; + struct drm_amdgpu_info_hw_ip info; + + r = amdgpu_query_hw_ip_info(device_handle, AMDGPU_HW_IP_COMPUTE, 0, &info); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_ctx_create(device_handle, &context_handle); + CU_ASSERT_EQUAL(r, 0); + + for (instance = 0; (1 << instance) & info.available_rings; instance++) { + r = amdgpu_bo_alloc_and_map(device_handle, 4096, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, + &ib_result_handle, &ib_result_cpu, + &ib_result_mc_address, &va_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_get_bo_list(device_handle, ib_result_handle, NULL, + &bo_list); + CU_ASSERT_EQUAL(r, 0); + + ptr = ib_result_cpu; + memset(ptr, 0, 16); + ptr[0]=PACKET3(PACKET3_NOP, 14); + + memset(&ib_info, 0, sizeof(struct amdgpu_cs_ib_info)); + ib_info.ib_mc_address = ib_result_mc_address; + ib_info.size = 16; + + memset(&ibs_request, 0, sizeof(struct amdgpu_cs_request)); + ibs_request.ip_type = AMDGPU_HW_IP_COMPUTE; + ibs_request.ring = instance; + ibs_request.number_of_ibs = 1; + ibs_request.ibs = &ib_info; + ibs_request.resources = bo_list; + ibs_request.fence_info.handle = NULL; + + memset(&fence_status, 0, sizeof(struct amdgpu_cs_fence)); + r = amdgpu_cs_submit(context_handle, 0,&ibs_request, 1); + CU_ASSERT_EQUAL(r, 0); + + fence_status.context = context_handle; + fence_status.ip_type = AMDGPU_HW_IP_COMPUTE; + fence_status.ip_instance = 0; + fence_status.ring = instance; + fence_status.fence = ibs_request.seq_no; + + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE, + 0, &expired); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_list_destroy(bo_list); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_unmap_and_free(ib_result_handle, va_handle, + ib_result_mc_address, 4096); + CU_ASSERT_EQUAL(r, 0); + } + + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_command_submission_compute_cp_write_data(void) +{ + amdgpu_command_submission_write_linear_helper(AMDGPU_HW_IP_COMPUTE); +} + +static void amdgpu_command_submission_compute_cp_const_fill(void) +{ + amdgpu_command_submission_const_fill_helper(AMDGPU_HW_IP_COMPUTE); +} + +static void amdgpu_command_submission_compute_cp_copy_data(void) +{ + amdgpu_command_submission_copy_linear_helper(AMDGPU_HW_IP_COMPUTE); +} + +static void amdgpu_command_submission_compute(void) +{ + /* write data using the CP */ + amdgpu_command_submission_compute_cp_write_data(); + /* const fill using the CP */ + amdgpu_command_submission_compute_cp_const_fill(); + /* copy data using the CP */ + amdgpu_command_submission_compute_cp_copy_data(); + /* nop test */ + amdgpu_command_submission_compute_nop(); +} + +/* + * caller need create/release: + * pm4_src, resources, ib_info, and ibs_request + * submit command stream described in ibs_request and wait for this IB accomplished + */ +void +amdgpu_test_exec_cs_helper_raw(amdgpu_device_handle device_handle, + amdgpu_context_handle context_handle, + unsigned ip_type, int instance, int pm4_dw, + uint32_t *pm4_src, int res_cnt, + amdgpu_bo_handle *resources, + struct amdgpu_cs_ib_info *ib_info, + struct amdgpu_cs_request *ibs_request, + bool secure) +{ + int r; + uint32_t expired; + uint32_t *ring_ptr; + amdgpu_bo_handle ib_result_handle; + void *ib_result_cpu; + uint64_t ib_result_mc_address; + struct amdgpu_cs_fence fence_status = {0}; + amdgpu_bo_handle *all_res = alloca(sizeof(resources[0]) * (res_cnt + 1)); + amdgpu_va_handle va_handle; + + /* prepare CS */ + CU_ASSERT_NOT_EQUAL(pm4_src, NULL); + CU_ASSERT_NOT_EQUAL(resources, NULL); + CU_ASSERT_NOT_EQUAL(ib_info, NULL); + CU_ASSERT_NOT_EQUAL(ibs_request, NULL); + CU_ASSERT_TRUE(pm4_dw <= 1024); + + /* allocate IB */ + r = amdgpu_bo_alloc_and_map(device_handle, 4096, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, + &ib_result_handle, &ib_result_cpu, + &ib_result_mc_address, &va_handle); + CU_ASSERT_EQUAL(r, 0); + + /* copy PM4 packet to ring from caller */ + ring_ptr = ib_result_cpu; + memcpy(ring_ptr, pm4_src, pm4_dw * sizeof(*pm4_src)); + + ib_info->ib_mc_address = ib_result_mc_address; + ib_info->size = pm4_dw; + if (secure) + ib_info->flags |= AMDGPU_IB_FLAGS_SECURE; + + ibs_request->ip_type = ip_type; + ibs_request->ring = instance; + ibs_request->number_of_ibs = 1; + ibs_request->ibs = ib_info; + ibs_request->fence_info.handle = NULL; + + memcpy(all_res, resources, sizeof(resources[0]) * res_cnt); + all_res[res_cnt] = ib_result_handle; + + r = amdgpu_bo_list_create(device_handle, res_cnt+1, all_res, + NULL, &ibs_request->resources); + CU_ASSERT_EQUAL(r, 0); + + CU_ASSERT_NOT_EQUAL(ibs_request, NULL); + + /* submit CS */ + r = amdgpu_cs_submit(context_handle, 0, ibs_request, 1); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_list_destroy(ibs_request->resources); + CU_ASSERT_EQUAL(r, 0); + + fence_status.ip_type = ip_type; + fence_status.ip_instance = 0; + fence_status.ring = ibs_request->ring; + fence_status.context = context_handle; + fence_status.fence = ibs_request->seq_no; + + /* wait for IB accomplished */ + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE, + 0, &expired); + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(expired, true); + + r = amdgpu_bo_unmap_and_free(ib_result_handle, va_handle, + ib_result_mc_address, 4096); + CU_ASSERT_EQUAL(r, 0); +} + +static void +amdgpu_test_exec_cs_helper(amdgpu_context_handle context_handle, + unsigned ip_type, int instance, int pm4_dw, + uint32_t *pm4_src, int res_cnt, + amdgpu_bo_handle *resources, + struct amdgpu_cs_ib_info *ib_info, + struct amdgpu_cs_request *ibs_request) +{ + amdgpu_test_exec_cs_helper_raw(device_handle, context_handle, + ip_type, instance, pm4_dw, pm4_src, + res_cnt, resources, ib_info, + ibs_request, false); +} + +void +amdgpu_command_submission_write_linear_helper_with_secure(amdgpu_device_handle + device, unsigned + ip_type, bool secure) +{ + const int sdma_write_length = 128; + const int pm4_dw = 256; + amdgpu_context_handle context_handle; + amdgpu_bo_handle bo; + amdgpu_bo_handle *resources; + uint32_t *pm4; + struct amdgpu_cs_ib_info *ib_info; + struct amdgpu_cs_request *ibs_request; + uint64_t bo_mc; + volatile uint32_t *bo_cpu; + uint32_t bo_cpu_origin; + int i, j, r, loop, ring_id; + uint64_t gtt_flags[2] = {0, AMDGPU_GEM_CREATE_CPU_GTT_USWC}; + amdgpu_va_handle va_handle; + struct drm_amdgpu_info_hw_ip hw_ip_info; + + pm4 = calloc(pm4_dw, sizeof(*pm4)); + CU_ASSERT_NOT_EQUAL(pm4, NULL); + + ib_info = calloc(1, sizeof(*ib_info)); + CU_ASSERT_NOT_EQUAL(ib_info, NULL); + + ibs_request = calloc(1, sizeof(*ibs_request)); + CU_ASSERT_NOT_EQUAL(ibs_request, NULL); + + r = amdgpu_query_hw_ip_info(device, ip_type, 0, &hw_ip_info); + CU_ASSERT_EQUAL(r, 0); + + for (i = 0; secure && (i < 2); i++) + gtt_flags[i] |= AMDGPU_GEM_CREATE_ENCRYPTED; + + r = amdgpu_cs_ctx_create(device, &context_handle); + + CU_ASSERT_EQUAL(r, 0); + + /* prepare resource */ + resources = calloc(1, sizeof(amdgpu_bo_handle)); + CU_ASSERT_NOT_EQUAL(resources, NULL); + + for (ring_id = 0; (1 << ring_id) & hw_ip_info.available_rings; ring_id++) { + loop = 0; + while(loop < 2) { + /* allocate UC bo for sDMA use */ + r = amdgpu_bo_alloc_and_map(device, + sdma_write_length * sizeof(uint32_t), + 4096, AMDGPU_GEM_DOMAIN_GTT, + gtt_flags[loop], &bo, (void**)&bo_cpu, + &bo_mc, &va_handle); + CU_ASSERT_EQUAL(r, 0); + + /* clear bo */ + memset((void*)bo_cpu, 0, sdma_write_length * sizeof(uint32_t)); + + resources[0] = bo; + + /* fulfill PM4: test DMA write-linear */ + i = j = 0; + if (ip_type == AMDGPU_HW_IP_DMA) { + if (family_id == AMDGPU_FAMILY_SI) + pm4[i++] = SDMA_PACKET_SI(SDMA_OPCODE_WRITE, 0, 0, 0, + sdma_write_length); + else + pm4[i++] = SDMA_PACKET(SDMA_OPCODE_WRITE, + SDMA_WRITE_SUB_OPCODE_LINEAR, + secure ? SDMA_ATOMIC_TMZ(1) : 0); + pm4[i++] = 0xfffffffc & bo_mc; + pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32; + if (family_id >= AMDGPU_FAMILY_AI) + pm4[i++] = sdma_write_length - 1; + else if (family_id != AMDGPU_FAMILY_SI) + pm4[i++] = sdma_write_length; + while(j++ < sdma_write_length) + pm4[i++] = 0xdeadbeaf; + } else if ((ip_type == AMDGPU_HW_IP_GFX) || + (ip_type == AMDGPU_HW_IP_COMPUTE)) { + pm4[i++] = PACKET3(PACKET3_WRITE_DATA, 2 + sdma_write_length); + pm4[i++] = WRITE_DATA_DST_SEL(5) | WR_CONFIRM; + pm4[i++] = 0xfffffffc & bo_mc; + pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32; + while(j++ < sdma_write_length) + pm4[i++] = 0xdeadbeaf; + } + + amdgpu_test_exec_cs_helper_raw(device, context_handle, + ip_type, ring_id, i, pm4, + 1, resources, ib_info, + ibs_request, secure); + + /* verify if SDMA test result meets with expected */ + i = 0; + if (!secure) { + while(i < sdma_write_length) { + CU_ASSERT_EQUAL(bo_cpu[i++], 0xdeadbeaf); + } + } else if (ip_type == AMDGPU_HW_IP_GFX) { + memset((void*)pm4, 0, pm4_dw * sizeof(uint32_t)); + pm4[i++] = PACKET3(PACKET3_ATOMIC_MEM, 7); + /* atomic opcode for 32b w/ RTN and ATOMIC_SWAPCMP_RTN + * command, 1-loop_until_compare_satisfied. + * single_pass_atomic, 0-lru + * engine_sel, 0-micro_engine + */ + pm4[i++] = (TC_OP_ATOMIC_CMPSWAP_RTN_32 | + ATOMIC_MEM_COMMAND(1) | + ATOMIC_MEM_CACHEPOLICAY(0) | + ATOMIC_MEM_ENGINESEL(0)); + pm4[i++] = 0xfffffffc & bo_mc; + pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32; + pm4[i++] = 0x12345678; + pm4[i++] = 0x0; + pm4[i++] = 0xdeadbeaf; + pm4[i++] = 0x0; + pm4[i++] = 0x100; + amdgpu_test_exec_cs_helper_raw(device, context_handle, + ip_type, ring_id, i, pm4, + 1, resources, ib_info, + ibs_request, true); + } else if (ip_type == AMDGPU_HW_IP_DMA) { + /* restore the bo_cpu to compare */ + bo_cpu_origin = bo_cpu[0]; + memset((void*)pm4, 0, pm4_dw * sizeof(uint32_t)); + /* atomic opcode for 32b w/ RTN and ATOMIC_SWAPCMP_RTN + * loop, 1-loop_until_compare_satisfied. + * single_pass_atomic, 0-lru + */ + pm4[i++] = SDMA_PACKET(SDMA_OPCODE_ATOMIC, + 0, + SDMA_ATOMIC_LOOP(1) | + SDMA_ATOMIC_TMZ(1) | + SDMA_ATOMIC_OPCODE(TC_OP_ATOMIC_CMPSWAP_RTN_32)); + pm4[i++] = 0xfffffffc & bo_mc; + pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32; + pm4[i++] = 0x12345678; + pm4[i++] = 0x0; + pm4[i++] = 0xdeadbeaf; + pm4[i++] = 0x0; + pm4[i++] = 0x100; + amdgpu_test_exec_cs_helper_raw(device, context_handle, + ip_type, ring_id, i, pm4, + 1, resources, ib_info, + ibs_request, true); + /* DMA's atomic behavir is unlike GFX + * If the comparing data is not equal to destination data, + * For GFX, loop again till gfx timeout(system hang). + * For DMA, loop again till timer expired and then send interrupt. + * So testcase can't use interrupt mechanism. + * We take another way to verify. When the comparing data is not + * equal to destination data, overwrite the source data to the destination + * buffer. Otherwise, original destination data unchanged. + * So if the bo_cpu data is overwritten, the result is passed. + */ + CU_ASSERT_NOT_EQUAL(bo_cpu[0], bo_cpu_origin); + + /* compare again for the case of dest_data != cmp_data */ + i = 0; + /* restore again, here dest_data should be */ + bo_cpu_origin = bo_cpu[0]; + memset((void*)pm4, 0, pm4_dw * sizeof(uint32_t)); + pm4[i++] = SDMA_PACKET(SDMA_OPCODE_ATOMIC, + 0, + SDMA_ATOMIC_LOOP(1) | + SDMA_ATOMIC_TMZ(1) | + SDMA_ATOMIC_OPCODE(TC_OP_ATOMIC_CMPSWAP_RTN_32)); + pm4[i++] = 0xfffffffc & bo_mc; + pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32; + pm4[i++] = 0x87654321; + pm4[i++] = 0x0; + pm4[i++] = 0xdeadbeaf; + pm4[i++] = 0x0; + pm4[i++] = 0x100; + amdgpu_test_exec_cs_helper_raw(device, context_handle, + ip_type, ring_id, i, pm4, + 1, resources, ib_info, + ibs_request, true); + /* here bo_cpu[0] should be unchanged, still is 0x12345678, otherwise failed*/ + CU_ASSERT_EQUAL(bo_cpu[0], bo_cpu_origin); + } + + r = amdgpu_bo_unmap_and_free(bo, va_handle, bo_mc, + sdma_write_length * sizeof(uint32_t)); + CU_ASSERT_EQUAL(r, 0); + loop++; + } + } + /* clean resources */ + free(resources); + free(ibs_request); + free(ib_info); + free(pm4); + + /* end of test */ + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_command_submission_write_linear_helper(unsigned ip_type) +{ + amdgpu_command_submission_write_linear_helper_with_secure(device_handle, + ip_type, + false); +} + +static void amdgpu_command_submission_sdma_write_linear(void) +{ + amdgpu_command_submission_write_linear_helper(AMDGPU_HW_IP_DMA); +} + +static void amdgpu_command_submission_const_fill_helper(unsigned ip_type) +{ + const int sdma_write_length = 1024 * 1024; + const int pm4_dw = 256; + amdgpu_context_handle context_handle; + amdgpu_bo_handle bo; + amdgpu_bo_handle *resources; + uint32_t *pm4; + struct amdgpu_cs_ib_info *ib_info; + struct amdgpu_cs_request *ibs_request; + uint64_t bo_mc; + volatile uint32_t *bo_cpu; + int i, j, r, loop, ring_id; + uint64_t gtt_flags[2] = {0, AMDGPU_GEM_CREATE_CPU_GTT_USWC}; + amdgpu_va_handle va_handle; + struct drm_amdgpu_info_hw_ip hw_ip_info; + + pm4 = calloc(pm4_dw, sizeof(*pm4)); + CU_ASSERT_NOT_EQUAL(pm4, NULL); + + ib_info = calloc(1, sizeof(*ib_info)); + CU_ASSERT_NOT_EQUAL(ib_info, NULL); + + ibs_request = calloc(1, sizeof(*ibs_request)); + CU_ASSERT_NOT_EQUAL(ibs_request, NULL); + + r = amdgpu_query_hw_ip_info(device_handle, ip_type, 0, &hw_ip_info); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_ctx_create(device_handle, &context_handle); + CU_ASSERT_EQUAL(r, 0); + + /* prepare resource */ + resources = calloc(1, sizeof(amdgpu_bo_handle)); + CU_ASSERT_NOT_EQUAL(resources, NULL); + + for (ring_id = 0; (1 << ring_id) & hw_ip_info.available_rings; ring_id++) { + loop = 0; + while(loop < 2) { + /* allocate UC bo for sDMA use */ + r = amdgpu_bo_alloc_and_map(device_handle, + sdma_write_length, 4096, + AMDGPU_GEM_DOMAIN_GTT, + gtt_flags[loop], &bo, (void**)&bo_cpu, + &bo_mc, &va_handle); + CU_ASSERT_EQUAL(r, 0); + + /* clear bo */ + memset((void*)bo_cpu, 0, sdma_write_length); + + resources[0] = bo; + + /* fulfill PM4: test DMA const fill */ + i = j = 0; + if (ip_type == AMDGPU_HW_IP_DMA) { + if (family_id == AMDGPU_FAMILY_SI) { + pm4[i++] = SDMA_PACKET_SI(SDMA_OPCODE_CONSTANT_FILL_SI, + 0, 0, 0, + sdma_write_length / 4); + pm4[i++] = 0xfffffffc & bo_mc; + pm4[i++] = 0xdeadbeaf; + pm4[i++] = (0xffffffff00000000 & bo_mc) >> 16; + } else { + pm4[i++] = SDMA_PACKET(SDMA_OPCODE_CONSTANT_FILL, 0, + SDMA_CONSTANT_FILL_EXTRA_SIZE(2)); + pm4[i++] = 0xffffffff & bo_mc; + pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32; + pm4[i++] = 0xdeadbeaf; + if (family_id >= AMDGPU_FAMILY_AI) + pm4[i++] = sdma_write_length - 1; + else + pm4[i++] = sdma_write_length; + } + } else if ((ip_type == AMDGPU_HW_IP_GFX) || + (ip_type == AMDGPU_HW_IP_COMPUTE)) { + if (family_id == AMDGPU_FAMILY_SI) { + pm4[i++] = PACKET3(PACKET3_DMA_DATA_SI, 4); + pm4[i++] = 0xdeadbeaf; + pm4[i++] = PACKET3_DMA_DATA_SI_ENGINE(0) | + PACKET3_DMA_DATA_SI_DST_SEL(0) | + PACKET3_DMA_DATA_SI_SRC_SEL(2) | + PACKET3_DMA_DATA_SI_CP_SYNC; + pm4[i++] = 0xffffffff & bo_mc; + pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32; + pm4[i++] = sdma_write_length; + } else { + pm4[i++] = PACKET3(PACKET3_DMA_DATA, 5); + pm4[i++] = PACKET3_DMA_DATA_ENGINE(0) | + PACKET3_DMA_DATA_DST_SEL(0) | + PACKET3_DMA_DATA_SRC_SEL(2) | + PACKET3_DMA_DATA_CP_SYNC; + pm4[i++] = 0xdeadbeaf; + pm4[i++] = 0; + pm4[i++] = 0xfffffffc & bo_mc; + pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32; + pm4[i++] = sdma_write_length; + } + } + + amdgpu_test_exec_cs_helper(context_handle, + ip_type, ring_id, + i, pm4, + 1, resources, + ib_info, ibs_request); + + /* verify if SDMA test result meets with expected */ + i = 0; + while(i < (sdma_write_length / 4)) { + CU_ASSERT_EQUAL(bo_cpu[i++], 0xdeadbeaf); + } + + r = amdgpu_bo_unmap_and_free(bo, va_handle, bo_mc, + sdma_write_length); + CU_ASSERT_EQUAL(r, 0); + loop++; + } + } + /* clean resources */ + free(resources); + free(ibs_request); + free(ib_info); + free(pm4); + + /* end of test */ + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_command_submission_sdma_const_fill(void) +{ + amdgpu_command_submission_const_fill_helper(AMDGPU_HW_IP_DMA); +} + +static void amdgpu_command_submission_copy_linear_helper(unsigned ip_type) +{ + const int sdma_write_length = 1024; + const int pm4_dw = 256; + amdgpu_context_handle context_handle; + amdgpu_bo_handle bo1, bo2; + amdgpu_bo_handle *resources; + uint32_t *pm4; + struct amdgpu_cs_ib_info *ib_info; + struct amdgpu_cs_request *ibs_request; + uint64_t bo1_mc, bo2_mc; + volatile unsigned char *bo1_cpu, *bo2_cpu; + int i, j, r, loop1, loop2, ring_id; + uint64_t gtt_flags[2] = {0, AMDGPU_GEM_CREATE_CPU_GTT_USWC}; + amdgpu_va_handle bo1_va_handle, bo2_va_handle; + struct drm_amdgpu_info_hw_ip hw_ip_info; + + pm4 = calloc(pm4_dw, sizeof(*pm4)); + CU_ASSERT_NOT_EQUAL(pm4, NULL); + + ib_info = calloc(1, sizeof(*ib_info)); + CU_ASSERT_NOT_EQUAL(ib_info, NULL); + + ibs_request = calloc(1, sizeof(*ibs_request)); + CU_ASSERT_NOT_EQUAL(ibs_request, NULL); + + r = amdgpu_query_hw_ip_info(device_handle, ip_type, 0, &hw_ip_info); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_ctx_create(device_handle, &context_handle); + CU_ASSERT_EQUAL(r, 0); + + /* prepare resource */ + resources = calloc(2, sizeof(amdgpu_bo_handle)); + CU_ASSERT_NOT_EQUAL(resources, NULL); + + for (ring_id = 0; (1 << ring_id) & hw_ip_info.available_rings; ring_id++) { + loop1 = loop2 = 0; + /* run 9 circle to test all mapping combination */ + while(loop1 < 2) { + while(loop2 < 2) { + /* allocate UC bo1for sDMA use */ + r = amdgpu_bo_alloc_and_map(device_handle, + sdma_write_length, 4096, + AMDGPU_GEM_DOMAIN_GTT, + gtt_flags[loop1], &bo1, + (void**)&bo1_cpu, &bo1_mc, + &bo1_va_handle); + CU_ASSERT_EQUAL(r, 0); + + /* set bo1 */ + memset((void*)bo1_cpu, 0xaa, sdma_write_length); + + /* allocate UC bo2 for sDMA use */ + r = amdgpu_bo_alloc_and_map(device_handle, + sdma_write_length, 4096, + AMDGPU_GEM_DOMAIN_GTT, + gtt_flags[loop2], &bo2, + (void**)&bo2_cpu, &bo2_mc, + &bo2_va_handle); + CU_ASSERT_EQUAL(r, 0); + + /* clear bo2 */ + memset((void*)bo2_cpu, 0, sdma_write_length); + + resources[0] = bo1; + resources[1] = bo2; + + /* fulfill PM4: test DMA copy linear */ + i = j = 0; + if (ip_type == AMDGPU_HW_IP_DMA) { + if (family_id == AMDGPU_FAMILY_SI) { + pm4[i++] = SDMA_PACKET_SI(SDMA_OPCODE_COPY_SI, + 0, 0, 0, + sdma_write_length); + pm4[i++] = 0xffffffff & bo2_mc; + pm4[i++] = 0xffffffff & bo1_mc; + pm4[i++] = (0xffffffff00000000 & bo2_mc) >> 32; + pm4[i++] = (0xffffffff00000000 & bo1_mc) >> 32; + } else { + pm4[i++] = SDMA_PACKET(SDMA_OPCODE_COPY, + SDMA_COPY_SUB_OPCODE_LINEAR, + 0); + if (family_id >= AMDGPU_FAMILY_AI) + pm4[i++] = sdma_write_length - 1; + else + pm4[i++] = sdma_write_length; + pm4[i++] = 0; + pm4[i++] = 0xffffffff & bo1_mc; + pm4[i++] = (0xffffffff00000000 & bo1_mc) >> 32; + pm4[i++] = 0xffffffff & bo2_mc; + pm4[i++] = (0xffffffff00000000 & bo2_mc) >> 32; + } + } else if ((ip_type == AMDGPU_HW_IP_GFX) || + (ip_type == AMDGPU_HW_IP_COMPUTE)) { + if (family_id == AMDGPU_FAMILY_SI) { + pm4[i++] = PACKET3(PACKET3_DMA_DATA_SI, 4); + pm4[i++] = 0xfffffffc & bo1_mc; + pm4[i++] = PACKET3_DMA_DATA_SI_ENGINE(0) | + PACKET3_DMA_DATA_SI_DST_SEL(0) | + PACKET3_DMA_DATA_SI_SRC_SEL(0) | + PACKET3_DMA_DATA_SI_CP_SYNC | + (0xffff00000000 & bo1_mc) >> 32; + pm4[i++] = 0xfffffffc & bo2_mc; + pm4[i++] = (0xffffffff00000000 & bo2_mc) >> 32; + pm4[i++] = sdma_write_length; + } else { + pm4[i++] = PACKET3(PACKET3_DMA_DATA, 5); + pm4[i++] = PACKET3_DMA_DATA_ENGINE(0) | + PACKET3_DMA_DATA_DST_SEL(0) | + PACKET3_DMA_DATA_SRC_SEL(0) | + PACKET3_DMA_DATA_CP_SYNC; + pm4[i++] = 0xfffffffc & bo1_mc; + pm4[i++] = (0xffffffff00000000 & bo1_mc) >> 32; + pm4[i++] = 0xfffffffc & bo2_mc; + pm4[i++] = (0xffffffff00000000 & bo2_mc) >> 32; + pm4[i++] = sdma_write_length; + } + } + + amdgpu_test_exec_cs_helper(context_handle, + ip_type, ring_id, + i, pm4, + 2, resources, + ib_info, ibs_request); + + /* verify if SDMA test result meets with expected */ + i = 0; + while(i < sdma_write_length) { + CU_ASSERT_EQUAL(bo2_cpu[i++], 0xaa); + } + r = amdgpu_bo_unmap_and_free(bo1, bo1_va_handle, bo1_mc, + sdma_write_length); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_bo_unmap_and_free(bo2, bo2_va_handle, bo2_mc, + sdma_write_length); + CU_ASSERT_EQUAL(r, 0); + loop2++; + } + loop1++; + } + } + /* clean resources */ + free(resources); + free(ibs_request); + free(ib_info); + free(pm4); + + /* end of test */ + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_command_submission_sdma_copy_linear(void) +{ + amdgpu_command_submission_copy_linear_helper(AMDGPU_HW_IP_DMA); +} + +static void amdgpu_command_submission_sdma(void) +{ + amdgpu_command_submission_sdma_write_linear(); + amdgpu_command_submission_sdma_const_fill(); + amdgpu_command_submission_sdma_copy_linear(); +} + +static void amdgpu_command_submission_multi_fence_wait_all(bool wait_all) +{ + amdgpu_context_handle context_handle; + amdgpu_bo_handle ib_result_handle, ib_result_ce_handle; + void *ib_result_cpu, *ib_result_ce_cpu; + uint64_t ib_result_mc_address, ib_result_ce_mc_address; + struct amdgpu_cs_request ibs_request[2] = {0}; + struct amdgpu_cs_ib_info ib_info[2]; + struct amdgpu_cs_fence fence_status[2] = {0}; + uint32_t *ptr; + uint32_t expired; + amdgpu_bo_list_handle bo_list; + amdgpu_va_handle va_handle, va_handle_ce; + int r; + int i = 0, ib_cs_num = 2; + struct drm_amdgpu_info_hw_ip info; + + r = amdgpu_query_hw_ip_info(device_handle, AMDGPU_HW_IP_GFX, 0, &info); + CU_ASSERT_EQUAL(r, 0); + + if (info.hw_ip_version_major >= 11) + return; + + r = amdgpu_cs_ctx_create(device_handle, &context_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_alloc_and_map(device_handle, 4096, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, + &ib_result_handle, &ib_result_cpu, + &ib_result_mc_address, &va_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_alloc_and_map(device_handle, 4096, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, + &ib_result_ce_handle, &ib_result_ce_cpu, + &ib_result_ce_mc_address, &va_handle_ce); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_get_bo_list(device_handle, ib_result_handle, + ib_result_ce_handle, &bo_list); + CU_ASSERT_EQUAL(r, 0); + + memset(ib_info, 0, 2 * sizeof(struct amdgpu_cs_ib_info)); + + /* IT_SET_CE_DE_COUNTERS */ + ptr = ib_result_ce_cpu; + if (family_id != AMDGPU_FAMILY_SI) { + ptr[i++] = 0xc0008900; + ptr[i++] = 0; + } + ptr[i++] = 0xc0008400; + ptr[i++] = 1; + ib_info[0].ib_mc_address = ib_result_ce_mc_address; + ib_info[0].size = i; + ib_info[0].flags = AMDGPU_IB_FLAG_CE; + + /* IT_WAIT_ON_CE_COUNTER */ + ptr = ib_result_cpu; + ptr[0] = 0xc0008600; + ptr[1] = 0x00000001; + ib_info[1].ib_mc_address = ib_result_mc_address; + ib_info[1].size = 2; + + for (i = 0; i < ib_cs_num; i++) { + ibs_request[i].ip_type = AMDGPU_HW_IP_GFX; + ibs_request[i].number_of_ibs = 2; + ibs_request[i].ibs = ib_info; + ibs_request[i].resources = bo_list; + ibs_request[i].fence_info.handle = NULL; + } + + r = amdgpu_cs_submit(context_handle, 0,ibs_request, ib_cs_num); + + CU_ASSERT_EQUAL(r, 0); + + for (i = 0; i < ib_cs_num; i++) { + fence_status[i].context = context_handle; + fence_status[i].ip_type = AMDGPU_HW_IP_GFX; + fence_status[i].fence = ibs_request[i].seq_no; + } + + r = amdgpu_cs_wait_fences(fence_status, ib_cs_num, wait_all, + AMDGPU_TIMEOUT_INFINITE, + &expired, NULL); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_unmap_and_free(ib_result_handle, va_handle, + ib_result_mc_address, 4096); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_unmap_and_free(ib_result_ce_handle, va_handle_ce, + ib_result_ce_mc_address, 4096); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_list_destroy(bo_list); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_command_submission_multi_fence(void) +{ + amdgpu_command_submission_multi_fence_wait_all(true); + amdgpu_command_submission_multi_fence_wait_all(false); +} + +static void amdgpu_userptr_test(void) +{ + int i, r, j; + uint32_t *pm4 = NULL; + uint64_t bo_mc; + void *ptr = NULL; + int pm4_dw = 256; + int sdma_write_length = 4; + amdgpu_bo_handle handle; + amdgpu_context_handle context_handle; + struct amdgpu_cs_ib_info *ib_info; + struct amdgpu_cs_request *ibs_request; + amdgpu_bo_handle buf_handle; + amdgpu_va_handle va_handle; + + pm4 = calloc(pm4_dw, sizeof(*pm4)); + CU_ASSERT_NOT_EQUAL(pm4, NULL); + + ib_info = calloc(1, sizeof(*ib_info)); + CU_ASSERT_NOT_EQUAL(ib_info, NULL); + + ibs_request = calloc(1, sizeof(*ibs_request)); + CU_ASSERT_NOT_EQUAL(ibs_request, NULL); + + r = amdgpu_cs_ctx_create(device_handle, &context_handle); + CU_ASSERT_EQUAL(r, 0); + + posix_memalign(&ptr, sysconf(_SC_PAGE_SIZE), BUFFER_SIZE); + CU_ASSERT_NOT_EQUAL(ptr, NULL); + memset(ptr, 0, BUFFER_SIZE); + + r = amdgpu_create_bo_from_user_mem(device_handle, + ptr, BUFFER_SIZE, &buf_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_va_range_alloc(device_handle, + amdgpu_gpu_va_range_general, + BUFFER_SIZE, 1, 0, &bo_mc, + &va_handle, 0); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_va_op(buf_handle, 0, BUFFER_SIZE, bo_mc, 0, AMDGPU_VA_OP_MAP); + CU_ASSERT_EQUAL(r, 0); + + handle = buf_handle; + + j = i = 0; + + if (family_id == AMDGPU_FAMILY_SI) + pm4[i++] = SDMA_PACKET_SI(SDMA_OPCODE_WRITE, 0, 0, 0, + sdma_write_length); + else + pm4[i++] = SDMA_PACKET(SDMA_OPCODE_WRITE, + SDMA_WRITE_SUB_OPCODE_LINEAR, 0); + pm4[i++] = 0xffffffff & bo_mc; + pm4[i++] = (0xffffffff00000000 & bo_mc) >> 32; + if (family_id >= AMDGPU_FAMILY_AI) + pm4[i++] = sdma_write_length - 1; + else if (family_id != AMDGPU_FAMILY_SI) + pm4[i++] = sdma_write_length; + + while (j++ < sdma_write_length) + pm4[i++] = 0xdeadbeaf; + + if (!fork()) { + pm4[0] = 0x0; + exit(0); + } + + amdgpu_test_exec_cs_helper(context_handle, + AMDGPU_HW_IP_DMA, 0, + i, pm4, + 1, &handle, + ib_info, ibs_request); + i = 0; + while (i < sdma_write_length) { + CU_ASSERT_EQUAL(((int*)ptr)[i++], 0xdeadbeaf); + } + free(ibs_request); + free(ib_info); + free(pm4); + + r = amdgpu_bo_va_op(buf_handle, 0, BUFFER_SIZE, bo_mc, 0, AMDGPU_VA_OP_UNMAP); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_va_range_free(va_handle); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_bo_free(buf_handle); + CU_ASSERT_EQUAL(r, 0); + free(ptr); + + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); + + wait(NULL); +} + +static void amdgpu_sync_dependency_test(void) +{ + amdgpu_context_handle context_handle[2]; + amdgpu_bo_handle ib_result_handle; + void *ib_result_cpu; + uint64_t ib_result_mc_address; + struct amdgpu_cs_request ibs_request; + struct amdgpu_cs_ib_info ib_info; + struct amdgpu_cs_fence fence_status; + uint32_t expired; + int i, j, r; + amdgpu_bo_list_handle bo_list; + amdgpu_va_handle va_handle; + static uint32_t *ptr; + uint64_t seq_no; + + r = amdgpu_cs_ctx_create(device_handle, &context_handle[0]); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_cs_ctx_create(device_handle, &context_handle[1]); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_alloc_and_map(device_handle, 8192, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, + &ib_result_handle, &ib_result_cpu, + &ib_result_mc_address, &va_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_get_bo_list(device_handle, ib_result_handle, NULL, + &bo_list); + CU_ASSERT_EQUAL(r, 0); + + ptr = ib_result_cpu; + i = 0; + + memcpy(ptr + CODE_OFFSET , shader_bin, sizeof(shader_bin)); + + /* Dispatch minimal init config and verify it's executed */ + ptr[i++] = PACKET3(PKT3_CONTEXT_CONTROL, 1); + ptr[i++] = 0x80000000; + ptr[i++] = 0x80000000; + + ptr[i++] = PACKET3(PKT3_CLEAR_STATE, 0); + ptr[i++] = 0x80000000; + + + /* Program compute regs */ + ptr[i++] = PACKET3(PKT3_SET_SH_REG, 2); + ptr[i++] = mmCOMPUTE_PGM_LO - PACKET3_SET_SH_REG_START; + ptr[i++] = (ib_result_mc_address + CODE_OFFSET * 4) >> 8; + ptr[i++] = (ib_result_mc_address + CODE_OFFSET * 4) >> 40; + + + ptr[i++] = PACKET3(PKT3_SET_SH_REG, 2); + ptr[i++] = mmCOMPUTE_PGM_RSRC1 - PACKET3_SET_SH_REG_START; + /* + * 002c0040 COMPUTE_PGM_RSRC1 <- VGPRS = 0 + SGPRS = 1 + PRIORITY = 0 + FLOAT_MODE = 192 (0xc0) + PRIV = 0 + DX10_CLAMP = 1 + DEBUG_MODE = 0 + IEEE_MODE = 0 + BULKY = 0 + CDBG_USER = 0 + * + */ + ptr[i++] = 0x002c0040; + + + /* + * 00000010 COMPUTE_PGM_RSRC2 <- SCRATCH_EN = 0 + USER_SGPR = 8 + TRAP_PRESENT = 0 + TGID_X_EN = 0 + TGID_Y_EN = 0 + TGID_Z_EN = 0 + TG_SIZE_EN = 0 + TIDIG_COMP_CNT = 0 + EXCP_EN_MSB = 0 + LDS_SIZE = 0 + EXCP_EN = 0 + * + */ + ptr[i++] = 0x00000010; + + +/* + * 00000100 COMPUTE_TMPRING_SIZE <- WAVES = 256 (0x100) + WAVESIZE = 0 + * + */ + ptr[i++] = PACKET3(PKT3_SET_SH_REG, 1); + ptr[i++] = mmCOMPUTE_TMPRING_SIZE - PACKET3_SET_SH_REG_START; + ptr[i++] = 0x00000100; + + ptr[i++] = PACKET3(PKT3_SET_SH_REG, 2); + ptr[i++] = mmCOMPUTE_USER_DATA_0 - PACKET3_SET_SH_REG_START; + ptr[i++] = 0xffffffff & (ib_result_mc_address + DATA_OFFSET * 4); + ptr[i++] = (0xffffffff00000000 & (ib_result_mc_address + DATA_OFFSET * 4)) >> 32; + + ptr[i++] = PACKET3(PKT3_SET_SH_REG, 1); + ptr[i++] = mmCOMPUTE_RESOURCE_LIMITS - PACKET3_SET_SH_REG_START; + ptr[i++] = 0; + + ptr[i++] = PACKET3(PKT3_SET_SH_REG, 3); + ptr[i++] = mmCOMPUTE_NUM_THREAD_X - PACKET3_SET_SH_REG_START; + ptr[i++] = 1; + ptr[i++] = 1; + ptr[i++] = 1; + + + /* Dispatch */ + ptr[i++] = PACKET3(PACKET3_DISPATCH_DIRECT, 3); + ptr[i++] = 1; + ptr[i++] = 1; + ptr[i++] = 1; + ptr[i++] = 0x00000045; /* DISPATCH DIRECT field */ + + + while (i & 7) + ptr[i++] = 0xffff1000; /* type3 nop packet */ + + memset(&ib_info, 0, sizeof(struct amdgpu_cs_ib_info)); + ib_info.ib_mc_address = ib_result_mc_address; + ib_info.size = i; + + memset(&ibs_request, 0, sizeof(struct amdgpu_cs_request)); + ibs_request.ip_type = AMDGPU_HW_IP_GFX; + ibs_request.ring = 0; + ibs_request.number_of_ibs = 1; + ibs_request.ibs = &ib_info; + ibs_request.resources = bo_list; + ibs_request.fence_info.handle = NULL; + + r = amdgpu_cs_submit(context_handle[1], 0,&ibs_request, 1); + CU_ASSERT_EQUAL(r, 0); + seq_no = ibs_request.seq_no; + + + + /* Prepare second command with dependency on the first */ + j = i; + ptr[i++] = PACKET3(PACKET3_WRITE_DATA, 3); + ptr[i++] = WRITE_DATA_DST_SEL(5) | WR_CONFIRM; + ptr[i++] = 0xfffffffc & (ib_result_mc_address + DATA_OFFSET * 4); + ptr[i++] = (0xffffffff00000000 & (ib_result_mc_address + DATA_OFFSET * 4)) >> 32; + ptr[i++] = 99; + + while (i & 7) + ptr[i++] = 0xffff1000; /* type3 nop packet */ + + memset(&ib_info, 0, sizeof(struct amdgpu_cs_ib_info)); + ib_info.ib_mc_address = ib_result_mc_address + j * 4; + ib_info.size = i - j; + + memset(&ibs_request, 0, sizeof(struct amdgpu_cs_request)); + ibs_request.ip_type = AMDGPU_HW_IP_GFX; + ibs_request.ring = 0; + ibs_request.number_of_ibs = 1; + ibs_request.ibs = &ib_info; + ibs_request.resources = bo_list; + ibs_request.fence_info.handle = NULL; + + ibs_request.number_of_dependencies = 1; + + ibs_request.dependencies = calloc(1, sizeof(*ibs_request.dependencies)); + ibs_request.dependencies[0].context = context_handle[1]; + ibs_request.dependencies[0].ip_instance = 0; + ibs_request.dependencies[0].ring = 0; + ibs_request.dependencies[0].fence = seq_no; + + + r = amdgpu_cs_submit(context_handle[0], 0,&ibs_request, 1); + CU_ASSERT_EQUAL(r, 0); + + + memset(&fence_status, 0, sizeof(struct amdgpu_cs_fence)); + fence_status.context = context_handle[0]; + fence_status.ip_type = AMDGPU_HW_IP_GFX; + fence_status.ip_instance = 0; + fence_status.ring = 0; + fence_status.fence = ibs_request.seq_no; + + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE,0, &expired); + CU_ASSERT_EQUAL(r, 0); + + /* Expect the second command to wait for shader to complete */ + CU_ASSERT_EQUAL(ptr[DATA_OFFSET], 99); + + r = amdgpu_bo_list_destroy(bo_list); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_unmap_and_free(ib_result_handle, va_handle, + ib_result_mc_address, 4096); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_ctx_free(context_handle[0]); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_cs_ctx_free(context_handle[1]); + CU_ASSERT_EQUAL(r, 0); + + free(ibs_request.dependencies); +} + +static void amdgpu_compute_dispatch_test(void) +{ + amdgpu_test_dispatch_helper(device_handle, AMDGPU_HW_IP_COMPUTE); +} +static void amdgpu_gfx_dispatch_test(void) +{ + amdgpu_test_dispatch_helper(device_handle, AMDGPU_HW_IP_GFX); +} + +static void amdgpu_draw_test(void) +{ + amdgpu_test_draw_helper(device_handle); +} +static void amdgpu_gpu_reset_test(void) +{ + int r; + char debugfs_path[256], tmp[10]; + int fd; + struct stat sbuf; + amdgpu_context_handle context_handle; + uint32_t hang_state, hangs; + + r = amdgpu_cs_ctx_create(device_handle, &context_handle); + CU_ASSERT_EQUAL(r, 0); + + r = fstat(drm_amdgpu[0], &sbuf); + CU_ASSERT_EQUAL(r, 0); + + sprintf(debugfs_path, "/sys/kernel/debug/dri/%d/amdgpu_gpu_recover", minor(sbuf.st_rdev)); + fd = open(debugfs_path, O_RDONLY); + CU_ASSERT(fd >= 0); + + r = read(fd, tmp, sizeof(tmp)/sizeof(char)); + CU_ASSERT(r > 0); + + r = amdgpu_cs_query_reset_state(context_handle, &hang_state, &hangs); + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(hang_state, AMDGPU_CTX_UNKNOWN_RESET); + + close(fd); + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); + + amdgpu_compute_dispatch_test(); + amdgpu_gfx_dispatch_test(); +} + +static void amdgpu_stable_pstate_test(void) +{ + int r; + amdgpu_context_handle context_handle; + uint32_t current_pstate = 0, new_pstate = 0; + + r = amdgpu_cs_ctx_create(device_handle, &context_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_ctx_stable_pstate(context_handle, + AMDGPU_CTX_OP_GET_STABLE_PSTATE, + 0, ¤t_pstate); + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(new_pstate, AMDGPU_CTX_STABLE_PSTATE_NONE); + + r = amdgpu_cs_ctx_stable_pstate(context_handle, + AMDGPU_CTX_OP_SET_STABLE_PSTATE, + AMDGPU_CTX_STABLE_PSTATE_PEAK, NULL); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_ctx_stable_pstate(context_handle, + AMDGPU_CTX_OP_GET_STABLE_PSTATE, + 0, &new_pstate); + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(new_pstate, AMDGPU_CTX_STABLE_PSTATE_PEAK); + + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); +} diff --git a/tests/amdgpu/bo_tests.c b/tests/amdgpu/bo_tests.c new file mode 100644 index 0000000..8fc7fe2 --- /dev/null +++ b/tests/amdgpu/bo_tests.c @@ -0,0 +1,317 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * +*/ + +#include + +#include "CUnit/Basic.h" + +#include "amdgpu_test.h" +#include "amdgpu_drm.h" +#include "amdgpu_internal.h" + +#define BUFFER_SIZE (4*1024) +#define BUFFER_ALIGN (4*1024) + +static amdgpu_device_handle device_handle; +static uint32_t major_version; +static uint32_t minor_version; + +static amdgpu_bo_handle buffer_handle; +static uint64_t virtual_mc_base_address; +static amdgpu_va_handle va_handle; + +static void amdgpu_bo_export_import(void); +static void amdgpu_bo_metadata(void); +static void amdgpu_bo_map_unmap(void); +static void amdgpu_memory_alloc(void); +static void amdgpu_mem_fail_alloc(void); +static void amdgpu_bo_find_by_cpu_mapping(void); + +CU_TestInfo bo_tests[] = { + { "Export/Import", amdgpu_bo_export_import }, + { "Metadata", amdgpu_bo_metadata }, + { "CPU map/unmap", amdgpu_bo_map_unmap }, + { "Memory alloc Test", amdgpu_memory_alloc }, + { "Memory fail alloc Test", amdgpu_mem_fail_alloc }, + { "Find bo by CPU mapping", amdgpu_bo_find_by_cpu_mapping }, + CU_TEST_INFO_NULL, +}; + +int suite_bo_tests_init(void) +{ + struct amdgpu_bo_alloc_request req = {0}; + amdgpu_bo_handle buf_handle; + uint64_t va; + int r; + + r = amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle); + if (r) { + if ((r == -EACCES) && (errno == EACCES)) + printf("\n\nError:%s. " + "Hint:Try to run this test program as root.", + strerror(errno)); + + return CUE_SINIT_FAILED; + } + + req.alloc_size = BUFFER_SIZE; + req.phys_alignment = BUFFER_ALIGN; + req.preferred_heap = AMDGPU_GEM_DOMAIN_GTT; + + r = amdgpu_bo_alloc(device_handle, &req, &buf_handle); + if (r) + return CUE_SINIT_FAILED; + + r = amdgpu_va_range_alloc(device_handle, + amdgpu_gpu_va_range_general, + BUFFER_SIZE, BUFFER_ALIGN, 0, + &va, &va_handle, 0); + if (r) + goto error_va_alloc; + + r = amdgpu_bo_va_op(buf_handle, 0, BUFFER_SIZE, va, 0, AMDGPU_VA_OP_MAP); + if (r) + goto error_va_map; + + buffer_handle = buf_handle; + virtual_mc_base_address = va; + + return CUE_SUCCESS; + +error_va_map: + amdgpu_va_range_free(va_handle); + +error_va_alloc: + amdgpu_bo_free(buf_handle); + return CUE_SINIT_FAILED; +} + +int suite_bo_tests_clean(void) +{ + int r; + + r = amdgpu_bo_va_op(buffer_handle, 0, BUFFER_SIZE, + virtual_mc_base_address, 0, + AMDGPU_VA_OP_UNMAP); + if (r) + return CUE_SCLEAN_FAILED; + + r = amdgpu_va_range_free(va_handle); + if (r) + return CUE_SCLEAN_FAILED; + + r = amdgpu_bo_free(buffer_handle); + if (r) + return CUE_SCLEAN_FAILED; + + r = amdgpu_device_deinitialize(device_handle); + if (r) + return CUE_SCLEAN_FAILED; + + return CUE_SUCCESS; +} + +static void amdgpu_bo_export_import_do_type(enum amdgpu_bo_handle_type type) +{ + struct amdgpu_bo_import_result res = {0}; + uint32_t shared_handle; + int r; + + r = amdgpu_bo_export(buffer_handle, type, &shared_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_import(device_handle, type, shared_handle, &res); + CU_ASSERT_EQUAL(r, 0); + + CU_ASSERT_EQUAL(res.buf_handle, buffer_handle); + CU_ASSERT_EQUAL(res.alloc_size, BUFFER_SIZE); + + r = amdgpu_bo_free(res.buf_handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_bo_export_import(void) +{ + if (open_render_node) { + printf("(DRM render node is used. Skip export/Import test) "); + return; + } + + amdgpu_bo_export_import_do_type(amdgpu_bo_handle_type_gem_flink_name); + amdgpu_bo_export_import_do_type(amdgpu_bo_handle_type_dma_buf_fd); +} + +static void amdgpu_bo_metadata(void) +{ + struct amdgpu_bo_metadata meta = {0}; + struct amdgpu_bo_info info = {0}; + int r; + + meta.size_metadata = 4; + meta.umd_metadata[0] = 0xdeadbeef; + + r = amdgpu_bo_set_metadata(buffer_handle, &meta); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_query_info(buffer_handle, &info); + CU_ASSERT_EQUAL(r, 0); + + CU_ASSERT_EQUAL(info.metadata.size_metadata, 4); + CU_ASSERT_EQUAL(info.metadata.umd_metadata[0], 0xdeadbeef); +} + +static void amdgpu_bo_map_unmap(void) +{ + uint32_t *ptr; + int i, r; + + r = amdgpu_bo_cpu_map(buffer_handle, (void **)&ptr); + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_NOT_EQUAL(ptr, NULL); + + for (i = 0; i < (BUFFER_SIZE / 4); ++i) + ptr[i] = 0xdeadbeef; + + r = amdgpu_bo_cpu_unmap(buffer_handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_memory_alloc(void) +{ + amdgpu_bo_handle bo; + amdgpu_va_handle va_handle; + uint64_t bo_mc; + int r; + + /* Test visible VRAM */ + bo = gpu_mem_alloc(device_handle, + 4096, 4096, + AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, + &bo_mc, &va_handle); + + r = gpu_mem_free(bo, va_handle, bo_mc, 4096); + CU_ASSERT_EQUAL(r, 0); + + /* Test invisible VRAM */ + bo = gpu_mem_alloc(device_handle, + 4096, 4096, + AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_NO_CPU_ACCESS, + &bo_mc, &va_handle); + + r = gpu_mem_free(bo, va_handle, bo_mc, 4096); + CU_ASSERT_EQUAL(r, 0); + + /* Test GART Cacheable */ + bo = gpu_mem_alloc(device_handle, + 4096, 4096, + AMDGPU_GEM_DOMAIN_GTT, + 0, &bo_mc, &va_handle); + + r = gpu_mem_free(bo, va_handle, bo_mc, 4096); + CU_ASSERT_EQUAL(r, 0); + + /* Test GART USWC */ + bo = gpu_mem_alloc(device_handle, + 4096, 4096, + AMDGPU_GEM_DOMAIN_GTT, + AMDGPU_GEM_CREATE_CPU_GTT_USWC, + &bo_mc, &va_handle); + + r = gpu_mem_free(bo, va_handle, bo_mc, 4096); + CU_ASSERT_EQUAL(r, 0); + + /* Test GDS */ + bo = gpu_mem_alloc(device_handle, 1024, 0, + AMDGPU_GEM_DOMAIN_GDS, 0, + NULL, NULL); + r = gpu_mem_free(bo, NULL, 0, 4096); + CU_ASSERT_EQUAL(r, 0); + + /* Test GWS */ + bo = gpu_mem_alloc(device_handle, 1, 0, + AMDGPU_GEM_DOMAIN_GWS, 0, + NULL, NULL); + r = gpu_mem_free(bo, NULL, 0, 4096); + CU_ASSERT_EQUAL(r, 0); + + /* Test OA */ + bo = gpu_mem_alloc(device_handle, 1, 0, + AMDGPU_GEM_DOMAIN_OA, 0, + NULL, NULL); + r = gpu_mem_free(bo, NULL, 0, 4096); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_mem_fail_alloc(void) +{ + int r; + struct amdgpu_bo_alloc_request req = {0}; + amdgpu_bo_handle buf_handle; + + /* Test impossible mem allocation, 1TB */ + req.alloc_size = 0xE8D4A51000; + req.phys_alignment = 4096; + req.preferred_heap = AMDGPU_GEM_DOMAIN_VRAM; + req.flags = AMDGPU_GEM_CREATE_NO_CPU_ACCESS; + + r = amdgpu_bo_alloc(device_handle, &req, &buf_handle); + CU_ASSERT_EQUAL(r, -ENOMEM); + + if (!r) { + r = amdgpu_bo_free(buf_handle); + CU_ASSERT_EQUAL(r, 0); + } +} + +static void amdgpu_bo_find_by_cpu_mapping(void) +{ + amdgpu_bo_handle bo_handle, find_bo_handle; + amdgpu_va_handle va_handle; + void *bo_cpu; + uint64_t bo_mc_address; + uint64_t offset; + int r; + + r = amdgpu_bo_alloc_and_map(device_handle, 4096, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, + &bo_handle, &bo_cpu, + &bo_mc_address, &va_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_find_bo_by_cpu_mapping(device_handle, + bo_cpu, + 4096, + &find_bo_handle, + &offset); + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(offset, 0); + CU_ASSERT_EQUAL(bo_handle->handle, find_bo_handle->handle); + + atomic_dec(&find_bo_handle->refcount, 1); + r = amdgpu_bo_unmap_and_free(bo_handle, va_handle, + bo_mc_address, 4096); + CU_ASSERT_EQUAL(r, 0); +} diff --git a/tests/amdgpu/cp_dma_tests.c b/tests/amdgpu/cp_dma_tests.c new file mode 100644 index 0000000..e82214f --- /dev/null +++ b/tests/amdgpu/cp_dma_tests.c @@ -0,0 +1,533 @@ +/* + * Copyright 2022 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * +*/ + +#include +#include +#include +#include + +#include "CUnit/Basic.h" + +#include "amdgpu_test.h" +#include "amdgpu_drm.h" +#include "amdgpu_internal.h" + +#define IB_SIZE 4096 +#define MAX_RESOURCES 8 + +#define DMA_SIZE 4097 +#define DMA_DATA_BYTE 0xea + +static bool do_p2p; + +static amdgpu_device_handle executing_device_handle; +static uint32_t executing_device_major_version; +static uint32_t executing_device_minor_version; + +static amdgpu_device_handle peer_exporting_device_handle; +static uint32_t peer_exporting_device_major_version; +static uint32_t peer_exporting_device_minor_version; + +static amdgpu_context_handle context_handle; +static amdgpu_bo_handle ib_handle; +static uint32_t *ib_cpu; +static uint64_t ib_mc_address; +static amdgpu_va_handle ib_va_handle; +static uint32_t num_dword; + +static amdgpu_bo_handle resources[MAX_RESOURCES]; +static unsigned num_resources; + +static uint8_t* reference_data; + +static void amdgpu_cp_dma_host_to_vram(void); +static void amdgpu_cp_dma_vram_to_host(void); +static void amdgpu_cp_dma_p2p_vram_to_vram(void); +static void amdgpu_cp_dma_p2p_host_to_vram(void); +static void amdgpu_cp_dma_p2p_vram_to_host(void); + +/** + * Tests in cp dma test suite + */ +CU_TestInfo cp_dma_tests[] = { + { "CP DMA write Host to VRAM", amdgpu_cp_dma_host_to_vram }, + { "CP DMA write VRAM to Host", amdgpu_cp_dma_vram_to_host }, + + { "Peer to Peer CP DMA write VRAM to VRAM", amdgpu_cp_dma_p2p_vram_to_vram }, + { "Peer to Peer CP DMA write Host to VRAM", amdgpu_cp_dma_p2p_host_to_vram }, + { "Peer to Peer CP DMA write VRAM to Host", amdgpu_cp_dma_p2p_vram_to_host }, + CU_TEST_INFO_NULL, +}; + +struct amdgpu_cp_dma_bo{ + amdgpu_bo_handle buf_handle; + amdgpu_va_handle va_handle; + uint64_t gpu_va; + uint64_t size; +}; + +static int allocate_bo_and_va(amdgpu_device_handle dev, + uint64_t size, uint64_t alignment, + uint32_t heap, uint64_t alloc_flags, + struct amdgpu_cp_dma_bo *bo) { + struct amdgpu_bo_alloc_request request = {}; + amdgpu_bo_handle buf_handle; + amdgpu_va_handle va_handle; + uint64_t vmc_addr; + int r; + + request.alloc_size = size; + request.phys_alignment = alignment; + request.preferred_heap = heap; + request.flags = alloc_flags; + + r = amdgpu_bo_alloc(dev, &request, &buf_handle); + if (r) + goto error_bo_alloc; + + r = amdgpu_va_range_alloc(dev, amdgpu_gpu_va_range_general, + size, alignment, 0, + &vmc_addr, &va_handle, 0); + if (r) + goto error_va_alloc; + + r = amdgpu_bo_va_op(buf_handle, 0, size, vmc_addr, + AMDGPU_VM_PAGE_READABLE | + AMDGPU_VM_PAGE_WRITEABLE | + AMDGPU_VM_PAGE_EXECUTABLE, + AMDGPU_VA_OP_MAP); + if (r) + goto error_va_map; + + bo->buf_handle = buf_handle; + bo->va_handle = va_handle; + bo->gpu_va = vmc_addr; + bo->size = size; + + return 0; + +error_va_map: + amdgpu_bo_va_op(buf_handle, 0, + size, vmc_addr, 0, AMDGPU_VA_OP_UNMAP); + +error_va_alloc: + amdgpu_va_range_free(va_handle); + +error_bo_alloc: + amdgpu_bo_free(buf_handle); + + return r; +} + +static int import_dma_buf_to_bo(amdgpu_device_handle dev, + int dmabuf_fd, struct amdgpu_cp_dma_bo *bo) { + amdgpu_va_handle va_handle; + uint64_t vmc_addr; + int r; + struct amdgpu_bo_import_result bo_import_result = {}; + + r = amdgpu_bo_import(dev, amdgpu_bo_handle_type_dma_buf_fd, + dmabuf_fd, &bo_import_result); + if (r) + goto error_bo_import; + + r = amdgpu_va_range_alloc(dev, amdgpu_gpu_va_range_general, + bo_import_result.alloc_size, 0, 0, + &vmc_addr, &va_handle, 0); + if (r) + goto error_va_alloc; + + r = amdgpu_bo_va_op(bo_import_result.buf_handle, 0, + bo_import_result.alloc_size, vmc_addr, + AMDGPU_VM_PAGE_READABLE | + AMDGPU_VM_PAGE_WRITEABLE | + AMDGPU_VM_PAGE_EXECUTABLE, + AMDGPU_VA_OP_MAP); + if (r) + goto error_va_map; + + bo->buf_handle = bo_import_result.buf_handle; + bo->va_handle = va_handle; + bo->gpu_va = vmc_addr; + bo->size = bo_import_result.alloc_size; + + return 0; + +error_va_map: + amdgpu_bo_va_op(bo_import_result.buf_handle, 0, + bo_import_result.alloc_size, vmc_addr, 0, AMDGPU_VA_OP_UNMAP); + +error_va_alloc: + amdgpu_va_range_free(va_handle); + +error_bo_import: + amdgpu_bo_free(bo_import_result.buf_handle); + + return r; +} + +static int free_bo(struct amdgpu_cp_dma_bo bo) { + int r; + r = amdgpu_bo_va_op(bo.buf_handle, 0, + bo.size, bo.gpu_va, 0, AMDGPU_VA_OP_UNMAP); + if(r) + return r; + + r = amdgpu_va_range_free(bo.va_handle); + if(r) + return r; + + r = amdgpu_bo_free(bo.buf_handle); + if(r) + return r; + + return 0; +} + +static int submit_and_sync() { + struct amdgpu_cs_request ibs_request = {0}; + struct amdgpu_cs_ib_info ib_info = {0}; + struct amdgpu_cs_fence fence_status = {0}; + uint32_t expired; + uint32_t family_id, chip_id, chip_rev; + unsigned gc_ip_type; + int r; + + r = amdgpu_bo_list_create(executing_device_handle, + num_resources, resources, + NULL, &ibs_request.resources); + if (r) + return r; + + family_id = executing_device_handle->info.family_id; + chip_id = executing_device_handle->info.chip_external_rev; + chip_rev = executing_device_handle->info.chip_rev; + + gc_ip_type = (asic_is_gfx_pipe_removed(family_id, chip_id, chip_rev)) ? + AMDGPU_HW_IP_COMPUTE : AMDGPU_HW_IP_GFX; + + ib_info.ib_mc_address = ib_mc_address; + ib_info.size = num_dword; + + ibs_request.ip_type = gc_ip_type; + ibs_request.number_of_ibs = 1; + ibs_request.ibs = &ib_info; + ibs_request.fence_info.handle = NULL; + + r = amdgpu_cs_submit(context_handle, 0, &ibs_request, 1); + if (r) + return r; + + r = amdgpu_bo_list_destroy(ibs_request.resources); + if (r) + return r; + + fence_status.context = context_handle; + fence_status.ip_type = gc_ip_type; + fence_status.fence = ibs_request.seq_no; + + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE, + 0, &expired); + if (r) + return r; + + return 0; +} + +static void cp_dma_cmd(struct amdgpu_cp_dma_bo src_bo, + struct amdgpu_cp_dma_bo dst_bo) { + _Static_assert(DMA_SIZE < (1 << 26), "DMA size exceeds CP DMA maximium!"); + + ib_cpu[0] = 0xc0055000; + ib_cpu[1] = 0x80000000; + ib_cpu[2] = src_bo.gpu_va & 0x00000000ffffffff; + ib_cpu[3] = (src_bo.gpu_va & 0xffffffff00000000) >> 32; + ib_cpu[4] = dst_bo.gpu_va & 0x00000000ffffffff; + ib_cpu[5] = (dst_bo.gpu_va & 0xffffffff00000000) >> 32; + // size is read from the lower 26bits. + ib_cpu[6] = ((1 << 26) - 1) & DMA_SIZE; + ib_cpu[7] = 0xffff1000; + + num_dword = 8; + + resources[0] = src_bo.buf_handle; + resources[1] = dst_bo.buf_handle; + resources[2] = ib_handle; + num_resources = 3; +} + +static void amdgpu_cp_dma(uint32_t src_heap, uint32_t dst_heap) { + int r; + struct amdgpu_cp_dma_bo src_bo = {0}; + struct amdgpu_cp_dma_bo dst_bo = {0}; + void *src_bo_cpu; + void *dst_bo_cpu; + + /* allocate the src bo, set its data to DMA_DATA_BYTE */ + r = allocate_bo_and_va(executing_device_handle, DMA_SIZE, 4096, + src_heap, AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, &src_bo); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_cpu_map(src_bo.buf_handle, (void **)&src_bo_cpu); + CU_ASSERT_EQUAL(r, 0); + memset(src_bo_cpu, DMA_DATA_BYTE, DMA_SIZE); + + r = amdgpu_bo_cpu_unmap(src_bo.buf_handle); + CU_ASSERT_EQUAL(r, 0); + + /* allocate the dst bo and clear its content to all 0 */ + r = allocate_bo_and_va(executing_device_handle, DMA_SIZE, 4096, + dst_heap, AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, &dst_bo); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_cpu_map(dst_bo.buf_handle, (void **)&dst_bo_cpu); + CU_ASSERT_EQUAL(r, 0); + + _Static_assert(DMA_DATA_BYTE != 0, "Initialization data should be different from DMA data!"); + memset(dst_bo_cpu, 0, DMA_SIZE); + + /* record CP DMA command and dispatch the command */ + cp_dma_cmd(src_bo, dst_bo); + + r = submit_and_sync(); + CU_ASSERT_EQUAL(r, 0); + + /* verify the dst bo is filled with DMA_DATA_BYTE */ + CU_ASSERT_EQUAL(memcmp(dst_bo_cpu, reference_data, DMA_SIZE) == 0, true); + + r = amdgpu_bo_cpu_unmap(dst_bo.buf_handle); + CU_ASSERT_EQUAL(r, 0); + + r = free_bo(src_bo); + CU_ASSERT_EQUAL(r, 0); + + r = free_bo(dst_bo); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_cp_dma_p2p(uint32_t src_heap, uint32_t dst_heap) { + int r; + struct amdgpu_cp_dma_bo exported_bo = {0}; + int dma_buf_fd; + int dma_buf_fd_dup; + struct amdgpu_cp_dma_bo src_bo = {0}; + struct amdgpu_cp_dma_bo imported_dst_bo = {0}; + void *exported_bo_cpu; + void *src_bo_cpu; + + /* allocate a bo on the peer device and export it to dma-buf */ + r = allocate_bo_and_va(peer_exporting_device_handle, DMA_SIZE, 4096, + src_heap, AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, &exported_bo); + CU_ASSERT_EQUAL(r, 0); + + /* map the exported bo and clear its content to 0 */ + _Static_assert(DMA_DATA_BYTE != 0, "Initialization data should be different from DMA data!"); + r = amdgpu_bo_cpu_map(exported_bo.buf_handle, (void **)&exported_bo_cpu); + CU_ASSERT_EQUAL(r, 0); + memset(exported_bo_cpu, 0, DMA_SIZE); + + r = amdgpu_bo_export(exported_bo.buf_handle, + amdgpu_bo_handle_type_dma_buf_fd, (uint32_t*)&dma_buf_fd); + CU_ASSERT_EQUAL(r, 0); + + // According to amdgpu_drm: + // "Buffer must be "imported" only using new "fd" + // (different from one used by "exporter")" + dma_buf_fd_dup = dup(dma_buf_fd); + r = close(dma_buf_fd); + CU_ASSERT_EQUAL(r, 0); + + /* import the dma-buf to the executing device, imported bo is the DMA destination */ + r = import_dma_buf_to_bo( + executing_device_handle, dma_buf_fd_dup, &imported_dst_bo); + CU_ASSERT_EQUAL(r, 0); + + r = close(dma_buf_fd_dup); + CU_ASSERT_EQUAL(r, 0); + + /* allocate the src bo and set its content to DMA_DATA_BYTE */ + r = allocate_bo_and_va(executing_device_handle, DMA_SIZE, 4096, + dst_heap, AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, &src_bo); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_cpu_map(src_bo.buf_handle, (void **)&src_bo_cpu); + CU_ASSERT_EQUAL(r, 0); + + memset(src_bo_cpu, DMA_DATA_BYTE, DMA_SIZE); + + r = amdgpu_bo_cpu_unmap(src_bo.buf_handle); + CU_ASSERT_EQUAL(r, 0); + + /* record CP DMA command and dispatch the command */ + cp_dma_cmd(src_bo, imported_dst_bo); + + r = submit_and_sync(); + CU_ASSERT_EQUAL(r, 0); + + /* verify the bo from the peer device is filled with DMA_DATA_BYTE */ + CU_ASSERT_EQUAL(memcmp(exported_bo_cpu, reference_data, DMA_SIZE) == 0, true); + + r = amdgpu_bo_cpu_unmap(exported_bo.buf_handle); + CU_ASSERT_EQUAL(r, 0); + + r = free_bo(exported_bo); + CU_ASSERT_EQUAL(r, 0); + + r = free_bo(imported_dst_bo); + CU_ASSERT_EQUAL(r, 0); + + r = free_bo(src_bo); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_cp_dma_host_to_vram(void) { + amdgpu_cp_dma(AMDGPU_GEM_DOMAIN_GTT, AMDGPU_GEM_DOMAIN_VRAM); +} + +static void amdgpu_cp_dma_vram_to_host(void) { + amdgpu_cp_dma(AMDGPU_GEM_DOMAIN_VRAM, AMDGPU_GEM_DOMAIN_GTT); +} + +static void amdgpu_cp_dma_p2p_vram_to_vram(void) { + amdgpu_cp_dma_p2p(AMDGPU_GEM_DOMAIN_VRAM, AMDGPU_GEM_DOMAIN_VRAM); +} + +static void amdgpu_cp_dma_p2p_host_to_vram(void) { + amdgpu_cp_dma_p2p(AMDGPU_GEM_DOMAIN_GTT, AMDGPU_GEM_DOMAIN_VRAM); +} + +static void amdgpu_cp_dma_p2p_vram_to_host(void) { + amdgpu_cp_dma_p2p(AMDGPU_GEM_DOMAIN_VRAM, AMDGPU_GEM_DOMAIN_GTT); +} + +int suite_cp_dma_tests_init() { + int r; + + r = amdgpu_device_initialize(drm_amdgpu[0], + &executing_device_major_version, + &executing_device_minor_version, + &executing_device_handle); + if (r) + return CUE_SINIT_FAILED; + + r = amdgpu_cs_ctx_create(executing_device_handle, &context_handle); + if (r) + return CUE_SINIT_FAILED; + + r = amdgpu_bo_alloc_and_map(executing_device_handle, IB_SIZE, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, + &ib_handle, (void**)&ib_cpu, + &ib_mc_address, &ib_va_handle); + if (r) + return CUE_SINIT_FAILED; + + if (do_p2p) { + r = amdgpu_device_initialize(drm_amdgpu[1], + &peer_exporting_device_major_version, + &peer_exporting_device_minor_version, + &peer_exporting_device_handle); + + if (r) + return CUE_SINIT_FAILED; + } + + reference_data = (uint8_t*)malloc(DMA_SIZE); + if (!reference_data) + return CUE_SINIT_FAILED; + memset(reference_data, DMA_DATA_BYTE, DMA_SIZE); + + return CUE_SUCCESS; +} + +int suite_cp_dma_tests_clean() { + int r; + + free(reference_data); + + r = amdgpu_bo_unmap_and_free(ib_handle, ib_va_handle, + ib_mc_address, IB_SIZE); + if (r) + return CUE_SCLEAN_FAILED; + + r = amdgpu_cs_ctx_free(context_handle); + if (r) + return CUE_SCLEAN_FAILED; + + r = amdgpu_device_deinitialize(executing_device_handle); + if (r) + return CUE_SCLEAN_FAILED; + + if (do_p2p) { + r = amdgpu_device_deinitialize(peer_exporting_device_handle); + if (r) + return CUE_SCLEAN_FAILED; + } + + return CUE_SUCCESS; +} + +CU_BOOL suite_cp_dma_tests_enable(void) { + int r = 0; + + if (amdgpu_device_initialize(drm_amdgpu[0], + &executing_device_major_version, + &executing_device_minor_version, + &executing_device_handle)) + return CU_FALSE; + + if (!(executing_device_handle->info.family_id >= AMDGPU_FAMILY_AI && + executing_device_handle->info.family_id <= AMDGPU_FAMILY_NV)) { + printf("Testing device has ASIC that is not supported by CP-DMA test suite!\n"); + return CU_FALSE; + } + + if (amdgpu_device_deinitialize(executing_device_handle)) + return CU_FALSE; + + if (drm_amdgpu[1] >= 0) { + r = amdgpu_device_initialize(drm_amdgpu[1], + &peer_exporting_device_major_version, + &peer_exporting_device_minor_version, + &peer_exporting_device_handle); + + if (r == 0 && (peer_exporting_device_handle->info.family_id >= AMDGPU_FAMILY_AI && + peer_exporting_device_handle->info.family_id <= AMDGPU_FAMILY_NV)) { + do_p2p = true; + } + + if (r == 0 && amdgpu_device_deinitialize(peer_exporting_device_handle) != 0) { + printf("Deinitialize peer_exporting_device_handle failed!\n"); + return CU_FALSE; + } + } + + if (!do_p2p) { + amdgpu_set_test_active("CP DMA Tests", "Peer to Peer CP DMA write VRAM to VRAM", CU_FALSE); + amdgpu_set_test_active("CP DMA Tests", "Peer to Peer CP DMA write Host to VRAM", CU_FALSE); + amdgpu_set_test_active("CP DMA Tests", "Peer to Peer CP DMA write VRAM to Host", CU_FALSE); + printf("Peer device is not opened or has ASIC not supported by the suite, skip all Peer to Peer tests.\n"); + } + + return CU_TRUE; +} diff --git a/tests/amdgpu/cs_tests.c b/tests/amdgpu/cs_tests.c new file mode 100644 index 0000000..f509678 --- /dev/null +++ b/tests/amdgpu/cs_tests.c @@ -0,0 +1,471 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * +*/ + +#include + +#include "CUnit/Basic.h" + +#include "util_math.h" + +#include "amdgpu_test.h" +#include "decode_messages.h" +#include "amdgpu_drm.h" +#include "amdgpu_internal.h" + +#define IB_SIZE 4096 +#define MAX_RESOURCES 16 + +static amdgpu_device_handle device_handle; +static uint32_t major_version; +static uint32_t minor_version; +static uint32_t family_id; +static uint32_t chip_rev; +static uint32_t chip_id; + +static amdgpu_context_handle context_handle; +static amdgpu_bo_handle ib_handle; +static uint64_t ib_mc_address; +static uint32_t *ib_cpu; +static amdgpu_va_handle ib_va_handle; + +static amdgpu_bo_handle resources[MAX_RESOURCES]; +static unsigned num_resources; + +static void amdgpu_cs_uvd_create(void); +static void amdgpu_cs_uvd_decode(void); +static void amdgpu_cs_uvd_destroy(void); + +CU_TestInfo cs_tests[] = { + { "UVD create", amdgpu_cs_uvd_create }, + { "UVD decode", amdgpu_cs_uvd_decode }, + { "UVD destroy", amdgpu_cs_uvd_destroy }, + CU_TEST_INFO_NULL, +}; + +CU_BOOL suite_cs_tests_enable(void) +{ + if (amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle)) + return CU_FALSE; + + family_id = device_handle->info.family_id; + chip_id = device_handle->info.chip_external_rev; + chip_rev = device_handle->info.chip_rev; + + if (amdgpu_device_deinitialize(device_handle)) + return CU_FALSE; + + + if (family_id >= AMDGPU_FAMILY_RV || family_id == AMDGPU_FAMILY_SI || + asic_is_gfx_pipe_removed(family_id, chip_id, chip_rev)) { + printf("\n\nThe ASIC NOT support UVD, suite disabled\n"); + return CU_FALSE; + } + + return CU_TRUE; +} + +int suite_cs_tests_init(void) +{ + amdgpu_bo_handle ib_result_handle; + void *ib_result_cpu; + uint64_t ib_result_mc_address; + amdgpu_va_handle ib_result_va_handle; + int r; + + r = amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle); + if (r) { + if ((r == -EACCES) && (errno == EACCES)) + printf("\n\nError:%s. " + "Hint:Try to run this test program as root.", + strerror(errno)); + + return CUE_SINIT_FAILED; + } + + family_id = device_handle->info.family_id; + /* VI asic POLARIS10/11 have specific external_rev_id */ + chip_rev = device_handle->info.chip_rev; + chip_id = device_handle->info.chip_external_rev; + + r = amdgpu_cs_ctx_create(device_handle, &context_handle); + if (r) + return CUE_SINIT_FAILED; + + r = amdgpu_bo_alloc_and_map(device_handle, IB_SIZE, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, + &ib_result_handle, &ib_result_cpu, + &ib_result_mc_address, + &ib_result_va_handle); + if (r) + return CUE_SINIT_FAILED; + + ib_handle = ib_result_handle; + ib_mc_address = ib_result_mc_address; + ib_cpu = ib_result_cpu; + ib_va_handle = ib_result_va_handle; + + return CUE_SUCCESS; +} + +int suite_cs_tests_clean(void) +{ + int r; + + r = amdgpu_bo_unmap_and_free(ib_handle, ib_va_handle, + ib_mc_address, IB_SIZE); + if (r) + return CUE_SCLEAN_FAILED; + + r = amdgpu_cs_ctx_free(context_handle); + if (r) + return CUE_SCLEAN_FAILED; + + r = amdgpu_device_deinitialize(device_handle); + if (r) + return CUE_SCLEAN_FAILED; + + return CUE_SUCCESS; +} + +static int submit(unsigned ndw, unsigned ip) +{ + struct amdgpu_cs_request ibs_request = {0}; + struct amdgpu_cs_ib_info ib_info = {0}; + struct amdgpu_cs_fence fence_status = {0}; + uint32_t expired; + int r; + + ib_info.ib_mc_address = ib_mc_address; + ib_info.size = ndw; + + ibs_request.ip_type = ip; + + r = amdgpu_bo_list_create(device_handle, num_resources, resources, + NULL, &ibs_request.resources); + if (r) + return r; + + ibs_request.number_of_ibs = 1; + ibs_request.ibs = &ib_info; + ibs_request.fence_info.handle = NULL; + + r = amdgpu_cs_submit(context_handle, 0, &ibs_request, 1); + if (r) + return r; + + r = amdgpu_bo_list_destroy(ibs_request.resources); + if (r) + return r; + + fence_status.context = context_handle; + fence_status.ip_type = ip; + fence_status.fence = ibs_request.seq_no; + + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE, + 0, &expired); + if (r) + return r; + + return 0; +} + +static void uvd_cmd(uint64_t addr, unsigned cmd, int *idx) +{ + ib_cpu[(*idx)++] = (family_id < AMDGPU_FAMILY_AI) ? 0x3BC4 : 0x81C4; + ib_cpu[(*idx)++] = addr; + ib_cpu[(*idx)++] = (family_id < AMDGPU_FAMILY_AI) ? 0x3BC5 : 0x81C5; + ib_cpu[(*idx)++] = addr >> 32; + ib_cpu[(*idx)++] = (family_id < AMDGPU_FAMILY_AI) ? 0x3BC3 : 0x81C3; + ib_cpu[(*idx)++] = cmd << 1; +} + +static void amdgpu_cs_uvd_create(void) +{ + struct amdgpu_bo_alloc_request req = {0}; + amdgpu_bo_handle buf_handle; + uint64_t va = 0; + amdgpu_va_handle va_handle; + void *msg; + int i, r; + + req.alloc_size = 4*1024; + req.preferred_heap = AMDGPU_GEM_DOMAIN_GTT; + + r = amdgpu_bo_alloc(device_handle, &req, &buf_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_va_range_alloc(device_handle, + amdgpu_gpu_va_range_general, + 4096, 1, 0, &va, + &va_handle, 0); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_va_op(buf_handle, 0, 4096, va, 0, AMDGPU_VA_OP_MAP); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_cpu_map(buf_handle, &msg); + CU_ASSERT_EQUAL(r, 0); + + memcpy(msg, uvd_create_msg, sizeof(uvd_create_msg)); + + if (family_id >= AMDGPU_FAMILY_VI) { + ((uint8_t*)msg)[0x10] = 7; + /* chip beyond polaris 10/11 */ + if ((family_id == AMDGPU_FAMILY_AI) || + (chip_id == chip_rev+0x50 || chip_id == chip_rev+0x5A || + chip_id == chip_rev+0x64)) { + /* dpb size */ + ((uint8_t*)msg)[0x28] = 0x00; + ((uint8_t*)msg)[0x29] = 0x94; + ((uint8_t*)msg)[0x2A] = 0x6B; + ((uint8_t*)msg)[0x2B] = 0x00; + } + } + + r = amdgpu_bo_cpu_unmap(buf_handle); + CU_ASSERT_EQUAL(r, 0); + + num_resources = 0; + resources[num_resources++] = buf_handle; + resources[num_resources++] = ib_handle; + + i = 0; + uvd_cmd(va, 0x0, &i); + for (; i % 16; ++i) + ib_cpu[i] = 0x80000000; + + r = submit(i, AMDGPU_HW_IP_UVD); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_va_op(buf_handle, 0, 4096, va, 0, AMDGPU_VA_OP_UNMAP); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_va_range_free(va_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_free(buf_handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_cs_uvd_decode(void) +{ + const unsigned dpb_size = 15923584, dt_size = 737280; + uint64_t msg_addr, fb_addr, bs_addr, dpb_addr, ctx_addr, dt_addr, it_addr; + struct amdgpu_bo_alloc_request req = {0}; + amdgpu_bo_handle buf_handle; + amdgpu_va_handle va_handle; + uint64_t va = 0; + uint64_t sum; + uint8_t *ptr; + int i, r; + + req.alloc_size = 4*1024; /* msg */ + req.alloc_size += 4*1024; /* fb */ + if (family_id >= AMDGPU_FAMILY_VI) + req.alloc_size += 4096; /*it_scaling_table*/ + req.alloc_size += ALIGN(sizeof(uvd_bitstream), 4*1024); + req.alloc_size += ALIGN(dpb_size, 4*1024); + req.alloc_size += ALIGN(dt_size, 4*1024); + + req.preferred_heap = AMDGPU_GEM_DOMAIN_GTT; + + r = amdgpu_bo_alloc(device_handle, &req, &buf_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_va_range_alloc(device_handle, + amdgpu_gpu_va_range_general, + req.alloc_size, 1, 0, &va, + &va_handle, 0); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_va_op(buf_handle, 0, req.alloc_size, va, 0, + AMDGPU_VA_OP_MAP); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_cpu_map(buf_handle, (void **)&ptr); + CU_ASSERT_EQUAL(r, 0); + + memcpy(ptr, uvd_decode_msg, sizeof(uvd_decode_msg)); + memcpy(ptr + sizeof(uvd_decode_msg), avc_decode_msg, sizeof(avc_decode_msg)); + + if (family_id >= AMDGPU_FAMILY_VI) { + ptr[0x10] = 7; + ptr[0x98] = 0x00; + ptr[0x99] = 0x02; + /* chip beyond polaris10/11 */ + if ((family_id == AMDGPU_FAMILY_AI) || + (chip_id == chip_rev+0x50 || chip_id == chip_rev+0x5A || + chip_id == chip_rev+0x64)) { + /* dpb size */ + ptr[0x24] = 0x00; + ptr[0x25] = 0x94; + ptr[0x26] = 0x6B; + ptr[0x27] = 0x00; + /*ctx size */ + ptr[0x2C] = 0x00; + ptr[0x2D] = 0xAF; + ptr[0x2E] = 0x50; + ptr[0x2F] = 0x00; + } + } + + ptr += 4*1024; + memset(ptr, 0, 4*1024); + if (family_id >= AMDGPU_FAMILY_VI) { + ptr += 4*1024; + memcpy(ptr, uvd_it_scaling_table, sizeof(uvd_it_scaling_table)); + } + + ptr += 4*1024; + memcpy(ptr, uvd_bitstream, sizeof(uvd_bitstream)); + + ptr += ALIGN(sizeof(uvd_bitstream), 4*1024); + memset(ptr, 0, dpb_size); + + ptr += ALIGN(dpb_size, 4*1024); + memset(ptr, 0, dt_size); + + num_resources = 0; + resources[num_resources++] = buf_handle; + resources[num_resources++] = ib_handle; + + msg_addr = va; + fb_addr = msg_addr + 4*1024; + if (family_id >= AMDGPU_FAMILY_VI) { + it_addr = fb_addr + 4*1024; + bs_addr = it_addr + 4*1024; + } else + bs_addr = fb_addr + 4*1024; + dpb_addr = ALIGN(bs_addr + sizeof(uvd_bitstream), 4*1024); + + ctx_addr = 0; + if (family_id >= AMDGPU_FAMILY_VI) { + if ((family_id == AMDGPU_FAMILY_AI) || + (chip_id == chip_rev+0x50 || chip_id == chip_rev+0x5A || + chip_id == chip_rev+0x64)) { + ctx_addr = ALIGN(dpb_addr + 0x006B9400, 4*1024); + } + } + + dt_addr = ALIGN(dpb_addr + dpb_size, 4*1024); + + i = 0; + uvd_cmd(msg_addr, 0x0, &i); + uvd_cmd(dpb_addr, 0x1, &i); + uvd_cmd(dt_addr, 0x2, &i); + uvd_cmd(fb_addr, 0x3, &i); + uvd_cmd(bs_addr, 0x100, &i); + + if (family_id >= AMDGPU_FAMILY_VI) { + uvd_cmd(it_addr, 0x204, &i); + if ((family_id == AMDGPU_FAMILY_AI) || + (chip_id == chip_rev+0x50 || chip_id == chip_rev+0x5A || + chip_id == chip_rev+0x64)) + uvd_cmd(ctx_addr, 0x206, &i); + } + + ib_cpu[i++] = (family_id < AMDGPU_FAMILY_AI) ? 0x3BC6 : 0x81C6; + ib_cpu[i++] = 0x1; + for (; i % 16; ++i) + ib_cpu[i] = 0x80000000; + + r = submit(i, AMDGPU_HW_IP_UVD); + CU_ASSERT_EQUAL(r, 0); + + /* TODO: use a real CRC32 */ + for (i = 0, sum = 0; i < dt_size; ++i) + sum += ptr[i]; + CU_ASSERT_EQUAL(sum, SUM_DECODE); + + r = amdgpu_bo_cpu_unmap(buf_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_va_op(buf_handle, 0, req.alloc_size, va, 0, AMDGPU_VA_OP_UNMAP); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_va_range_free(va_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_free(buf_handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_cs_uvd_destroy(void) +{ + struct amdgpu_bo_alloc_request req = {0}; + amdgpu_bo_handle buf_handle; + amdgpu_va_handle va_handle; + uint64_t va = 0; + void *msg; + int i, r; + + req.alloc_size = 4*1024; + req.preferred_heap = AMDGPU_GEM_DOMAIN_GTT; + + r = amdgpu_bo_alloc(device_handle, &req, &buf_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_va_range_alloc(device_handle, + amdgpu_gpu_va_range_general, + req.alloc_size, 1, 0, &va, + &va_handle, 0); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_va_op(buf_handle, 0, req.alloc_size, va, 0, + AMDGPU_VA_OP_MAP); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_cpu_map(buf_handle, &msg); + CU_ASSERT_EQUAL(r, 0); + + memcpy(msg, uvd_destroy_msg, sizeof(uvd_destroy_msg)); + if (family_id >= AMDGPU_FAMILY_VI) + ((uint8_t*)msg)[0x10] = 7; + + r = amdgpu_bo_cpu_unmap(buf_handle); + CU_ASSERT_EQUAL(r, 0); + + num_resources = 0; + resources[num_resources++] = buf_handle; + resources[num_resources++] = ib_handle; + + i = 0; + uvd_cmd(va, 0x0, &i); + for (; i % 16; ++i) + ib_cpu[i] = 0x80000000; + + r = submit(i, AMDGPU_HW_IP_UVD); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_va_op(buf_handle, 0, req.alloc_size, va, 0, AMDGPU_VA_OP_UNMAP); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_va_range_free(va_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_free(buf_handle); + CU_ASSERT_EQUAL(r, 0); +} diff --git a/tests/amdgpu/deadlock_tests.c b/tests/amdgpu/deadlock_tests.c new file mode 100644 index 0000000..2928233 --- /dev/null +++ b/tests/amdgpu/deadlock_tests.c @@ -0,0 +1,696 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * +*/ + +#include +#include +#include +#if HAVE_ALLOCA_H +# include +#endif + +#include "CUnit/Basic.h" + +#include "amdgpu_test.h" +#include "amdgpu_drm.h" +#include "amdgpu_internal.h" + +#include + + +/* + * This defines the delay in MS after which memory location designated for + * compression against reference value is written to, unblocking command + * processor + */ +#define WRITE_MEM_ADDRESS_DELAY_MS 100 + +#define PACKET_TYPE3 3 + +#define PACKET3(op, n) ((PACKET_TYPE3 << 30) | \ + (((op) & 0xFF) << 8) | \ + ((n) & 0x3FFF) << 16) + +#define PACKET3_WAIT_REG_MEM 0x3C +#define WAIT_REG_MEM_FUNCTION(x) ((x) << 0) + /* 0 - always + * 1 - < + * 2 - <= + * 3 - == + * 4 - != + * 5 - >= + * 6 - > + */ +#define WAIT_REG_MEM_MEM_SPACE(x) ((x) << 4) + /* 0 - reg + * 1 - mem + */ +#define WAIT_REG_MEM_OPERATION(x) ((x) << 6) + /* 0 - wait_reg_mem + * 1 - wr_wait_wr_reg + */ +#define WAIT_REG_MEM_ENGINE(x) ((x) << 8) + /* 0 - me + * 1 - pfp + */ + +#define PACKET3_WRITE_DATA 0x37 +#define WRITE_DATA_DST_SEL(x) ((x) << 8) + /* 0 - register + * 1 - memory (sync - via GRBM) + * 2 - gl2 + * 3 - gds + * 4 - reserved + * 5 - memory (async - direct) + */ +#define WR_ONE_ADDR (1 << 16) +#define WR_CONFIRM (1 << 20) +#define WRITE_DATA_CACHE_POLICY(x) ((x) << 25) + /* 0 - LRU + * 1 - Stream + */ +#define WRITE_DATA_ENGINE_SEL(x) ((x) << 30) + /* 0 - me + * 1 - pfp + * 2 - ce + */ + +#define mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR 0x54f + +#define SDMA_PKT_HEADER_OP(x) (x & 0xff) +#define SDMA_OP_POLL_REGMEM 8 + +static amdgpu_device_handle device_handle; +static uint32_t major_version; +static uint32_t minor_version; + +static pthread_t stress_thread; +static uint32_t *ptr; + +static uint32_t family_id; +static uint32_t chip_rev; +static uint32_t chip_id; + +int use_uc_mtype = 0; + +static void amdgpu_deadlock_helper(unsigned ip_type); +static void amdgpu_deadlock_gfx(void); +static void amdgpu_deadlock_compute(void); +static void amdgpu_illegal_reg_access(); +static void amdgpu_illegal_mem_access(); +static void amdgpu_deadlock_sdma(void); +static void amdgpu_dispatch_hang_gfx(void); +static void amdgpu_dispatch_hang_compute(void); +static void amdgpu_dispatch_hang_slow_gfx(void); +static void amdgpu_dispatch_hang_slow_compute(void); +static void amdgpu_draw_hang_gfx(void); +static void amdgpu_draw_hang_slow_gfx(void); +static void amdgpu_hang_sdma(void); +static void amdgpu_hang_slow_sdma(void); + +CU_BOOL suite_deadlock_tests_enable(void) +{ + CU_BOOL enable = CU_TRUE; + + if (amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle)) + return CU_FALSE; + + family_id = device_handle->info.family_id; + chip_id = device_handle->info.chip_external_rev; + chip_rev = device_handle->info.chip_rev; + + /* + * Only enable for ASICs supporting GPU reset and for which it's enabled + * by default (currently GFX8+ dGPUS and gfx9+ APUs). Note that Raven1 + * did not support GPU reset, but newer variants do. + */ + if (family_id == AMDGPU_FAMILY_SI || + family_id == AMDGPU_FAMILY_KV || + family_id == AMDGPU_FAMILY_CZ || + family_id == AMDGPU_FAMILY_RV) { + printf("\n\nGPU reset is not enabled for the ASIC, deadlock suite disabled\n"); + enable = CU_FALSE; + } + + if (asic_is_gfx_pipe_removed(family_id, chip_id, chip_rev)) { + if (amdgpu_set_test_active("Deadlock Tests", + "gfx ring block test (set amdgpu.lockup_timeout=50)", + CU_FALSE)) + fprintf(stderr, "test deactivation failed - %s\n", + CU_get_error_msg()); + } + + if (device_handle->info.family_id >= AMDGPU_FAMILY_AI) + use_uc_mtype = 1; + + if (amdgpu_device_deinitialize(device_handle)) + return CU_FALSE; + + return enable; +} + +int suite_deadlock_tests_init(void) +{ + int r; + + r = amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle); + + if (r) { + if ((r == -EACCES) && (errno == EACCES)) + printf("\n\nError:%s. " + "Hint:Try to run this test program as root.", + strerror(errno)); + return CUE_SINIT_FAILED; + } + + return CUE_SUCCESS; +} + +int suite_deadlock_tests_clean(void) +{ + int r = amdgpu_device_deinitialize(device_handle); + + if (r == 0) + return CUE_SUCCESS; + else + return CUE_SCLEAN_FAILED; +} + + +CU_TestInfo deadlock_tests[] = { + { "gfx ring block test (set amdgpu.lockup_timeout=50)", amdgpu_deadlock_gfx }, + { "compute ring block test (set amdgpu.lockup_timeout=50)", amdgpu_deadlock_compute }, + { "sdma ring block test (set amdgpu.lockup_timeout=50)", amdgpu_deadlock_sdma }, + { "illegal reg access test", amdgpu_illegal_reg_access }, + { "illegal mem access test (set amdgpu.vm_fault_stop=2)", amdgpu_illegal_mem_access }, + { "gfx ring bad dispatch test (set amdgpu.lockup_timeout=50)", amdgpu_dispatch_hang_gfx }, + { "compute ring bad dispatch test (set amdgpu.lockup_timeout=50,50)", amdgpu_dispatch_hang_compute }, + { "gfx ring bad slow dispatch test (set amdgpu.lockup_timeout=50)", amdgpu_dispatch_hang_slow_gfx }, + { "compute ring bad slow dispatch test (set amdgpu.lockup_timeout=50,50)", amdgpu_dispatch_hang_slow_compute }, + { "gfx ring bad draw test (set amdgpu.lockup_timeout=50)", amdgpu_draw_hang_gfx }, + { "gfx ring slow bad draw test (set amdgpu.lockup_timeout=50)", amdgpu_draw_hang_slow_gfx }, + { "sdma ring corrupted header test (set amdgpu.lockup_timeout=50)", amdgpu_hang_sdma }, + { "sdma ring slow linear copy test (set amdgpu.lockup_timeout=50)", amdgpu_hang_slow_sdma }, + CU_TEST_INFO_NULL, +}; + +static void *write_mem_address(void *data) +{ + int i; + + /* useconds_t range is [0, 1,000,000] so use loop for waits > 1s */ + for (i = 0; i < WRITE_MEM_ADDRESS_DELAY_MS; i++) + usleep(1000); + + ptr[256] = 0x1; + + return 0; +} + +static void amdgpu_deadlock_gfx(void) +{ + amdgpu_deadlock_helper(AMDGPU_HW_IP_GFX); +} + +static void amdgpu_deadlock_compute(void) +{ + amdgpu_deadlock_helper(AMDGPU_HW_IP_COMPUTE); +} + +static void amdgpu_deadlock_helper(unsigned ip_type) +{ + amdgpu_context_handle context_handle; + amdgpu_bo_handle ib_result_handle; + void *ib_result_cpu; + uint64_t ib_result_mc_address; + struct amdgpu_cs_request ibs_request; + struct amdgpu_cs_ib_info ib_info; + struct amdgpu_cs_fence fence_status; + uint32_t expired; + int i, r; + amdgpu_bo_list_handle bo_list; + amdgpu_va_handle va_handle; + + r = pthread_create(&stress_thread, NULL, write_mem_address, NULL); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_ctx_create(device_handle, &context_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_alloc_and_map_raw(device_handle, 4096, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, use_uc_mtype ? AMDGPU_VM_MTYPE_UC : 0, + &ib_result_handle, &ib_result_cpu, + &ib_result_mc_address, &va_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_get_bo_list(device_handle, ib_result_handle, NULL, + &bo_list); + CU_ASSERT_EQUAL(r, 0); + + ptr = ib_result_cpu; + + ptr[0] = PACKET3(PACKET3_WAIT_REG_MEM, 5); + ptr[1] = (WAIT_REG_MEM_MEM_SPACE(1) | /* memory */ + WAIT_REG_MEM_FUNCTION(4) | /* != */ + WAIT_REG_MEM_ENGINE(0)); /* me */ + ptr[2] = (ib_result_mc_address + 256*4) & 0xfffffffc; + ptr[3] = ((ib_result_mc_address + 256*4) >> 32) & 0xffffffff; + ptr[4] = 0x00000000; /* reference value */ + ptr[5] = 0xffffffff; /* and mask */ + ptr[6] = 0x00000004; /* poll interval */ + + for (i = 7; i < 16; ++i) + ptr[i] = 0xffff1000; + + + ptr[256] = 0x0; /* the memory we wait on to change */ + + + + memset(&ib_info, 0, sizeof(struct amdgpu_cs_ib_info)); + ib_info.ib_mc_address = ib_result_mc_address; + ib_info.size = 16; + + memset(&ibs_request, 0, sizeof(struct amdgpu_cs_request)); + ibs_request.ip_type = ip_type; + ibs_request.ring = 0; + ibs_request.number_of_ibs = 1; + ibs_request.ibs = &ib_info; + ibs_request.resources = bo_list; + ibs_request.fence_info.handle = NULL; + for (i = 0; i < 200; i++) { + r = amdgpu_cs_submit(context_handle, 0,&ibs_request, 1); + CU_ASSERT_EQUAL((r == 0 || r == -ECANCELED), 1); + + } + + memset(&fence_status, 0, sizeof(struct amdgpu_cs_fence)); + fence_status.context = context_handle; + fence_status.ip_type = ip_type; + fence_status.ip_instance = 0; + fence_status.ring = 0; + fence_status.fence = ibs_request.seq_no; + + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE,0, &expired); + CU_ASSERT_EQUAL((r == 0 || r == -ECANCELED), 1); + + pthread_join(stress_thread, NULL); + + r = amdgpu_bo_list_destroy(bo_list); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_unmap_and_free(ib_result_handle, va_handle, + ib_result_mc_address, 4096); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_deadlock_sdma(void) +{ + amdgpu_context_handle context_handle; + amdgpu_bo_handle ib_result_handle; + void *ib_result_cpu; + uint64_t ib_result_mc_address; + struct amdgpu_cs_request ibs_request; + struct amdgpu_cs_ib_info ib_info; + struct amdgpu_cs_fence fence_status; + uint32_t expired; + int i, r; + amdgpu_bo_list_handle bo_list; + amdgpu_va_handle va_handle; + struct drm_amdgpu_info_hw_ip info; + uint32_t ring_id; + + r = amdgpu_query_hw_ip_info(device_handle, AMDGPU_HW_IP_DMA, 0, &info); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_ctx_create(device_handle, &context_handle); + CU_ASSERT_EQUAL(r, 0); + + for (ring_id = 0; (1 << ring_id) & info.available_rings; ring_id++) { + r = pthread_create(&stress_thread, NULL, write_mem_address, NULL); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_alloc_and_map_raw(device_handle, 4096, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, use_uc_mtype ? AMDGPU_VM_MTYPE_UC : 0, + &ib_result_handle, &ib_result_cpu, + &ib_result_mc_address, &va_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_get_bo_list(device_handle, ib_result_handle, NULL, + &bo_list); + CU_ASSERT_EQUAL(r, 0); + + ptr = ib_result_cpu; + i = 0; + + ptr[i++] = SDMA_PKT_HEADER_OP(SDMA_OP_POLL_REGMEM) | + (0 << 26) | /* WAIT_REG_MEM */ + (4 << 28) | /* != */ + (1 << 31); /* memory */ + ptr[i++] = (ib_result_mc_address + 256*4) & 0xfffffffc; + ptr[i++] = ((ib_result_mc_address + 256*4) >> 32) & 0xffffffff; + ptr[i++] = 0x00000000; /* reference value */ + ptr[i++] = 0xffffffff; /* and mask */ + ptr[i++] = 4 | /* poll interval */ + (0xfff << 16); /* retry count */ + + for (; i < 16; i++) + ptr[i] = 0; + + ptr[256] = 0x0; /* the memory we wait on to change */ + + memset(&ib_info, 0, sizeof(struct amdgpu_cs_ib_info)); + ib_info.ib_mc_address = ib_result_mc_address; + ib_info.size = 16; + + memset(&ibs_request, 0, sizeof(struct amdgpu_cs_request)); + ibs_request.ip_type = AMDGPU_HW_IP_DMA; + ibs_request.ring = ring_id; + ibs_request.number_of_ibs = 1; + ibs_request.ibs = &ib_info; + ibs_request.resources = bo_list; + ibs_request.fence_info.handle = NULL; + + for (i = 0; i < 200; i++) { + r = amdgpu_cs_submit(context_handle, 0,&ibs_request, 1); + CU_ASSERT_EQUAL((r == 0 || r == -ECANCELED), 1); + + } + + memset(&fence_status, 0, sizeof(struct amdgpu_cs_fence)); + fence_status.context = context_handle; + fence_status.ip_type = AMDGPU_HW_IP_DMA; + fence_status.ip_instance = 0; + fence_status.ring = ring_id; + fence_status.fence = ibs_request.seq_no; + + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE,0, &expired); + CU_ASSERT_EQUAL((r == 0 || r == -ECANCELED), 1); + + pthread_join(stress_thread, NULL); + + r = amdgpu_bo_list_destroy(bo_list); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_unmap_and_free(ib_result_handle, va_handle, + ib_result_mc_address, 4096); + CU_ASSERT_EQUAL(r, 0); + } + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void bad_access_helper(int reg_access) +{ + amdgpu_context_handle context_handle; + amdgpu_bo_handle ib_result_handle; + void *ib_result_cpu; + uint64_t ib_result_mc_address; + struct amdgpu_cs_request ibs_request; + struct amdgpu_cs_ib_info ib_info; + struct amdgpu_cs_fence fence_status; + uint32_t expired; + int i, r; + amdgpu_bo_list_handle bo_list; + amdgpu_va_handle va_handle; + + r = amdgpu_cs_ctx_create(device_handle, &context_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_alloc_and_map_raw(device_handle, 4096, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, 0, + &ib_result_handle, &ib_result_cpu, + &ib_result_mc_address, &va_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_get_bo_list(device_handle, ib_result_handle, NULL, + &bo_list); + CU_ASSERT_EQUAL(r, 0); + + ptr = ib_result_cpu; + i = 0; + + ptr[i++] = PACKET3(PACKET3_WRITE_DATA, 3); + ptr[i++] = (reg_access ? WRITE_DATA_DST_SEL(0) : WRITE_DATA_DST_SEL(5))| WR_CONFIRM; + ptr[i++] = reg_access ? mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR : 0xdeadbee0; + ptr[i++] = 0; + ptr[i++] = 0xdeadbeef; + + for (; i < 16; ++i) + ptr[i] = 0xffff1000; + + memset(&ib_info, 0, sizeof(struct amdgpu_cs_ib_info)); + ib_info.ib_mc_address = ib_result_mc_address; + ib_info.size = 16; + + memset(&ibs_request, 0, sizeof(struct amdgpu_cs_request)); + ibs_request.ip_type = AMDGPU_HW_IP_GFX; + ibs_request.ring = 0; + ibs_request.number_of_ibs = 1; + ibs_request.ibs = &ib_info; + ibs_request.resources = bo_list; + ibs_request.fence_info.handle = NULL; + + r = amdgpu_cs_submit(context_handle, 0,&ibs_request, 1); + CU_ASSERT_EQUAL((r == 0 || r == -ECANCELED), 1); + + + memset(&fence_status, 0, sizeof(struct amdgpu_cs_fence)); + fence_status.context = context_handle; + fence_status.ip_type = AMDGPU_HW_IP_GFX; + fence_status.ip_instance = 0; + fence_status.ring = 0; + fence_status.fence = ibs_request.seq_no; + + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE,0, &expired); + CU_ASSERT_EQUAL((r == 0 || r == -ECANCELED), 1); + + r = amdgpu_bo_list_destroy(bo_list); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_unmap_and_free(ib_result_handle, va_handle, + ib_result_mc_address, 4096); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_illegal_reg_access() +{ + bad_access_helper(1); +} + +static void amdgpu_illegal_mem_access() +{ + bad_access_helper(0); +} + +static void amdgpu_dispatch_hang_gfx(void) +{ + amdgpu_test_dispatch_hang_helper(device_handle, AMDGPU_HW_IP_GFX); +} +static void amdgpu_dispatch_hang_compute(void) +{ + amdgpu_test_dispatch_hang_helper(device_handle, AMDGPU_HW_IP_COMPUTE); +} +static void amdgpu_dispatch_hang_slow_gfx(void) +{ + amdgpu_test_dispatch_hang_slow_helper(device_handle, AMDGPU_HW_IP_GFX); +} +static void amdgpu_dispatch_hang_slow_compute(void) +{ + amdgpu_test_dispatch_hang_slow_helper(device_handle, AMDGPU_HW_IP_COMPUTE); +} +static void amdgpu_draw_hang_gfx(void) +{ + amdgpu_test_draw_hang_helper(device_handle); +} +static void amdgpu_draw_hang_slow_gfx(void) +{ + amdgpu_test_draw_hang_slow_helper(device_handle); +} + +#define DMA_CORRUPTED_HEADER_HANG 1 +#define DMA_SLOW_LINEARCOPY_HANG 2 + +static void amdgpu_hang_sdma_helper(unsigned hang_type) +{ + const int sdma_write_length = 1024; + amdgpu_context_handle context_handle; + amdgpu_bo_handle ib_result_handle; + amdgpu_bo_handle bo1, bo2; + amdgpu_bo_handle resources[3]; + amdgpu_bo_list_handle bo_list; + void *ib_result_cpu; + struct amdgpu_cs_ib_info ib_info; + struct amdgpu_cs_request ibs_request; + struct amdgpu_cs_fence fence_status; + uint64_t bo1_mc, bo2_mc; + uint64_t ib_result_mc_address; + volatile unsigned char *bo1_cpu, *bo2_cpu; + amdgpu_va_handle bo1_va_handle, bo2_va_handle; + amdgpu_va_handle va_handle; + struct drm_amdgpu_info_hw_ip hw_ip_info; + int i, j, r; + uint32_t expired, ib_size; + + r = amdgpu_query_hw_ip_info(device_handle, AMDGPU_HW_IP_DMA, 0, &hw_ip_info); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_ctx_create(device_handle, &context_handle); + CU_ASSERT_EQUAL(r, 0); + + if (hang_type == DMA_CORRUPTED_HEADER_HANG) + ib_size = 4096; + else + ib_size = 4096 * 0x20000; + + r = amdgpu_bo_alloc_and_map(device_handle, ib_size, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, + &ib_result_handle, &ib_result_cpu, + &ib_result_mc_address, &va_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_alloc_and_map(device_handle, + sdma_write_length, 4096, + AMDGPU_GEM_DOMAIN_GTT, + 0, &bo1, + (void**)&bo1_cpu, &bo1_mc, + &bo1_va_handle); + CU_ASSERT_EQUAL(r, 0); + + /* set bo1 */ + memset((void*)bo1_cpu, 0xaa, sdma_write_length); + + /* allocate UC bo2 for sDMA use */ + r = amdgpu_bo_alloc_and_map(device_handle, + sdma_write_length, 4096, + AMDGPU_GEM_DOMAIN_GTT, + 0, &bo2, + (void**)&bo2_cpu, &bo2_mc, + &bo2_va_handle); + CU_ASSERT_EQUAL(r, 0); + + /* clear bo2 */ + memset((void*)bo2_cpu, 0, sdma_write_length); + + resources[0] = bo1; + resources[1] = bo2; + resources[2] = ib_result_handle; + r = amdgpu_bo_list_create(device_handle, 3, + resources, NULL, &bo_list); + + /* fulfill PM4: with bad copy linear header */ + ptr = ib_result_cpu; + i = 0; + if (hang_type == DMA_CORRUPTED_HEADER_HANG) { + ptr[i++] = 0x23decd3d; + ptr[i++] = sdma_write_length - 1; + ptr[i++] = 0; + ptr[i++] = 0xffffffff & bo1_mc; + ptr[i++] = (0xffffffff00000000 & bo1_mc) >> 32; + ptr[i++] = 0xffffffff & bo2_mc; + ptr[i++] = (0xffffffff00000000 & bo2_mc) >> 32; + } else { + for (j = 1; j < 0x20000; j++) { + ptr[i++] = 0x1; + ptr[i++] = sdma_write_length - 1; + ptr[i++] = 0; + ptr[i++] = 0xffffffff & bo1_mc; + ptr[i++] = (0xffffffff00000000 & bo1_mc) >> 32; + ptr[i++] = 0xffffffff & bo2_mc; + ptr[i++] = (0xffffffff00000000 & bo2_mc) >> 32; + ptr[i++] = 0x1; + ptr[i++] = sdma_write_length - 1; + ptr[i++] = 0; + ptr[i++] = 0xffffffff & bo2_mc; + ptr[i++] = (0xffffffff00000000 & bo2_mc) >> 32; + ptr[i++] = 0xffffffff & bo1_mc; + ptr[i++] = (0xffffffff00000000 & bo1_mc) >> 32; + } + } + + /* exec command */ + memset(&ib_info, 0, sizeof(struct amdgpu_cs_ib_info)); + ib_info.ib_mc_address = ib_result_mc_address; + ib_info.size = i; + + memset(&ibs_request, 0, sizeof(struct amdgpu_cs_request)); + ibs_request.ip_type = AMDGPU_HW_IP_DMA; + ibs_request.ring = 0; + ibs_request.number_of_ibs = 1; + ibs_request.ibs = &ib_info; + ibs_request.resources = bo_list; + ibs_request.fence_info.handle = NULL; + + r = amdgpu_cs_submit(context_handle, 0, &ibs_request, 1); + CU_ASSERT_EQUAL(r, 0); + + memset(&fence_status, 0, sizeof(struct amdgpu_cs_fence)); + fence_status.context = context_handle; + fence_status.ip_type = AMDGPU_HW_IP_DMA; + fence_status.ip_instance = 0; + fence_status.ring = 0; + fence_status.fence = ibs_request.seq_no; + + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE, + 0, &expired); + CU_ASSERT_EQUAL((r == 0 || r == -ECANCELED), 1); + + r = amdgpu_bo_list_destroy(bo_list); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_unmap_and_free(ib_result_handle, va_handle, + ib_result_mc_address, 4096); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_unmap_and_free(bo1, bo1_va_handle, bo1_mc, + sdma_write_length); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_unmap_and_free(bo2, bo2_va_handle, bo2_mc, + sdma_write_length); + CU_ASSERT_EQUAL(r, 0); + + /* end of test */ + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_hang_sdma(void) +{ + amdgpu_hang_sdma_helper(DMA_CORRUPTED_HEADER_HANG); +} +static void amdgpu_hang_slow_sdma(void) +{ + amdgpu_hang_sdma_helper(DMA_SLOW_LINEARCOPY_HANG); +} diff --git a/tests/amdgpu/decode_messages.h b/tests/amdgpu/decode_messages.h new file mode 100644 index 0000000..218cd77 --- /dev/null +++ b/tests/amdgpu/decode_messages.h @@ -0,0 +1,881 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 _DECODE_MESSAGES_H_ +#define _DECODE_MESSAGES_H_ + +#define SUM_DECODE 0x20345d8 + +static const uint8_t uvd_create_msg[] = { + 0xe4,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x44,0x40,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x03,0x00,0x00, + 0xe0,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xf9,0xf2,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static const uint8_t uvd_bitstream[] ={ + 0x00,0x00,0x01,0x25,0xb8,0x20,0x20,0x21,0x44,0xc5,0x00,0x01,0x57,0x9b,0xef,0xbe, + 0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb, + 0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef, + 0xbe,0xfb,0xef,0xbe,0xff,0x87,0xff,0xc2,0x58,0x0e,0x00,0x02,0x02,0xa0,0x00,0x20, + 0x3a,0x00,0x0d,0x00,0x01,0x01,0xa4,0xcb,0x94,0x73,0xeb,0xae,0xba,0xeb,0xae,0xba, + 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb, + 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae, + 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba, + 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb, + 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae, + 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba, + 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb, + 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae, + 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba, + 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb, + 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae, + 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba, + 0xeb,0xae,0xba,0xeb,0xaf,0x00,0x00,0x01,0x25,0x00,0xa2,0xb8,0x20,0x20,0x21,0x44, + 0xc5,0x00,0x01,0x57,0x9b,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe, + 0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb, + 0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xff,0x87,0xff,0xc2,0x58, + 0x0e,0x00,0x02,0x02,0xa0,0x00,0x20,0x3a,0x00,0x0d,0x00,0x01,0x01,0xa4,0xcb,0x94, + 0x73,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba, + 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb, + 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae, + 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba, + 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb, + 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae, + 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba, + 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb, + 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae, + 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba, + 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb, + 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae, + 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xaf,0x00,0x00,0x01,0x25, + 0x00,0x51,0x2e,0x08,0x08,0x08,0x51,0x31,0x40,0x00,0x55,0xe6,0xfb,0xef,0xbe,0xfb, + 0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef, + 0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe, + 0xfb,0xef,0xbf,0xe1,0xff,0xf0,0x96,0x03,0x80,0x00,0x80,0xa8,0x00,0x08,0x0e,0x80, + 0x03,0x40,0x00,0x40,0x69,0x32,0xe5,0x1c,0xfa,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb, + 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae, + 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba, + 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb, + 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae, + 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba, + 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb, + 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae, + 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba, + 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb, + 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae, + 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba, + 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb, + 0xae,0xba,0xeb,0xc0,0x00,0x00,0x01,0x25,0x00,0x79,0xae,0x08,0x08,0x08,0x51,0x31, + 0x40,0x00,0x55,0xe6,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe, + 0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb, + 0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbf,0xe1,0xff,0xf0,0x96,0x03, + 0x80,0x00,0x80,0xa8,0x00,0x08,0x0e,0x80,0x03,0x40,0x00,0x40,0x69,0x32,0xe5,0x1c, + 0xfa,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba, + 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb, + 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae, + 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba, + 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb, + 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae, + 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba, + 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb, + 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae, + 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba, + 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb, + 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae, + 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xc0,0x00,0x00,0x01,0x25, + 0x00,0x28,0x8b,0x82,0x02,0x02,0x14,0x4c,0x50,0x00,0x15,0x79,0xbe,0xfb,0xef,0xbe, + 0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb, + 0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef,0xbe,0xfb,0xef, + 0xbe,0xfb,0xef,0xf8,0x7f,0xfc,0x25,0x80,0xe0,0x00,0x20,0x2a,0x00,0x02,0x03,0xa0, + 0x00,0xd0,0x00,0x10,0x1a,0x4c,0xb9,0x47,0x3e,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba, + 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb, + 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae, + 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba, + 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb, + 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae, + 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba, + 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb, + 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae, + 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba, + 0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb, + 0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae, + 0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba,0xeb,0xae,0xba, + 0xeb,0xae,0xba,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static const uint8_t uvd_decode_msg[] = { + 0xe4,0x0d,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x44,0x40,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x60,0x03,0x00,0x00,0xe0,0x01,0x00,0x00, + 0x00,0x00,0x00,0x00,0x80,0xf9,0xf2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x05,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0xc0,0x03,0x00,0x00,0x80,0x07,0x00,0x00,0x60,0x09,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static const uint8_t avc_decode_msg[] = { + 0x02,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x85,0x00,0x00,0x00,0x88,0x00,0x00,0x00, + 0x01,0x00,0x00,0x01,0x00,0x03,0x02,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static const uint8_t uvd_destroy_msg[] = { + 0xe4,0x0d,0x00,0x00,0x02,0x00,0x00,0x00,0x03,0x00,0x44,0x40,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static const uint8_t uvd_it_scaling_table[] = { + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, +}; + +static const uint8_t vcn_dec_create_msg[] = { + 0x28,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x03,0x00,0x44,0x40,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x28,0x00,0x00,0x00, + 0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x60,0x03,0x00,0x00,0xe0,0x01,0x00,0x00, +}; + +static const uint8_t vcn_dec_decode_msg[] = { + 0x28,0x00,0x00,0x00,0x90,0x06,0x00,0x00,0x02,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x03,0x00,0x44,0x40,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x38,0x00,0x00,0x00, + 0xb4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0xec,0x00,0x00,0x00, + 0x5c,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x60,0x03,0x00,0x00,0xe0,0x01,0x00,0x00,0x80,0x05,0x00,0x00,0x00,0x94,0x6b,0x00, + 0x96,0x4e,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xaf,0x50,0x00, + 0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00, + 0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0xc0,0x03,0x00,0x00,0x80,0x07,0x00,0x00,0x60,0x09,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static const uint8_t vcn_dec_destroy_msg[] = { + 0x28,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00, + 0x03,0x00,0x44,0x40,0x00,0x00,0x00,0x00, +}; + +static const uint8_t feedback_msg[] = { + 0x2c,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; + +static const uint8_t jpeg_bitstream[] = { + 0xFF, 0xD8, 0xFF, 0xDB, 0x01, 0x06, 0x00, 0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, + 0x08, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x0A, 0x0A, 0x0A, 0x0C, 0x0C, 0x0B, + 0x0B, 0x0E, 0x0E, 0x0E, 0x11, 0x11, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC4, 0x00, 0x4B, 0x00, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x11, 0x08, 0x00, 0x08, 0x00, 0x08, + 0x03, 0x00, 0x22, 0x00, 0x01, 0x11, 0x00, 0x02, 0x11, 0x00, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00, + 0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00, 0x9F, 0xC0, 0x07, 0xFF, 0xD9, 0xFF, 0xD9, +}; + +#endif /* _DECODE_MESSAGES_H_ */ diff --git a/tests/amdgpu/frame.h b/tests/amdgpu/frame.h new file mode 100644 index 0000000..335401c --- /dev/null +++ b/tests/amdgpu/frame.h @@ -0,0 +1,1949 @@ +/* + * Copyright 2015 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 _frame_h_ +#define _frame_h_ + +static const uint8_t frame[] = { + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, + 0x6a, 0x6a, 0x6a, 0x6a, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x10, 0xcd, 0x13, 0x67, 0xa2, 0x2b, 0xa5, 0x29, + 0x5d, 0xcb, 0xd5, 0xa4, 0x27, 0x2a, 0x62, 0x20, 0x70, 0x78, 0x6d, 0xe9, 0x1e, 0xeb, 0x25, 0xa6, + 0x62, 0x29, 0x13, 0xa4, 0xab, 0x29, 0x12, 0x35, 0x4c, 0x77, 0x73, 0x42, 0xe0, 0xd0, 0x62, 0xa5, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xad, 0x17, 0x5c, 0xc3, 0xdc, 0x41, 0x1e, 0xbe, + 0x4e, 0x90, 0xab, 0xbf, 0x86, 0x33, 0x1f, 0xeb, 0x15, 0xac, 0x64, 0x38, 0xd0, 0x44, 0xe6, 0x3e, + 0xe9, 0x50, 0x8f, 0x32, 0xbd, 0x18, 0x7a, 0x4a, 0xaa, 0x12, 0x61, 0x91, 0x62, 0xaa, 0xd9, 0x6e, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xa4, 0xc6, 0x37, 0x7f, 0x6e, 0x6a, 0xa6, 0xd0, + 0xd6, 0x84, 0x51, 0x96, 0x13, 0xd6, 0xc4, 0x3e, 0x60, 0x36, 0x62, 0xbd, 0xd9, 0xe2, 0x78, 0xe3, + 0x83, 0x99, 0xda, 0x8e, 0x31, 0xd4, 0x64, 0x1f, 0xc7, 0x1b, 0xbe, 0xaa, 0x76, 0x22, 0x6b, 0x6b, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x42, 0x69, 0xb0, 0x8a, 0xcc, 0x74, 0x17, 0x4c, + 0x98, 0xe1, 0xc1, 0xaa, 0x19, 0xe5, 0xc3, 0xce, 0x69, 0xb1, 0xe5, 0x62, 0xe7, 0x2f, 0xe0, 0xc4, + 0xe8, 0x25, 0x84, 0xe8, 0x5f, 0x84, 0xb0, 0xab, 0x40, 0x3b, 0x9e, 0x95, 0x27, 0x44, 0x1e, 0x7a, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xe4, 0x77, 0xc8, 0x7d, 0xd2, 0x6e, 0xe5, 0x1f, + 0x8d, 0x33, 0x7c, 0x8e, 0x90, 0xbe, 0x1f, 0xb9, 0x5b, 0xc1, 0x5d, 0xdf, 0xc6, 0x23, 0x25, 0xc9, + 0x25, 0xb1, 0x13, 0x5e, 0x7c, 0x93, 0x67, 0xdf, 0x9b, 0x8f, 0x71, 0xb8, 0x34, 0xa4, 0x6b, 0xa1, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x40, 0xb8, 0x74, 0xbb, 0xa5, 0x3b, 0x40, 0x12, + 0x2b, 0x14, 0x43, 0x36, 0x93, 0x26, 0xe8, 0xda, 0x22, 0xcf, 0xc2, 0x69, 0xb0, 0xd0, 0x7a, 0xb1, + 0xc8, 0x2a, 0x92, 0x27, 0x94, 0x19, 0x97, 0xb3, 0x92, 0x65, 0xc5, 0x8d, 0xe8, 0xa6, 0xd0, 0x9b, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x88, 0x92, 0x2e, 0x4b, 0x64, 0xda, 0xce, 0x16, + 0x67, 0x70, 0xeb, 0x5c, 0x86, 0x6b, 0xc2, 0xe4, 0xbd, 0xdc, 0x46, 0x28, 0xd8, 0xd4, 0x19, 0x69, + 0xd5, 0xcf, 0x8e, 0x89, 0x40, 0x96, 0x7b, 0xb2, 0xc9, 0x5e, 0x18, 0xc6, 0xd6, 0xd2, 0x3c, 0x4a, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x46, 0x50, 0x88, 0xb8, 0x9a, 0x8c, 0xc8, 0xae, + 0xae, 0xcd, 0x63, 0x62, 0xc3, 0x8a, 0x32, 0xb3, 0x5c, 0x1c, 0xa2, 0x55, 0x27, 0x55, 0x87, 0x6b, + 0x3e, 0x33, 0xd6, 0x70, 0xd0, 0x59, 0x76, 0xb0, 0xcd, 0x4a, 0x6e, 0x4a, 0xb1, 0xa1, 0x17, 0x24, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xc8, 0xb5, 0xe3, 0x7a, 0x17, 0x63, 0x70, 0xca, + 0x37, 0xbd, 0x1f, 0x72, 0x5e, 0x2f, 0x7c, 0xb7, 0xd2, 0xcb, 0xa8, 0xa9, 0x13, 0x98, 0x2b, 0x7e, + 0x74, 0x3f, 0x94, 0x6f, 0x8c, 0x1a, 0xce, 0x38, 0x61, 0x72, 0xe2, 0x18, 0x4e, 0xac, 0x5c, 0xc3, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x92, 0xd8, 0xb7, 0x88, 0xa8, 0x6e, 0xc5, 0xce, + 0x1f, 0x4a, 0x64, 0x3b, 0x1a, 0x21, 0x9f, 0xa6, 0x46, 0xe7, 0x1a, 0xcf, 0xc8, 0x20, 0xc1, 0x20, + 0x83, 0xbe, 0x5b, 0x99, 0x4d, 0xd4, 0x5e, 0xb3, 0xc3, 0x4b, 0xab, 0x3e, 0xc7, 0x85, 0xea, 0xc4, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x10, 0x48, 0xe0, 0x84, 0xa8, 0x1d, 0x81, 0x62, + 0x74, 0x67, 0xb0, 0x32, 0x4c, 0x23, 0x56, 0xd0, 0x85, 0x9b, 0x20, 0xca, 0xb4, 0x49, 0xdd, 0xad, + 0x1f, 0xab, 0xcf, 0x16, 0x7d, 0xbd, 0x78, 0xb0, 0xd3, 0xa0, 0x5c, 0x50, 0xa1, 0xd7, 0x37, 0xa0, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x52, 0x55, 0x97, 0xd6, 0x93, 0x6c, 0xd2, 0xa1, + 0x94, 0xc2, 0x2c, 0x51, 0x68, 0x34, 0x88, 0xc7, 0x8c, 0x1f, 0x3f, 0x93, 0x68, 0x86, 0xb1, 0xa5, + 0xe1, 0x56, 0x89, 0x20, 0xa5, 0xe2, 0x28, 0x9a, 0x11, 0x8f, 0xa4, 0xa7, 0x81, 0x6d, 0xe2, 0x87, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xe2, 0x34, 0x79, 0x8d, 0xe2, 0xe1, 0xa3, 0x38, + 0x83, 0x3b, 0xb0, 0x7f, 0x4b, 0x2b, 0x44, 0xb7, 0x68, 0x21, 0x85, 0x79, 0x74, 0x8c, 0xbc, 0x65, + 0xbb, 0x16, 0xd0, 0x2a, 0xb7, 0x70, 0x13, 0x94, 0xc3, 0x87, 0x23, 0x46, 0x2f, 0xe3, 0xb7, 0xcf, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x35, 0xdd, 0x60, 0x5d, 0xc3, 0xd6, 0x75, 0x20, + 0x78, 0xbd, 0x49, 0x23, 0xaf, 0x1e, 0xa2, 0x14, 0xca, 0x81, 0x39, 0xbb, 0x19, 0xc2, 0x82, 0xde, + 0x68, 0xbe, 0xdb, 0xdd, 0xa4, 0x86, 0x51, 0xe7, 0xad, 0x2b, 0x25, 0xb0, 0xb7, 0x3d, 0xd0, 0xac, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x62, 0x50, 0xa9, 0x7e, 0x3b, 0xc0, 0x41, 0x9a, + 0x6e, 0xd0, 0x8f, 0x4a, 0x21, 0xd1, 0xe1, 0x9f, 0xdb, 0xb6, 0xe2, 0x41, 0x4a, 0x15, 0xb5, 0x95, + 0x64, 0x97, 0xd3, 0x42, 0xc5, 0x63, 0xdd, 0xb7, 0x57, 0x6c, 0xc3, 0x54, 0x91, 0x2b, 0xdc, 0x52, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xb2, 0xe1, 0x14, 0x37, 0x92, 0xea, 0xb8, 0xc3, + 0x95, 0x4b, 0x31, 0xab, 0x9b, 0xb8, 0x8f, 0xca, 0x66, 0x45, 0xae, 0x71, 0xaf, 0xb8, 0x2b, 0x57, + 0x87, 0x17, 0x90, 0x28, 0x98, 0x62, 0x47, 0x2c, 0xeb, 0x92, 0x79, 0x26, 0x52, 0x7d, 0x70, 0x88, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xa3, 0x38, 0x7a, 0xe7, 0x7e, 0x27, 0x49, 0xbd, + 0xe2, 0xcc, 0x88, 0xe6, 0x36, 0xae, 0xd6, 0x7c, 0x48, 0xe3, 0xe6, 0x7d, 0x11, 0xd4, 0xa0, 0x3e, + 0x6e, 0x9d, 0xdb, 0x9b, 0xdc, 0xb0, 0x70, 0xdc, 0x58, 0x5b, 0xda, 0x99, 0x92, 0x65, 0x48, 0x86, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x52, 0x52, 0x5c, 0x69, 0xd6, 0x8d, 0xb1, 0x5f, + 0xa3, 0x1c, 0xe1, 0x1e, 0x78, 0x15, 0x97, 0x9e, 0x44, 0xdf, 0x56, 0x60, 0x38, 0x18, 0x43, 0x1b, + 0xc1, 0x91, 0x6e, 0x48, 0x98, 0xe2, 0x19, 0x36, 0x9d, 0x6c, 0x23, 0x5a, 0x97, 0xa4, 0x26, 0x13, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x12, 0x33, 0x7a, 0x68, 0xb2, 0x29, 0x92, 0x81, + 0xa0, 0x5a, 0x9e, 0xd5, 0xbd, 0xb7, 0x4f, 0x13, 0x55, 0xb7, 0xe7, 0x73, 0x52, 0x32, 0x21, 0xbf, + 0x3a, 0x1b, 0xb1, 0x60, 0x19, 0x5f, 0x77, 0x8b, 0x7c, 0x2a, 0x87, 0x26, 0x82, 0x7f, 0x1d, 0xda, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xd6, 0xa3, 0xcd, 0xc3, 0x76, 0x48, 0x21, 0xd8, + 0x21, 0xab, 0x86, 0xc2, 0x5f, 0x57, 0xca, 0x7f, 0x38, 0x19, 0x4a, 0x20, 0xd6, 0xe8, 0x51, 0x22, + 0x5b, 0xb9, 0x24, 0xb8, 0x85, 0x87, 0x7b, 0xe1, 0x38, 0xbc, 0xdd, 0xad, 0xdd, 0xca, 0x1f, 0xc7, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x55, 0x4c, 0x1f, 0xdb, 0x80, 0xc3, 0xc0, 0x64, + 0xc3, 0x44, 0x9a, 0x1e, 0xd7, 0xd3, 0x1f, 0xa5, 0xba, 0xe3, 0x26, 0xe8, 0x7e, 0x8d, 0x5c, 0xaa, + 0xb1, 0x82, 0xc9, 0x3a, 0xd7, 0xd5, 0xb0, 0xd0, 0x45, 0x53, 0x8a, 0x65, 0x78, 0xe4, 0x6c, 0x86, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x58, 0x7a, 0xc3, 0xdc, 0xbb, 0x6b, 0x44, 0x70, + 0x10, 0x86, 0x88, 0x5c, 0x2e, 0xdc, 0x25, 0x4b, 0xb7, 0xb1, 0x88, 0xca, 0x27, 0xb1, 0x83, 0x2c, + 0x21, 0x9c, 0xe2, 0xbf, 0xe4, 0x2a, 0x35, 0x19, 0xdc, 0x99, 0xbc, 0x4a, 0x44, 0xd6, 0x4d, 0x75, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x47, 0x5b, 0x67, 0x73, 0x35, 0xe3, 0x3e, 0xb4, + 0x7a, 0x48, 0x13, 0x49, 0x47, 0xac, 0xdc, 0xa8, 0x1a, 0x2b, 0x44, 0xb4, 0xac, 0x99, 0x82, 0x13, + 0xc8, 0x7b, 0x7e, 0x9f, 0xeb, 0xab, 0xa2, 0xc8, 0xb2, 0x3e, 0x96, 0xd3, 0x53, 0x13, 0x33, 0x42, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2c, 0xdd, 0x42, 0x16, 0x1e, 0x35, 0x6a, 0xa0, + 0x5f, 0x93, 0x62, 0xc5, 0x6d, 0xc3, 0xde, 0x84, 0x4b, 0xdf, 0xde, 0xab, 0xbc, 0x31, 0xcd, 0xa1, + 0xa6, 0x10, 0x33, 0x48, 0x4c, 0x6f, 0x6a, 0xc0, 0xd8, 0x97, 0x2e, 0xb5, 0x48, 0x74, 0x70, 0x29, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x44, 0xd8, 0x5a, 0x9a, 0xc4, 0x1a, 0xd4, 0xa7, + 0x73, 0xc3, 0x1f, 0x10, 0x54, 0x95, 0x59, 0x16, 0x53, 0x88, 0x14, 0x30, 0xbd, 0x8c, 0x6f, 0x8d, + 0x19, 0x2f, 0xaf, 0x14, 0x88, 0xd6, 0x79, 0x33, 0xd6, 0xd6, 0x22, 0xb6, 0x9a, 0xa0, 0xcb, 0x90, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x93, 0xe1, 0xcc, 0x2f, 0x51, 0x67, 0x8a, 0x17, + 0xc3, 0xaa, 0x31, 0x31, 0x8c, 0xb3, 0xaa, 0x98, 0xb6, 0x5d, 0xe2, 0x6e, 0xa1, 0xcf, 0x10, 0xd4, + 0x8e, 0x6c, 0x93, 0xbd, 0x8b, 0xe9, 0x4f, 0x55, 0xdc, 0x3c, 0x4a, 0xad, 0x76, 0xcf, 0xea, 0xb7, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x50, 0x85, 0xcf, 0x57, 0x56, 0xa3, 0x1a, + 0x49, 0x25, 0xbe, 0x8d, 0x54, 0xa7, 0x78, 0x68, 0x76, 0x53, 0xc7, 0x59, 0x59, 0x66, 0xa1, 0xe4, + 0xa0, 0x68, 0x4d, 0x57, 0x85, 0x62, 0x2a, 0x56, 0x68, 0x38, 0x2b, 0xd3, 0xbd, 0x9a, 0xc4, 0xe0, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xb9, 0x40, 0x3e, 0x19, 0x40, 0xab, 0x60, 0xba, + 0xbf, 0x68, 0xb8, 0xe7, 0xa3, 0x3c, 0x73, 0x9b, 0x12, 0x68, 0xca, 0x89, 0x3f, 0x45, 0x67, 0xbd, + 0xd9, 0x3c, 0xd4, 0xc0, 0xa5, 0x15, 0x98, 0x6a, 0x81, 0x8b, 0x38, 0x6e, 0x27, 0x4c, 0x30, 0x29, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xbd, 0x8a, 0x61, 0x55, 0x4f, 0xb8, 0x2b, 0x6b, + 0x3b, 0x19, 0xe2, 0x10, 0x44, 0xc7, 0x51, 0x4a, 0x3a, 0x3b, 0xc3, 0x3e, 0xab, 0xca, 0x84, 0x86, + 0xab, 0xe4, 0xa3, 0x5a, 0xa7, 0xaf, 0x4e, 0x80, 0xa0, 0x95, 0x94, 0xde, 0xd6, 0x6e, 0x2f, 0x68, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x36, 0x8c, 0x49, 0x53, 0x7a, 0x50, 0xcb, + 0x75, 0x13, 0xcb, 0xab, 0x92, 0x70, 0x14, 0x6a, 0x8d, 0x4c, 0x9c, 0x5c, 0xa5, 0x69, 0x46, 0x1d, + 0x99, 0x68, 0x71, 0x72, 0x44, 0x87, 0xe7, 0xa8, 0xe6, 0x99, 0x9d, 0xdb, 0x31, 0x86, 0xc9, 0x9c, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xdd, 0x7d, 0xe8, 0xd0, 0x1c, 0x30, 0x8d, 0x2d, + 0x56, 0x5a, 0x1f, 0x1d, 0xc2, 0xa2, 0x7f, 0xcb, 0xd8, 0xbc, 0xcb, 0x6e, 0x12, 0x6e, 0x26, 0x62, + 0xeb, 0x48, 0x32, 0x91, 0x7b, 0x59, 0x6d, 0xac, 0xc7, 0x7a, 0x34, 0x55, 0xc3, 0x54, 0x9c, 0xbf, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x35, 0xea, 0xd9, 0x1f, 0xbd, 0xc9, 0x84, 0xe8, + 0xb1, 0x92, 0xc0, 0x7a, 0xde, 0x74, 0xe8, 0x87, 0xb1, 0xd6, 0x22, 0xc9, 0x19, 0x41, 0x7e, 0x36, + 0x62, 0xc6, 0x62, 0x99, 0x93, 0x4d, 0xa9, 0x7c, 0x5c, 0x23, 0x32, 0xe5, 0x5a, 0x4d, 0xbc, 0x87, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, + 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x10, 0x92, 0x5b, 0x51, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, + 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x36, 0x22, 0x80, 0x80, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, + 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0x5a, 0xf0, 0xa5, 0xaf, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa5, 0xaf, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x93, 0x48, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa5, 0xaf, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x93, 0x48, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa5, 0xaf, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x93, 0x48, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa5, 0xaf, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x93, 0x48, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa5, 0xaf, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x93, 0x48, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, + 0xf0, 0x6e, 0xf0, 0x6e, 0xf0, 0x6e, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa5, 0xaf, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, 0xca, 0xde, + 0xca, 0xde, 0xca, 0xde, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x93, 0x48, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, 0xa6, 0x10, + 0xa6, 0x10, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0xb6, 0xa3, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0xb6, 0xa3, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0xb6, 0xa3, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0xb6, 0xa3, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0xb6, 0xa3, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0xb6, 0xa3, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0xb6, 0xa3, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0xb6, 0xa3, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0xb6, 0xa3, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0xb6, 0xa3, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0xb6, 0xa3, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0xb6, 0xa3, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0xb6, 0xa3, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0xb6, 0xa3, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0xb6, 0xa3, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, + 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0xc6, 0x15, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0xb6, 0xa3, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, 0xeb, 0xc6, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +}; +#endif diff --git a/tests/amdgpu/hotunplug_tests.c b/tests/amdgpu/hotunplug_tests.c new file mode 100644 index 0000000..2b26567 --- /dev/null +++ b/tests/amdgpu/hotunplug_tests.c @@ -0,0 +1,443 @@ +/* + * Copyright 2021 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * +*/ + +#include +#include +#include +#include +#include +#if HAVE_ALLOCA_H +# include +#endif + +#include "CUnit/Basic.h" + +#include "amdgpu_test.h" +#include "amdgpu_drm.h" +#include "amdgpu_internal.h" +#include "xf86drm.h" +#include + +#define GFX_COMPUTE_NOP 0xffff1000 + +static amdgpu_device_handle device_handle; +static uint32_t major_version; +static uint32_t minor_version; +static char *sysfs_remove = NULL; +static bool do_cs; + +CU_BOOL suite_hotunplug_tests_enable(void) +{ + CU_BOOL enable = CU_TRUE; + drmDevicePtr device; + + if (drmGetDevice2(drm_amdgpu[0], DRM_DEVICE_GET_PCI_REVISION, &device)) { + printf("\n\nGPU Failed to get DRM device PCI info!\n"); + return CU_FALSE; + } + + if (device->bustype != DRM_BUS_PCI) { + printf("\n\nGPU device is not on PCI bus!\n"); + amdgpu_device_deinitialize(device_handle); + return CU_FALSE; + } + + if (amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle)) + return CU_FALSE; + + /* Latest tested amdgpu version to work with all the tests */ + if (minor_version < 46) + enable = false; + + if (amdgpu_device_deinitialize(device_handle)) + return CU_FALSE; + + return enable; +} + +int suite_hotunplug_tests_init(void) +{ + /* We need to open/close device at each test manually */ + amdgpu_close_devices(); + + return CUE_SUCCESS; +} + +int suite_hotunplug_tests_clean(void) +{ + + + return CUE_SUCCESS; +} + +static int amdgpu_hotunplug_trigger(const char *pathname) +{ + int fd, len; + + fd = open(pathname, O_WRONLY); + if (fd < 0) + return -errno; + + len = write(fd, "1", 1); + close(fd); + + return len; +} + +static int amdgpu_hotunplug_setup_test() +{ + int r; + char *tmp_str; + + if (amdgpu_open_device_on_test_index(open_render_node) < 0) { + printf("\n\n Failed to reopen device file!\n"); + return CUE_SINIT_FAILED; + + + + } + + r = amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle); + + if (r) { + if ((r == -EACCES) && (errno == EACCES)) + printf("\n\nError:%s. " + "Hint:Try to run this test program as root.", + strerror(errno)); + return CUE_SINIT_FAILED; + } + + tmp_str = amdgpu_get_device_from_fd(drm_amdgpu[0]); + if (!tmp_str){ + printf("\n\n Device path not found!\n"); + return CUE_SINIT_FAILED; + } + + sysfs_remove = realloc(tmp_str, strlen(tmp_str) * 2); + strcat(sysfs_remove, "/remove"); + + return 0; +} + +static int amdgpu_hotunplug_teardown_test() +{ + if (amdgpu_device_deinitialize(device_handle)) + return CUE_SCLEAN_FAILED; + + amdgpu_close_devices(); + + if (sysfs_remove) + free(sysfs_remove); + + return 0; +} + +static inline int amdgpu_hotunplug_remove() +{ + return amdgpu_hotunplug_trigger(sysfs_remove); +} + +static inline int amdgpu_hotunplug_rescan() +{ + return amdgpu_hotunplug_trigger("/sys/bus/pci/rescan"); +} + +static int amdgpu_cs_sync(amdgpu_context_handle context, + unsigned int ip_type, + int ring, + unsigned int seqno) +{ + struct amdgpu_cs_fence fence = { + .context = context, + .ip_type = ip_type, + .ring = ring, + .fence = seqno, + }; + uint32_t expired; + + return amdgpu_cs_query_fence_status(&fence, + AMDGPU_TIMEOUT_INFINITE, + 0, &expired); +} + +static void *amdgpu_nop_cs() +{ + amdgpu_bo_handle ib_result_handle; + void *ib_result_cpu; + uint64_t ib_result_mc_address; + uint32_t *ptr; + int i, r; + amdgpu_bo_list_handle bo_list; + amdgpu_va_handle va_handle; + amdgpu_context_handle context; + struct amdgpu_cs_request ibs_request; + struct amdgpu_cs_ib_info ib_info; + + r = amdgpu_cs_ctx_create(device_handle, &context); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_alloc_and_map(device_handle, 4096, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, + &ib_result_handle, &ib_result_cpu, + &ib_result_mc_address, &va_handle); + CU_ASSERT_EQUAL(r, 0); + + ptr = ib_result_cpu; + for (i = 0; i < 16; ++i) + ptr[i] = GFX_COMPUTE_NOP; + + r = amdgpu_bo_list_create(device_handle, 1, &ib_result_handle, NULL, &bo_list); + CU_ASSERT_EQUAL(r, 0); + + memset(&ib_info, 0, sizeof(struct amdgpu_cs_ib_info)); + ib_info.ib_mc_address = ib_result_mc_address; + ib_info.size = 16; + + memset(&ibs_request, 0, sizeof(struct amdgpu_cs_request)); + ibs_request.ip_type = AMDGPU_HW_IP_GFX; + ibs_request.ring = 0; + ibs_request.number_of_ibs = 1; + ibs_request.ibs = &ib_info; + ibs_request.resources = bo_list; + + while (do_cs) + amdgpu_cs_submit(context, 0, &ibs_request, 1); + + amdgpu_cs_sync(context, AMDGPU_HW_IP_GFX, 0, ibs_request.seq_no); + amdgpu_bo_list_destroy(bo_list); + amdgpu_bo_unmap_and_free(ib_result_handle, va_handle, + ib_result_mc_address, 4096); + + amdgpu_cs_ctx_free(context); + + return (void *)0; +} + +static pthread_t* amdgpu_create_cs_thread() +{ + int r; + pthread_t *thread = malloc(sizeof(*thread)); + if (!thread) + return NULL; + + do_cs = true; + + r = pthread_create(thread, NULL, amdgpu_nop_cs, NULL); + CU_ASSERT_EQUAL(r, 0); + + /* Give thread enough time to start*/ + usleep(100000); + return thread; +} + +static void amdgpu_destroy_cs_thread(pthread_t *thread) +{ + void *status; + + do_cs = false; + + pthread_join(*thread, &status); + CU_ASSERT_EQUAL(status, 0); + + free(thread); +} + + +static void amdgpu_hotunplug_test(bool with_cs) +{ + int r; + pthread_t *thread = NULL; + + r = amdgpu_hotunplug_setup_test(); + CU_ASSERT_EQUAL(r , 0); + + if (with_cs) { + thread = amdgpu_create_cs_thread(); + CU_ASSERT_NOT_EQUAL(thread, NULL); + } + + r = amdgpu_hotunplug_remove(); + CU_ASSERT_EQUAL(r > 0, 1); + + if (with_cs) + amdgpu_destroy_cs_thread(thread); + + r = amdgpu_hotunplug_teardown_test(); + CU_ASSERT_EQUAL(r , 0); + + r = amdgpu_hotunplug_rescan(); + CU_ASSERT_EQUAL(r > 0, 1); +} + +static void amdgpu_hotunplug_simple(void) +{ + amdgpu_hotunplug_test(false); +} + +static void amdgpu_hotunplug_with_cs(void) +{ + amdgpu_hotunplug_test(true); +} + +static void amdgpu_hotunplug_with_exported_bo(void) +{ + int r; + uint32_t dma_buf_fd; + unsigned int *ptr; + amdgpu_bo_handle bo_handle; + + struct amdgpu_bo_alloc_request request = { + .alloc_size = 4096, + .phys_alignment = 4096, + .preferred_heap = AMDGPU_GEM_DOMAIN_GTT, + .flags = 0, + }; + + r = amdgpu_hotunplug_setup_test(); + CU_ASSERT_EQUAL(r , 0); + + amdgpu_bo_alloc(device_handle, &request, &bo_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_export(bo_handle, amdgpu_bo_handle_type_dma_buf_fd, &dma_buf_fd); + CU_ASSERT_EQUAL(r, 0); + + ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, dma_buf_fd, 0); + CU_ASSERT_NOT_EQUAL(ptr, MAP_FAILED); + + r = amdgpu_hotunplug_remove(); + CU_ASSERT_EQUAL(r > 0, 1); + + amdgpu_bo_free(bo_handle); + + r = amdgpu_hotunplug_teardown_test(); + CU_ASSERT_EQUAL(r , 0); + + *ptr = 0xdeafbeef; + + munmap(ptr, 4096); + close (dma_buf_fd); + + r = amdgpu_hotunplug_rescan(); + CU_ASSERT_EQUAL(r > 0, 1); +} + +static void amdgpu_hotunplug_with_exported_fence(void) +{ + amdgpu_bo_handle ib_result_handle; + void *ib_result_cpu; + uint64_t ib_result_mc_address; + uint32_t *ptr, sync_obj_handle, sync_obj_handle2; + int i, r; + amdgpu_bo_list_handle bo_list; + amdgpu_va_handle va_handle; + uint32_t major2, minor2; + amdgpu_device_handle device2; + amdgpu_context_handle context; + struct amdgpu_cs_request ibs_request; + struct amdgpu_cs_ib_info ib_info; + struct amdgpu_cs_fence fence_status = {0}; + int shared_fd; + + r = amdgpu_hotunplug_setup_test(); + CU_ASSERT_EQUAL(r , 0); + + r = amdgpu_device_initialize(drm_amdgpu[1], &major2, &minor2, &device2); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_ctx_create(device_handle, &context); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_alloc_and_map(device_handle, 4096, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, + &ib_result_handle, &ib_result_cpu, + &ib_result_mc_address, &va_handle); + CU_ASSERT_EQUAL(r, 0); + + ptr = ib_result_cpu; + for (i = 0; i < 16; ++i) + ptr[i] = GFX_COMPUTE_NOP; + + r = amdgpu_bo_list_create(device_handle, 1, &ib_result_handle, NULL, &bo_list); + CU_ASSERT_EQUAL(r, 0); + + memset(&ib_info, 0, sizeof(struct amdgpu_cs_ib_info)); + ib_info.ib_mc_address = ib_result_mc_address; + ib_info.size = 16; + + memset(&ibs_request, 0, sizeof(struct amdgpu_cs_request)); + ibs_request.ip_type = AMDGPU_HW_IP_GFX; + ibs_request.ring = 0; + ibs_request.number_of_ibs = 1; + ibs_request.ibs = &ib_info; + ibs_request.resources = bo_list; + + CU_ASSERT_EQUAL(amdgpu_cs_submit(context, 0, &ibs_request, 1), 0); + + fence_status.context = context; + fence_status.ip_type = AMDGPU_HW_IP_GFX; + fence_status.ip_instance = 0; + fence_status.fence = ibs_request.seq_no; + + CU_ASSERT_EQUAL(amdgpu_cs_fence_to_handle(device_handle, &fence_status, + AMDGPU_FENCE_TO_HANDLE_GET_SYNCOBJ, + &sync_obj_handle), + 0); + + CU_ASSERT_EQUAL(amdgpu_cs_export_syncobj(device_handle, sync_obj_handle, &shared_fd), 0); + + CU_ASSERT_EQUAL(amdgpu_cs_import_syncobj(device2, shared_fd, &sync_obj_handle2), 0); + + CU_ASSERT_EQUAL(amdgpu_cs_destroy_syncobj(device_handle, sync_obj_handle), 0); + + CU_ASSERT_EQUAL(amdgpu_bo_list_destroy(bo_list), 0); + CU_ASSERT_EQUAL(amdgpu_bo_unmap_and_free(ib_result_handle, va_handle, + ib_result_mc_address, 4096), 0); + CU_ASSERT_EQUAL(amdgpu_cs_ctx_free(context), 0); + + r = amdgpu_hotunplug_remove(); + CU_ASSERT_EQUAL(r > 0, 1); + + CU_ASSERT_EQUAL(amdgpu_cs_syncobj_wait(device2, &sync_obj_handle2, 1, 100000000, 0, NULL), 0); + + CU_ASSERT_EQUAL(amdgpu_cs_destroy_syncobj(device2, sync_obj_handle2), 0); + + amdgpu_device_deinitialize(device2); + + r = amdgpu_hotunplug_teardown_test(); + CU_ASSERT_EQUAL(r , 0); + + r = amdgpu_hotunplug_rescan(); + CU_ASSERT_EQUAL(r > 0, 1); +} + + +CU_TestInfo hotunplug_tests[] = { + { "Unplug card and rescan the bus to plug it back", amdgpu_hotunplug_simple }, + { "Same as first test but with command submission", amdgpu_hotunplug_with_cs }, + { "Unplug with exported bo", amdgpu_hotunplug_with_exported_bo }, + { "Unplug with exported fence", amdgpu_hotunplug_with_exported_fence }, + CU_TEST_INFO_NULL, +}; diff --git a/tests/amdgpu/jpeg_tests.c b/tests/amdgpu/jpeg_tests.c new file mode 100644 index 0000000..772a4fe --- /dev/null +++ b/tests/amdgpu/jpeg_tests.c @@ -0,0 +1,579 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + */ + +#include +#include + +#include "CUnit/Basic.h" + +#include "util_math.h" + +#include "amdgpu_drm.h" +#include "amdgpu_internal.h" +#include "amdgpu_test.h" +#include "decode_messages.h" + +/* jpeg registers */ +#define mmUVD_JPEG_CNTL 0x0200 +#define mmUVD_JPEG_RB_BASE 0x0201 +#define mmUVD_JPEG_RB_WPTR 0x0202 +#define mmUVD_JPEG_RB_RPTR 0x0203 +#define mmUVD_JPEG_RB_SIZE 0x0204 +#define mmUVD_JPEG_TIER_CNTL2 0x021a +#define mmUVD_JPEG_UV_TILING_CTRL 0x021c +#define mmUVD_JPEG_TILING_CTRL 0x021e +#define mmUVD_JPEG_OUTBUF_RPTR 0x0220 +#define mmUVD_JPEG_OUTBUF_WPTR 0x0221 +#define mmUVD_JPEG_PITCH 0x0222 +#define mmUVD_JPEG_INT_EN 0x0229 +#define mmUVD_JPEG_UV_PITCH 0x022b +#define mmUVD_JPEG_INDEX 0x023e +#define mmUVD_JPEG_DATA 0x023f +#define mmUVD_LMI_JPEG_WRITE_64BIT_BAR_HIGH 0x0438 +#define mmUVD_LMI_JPEG_WRITE_64BIT_BAR_LOW 0x0439 +#define mmUVD_LMI_JPEG_READ_64BIT_BAR_HIGH 0x045a +#define mmUVD_LMI_JPEG_READ_64BIT_BAR_LOW 0x045b +#define mmUVD_CTX_INDEX 0x0528 +#define mmUVD_CTX_DATA 0x0529 +#define mmUVD_SOFT_RESET 0x05a0 + +#define vcnipUVD_JPEG_DEC_SOFT_RST 0x402f +#define vcnipUVD_JRBC_IB_COND_RD_TIMER 0x408e +#define vcnipUVD_JRBC_IB_REF_DATA 0x408f +#define vcnipUVD_LMI_JPEG_READ_64BIT_BAR_HIGH 0x40e1 +#define vcnipUVD_LMI_JPEG_READ_64BIT_BAR_LOW 0x40e0 +#define vcnipUVD_JPEG_RB_BASE 0x4001 +#define vcnipUVD_JPEG_RB_SIZE 0x4004 +#define vcnipUVD_JPEG_RB_WPTR 0x4002 +#define vcnipUVD_JPEG_PITCH 0x401f +#define vcnipUVD_JPEG_UV_PITCH 0x4020 +#define vcnipJPEG_DEC_ADDR_MODE 0x4027 +#define vcnipJPEG_DEC_Y_GFX10_TILING_SURFACE 0x4024 +#define vcnipJPEG_DEC_UV_GFX10_TILING_SURFACE 0x4025 +#define vcnipUVD_LMI_JPEG_WRITE_64BIT_BAR_HIGH 0x40e3 +#define vcnipUVD_LMI_JPEG_WRITE_64BIT_BAR_LOW 0x40e2 +#define vcnipUVD_JPEG_INDEX 0x402c +#define vcnipUVD_JPEG_DATA 0x402d +#define vcnipUVD_JPEG_TIER_CNTL2 0x400f +#define vcnipUVD_JPEG_OUTBUF_RPTR 0x401e +#define vcnipUVD_JPEG_OUTBUF_CNTL 0x401c +#define vcnipUVD_JPEG_INT_EN 0x400a +#define vcnipUVD_JPEG_CNTL 0x4000 +#define vcnipUVD_JPEG_RB_RPTR 0x4003 +#define vcnipUVD_JPEG_OUTBUF_WPTR 0x401d + + +#define RDECODE_PKT_REG_J(x) ((unsigned)(x)&0x3FFFF) +#define RDECODE_PKT_RES_J(x) (((unsigned)(x)&0x3F) << 18) +#define RDECODE_PKT_COND_J(x) (((unsigned)(x)&0xF) << 24) +#define RDECODE_PKT_TYPE_J(x) (((unsigned)(x)&0xF) << 28) +#define RDECODE_PKTJ(reg, cond, type) (RDECODE_PKT_REG_J(reg) | \ + RDECODE_PKT_RES_J(0) | \ + RDECODE_PKT_COND_J(cond) | \ + RDECODE_PKT_TYPE_J(type)) + +#define UVD_BASE_INST0_SEG1 0x00007E00 +#define SOC15_REG_ADDR(reg) (UVD_BASE_INST0_SEG1 + reg) + +#define COND0 0 +#define COND1 1 +#define COND3 3 +#define TYPE0 0 +#define TYPE1 1 +#define TYPE3 3 +#define JPEG_DEC_DT_PITCH 0x100 +#define JPEG_DEC_BSD_SIZE 0x180 +#define JPEG_DEC_LUMA_OFFSET 0 +#define JPEG_DEC_CHROMA_OFFSET 0x1000 +#define JPEG_DEC_SUM 4096 +#define IB_SIZE 4096 +#define MAX_RESOURCES 16 + +struct amdgpu_jpeg_bo { + amdgpu_bo_handle handle; + amdgpu_va_handle va_handle; + uint64_t addr; + uint64_t size; + uint8_t *ptr; +}; + +static amdgpu_device_handle device_handle; +static uint32_t major_version; +static uint32_t minor_version; +static uint32_t family_id; +static uint32_t chip_rev; +static uint32_t chip_id; +static uint32_t asic_id; +static uint32_t chip_rev; +static uint32_t chip_id; + +static amdgpu_context_handle context_handle; +static amdgpu_bo_handle ib_handle; +static amdgpu_va_handle ib_va_handle; +static uint64_t ib_mc_address; +static uint32_t *ib_cpu; +static uint32_t len; + +static amdgpu_bo_handle resources[MAX_RESOURCES]; +static unsigned num_resources; +bool jpeg_direct_reg; + +static void set_reg_jpeg(unsigned reg, unsigned cond, unsigned type, + uint32_t val); +static void send_cmd_bitstream(uint64_t addr); +static void send_cmd_target(uint64_t addr); +static void send_cmd_bitstream_direct(uint64_t addr); +static void send_cmd_target_direct(uint64_t addr); + +static void amdgpu_cs_jpeg_decode(void); + +CU_TestInfo jpeg_tests[] = { + {"JPEG decode", amdgpu_cs_jpeg_decode}, + CU_TEST_INFO_NULL, +}; + +CU_BOOL suite_jpeg_tests_enable(void) +{ + struct drm_amdgpu_info_hw_ip info; + int r; + + if (amdgpu_device_initialize(drm_amdgpu[0], &major_version, &minor_version, + &device_handle)) + return CU_FALSE; + + family_id = device_handle->info.family_id; + asic_id = device_handle->info.asic_id; + chip_rev = device_handle->info.chip_rev; + chip_id = device_handle->info.chip_external_rev; + + r = amdgpu_query_hw_ip_info(device_handle, AMDGPU_HW_IP_VCN_JPEG, 0, &info); + + if (amdgpu_device_deinitialize(device_handle)) + return CU_FALSE; + + if (r != 0 || !info.available_rings || + (family_id < AMDGPU_FAMILY_RV && + (family_id == AMDGPU_FAMILY_AI && + (chip_id - chip_rev) < 0x32))) { /* Arcturus */ + printf("\n\nThe ASIC NOT support JPEG, suite disabled\n"); + return CU_FALSE; + } + + if (info.hw_ip_version_major == 1) + jpeg_direct_reg = false; + else if (info.hw_ip_version_major > 1 && info.hw_ip_version_major <= 3) + jpeg_direct_reg = true; + else + return CU_FALSE; + + return CU_TRUE; +} + +int suite_jpeg_tests_init(void) +{ + int r; + + r = amdgpu_device_initialize(drm_amdgpu[0], &major_version, &minor_version, + &device_handle); + if (r) + return CUE_SINIT_FAILED; + + family_id = device_handle->info.family_id; + + r = amdgpu_cs_ctx_create(device_handle, &context_handle); + if (r) + return CUE_SINIT_FAILED; + + r = amdgpu_bo_alloc_and_map(device_handle, IB_SIZE, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, &ib_handle, + (void **)&ib_cpu, &ib_mc_address, &ib_va_handle); + if (r) + return CUE_SINIT_FAILED; + + return CUE_SUCCESS; +} + +int suite_jpeg_tests_clean(void) +{ + int r; + + r = amdgpu_bo_unmap_and_free(ib_handle, ib_va_handle, ib_mc_address, IB_SIZE); + if (r) + return CUE_SCLEAN_FAILED; + + r = amdgpu_cs_ctx_free(context_handle); + if (r) + return CUE_SCLEAN_FAILED; + + r = amdgpu_device_deinitialize(device_handle); + if (r) + return CUE_SCLEAN_FAILED; + + return CUE_SUCCESS; +} + +static int submit(unsigned ndw, unsigned ip) +{ + struct amdgpu_cs_request ibs_request = {0}; + struct amdgpu_cs_ib_info ib_info = {0}; + struct amdgpu_cs_fence fence_status = {0}; + uint32_t expired; + int r; + + ib_info.ib_mc_address = ib_mc_address; + ib_info.size = ndw; + + ibs_request.ip_type = ip; + + r = amdgpu_bo_list_create(device_handle, num_resources, resources, NULL, + &ibs_request.resources); + if (r) + return r; + + ibs_request.number_of_ibs = 1; + ibs_request.ibs = &ib_info; + ibs_request.fence_info.handle = NULL; + + r = amdgpu_cs_submit(context_handle, 0, &ibs_request, 1); + if (r) + return r; + + r = amdgpu_bo_list_destroy(ibs_request.resources); + if (r) + return r; + + fence_status.context = context_handle; + fence_status.ip_type = ip; + fence_status.fence = ibs_request.seq_no; + + r = amdgpu_cs_query_fence_status(&fence_status, AMDGPU_TIMEOUT_INFINITE, 0, + &expired); + if (r) + return r; + + return 0; +} + +static void alloc_resource(struct amdgpu_jpeg_bo *jpeg_bo, unsigned size, + unsigned domain) +{ + struct amdgpu_bo_alloc_request req = {0}; + amdgpu_bo_handle buf_handle; + amdgpu_va_handle va_handle; + uint64_t va = 0; + int r; + + req.alloc_size = ALIGN(size, 4096); + req.preferred_heap = domain; + r = amdgpu_bo_alloc(device_handle, &req, &buf_handle); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_va_range_alloc(device_handle, amdgpu_gpu_va_range_general, + req.alloc_size, 1, 0, &va, &va_handle, 0); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_bo_va_op(buf_handle, 0, req.alloc_size, va, 0, AMDGPU_VA_OP_MAP); + CU_ASSERT_EQUAL(r, 0); + jpeg_bo->addr = va; + jpeg_bo->handle = buf_handle; + jpeg_bo->size = req.alloc_size; + jpeg_bo->va_handle = va_handle; + r = amdgpu_bo_cpu_map(jpeg_bo->handle, (void **)&jpeg_bo->ptr); + CU_ASSERT_EQUAL(r, 0); + memset(jpeg_bo->ptr, 0, size); + r = amdgpu_bo_cpu_unmap(jpeg_bo->handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void free_resource(struct amdgpu_jpeg_bo *jpeg_bo) +{ + int r; + + r = amdgpu_bo_va_op(jpeg_bo->handle, 0, jpeg_bo->size, jpeg_bo->addr, 0, + AMDGPU_VA_OP_UNMAP); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_va_range_free(jpeg_bo->va_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_free(jpeg_bo->handle); + CU_ASSERT_EQUAL(r, 0); + memset(jpeg_bo, 0, sizeof(*jpeg_bo)); +} + +static void set_reg_jpeg(unsigned reg, unsigned cond, unsigned type, + uint32_t val) +{ + ib_cpu[len++] = RDECODE_PKTJ(reg, cond, type); + ib_cpu[len++] = val; +} + +/* send a bitstream buffer command */ +static void send_cmd_bitstream(uint64_t addr) +{ + + /* jpeg soft reset */ + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_JPEG_CNTL), COND0, TYPE0, 1); + + /* ensuring the Reset is asserted in SCLK domain */ + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_CTX_INDEX), COND0, TYPE0, 0x01C2); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_CTX_DATA), COND0, TYPE0, 0x01400200); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_CTX_INDEX), COND0, TYPE0, 0x01C3); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_CTX_DATA), COND0, TYPE0, (1 << 9)); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_SOFT_RESET), COND0, TYPE3, (1 << 9)); + + /* wait mem */ + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_JPEG_CNTL), COND0, TYPE0, 0); + + /* ensuring the Reset is de-asserted in SCLK domain */ + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_CTX_INDEX), COND0, TYPE0, 0x01C3); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_CTX_DATA), COND0, TYPE0, (0 << 9)); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_SOFT_RESET), COND0, TYPE3, (1 << 9)); + + /* set UVD_LMI_JPEG_READ_64BIT_BAR_LOW/HIGH based on bitstream buffer address */ + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_LMI_JPEG_READ_64BIT_BAR_HIGH), COND0, TYPE0, + (addr >> 32)); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_LMI_JPEG_READ_64BIT_BAR_LOW), COND0, TYPE0, + (unsigned int)addr); + + /* set jpeg_rb_base */ + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_JPEG_RB_BASE), COND0, TYPE0, 0); + + /* set jpeg_rb_base */ + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_JPEG_RB_SIZE), COND0, TYPE0, 0xFFFFFFF0); + + /* set jpeg_rb_wptr */ + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_JPEG_RB_WPTR), COND0, TYPE0, + (JPEG_DEC_BSD_SIZE >> 2)); +} + +/* send a target buffer command */ +static void send_cmd_target(uint64_t addr) +{ + + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_JPEG_PITCH), COND0, TYPE0, + (JPEG_DEC_DT_PITCH >> 4)); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_JPEG_UV_PITCH), COND0, TYPE0, + (JPEG_DEC_DT_PITCH >> 4)); + + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_JPEG_TILING_CTRL), COND0, TYPE0, 0); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_JPEG_UV_TILING_CTRL), COND0, TYPE0, 0); + + /* set UVD_LMI_JPEG_WRITE_64BIT_BAR_LOW/HIGH based on target buffer address */ + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_LMI_JPEG_WRITE_64BIT_BAR_HIGH), COND0, + TYPE0, (addr >> 32)); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_LMI_JPEG_WRITE_64BIT_BAR_LOW), COND0, TYPE0, + (unsigned int)addr); + + /* set output buffer data address */ + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_JPEG_INDEX), COND0, TYPE0, 0); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_JPEG_DATA), COND0, TYPE0, + JPEG_DEC_LUMA_OFFSET); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_JPEG_INDEX), COND0, TYPE0, 1); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_JPEG_DATA), COND0, TYPE0, + JPEG_DEC_CHROMA_OFFSET); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_JPEG_TIER_CNTL2), COND0, TYPE3, 0); + + /* set output buffer read pointer */ + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_JPEG_OUTBUF_RPTR), COND0, TYPE0, 0); + + /* enable error interrupts */ + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_JPEG_INT_EN), COND0, TYPE0, 0xFFFFFFFE); + + /* start engine command */ + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_JPEG_CNTL), COND0, TYPE0, 0x6); + + /* wait for job completion, wait for job JBSI fetch done */ + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_CTX_INDEX), COND0, TYPE0, 0x01C3); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_CTX_DATA), COND0, TYPE0, + (JPEG_DEC_BSD_SIZE >> 2)); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_CTX_INDEX), COND0, TYPE0, 0x01C2); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_CTX_DATA), COND0, TYPE0, 0x01400200); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_JPEG_RB_RPTR), COND0, TYPE3, 0xFFFFFFFF); + + /* wait for job jpeg outbuf idle */ + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_CTX_INDEX), COND0, TYPE0, 0x01C3); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_CTX_DATA), COND0, TYPE0, 0xFFFFFFFF); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_JPEG_OUTBUF_WPTR), COND0, TYPE3, + 0x00000001); + + /* stop engine */ + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_JPEG_CNTL), COND0, TYPE0, 0x4); + + /* asserting jpeg lmi drop */ + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_CTX_INDEX), COND0, TYPE0, 0x0005); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_CTX_DATA), COND0, TYPE0, + (1 << 23 | 1 << 0)); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_CTX_DATA), COND0, TYPE1, 0); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_CTX_DATA), COND0, TYPE0, 0); + + /* asserting jpeg reset */ + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_JPEG_CNTL), COND0, TYPE0, 1); + + /* ensure reset is asserted in sclk domain */ + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_CTX_INDEX), COND0, TYPE0, 0x01C3); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_CTX_DATA), COND0, TYPE0, (1 << 9)); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_SOFT_RESET), COND0, TYPE3, (1 << 9)); + + /* de-assert jpeg reset */ + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_JPEG_CNTL), COND0, TYPE0, 0); + + /* ensure reset is de-asserted in sclk domain */ + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_CTX_INDEX), COND0, TYPE0, 0x01C3); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_CTX_DATA), COND0, TYPE0, (0 << 9)); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_SOFT_RESET), COND0, TYPE3, (1 << 9)); + + /* de-asserting jpeg lmi drop */ + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_CTX_INDEX), COND0, TYPE0, 0x0005); + set_reg_jpeg(SOC15_REG_ADDR(mmUVD_CTX_DATA), COND0, TYPE0, 0); +} + +/* send a bitstream buffer command */ +static void send_cmd_bitstream_direct(uint64_t addr) +{ + + /* jpeg soft reset */ + set_reg_jpeg(vcnipUVD_JPEG_DEC_SOFT_RST, COND0, TYPE0, 1); + + /* ensuring the Reset is asserted in SCLK domain */ + set_reg_jpeg(vcnipUVD_JRBC_IB_COND_RD_TIMER, COND0, TYPE0, 0x01400200); + set_reg_jpeg(vcnipUVD_JRBC_IB_REF_DATA, COND0, TYPE0, (0x1 << 0x10)); + set_reg_jpeg(vcnipUVD_JPEG_DEC_SOFT_RST, COND3, TYPE3, (0x1 << 0x10)); + + /* wait mem */ + set_reg_jpeg(vcnipUVD_JPEG_DEC_SOFT_RST, COND0, TYPE0, 0); + + /* ensuring the Reset is de-asserted in SCLK domain */ + set_reg_jpeg(vcnipUVD_JRBC_IB_REF_DATA, COND0, TYPE0, (0 << 0x10)); + set_reg_jpeg(vcnipUVD_JPEG_DEC_SOFT_RST, COND3, TYPE3, (0x1 << 0x10)); + + /* set UVD_LMI_JPEG_READ_64BIT_BAR_LOW/HIGH based on bitstream buffer address */ + set_reg_jpeg(vcnipUVD_LMI_JPEG_READ_64BIT_BAR_HIGH, COND0, TYPE0, + (addr >> 32)); + set_reg_jpeg(vcnipUVD_LMI_JPEG_READ_64BIT_BAR_LOW, COND0, TYPE0, addr); + + /* set jpeg_rb_base */ + set_reg_jpeg(vcnipUVD_JPEG_RB_BASE, COND0, TYPE0, 0); + + /* set jpeg_rb_base */ + set_reg_jpeg(vcnipUVD_JPEG_RB_SIZE, COND0, TYPE0, 0xFFFFFFF0); + + /* set jpeg_rb_wptr */ + set_reg_jpeg(vcnipUVD_JPEG_RB_WPTR, COND0, TYPE0, (JPEG_DEC_BSD_SIZE >> 2)); +} + +/* send a target buffer command */ +static void send_cmd_target_direct(uint64_t addr) +{ + + set_reg_jpeg(vcnipUVD_JPEG_PITCH, COND0, TYPE0, (JPEG_DEC_DT_PITCH >> 4)); + set_reg_jpeg(vcnipUVD_JPEG_UV_PITCH, COND0, TYPE0, (JPEG_DEC_DT_PITCH >> 4)); + + set_reg_jpeg(vcnipJPEG_DEC_ADDR_MODE, COND0, TYPE0, 0); + set_reg_jpeg(vcnipJPEG_DEC_Y_GFX10_TILING_SURFACE, COND0, TYPE0, 0); + set_reg_jpeg(vcnipJPEG_DEC_UV_GFX10_TILING_SURFACE, COND0, TYPE0, 0); + + /* set UVD_LMI_JPEG_WRITE_64BIT_BAR_LOW/HIGH based on target buffer address */ + set_reg_jpeg(vcnipUVD_LMI_JPEG_WRITE_64BIT_BAR_HIGH, COND0, TYPE0, + (addr >> 32)); + set_reg_jpeg(vcnipUVD_LMI_JPEG_WRITE_64BIT_BAR_LOW, COND0, TYPE0, addr); + + /* set output buffer data address */ + set_reg_jpeg(vcnipUVD_JPEG_INDEX, COND0, TYPE0, 0); + set_reg_jpeg(vcnipUVD_JPEG_DATA, COND0, TYPE0, JPEG_DEC_LUMA_OFFSET); + set_reg_jpeg(vcnipUVD_JPEG_INDEX, COND0, TYPE0, 1); + set_reg_jpeg(vcnipUVD_JPEG_DATA, COND0, TYPE0, JPEG_DEC_CHROMA_OFFSET); + set_reg_jpeg(vcnipUVD_JPEG_TIER_CNTL2, COND0, 0, 0); + + /* set output buffer read pointer */ + set_reg_jpeg(vcnipUVD_JPEG_OUTBUF_RPTR, COND0, TYPE0, 0); + set_reg_jpeg(vcnipUVD_JPEG_OUTBUF_CNTL, COND0, TYPE0, + ((0x00001587 & (~0x00000180L)) | (0x1 << 0x7) | (0x1 << 0x6))); + + /* enable error interrupts */ + set_reg_jpeg(vcnipUVD_JPEG_INT_EN, COND0, TYPE0, 0xFFFFFFFE); + + /* start engine command */ + set_reg_jpeg(vcnipUVD_JPEG_CNTL, COND0, TYPE0, 0xE); + + /* wait for job completion, wait for job JBSI fetch done */ + set_reg_jpeg(vcnipUVD_JRBC_IB_REF_DATA, COND0, TYPE0, + (JPEG_DEC_BSD_SIZE >> 2)); + set_reg_jpeg(vcnipUVD_JRBC_IB_COND_RD_TIMER, COND0, TYPE0, 0x01400200); + set_reg_jpeg(vcnipUVD_JPEG_RB_RPTR, COND3, TYPE3, 0xFFFFFFFF); + + /* wait for job jpeg outbuf idle */ + set_reg_jpeg(vcnipUVD_JRBC_IB_REF_DATA, COND0, TYPE0, 0xFFFFFFFF); + set_reg_jpeg(vcnipUVD_JPEG_OUTBUF_WPTR, COND3, TYPE3, 0x00000001); + + /* stop engine */ + set_reg_jpeg(vcnipUVD_JPEG_CNTL, COND0, TYPE0, 0x4); +} + +static void amdgpu_cs_jpeg_decode(void) +{ + + struct amdgpu_jpeg_bo dec_buf; + int size, r; + uint8_t *dec; + int sum = 0, i, j; + + size = 16 * 1024; /* 8K bitstream + 8K output */ + num_resources = 0; + alloc_resource(&dec_buf, size, AMDGPU_GEM_DOMAIN_VRAM); + resources[num_resources++] = dec_buf.handle; + resources[num_resources++] = ib_handle; + r = amdgpu_bo_cpu_map(dec_buf.handle, (void **)&dec_buf.ptr); + CU_ASSERT_EQUAL(r, 0); + memcpy(dec_buf.ptr, jpeg_bitstream, sizeof(jpeg_bitstream)); + + len = 0; + + if (jpeg_direct_reg == true) { + send_cmd_bitstream_direct(dec_buf.addr); + send_cmd_target_direct(dec_buf.addr + (size / 2)); + } else { + send_cmd_bitstream(dec_buf.addr); + send_cmd_target(dec_buf.addr + (size / 2)); + } + + amdgpu_bo_cpu_unmap(dec_buf.handle); + r = submit(len, AMDGPU_HW_IP_VCN_JPEG); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_cpu_map(dec_buf.handle, (void **)&dec_buf.ptr); + CU_ASSERT_EQUAL(r, 0); + + dec = dec_buf.ptr + (size / 2); + + /* calculate result checksum */ + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + sum += *((dec + JPEG_DEC_LUMA_OFFSET + i * JPEG_DEC_DT_PITCH) + j); + for (i = 0; i < 4; i++) + for (j = 0; j < 8; j++) + sum += *((dec + JPEG_DEC_CHROMA_OFFSET + i * JPEG_DEC_DT_PITCH) + j); + + amdgpu_bo_cpu_unmap(dec_buf.handle); + CU_ASSERT_EQUAL(sum, JPEG_DEC_SUM); + + free_resource(&dec_buf); +} diff --git a/tests/amdgpu/meson.build b/tests/amdgpu/meson.build new file mode 100644 index 0000000..8618f6a --- /dev/null +++ b/tests/amdgpu/meson.build @@ -0,0 +1,46 @@ +# Copyright © 2017-2018 Intel Corporation + +# 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. + +if dep_cunit.found() + amdgpu_test = executable( + 'amdgpu_test', + files( + 'amdgpu_test.c', 'basic_tests.c', 'bo_tests.c', 'cs_tests.c', + 'vce_tests.c', 'uvd_enc_tests.c', 'vcn_tests.c', 'deadlock_tests.c', + 'vm_tests.c', 'ras_tests.c', 'syncobj_tests.c', 'security_tests.c', + 'hotunplug_tests.c', 'jpeg_tests.c', 'cp_dma_tests.c', 'shader_test_util.c' + ), + dependencies : [dep_cunit, dep_threads, dep_atomic_ops], + include_directories : [inc_root, inc_drm, include_directories('../../amdgpu')], + link_with : [libdrm, libdrm_amdgpu], + install : with_install_tests, + ) +endif + +amdgpu_stress = executable( + 'amdgpu_stress', + files( + 'amdgpu_stress.c' + ), + dependencies : [dep_threads, dep_atomic_ops], + include_directories : [inc_root, inc_drm, include_directories('../../amdgpu')], + link_with : [libdrm, libdrm_amdgpu], + install : with_install_tests, +) diff --git a/tests/amdgpu/ras_tests.c b/tests/amdgpu/ras_tests.c new file mode 100644 index 0000000..810bf17 --- /dev/null +++ b/tests/amdgpu/ras_tests.c @@ -0,0 +1,1003 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * +*/ + +#include "CUnit/Basic.h" + +#include "amdgpu_test.h" +#include "amdgpu_drm.h" +#include "amdgpu_internal.h" +#include +#include +#include +#include "xf86drm.h" +#include + +#define PATH_SIZE PATH_MAX + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +const char *ras_block_string[] = { + "umc", + "sdma", + "gfx", + "mmhub", + "athub", + "pcie_bif", + "hdp", + "xgmi_wafl", + "df", + "smn", + "sem", + "mp0", + "mp1", + "fuse", +}; + +#define ras_block_str(i) (ras_block_string[i]) + +enum amdgpu_ras_block { + AMDGPU_RAS_BLOCK__UMC = 0, + AMDGPU_RAS_BLOCK__SDMA, + AMDGPU_RAS_BLOCK__GFX, + AMDGPU_RAS_BLOCK__MMHUB, + AMDGPU_RAS_BLOCK__ATHUB, + AMDGPU_RAS_BLOCK__PCIE_BIF, + AMDGPU_RAS_BLOCK__HDP, + AMDGPU_RAS_BLOCK__XGMI_WAFL, + AMDGPU_RAS_BLOCK__DF, + AMDGPU_RAS_BLOCK__SMN, + AMDGPU_RAS_BLOCK__SEM, + AMDGPU_RAS_BLOCK__MP0, + AMDGPU_RAS_BLOCK__MP1, + AMDGPU_RAS_BLOCK__FUSE, + + AMDGPU_RAS_BLOCK__LAST +}; + +#define AMDGPU_RAS_BLOCK_COUNT AMDGPU_RAS_BLOCK__LAST +#define AMDGPU_RAS_BLOCK_MASK ((1ULL << AMDGPU_RAS_BLOCK_COUNT) - 1) + +enum amdgpu_ras_gfx_subblock { + /* CPC */ + AMDGPU_RAS_BLOCK__GFX_CPC_INDEX_START = 0, + AMDGPU_RAS_BLOCK__GFX_CPC_SCRATCH = + AMDGPU_RAS_BLOCK__GFX_CPC_INDEX_START, + AMDGPU_RAS_BLOCK__GFX_CPC_UCODE, + AMDGPU_RAS_BLOCK__GFX_DC_STATE_ME1, + AMDGPU_RAS_BLOCK__GFX_DC_CSINVOC_ME1, + AMDGPU_RAS_BLOCK__GFX_DC_RESTORE_ME1, + AMDGPU_RAS_BLOCK__GFX_DC_STATE_ME2, + AMDGPU_RAS_BLOCK__GFX_DC_CSINVOC_ME2, + AMDGPU_RAS_BLOCK__GFX_DC_RESTORE_ME2, + AMDGPU_RAS_BLOCK__GFX_CPC_INDEX_END = + AMDGPU_RAS_BLOCK__GFX_DC_RESTORE_ME2, + /* CPF */ + AMDGPU_RAS_BLOCK__GFX_CPF_INDEX_START, + AMDGPU_RAS_BLOCK__GFX_CPF_ROQ_ME2 = + AMDGPU_RAS_BLOCK__GFX_CPF_INDEX_START, + AMDGPU_RAS_BLOCK__GFX_CPF_ROQ_ME1, + AMDGPU_RAS_BLOCK__GFX_CPF_TAG, + AMDGPU_RAS_BLOCK__GFX_CPF_INDEX_END = AMDGPU_RAS_BLOCK__GFX_CPF_TAG, + /* CPG */ + AMDGPU_RAS_BLOCK__GFX_CPG_INDEX_START, + AMDGPU_RAS_BLOCK__GFX_CPG_DMA_ROQ = + AMDGPU_RAS_BLOCK__GFX_CPG_INDEX_START, + AMDGPU_RAS_BLOCK__GFX_CPG_DMA_TAG, + AMDGPU_RAS_BLOCK__GFX_CPG_TAG, + AMDGPU_RAS_BLOCK__GFX_CPG_INDEX_END = AMDGPU_RAS_BLOCK__GFX_CPG_TAG, + /* GDS */ + AMDGPU_RAS_BLOCK__GFX_GDS_INDEX_START, + AMDGPU_RAS_BLOCK__GFX_GDS_MEM = AMDGPU_RAS_BLOCK__GFX_GDS_INDEX_START, + AMDGPU_RAS_BLOCK__GFX_GDS_INPUT_QUEUE, + AMDGPU_RAS_BLOCK__GFX_GDS_OA_PHY_CMD_RAM_MEM, + AMDGPU_RAS_BLOCK__GFX_GDS_OA_PHY_DATA_RAM_MEM, + AMDGPU_RAS_BLOCK__GFX_GDS_OA_PIPE_MEM, + AMDGPU_RAS_BLOCK__GFX_GDS_INDEX_END = + AMDGPU_RAS_BLOCK__GFX_GDS_OA_PIPE_MEM, + /* SPI */ + AMDGPU_RAS_BLOCK__GFX_SPI_SR_MEM, + /* SQ */ + AMDGPU_RAS_BLOCK__GFX_SQ_INDEX_START, + AMDGPU_RAS_BLOCK__GFX_SQ_SGPR = AMDGPU_RAS_BLOCK__GFX_SQ_INDEX_START, + AMDGPU_RAS_BLOCK__GFX_SQ_LDS_D, + AMDGPU_RAS_BLOCK__GFX_SQ_LDS_I, + AMDGPU_RAS_BLOCK__GFX_SQ_VGPR, + AMDGPU_RAS_BLOCK__GFX_SQ_INDEX_END = AMDGPU_RAS_BLOCK__GFX_SQ_VGPR, + /* SQC (3 ranges) */ + AMDGPU_RAS_BLOCK__GFX_SQC_INDEX_START, + /* SQC range 0 */ + AMDGPU_RAS_BLOCK__GFX_SQC_INDEX0_START = + AMDGPU_RAS_BLOCK__GFX_SQC_INDEX_START, + AMDGPU_RAS_BLOCK__GFX_SQC_INST_UTCL1_LFIFO = + AMDGPU_RAS_BLOCK__GFX_SQC_INDEX0_START, + AMDGPU_RAS_BLOCK__GFX_SQC_DATA_CU0_WRITE_DATA_BUF, + AMDGPU_RAS_BLOCK__GFX_SQC_DATA_CU0_UTCL1_LFIFO, + AMDGPU_RAS_BLOCK__GFX_SQC_DATA_CU1_WRITE_DATA_BUF, + AMDGPU_RAS_BLOCK__GFX_SQC_DATA_CU1_UTCL1_LFIFO, + AMDGPU_RAS_BLOCK__GFX_SQC_DATA_CU2_WRITE_DATA_BUF, + AMDGPU_RAS_BLOCK__GFX_SQC_DATA_CU2_UTCL1_LFIFO, + AMDGPU_RAS_BLOCK__GFX_SQC_INDEX0_END = + AMDGPU_RAS_BLOCK__GFX_SQC_DATA_CU2_UTCL1_LFIFO, + /* SQC range 1 */ + AMDGPU_RAS_BLOCK__GFX_SQC_INDEX1_START, + AMDGPU_RAS_BLOCK__GFX_SQC_INST_BANKA_TAG_RAM = + AMDGPU_RAS_BLOCK__GFX_SQC_INDEX1_START, + AMDGPU_RAS_BLOCK__GFX_SQC_INST_BANKA_UTCL1_MISS_FIFO, + AMDGPU_RAS_BLOCK__GFX_SQC_INST_BANKA_MISS_FIFO, + AMDGPU_RAS_BLOCK__GFX_SQC_INST_BANKA_BANK_RAM, + AMDGPU_RAS_BLOCK__GFX_SQC_DATA_BANKA_TAG_RAM, + AMDGPU_RAS_BLOCK__GFX_SQC_DATA_BANKA_HIT_FIFO, + AMDGPU_RAS_BLOCK__GFX_SQC_DATA_BANKA_MISS_FIFO, + AMDGPU_RAS_BLOCK__GFX_SQC_DATA_BANKA_DIRTY_BIT_RAM, + AMDGPU_RAS_BLOCK__GFX_SQC_DATA_BANKA_BANK_RAM, + AMDGPU_RAS_BLOCK__GFX_SQC_INDEX1_END = + AMDGPU_RAS_BLOCK__GFX_SQC_DATA_BANKA_BANK_RAM, + /* SQC range 2 */ + AMDGPU_RAS_BLOCK__GFX_SQC_INDEX2_START, + AMDGPU_RAS_BLOCK__GFX_SQC_INST_BANKB_TAG_RAM = + AMDGPU_RAS_BLOCK__GFX_SQC_INDEX2_START, + AMDGPU_RAS_BLOCK__GFX_SQC_INST_BANKB_UTCL1_MISS_FIFO, + AMDGPU_RAS_BLOCK__GFX_SQC_INST_BANKB_MISS_FIFO, + AMDGPU_RAS_BLOCK__GFX_SQC_INST_BANKB_BANK_RAM, + AMDGPU_RAS_BLOCK__GFX_SQC_DATA_BANKB_TAG_RAM, + AMDGPU_RAS_BLOCK__GFX_SQC_DATA_BANKB_HIT_FIFO, + AMDGPU_RAS_BLOCK__GFX_SQC_DATA_BANKB_MISS_FIFO, + AMDGPU_RAS_BLOCK__GFX_SQC_DATA_BANKB_DIRTY_BIT_RAM, + AMDGPU_RAS_BLOCK__GFX_SQC_DATA_BANKB_BANK_RAM, + AMDGPU_RAS_BLOCK__GFX_SQC_INDEX2_END = + AMDGPU_RAS_BLOCK__GFX_SQC_DATA_BANKB_BANK_RAM, + AMDGPU_RAS_BLOCK__GFX_SQC_INDEX_END = + AMDGPU_RAS_BLOCK__GFX_SQC_INDEX2_END, + /* TA */ + AMDGPU_RAS_BLOCK__GFX_TA_INDEX_START, + AMDGPU_RAS_BLOCK__GFX_TA_FS_DFIFO = + AMDGPU_RAS_BLOCK__GFX_TA_INDEX_START, + AMDGPU_RAS_BLOCK__GFX_TA_FS_AFIFO, + AMDGPU_RAS_BLOCK__GFX_TA_FL_LFIFO, + AMDGPU_RAS_BLOCK__GFX_TA_FX_LFIFO, + AMDGPU_RAS_BLOCK__GFX_TA_FS_CFIFO, + AMDGPU_RAS_BLOCK__GFX_TA_INDEX_END = AMDGPU_RAS_BLOCK__GFX_TA_FS_CFIFO, + /* TCA */ + AMDGPU_RAS_BLOCK__GFX_TCA_INDEX_START, + AMDGPU_RAS_BLOCK__GFX_TCA_HOLE_FIFO = + AMDGPU_RAS_BLOCK__GFX_TCA_INDEX_START, + AMDGPU_RAS_BLOCK__GFX_TCA_REQ_FIFO, + AMDGPU_RAS_BLOCK__GFX_TCA_INDEX_END = + AMDGPU_RAS_BLOCK__GFX_TCA_REQ_FIFO, + /* TCC (5 sub-ranges) */ + AMDGPU_RAS_BLOCK__GFX_TCC_INDEX_START, + /* TCC range 0 */ + AMDGPU_RAS_BLOCK__GFX_TCC_INDEX0_START = + AMDGPU_RAS_BLOCK__GFX_TCC_INDEX_START, + AMDGPU_RAS_BLOCK__GFX_TCC_CACHE_DATA = + AMDGPU_RAS_BLOCK__GFX_TCC_INDEX0_START, + AMDGPU_RAS_BLOCK__GFX_TCC_CACHE_DATA_BANK_0_1, + AMDGPU_RAS_BLOCK__GFX_TCC_CACHE_DATA_BANK_1_0, + AMDGPU_RAS_BLOCK__GFX_TCC_CACHE_DATA_BANK_1_1, + AMDGPU_RAS_BLOCK__GFX_TCC_CACHE_DIRTY_BANK_0, + AMDGPU_RAS_BLOCK__GFX_TCC_CACHE_DIRTY_BANK_1, + AMDGPU_RAS_BLOCK__GFX_TCC_HIGH_RATE_TAG, + AMDGPU_RAS_BLOCK__GFX_TCC_LOW_RATE_TAG, + AMDGPU_RAS_BLOCK__GFX_TCC_INDEX0_END = + AMDGPU_RAS_BLOCK__GFX_TCC_LOW_RATE_TAG, + /* TCC range 1 */ + AMDGPU_RAS_BLOCK__GFX_TCC_INDEX1_START, + AMDGPU_RAS_BLOCK__GFX_TCC_IN_USE_DEC = + AMDGPU_RAS_BLOCK__GFX_TCC_INDEX1_START, + AMDGPU_RAS_BLOCK__GFX_TCC_IN_USE_TRANSFER, + AMDGPU_RAS_BLOCK__GFX_TCC_INDEX1_END = + AMDGPU_RAS_BLOCK__GFX_TCC_IN_USE_TRANSFER, + /* TCC range 2 */ + AMDGPU_RAS_BLOCK__GFX_TCC_INDEX2_START, + AMDGPU_RAS_BLOCK__GFX_TCC_RETURN_DATA = + AMDGPU_RAS_BLOCK__GFX_TCC_INDEX2_START, + AMDGPU_RAS_BLOCK__GFX_TCC_RETURN_CONTROL, + AMDGPU_RAS_BLOCK__GFX_TCC_UC_ATOMIC_FIFO, + AMDGPU_RAS_BLOCK__GFX_TCC_WRITE_RETURN, + AMDGPU_RAS_BLOCK__GFX_TCC_WRITE_CACHE_READ, + AMDGPU_RAS_BLOCK__GFX_TCC_SRC_FIFO, + AMDGPU_RAS_BLOCK__GFX_TCC_SRC_FIFO_NEXT_RAM, + AMDGPU_RAS_BLOCK__GFX_TCC_CACHE_TAG_PROBE_FIFO, + AMDGPU_RAS_BLOCK__GFX_TCC_INDEX2_END = + AMDGPU_RAS_BLOCK__GFX_TCC_CACHE_TAG_PROBE_FIFO, + /* TCC range 3 */ + AMDGPU_RAS_BLOCK__GFX_TCC_INDEX3_START, + AMDGPU_RAS_BLOCK__GFX_TCC_LATENCY_FIFO = + AMDGPU_RAS_BLOCK__GFX_TCC_INDEX3_START, + AMDGPU_RAS_BLOCK__GFX_TCC_LATENCY_FIFO_NEXT_RAM, + AMDGPU_RAS_BLOCK__GFX_TCC_INDEX3_END = + AMDGPU_RAS_BLOCK__GFX_TCC_LATENCY_FIFO_NEXT_RAM, + /* TCC range 4 */ + AMDGPU_RAS_BLOCK__GFX_TCC_INDEX4_START, + AMDGPU_RAS_BLOCK__GFX_TCC_WRRET_TAG_WRITE_RETURN = + AMDGPU_RAS_BLOCK__GFX_TCC_INDEX4_START, + AMDGPU_RAS_BLOCK__GFX_TCC_ATOMIC_RETURN_BUFFER, + AMDGPU_RAS_BLOCK__GFX_TCC_INDEX4_END = + AMDGPU_RAS_BLOCK__GFX_TCC_ATOMIC_RETURN_BUFFER, + AMDGPU_RAS_BLOCK__GFX_TCC_INDEX_END = + AMDGPU_RAS_BLOCK__GFX_TCC_INDEX4_END, + /* TCI */ + AMDGPU_RAS_BLOCK__GFX_TCI_WRITE_RAM, + /* TCP */ + AMDGPU_RAS_BLOCK__GFX_TCP_INDEX_START, + AMDGPU_RAS_BLOCK__GFX_TCP_CACHE_RAM = + AMDGPU_RAS_BLOCK__GFX_TCP_INDEX_START, + AMDGPU_RAS_BLOCK__GFX_TCP_LFIFO_RAM, + AMDGPU_RAS_BLOCK__GFX_TCP_CMD_FIFO, + AMDGPU_RAS_BLOCK__GFX_TCP_VM_FIFO, + AMDGPU_RAS_BLOCK__GFX_TCP_DB_RAM, + AMDGPU_RAS_BLOCK__GFX_TCP_UTCL1_LFIFO0, + AMDGPU_RAS_BLOCK__GFX_TCP_UTCL1_LFIFO1, + AMDGPU_RAS_BLOCK__GFX_TCP_INDEX_END = + AMDGPU_RAS_BLOCK__GFX_TCP_UTCL1_LFIFO1, + /* TD */ + AMDGPU_RAS_BLOCK__GFX_TD_INDEX_START, + AMDGPU_RAS_BLOCK__GFX_TD_SS_FIFO_LO = + AMDGPU_RAS_BLOCK__GFX_TD_INDEX_START, + AMDGPU_RAS_BLOCK__GFX_TD_SS_FIFO_HI, + AMDGPU_RAS_BLOCK__GFX_TD_CS_FIFO, + AMDGPU_RAS_BLOCK__GFX_TD_INDEX_END = AMDGPU_RAS_BLOCK__GFX_TD_CS_FIFO, + /* EA (3 sub-ranges) */ + AMDGPU_RAS_BLOCK__GFX_EA_INDEX_START, + /* EA range 0 */ + AMDGPU_RAS_BLOCK__GFX_EA_INDEX0_START = + AMDGPU_RAS_BLOCK__GFX_EA_INDEX_START, + AMDGPU_RAS_BLOCK__GFX_EA_DRAMRD_CMDMEM = + AMDGPU_RAS_BLOCK__GFX_EA_INDEX0_START, + AMDGPU_RAS_BLOCK__GFX_EA_DRAMWR_CMDMEM, + AMDGPU_RAS_BLOCK__GFX_EA_DRAMWR_DATAMEM, + AMDGPU_RAS_BLOCK__GFX_EA_RRET_TAGMEM, + AMDGPU_RAS_BLOCK__GFX_EA_WRET_TAGMEM, + AMDGPU_RAS_BLOCK__GFX_EA_GMIRD_CMDMEM, + AMDGPU_RAS_BLOCK__GFX_EA_GMIWR_CMDMEM, + AMDGPU_RAS_BLOCK__GFX_EA_GMIWR_DATAMEM, + AMDGPU_RAS_BLOCK__GFX_EA_INDEX0_END = + AMDGPU_RAS_BLOCK__GFX_EA_GMIWR_DATAMEM, + /* EA range 1 */ + AMDGPU_RAS_BLOCK__GFX_EA_INDEX1_START, + AMDGPU_RAS_BLOCK__GFX_EA_DRAMRD_PAGEMEM = + AMDGPU_RAS_BLOCK__GFX_EA_INDEX1_START, + AMDGPU_RAS_BLOCK__GFX_EA_DRAMWR_PAGEMEM, + AMDGPU_RAS_BLOCK__GFX_EA_IORD_CMDMEM, + AMDGPU_RAS_BLOCK__GFX_EA_IOWR_CMDMEM, + AMDGPU_RAS_BLOCK__GFX_EA_IOWR_DATAMEM, + AMDGPU_RAS_BLOCK__GFX_EA_GMIRD_PAGEMEM, + AMDGPU_RAS_BLOCK__GFX_EA_GMIWR_PAGEMEM, + AMDGPU_RAS_BLOCK__GFX_EA_INDEX1_END = + AMDGPU_RAS_BLOCK__GFX_EA_GMIWR_PAGEMEM, + /* EA range 2 */ + AMDGPU_RAS_BLOCK__GFX_EA_INDEX2_START, + AMDGPU_RAS_BLOCK__GFX_EA_MAM_D0MEM = + AMDGPU_RAS_BLOCK__GFX_EA_INDEX2_START, + AMDGPU_RAS_BLOCK__GFX_EA_MAM_D1MEM, + AMDGPU_RAS_BLOCK__GFX_EA_MAM_D2MEM, + AMDGPU_RAS_BLOCK__GFX_EA_MAM_D3MEM, + AMDGPU_RAS_BLOCK__GFX_EA_INDEX2_END = + AMDGPU_RAS_BLOCK__GFX_EA_MAM_D3MEM, + AMDGPU_RAS_BLOCK__GFX_EA_INDEX_END = + AMDGPU_RAS_BLOCK__GFX_EA_INDEX2_END, + /* UTC VM L2 bank */ + AMDGPU_RAS_BLOCK__UTC_VML2_BANK_CACHE, + /* UTC VM walker */ + AMDGPU_RAS_BLOCK__UTC_VML2_WALKER, + /* UTC ATC L2 2MB cache */ + AMDGPU_RAS_BLOCK__UTC_ATCL2_CACHE_2M_BANK, + /* UTC ATC L2 4KB cache */ + AMDGPU_RAS_BLOCK__UTC_ATCL2_CACHE_4K_BANK, + AMDGPU_RAS_BLOCK__GFX_MAX +}; + +enum amdgpu_ras_error_type { + AMDGPU_RAS_ERROR__NONE = 0, + AMDGPU_RAS_ERROR__PARITY = 1, + AMDGPU_RAS_ERROR__SINGLE_CORRECTABLE = 2, + AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE = 4, + AMDGPU_RAS_ERROR__POISON = 8, +}; + +struct ras_inject_test_config { + char name[64]; + char block[32]; + int sub_block; + enum amdgpu_ras_error_type type; + uint64_t address; + uint64_t value; +}; + +struct ras_common_if { + enum amdgpu_ras_block block; + enum amdgpu_ras_error_type type; + uint32_t sub_block_index; + char name[32]; +}; + +struct ras_inject_if { + struct ras_common_if head; + uint64_t address; + uint64_t value; +}; + +struct ras_debug_if { + union { + struct ras_common_if head; + struct ras_inject_if inject; + }; + int op; +}; +/* for now, only umc, gfx, sdma has implemented. */ +#define DEFAULT_RAS_BLOCK_MASK_INJECT ((1 << AMDGPU_RAS_BLOCK__UMC) |\ + (1 << AMDGPU_RAS_BLOCK__GFX)) +#define DEFAULT_RAS_BLOCK_MASK_QUERY ((1 << AMDGPU_RAS_BLOCK__UMC) |\ + (1 << AMDGPU_RAS_BLOCK__GFX)) +#define DEFAULT_RAS_BLOCK_MASK_BASIC (1 << AMDGPU_RAS_BLOCK__UMC |\ + (1 << AMDGPU_RAS_BLOCK__SDMA) |\ + (1 << AMDGPU_RAS_BLOCK__GFX)) + +static uint32_t ras_block_mask_inject = DEFAULT_RAS_BLOCK_MASK_INJECT; +static uint32_t ras_block_mask_query = DEFAULT_RAS_BLOCK_MASK_INJECT; +static uint32_t ras_block_mask_basic = DEFAULT_RAS_BLOCK_MASK_BASIC; + +struct ras_test_mask { + uint32_t inject_mask; + uint32_t query_mask; + uint32_t basic_mask; +}; + +struct amdgpu_ras_data { + amdgpu_device_handle device_handle; + uint32_t id; + uint32_t capability; + struct ras_test_mask test_mask; +}; + +/* all devices who has ras supported */ +static struct amdgpu_ras_data devices[MAX_CARDS_SUPPORTED]; +static int devices_count; + +struct ras_DID_test_mask{ + uint16_t device_id; + uint16_t revision_id; + struct ras_test_mask test_mask; +}; + +/* white list for inject test. */ +#define RAS_BLOCK_MASK_ALL {\ + DEFAULT_RAS_BLOCK_MASK_INJECT,\ + DEFAULT_RAS_BLOCK_MASK_QUERY,\ + DEFAULT_RAS_BLOCK_MASK_BASIC\ +} + +#define RAS_BLOCK_MASK_QUERY_BASIC {\ + 0,\ + DEFAULT_RAS_BLOCK_MASK_QUERY,\ + DEFAULT_RAS_BLOCK_MASK_BASIC\ +} + +static const struct ras_inject_test_config umc_ras_inject_test[] = { + {"ras_umc.1.0", "umc", 0, AMDGPU_RAS_ERROR__SINGLE_CORRECTABLE, 0, 0}, +}; + +static const struct ras_inject_test_config gfx_ras_inject_test[] = { + {"ras_gfx.2.0", "gfx", AMDGPU_RAS_BLOCK__GFX_CPC_UCODE, + AMDGPU_RAS_ERROR__SINGLE_CORRECTABLE, 0, 0}, + {"ras_gfx.2.1", "gfx", AMDGPU_RAS_BLOCK__GFX_CPF_TAG, + AMDGPU_RAS_ERROR__SINGLE_CORRECTABLE, 0, 0}, + {"ras_gfx.2.2", "gfx", AMDGPU_RAS_BLOCK__GFX_CPG_TAG, + AMDGPU_RAS_ERROR__SINGLE_CORRECTABLE, 0, 0}, + {"ras_gfx.2.3", "gfx", AMDGPU_RAS_BLOCK__GFX_SQ_LDS_D, + AMDGPU_RAS_ERROR__SINGLE_CORRECTABLE, 0, 0}, + {"ras_gfx.2.4", "gfx", AMDGPU_RAS_BLOCK__GFX_SQC_DATA_CU1_UTCL1_LFIFO, + AMDGPU_RAS_ERROR__SINGLE_CORRECTABLE, 0, 0}, + {"ras_gfx.2.5", "gfx", AMDGPU_RAS_BLOCK__GFX_SQC_INST_BANKA_TAG_RAM, + AMDGPU_RAS_ERROR__SINGLE_CORRECTABLE, 0, 0}, + {"ras_gfx.2.6", "gfx", AMDGPU_RAS_BLOCK__GFX_SQC_INST_BANKB_TAG_RAM, + AMDGPU_RAS_ERROR__SINGLE_CORRECTABLE, 0, 0}, + {"ras_gfx.2.7", "gfx", AMDGPU_RAS_BLOCK__GFX_TA_FS_DFIFO, + AMDGPU_RAS_ERROR__SINGLE_CORRECTABLE, 0, 0}, + {"ras_gfx.2.8", "gfx", AMDGPU_RAS_BLOCK__GFX_TCC_CACHE_DATA, + AMDGPU_RAS_ERROR__SINGLE_CORRECTABLE, 0, 0}, + {"ras_gfx.2.9", "gfx", AMDGPU_RAS_BLOCK__GFX_TCC_CACHE_DATA_BANK_0_1, + AMDGPU_RAS_ERROR__SINGLE_CORRECTABLE, 0, 0}, + {"ras_gfx.2.10", "gfx", AMDGPU_RAS_BLOCK__GFX_TCC_CACHE_DATA_BANK_1_0, + AMDGPU_RAS_ERROR__SINGLE_CORRECTABLE, 0, 0}, + {"ras_gfx.2.11", "gfx", AMDGPU_RAS_BLOCK__GFX_TCC_CACHE_DATA_BANK_1_1, + AMDGPU_RAS_ERROR__SINGLE_CORRECTABLE, 0, 0}, + {"ras_gfx.2.12", "gfx", AMDGPU_RAS_BLOCK__GFX_TCP_CACHE_RAM, + AMDGPU_RAS_ERROR__SINGLE_CORRECTABLE, 0, 0}, + {"ras_gfx.2.13", "gfx", AMDGPU_RAS_BLOCK__GFX_TD_SS_FIFO_LO, + AMDGPU_RAS_ERROR__SINGLE_CORRECTABLE, 0, 0}, + {"ras_gfx.2.14", "gfx", AMDGPU_RAS_BLOCK__GFX_EA_DRAMRD_CMDMEM, + AMDGPU_RAS_ERROR__SINGLE_CORRECTABLE, 0, 0}, +}; + +static const struct ras_DID_test_mask ras_DID_array[] = { + {0x66a1, 0x00, RAS_BLOCK_MASK_ALL}, + {0x66a1, 0x01, RAS_BLOCK_MASK_ALL}, + {0x66a1, 0x04, RAS_BLOCK_MASK_ALL}, +}; + +static uint32_t amdgpu_ras_find_block_id_by_name(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ras_block_string); i++) { + if (strcmp(name, ras_block_string[i]) == 0) + return i; + } + + return ARRAY_SIZE(ras_block_string); +} + +static char *amdgpu_ras_get_error_type_id(enum amdgpu_ras_error_type type) +{ + switch (type) { + case AMDGPU_RAS_ERROR__PARITY: + return "parity"; + case AMDGPU_RAS_ERROR__SINGLE_CORRECTABLE: + return "single_correctable"; + case AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE: + return "multi_uncorrectable"; + case AMDGPU_RAS_ERROR__POISON: + return "poison"; + case AMDGPU_RAS_ERROR__NONE: + default: + return NULL; + } +} + +static struct ras_test_mask amdgpu_ras_get_test_mask(drmDevicePtr device) +{ + int i; + static struct ras_test_mask default_test_mask = RAS_BLOCK_MASK_QUERY_BASIC; + + for (i = 0; i < sizeof(ras_DID_array) / sizeof(ras_DID_array[0]); i++) { + if (ras_DID_array[i].device_id == device->deviceinfo.pci->device_id && + ras_DID_array[i].revision_id == device->deviceinfo.pci->revision_id) + return ras_DID_array[i].test_mask; + } + return default_test_mask; +} + +static uint32_t amdgpu_ras_lookup_capability(amdgpu_device_handle device_handle) +{ + union { + uint64_t feature_mask; + struct { + uint32_t enabled_features; + uint32_t supported_features; + }; + } features = { 0 }; + int ret; + + ret = amdgpu_query_info(device_handle, AMDGPU_INFO_RAS_ENABLED_FEATURES, + sizeof(features), &features); + if (ret) + return 0; + + return features.supported_features; +} + +static int get_file_contents(char *file, char *buf, int size); + +static int amdgpu_ras_lookup_id(drmDevicePtr device) +{ + char path[PATH_SIZE]; + char str[128]; + drmPciBusInfo info; + int i; + int ret; + + for (i = 0; i < MAX_CARDS_SUPPORTED; i++) { + memset(str, 0, sizeof(str)); + memset(&info, 0, sizeof(info)); + snprintf(path, PATH_SIZE, "/sys/kernel/debug/dri/%d/name", i); + if (get_file_contents(path, str, sizeof(str)) <= 0) + continue; + + ret = sscanf(str, "amdgpu dev=%04hx:%02hhx:%02hhx.%01hhx", + &info.domain, &info.bus, &info.dev, &info.func); + if (ret != 4) + continue; + + if (memcmp(&info, device->businfo.pci, sizeof(info)) == 0) + return i; + } + return -1; +} + +//helpers + +static int test_card; +static char sysfs_path[PATH_SIZE]; +static char debugfs_path[PATH_SIZE]; +static uint32_t ras_mask; +static amdgpu_device_handle device_handle; + +static void set_test_card(int card) +{ + test_card = card; + snprintf(sysfs_path, PATH_SIZE, "/sys/class/drm/card%d/device/ras/", devices[card].id); + snprintf(debugfs_path, PATH_SIZE, "/sys/kernel/debug/dri/%d/ras/", devices[card].id); + ras_mask = devices[card].capability; + device_handle = devices[card].device_handle; + ras_block_mask_inject = devices[card].test_mask.inject_mask; + ras_block_mask_query = devices[card].test_mask.query_mask; + ras_block_mask_basic = devices[card].test_mask.basic_mask; +} + +static const char *get_ras_sysfs_root(void) +{ + return sysfs_path; +} + +static const char *get_ras_debugfs_root(void) +{ + return debugfs_path; +} + +static int set_file_contents(char *file, char *buf, int size) +{ + int n, fd; + fd = open(file, O_WRONLY); + if (fd == -1) + return -1; + n = write(fd, buf, size); + close(fd); + return n; +} + +static int get_file_contents(char *file, char *buf, int size) +{ + int n, fd; + fd = open(file, O_RDONLY); + if (fd == -1) + return -1; + n = read(fd, buf, size); + close(fd); + return n; +} + +static int is_file_ok(char *file, int flags) +{ + int fd; + + fd = open(file, flags); + if (fd == -1) + return -1; + close(fd); + return 0; +} + +static int amdgpu_ras_is_feature_enabled(enum amdgpu_ras_block block) +{ + uint32_t feature_mask; + int ret; + + ret = amdgpu_query_info(device_handle, AMDGPU_INFO_RAS_ENABLED_FEATURES, + sizeof(feature_mask), &feature_mask); + if (ret) + return -1; + + return (1 << block) & feature_mask; +} + +static int amdgpu_ras_is_feature_supported(enum amdgpu_ras_block block) +{ + return (1 << block) & ras_mask; +} + +static int amdgpu_ras_invoke(struct ras_debug_if *data) +{ + char path[PATH_SIZE]; + int ret; + + snprintf(path, sizeof(path), "%s", get_ras_debugfs_root()); + strncat(path, "ras_ctrl", sizeof(path) - strlen(path)); + + ret = set_file_contents(path, (char *)data, sizeof(*data)) + - sizeof(*data); + return ret; +} + +static int amdgpu_ras_query_err_count(enum amdgpu_ras_block block, + unsigned long *ue, unsigned long *ce) +{ + char buf[64]; + char name[PATH_SIZE]; + + *ue = *ce = 0; + + if (amdgpu_ras_is_feature_supported(block) <= 0) + return -1; + + snprintf(name, sizeof(name), "%s", get_ras_sysfs_root()); + strncat(name, ras_block_str(block), sizeof(name) - strlen(name)); + strncat(name, "_err_count", sizeof(name) - strlen(name)); + + if (is_file_ok(name, O_RDONLY)) + return 0; + + if (get_file_contents(name, buf, sizeof(buf)) <= 0) + return -1; + + if (sscanf(buf, "ue: %lu\nce: %lu", ue, ce) != 2) + return -1; + + return 0; +} + +static int amdgpu_ras_inject(enum amdgpu_ras_block block, + uint32_t sub_block, enum amdgpu_ras_error_type type, + uint64_t address, uint64_t value) +{ + struct ras_debug_if data = { .op = 2, }; + struct ras_inject_if *inject = &data.inject; + int ret; + + if (amdgpu_ras_is_feature_enabled(block) <= 0) { + fprintf(stderr, "block id(%d) is not valid\n", block); + return -1; + } + + inject->head.block = block; + inject->head.type = type; + inject->head.sub_block_index = sub_block; + strncpy(inject->head.name, ras_block_str(block), sizeof(inject->head.name)-1); + inject->address = address; + inject->value = value; + + ret = amdgpu_ras_invoke(&data); + CU_ASSERT_EQUAL(ret, 0); + if (ret) + return -1; + + return 0; +} + +//tests +static void amdgpu_ras_features_test(int enable) +{ + struct ras_debug_if data; + int ret; + int i; + + data.op = enable; + for (i = 0; i < AMDGPU_RAS_BLOCK__LAST; i++) { + struct ras_common_if head = { + .block = i, + .type = AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE, + .sub_block_index = 0, + .name = "", + }; + + if (amdgpu_ras_is_feature_supported(i) <= 0) + continue; + + data.head = head; + + ret = amdgpu_ras_invoke(&data); + CU_ASSERT_EQUAL(ret, 0); + + if (ret) + continue; + + ret = enable ^ amdgpu_ras_is_feature_enabled(i); + CU_ASSERT_EQUAL(ret, 0); + } +} + +static void amdgpu_ras_disable_test(void) +{ + int i; + for (i = 0; i < devices_count; i++) { + set_test_card(i); + amdgpu_ras_features_test(0); + } +} + +static void amdgpu_ras_enable_test(void) +{ + int i; + for (i = 0; i < devices_count; i++) { + set_test_card(i); + amdgpu_ras_features_test(1); + } +} + +static void __amdgpu_ras_ip_inject_test(const struct ras_inject_test_config *ip_test, + uint32_t size) +{ + int i, ret; + unsigned long old_ue, old_ce; + unsigned long ue, ce; + uint32_t block; + int timeout; + bool pass; + + for (i = 0; i < size; i++) { + timeout = 3; + pass = false; + + block = amdgpu_ras_find_block_id_by_name(ip_test[i].block); + + /* Ensure one valid ip block */ + if (block == ARRAY_SIZE(ras_block_string)) + break; + + /* Ensure RAS feature for the IP block is enabled by kernel */ + if (amdgpu_ras_is_feature_supported(block) <= 0) + break; + + ret = amdgpu_ras_query_err_count(block, &old_ue, &old_ce); + CU_ASSERT_EQUAL(ret, 0); + if (ret) + break; + + ret = amdgpu_ras_inject(block, + ip_test[i].sub_block, + ip_test[i].type, + ip_test[i].address, + ip_test[i].value); + CU_ASSERT_EQUAL(ret, 0); + if (ret) + break; + + while (timeout > 0) { + sleep(5); + + ret = amdgpu_ras_query_err_count(block, &ue, &ce); + CU_ASSERT_EQUAL(ret, 0); + if (ret) + break; + + if (old_ue != ue || old_ce != ce) { + pass = true; + sleep(20); + break; + } + timeout -= 1; + } + printf("\t Test %s@block %s, subblock %d, error_type %s, address %ld, value %ld: %s\n", + ip_test[i].name, + ip_test[i].block, + ip_test[i].sub_block, + amdgpu_ras_get_error_type_id(ip_test[i].type), + ip_test[i].address, + ip_test[i].value, + pass ? "Pass" : "Fail"); + } +} + +static void __amdgpu_ras_inject_test(void) +{ + printf("...\n"); + + /* run UMC ras inject test */ + __amdgpu_ras_ip_inject_test(umc_ras_inject_test, + ARRAY_SIZE(umc_ras_inject_test)); + + /* run GFX ras inject test */ + __amdgpu_ras_ip_inject_test(gfx_ras_inject_test, + ARRAY_SIZE(gfx_ras_inject_test)); +} + +static void amdgpu_ras_inject_test(void) +{ + int i; + for (i = 0; i < devices_count; i++) { + set_test_card(i); + __amdgpu_ras_inject_test(); + } +} + +static void __amdgpu_ras_query_test(void) +{ + unsigned long ue, ce; + int ret; + int i; + + for (i = 0; i < AMDGPU_RAS_BLOCK__LAST; i++) { + if (amdgpu_ras_is_feature_supported(i) <= 0) + continue; + + if (!((1 << i) & ras_block_mask_query)) + continue; + + ret = amdgpu_ras_query_err_count(i, &ue, &ce); + CU_ASSERT_EQUAL(ret, 0); + } +} + +static void amdgpu_ras_query_test(void) +{ + int i; + for (i = 0; i < devices_count; i++) { + set_test_card(i); + __amdgpu_ras_query_test(); + } +} + +static void amdgpu_ras_basic_test(void) +{ + int ret; + int i; + int j; + uint32_t features; + char path[PATH_SIZE]; + + ret = is_file_ok("/sys/module/amdgpu/parameters/ras_mask", O_RDONLY); + CU_ASSERT_EQUAL(ret, 0); + + for (i = 0; i < devices_count; i++) { + set_test_card(i); + + ret = amdgpu_query_info(device_handle, AMDGPU_INFO_RAS_ENABLED_FEATURES, + sizeof(features), &features); + CU_ASSERT_EQUAL(ret, 0); + + snprintf(path, sizeof(path), "%s", get_ras_debugfs_root()); + strncat(path, "ras_ctrl", sizeof(path) - strlen(path)); + + ret = is_file_ok(path, O_WRONLY); + CU_ASSERT_EQUAL(ret, 0); + + snprintf(path, sizeof(path), "%s", get_ras_sysfs_root()); + strncat(path, "features", sizeof(path) - strlen(path)); + + ret = is_file_ok(path, O_RDONLY); + CU_ASSERT_EQUAL(ret, 0); + + for (j = 0; j < AMDGPU_RAS_BLOCK__LAST; j++) { + ret = amdgpu_ras_is_feature_supported(j); + if (ret <= 0) + continue; + + if (!((1 << j) & ras_block_mask_basic)) + continue; + + snprintf(path, sizeof(path), "%s", get_ras_sysfs_root()); + strncat(path, ras_block_str(j), sizeof(path) - strlen(path)); + strncat(path, "_err_count", sizeof(path) - strlen(path)); + + ret = is_file_ok(path, O_RDONLY); + CU_ASSERT_EQUAL(ret, 0); + + snprintf(path, sizeof(path), "%s", get_ras_debugfs_root()); + strncat(path, ras_block_str(j), sizeof(path) - strlen(path)); + strncat(path, "_err_inject", sizeof(path) - strlen(path)); + + ret = is_file_ok(path, O_WRONLY); + CU_ASSERT_EQUAL(ret, 0); + } + } +} + +CU_TestInfo ras_tests[] = { + { "ras basic test", amdgpu_ras_basic_test }, + { "ras query test", amdgpu_ras_query_test }, + { "ras inject test", amdgpu_ras_inject_test }, + { "ras disable test", amdgpu_ras_disable_test }, + { "ras enable test", amdgpu_ras_enable_test }, + CU_TEST_INFO_NULL, +}; + +CU_BOOL suite_ras_tests_enable(void) +{ + amdgpu_device_handle device_handle; + uint32_t major_version; + uint32_t minor_version; + int i; + drmDevicePtr device; + + for (i = 0; i < MAX_CARDS_SUPPORTED && drm_amdgpu[i] >= 0; i++) { + if (amdgpu_device_initialize(drm_amdgpu[i], &major_version, + &minor_version, &device_handle)) + continue; + + if (drmGetDevice2(drm_amdgpu[i], + DRM_DEVICE_GET_PCI_REVISION, + &device)) + continue; + + if (device->bustype == DRM_BUS_PCI && + amdgpu_ras_lookup_capability(device_handle)) { + amdgpu_device_deinitialize(device_handle); + return CU_TRUE; + } + + if (amdgpu_device_deinitialize(device_handle)) + continue; + } + + return CU_FALSE; +} + +int suite_ras_tests_init(void) +{ + drmDevicePtr device; + amdgpu_device_handle device_handle; + uint32_t major_version; + uint32_t minor_version; + uint32_t capability; + struct ras_test_mask test_mask; + int id; + int i; + int r; + + for (i = 0; i < MAX_CARDS_SUPPORTED && drm_amdgpu[i] >= 0; i++) { + r = amdgpu_device_initialize(drm_amdgpu[i], &major_version, + &minor_version, &device_handle); + if (r) + continue; + + if (drmGetDevice2(drm_amdgpu[i], + DRM_DEVICE_GET_PCI_REVISION, + &device)) { + amdgpu_device_deinitialize(device_handle); + continue; + } + + if (device->bustype != DRM_BUS_PCI) { + amdgpu_device_deinitialize(device_handle); + continue; + } + + capability = amdgpu_ras_lookup_capability(device_handle); + if (capability == 0) { + amdgpu_device_deinitialize(device_handle); + continue; + + } + + id = amdgpu_ras_lookup_id(device); + if (id == -1) { + amdgpu_device_deinitialize(device_handle); + continue; + } + + test_mask = amdgpu_ras_get_test_mask(device); + + devices[devices_count++] = (struct amdgpu_ras_data) { + device_handle, id, capability, test_mask, + }; + } + + if (devices_count == 0) + return CUE_SINIT_FAILED; + + return CUE_SUCCESS; +} + +int suite_ras_tests_clean(void) +{ + int r; + int i; + int ret = CUE_SUCCESS; + + for (i = 0; i < devices_count; i++) { + r = amdgpu_device_deinitialize(devices[i].device_handle); + if (r) + ret = CUE_SCLEAN_FAILED; + } + return ret; +} diff --git a/tests/amdgpu/security_tests.c b/tests/amdgpu/security_tests.c new file mode 100644 index 0000000..e6c9f9a --- /dev/null +++ b/tests/amdgpu/security_tests.c @@ -0,0 +1,486 @@ +/* + * Copyright 2019 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + */ + +#include "CUnit/Basic.h" + +#include "amdgpu_test.h" +#include "amdgpu_drm.h" +#include "amdgpu_internal.h" + +#include +#include +#ifdef __FreeBSD__ +#include +#else +#include +#endif +#include +#include + +static amdgpu_device_handle device_handle; +static uint32_t major_version; +static uint32_t minor_version; + +static struct drm_amdgpu_info_hw_ip sdma_info; + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(_Arr) (sizeof(_Arr)/sizeof((_Arr)[0])) +#endif + + +/* --------------------- Secure bounce test ------------------------ * + * + * The secure bounce test tests that we can evict a TMZ buffer, + * and page it back in, via a bounce buffer, as it encryption/decryption + * depends on its physical address, and have the same data, i.e. data + * integrity is preserved. + * + * The steps are as follows (from Christian K.): + * + * Buffer A which is TMZ protected and filled by the CPU with a + * certain pattern. That the GPU is reading only random nonsense from + * that pattern is irrelevant for the test. + * + * This buffer A is then secure copied into buffer B which is also + * TMZ protected. + * + * Buffer B is moved around, from VRAM to GTT, GTT to SYSTEM, + * etc. + * + * Then, we use another secure copy of buffer B back to buffer A. + * + * And lastly we check with the CPU the pattern. + * + * Assuming that we don't have memory contention and buffer A stayed + * at the same place, we should still see the same pattern when read + * by the CPU. + * + * If we don't see the same pattern then something in the buffer + * migration code is not working as expected. + */ + +#define SECURE_BOUNCE_TEST_STR "secure bounce" +#define SECURE_BOUNCE_FAILED_STR SECURE_BOUNCE_TEST_STR " failed" + +#define PRINT_ERROR(_Res) fprintf(stderr, "%s:%d: %s (%d)\n", \ + __func__, __LINE__, strerror(-(_Res)), _Res) + +#define PACKET_LCOPY_SIZE 7 +#define PACKET_NOP_SIZE 12 + +struct sec_amdgpu_bo { + struct amdgpu_bo *bo; + struct amdgpu_va *va; +}; + +struct command_ctx { + struct amdgpu_device *dev; + struct amdgpu_cs_ib_info cs_ibinfo; + struct amdgpu_cs_request cs_req; + struct amdgpu_context *context; + int ring_id; +}; + +/** + * amdgpu_bo_alloc_map -- Allocate and map a buffer object (BO) + * @dev: The AMDGPU device this BO belongs to. + * @size: The size of the BO. + * @alignment: Alignment of the BO. + * @gem_domain: One of AMDGPU_GEM_DOMAIN_xyz. + * @alloc_flags: One of AMDGPU_GEM_CREATE_xyz. + * @sbo: the result + * + * Allocate a buffer object (BO) with the desired attributes + * as specified by the argument list and write out the result + * into @sbo. + * + * Return 0 on success and @sbo->bo and @sbo->va are set, + * or -errno on error. + */ +static int amdgpu_bo_alloc_map(struct amdgpu_device *dev, + unsigned size, + unsigned alignment, + unsigned gem_domain, + uint64_t alloc_flags, + struct sec_amdgpu_bo *sbo) +{ + void *cpu; + uint64_t mc_addr; + + return amdgpu_bo_alloc_and_map_raw(dev, + size, + alignment, + gem_domain, + alloc_flags, + 0, + &sbo->bo, + &cpu, &mc_addr, + &sbo->va); +} + +static void amdgpu_bo_unmap_free(struct sec_amdgpu_bo *sbo, + const uint64_t size) +{ + (void) amdgpu_bo_unmap_and_free(sbo->bo, + sbo->va, + sbo->va->address, + size); + sbo->bo = NULL; + sbo->va = NULL; +} + +static void amdgpu_sdma_lcopy(uint32_t *packet, + const uint64_t dst, + const uint64_t src, + const uint32_t size, + const int secure) +{ + /* Set the packet to Linear copy with TMZ set. + */ + packet[0] = htole32(secure << 18 | 1); + packet[1] = htole32(size-1); + packet[2] = htole32(0); + packet[3] = htole32((uint32_t)(src & 0xFFFFFFFFU)); + packet[4] = htole32((uint32_t)(src >> 32)); + packet[5] = htole32((uint32_t)(dst & 0xFFFFFFFFU)); + packet[6] = htole32((uint32_t)(dst >> 32)); +} + +static void amdgpu_sdma_nop(uint32_t *packet, uint32_t nop_count) +{ + /* A packet of the desired number of NOPs. + */ + packet[0] = htole32(nop_count << 16); + for ( ; nop_count > 0; nop_count--) + packet[nop_count-1] = 0; +} + +/** + * amdgpu_bo_lcopy -- linear copy with TMZ set, using sDMA + * @dev: AMDGPU device to which both buffer objects belong to + * @dst: destination buffer object + * @src: source buffer object + * @size: size of memory to move, in bytes. + * @secure: Set to 1 to perform secure copy, 0 for clear + * + * Issues and waits for completion of a Linear Copy with TMZ + * set, to the sDMA engine. @size should be a multiple of + * at least 16 bytes. + */ +static void amdgpu_bo_lcopy(struct command_ctx *ctx, + struct sec_amdgpu_bo *dst, + struct sec_amdgpu_bo *src, + const uint32_t size, + int secure) +{ + struct amdgpu_bo *bos[] = { dst->bo, src->bo }; + uint32_t packet[PACKET_LCOPY_SIZE]; + + amdgpu_sdma_lcopy(packet, + dst->va->address, + src->va->address, + size, secure); + amdgpu_test_exec_cs_helper_raw(ctx->dev, ctx->context, + AMDGPU_HW_IP_DMA, ctx->ring_id, + ARRAY_SIZE(packet), packet, + ARRAY_SIZE(bos), bos, + &ctx->cs_ibinfo, &ctx->cs_req, + secure == 1); +} + +/** + * amdgpu_bo_move -- Evoke a move of the buffer object (BO) + * @dev: device to which this buffer object belongs to + * @bo: the buffer object to be moved + * @whereto: one of AMDGPU_GEM_DOMAIN_xyz + * @secure: set to 1 to submit secure IBs + * + * Evokes a move of the buffer object @bo to the GEM domain + * descibed by @whereto. + * + * Returns 0 on sucess; -errno on error. + */ +static int amdgpu_bo_move(struct command_ctx *ctx, + struct amdgpu_bo *bo, + uint64_t whereto, + int secure) +{ + struct amdgpu_bo *bos[] = { bo }; + struct drm_amdgpu_gem_op gop = { + .handle = bo->handle, + .op = AMDGPU_GEM_OP_SET_PLACEMENT, + .value = whereto, + }; + uint32_t packet[PACKET_NOP_SIZE]; + int res; + + /* Change the buffer's placement. + */ + res = drmIoctl(ctx->dev->fd, DRM_IOCTL_AMDGPU_GEM_OP, &gop); + if (res) + return -errno; + + /* Now issue a NOP to actually evoke the MM to move + * it to the desired location. + */ + amdgpu_sdma_nop(packet, PACKET_NOP_SIZE); + amdgpu_test_exec_cs_helper_raw(ctx->dev, ctx->context, + AMDGPU_HW_IP_DMA, ctx->ring_id, + ARRAY_SIZE(packet), packet, + ARRAY_SIZE(bos), bos, + &ctx->cs_ibinfo, &ctx->cs_req, + secure == 1); + return 0; +} + +/* Safe, O Sec! + */ +static const uint8_t secure_pattern[] = { 0x5A, 0xFE, 0x05, 0xEC }; + +#define SECURE_BUFFER_SIZE (4 * 1024 * sizeof(secure_pattern)) + +static void amdgpu_secure_bounce(void) +{ + struct sec_amdgpu_bo alice, bob; + struct command_ctx sb_ctx; + long page_size; + uint8_t *pp; + int res; + + page_size = sysconf(_SC_PAGESIZE); + + memset(&sb_ctx, 0, sizeof(sb_ctx)); + sb_ctx.dev = device_handle; + res = amdgpu_cs_ctx_create(sb_ctx.dev, &sb_ctx.context); + if (res) { + PRINT_ERROR(res); + CU_FAIL(SECURE_BOUNCE_FAILED_STR); + return; + } + + /* Use the first present ring. + */ + res = ffs(sdma_info.available_rings) - 1; + if (res == -1) { + PRINT_ERROR(-ENOENT); + CU_FAIL(SECURE_BOUNCE_FAILED_STR); + goto Out_free_ctx; + } + sb_ctx.ring_id = res; + + /* Allocate a buffer named Alice in VRAM. + */ + res = amdgpu_bo_alloc_map(device_handle, + SECURE_BUFFER_SIZE, + page_size, + AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_ENCRYPTED, + &alice); + if (res) { + PRINT_ERROR(res); + CU_FAIL(SECURE_BOUNCE_FAILED_STR); + return; + } + + /* Fill Alice with a pattern. + */ + for (pp = alice.bo->cpu_ptr; + pp < (__typeof__(pp)) alice.bo->cpu_ptr + SECURE_BUFFER_SIZE; + pp += sizeof(secure_pattern)) + memcpy(pp, secure_pattern, sizeof(secure_pattern)); + + /* Allocate a buffer named Bob in VRAM. + */ + res = amdgpu_bo_alloc_map(device_handle, + SECURE_BUFFER_SIZE, + page_size, + AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_ENCRYPTED, + &bob); + if (res) { + PRINT_ERROR(res); + CU_FAIL(SECURE_BOUNCE_FAILED_STR); + goto Out_free_Alice; + } + + /* sDMA TMZ copy from Alice to Bob. + */ + amdgpu_bo_lcopy(&sb_ctx, &bob, &alice, SECURE_BUFFER_SIZE, 1); + + /* Move Bob to the GTT domain. + */ + res = amdgpu_bo_move(&sb_ctx, bob.bo, AMDGPU_GEM_DOMAIN_GTT, 0); + if (res) { + PRINT_ERROR(res); + CU_FAIL(SECURE_BOUNCE_FAILED_STR); + goto Out_free_all; + } + + /* sDMA TMZ copy from Bob to Alice. + */ + amdgpu_bo_lcopy(&sb_ctx, &alice, &bob, SECURE_BUFFER_SIZE, 1); + + /* Verify the contents of Alice. + */ + for (pp = alice.bo->cpu_ptr; + pp < (__typeof__(pp)) alice.bo->cpu_ptr + SECURE_BUFFER_SIZE; + pp += sizeof(secure_pattern)) { + res = memcmp(pp, secure_pattern, sizeof(secure_pattern)); + if (res) { + fprintf(stderr, SECURE_BOUNCE_FAILED_STR); + CU_FAIL(SECURE_BOUNCE_FAILED_STR); + break; + } + } + +Out_free_all: + amdgpu_bo_unmap_free(&bob, SECURE_BUFFER_SIZE); +Out_free_Alice: + amdgpu_bo_unmap_free(&alice, SECURE_BUFFER_SIZE); +Out_free_ctx: + res = amdgpu_cs_ctx_free(sb_ctx.context); + CU_ASSERT_EQUAL(res, 0); +} + +/* ----------------------------------------------------------------- */ + +static void amdgpu_security_alloc_buf_test(void) +{ + amdgpu_bo_handle bo; + amdgpu_va_handle va_handle; + uint64_t bo_mc; + int r; + + /* Test secure buffer allocation in VRAM */ + bo = gpu_mem_alloc(device_handle, 4096, 4096, + AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_ENCRYPTED, + &bo_mc, &va_handle); + + r = gpu_mem_free(bo, va_handle, bo_mc, 4096); + CU_ASSERT_EQUAL(r, 0); + + /* Test secure buffer allocation in system memory */ + bo = gpu_mem_alloc(device_handle, 4096, 4096, + AMDGPU_GEM_DOMAIN_GTT, + AMDGPU_GEM_CREATE_ENCRYPTED, + &bo_mc, &va_handle); + + r = gpu_mem_free(bo, va_handle, bo_mc, 4096); + CU_ASSERT_EQUAL(r, 0); + + /* Test secure buffer allocation in invisible VRAM */ + bo = gpu_mem_alloc(device_handle, 4096, 4096, + AMDGPU_GEM_DOMAIN_GTT, + AMDGPU_GEM_CREATE_ENCRYPTED | + AMDGPU_GEM_CREATE_NO_CPU_ACCESS, + &bo_mc, &va_handle); + + r = gpu_mem_free(bo, va_handle, bo_mc, 4096); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_security_gfx_submission_test(void) +{ + amdgpu_command_submission_write_linear_helper_with_secure(device_handle, + AMDGPU_HW_IP_GFX, + true); +} + +static void amdgpu_security_sdma_submission_test(void) +{ + amdgpu_command_submission_write_linear_helper_with_secure(device_handle, + AMDGPU_HW_IP_DMA, + true); +} + +/* ----------------------------------------------------------------- */ + +CU_TestInfo security_tests[] = { + { "allocate secure buffer test", amdgpu_security_alloc_buf_test }, + { "graphics secure command submission", amdgpu_security_gfx_submission_test }, + { "sDMA secure command submission", amdgpu_security_sdma_submission_test }, + { SECURE_BOUNCE_TEST_STR, amdgpu_secure_bounce }, + CU_TEST_INFO_NULL, +}; + +CU_BOOL suite_security_tests_enable(void) +{ + CU_BOOL enable = CU_TRUE; + + if (amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle)) + return CU_FALSE; + + + if (!(device_handle->dev_info.ids_flags & AMDGPU_IDS_FLAGS_TMZ)) { + printf("\n\nDon't support TMZ (trust memory zone), security suite disabled\n"); + enable = CU_FALSE; + } + + if ((major_version < 3) || + ((major_version == 3) && (minor_version < 37))) { + printf("\n\nDon't support TMZ (trust memory zone), kernel DRM version (%d.%d)\n", + major_version, minor_version); + printf("is older, security suite disabled\n"); + enable = CU_FALSE; + } + + if (amdgpu_device_deinitialize(device_handle)) + return CU_FALSE; + + return enable; +} + +int suite_security_tests_init(void) +{ + int res; + + res = amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle); + if (res) { + PRINT_ERROR(res); + return CUE_SINIT_FAILED; + } + + res = amdgpu_query_hw_ip_info(device_handle, + AMDGPU_HW_IP_DMA, + 0, &sdma_info); + if (res) { + PRINT_ERROR(res); + return CUE_SINIT_FAILED; + } + + return CUE_SUCCESS; +} + +int suite_security_tests_clean(void) +{ + int res; + + res = amdgpu_device_deinitialize(device_handle); + if (res) + return CUE_SCLEAN_FAILED; + + return CUE_SUCCESS; +} diff --git a/tests/amdgpu/shader_code.h b/tests/amdgpu/shader_code.h new file mode 100644 index 0000000..74d32bb --- /dev/null +++ b/tests/amdgpu/shader_code.h @@ -0,0 +1,153 @@ +/* + * Copyright 2022 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 _shader_code_h_ +#define _shader_code_h_ + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#endif + +enum amdgpu_test_gfx_version { + AMDGPU_TEST_GFX_V9 = 0, + AMDGPU_TEST_GFX_V10, + AMDGPU_TEST_GFX_V11, + AMDGPU_TEST_GFX_MAX, +}; + +enum cs_type { + CS_BUFFERCLEAR = 0, + CS_BUFFERCOPY, + CS_HANG, + CS_HANG_SLOW, +}; + +enum ps_type { + PS_CONST, + PS_TEX, + PS_HANG, + PS_HANG_SLOW +}; + +enum vs_type { + VS_RECTPOSTEXFAST, +}; + +struct reg_info { + uint32_t reg_offset; ///< Memory mapped register offset + uint32_t reg_value; ///< register value +}; + +#include "shader_code_hang.h" +#include "shader_code_gfx9.h" +#include "shader_code_gfx10.h" +#include "shader_code_gfx11.h" + +struct shader_test_cs_shader { + const uint32_t *shader; + uint32_t shader_size; + const struct reg_info *sh_reg; + uint32_t num_sh_reg; + const struct reg_info *context_reg; + uint32_t num_context_reg; +}; + +struct shader_test_ps_shader { + const uint32_t *shader; + unsigned shader_size; + const uint32_t patchinfo_code_size; + const uint32_t *patchinfo_code; + const uint32_t *patchinfo_code_offset; + const struct reg_info *sh_reg; + const uint32_t num_sh_reg; + const struct reg_info *context_reg; + const uint32_t num_context_reg; +}; + +struct shader_test_vs_shader { + const uint32_t *shader; + uint32_t shader_size; + const struct reg_info *sh_reg; + uint32_t num_sh_reg; + const struct reg_info *context_reg; + uint32_t num_context_reg; +}; + +static const struct shader_test_cs_shader shader_test_cs[AMDGPU_TEST_GFX_MAX][2] = { + // gfx9, cs_bufferclear + {{bufferclear_cs_shader_gfx9, sizeof(bufferclear_cs_shader_gfx9), bufferclear_cs_shader_registers_gfx9, ARRAY_SIZE(bufferclear_cs_shader_registers_gfx9)}, + // gfx9, cs_buffercopy + {buffercopy_cs_shader_gfx9, sizeof(buffercopy_cs_shader_gfx9), bufferclear_cs_shader_registers_gfx9, ARRAY_SIZE(bufferclear_cs_shader_registers_gfx9)}}, + // gfx10, cs_bufferclear + {{bufferclear_cs_shader_gfx10, sizeof(bufferclear_cs_shader_gfx10), bufferclear_cs_shader_registers_gfx9, ARRAY_SIZE(bufferclear_cs_shader_registers_gfx9)}, + // gfx10, cs_buffercopy + {buffercopy_cs_shader_gfx10, sizeof(bufferclear_cs_shader_gfx10), bufferclear_cs_shader_registers_gfx9, ARRAY_SIZE(bufferclear_cs_shader_registers_gfx9)}}, + // gfx11, cs_bufferclear + {{bufferclear_cs_shader_gfx11, sizeof(bufferclear_cs_shader_gfx11), bufferclear_cs_shader_registers_gfx11, ARRAY_SIZE(bufferclear_cs_shader_registers_gfx11)}, + // gfx11, cs_buffercopy + {buffercopy_cs_shader_gfx11, sizeof(bufferclear_cs_shader_gfx11), bufferclear_cs_shader_registers_gfx11, ARRAY_SIZE(bufferclear_cs_shader_registers_gfx11)}}, +}; + +#define SHADER_PS_INFO(_ps, _n) \ + {ps_##_ps##_shader_gfx##_n, sizeof(ps_##_ps##_shader_gfx##_n), \ + ps_##_ps##_shader_patchinfo_code_size_gfx##_n, \ + ps_##_ps##_shader_patchinfo_code_gfx##_n, \ + ps_##_ps##_shader_patchinfo_offset_gfx##_n, \ + ps_##_ps##_sh_registers_gfx##_n, ps_##_ps##_num_sh_registers_gfx##_n, \ + ps_##_ps##_context_registers_gfx##_n, ps_##_ps##_num_context_registers_gfx##_n} +static const struct shader_test_ps_shader shader_test_ps[AMDGPU_TEST_GFX_MAX][2] = { + {SHADER_PS_INFO(const, 9), SHADER_PS_INFO(tex, 9)}, + {SHADER_PS_INFO(const, 10), SHADER_PS_INFO(tex, 10)}, + {SHADER_PS_INFO(const, 11), SHADER_PS_INFO(tex, 11)}, +}; + +#define SHADER_VS_INFO(_vs, _n) \ + {vs_##_vs##_shader_gfx##_n, sizeof(vs_##_vs##_shader_gfx##_n), \ + vs_##_vs##_sh_registers_gfx##_n, vs_##_vs##_num_sh_registers_gfx##_n, \ + vs_##_vs##_context_registers_gfx##_n, vs_##_vs##_num_context_registers_gfx##_n} +static const struct shader_test_vs_shader shader_test_vs[AMDGPU_TEST_GFX_MAX][1] = { + {SHADER_VS_INFO(RectPosTexFast, 9)}, + {SHADER_VS_INFO(RectPosTexFast, 10)}, + {SHADER_VS_INFO(RectPosTexFast, 11)}, +}; + +struct shader_test_gfx_info { + const uint32_t *preamble_cache; + uint32_t size_preamble_cache; + const uint32_t *cached_cmd; + uint32_t size_cached_cmd; + uint32_t sh_reg_base; + uint32_t context_reg_base; +}; + +#define SHADER_TEST_GFX_INFO(_n) \ + preamblecache_gfx##_n, sizeof(preamblecache_gfx##_n), \ + cached_cmd_gfx##_n, sizeof(cached_cmd_gfx##_n), \ + sh_reg_base_gfx##_n, context_reg_base_gfx##_n + +static struct shader_test_gfx_info shader_test_gfx_info[AMDGPU_TEST_GFX_MAX] = { + {SHADER_TEST_GFX_INFO(9),}, + {SHADER_TEST_GFX_INFO(10),}, + {SHADER_TEST_GFX_INFO(11),}, +}; +#endif diff --git a/tests/amdgpu/shader_code_gfx10.h b/tests/amdgpu/shader_code_gfx10.h new file mode 100644 index 0000000..4849bbc --- /dev/null +++ b/tests/amdgpu/shader_code_gfx10.h @@ -0,0 +1,202 @@ +/* + * Copyright 2022 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 _shader_code_gfx10_h_ +#define _shader_code_gfx10_h_ + +static const uint32_t bufferclear_cs_shader_gfx10[] = { + 0xD7460004, 0x04010C08, 0x7E000204, 0x7E020205, + 0x7E040206, 0x7E060207, 0xE01C2000, 0x80000004, + 0xBF810000 +}; + +static const uint32_t buffercopy_cs_shader_gfx10[] = { + 0xD7460001, 0x04010C08, 0xE00C2000, 0x80000201, + 0xBF8C3F70, 0xE01C2000, 0x80010201, 0xBF810000 +}; + +static const uint32_t ps_const_shader_gfx10[] = { + 0x7E000200, 0x7E020201, 0x7E040202, 0x7E060203, + 0x5E000300, 0x5E020702, 0xBF800000, 0xBF800000, + 0xF8001C0F, 0x00000100, 0xBF810000 +}; + +static const uint32_t ps_const_shader_patchinfo_code_size_gfx10 = 6; + +static const uint32_t ps_const_shader_patchinfo_code_gfx10[][10][6] = { + {{ 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8001890, 0x00000000 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8001801, 0x00000000 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8001803, 0x00000100 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8001803, 0x00000300 }, + { 0x5E000300, 0x5E020702, 0xBF800000, 0xBF800000, 0xF8001C0F, 0x00000100 }, + { 0xD7690000, 0x00020300, 0xD7690001, 0x00020702, 0xF8001C0F, 0x00000100 }, + { 0xD7680000, 0x00020300, 0xD7680001, 0x00020702, 0xF8001C0F, 0x00000100 }, + { 0xD76A0000, 0x00020300, 0xD76A0001, 0x00020702, 0xF8001C0F, 0x00000100 }, + { 0xD76B0000, 0x00020300, 0xD76B0001, 0x00020702, 0xF8001C0F, 0x00000100 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF800180F, 0x03020100 } + } +}; + +static const uint32_t ps_const_shader_patchinfo_offset_gfx10[] = { + 0x00000004 +}; + +static const uint32_t ps_const_num_sh_registers_gfx10 = 2; + +static const struct reg_info ps_const_sh_registers_gfx10[] = { + {0x2C0A, 0x000C0000},//{ mmSPI_SHADER_PGM_RSRC1_PS, 0x000C0000 }, + {0x2C0B, 0x00000008}, //{ mmSPI_SHADER_PGM_RSRC2_PS, 0x00000008 } +}; + +static const struct reg_info ps_const_context_registers_gfx10[] = +{ + {0xA1B4, 0x00000002}, //{ mmSPI_PS_INPUT_ADDR, 0x00000002 }, + {0xA1B6, 0x00000000}, //{ mmSPI_PS_IN_CONTROL, 0x00000000 }, + {0xA08F, 0x0000000F}, //{ mmCB_SHADER_MASK, 0x0000000F }, + {0xA203, 0x00000010}, //{ mmDB_SHADER_CONTROL, 0x00000010 }, + {0xA1C4, 0x00000000}, //{ mmSPI_SHADER_Z_FORMAT, 0x00000000 }, + {0xA1B8, 0x00000000}, //{ mmSPI_BARYC_CNTL, 0x00000000 /* Always 0 for now */}, + {0xA1C5, 0x00000004}, //{ mmSPI_SHADER_COL_FORMAT, 0x00000004 /* SI_EXPORT_FMT_FP16_ABGR */ } +}; + +static const uint32_t ps_const_num_context_registers_gfx10 = 7; + +static const uint32_t ps_tex_shader_gfx10[] = { + 0xBEFC030C, 0xBE8E047E, 0xBEFE0A7E, 0xC8080000, + 0xC80C0100, 0xC8090001, 0xC80D0101, 0xF0800F0A, + 0x00400402, 0x00000003, 0xBEFE040E, 0xBF8C0F70, + 0x5E000B04, 0x5E020F06, 0xBF800000, 0xBF800000, + 0xF8001C0F, 0x00000100, 0xBF810000 +}; + +static const uint32_t ps_tex_shader_patchinfo_offset_gfx10[] = { + 0x0000000C +}; + +static const uint32_t ps_tex_shader_patchinfo_code_size_gfx10 = 6; + +static const uint32_t ps_tex_shader_patchinfo_code_gfx10[][10][6] = { + {{ 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8001890, 0x00000000 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8001801, 0x00000004 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8001803, 0x00000504 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8001803, 0x00000704 }, + { 0x5E000B04, 0x5E020F06, 0xBF800000, 0xBF800000, 0xF8001C0F, 0x00000100 }, + { 0xD7690000, 0x00020B04, 0xD7690001, 0x00020F06, 0xF8001C0F, 0x00000100 }, + { 0xD7680000, 0x00020B04, 0xD7680001, 0x00020F06, 0xF8001C0F, 0x00000100 }, + { 0xD76A0000, 0x00020B04, 0xD76A0001, 0x00020F06, 0xF8001C0F, 0x00000100 }, + { 0xD76B0000, 0x00020B04, 0xD76B0001, 0x00020F06, 0xF8001C0F, 0x00000100 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF800180F, 0x07060504 } + } +}; + +static const struct reg_info ps_tex_sh_registers_gfx10[] = +{ + {0x2C0A, 0xc0081}, //0x020C0080 }, //{ mmSPI_SHADER_PGM_RSRC1_PS, 0x020C0080 }, + {0x2C0B, 0x00000018 }, //{ mmSPI_SHADER_PGM_RSRC2_PS, 0x00000018 } +}; + +static const uint32_t ps_tex_num_sh_registers_gfx10 = 2; + +// Holds Context Register Information +static const struct reg_info ps_tex_context_registers_gfx10[] = +{ + {0xA1B4, 0x00000002}, //{ mmSPI_PS_INPUT_ADDR, 0x00000002 }, + {0xA1B6, 0x00000001}, //{ mmSPI_PS_IN_CONTROL, 0x00000001 }, + {0xA08F, 0x0000000F}, //{ mmCB_SHADER_MASK, 0x0000000F }, + {0xA203, 0x00000010}, //{ mmDB_SHADER_CONTROL, 0x00000010 }, + {0xA1C4, 0x00000000}, //{ mmSPI_SHADER_Z_FORMAT, 0x00000000 }, + {0xA1B8, 0x00000000}, //{ mmSPI_BARYC_CNTL, 0x00000000 /* Always 0 for now */}, + {0xA1C5, 0x00000004}, //{ mmSPI_SHADER_COL_FORMAT, 0x00000004 /* SI_EXPORT_FMT_FP16_ABGR */ } +}; + +static const uint32_t ps_tex_num_context_registers_gfx10 = 7; + +static const uint32_t vs_RectPosTexFast_shader_gfx10[] = { + 0x7E000B00, 0x060000F3, 0x7E020202, 0x7E040206, + 0x7C040080, 0x060000F3, 0xD5010001, 0x01AA0200, + 0x7E060203, 0xD5010002, 0x01AA0404, 0x7E080207, + 0x7C040080, 0xD5010000, 0x01A80101, 0xD5010001, + 0x01AA0601, 0x7E060208, 0x7E0A02F2, 0xD5010002, + 0x01A80902, 0xD5010004, 0x01AA0805, 0x7E0C0209, + 0xF80008CF, 0x05030100, 0xF800020F, 0x05060402, + 0xBF810000 +}; + +static const struct reg_info vs_RectPosTexFast_sh_registers_gfx10[] = +{ + {0x2C4A, 0x080C0041 }, //{ mmSPI_SHADER_PGM_RSRC1_VS, 0x080C0041 }, + {0x2C4B, 0x00000018 }, //{ mmSPI_SHADER_PGM_RSRC2_VS, 0x00000018 } +}; + +static const uint32_t vs_RectPosTexFast_num_sh_registers_gfx10 = 2; + +// Holds Context Register Information +static const struct reg_info vs_RectPosTexFast_context_registers_gfx10[] = +{ + {0xA1B1, 0x00000000}, //{ mmSPI_VS_OUT_CONFIG, 0x00000000 }, + {0xA1C3, 0x00000000}, //{ mmSPI_SHADER_POS_FORMAT, 0x00000000 /* Always 0 for now */} +}; + +static const uint32_t vs_RectPosTexFast_num_context_registers_gfx10 = 2; + +static const uint32_t preamblecache_gfx10[] = { + 0xc0026900, 0x81, 0x80000000, 0x40004000, 0xc0026900, 0x8c, 0xaa99aaaa, 0x0, + 0xc0026900, 0x90, 0x80000000, 0x40004000, 0xc0026900, 0x94, 0x80000000, 0x40004000, + 0xc0026900, 0xb4, 0x0, 0x3f800000, 0xc0016900, 0x103, 0x0, + 0xc0016900, 0x208, 0x0, 0xc0016900, 0x290, 0x0, + 0xc0016900, 0x2a1, 0x0, 0xc0026900, 0x2ad, 0x0, 0x0, + 0xc0016900, 0x2d5, 0x10000, 0xc0016900, 0x2dc, 0x0, + 0xc0066900, 0x2de, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0026900, 0x2e5, 0x0, 0x0, + 0xc0056900, 0x2f9, 0x5, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, + 0xc0046900, 0x310, 0, 0x3, 0, 0x100000, 0xc0026900, 0x316, 0xe, 0x20, + 0xc0016900, 0x349, 0x0, 0xc0016900, 0x358, 0x0, 0xc0016900, 0x367, 0x0, + 0xc0016900, 0x376, 0x0, 0xc0016900, 0x385, 0x0, 0xc0016900, 0x6, 0x0, + 0xc0056900, 0xe8, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xc0076900, 0x1e1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xc0026900, 0x204, 0x90000, 0x4, 0xc0046900, 0x20c, 0x0, 0x0, 0x0, 0x0, + 0xc0016900, 0x2b2, 0x0, 0xc0026900, 0x30e, 0xffffffff, 0xffffffff, + 0xc0016900, 0x314, 0x0, 0xc0016900, 0x10a, 0, 0xc0016900, 0x2a6, 0, 0xc0016900, 0x210, 0, + 0xc0016900, 0x2db, 0, 0xc0016900, 0x1d4, 0, 0xc0002f00, 0x1, 0xc0016900, 0x1, 0x1, 0xc0016900, 0xe, 0x2, + 0xc0016900, 0x206, 0x300, 0xc0016900, 0x212, 0x200, 0xc0017900, 0x7b, 0x20, 0xc0017a00, 0x20000243, 0x0, + 0xc0017900, 0x249, 0, 0xc0017900, 0x24a, 0, 0xc0017900, 0x24b, 0, 0xc0017900, 0x259, 0xffffffff, + 0xc0017900, 0x25f, 0, 0xc0017900, 0x260, 0, 0xc0017900, 0x262, 0, + 0xc0017600, 0x45, 0x0, 0xc0017600, 0x6, 0x0, + 0xc0067600, 0x70, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xc0067600, 0x30, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 +}; + +static const uint32_t cached_cmd_gfx10[] = { + 0xc0016900, 0x0, 0x0, 0xc0026900, 0x3, 0x2a, 0x0, + 0xc0046900, 0xa, 0x0, 0x0, 0x0, 0x200020, + 0xc0016900, 0x83, 0xffff, 0xc0026900, 0x8e, 0xf, 0xf, + 0xc0056900, 0x105, 0x0, 0x0, 0x0, 0x0, 0x18, + 0xc0026900, 0x10b, 0x0, 0x0, 0xc0016900, 0x1e0, 0x0, + 0xc0036900, 0x200, 0x0, 0x10000, 0xcc0011, + 0xc0026900, 0x292, 0x20, 0x6020000, + 0xc0026900, 0x2b0, 0x0, 0x0, 0xc0016900, 0x2f8, 0x0 +}; + +static const uint32_t sh_reg_base_gfx10 = 0x2C00; +static const uint32_t context_reg_base_gfx10 = 0xA000; + +#endif diff --git a/tests/amdgpu/shader_code_gfx11.h b/tests/amdgpu/shader_code_gfx11.h new file mode 100644 index 0000000..d9ee0a7 --- /dev/null +++ b/tests/amdgpu/shader_code_gfx11.h @@ -0,0 +1,320 @@ +/* + * Copyright 2022 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 _shader_code_gfx11_h_ +#define _shader_code_gfx11_h_ + +static const uint32_t bufferclear_cs_shader_gfx11[] = { + 0xB0802006, 0xBF840003, 0x360000FF, 0x000003FF, + 0x7E020205, 0x7E040206, 0x7E060207, 0xBF870004, + 0xD6460004, 0x04010C08, 0x7E000204, 0xE01C0000, + 0x80800004, 0xBFB60003, 0xBFB00000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000 +}; + +static const struct reg_info bufferclear_cs_shader_registers_gfx11[] = { + {0x2e12, 0x600C0041}, //{ mmCOMPUTE_PGM_RSRC1, 0x600C0041 }, + {0x2e13, 0x00000090}, //{ mmCOMPUTE_PGM_RSRC2, 0x00000090 }, + {0x2e07, 0x00000040}, //{ mmCOMPUTE_NUM_THREAD_X, 0x00000040 }, + {0x2e08, 0x00000001}, //{ mmCOMPUTE_NUM_THREAD_Y, 0x00000001 }, + {0x2e09, 0x00000001}, //{ mmCOMPUTE_NUM_THREAD_Z, 0x00000001 } +}; + +static const uint32_t buffercopy_cs_shader_gfx11[] = { + 0xB0802006, 0xBF840003, 0x360000FF, 0x000003FF, + 0xBF870001, 0xD6460001, 0x04010C08, 0xE00C0000, + 0x80800201, 0xBF8903F7, 0xE01C0000, 0x80810201, + 0xBFB60003, 0xBFB00000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000 +}; + +static const uint32_t ps_const_shader_gfx11[] = { + 0xB0802006, 0xBF840003, 0x7E000200, 0x7E020201, + 0x7E040202, 0x7E060203, 0x5E000300, 0x5E020702, + 0xBF800000, 0xBF800000, 0xF8000803, 0x00000100, + 0xBFB00000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000 +}; + +static const uint32_t ps_const_shader_patchinfo_code_size_gfx11 = 6; + +static const uint32_t ps_const_shader_patchinfo_code_gfx11[][10][6] = { + {{ 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8000890, 0x00000000 }, // SI_EXPORT_FMT_ZERO + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8000801, 0x00000000 }, // SI_EXPORT_FMT_32_R + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8000803, 0x00000100 }, // SI_EXPORT_FMT_32_GR + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8000803, 0x00000300 }, // SI_EXPORT_FMT_32_AR + { 0x5E000300, 0x5E020702, 0xBF800000, 0xBF800000, 0xF8000803, 0x00000100 }, // SI_EXPORT_FMT_FP16_ABGR + { 0xD7220000, 0x00020300, 0xD7220001, 0x00020702, 0xF8000803, 0x00000100 }, // SI_EXPORT_FMT_UNORM16_ABGR + { 0xD7210000, 0x00020300, 0xD7210001, 0x00020702, 0xF8000803, 0x00000100 }, // SI_EXPORT_FMT_SNORM16_ABGR + { 0xD7230000, 0x00020300, 0xD7230001, 0x00020702, 0xF8000803, 0x00000100 }, // SI_EXPORT_FMT_uint32_t16_ABGR + { 0xD7240000, 0x00020300, 0xD7240001, 0x00020702, 0xF8000803, 0x00000100 }, // SI_EXPORT_FMT_SINT16_ABGR + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF800080F, 0x03020100 } // SI_EXPORT_FMT_32_ABGR + } +}; + +static const uint32_t ps_const_shader_patchinfo_offset_gfx11[] = { + 0x00000006 +}; + +static const uint32_t ps_const_num_sh_registers_gfx11 = 2; + +static const struct reg_info ps_const_sh_registers_gfx11[] = { + {0x2C0A, 0x020C0000}, //{ mmSPI_SHADER_PGM_RSRC1_PS, 0x020C0000 }, + {0x2C0B, 0x00000008}, //{ mmSPI_SHADER_PGM_RSRC2_PS, 0x00000008 } +}; + +static const struct reg_info ps_const_context_registers_gfx11[] = { + {0xA1B4, 0x00000002 }, //{ mmSPI_PS_INPUT_ADDR, 0x00000002 }, + {0xA1B6, 0x00000000 }, //{ mmSPI_PS_IN_CONTROL, 0x00000000 }, + {0xA08F, 0x0000000F }, //{ mmCB_SHADER_MASK, 0x0000000F }, + {0xA203, 0x00000010 }, //{ mmDB_SHADER_CONTROL, 0x00000010 }, + {0xA1C4, 0x00000000 }, //{ mmSPI_SHADER_Z_FORMAT, 0x00000000 }, + {0xA1B8, 0x00000000 }, //{ mmSPI_BARYC_CNTL, 0x00000000 /* Always 0 for now */}, + {0xA1C5, 0x00000004 }, //{ mmSPI_SHADER_COL_FORMAT, 0x00000004 /* SI_EXPORT_FMT_FP16_ABGR */ } +}; + +static const uint32_t ps_const_num_context_registers_gfx11 = 7; + +static const uint32_t ps_tex_shader_gfx11[] = +{ + 0xB0802006, 0xBF840003, 0xBEFD000C, 0xBE8E017E, + 0xBEFE1D7E, 0xCE000003, 0xCE000102, 0xCD000104, + 0x040E0103, 0xCD000000, 0x040A0102, 0xBF870112, + 0xCD010703, 0x04120303, 0xCD010700, 0x04020302, + 0x8BFE0E7E, 0xF06C0F05, 0x08000003, 0x00000000, + 0xBEFE010E, 0xBF8903F7, 0x5E000300, 0x5E020702, + 0xBF800000, 0xBF800000, 0xF8000803, 0x00000100, + 0xBFB00000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000 +}; + +static const uint32_t ps_tex_shader_patchinfo_offset_gfx11[] = +{ + 0x00000016 +}; + +// Denotes the Patch Info Code Length +static const uint32_t ps_tex_shader_patchinfo_code_size_gfx11 = 6; + +static const uint32_t ps_tex_shader_patchinfo_code_gfx11[][10][6] = +{ + {{ 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8000890, 0x00000000 }, // SI_EXPORT_FMT_ZERO + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8000801, 0x00000000 }, // SI_EXPORT_FMT_32_R + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8000803, 0x00000100 }, // SI_EXPORT_FMT_32_GR + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF8000803, 0x00000300 }, // SI_EXPORT_FMT_32_AR + { 0x5E000300, 0x5E020702, 0xBF800000, 0xBF800000, 0xF8000803, 0x00000100 }, // SI_EXPORT_FMT_FP16_ABGR + { 0xD7220000, 0x00020300, 0xD7220001, 0x00020702, 0xF8000803, 0x00000100 }, // SI_EXPORT_FMT_UNORM16_ABGR + { 0xD7210000, 0x00020300, 0xD7210001, 0x00020702, 0xF8000803, 0x00000100 }, // SI_EXPORT_FMT_SNORM16_ABGR + { 0xD7230000, 0x00020300, 0xD7230001, 0x00020702, 0xF8000803, 0x00000100 }, // SI_EXPORT_FMT_uint32_t16_ABGR + { 0xD7240000, 0x00020300, 0xD7240001, 0x00020702, 0xF8000803, 0x00000100 }, // SI_EXPORT_FMT_SINT16_ABGR + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF800080F, 0x03020100 } // SI_EXPORT_FMT_32_ABGR + } +}; +// Holds Sh Register Information +static const struct reg_info ps_tex_sh_registers_gfx11[] = +{ + {0x2C0A, 0x020C0081 }, //{ mmSPI_SHADER_PGM_RSRC1_PS, 0x020C0081 }, + {0x2C0B, 0x00000018 } //{ mmSPI_SHADER_PGM_RSRC2_PS, 0x00000018 } +}; + +static const uint32_t ps_tex_num_sh_registers_gfx11 = 2; + +// Holds Context Register Information +static const struct reg_info ps_tex_context_registers_gfx11[] = +{ + {0xA1B4, 0x00000002 }, //{ mmSPI_PS_INPUT_ADDR, 0x00000002 }, + {0xA1B6, 0x00000001 }, //{ mmSPI_PS_IN_CONTROL, 0x00000001 }, + {0xA08F, 0x0000000F }, //{ mmCB_SHADER_MASK, 0x0000000F }, + {0xA203, 0x00000010 }, //{ mmDB_SHADER_CONTROL, 0x00000010 }, + {0xA1C4, 0x00000000 }, //{ mmSPI_SHADER_Z_FORMAT, 0x00000000 }, + {0xA1B8, 0x00000000 }, //{ mmSPI_BARYC_CNTL, 0x00000000 /* Always 0 for now */}, + {0xA1C5, 0x00000004 } //{ mmSPI_SHADER_COL_FORMAT, 0x00000004 /* SI_EXPORT_FMT_FP16_ABGR */ } +}; + +static const uint32_t ps_tex_num_context_registers_gfx11 = 7; + + +static const uint32_t vs_RectPosTexFast_shader_gfx11[] = +{ + 0xB0802006, 0xBEFE01C1, 0xBF840003, 0xF408050A, + 0xF80000B0, 0xD71F0001, 0x000100C1, 0x9300FF03, + 0x00040018, 0x9301FF02, 0x0009000C, 0xBF870091, + 0xD7200001, 0x000202C1, 0xD60B0001, 0x04058000, + 0xBF870001, 0xD4490000, 0x00000301, 0xBE862100, + 0x7E040B05, 0xBFA5001C, 0x7E06020A, 0x7E08020E, + 0x7E0A020F, 0xBF8701B4, 0x060404F3, 0x7E140211, + 0x7E0E0210, 0x7C240480, 0x060404F3, 0xD5010003, + 0x01AA0608, 0xD5010004, 0x01AA080C, 0xBF870003, + 0xD4120012, 0x00010102, 0x7E04020B, 0xBEEA1F12, + 0xBF870483, 0xD5010008, 0x01AA080C, 0xD5010006, + 0x01AA0608, 0xBF870003, 0xD5010004, 0x004A0409, + 0xD5010009, 0x004A0A0D, 0xBEFE0106, 0x9302FF02, + 0x00090016, 0xBF870009, 0xD4C9007E, 0x00000501, + 0xBFA50002, 0xF8000941, 0x00000000, 0xBF89FFF0, + 0x8BFE0006, 0xD71F0000, 0x000100C1, 0xBFA50013, + 0x7E1602F2, 0x9300FF03, 0x00040018, 0x8B01FF05, + 0x00007FFF, 0xBF8704B2, 0xD7200000, 0x000200C1, + 0x7E0202F2, 0x84018901, 0x80018001, 0xBF870002, + 0xD60B0000, 0x04018000, 0xF80008CF, 0x01070406, + 0xBF89FC07, 0xE0744000, 0x01850800, 0xBFB00000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, + 0xBF9F0000, 0xBF9F0000, 0xBF9F0000, 0xBF9F0000 +}; + +static const struct reg_info vs_RectPosTexFast_sh_registers_gfx11[] = +{ + {0x2C8A, 0x020C00C2}, //{ mmSPI_SHADER_PGM_RSRC1_GS, 0x020C00C2 }, + {0x2C8B, 0x0008001C}, //{ mmSPI_SHADER_PGM_RSRC2_GS, 0x0008001C } +}; + +static const uint32_t vs_RectPosTexFast_num_sh_registers_gfx11 = 2; + +// Holds Context Register Information +static const struct reg_info vs_RectPosTexFast_context_registers_gfx11[] = +{ + {0xA1B1, 0x00000000}, //{ mmSPI_VS_OUT_CONFIG, 0x00000000 }, + {0xA1C2, 0x00000001}, //{ mmSPI_SHADER_IDX_FORMAT, 0x00000001 }, + {0xA1C3, 0x00000000}, //{ mmSPI_SHADER_POS_FORMAT, 0x00000000 /* Always 0 for now */}, + {0xA2E4, 0x00000000}, //{ mmVGT_GS_INSTANCE_CNT, 0x00000000 }, + {0xA2AB, 0x00000004}, //{ mmVGT_ESGS_RING_ITEMSIZE, 0x00000004 }, + {0xA2CE, 0x00000001}, //{ mmVGT_GS_MAX_VERT_OUT, 0x00000001 } +}; + +static const uint32_t vs_RectPosTexFast_num_context_registers_gfx11 = 6; + +static const uint32_t preamblecache_gfx11[] = { + 0xc0026900, 0x81, 0x80000000, 0x40004000, 0xc0026900, 0x8c, 0xaa99aaaa, 0x0, + 0xc0026900, 0x90, 0x80000000, 0x40004000, 0xc0026900, 0x94, 0x80000000, 0x40004000, + 0xc0026900, 0xb4, 0x0, 0x3f800000, 0xc0016900, 0x103, 0x0, 0xc0016900, 0x208, 0x0, + 0xc0016900, 0x2a1, 0x0, 0xc0016900, 0x2ad, 0x0, 0xc0016900, 0x2dc, 0x0, + 0xc0066900, 0x2de, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xc0056900, 0x2f9, 0x5, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, + 0xc0046900, 0x310, 0x0, 0x3, 0x0, 0x100000, 0xc0016900, 0x349, 0x0, + 0xc0016900, 0x358, 0x0, 0xc0016900, 0x367, 0x0, 0xc0016900, 0x376, 0x0, + 0xc0016900, 0x385, 0x0, 0xc0076900, 0x1e1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xc0026900, 0x204, 0x90000, 0x4, 0xc0016900, 0x20c, 0x0, 0xc0026900, 0x20e, 0x0, 0x0, + 0xc0016900, 0x2b2, 0x0, 0xc0026900, 0x30e, 0xffffffff, 0xffffffff, + 0xc0016900, 0x314, 0x0, 0xc0016900, 0x10a, 0x0, 0xc0016900, 0x2a6, 0x0, + 0xc0016900, 0x210, 0x0, 0xc0016900, 0x2db, 0x0, 0xc0016900, 0x2e4, 0x0, + 0xc0002f00, 0x1, 0xc0016900, 0x1, 0x0, 0xc0016900, 0x206, 0x300, + 0xc0016900, 0x212, 0x200, 0xc0016900, 0xf4, 0x0, 0xc0016900, 0x18, 0x0, + 0xc0016900, 0x1d4, 0xff, 0xc0016900, 0x2ce, 0x1, 0xc0016900, 0x2d3, 0x20001, + 0xc0016900, 0x1ff, 0x80, 0xc0016900, 0x2d5, 0x6012010, 0xc0017a00, 0x20000243, 0x0, + 0xc0017900, 0x249, 0x0, 0xc0017900, 0x24a, 0x0, 0xc0017900, 0x24b, 0x0, + 0xc0017900, 0x259, 0xffffffff, 0xc0017900, 0x25f, 0x0, 0xc0017900, 0x260, 0x0, + 0xc0017900, 0x262, 0x0, 0xc0017900, 0x444, 0x0, 0xc0017900, 0x445, 0x0, + 0xc0017600, 0x6, 0x0, 0xc0017600, 0x80, 0x0, 0xc0017600, 0xb0, 0x0, + 0xc0047600, 0xb2, 0x0, 0x0, 0x0, 0x0, 0xc0017600, 0x30, 0x0, + 0xc0047600, 0x32, 0x0, 0x0, 0x0, 0x0 +}; + +static const uint32_t cached_cmd_gfx11[] = { + 0xc0016900, 0x0, 0x0, 0xc0026900, 0x3, 0x2a, 0x0, + 0xc0046900, 0xa, 0x0, 0x0, 0x0, 0x200020, + 0xc0016900, 0x83, 0xffff, 0xc0026900, 0x8e, 0xf, 0xf, + 0xc0056900, 0x105, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xc0026900, 0x10b, 0x0, 0x0, 0xc0016900, 0x1e0, 0x0, + 0xc0036900, 0x200, 0x0, 0x10000, 0xcc0011, + 0xc0026900, 0x292, 0x20, 0x6020000, + 0xc0026900, 0x2b0, 0x0, 0x0, 0xc0016900, 0x2f8, 0x0, + 0xc0046900, 0x1d5, 0x0, 0x0, 0x0, 0x0, 0xc0016900, 0x104, 0x4a00005, + 0xc0016900, 0x1f, 0xf2a0055, 0xc0017900, 0x266, 0x4 +}; +static const uint32_t sh_reg_base_gfx11 = 0x2C00; +static const uint32_t context_reg_base_gfx11 = 0xA000; + +#endif diff --git a/tests/amdgpu/shader_code_gfx9.h b/tests/amdgpu/shader_code_gfx9.h new file mode 100644 index 0000000..3ad1ca8 --- /dev/null +++ b/tests/amdgpu/shader_code_gfx9.h @@ -0,0 +1,204 @@ +/* + * Copyright 2022 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 _shader_code_gfx9_h_ +#define _shader_code_gfx9_h_ + +static const uint32_t bufferclear_cs_shader_gfx9[] = { + 0x260000ff, 0x000003ff, 0xd1fd0000, 0x04010c08, + 0x7e020280, 0x7e040204, 0x7e060205, 0x7e080206, + 0x7e0a0207, 0xe01c2000, 0x80000200, 0xbf8c0000, + 0xbf810000 +}; + +static const struct reg_info bufferclear_cs_shader_registers_gfx9[] = { + {0x2e12, 0x000C0041}, //{ mmCOMPUTE_PGM_RSRC1, 0x000C0041 }, + {0x2e13, 0x00000090}, //{ mmCOMPUTE_PGM_RSRC2, 0x00000090 }, + {0x2e07, 0x00000040}, //{ mmCOMPUTE_NUM_THREAD_X, 0x00000040 }, + {0x2e08, 0x00000001}, //{ mmCOMPUTE_NUM_THREAD_Y, 0x00000001 }, + {0x2e09, 0x00000001}, //{ mmCOMPUTE_NUM_THREAD_Z, 0x00000001 } +}; + +static const uint32_t buffercopy_cs_shader_gfx9[] = { + 0x260000ff, 0x000003ff, 0xd1fd0000, 0x04010c08, + 0x7e020280, 0xe00c2000, 0x80000200, 0xbf8c0f70, + 0xe01c2000, 0x80010200, 0xbf810000 +}; + +static const uint32_t ps_const_shader_gfx9[] = { + 0x7E000200, 0x7E020201, 0x7E040202, 0x7E060203, + 0xD2960000, 0x00020300, 0xD2960001, 0x00020702, + 0xC4001C0F, 0x00000100, 0xBF810000 +}; + +static const uint32_t ps_const_shader_patchinfo_code_size_gfx9 = 6; + +static const uint32_t ps_const_shader_patchinfo_code_gfx9[][10][6] = { + {{ 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xC4001890, 0x00000000 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xC4001801, 0x00000000 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xC4001803, 0x00000100 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xC4001803, 0x00000300 }, + { 0xD2960000, 0x00020300, 0xD2960001, 0x00020702, 0xC4001C0F, 0x00000100 }, + { 0xD2950000, 0x00020300, 0xD2950001, 0x00020702, 0xC4001C0F, 0x00000100 }, + { 0xD2940000, 0x00020300, 0xD2940001, 0x00020702, 0xC4001C0F, 0x00000100 }, + { 0xD2970000, 0x00020300, 0xD2970001, 0x00020702, 0xC4001C0F, 0x00000100 }, + { 0xD2980000, 0x00020300, 0xD2980001, 0x00020702, 0xC4001C0F, 0x00000100 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xC400180F, 0x03020100 } + } +}; + +static const uint32_t ps_const_shader_patchinfo_offset_gfx9[] = { + 0x00000004 +}; + +static const uint32_t ps_const_num_sh_registers_gfx9 = 2; + +static const struct reg_info ps_const_sh_registers_gfx9[] = { + {0x2C0A, 0x000C0040},//{ mmSPI_SHADER_PGM_RSRC1_PS, 0x000C0040 }, + {0x2C0B, 0x00000008}, //{ mmSPI_SHADER_PGM_RSRC2_PS, 0x00000008 } +}; + +static const uint32_t ps_const_num_context_registers_gfx9 = 7; + +static const struct reg_info ps_const_context_registers_gfx9[] = { + {0xA1B4, 0x00000002}, //{ mmSPI_PS_INPUT_ADDR, 0x00000002 }, + {0xA1B6, 0x00000000}, //{ mmSPI_PS_IN_CONTROL, 0x00000000 }, + {0xA08F, 0x0000000F}, //{ mmCB_SHADER_MASK, 0x0000000F }, + {0xA203, 0x00000010}, //{ mmDB_SHADER_CONTROL, 0x00000010 }, + {0xA1C4, 0x00000000}, //{ mmSPI_SHADER_Z_FORMAT, 0x00000000 }, + {0xA1B8, 0x00000000}, //{ mmSPI_BARYC_CNTL, 0x00000000 /* Always 0 for now */}, + {0xA1C5, 0x00000004}, //{ mmSPI_SHADER_COL_FORMAT, 0x00000004 } +}; + +static const uint32_t ps_tex_shader_gfx9[] = { + 0xBEFC000C, 0xBE8E017E, 0xBEFE077E, 0xD4180000, + 0xD4190001, 0xD41C0100, 0xD41D0101, 0xF0800F00, + 0x00400206, 0xBEFE010E, 0xBF8C0F70, 0xD2960000, + 0x00020702, 0xD2960001, 0x00020B04, 0xC4001C0F, + 0x00000100, 0xBF810000 +}; + +static const uint32_t ps_tex_shader_patchinfo_offset_gfx9[] = { + 0x0000000B +}; + +static const uint32_t ps_tex_shader_patchinfo_code_size_gfx9 = 6; + +static const uint32_t ps_tex_shader_patchinfo_code_gfx9[][10][6] = { + {{ 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xC4001890, 0x00000000 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xC4001801, 0x00000002 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xC4001803, 0x00000302 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xC4001803, 0x00000502 }, + { 0xD2960000, 0x00020702, 0xD2960001, 0x00020B04, 0xC4001C0F, 0x00000100 }, + { 0xD2950000, 0x00020702, 0xD2950001, 0x00020B04, 0xC4001C0F, 0x00000100 }, + { 0xD2940000, 0x00020702, 0xD2940001, 0x00020B04, 0xC4001C0F, 0x00000100 }, + { 0xD2970000, 0x00020702, 0xD2970001, 0x00020B04, 0xC4001C0F, 0x00000100 }, + { 0xD2980000, 0x00020702, 0xD2980001, 0x00020B04, 0xC4001C0F, 0x00000100 }, + { 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xC400180F, 0x05040302 } + } +}; + +static const uint32_t ps_tex_num_sh_registers_gfx9 = 2; +static const struct reg_info ps_tex_sh_registers_gfx9[] = { + {0x2C0A, 0x000C0081},//{ mmSPI_SHADER_PGM_RSRC1_PS, 0x000C0081 }, + {0x2C0B, 0x00000018}, //{ mmSPI_SHADER_PGM_RSRC2_PS, 0x00000018 } +}; + +static const uint32_t ps_tex_num_context_registers_gfx9 = 7; + +static const struct reg_info ps_tex_context_registers_gfx9[] = { + {0xA1B4, 0x00000002}, //{ mmSPI_PS_INPUT_ADDR, 0x00000002 }, + {0xA1B6, 0x00000001}, //{ mmSPI_PS_IN_CONTROL, 0x00000001 }, + {0xA08F, 0x0000000F}, //{ mmCB_SHADER_MASK, 0x0000000F }, + {0xA203, 0x00000010}, //{ mmDB_SHADER_CONTROL, 0x00000010 }, + {0xA1C4, 0x00000000}, //{ mmSPI_SHADER_Z_FORMAT, 0x00000000 }, + {0xA1B8, 0x00000000}, //{ mmSPI_BARYC_CNTL, 0x00000000 /* Always 0 for now */}, + {0xA1C5, 0x00000004}, //{ mmSPI_SHADER_COL_FORMAT, 0x00000004 } +}; + +static const uint32_t vs_RectPosTexFast_shader_gfx9[] = { + 0x7E000B00, 0x020000F3, 0xD042000A, 0x00010100, + 0x7E020202, 0x7E040200, 0x020000F3, 0x7E060206, + 0x7E080204, 0xD1000001, 0x002A0302, 0x7C840080, + 0x7E000200, 0x7E040203, 0x7E0A0201, 0xD1000003, + 0x002A0704, 0x7E0C0207, 0x7E0E0205, 0x00000101, + 0x00020505, 0x7E040208, 0x7E0A02F2, 0x00060903, + 0x00080D07, 0x7E0C0209, 0xC40008CF, 0x05020100, + 0xC400020F, 0x05060403, 0xBF810000 +}; + +static const struct reg_info vs_RectPosTexFast_sh_registers_gfx9[] = +{ + {0x2C4A, 0x000C0081}, //{ mmSPI_SHADER_PGM_RSRC1_VS, 0x000C0081 }, + {0x2C4B, 0x00000018}, //{ mmSPI_SHADER_PGM_RSRC2_VS, 0x00000018 } +}; + +static const uint32_t vs_RectPosTexFast_num_sh_registers_gfx9 = 2; + +// Holds Context Register Information +static const struct reg_info vs_RectPosTexFast_context_registers_gfx9[] = +{ + {0xA1B1, 0x00000000}, //{ mmSPI_VS_OUT_CONFIG, 0x00000000 }, + {0xA1C3, 0x00000000}, //{ mmSPI_SHADER_POS_FORMAT, 0x00000000 /* Always 0 for now */} +}; + +static const uint32_t vs_RectPosTexFast_num_context_registers_gfx9 = 2; + +static const uint32_t preamblecache_gfx9[] = { + 0xc0026900, 0x81, 0x80000000, 0x40004000, 0xc0026900, 0x8c, 0xaa99aaaa, 0x0, + 0xc0026900, 0x90, 0x80000000, 0x40004000, 0xc0026900, 0x94, 0x80000000, 0x40004000, + 0xc0026900, 0xb4, 0x0, 0x3f800000, 0xc0016900, 0x103, 0x0, + 0xc0016900, 0x208, 0x0, 0xc0016900, 0x290, 0x0, + 0xc0016900, 0x2a1, 0x0, 0xc0026900, 0x2ad, 0x0, 0x0, + 0xc0016900, 0x2d5, 0x10000, 0xc0016900, 0x2dc, 0x0, + 0xc0066900, 0x2de, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0026900, 0x2e5, 0x0, 0x0, + 0xc0056900, 0x2f9, 0x5, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, + 0xc0036900, 0x311, 0x3, 0, 0x100000, 0xc0026900, 0x316, 0x1e, 0x20, + 0xc0016900, 0x349, 0x0, 0xc0016900, 0x358, 0x0, 0xc0016900, 0x367, 0x0, + 0xc0016900, 0x376, 0x0, 0xc0016900, 0x385, 0x0, 0xc0016900, 0x19, 0x0, + 0xc0056900, 0xe8, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xc0076900, 0x1e1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xc0026900, 0x204, 0x90000, 0x4, 0xc0046900, 0x20c, 0x0, 0x0, 0x0, 0x0, + 0xc0016900, 0x2b2, 0x0, 0xc0026900, 0x30e, 0xffffffff, 0xffffffff, + 0xc0016900, 0x314, 0x0, 0xc0016900, 0x2a6, 0, 0xc0016900, 0x210, 0, + 0xc0002f00, 0x1, 0xc0016900, 0x1, 0x1, + 0xc0016900, 0x18, 0x2, 0xc0016900, 0x206, 0x300, 0xc0017900, 0x20000243, 0x0, + 0xc0017900, 0x248, 0xffffffff, 0xc0017900, 0x249, 0x0, 0xc0017900, 0x24a, 0x0, + 0xc0017900, 0x24b, 0x0 +}; + +static const uint32_t cached_cmd_gfx9[] = { + 0xc0016900, 0x0, 0x0, 0xc0026900, 0x3, 0x2a, 0x0, + 0xc0046900, 0xa, 0x0, 0x0, 0x0, 0x200020, + 0xc0016900, 0x83, 0xffff, 0xc0026900, 0x8e, 0xf, 0xf, + 0xc0056900, 0x105, 0x0, 0x0, 0x0, 0x0, 0x12, + 0xc0026900, 0x10b, 0x0, 0x0, 0xc0016900, 0x1e0, 0x0, + 0xc0036900, 0x200, 0x0, 0x10000, 0xcc0011, + 0xc0026900, 0x292, 0x20, 0x60201b8, + 0xc0026900, 0x2b0, 0x0, 0x0, 0xc0016900, 0x2f8, 0x0 +}; + +static const uint32_t sh_reg_base_gfx9 = 0x2C00; +static const uint32_t context_reg_base_gfx9 = 0xA000; + +#endif diff --git a/tests/amdgpu/shader_code_hang.h b/tests/amdgpu/shader_code_hang.h new file mode 100644 index 0000000..070bd71 --- /dev/null +++ b/tests/amdgpu/shader_code_hang.h @@ -0,0 +1,104 @@ +/* + * Copyright 2022 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 _shader_code_hang_h_ +#define _shader_code_hang_h_ + +static const unsigned int memcpy_shader_hang[] = { + 0xFFFFFFFF, 0xBEFE0A7E, 0xBEFC0304, 0xC0C20100, + 0xC0800300, 0xC8080000, 0xC80C0100, 0xC8090001, + 0xC80D0101, 0xBF8C007F, 0xF0800F00, 0x00010002, + 0xBEFE040C, 0xBF8C0F70, 0xBF800000, 0xBF800000, + 0xF800180F, 0x03020100, 0xBF810000 +}; + +struct shader_test_shader_bin { + const uint32_t *shader; + uint32_t header_length; + uint32_t body_length; + uint32_t foot_length; +}; + +static const unsigned int memcpy_cs_hang_slow_ai_codes[] = { + 0xd1fd0000, 0x04010c08, 0xe00c2000, 0x80000100, + 0xbf8c0f70, 0xe01c2000, 0x80010100, 0xbf810000 +}; + +static struct shader_test_shader_bin memcpy_cs_hang_slow_ai = { + memcpy_cs_hang_slow_ai_codes, 4, 3, 1 +}; + +static const unsigned int memcpy_cs_hang_slow_rv_codes[] = { + 0x8e00860c, 0x32000000, 0xe00c2000, 0x80010100, + 0xbf8c0f70, 0xe01c2000, 0x80020100, 0xbf810000 +}; + +static struct shader_test_shader_bin memcpy_cs_hang_slow_rv = { + memcpy_cs_hang_slow_rv_codes, 4, 3, 1 +}; + +static const unsigned int memcpy_cs_hang_slow_nv_codes[] = { + 0xd7460000, 0x04010c08, 0xe00c2000, 0x80000100, + 0xbf8c0f70, 0xe01ca000, 0x80010100, 0xbf810000 +}; + +static struct shader_test_shader_bin memcpy_cs_hang_slow_nv = { + memcpy_cs_hang_slow_nv_codes, 4, 3, 1 +}; + + +static const unsigned int memcpy_ps_hang_slow_ai_codes[] = { + 0xbefc000c, 0xbe8e017e, 0xbefe077e, 0xd4080000, + 0xd4090001, 0xd40c0100, 0xd40d0101, 0xf0800f00, + 0x00400002, 0xbefe010e, 0xbf8c0f70, 0xbf800000, + 0xbf800000, 0xbf800000, 0xbf800000, 0xc400180f, + 0x03020100, 0xbf810000 +}; + +static struct shader_test_shader_bin memcpy_ps_hang_slow_ai = { + memcpy_ps_hang_slow_ai_codes, 7, 2, 9 +}; + +static const unsigned int memcpy_ps_hang_slow_navi10_codes[] = { + 0xBEFC030C,0xBE8E047E,0xBEFE0A7E,0xC8080000, + 0xC80C0100,0xC8090001,0xC80D0101,0xF0800F0A, + 0x00400402,0x00000003,0xBEFE040E,0xBF8C0F70, + 0xBF800000,0xBF800000,0xBF800000,0xBF800000, + 0xF800180F,0x07060504,0xBF810000 +}; + +static struct shader_test_shader_bin memcpy_ps_hang_slow_navi10 = { + memcpy_ps_hang_slow_navi10_codes, 7, 3, 9 +}; + +static const unsigned int memcpy_ps_hang_slow_navi21_codes[] = { + 0xBEFC030C, 0xBE8E047E, 0xBEFE0A7E, 0xC8080000, 0xC8000100, 0xC8090001, 0xC8010101, 0x87FE0E7E, // header + 0xF0800F0A, 0x00400002, 0x00000000, // body - image_sample instruction + 0xBFA3FFE3, 0xBEFE040E, 0xBF8C3F70, 0xBF800000, 0xBF800000, 0xBF800000, 0xBF800000, 0xF800180F, 0x03020100, 0xBF810000 // footer +}; + +static struct shader_test_shader_bin memcpy_ps_hang_slow_navi21 = { + memcpy_ps_hang_slow_navi21_codes, 8, 3, 10 +}; + +#endif diff --git a/tests/amdgpu/shader_test_util.c b/tests/amdgpu/shader_test_util.c new file mode 100644 index 0000000..60148fb --- /dev/null +++ b/tests/amdgpu/shader_test_util.c @@ -0,0 +1,2156 @@ +#include +#include +#include +#include +#include +#include + +#include "CUnit/Basic.h" +#include "amdgpu_test.h" +#include "shader_code.h" + +#define PACKET3_DISPATCH_DIRECT 0x15 +#define PACKET3_CONTEXT_CONTROL 0x28 +#define PACKET3_DRAW_INDEX_AUTO 0x2D +#define PACKET3_SET_CONTEXT_REG 0x69 +#define PACKET3_SET_SH_REG 0x76 +#define PACKET3_SET_SH_REG_OFFSET 0x77 +#define PACKET3_SET_UCONFIG_REG 0x79 +#define PACKET3_SET_SH_REG_INDEX 0x9B + +#define PACKET_TYPE3 3 +#define PACKET3(op, n) ((PACKET_TYPE3 << 30) | \ + (((op) & 0xFF) << 8) | \ + ((n) & 0x3FFF) << 16) +#define PACKET3_COMPUTE(op, n) PACKET3(op, n) | (1 << 1) + + +struct shader_test_bo { + amdgpu_bo_handle bo; + unsigned size; + unsigned heap; + void *ptr; + uint64_t mc_address; + amdgpu_va_handle va; +}; + +struct shader_test_draw { + struct shader_test_bo ps_bo; + enum ps_type ps_type; + struct shader_test_bo vs_bo; + enum vs_type vs_type; +}; +struct shader_test_dispatch { + struct shader_test_bo cs_bo; + enum cs_type cs_type; +}; + +struct shader_test_info { + amdgpu_device_handle device_handle; + enum amdgpu_test_gfx_version version; + unsigned ip; + unsigned ring; + int hang; + int hang_slow; +}; + +struct shader_test_priv { + const struct shader_test_info *info; + unsigned cmd_curr; + + union { + struct shader_test_draw shader_draw; + struct shader_test_dispatch shader_dispatch; + }; + struct shader_test_bo vtx_attributes_mem; + struct shader_test_bo cmd; + struct shader_test_bo src; + struct shader_test_bo dst; +}; + +static int shader_test_bo_alloc(amdgpu_device_handle device_handle, + struct shader_test_bo *shader_test_bo) +{ + return amdgpu_bo_alloc_and_map(device_handle, shader_test_bo->size, 4096, + shader_test_bo->heap, 0, + &(shader_test_bo->bo), (void **)&(shader_test_bo->ptr), + &(shader_test_bo->mc_address), &(shader_test_bo->va)); +} + +static int shader_test_bo_free(struct shader_test_bo *shader_test_bo) +{ + return amdgpu_bo_unmap_and_free(shader_test_bo->bo, shader_test_bo->va, + shader_test_bo->mc_address, + shader_test_bo->size); +} + +void shader_test_for_each(amdgpu_device_handle device_handle, unsigned ip, + void (*fn)(struct shader_test_info *test_info)) +{ + int r; + uint32_t ring_id; + struct shader_test_info test_info = {0}; + struct drm_amdgpu_info_hw_ip info = {0}; + + r = amdgpu_query_hw_ip_info(device_handle, ip, 0, &info); + CU_ASSERT_EQUAL(r, 0); + if (!info.available_rings) { + printf("SKIP ... as there's no %s ring\n", + (ip == AMDGPU_HW_IP_GFX) ? "graphics": "compute"); + return; + } + + switch (info.hw_ip_version_major) { + case 9: + test_info.version = AMDGPU_TEST_GFX_V9; + break; + case 10: + test_info.version = AMDGPU_TEST_GFX_V10; + break; + case 11: + test_info.version = AMDGPU_TEST_GFX_V11; + break; + default: + printf("SKIP ... unsupported gfx version %d\n", info.hw_ip_version_major); + return; + } + + test_info.device_handle = device_handle; + test_info.ip = ip; + + printf("\n"); + for (ring_id = 0; (1 << ring_id) & info.available_rings; ring_id++) { + printf("%s ring %d\n", (ip == AMDGPU_HW_IP_GFX) ? "graphics": "compute", + ring_id); + test_info.ring = ring_id; + fn(&test_info); + } +} + +static void write_context_control(struct shader_test_priv *test_priv) +{ + int i = test_priv->cmd_curr; + uint32_t *ptr = test_priv->cmd.ptr; + + if (test_priv->info->ip == AMDGPU_HW_IP_GFX) { + ptr[i++] = PACKET3(PACKET3_CONTEXT_CONTROL, 1); + ptr[i++] = 0x80000000; + ptr[i++] = 0x80000000; + } + + test_priv->cmd_curr = i; +} + +static void shader_test_load_shader_hang_slow(struct shader_test_bo *shader_bo, + struct shader_test_shader_bin *shader_bin) +{ + int i, j, loop; + + loop = (shader_bo->size / sizeof(uint32_t) - shader_bin->header_length + - shader_bin->foot_length) / shader_bin->body_length; + + memcpy(shader_bo->ptr, shader_bin->shader, shader_bin->header_length * sizeof(uint32_t)); + + j = shader_bin->header_length; + for (i = 0; i < loop; i++) { + memcpy(shader_bo->ptr + j, + shader_bin->shader + shader_bin->header_length, + shader_bin->body_length * sizeof(uint32_t)); + j += shader_bin->body_length; + } + + memcpy(shader_bo->ptr + j, + shader_bin->shader + shader_bin->header_length + shader_bin->body_length, + shader_bin->foot_length * sizeof(uint32_t)); +} + +static void amdgpu_dispatch_load_cs_shader_hang_slow(struct shader_test_priv *test_priv) +{ + struct amdgpu_gpu_info gpu_info = {0}; + struct shader_test_shader_bin *cs_shader_bin; + int r; + + r = amdgpu_query_gpu_info(test_priv->info->device_handle, &gpu_info); + CU_ASSERT_EQUAL(r, 0); + + switch (gpu_info.family_id) { + case AMDGPU_FAMILY_AI: + cs_shader_bin = &memcpy_cs_hang_slow_ai; + break; + case AMDGPU_FAMILY_RV: + cs_shader_bin = &memcpy_cs_hang_slow_rv; + break; + default: + cs_shader_bin = &memcpy_cs_hang_slow_nv; + break; + } + + shader_test_load_shader_hang_slow(&test_priv->shader_dispatch.cs_bo, cs_shader_bin); +} + +static void amdgpu_dispatch_load_cs_shader(struct shader_test_priv *test_priv) +{ + if (test_priv->info->hang) { + if (test_priv->info->hang_slow) + amdgpu_dispatch_load_cs_shader_hang_slow(test_priv); + else + memcpy(test_priv->shader_dispatch.cs_bo.ptr, memcpy_shader_hang, + sizeof(memcpy_shader_hang)); + } else { + memcpy(test_priv->shader_dispatch.cs_bo.ptr, + shader_test_cs[test_priv->info->version][test_priv->shader_dispatch.cs_type].shader, + shader_test_cs[test_priv->info->version][test_priv->shader_dispatch.cs_type].shader_size); + } +} + +static void amdgpu_dispatch_init_gfx9(struct shader_test_priv *test_priv) +{ + int i; + uint32_t *ptr = test_priv->cmd.ptr; + + /* Write context control and load shadowing register if necessary */ + write_context_control(test_priv); + + i = test_priv->cmd_curr; + + /* Issue commands to set default compute state. */ + /* clear mmCOMPUTE_START_Z - mmCOMPUTE_START_X */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 3); + ptr[i++] = 0x204; + i += 3; + + /* clear mmCOMPUTE_TMPRING_SIZE */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 1); + ptr[i++] = 0x218; + ptr[i++] = 0; + + test_priv->cmd_curr = i; +} + +static void amdgpu_dispatch_init_gfx10(struct shader_test_priv *test_priv) +{ + int i; + uint32_t *ptr = test_priv->cmd.ptr; + + amdgpu_dispatch_init_gfx9(test_priv); + + i = test_priv->cmd_curr; + + /* mmCOMPUTE_SHADER_CHKSUM */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 1); + ptr[i++] = 0x22a; + ptr[i++] = 0; + /* mmCOMPUTE_REQ_CTRL */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 6); + ptr[i++] = 0x222; + i += 6; + /* mmCP_COHER_START_DELAY */ + ptr[i++] = PACKET3(PACKET3_SET_UCONFIG_REG, 1); + ptr[i++] = 0x7b; + ptr[i++] = 0x20; + + test_priv->cmd_curr = i; +} + +static void amdgpu_dispatch_init_gfx11(struct shader_test_priv *test_priv) +{ + int i; + uint32_t *ptr = test_priv->cmd.ptr; + + /* Write context control and load shadowing register if necessary */ + write_context_control(test_priv); + + i = test_priv->cmd_curr; + + /* Issue commands to set default compute state. */ + /* clear mmCOMPUTE_START_Z - mmCOMPUTE_START_X */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 3); + ptr[i++] = 0x204; + i += 3; + + /* clear mmCOMPUTE_TMPRING_SIZE */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 1); + ptr[i++] = 0x218; + ptr[i++] = 0; + + /* mmCOMPUTE_REQ_CTRL */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 1); + ptr[i++] = 0x222; + ptr[i++] = 0; + + /* mmCOMPUTE_USER_ACCUM_0 .. 3*/ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 4); + ptr[i++] = 0x224; + i += 4; + + /* mmCOMPUTE_SHADER_CHKSUM */ + ptr[i++] = PACKET3(PACKET3_SET_UCONFIG_REG, 1); + ptr[i++] = 0x22a; + ptr[i++] = 0; + + test_priv->cmd_curr = i; +} + +static void amdgpu_dispatch_init(struct shader_test_priv *test_priv) +{ + switch (test_priv->info->version) { + case AMDGPU_TEST_GFX_V9: + amdgpu_dispatch_init_gfx9(test_priv); + break; + case AMDGPU_TEST_GFX_V10: + amdgpu_dispatch_init_gfx10(test_priv); + break; + case AMDGPU_TEST_GFX_V11: + amdgpu_dispatch_init_gfx11(test_priv); + break; + } +} + +static void amdgpu_dispatch_write_cumask(struct shader_test_priv *test_priv) +{ + int i = test_priv->cmd_curr; + uint32_t *ptr = test_priv->cmd.ptr; + + /* Issue commands to set cu mask used in current dispatch */ + switch (test_priv->info->version) { + case AMDGPU_TEST_GFX_V9: + /* set mmCOMPUTE_STATIC_THREAD_MGMT_SE1 - mmCOMPUTE_STATIC_THREAD_MGMT_SE0 */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 2); + ptr[i++] = 0x216; + ptr[i++] = 0xffffffff; + ptr[i++] = 0xffffffff; + /* set mmCOMPUTE_STATIC_THREAD_MGMT_SE3 - mmCOMPUTE_STATIC_THREAD_MGMT_SE2 */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 2); + ptr[i++] = 0x219; + ptr[i++] = 0xffffffff; + ptr[i++] = 0xffffffff; + break; + case AMDGPU_TEST_GFX_V10: + case AMDGPU_TEST_GFX_V11: + /* set mmCOMPUTE_STATIC_THREAD_MGMT_SE1 - mmCOMPUTE_STATIC_THREAD_MGMT_SE0 */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG_INDEX, 2); + ptr[i++] = 0x30000216; + ptr[i++] = 0xffffffff; + ptr[i++] = 0xffffffff; + /* set mmCOMPUTE_STATIC_THREAD_MGMT_SE3 - mmCOMPUTE_STATIC_THREAD_MGMT_SE2 */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG_INDEX, 2); + ptr[i++] = 0x30000219; + ptr[i++] = 0xffffffff; + ptr[i++] = 0xffffffff; + break; + } + + test_priv->cmd_curr = i; +} + +static void amdgpu_dispatch_write2hw_gfx9(struct shader_test_priv *test_priv) +{ + const struct shader_test_cs_shader *cs_shader = &shader_test_cs[test_priv->info->version][test_priv->shader_dispatch.cs_type]; + int j, i = test_priv->cmd_curr; + uint32_t *ptr = test_priv->cmd.ptr; + uint64_t shader_addr = test_priv->shader_dispatch.cs_bo.mc_address; + + /* Writes shader state to HW */ + /* set mmCOMPUTE_PGM_HI - mmCOMPUTE_PGM_LO */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 2); + ptr[i++] = 0x20c; + ptr[i++] = (shader_addr >> 8); + ptr[i++] = (shader_addr >> 40); + /* write sh regs*/ + for (j = 0; j < cs_shader->num_sh_reg; j++) { + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 1); + /* - Gfx9ShRegBase */ + ptr[i++] = cs_shader->sh_reg[j].reg_offset - shader_test_gfx_info[test_priv->info->version].sh_reg_base; + ptr[i++] = cs_shader->sh_reg[j].reg_value; + } + + /* Write constant data */ + if (CS_BUFFERCLEAR == test_priv->shader_dispatch.cs_type) { + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 4); + ptr[i++] = 0x240; + ptr[i++] = test_priv->dst.mc_address; + ptr[i++] = (test_priv->dst.mc_address >> 32) | 0x100000; + ptr[i++] = test_priv->dst.size / 16; + ptr[i++] = 0x74fac; + + /* Sets a range of pixel shader constants */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 4); + ptr[i++] = 0x244; + ptr[i++] = 0x22222222; + ptr[i++] = 0x22222222; + ptr[i++] = 0x22222222; + ptr[i++] = 0x22222222; + } else { + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 4); + ptr[i++] = 0x240; + ptr[i++] = test_priv->src.mc_address; + ptr[i++] = (test_priv->src.mc_address >> 32) | 0x100000; + ptr[i++] = test_priv->src.size / 16; + ptr[i++] = 0x74fac; + + /* Writes the UAV constant data to the SGPRs. */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 4); + ptr[i++] = 0x244; + ptr[i++] = test_priv->dst.mc_address; + ptr[i++] = (test_priv->dst.mc_address >> 32) | 0x100000; + ptr[i++] = test_priv->dst.size / 16; + ptr[i++] = 0x74fac; + } + + test_priv->cmd_curr = i; +} + +static void amdgpu_dispatch_write2hw_gfx10(struct shader_test_priv *test_priv) +{ + int i = test_priv->cmd_curr; + uint32_t *ptr = test_priv->cmd.ptr; + const struct shader_test_cs_shader *cs_shader = &shader_test_cs[test_priv->info->version][test_priv->shader_dispatch.cs_type]; + int j; + uint64_t shader_addr = test_priv->shader_dispatch.cs_bo.mc_address; + + /* Writes shader state to HW */ + /* set mmCOMPUTE_PGM_HI - mmCOMPUTE_PGM_LO */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 2); + ptr[i++] = 0x20c; + ptr[i++] = (shader_addr >> 8); + ptr[i++] = (shader_addr >> 40); + /* write sh regs*/ + for (j = 0; j < cs_shader->num_sh_reg; j++) { + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 1); + /* - Gfx9ShRegBase */ + ptr[i++] = cs_shader->sh_reg[j].reg_offset - shader_test_gfx_info[test_priv->info->version].sh_reg_base; + ptr[i++] = cs_shader->sh_reg[j].reg_value; + } + + /* mmCOMPUTE_PGM_RSRC3 */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 1); + ptr[i++] = 0x228; + ptr[i++] = 0; + + if (CS_BUFFERCLEAR == test_priv->shader_dispatch.cs_type) { + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 4); + ptr[i++] = 0x240; + ptr[i++] = test_priv->dst.mc_address; + ptr[i++] = (test_priv->dst.mc_address >> 32) | 0x100000; + ptr[i++] = test_priv->dst.size / 16; + ptr[i++] = 0x1104bfac; + + /* Sets a range of pixel shader constants */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 4); + ptr[i++] = 0x244; + ptr[i++] = 0x22222222; + ptr[i++] = 0x22222222; + ptr[i++] = 0x22222222; + ptr[i++] = 0x22222222; + } else { + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 4); + ptr[i++] = 0x240; + ptr[i++] = test_priv->src.mc_address; + ptr[i++] = (test_priv->src.mc_address >> 32) | 0x100000; + ptr[i++] = test_priv->src.size / 16; + ptr[i++] = 0x1104bfac; + + /* Writes the UAV constant data to the SGPRs. */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 4); + ptr[i++] = 0x244; + ptr[i++] = test_priv->dst.mc_address; + ptr[i++] = (test_priv->dst.mc_address>> 32) | 0x100000; + ptr[i++] = test_priv->dst.size / 16; + ptr[i++] = 0x1104bfac; + } + + test_priv->cmd_curr = i; +} + +static void amdgpu_dispatch_write2hw_gfx11(struct shader_test_priv *test_priv) +{ + enum amdgpu_test_gfx_version version = test_priv->info->version; + const struct shader_test_cs_shader *cs_shader = &shader_test_cs[version][test_priv->shader_dispatch.cs_type]; + int j, i = test_priv->cmd_curr; + uint32_t *ptr = test_priv->cmd.ptr; + uint64_t shader_addr = test_priv->shader_dispatch.cs_bo.mc_address; + + /* Writes shader state to HW */ + /* set mmCOMPUTE_PGM_HI - mmCOMPUTE_PGM_LO */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 2); + ptr[i++] = 0x20c; + ptr[i++] = (shader_addr >> 8); + ptr[i++] = (shader_addr >> 40); + + /* write sh regs*/ + for (j = 0; j < cs_shader->num_sh_reg; j++) { + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 1); + /* - Gfx9ShRegBase */ + ptr[i++] = cs_shader->sh_reg[j].reg_offset - shader_test_gfx_info[version].sh_reg_base; + ptr[i++] = cs_shader->sh_reg[j].reg_value; + if (cs_shader->sh_reg[j].reg_offset == 0x2E12) + ptr[i-1] &= ~(1<<29); + } + + /* mmCOMPUTE_PGM_RSRC3 */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 1); + ptr[i++] = 0x228; + ptr[i++] = 0x3f0; + + /* Write constant data */ + /* Writes the texture resource constants data to the SGPRs */ + if (CS_BUFFERCLEAR == test_priv->shader_dispatch.cs_type) { + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 4); + ptr[i++] = 0x240; + ptr[i++] = test_priv->dst.mc_address; + ptr[i++] = (test_priv->dst.mc_address >> 32) | 0x100000; + ptr[i++] = test_priv->dst.size / 16; + ptr[i++] = 0x1003dfac; + + /* Sets a range of pixel shader constants */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 4); + ptr[i++] = 0x244; + ptr[i++] = 0x22222222; + ptr[i++] = 0x22222222; + ptr[i++] = 0x22222222; + ptr[i++] = 0x22222222; + } else { + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 4); + ptr[i++] = 0x240; + ptr[i++] = test_priv->src.mc_address; + ptr[i++] = (test_priv->src.mc_address >> 32) | 0x100000; + ptr[i++] = test_priv->src.size / 16; + ptr[i++] = 0x1003dfac; + + /* Writes the UAV constant data to the SGPRs. */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 4); + ptr[i++] = 0x244; + ptr[i++] = test_priv->dst.mc_address; + ptr[i++] = (test_priv->dst.mc_address>> 32) | 0x100000; + ptr[i++] = test_priv->dst.size / 16; + ptr[i++] = 0x1003dfac; + } + + test_priv->cmd_curr = i; +} + +static void amdgpu_dispatch_write2hw(struct shader_test_priv *test_priv) +{ + switch (test_priv->info->version) { + case AMDGPU_TEST_GFX_V9: + amdgpu_dispatch_write2hw_gfx9(test_priv); + break; + case AMDGPU_TEST_GFX_V10: + amdgpu_dispatch_write2hw_gfx10(test_priv); + break; + case AMDGPU_TEST_GFX_V11: + amdgpu_dispatch_write2hw_gfx11(test_priv); + break; + } +} + +static void amdgpu_dispatch_write_dispatch_cmd(struct shader_test_priv *test_priv) +{ + int i = test_priv->cmd_curr; + uint32_t *ptr = test_priv->cmd.ptr; + + /* clear mmCOMPUTE_RESOURCE_LIMITS */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_SET_SH_REG, 1); + ptr[i++] = 0x215; + ptr[i++] = 0; + + /* dispatch direct command */ + ptr[i++] = PACKET3_COMPUTE(PACKET3_DISPATCH_DIRECT, 3); + ptr[i++] = (test_priv->dst.size / 16 + 0x40 - 1 ) / 0x40;//0x10; + ptr[i++] = 1; + ptr[i++] = 1; + ptr[i++] = 1; + + test_priv->cmd_curr = i; +} +static void amdgpu_test_dispatch_memset(struct shader_test_info *test_info) +{ + amdgpu_context_handle context_handle; + amdgpu_bo_handle resources[3]; + struct shader_test_priv test_priv; + struct shader_test_bo *cmd = &(test_priv.cmd); + struct shader_test_bo *dst = &(test_priv.dst); + struct shader_test_bo *shader = &(test_priv.shader_dispatch.cs_bo); + uint32_t *ptr_cmd; + uint8_t *ptr_dst; + int i, r; + struct amdgpu_cs_request ibs_request = {0}; + struct amdgpu_cs_ib_info ib_info= {0}; + amdgpu_bo_list_handle bo_list; + struct amdgpu_cs_fence fence_status = {0}; + uint32_t expired; + uint8_t cptr[16]; + + memset(&test_priv, 0, sizeof(test_priv)); + test_priv.info = test_info; + test_priv.shader_dispatch.cs_type = CS_BUFFERCLEAR; + r = amdgpu_cs_ctx_create(test_info->device_handle, &context_handle); + CU_ASSERT_EQUAL(r, 0); + + cmd->size = 4096; + cmd->heap = AMDGPU_GEM_DOMAIN_GTT; + r = shader_test_bo_alloc(test_info->device_handle, cmd); + CU_ASSERT_EQUAL(r, 0); + ptr_cmd = cmd->ptr; + memset(ptr_cmd, 0, cmd->size); + + shader->size = 4096; + shader->heap = AMDGPU_GEM_DOMAIN_VRAM; + r = shader_test_bo_alloc(test_info->device_handle, shader); + CU_ASSERT_EQUAL(r, 0); + memset(shader->ptr, 0, shader->size); + amdgpu_dispatch_load_cs_shader(&test_priv); + + dst->size = 0x4000; + dst->heap = AMDGPU_GEM_DOMAIN_VRAM; + r = shader_test_bo_alloc(test_info->device_handle, dst); + CU_ASSERT_EQUAL(r, 0); + + amdgpu_dispatch_init(&test_priv); + + /* Issue commands to set cu mask used in current dispatch */ + amdgpu_dispatch_write_cumask(&test_priv); + + /* Writes shader state to HW */ + amdgpu_dispatch_write2hw(&test_priv); + + amdgpu_dispatch_write_dispatch_cmd(&test_priv); + + i = test_priv.cmd_curr; + while (i & 7) + ptr_cmd[i++] = 0xffff1000; /* type3 nop packet */ + test_priv.cmd_curr = i; + + resources[0] = dst->bo; + resources[1] = shader->bo; + resources[2] = cmd->bo; + r = amdgpu_bo_list_create(test_info->device_handle, 3, resources, NULL, &bo_list); + CU_ASSERT_EQUAL(r, 0); + + ib_info.ib_mc_address = cmd->mc_address; + ib_info.size = test_priv.cmd_curr; + ibs_request.ip_type = test_info->ip; + ibs_request.ring = test_info->ring; + ibs_request.resources = bo_list; + ibs_request.number_of_ibs = 1; + ibs_request.ibs = &ib_info; + ibs_request.fence_info.handle = NULL; + + /* submit CS */ + r = amdgpu_cs_submit(context_handle, 0, &ibs_request, 1); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_list_destroy(bo_list); + CU_ASSERT_EQUAL(r, 0); + + fence_status.ip_type = test_info->ip; + fence_status.ip_instance = 0; + fence_status.ring = test_info->ring; + fence_status.context = context_handle; + fence_status.fence = ibs_request.seq_no; + + /* wait for IB accomplished */ + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE, + 0, &expired); + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(expired, true); + + /* verify if memset test result meets with expected */ + i = 0; + ptr_dst = (uint8_t *)(dst->ptr); + memset(cptr, 0x22, 16); + CU_ASSERT_EQUAL(memcmp(ptr_dst + i, cptr, 16), 0); + i = dst->size - 16; + CU_ASSERT_EQUAL(memcmp(ptr_dst + i, cptr, 16), 0); + i = dst->size / 2; + CU_ASSERT_EQUAL(memcmp(ptr_dst + i, cptr, 16), 0); + + r = shader_test_bo_free(dst); + CU_ASSERT_EQUAL(r, 0); + + r = shader_test_bo_free(shader); + CU_ASSERT_EQUAL(r, 0); + + r = shader_test_bo_free(cmd); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); +} + +static +void amdgpu_test_dispatch_memcpy(struct shader_test_info *test_info) +{ + struct shader_test_priv test_priv; + amdgpu_context_handle context_handle; + amdgpu_bo_handle resources[4]; + struct shader_test_bo *cmd = &(test_priv.cmd); + struct shader_test_bo *src = &(test_priv.src); + struct shader_test_bo *dst = &(test_priv.dst); + struct shader_test_bo *shader = &(test_priv.shader_dispatch.cs_bo); + uint32_t *ptr_cmd; + uint8_t *ptr_src; + uint8_t *ptr_dst; + int i, r; + struct amdgpu_cs_request ibs_request = {0}; + struct amdgpu_cs_ib_info ib_info= {0}; + uint32_t expired, hang_state, hangs; + amdgpu_bo_list_handle bo_list; + struct amdgpu_cs_fence fence_status = {0}; + + memset(&test_priv, 0, sizeof(test_priv)); + test_priv.info = test_info; + test_priv.cmd.size = 4096; + test_priv.cmd.heap = AMDGPU_GEM_DOMAIN_GTT; + + test_priv.shader_dispatch.cs_bo.heap = AMDGPU_GEM_DOMAIN_VRAM; + test_priv.shader_dispatch.cs_type = CS_BUFFERCOPY; + test_priv.src.heap = AMDGPU_GEM_DOMAIN_VRAM; + test_priv.dst.heap = AMDGPU_GEM_DOMAIN_VRAM; + if (test_info->hang_slow) { + test_priv.shader_dispatch.cs_bo.size = 0x4000000; + test_priv.src.size = 0x4000000; + test_priv.dst.size = 0x4000000; + } else { + test_priv.shader_dispatch.cs_bo.size = 4096; + test_priv.src.size = 0x4000; + test_priv.dst.size = 0x4000; + } + + r = amdgpu_cs_ctx_create(test_info->device_handle, &context_handle); + CU_ASSERT_EQUAL(r, 0); + + r = shader_test_bo_alloc(test_info->device_handle, cmd); + CU_ASSERT_EQUAL(r, 0); + ptr_cmd = cmd->ptr; + memset(ptr_cmd, 0, cmd->size); + + r = shader_test_bo_alloc(test_info->device_handle, shader); + CU_ASSERT_EQUAL(r, 0); + memset(shader->ptr, 0, shader->size); + amdgpu_dispatch_load_cs_shader(&test_priv); + + r = shader_test_bo_alloc(test_info->device_handle, src); + CU_ASSERT_EQUAL(r, 0); + ptr_src = (uint8_t *)(src->ptr); + memset(ptr_src, 0x55, src->size); + + r = shader_test_bo_alloc(test_info->device_handle, dst); + CU_ASSERT_EQUAL(r, 0); + + amdgpu_dispatch_init(&test_priv); + + /* Issue commands to set cu mask used in current dispatch */ + amdgpu_dispatch_write_cumask(&test_priv); + + /* Writes shader state to HW */ + amdgpu_dispatch_write2hw(&test_priv); + + amdgpu_dispatch_write_dispatch_cmd(&test_priv); + + i = test_priv.cmd_curr; + while (i & 7) + ptr_cmd[i++] = 0xffff1000; /* type3 nop packet */ + test_priv.cmd_curr = i; + + resources[0] = shader->bo; + resources[1] = src->bo; + resources[2] = dst->bo; + resources[3] = cmd->bo; + r = amdgpu_bo_list_create(test_info->device_handle, 4, resources, NULL, &bo_list); + CU_ASSERT_EQUAL(r, 0); + + ib_info.ib_mc_address = cmd->mc_address; + ib_info.size = test_priv.cmd_curr; + ibs_request.ip_type = test_info->ip; + ibs_request.ring = test_info->ring; + ibs_request.resources = bo_list; + ibs_request.number_of_ibs = 1; + ibs_request.ibs = &ib_info; + ibs_request.fence_info.handle = NULL; + r = amdgpu_cs_submit(context_handle, 0, &ibs_request, 1); + CU_ASSERT_EQUAL(r, 0); + + fence_status.ip_type = test_info->ip; + fence_status.ip_instance = 0; + fence_status.ring = test_info->ring; + fence_status.context = context_handle; + fence_status.fence = ibs_request.seq_no; + + /* wait for IB accomplished */ + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE, + 0, &expired); + + if (!test_info->hang) { + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(expired, true); + + /* verify if memcpy test result meets with expected */ + i = 0; + ptr_dst = (uint8_t *)dst->ptr; + CU_ASSERT_EQUAL(memcmp(ptr_dst + i, ptr_src + i, 16), 0); + i = dst->size - 16; + CU_ASSERT_EQUAL(memcmp(ptr_dst + i, ptr_src + i, 16), 0); + i = dst->size / 2; + CU_ASSERT_EQUAL(memcmp(ptr_dst + i, ptr_src + i, 16), 0); + } else { + r = amdgpu_cs_query_reset_state(context_handle, &hang_state, &hangs); + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(hang_state, AMDGPU_CTX_UNKNOWN_RESET); + } + + r = amdgpu_bo_list_destroy(bo_list); + CU_ASSERT_EQUAL(r, 0); + + r = shader_test_bo_free(src); + CU_ASSERT_EQUAL(r, 0); + r = shader_test_bo_free(dst); + CU_ASSERT_EQUAL(r, 0); + + r = shader_test_bo_free(shader); + CU_ASSERT_EQUAL(r, 0); + + r = shader_test_bo_free(cmd); + + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void shader_test_dispatch_cb(struct shader_test_info *test_info) +{ + amdgpu_test_dispatch_memset(test_info); + amdgpu_test_dispatch_memcpy(test_info); +} +static void shader_test_dispatch_hang_cb(struct shader_test_info *test_info) +{ + test_info->hang = 0; + amdgpu_test_dispatch_memcpy(test_info); + + test_info->hang = 1; + amdgpu_test_dispatch_memcpy(test_info); + + test_info->hang = 0; + amdgpu_test_dispatch_memcpy(test_info); +} + +static void shader_test_dispatch_hang_slow_cb(struct shader_test_info *test_info) +{ + test_info->hang = 0; + test_info->hang_slow = 0; + amdgpu_test_dispatch_memcpy(test_info); + + test_info->hang = 1; + test_info->hang_slow = 1; + amdgpu_test_dispatch_memcpy(test_info); + + test_info->hang = 0; + test_info->hang_slow = 0; + amdgpu_test_dispatch_memcpy(test_info); +} + +void amdgpu_test_dispatch_helper(amdgpu_device_handle device_handle, unsigned ip) +{ + shader_test_for_each(device_handle, ip, shader_test_dispatch_cb); +} + +void amdgpu_test_dispatch_hang_helper(amdgpu_device_handle device_handle, uint32_t ip) +{ + shader_test_for_each(device_handle, ip, shader_test_dispatch_hang_cb); +} + +void amdgpu_test_dispatch_hang_slow_helper(amdgpu_device_handle device_handle, uint32_t ip) +{ + shader_test_for_each(device_handle, ip, shader_test_dispatch_hang_slow_cb); +} + +static void amdgpu_draw_load_ps_shader_hang_slow(struct shader_test_priv *test_priv) +{ + struct amdgpu_gpu_info gpu_info = {0}; + struct shader_test_shader_bin *ps_shader_bin = &memcpy_ps_hang_slow_navi21; + int r; + + r = amdgpu_query_gpu_info(test_priv->info->device_handle, &gpu_info); + CU_ASSERT_EQUAL(r, 0); + + switch (gpu_info.family_id) { + case AMDGPU_FAMILY_AI: + case AMDGPU_FAMILY_RV: + ps_shader_bin = &memcpy_ps_hang_slow_ai; + break; + case AMDGPU_FAMILY_NV: + if (gpu_info.chip_external_rev < 40) + ps_shader_bin = &memcpy_ps_hang_slow_navi10; + break; + } + + shader_test_load_shader_hang_slow(&test_priv->shader_draw.ps_bo, ps_shader_bin); +} + +static uint32_t round_up_size(uint32_t size) +{ + return (size + 255) & ~255; +} +static void amdgpu_draw_load_ps_shader(struct shader_test_priv *test_priv) +{ + uint8_t *ptr_shader = test_priv->shader_draw.ps_bo.ptr; + const struct shader_test_ps_shader *shader; + uint32_t shader_offset, num_export_fmt; + uint32_t mem_offset, patch_code_offset; + int i; + + if (test_priv->info->hang) { + if (test_priv->info->hang_slow) + amdgpu_draw_load_ps_shader_hang_slow(test_priv); + else + memcpy(ptr_shader, memcpy_shader_hang, sizeof(memcpy_shader_hang)); + + return; + } + + shader = &shader_test_ps[test_priv->info->version][test_priv->shader_draw.ps_type]; + num_export_fmt = 10; + shader_offset = round_up_size(shader->shader_size); + /* write main shader program */ + for (i = 0 ; i < num_export_fmt; i++) { + mem_offset = i * shader_offset; + memcpy(ptr_shader + mem_offset, shader->shader, shader->shader_size); + } + + /* overwrite patch codes */ + for (i = 0 ; i < num_export_fmt; i++) { + mem_offset = i * shader_offset + shader->patchinfo_code_offset[0] * sizeof(uint32_t); + patch_code_offset = i * shader->patchinfo_code_size; + memcpy(ptr_shader + mem_offset, + shader->patchinfo_code + patch_code_offset, + shader->patchinfo_code_size * sizeof(uint32_t)); + } +} + +/* load RectPosTexFast_VS */ +static void amdgpu_draw_load_vs_shader(struct shader_test_priv *test_priv) +{ + uint8_t *ptr_shader = test_priv->shader_draw.vs_bo.ptr; + const struct shader_test_vs_shader *shader = &shader_test_vs[test_priv->info->version][test_priv->shader_draw.vs_type]; + + memcpy(ptr_shader, shader->shader, shader->shader_size); +} + +static void amdgpu_draw_init(struct shader_test_priv *test_priv) +{ + int i; + uint32_t *ptr = test_priv->cmd.ptr; + const struct shader_test_gfx_info *gfx_info = &shader_test_gfx_info[test_priv->info->version]; + + /* Write context control and load shadowing register if necessary */ + write_context_control(test_priv); + i = test_priv->cmd_curr; + + if (test_priv->info->version == AMDGPU_TEST_GFX_V11) { + ptr[i++] = PACKET3(PACKET3_SET_UCONFIG_REG, 1); + ptr[i++] = 0x446; + ptr[i++] = (test_priv->vtx_attributes_mem.mc_address >> 16); + // mmSPI_ATTRIBUTE_RING_SIZE + ptr[i++] = PACKET3(PACKET3_SET_UCONFIG_REG, 1); + ptr[i++] = 0x447; + ptr[i++] = 0x20001; + } + memcpy(ptr + i, gfx_info->preamble_cache, gfx_info->size_preamble_cache); + + test_priv->cmd_curr = i + gfx_info->size_preamble_cache/sizeof(uint32_t); +} + +static void amdgpu_draw_setup_and_write_drawblt_surf_info_gfx9(struct shader_test_priv *test_priv) +{ + int i = test_priv->cmd_curr; + uint32_t *ptr = test_priv->cmd.ptr; + + /* setup color buffer */ + /* offset reg + 0xA318 CB_COLOR0_BASE + 0xA319 CB_COLOR0_BASE_EXT + 0xA31A CB_COLOR0_ATTRIB2 + 0xA31B CB_COLOR0_VIEW + 0xA31C CB_COLOR0_INFO + 0xA31D CB_COLOR0_ATTRIB + 0xA31E CB_COLOR0_DCC_CONTROL + 0xA31F CB_COLOR0_CMASK + 0xA320 CB_COLOR0_CMASK_BASE_EXT + 0xA321 CB_COLOR0_FMASK + 0xA322 CB_COLOR0_FMASK_BASE_EXT + 0xA323 CB_COLOR0_CLEAR_WORD0 + 0xA324 CB_COLOR0_CLEAR_WORD1 + 0xA325 CB_COLOR0_DCC_BASE + 0xA326 CB_COLOR0_DCC_BASE_EXT */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 15); + ptr[i++] = 0x318; + ptr[i++] = test_priv->dst.mc_address >> 8; + ptr[i++] = test_priv->dst.mc_address >> 40; + ptr[i++] = test_priv->info->hang_slow ? 0x3ffc7ff : 0x7c01f; + ptr[i++] = 0; + ptr[i++] = 0x50438; + ptr[i++] = 0x10140000; + i += 9; + + /* mmCB_MRT0_EPITCH */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x1e8; + ptr[i++] = test_priv->info->hang_slow ? 0xfff : 0x1f; + + /* 0xA32B CB_COLOR1_BASE */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x32b; + ptr[i++] = 0; + + /* 0xA33A CB_COLOR1_BASE */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x33a; + ptr[i++] = 0; + + /* SPI_SHADER_COL_FORMAT */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x1c5; + ptr[i++] = 9; + + /* Setup depth buffer */ + /* mmDB_Z_INFO */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 2); + ptr[i++] = 0xe; + i += 2; + + test_priv->cmd_curr = i; +} +static void amdgpu_draw_setup_and_write_drawblt_surf_info_gfx10(struct shader_test_priv *test_priv) +{ + int i = test_priv->cmd_curr; + uint32_t *ptr = test_priv->cmd.ptr; + + /* setup color buffer */ + /* 0xA318 CB_COLOR0_BASE + 0xA319 CB_COLOR0_PITCH + 0xA31A CB_COLOR0_SLICE + 0xA31B CB_COLOR0_VIEW + 0xA31C CB_COLOR0_INFO + 0xA31D CB_COLOR0_ATTRIB + 0xA31E CB_COLOR0_DCC_CONTROL + 0xA31F CB_COLOR0_CMASK + 0xA320 CB_COLOR0_CMASK_SLICE + 0xA321 CB_COLOR0_FMASK + 0xA322 CB_COLOR0_FMASK_SLICE + 0xA323 CB_COLOR0_CLEAR_WORD0 + 0xA324 CB_COLOR0_CLEAR_WORD1 + 0xA325 CB_COLOR0_DCC_BASE */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 14); + ptr[i++] = 0x318; + ptr[i++] = test_priv->dst.mc_address >> 8; + i += 3; + ptr[i++] = 0x50438; + i += 9; + + /* 0xA390 CB_COLOR0_BASE_EXT */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x390; + ptr[i++] = test_priv->dst.mc_address >> 40; + + /* 0xA398 CB_COLOR0_CMASK_BASE_EXT */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x398; + ptr[i++] = 0; + + /* 0xA3A0 CB_COLOR0_FMASK_BASE_EXT */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x3a0; + ptr[i++] = 0; + + /* 0xA3A8 CB_COLOR0_DCC_BASE_EXT */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x3a8; + ptr[i++] = 0; + + /* 0xA3B0 CB_COLOR0_ATTRIB2 */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x3b0; + ptr[i++] = test_priv->info->hang_slow ? 0x3ffc7ff : 0x7c01f; + + /* 0xA3B8 CB_COLOR0_ATTRIB3 */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x3b8; + ptr[i++] = 0x9014000; + + /* 0xA32B CB_COLOR1_BASE */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x32b; + ptr[i++] = 0; + + /* 0xA33A CB_COLOR1_BASE */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x33a; + ptr[i++] = 0; + + /* SPI_SHADER_COL_FORMAT */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x1c5; + ptr[i++] = 9; + + /* Setup depth buffer */ + /* mmDB_Z_INFO */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 2); + ptr[i++] = 0x10; + i += 2; + + test_priv->cmd_curr = i; +} + +static void amdgpu_draw_setup_and_write_drawblt_surf_info_gfx11(struct shader_test_priv *test_priv) +{ + int i = test_priv->cmd_curr; + uint32_t *ptr = test_priv->cmd.ptr; + + /* mmCB_COLOR0_BASE */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x318; + ptr[i++] = test_priv->dst.mc_address >> 8; + /* mmCB_COLOR0_VIEW .. mmCB_COLOR0_DCC_CONTROL */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 4); + ptr[i++] = 0x31b; + i++; + ptr[i++] = 0x5040e; + i += 2; + /* mmCB_COLOR0_DCC_BASE */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x325; + ptr[i++] = 0; + /* mmCB_COLOR0_BASE_EXT */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x390; + ptr[i++] = (test_priv->dst.mc_address >> 40) & 0xFF; + /* mmCB_COLOR0_DCC_BASE_EXT */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x3a8; + ptr[i++] = 0; + /* mmCB_COLOR0_ATTRIB2 */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x3b0; + ptr[i++] = test_priv->info->hang_slow ? 0x1ffc7ff : 0x7c01f; + /* mmCB_COLOR0_ATTRIB3 */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x3b8; + ptr[i++] = test_priv->info->hang_slow ? 0x1028000 : 0x1018000; + /* mmCB_COLOR0_INFO */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x32b; + ptr[i++] = 0; + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x33a; + ptr[i++] = 0; + /* mmSPI_SHADER_COL_FORMAT */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x1c5; + ptr[i++] = 0x9; + /* mmDB_Z_INFO */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 2); + ptr[i++] = 0x10; + i += 2; + + test_priv->cmd_curr = i; +} + +static void amdgpu_draw_setup_and_write_drawblt_surf_info(struct shader_test_priv *test_priv) +{ + switch (test_priv->info->version) { + case AMDGPU_TEST_GFX_V9: + amdgpu_draw_setup_and_write_drawblt_surf_info_gfx9(test_priv); + break; + case AMDGPU_TEST_GFX_V10: + amdgpu_draw_setup_and_write_drawblt_surf_info_gfx10(test_priv); + break; + case AMDGPU_TEST_GFX_V11: + amdgpu_draw_setup_and_write_drawblt_surf_info_gfx11(test_priv); + break; + } +} + +static void amdgpu_draw_setup_and_write_drawblt_state_gfx9(struct shader_test_priv *test_priv) +{ + int i = test_priv->cmd_curr; + uint32_t *ptr = test_priv->cmd.ptr; + const struct shader_test_gfx_info *gfx_info = &shader_test_gfx_info[test_priv->info->version]; + + /* mmPA_SC_TILE_STEERING_OVERRIDE */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0xd7; + ptr[i++] = 0; + + ptr[i++] = 0xffff1000; + ptr[i++] = 0xc0021000; + + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0xd7; + ptr[i++] = 1; + + /* mmPA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0 */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 16); + ptr[i++] = 0x2fe; + i += 16; + + /* mmPA_SC_CENTROID_PRIORITY_0 */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 2); + ptr[i++] = 0x2f5; + i += 2; + + memcpy(ptr + i, gfx_info->cached_cmd, gfx_info->size_cached_cmd); + if (test_priv->info->hang_slow) + *(ptr + i + 12) = 0x8000800; + + test_priv->cmd_curr = i + gfx_info->size_cached_cmd/sizeof(uint32_t); +} + +static void amdgpu_draw_setup_and_write_drawblt_state_gfx10(struct shader_test_priv *test_priv) +{ + int i = test_priv->cmd_curr; + uint32_t *ptr = test_priv->cmd.ptr; + const struct shader_test_gfx_info *gfx_info = &shader_test_gfx_info[test_priv->info->version]; + + /* mmPA_SC_TILE_STEERING_OVERRIDE */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0xd7; + ptr[i++] = 0; + + ptr[i++] = 0xffff1000; + ptr[i++] = 0xc0021000; + + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0xd7; + ptr[i++] = 0; + + /* mmPA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0 */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 16); + ptr[i++] = 0x2fe; + i += 16; + + /* mmPA_SC_CENTROID_PRIORITY_0 */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 2); + ptr[i++] = 0x2f5; + i += 2; + + memcpy(ptr + i, gfx_info->cached_cmd, gfx_info->size_cached_cmd); + if (test_priv->info->hang_slow) + *(ptr + i + 12) = 0x8000800; + i += gfx_info->size_cached_cmd/sizeof(uint32_t); + + /* mmCB_RMI_GL2_CACHE_CONTROL */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x104; + ptr[i++] = 0x40aa0055; + /* mmDB_RMI_L2_CACHE_CONTROL */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x1f; + ptr[i++] = 0x2a0055; + + test_priv->cmd_curr = i; +} + +static void amdgpu_draw_setup_and_write_drawblt_state_gfx11(struct shader_test_priv *test_priv) +{ + int i = test_priv->cmd_curr; + uint32_t *ptr = test_priv->cmd.ptr; + const struct shader_test_gfx_info *gfx_info = &shader_test_gfx_info[test_priv->info->version]; + + /* mmPA_SC_TILE_STEERING_OVERRIDE */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0xd7; + ptr[i++] = 0; + + ptr[i++] = 0xffff1000; + ptr[i++] = 0xc0021000; + + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0xd7; + i++; + + /* mmPA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0 */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 16); + ptr[i++] = 0x2fe; + i += 16; + + /* mmPA_SC_CENTROID_PRIORITY_0 */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 2); + ptr[i++] = 0x2f5; + i += 2; + + memcpy(ptr + i, gfx_info->cached_cmd, gfx_info->size_cached_cmd); + if (test_priv->info->hang_slow) + *(ptr + i + 12) = 0x8000800; + + test_priv->cmd_curr = i + gfx_info->size_cached_cmd/sizeof(uint32_t); +} + +static void amdgpu_draw_setup_and_write_drawblt_state(struct shader_test_priv *test_priv) +{ + switch (test_priv->info->version) { + case AMDGPU_TEST_GFX_V9: + amdgpu_draw_setup_and_write_drawblt_state_gfx9(test_priv); + break; + case AMDGPU_TEST_GFX_V10: + amdgpu_draw_setup_and_write_drawblt_state_gfx10(test_priv); + break; + case AMDGPU_TEST_GFX_V11: + amdgpu_draw_setup_and_write_drawblt_state_gfx11(test_priv); + break; + } +} + +static void amdgpu_draw_vs_RectPosTexFast_write2hw_gfx9(struct shader_test_priv *test_priv) +{ + int i = test_priv->cmd_curr; + uint32_t *ptr = test_priv->cmd.ptr; + uint64_t shader_addr = test_priv->shader_draw.vs_bo.mc_address; + enum ps_type ps = test_priv->shader_draw.ps_type; + + /* mmPA_CL_VS_OUT_CNTL */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x207; + ptr[i++] = 0; + + /* mmSPI_SHADER_PGM_RSRC3_VS */ + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 1); + ptr[i++] = 0x46; + ptr[i++] = 0xffff; + + /* mmSPI_SHADER_PGM_LO_VS...mmSPI_SHADER_PGM_HI_VS */ + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 2); + ptr[i++] = 0x48; + ptr[i++] = shader_addr >> 8; + ptr[i++] = shader_addr >> 40; + + /* mmSPI_SHADER_PGM_RSRC1_VS */ + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 1); + ptr[i++] = 0x4a; + ptr[i++] = 0xc0081; + + /* mmSPI_SHADER_PGM_RSRC2_VS */ + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 1); + ptr[i++] = 0x4b; + ptr[i++] = 0x18; + + /* mmSPI_VS_OUT_CONFIG */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x1b1; + ptr[i++] = 2; + + /* mmSPI_SHADER_POS_FORMAT */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x1c3; + ptr[i++] = 4; + + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 4); + ptr[i++] = 0x4c; + i += 2; + ptr[i++] = test_priv->info->hang_slow ? 0x45000000 : 0x42000000; + ptr[i++] = test_priv->info->hang_slow ? 0x45000000 : 0x42000000; + + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 4); + ptr[i++] = 0x50; + i += 2; + if (ps == PS_CONST) { + i += 2; + } else if (ps == PS_TEX) { + ptr[i++] = 0x3f800000; + ptr[i++] = 0x3f800000; + } + + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 4); + ptr[i++] = 0x54; + i += 4; + + test_priv->cmd_curr = i; +} + +static void amdgpu_draw_vs_RectPosTexFast_write2hw_gfx10(struct shader_test_priv *test_priv) +{ + int i = test_priv->cmd_curr; + uint32_t *ptr = test_priv->cmd.ptr; + uint64_t shader_addr = test_priv->shader_draw.vs_bo.mc_address; + enum ps_type ps = test_priv->shader_draw.ps_type; + + /* mmPA_CL_VS_OUT_CNTL */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x207; + ptr[i++] = 0; + + /* mmSPI_SHADER_PGM_RSRC3_VS */ + ptr[i++] = PACKET3(PACKET3_SET_SH_REG_INDEX, 1); + ptr[i++] = 0x30000046; + ptr[i++] = 0xffff; + /* mmSPI_SHADER_PGM_RSRC4_VS */ + ptr[i++] = PACKET3(PACKET3_SET_SH_REG_INDEX, 1); + ptr[i++] = 0x30000041; + ptr[i++] = 0xffff; + + /* mmSPI_SHADER_PGM_LO_VS...mmSPI_SHADER_PGM_HI_VS */ + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 2); + ptr[i++] = 0x48; + ptr[i++] = shader_addr >> 8; + ptr[i++] = shader_addr >> 40; + + /* mmSPI_SHADER_PGM_RSRC1_VS */ + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 1); + ptr[i++] = 0x4a; + ptr[i++] = 0xc0041; + /* mmSPI_SHADER_PGM_RSRC2_VS */ + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 1); + ptr[i++] = 0x4b; + ptr[i++] = 0x18; + + /* mmSPI_VS_OUT_CONFIG */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x1b1; + ptr[i++] = 2; + + /* mmSPI_SHADER_POS_FORMAT */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x1c3; + ptr[i++] = 4; + + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 4); + ptr[i++] = 0x4c; + i += 2; + ptr[i++] = test_priv->info->hang_slow ? 0x45000000 : 0x42000000; + ptr[i++] = test_priv->info->hang_slow ? 0x45000000 : 0x42000000; + + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 4); + ptr[i++] = 0x50; + i += 2; + if (ps == PS_CONST) { + i += 2; + } else if (ps == PS_TEX) { + ptr[i++] = 0x3f800000; + ptr[i++] = 0x3f800000; + } + + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 4); + ptr[i++] = 0x54; + i += 4; + + test_priv->cmd_curr = i; +} + + +static void amdgpu_draw_vs_RectPosTexFast_write2hw_gfx11(struct shader_test_priv *test_priv) +{ + int i = test_priv->cmd_curr; + uint32_t *ptr = test_priv->cmd.ptr; + const struct shader_test_gfx_info *gfx_info = &shader_test_gfx_info[test_priv->info->version]; + uint64_t shader_addr = test_priv->shader_draw.vs_bo.mc_address; + const struct shader_test_vs_shader *shader = &shader_test_vs[test_priv->info->version][test_priv->shader_draw.vs_type]; + enum ps_type ps = test_priv->shader_draw.ps_type; + int j, offset; + + /* mmPA_CL_VS_OUT_CNTL */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x207; + ptr[i++] = 0; + + /* mmSPI_SHADER_PGM_RSRC3_GS */ + ptr[i++] = PACKET3(PACKET3_SET_SH_REG_INDEX, 1); + ptr[i++] = 0x30000087; + ptr[i++] = 0xffff; + /* mmSPI_SHADER_PGM_RSRC4_GS */ + ptr[i++] = PACKET3(PACKET3_SET_SH_REG_INDEX, 1); + ptr[i++] = 0x30000081; + ptr[i++] = 0x1fff0001; + + /* mmSPI_SHADER_PGM_LO_ES */ + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 2); + ptr[i++] = 0xc8; + ptr[i++] = shader_addr >> 8; + ptr[i++] = shader_addr >> 40; + + /* write sh reg */ + for (j = 0; j < shader->num_sh_reg; j++) { + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 1); + ptr[i++] = shader->sh_reg[j].reg_offset - gfx_info->sh_reg_base; + ptr[i++] = shader->sh_reg[j].reg_value; + } + /* write context reg */ + for (j = 0; j < shader->num_context_reg; j++) { + switch (shader->context_reg[j].reg_offset) { + case 0xA1B1: //mmSPI_VS_OUT_CONFIG + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = shader->context_reg[j].reg_offset - gfx_info->context_reg_base; + ptr[i++] = 2; + break; + case 0xA1C3: //mmSPI_SHADER_POS_FORMAT + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = shader->context_reg[j].reg_offset - gfx_info->context_reg_base; + ptr[i++] = 4; + break; + case 0xA2E4: //mmVGT_GS_INSTANCE_CNT + case 0xA2CE: //mmVGT_GS_MAX_VERT_OUT + break; + default: + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = shader->context_reg[j].reg_offset - gfx_info->context_reg_base; + ptr[i++] = shader->context_reg[j].reg_value; + break; + } + } + + // write constant + // dst rect + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 4); + ptr[i++] = 0x8c; + i += 2; + ptr[i++] = test_priv->info->hang_slow ? 0x45000000 : 0x42000000; + ptr[i++] = test_priv->info->hang_slow ? 0x45000000 : 0x42000000; + // src rect + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 4); + ptr[i++] = 0x90; + i += 2; + if (ps == PS_CONST) { + i += 2; + } else if (ps == PS_TEX) { + ptr[i++] = 0x3f800000; + ptr[i++] = 0x3f800000; + } + + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 4); + ptr[i++] = 0x94; + i += 4; + // vtx_attributes_mem + ptr[i++] = 0xc02f1000; + offset = i * sizeof(uint32_t); + i += 44; + ptr[i++] = test_priv->vtx_attributes_mem.mc_address & 0xffffffff; + ptr[i++] = 0xc0100000 | ((test_priv->vtx_attributes_mem.mc_address >> 32) & 0xffff); + ptr[i++] = test_priv->vtx_attributes_mem.size / 16; + ptr[i++] = 0x2043ffac; + ptr[i++] = PACKET3(PACKET3_SET_SH_REG_OFFSET, 2); + ptr[i++] = 0x98; + ptr[i++] = offset; + i++; + + test_priv->cmd_curr = i; +} + +static void amdgpu_draw_vs_RectPosTexFast_write2hw(struct shader_test_priv *test_priv) +{ + switch (test_priv->info->version) { + case AMDGPU_TEST_GFX_V9: + amdgpu_draw_vs_RectPosTexFast_write2hw_gfx9(test_priv); + break; + case AMDGPU_TEST_GFX_V10: + amdgpu_draw_vs_RectPosTexFast_write2hw_gfx10(test_priv); + break; + case AMDGPU_TEST_GFX_V11: + amdgpu_draw_vs_RectPosTexFast_write2hw_gfx11(test_priv); + break; + } +} + +static void amdgpu_draw_ps_write2hw_gfx9_10(struct shader_test_priv *test_priv) +{ + int i, j; + uint64_t shader_addr = test_priv->shader_draw.ps_bo.mc_address; + const struct shader_test_ps_shader *ps = &shader_test_ps[test_priv->info->version][test_priv->shader_draw.ps_type]; + uint32_t *ptr = test_priv->cmd.ptr; + + i = test_priv->cmd_curr; + + if (test_priv->info->version == AMDGPU_TEST_GFX_V9) { + /* 0x2c07 SPI_SHADER_PGM_RSRC3_PS + 0x2c08 SPI_SHADER_PGM_LO_PS + 0x2c09 SPI_SHADER_PGM_HI_PS */ + /* multiplicator 9 is from SPI_SHADER_COL_FORMAT */ + if (!test_priv->info->hang) + shader_addr += 256 * 9; + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 3); + ptr[i++] = 0x7; + ptr[i++] = 0xffff; + ptr[i++] = shader_addr >> 8; + ptr[i++] = shader_addr >> 40; + } else { + //if (!test_priv->info->hang) + shader_addr += 256 * 9; + /* 0x2c08 SPI_SHADER_PGM_LO_PS + 0x2c09 SPI_SHADER_PGM_HI_PS */ + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 2); + ptr[i++] = 0x8; + ptr[i++] = shader_addr >> 8; + ptr[i++] = shader_addr >> 40; + + /* mmSPI_SHADER_PGM_RSRC3_PS */ + ptr[i++] = PACKET3(PACKET3_SET_SH_REG_INDEX, 1); + ptr[i++] = 0x30000007; + ptr[i++] = 0xffff; + /* mmSPI_SHADER_PGM_RSRC4_PS */ + ptr[i++] = PACKET3(PACKET3_SET_SH_REG_INDEX, 1); + ptr[i++] = 0x30000001; + ptr[i++] = 0xffff; + } + + for (j = 0; j < ps->num_sh_reg; j++) { + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 1); + ptr[i++] = ps->sh_reg[j].reg_offset - 0x2c00; + ptr[i++] = ps->sh_reg[j].reg_value; + } + + for (j = 0; j < ps->num_context_reg; j++) { + if (ps->context_reg[j].reg_offset != 0xA1C5) { + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = ps->context_reg[j].reg_offset - 0xa000; + ptr[i++] = ps->context_reg[j].reg_value; + } + + if (ps->context_reg[j].reg_offset == 0xA1B4) { + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x1b3; + ptr[i++] = 2; + } + } + + test_priv->cmd_curr = i; +} + +static void amdgpu_draw_ps_write2hw_gfx11(struct shader_test_priv *test_priv) +{ + int i, j; + uint64_t shader_addr = test_priv->shader_draw.ps_bo.mc_address; + enum amdgpu_test_gfx_version version = test_priv->info->version; + const struct shader_test_ps_shader *ps = &shader_test_ps[version][test_priv->shader_draw.ps_type]; + uint32_t *ptr = test_priv->cmd.ptr; + uint32_t export_shader_offset; + + i = test_priv->cmd_curr; + + /* SPI_SHADER_PGM_LO_PS + SPI_SHADER_PGM_HI_PS */ + shader_addr >>= 8; + if (!test_priv->info->hang) { + export_shader_offset = (round_up_size(ps->shader_size) * 9) >> 8; + shader_addr += export_shader_offset; + } + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 2); + ptr[i++] = 0x8; + ptr[i++] = shader_addr & 0xffffffff; + ptr[i++] = (shader_addr >> 32) & 0xffffffff; + /* mmSPI_SHADER_PGM_RSRC3_PS */ + ptr[i++] = PACKET3(PACKET3_SET_SH_REG_INDEX, 1); + ptr[i++] = 0x30000007; + ptr[i++] = 0xffff; + /* mmSPI_SHADER_PGM_RSRC4_PS */ + ptr[i++] = PACKET3(PACKET3_SET_SH_REG_INDEX, 1); + ptr[i++] = 0x30000001; + ptr[i++] = 0x3fffff; + + for (j = 0; j < ps->num_sh_reg; j++) { + ptr[i++] = PACKET3(PACKET3_SET_SH_REG, 1); + ptr[i++] = ps->sh_reg[j].reg_offset - shader_test_gfx_info[version].sh_reg_base; + ptr[i++] = ps->sh_reg[j].reg_value; + } + + for (j = 0; j < ps->num_context_reg; j++) { + /* !mmSPI_SHADER_COL_FORMAT */ + if (ps->context_reg[j].reg_offset != 0xA1C5) { + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = ps->context_reg[j].reg_offset - shader_test_gfx_info[version].context_reg_base; + ptr[i++] = ps->context_reg[j].reg_value; + } + + /* mmSPI_PS_INPUT_ADDR */ + if (ps->context_reg[j].reg_offset == 0xA1B4) { + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x1b3; + ptr[i++] = 2; + } + } + + test_priv->cmd_curr = i; +} + +static void amdgpu_draw_ps_write2hw(struct shader_test_priv *test_priv) +{ + switch (test_priv->info->version) { + case AMDGPU_TEST_GFX_V9: + case AMDGPU_TEST_GFX_V10: + amdgpu_draw_ps_write2hw_gfx9_10(test_priv); + break; + case AMDGPU_TEST_GFX_V11: + amdgpu_draw_ps_write2hw_gfx11(test_priv); + break; + } +} + +static void amdgpu_draw_draw(struct shader_test_priv *test_priv) +{ + int i = test_priv->cmd_curr; + uint32_t *ptr = test_priv->cmd.ptr; + + switch (test_priv->info->version) { + case AMDGPU_TEST_GFX_V9: + /* mmIA_MULTI_VGT_PARAM */ + ptr[i++] = PACKET3(PACKET3_SET_UCONFIG_REG, 1); + ptr[i++] = 0x40000258; + ptr[i++] = 0xd00ff; + /* mmVGT_PRIMITIVE_TYPE */ + ptr[i++] = PACKET3(PACKET3_SET_UCONFIG_REG, 1); + ptr[i++] = 0x10000242; + ptr[i++] = 0x11; + break; + case AMDGPU_TEST_GFX_V10: + /* mmGE_CNTL */ + ptr[i++] = PACKET3(PACKET3_SET_UCONFIG_REG, 1); + ptr[i++] = 0x25b; + ptr[i++] = 0xff; + /* mmVGT_PRIMITIVE_TYPE */ + ptr[i++] = PACKET3(PACKET3_SET_UCONFIG_REG, 1); + ptr[i++] = 0x242; + ptr[i++] = 0x11; + break; + case AMDGPU_TEST_GFX_V11: + /* mmGE_CNTL */ + ptr[i++] = PACKET3(PACKET3_SET_UCONFIG_REG, 1); + ptr[i++] = 0x25b; + ptr[i++] = 0x80fc80; + /* mmVGT_PRIMITIVE_TYPE */ + ptr[i++] = PACKET3(PACKET3_SET_UCONFIG_REG, 1); + ptr[i++] = 0x242; + ptr[i++] = 0x11; + break; + } + + ptr[i++] = PACKET3(PACKET3_DRAW_INDEX_AUTO, 1); + ptr[i++] = 3; + ptr[i++] = 2; + + test_priv->cmd_curr = i; +} + +static void amdgpu_memset_draw_test(struct shader_test_info *test_info) +{ + struct shader_test_priv test_priv; + amdgpu_context_handle context_handle; + struct shader_test_bo *ps_bo = &(test_priv.shader_draw.ps_bo); + struct shader_test_bo *vs_bo = &(test_priv.shader_draw.vs_bo); + struct shader_test_bo *dst = &(test_priv.dst); + struct shader_test_bo *cmd = &(test_priv.cmd); + struct shader_test_bo *vtx_attributes_mem = &(test_priv.vtx_attributes_mem); + amdgpu_bo_handle resources[5]; + uint8_t *ptr_dst; + uint32_t *ptr_cmd; + int i, r; + struct amdgpu_cs_request ibs_request = {0}; + struct amdgpu_cs_ib_info ib_info = {0}; + struct amdgpu_cs_fence fence_status = {0}; + uint32_t expired; + amdgpu_bo_list_handle bo_list; + uint8_t cptr[16]; + + memset(&test_priv, 0, sizeof(test_priv)); + test_priv.info = test_info; + + r = amdgpu_cs_ctx_create(test_info->device_handle, &context_handle); + CU_ASSERT_EQUAL(r, 0); + + ps_bo->size = 0x2000; + ps_bo->heap = AMDGPU_GEM_DOMAIN_VRAM; + r = shader_test_bo_alloc(test_info->device_handle, ps_bo); + CU_ASSERT_EQUAL(r, 0); + memset(ps_bo->ptr, 0, ps_bo->size); + + vs_bo->size = 4096; + vs_bo->heap = AMDGPU_GEM_DOMAIN_VRAM; + r = shader_test_bo_alloc(test_info->device_handle, vs_bo); + CU_ASSERT_EQUAL(r, 0); + memset(vs_bo->ptr, 0, vs_bo->size); + + test_priv.shader_draw.ps_type = PS_CONST; + amdgpu_draw_load_ps_shader(&test_priv); + + test_priv.shader_draw.vs_type = VS_RECTPOSTEXFAST; + amdgpu_draw_load_vs_shader(&test_priv); + + cmd->size = 4096; + cmd->heap = AMDGPU_GEM_DOMAIN_GTT; + r = shader_test_bo_alloc(test_info->device_handle, cmd); + CU_ASSERT_EQUAL(r, 0); + ptr_cmd = cmd->ptr; + memset(ptr_cmd, 0, cmd->size); + + dst->size = 0x4000; + dst->heap = AMDGPU_GEM_DOMAIN_VRAM; + r = shader_test_bo_alloc(test_info->device_handle, dst); + CU_ASSERT_EQUAL(r, 0); + + if (test_info->version == AMDGPU_TEST_GFX_V11) { + vtx_attributes_mem->size = 0x4040000; + vtx_attributes_mem->heap = AMDGPU_GEM_DOMAIN_VRAM; + + r = shader_test_bo_alloc(test_info->device_handle, vtx_attributes_mem); + CU_ASSERT_EQUAL(r, 0); + } + + amdgpu_draw_init(&test_priv); + + amdgpu_draw_setup_and_write_drawblt_surf_info(&test_priv); + + amdgpu_draw_setup_and_write_drawblt_state(&test_priv); + + amdgpu_draw_vs_RectPosTexFast_write2hw(&test_priv); + + amdgpu_draw_ps_write2hw(&test_priv); + + i = test_priv.cmd_curr; + /* ps constant data */ + ptr_cmd[i++] = PACKET3(PACKET3_SET_SH_REG, 4); + ptr_cmd[i++] = 0xc; + ptr_cmd[i++] = 0x33333333; + ptr_cmd[i++] = 0x33333333; + ptr_cmd[i++] = 0x33333333; + ptr_cmd[i++] = 0x33333333; + test_priv.cmd_curr = i; + + amdgpu_draw_draw(&test_priv); + + i = test_priv.cmd_curr; + while (i & 7) + ptr_cmd[i++] = 0xffff1000; /* type3 nop packet */ + test_priv.cmd_curr = i; + + i = 0; + resources[i++] = dst->bo; + resources[i++] = ps_bo->bo; + resources[i++] = vs_bo->bo; + resources[i++] = cmd->bo; + if (vtx_attributes_mem->size) + resources[i++] = vtx_attributes_mem->bo; + r = amdgpu_bo_list_create(test_info->device_handle, i, resources, NULL, &bo_list); + CU_ASSERT_EQUAL(r, 0); + + ib_info.ib_mc_address = cmd->mc_address; + ib_info.size = test_priv.cmd_curr; + ibs_request.ip_type = test_info->ip; + ibs_request.ring = test_info->ring; + ibs_request.resources = bo_list; + ibs_request.number_of_ibs = 1; + ibs_request.ibs = &ib_info; + ibs_request.fence_info.handle = NULL; + + /* submit CS */ + r = amdgpu_cs_submit(context_handle, 0, &ibs_request, 1); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_list_destroy(bo_list); + CU_ASSERT_EQUAL(r, 0); + + fence_status.ip_type = test_info->ip; + fence_status.ip_instance = 0; + fence_status.ring = test_info->ring; + fence_status.context = context_handle; + fence_status.fence = ibs_request.seq_no; + + /* wait for IB accomplished */ + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE, + 0, &expired); + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(expired, true); + + /* verify if memset test result meets with expected */ + i = 0; + ptr_dst = dst->ptr; + memset(cptr, 0x33, 16); + CU_ASSERT_EQUAL(memcmp(ptr_dst + i, cptr, 16), 0); + i = dst->size - 16; + CU_ASSERT_EQUAL(memcmp(ptr_dst + i, cptr, 16), 0); + i = dst->size / 2; + CU_ASSERT_EQUAL(memcmp(ptr_dst + i, cptr, 16), 0); + + if (vtx_attributes_mem->size) { + r = shader_test_bo_free(vtx_attributes_mem); + CU_ASSERT_EQUAL(r, 0); + } + + r = shader_test_bo_free(dst); + CU_ASSERT_EQUAL(r, 0); + + r = shader_test_bo_free(cmd); + CU_ASSERT_EQUAL(r, 0); + + r = shader_test_bo_free(ps_bo); + CU_ASSERT_EQUAL(r, 0); + + r = shader_test_bo_free(vs_bo); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_memcpy_draw_test(struct shader_test_info *test_info) +{ + struct shader_test_priv test_priv; + amdgpu_context_handle context_handle; + struct shader_test_bo *ps_bo = &(test_priv.shader_draw.ps_bo); + struct shader_test_bo *vs_bo = &(test_priv.shader_draw.vs_bo); + struct shader_test_bo *src = &(test_priv.src); + struct shader_test_bo *dst = &(test_priv.dst); + struct shader_test_bo *cmd = &(test_priv.cmd); + struct shader_test_bo *vtx_attributes_mem = &(test_priv.vtx_attributes_mem); + amdgpu_bo_handle resources[6]; + uint8_t *ptr_dst; + uint8_t *ptr_src; + uint32_t *ptr_cmd; + int i, r; + struct amdgpu_cs_request ibs_request = {0}; + struct amdgpu_cs_ib_info ib_info = {0}; + uint32_t hang_state, hangs; + uint32_t expired; + amdgpu_bo_list_handle bo_list; + struct amdgpu_cs_fence fence_status = {0}; + + memset(&test_priv, 0, sizeof(test_priv)); + test_priv.info = test_info; + test_priv.cmd.size = 4096; + test_priv.cmd.heap = AMDGPU_GEM_DOMAIN_GTT; + + ps_bo->heap = AMDGPU_GEM_DOMAIN_VRAM; + test_priv.shader_draw.ps_type = PS_TEX; + vs_bo->size = 4096; + vs_bo->heap = AMDGPU_GEM_DOMAIN_VRAM; + test_priv.shader_draw.vs_type = VS_RECTPOSTEXFAST; + test_priv.src.heap = AMDGPU_GEM_DOMAIN_VRAM; + test_priv.dst.heap = AMDGPU_GEM_DOMAIN_VRAM; + if (test_info->hang_slow) { + test_priv.shader_draw.ps_bo.size = 16*1024*1024; + test_priv.src.size = 0x4000000; + test_priv.dst.size = 0x4000000; + } else { + test_priv.shader_draw.ps_bo.size = 0x2000; + test_priv.src.size = 0x4000; + test_priv.dst.size = 0x4000; + } + + r = amdgpu_cs_ctx_create(test_info->device_handle, &context_handle); + CU_ASSERT_EQUAL(r, 0); + + r = shader_test_bo_alloc(test_info->device_handle, ps_bo); + CU_ASSERT_EQUAL(r, 0); + memset(ps_bo->ptr, 0, ps_bo->size); + + r = shader_test_bo_alloc(test_info->device_handle, vs_bo); + CU_ASSERT_EQUAL(r, 0); + memset(vs_bo->ptr, 0, vs_bo->size); + + amdgpu_draw_load_ps_shader(&test_priv); + amdgpu_draw_load_vs_shader(&test_priv); + + r = shader_test_bo_alloc(test_info->device_handle, cmd); + CU_ASSERT_EQUAL(r, 0); + ptr_cmd = cmd->ptr; + memset(ptr_cmd, 0, cmd->size); + + r = shader_test_bo_alloc(test_info->device_handle, src); + CU_ASSERT_EQUAL(r, 0); + ptr_src = src->ptr; + memset(ptr_src, 0x55, src->size); + + r = shader_test_bo_alloc(test_info->device_handle, dst); + CU_ASSERT_EQUAL(r, 0); + + if (test_info->version == AMDGPU_TEST_GFX_V11) { + vtx_attributes_mem->size = 0x4040000; + vtx_attributes_mem->heap = AMDGPU_GEM_DOMAIN_VRAM; + + r = shader_test_bo_alloc(test_info->device_handle, vtx_attributes_mem); + CU_ASSERT_EQUAL(r, 0); + } + + amdgpu_draw_init(&test_priv); + + amdgpu_draw_setup_and_write_drawblt_surf_info(&test_priv); + + amdgpu_draw_setup_and_write_drawblt_state(&test_priv); + + amdgpu_draw_vs_RectPosTexFast_write2hw(&test_priv); + + amdgpu_draw_ps_write2hw(&test_priv); + + // write ps user constant data + i = test_priv.cmd_curr; + ptr_cmd[i++] = PACKET3(PACKET3_SET_SH_REG, 8); + switch (test_info->version) { + case AMDGPU_TEST_GFX_V9: + ptr_cmd[i++] = 0xc; + ptr_cmd[i++] = src->mc_address >> 8; + ptr_cmd[i++] = src->mc_address >> 40 | 0x10e00000; + ptr_cmd[i++] = test_info->hang_slow ? 0x1ffcfff : 0x7c01f; + ptr_cmd[i++] = 0x90500fac; + ptr_cmd[i++] = test_info->hang_slow ? 0x1ffe000 : 0x3e000; + i += 3; + break; + case AMDGPU_TEST_GFX_V10: + ptr_cmd[i++] = 0xc; + ptr_cmd[i++] = src->mc_address >> 8; + ptr_cmd[i++] = src->mc_address >> 40 | 0xc4b00000; + ptr_cmd[i++] = test_info->hang_slow ? 0x81ffc1ff : 0x8007c007; + ptr_cmd[i++] = 0x90500fac; + i += 2; + ptr_cmd[i++] = test_info->hang_slow ? 0 : 0x400; + i++; + break; + case AMDGPU_TEST_GFX_V11: + ptr_cmd[i++] = 0xc; + ptr_cmd[i++] = src->mc_address >> 8; + ptr_cmd[i++] = src->mc_address >> 40 | 0xc4b00000; + ptr_cmd[i++] = test_info->hang_slow ? 0x1ffc1ff : 0x7c007; + ptr_cmd[i++] = test_info->hang_slow ? 0x90a00fac : 0x90600fac; + i += 2; + ptr_cmd[i++] = 0x400; + i++; + break; + } + + ptr_cmd[i++] = PACKET3(PACKET3_SET_SH_REG, 4); + ptr_cmd[i++] = 0x14; + ptr_cmd[i++] = 0x92; + i += 3; + + ptr_cmd[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr_cmd[i++] = 0x191; + ptr_cmd[i++] = 0; + test_priv.cmd_curr = i; + + amdgpu_draw_draw(&test_priv); + + i = test_priv.cmd_curr; + while (i & 7) + ptr_cmd[i++] = 0xffff1000; /* type3 nop packet */ + test_priv.cmd_curr = i; + + i = 0; + resources[i++] = dst->bo; + resources[i++] = src->bo; + resources[i++] = ps_bo->bo; + resources[i++] = vs_bo->bo; + resources[i++] = cmd->bo; + if (vtx_attributes_mem->size) + resources[i++] = vtx_attributes_mem->bo; + r = amdgpu_bo_list_create(test_info->device_handle, i, resources, NULL, &bo_list); + CU_ASSERT_EQUAL(r, 0); + + ib_info.ib_mc_address = cmd->mc_address; + ib_info.size = test_priv.cmd_curr; + ibs_request.ip_type = test_info->ip; + ibs_request.ring = test_info->ring; + ibs_request.resources = bo_list; + ibs_request.number_of_ibs = 1; + ibs_request.ibs = &ib_info; + ibs_request.fence_info.handle = NULL; + r = amdgpu_cs_submit(context_handle, 0, &ibs_request, 1); + CU_ASSERT_EQUAL(r, 0); + + fence_status.ip_type = test_info->ip; + fence_status.ip_instance = 0; + fence_status.ring = test_info->ring; + fence_status.context = context_handle; + fence_status.fence = ibs_request.seq_no; + + /* wait for IB accomplished */ + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE, + 0, &expired); + if (!test_info->hang) { + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(expired, true); + + /* verify if memcpy test result meets with expected */ + i = 0; + ptr_dst = dst->ptr; + CU_ASSERT_EQUAL(memcmp(ptr_dst + i, ptr_src + i, 16), 0); + i = dst->size - 16; + CU_ASSERT_EQUAL(memcmp(ptr_dst + i, ptr_src + i, 16), 0); + i = dst->size / 2; + CU_ASSERT_EQUAL(memcmp(ptr_dst + i, ptr_src + i, 16), 0); + } else { + r = amdgpu_cs_query_reset_state(context_handle, &hang_state, &hangs); + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(hang_state, AMDGPU_CTX_UNKNOWN_RESET); + } + + r = amdgpu_bo_list_destroy(bo_list); + CU_ASSERT_EQUAL(r, 0); + + if (vtx_attributes_mem->size) { + r = shader_test_bo_free(vtx_attributes_mem); + CU_ASSERT_EQUAL(r, 0); + } + + r = shader_test_bo_free(src); + CU_ASSERT_EQUAL(r, 0); + + r = shader_test_bo_free(dst); + CU_ASSERT_EQUAL(r, 0); + + r = shader_test_bo_free(cmd); + CU_ASSERT_EQUAL(r, 0); + + r = shader_test_bo_free(ps_bo); + CU_ASSERT_EQUAL(r, 0); + + r = shader_test_bo_free(vs_bo); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void shader_test_draw_cb(struct shader_test_info *test_info) +{ + amdgpu_memset_draw_test(test_info); + amdgpu_memcpy_draw_test(test_info); +} + +static void shader_test_draw_hang_cb(struct shader_test_info *test_info) +{ + test_info->hang = 0; + amdgpu_memcpy_draw_test(test_info); + + test_info->hang = 1; + amdgpu_memcpy_draw_test(test_info); + + test_info->hang = 0; + amdgpu_memcpy_draw_test(test_info); +} + +static void shader_test_draw_hang_slow_cb(struct shader_test_info *test_info) +{ + test_info->hang = 0; + test_info->hang_slow = 0; + amdgpu_memcpy_draw_test(test_info); + + test_info->hang = 1; + test_info->hang_slow = 1; + amdgpu_memcpy_draw_test(test_info); + + test_info->hang = 0; + test_info->hang_slow = 0; + amdgpu_memcpy_draw_test(test_info); +} + + +void amdgpu_test_draw_helper(amdgpu_device_handle device_handle) +{ + shader_test_for_each(device_handle, AMDGPU_HW_IP_GFX, shader_test_draw_cb); +} + +void amdgpu_test_draw_hang_helper(amdgpu_device_handle device_handle) +{ + shader_test_for_each(device_handle, AMDGPU_HW_IP_GFX, shader_test_draw_hang_cb); +} + +void amdgpu_test_draw_hang_slow_helper(amdgpu_device_handle device_handle) +{ + shader_test_for_each(device_handle, AMDGPU_HW_IP_GFX, shader_test_draw_hang_slow_cb); +} diff --git a/tests/amdgpu/syncobj_tests.c b/tests/amdgpu/syncobj_tests.c new file mode 100644 index 0000000..690bea0 --- /dev/null +++ b/tests/amdgpu/syncobj_tests.c @@ -0,0 +1,314 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * +*/ + +#include "CUnit/Basic.h" +#include "xf86drm.h" + +#include "amdgpu_test.h" +#include "amdgpu_drm.h" +#include "amdgpu_internal.h" +#include + +static amdgpu_device_handle device_handle; +static uint32_t major_version; +static uint32_t minor_version; + +static uint32_t family_id; +static uint32_t chip_id; +static uint32_t chip_rev; + +static void amdgpu_syncobj_timeline_test(void); + +CU_BOOL suite_syncobj_timeline_tests_enable(void) +{ + int r; + uint64_t cap = 0; + + r = drmGetCap(drm_amdgpu[0], DRM_CAP_SYNCOBJ_TIMELINE, &cap); + if (r || cap == 0) + return CU_FALSE; + + return CU_TRUE; +} + +int suite_syncobj_timeline_tests_init(void) +{ + int r; + + r = amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle); + + if (r) { + if ((r == -EACCES) && (errno == EACCES)) + printf("\n\nError:%s. " + "Hint:Try to run this test program as root.", + strerror(errno)); + return CUE_SINIT_FAILED; + } + + return CUE_SUCCESS; +} + +int suite_syncobj_timeline_tests_clean(void) +{ + int r = amdgpu_device_deinitialize(device_handle); + + if (r == 0) + return CUE_SUCCESS; + else + return CUE_SCLEAN_FAILED; +} + + +CU_TestInfo syncobj_timeline_tests[] = { + { "syncobj timeline test", amdgpu_syncobj_timeline_test }, + CU_TEST_INFO_NULL, +}; + +#define GFX_COMPUTE_NOP 0xffff1000 +#define SDMA_NOP 0x0 +static int syncobj_command_submission_helper(uint32_t syncobj_handle, bool + wait_or_signal, uint64_t point) +{ + amdgpu_context_handle context_handle; + amdgpu_bo_handle ib_result_handle; + void *ib_result_cpu; + uint64_t ib_result_mc_address; + struct drm_amdgpu_cs_chunk chunks[2]; + struct drm_amdgpu_cs_chunk_data chunk_data; + struct drm_amdgpu_cs_chunk_syncobj syncobj_data; + struct amdgpu_cs_fence fence_status; + amdgpu_bo_list_handle bo_list; + amdgpu_va_handle va_handle; + uint32_t expired; + int i, r; + uint64_t seq_no; + static uint32_t *ptr; + struct amdgpu_gpu_info gpu_info = {0}; + unsigned gc_ip_type; + + r = amdgpu_query_gpu_info(device_handle, &gpu_info); + CU_ASSERT_EQUAL(r, 0); + + family_id = device_handle->info.family_id; + chip_id = device_handle->info.chip_external_rev; + chip_rev = device_handle->info.chip_rev; + + gc_ip_type = (asic_is_gfx_pipe_removed(family_id, chip_id, chip_rev)) ? + AMDGPU_HW_IP_COMPUTE : AMDGPU_HW_IP_GFX; + + r = amdgpu_cs_ctx_create(device_handle, &context_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_alloc_and_map(device_handle, 4096, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, + &ib_result_handle, &ib_result_cpu, + &ib_result_mc_address, &va_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_get_bo_list(device_handle, ib_result_handle, NULL, + &bo_list); + CU_ASSERT_EQUAL(r, 0); + + ptr = ib_result_cpu; + + for (i = 0; i < 16; ++i) + ptr[i] = wait_or_signal ? GFX_COMPUTE_NOP: SDMA_NOP; + + chunks[0].chunk_id = AMDGPU_CHUNK_ID_IB; + chunks[0].length_dw = sizeof(struct drm_amdgpu_cs_chunk_ib) / 4; + chunks[0].chunk_data = (uint64_t)(uintptr_t)&chunk_data; + chunk_data.ib_data._pad = 0; + chunk_data.ib_data.va_start = ib_result_mc_address; + chunk_data.ib_data.ib_bytes = 16 * 4; + chunk_data.ib_data.ip_type = wait_or_signal ? gc_ip_type : + AMDGPU_HW_IP_DMA; + chunk_data.ib_data.ip_instance = 0; + chunk_data.ib_data.ring = 0; + chunk_data.ib_data.flags = AMDGPU_IB_FLAG_EMIT_MEM_SYNC; + + chunks[1].chunk_id = wait_or_signal ? + AMDGPU_CHUNK_ID_SYNCOBJ_TIMELINE_WAIT : + AMDGPU_CHUNK_ID_SYNCOBJ_TIMELINE_SIGNAL; + chunks[1].length_dw = sizeof(struct drm_amdgpu_cs_chunk_syncobj) / 4; + chunks[1].chunk_data = (uint64_t)(uintptr_t)&syncobj_data; + syncobj_data.handle = syncobj_handle; + syncobj_data.point = point; + syncobj_data.flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT; + + r = amdgpu_cs_submit_raw(device_handle, + context_handle, + bo_list, + 2, + chunks, + &seq_no); + CU_ASSERT_EQUAL(r, 0); + + + memset(&fence_status, 0, sizeof(struct amdgpu_cs_fence)); + fence_status.context = context_handle; + fence_status.ip_type = wait_or_signal ? gc_ip_type : + AMDGPU_HW_IP_DMA; + fence_status.ip_instance = 0; + fence_status.ring = 0; + fence_status.fence = seq_no; + + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE,0, &expired); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_list_destroy(bo_list); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_unmap_and_free(ib_result_handle, va_handle, + ib_result_mc_address, 4096); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); + + return r; +} + +struct syncobj_point { + uint32_t syncobj_handle; + uint64_t point; +}; + +static void *syncobj_wait(void *data) +{ + struct syncobj_point *sp = (struct syncobj_point *)data; + int r; + + r = syncobj_command_submission_helper(sp->syncobj_handle, true, + sp->point); + CU_ASSERT_EQUAL(r, 0); + + return (void *)(long)r; +} + +static void *syncobj_signal(void *data) +{ + struct syncobj_point *sp = (struct syncobj_point *)data; + int r; + + r = syncobj_command_submission_helper(sp->syncobj_handle, false, + sp->point); + CU_ASSERT_EQUAL(r, 0); + + return (void *)(long)r; +} + +static void amdgpu_syncobj_timeline_test(void) +{ + static pthread_t wait_thread; + static pthread_t signal_thread; + static pthread_t c_thread; + struct syncobj_point sp1, sp2, sp3; + uint32_t syncobj_handle; + uint64_t payload; + uint64_t wait_point, signal_point; + uint64_t timeout; + struct timespec tp; + int r, sync_fd; + void *tmp; + + r = amdgpu_cs_create_syncobj2(device_handle, 0, &syncobj_handle); + CU_ASSERT_EQUAL(r, 0); + + // wait on point 5 + sp1.syncobj_handle = syncobj_handle; + sp1.point = 5; + r = pthread_create(&wait_thread, NULL, syncobj_wait, &sp1); + CU_ASSERT_EQUAL(r, 0); + + // signal on point 10 + sp2.syncobj_handle = syncobj_handle; + sp2.point = 10; + r = pthread_create(&signal_thread, NULL, syncobj_signal, &sp2); + CU_ASSERT_EQUAL(r, 0); + + r = pthread_join(wait_thread, &tmp); + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(tmp, 0); + + r = pthread_join(signal_thread, &tmp); + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(tmp, 0); + + //query timeline payload + r = amdgpu_cs_syncobj_query(device_handle, &syncobj_handle, + &payload, 1); + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(payload, 10); + + //signal on point 16 + sp3.syncobj_handle = syncobj_handle; + sp3.point = 16; + r = pthread_create(&c_thread, NULL, syncobj_signal, &sp3); + CU_ASSERT_EQUAL(r, 0); + //CPU wait on point 16 + wait_point = 16; + timeout = 0; + clock_gettime(CLOCK_MONOTONIC, &tp); + timeout = tp.tv_sec * 1000000000ULL + tp.tv_nsec; + timeout += 0x10000000000; //10s + r = amdgpu_cs_syncobj_timeline_wait(device_handle, &syncobj_handle, + &wait_point, 1, timeout, + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL | + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, + NULL); + + CU_ASSERT_EQUAL(r, 0); + r = pthread_join(c_thread, &tmp); + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(tmp, 0); + + // export point 16 and import to point 18 + r = amdgpu_cs_syncobj_export_sync_file2(device_handle, syncobj_handle, + 16, + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, + &sync_fd); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_cs_syncobj_import_sync_file2(device_handle, syncobj_handle, + 18, sync_fd); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_cs_syncobj_query(device_handle, &syncobj_handle, + &payload, 1); + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(payload, 18); + + // CPU signal on point 20 + signal_point = 20; + r = amdgpu_cs_syncobj_timeline_signal(device_handle, &syncobj_handle, + &signal_point, 1); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_cs_syncobj_query(device_handle, &syncobj_handle, + &payload, 1); + CU_ASSERT_EQUAL(r, 0); + CU_ASSERT_EQUAL(payload, 20); + + r = amdgpu_cs_destroy_syncobj(device_handle, syncobj_handle); + CU_ASSERT_EQUAL(r, 0); + +} diff --git a/tests/amdgpu/uvd_enc_tests.c b/tests/amdgpu/uvd_enc_tests.c new file mode 100644 index 0000000..b4251bc --- /dev/null +++ b/tests/amdgpu/uvd_enc_tests.c @@ -0,0 +1,491 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * +*/ + +#include +#include + +#include "CUnit/Basic.h" + +#include "util_math.h" + +#include "amdgpu_test.h" +#include "amdgpu_drm.h" +#include "amdgpu_internal.h" +#include "frame.h" +#include "uve_ib.h" + +#define IB_SIZE 4096 +#define MAX_RESOURCES 16 + +struct amdgpu_uvd_enc_bo { + amdgpu_bo_handle handle; + amdgpu_va_handle va_handle; + uint64_t addr; + uint64_t size; + uint8_t *ptr; +}; + +struct amdgpu_uvd_enc { + unsigned width; + unsigned height; + struct amdgpu_uvd_enc_bo session; + struct amdgpu_uvd_enc_bo vbuf; + struct amdgpu_uvd_enc_bo bs; + struct amdgpu_uvd_enc_bo fb; + struct amdgpu_uvd_enc_bo cpb; +}; + +static amdgpu_device_handle device_handle; +static uint32_t major_version; +static uint32_t minor_version; +static uint32_t family_id; + +static amdgpu_context_handle context_handle; +static amdgpu_bo_handle ib_handle; +static amdgpu_va_handle ib_va_handle; +static uint64_t ib_mc_address; +static uint32_t *ib_cpu; + +static struct amdgpu_uvd_enc enc; +static amdgpu_bo_handle resources[MAX_RESOURCES]; +static unsigned num_resources; + +static void amdgpu_cs_uvd_enc_create(void); +static void amdgpu_cs_uvd_enc_session_init(void); +static void amdgpu_cs_uvd_enc_encode(void); +static void amdgpu_cs_uvd_enc_destroy(void); + + +CU_TestInfo uvd_enc_tests[] = { + { "UVD ENC create", amdgpu_cs_uvd_enc_create }, + { "UVD ENC session init", amdgpu_cs_uvd_enc_session_init }, + { "UVD ENC encode", amdgpu_cs_uvd_enc_encode }, + { "UVD ENC destroy", amdgpu_cs_uvd_enc_destroy }, + CU_TEST_INFO_NULL, +}; + +CU_BOOL suite_uvd_enc_tests_enable(void) +{ + int r; + struct drm_amdgpu_info_hw_ip info; + + if (amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle)) + return CU_FALSE; + + r = amdgpu_query_hw_ip_info(device_handle, AMDGPU_HW_IP_UVD_ENC, 0, &info); + + if (amdgpu_device_deinitialize(device_handle)) + return CU_FALSE; + + if (!info.available_rings) + printf("\n\nThe ASIC NOT support UVD ENC, suite disabled.\n"); + + return (r == 0 && (info.available_rings ? CU_TRUE : CU_FALSE)); +} + + +int suite_uvd_enc_tests_init(void) +{ + int r; + + r = amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle); + if (r) + return CUE_SINIT_FAILED; + + family_id = device_handle->info.family_id; + + r = amdgpu_cs_ctx_create(device_handle, &context_handle); + if (r) + return CUE_SINIT_FAILED; + + r = amdgpu_bo_alloc_and_map(device_handle, IB_SIZE, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, + &ib_handle, (void**)&ib_cpu, + &ib_mc_address, &ib_va_handle); + if (r) + return CUE_SINIT_FAILED; + + return CUE_SUCCESS; +} + +int suite_uvd_enc_tests_clean(void) +{ + int r; + + r = amdgpu_bo_unmap_and_free(ib_handle, ib_va_handle, + ib_mc_address, IB_SIZE); + if (r) + return CUE_SCLEAN_FAILED; + + r = amdgpu_cs_ctx_free(context_handle); + if (r) + return CUE_SCLEAN_FAILED; + + r = amdgpu_device_deinitialize(device_handle); + if (r) + return CUE_SCLEAN_FAILED; + + return CUE_SUCCESS; +} + +static int submit(unsigned ndw, unsigned ip) +{ + struct amdgpu_cs_request ibs_request = {0}; + struct amdgpu_cs_ib_info ib_info = {0}; + struct amdgpu_cs_fence fence_status = {0}; + uint32_t expired; + int r; + + ib_info.ib_mc_address = ib_mc_address; + ib_info.size = ndw; + + ibs_request.ip_type = ip; + + r = amdgpu_bo_list_create(device_handle, num_resources, resources, + NULL, &ibs_request.resources); + if (r) + return r; + + ibs_request.number_of_ibs = 1; + ibs_request.ibs = &ib_info; + ibs_request.fence_info.handle = NULL; + + r = amdgpu_cs_submit(context_handle, 0, &ibs_request, 1); + if (r) + return r; + + r = amdgpu_bo_list_destroy(ibs_request.resources); + if (r) + return r; + + fence_status.context = context_handle; + fence_status.ip_type = ip; + fence_status.fence = ibs_request.seq_no; + + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE, + 0, &expired); + if (r) + return r; + + return 0; +} + +static void alloc_resource(struct amdgpu_uvd_enc_bo *uvd_enc_bo, + unsigned size, unsigned domain) +{ + struct amdgpu_bo_alloc_request req = {0}; + amdgpu_bo_handle buf_handle; + amdgpu_va_handle va_handle; + uint64_t va = 0; + int r; + + req.alloc_size = ALIGN(size, 4096); + req.preferred_heap = domain; + r = amdgpu_bo_alloc(device_handle, &req, &buf_handle); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_va_range_alloc(device_handle, + amdgpu_gpu_va_range_general, + req.alloc_size, 1, 0, &va, + &va_handle, 0); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_bo_va_op(buf_handle, 0, req.alloc_size, va, 0, + AMDGPU_VA_OP_MAP); + CU_ASSERT_EQUAL(r, 0); + uvd_enc_bo->addr = va; + uvd_enc_bo->handle = buf_handle; + uvd_enc_bo->size = req.alloc_size; + uvd_enc_bo->va_handle = va_handle; + r = amdgpu_bo_cpu_map(uvd_enc_bo->handle, (void **)&uvd_enc_bo->ptr); + CU_ASSERT_EQUAL(r, 0); + memset(uvd_enc_bo->ptr, 0, size); + r = amdgpu_bo_cpu_unmap(uvd_enc_bo->handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void free_resource(struct amdgpu_uvd_enc_bo *uvd_enc_bo) +{ + int r; + + r = amdgpu_bo_va_op(uvd_enc_bo->handle, 0, uvd_enc_bo->size, + uvd_enc_bo->addr, 0, AMDGPU_VA_OP_UNMAP); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_va_range_free(uvd_enc_bo->va_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_free(uvd_enc_bo->handle); + CU_ASSERT_EQUAL(r, 0); + memset(uvd_enc_bo, 0, sizeof(*uvd_enc_bo)); +} + +static void amdgpu_cs_uvd_enc_create(void) +{ + enc.width = 160; + enc.height = 128; + + num_resources = 0; + alloc_resource(&enc.session, 128 * 1024, AMDGPU_GEM_DOMAIN_GTT); + resources[num_resources++] = enc.session.handle; + resources[num_resources++] = ib_handle; +} + +static void check_result(struct amdgpu_uvd_enc *enc) +{ + uint64_t sum; + uint32_t s = 175602; + uint32_t *ptr, size; + int j, r; + + r = amdgpu_bo_cpu_map(enc->fb.handle, (void **)&enc->fb.ptr); + CU_ASSERT_EQUAL(r, 0); + ptr = (uint32_t *)enc->fb.ptr; + size = ptr[6]; + r = amdgpu_bo_cpu_unmap(enc->fb.handle); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_bo_cpu_map(enc->bs.handle, (void **)&enc->bs.ptr); + CU_ASSERT_EQUAL(r, 0); + for (j = 0, sum = 0; j < size; ++j) + sum += enc->bs.ptr[j]; + CU_ASSERT_EQUAL(sum, s); + r = amdgpu_bo_cpu_unmap(enc->bs.handle); + CU_ASSERT_EQUAL(r, 0); + +} + +static void amdgpu_cs_uvd_enc_session_init(void) +{ + int len, r; + + len = 0; + memcpy((ib_cpu + len), uve_session_info, sizeof(uve_session_info)); + len += sizeof(uve_session_info) / 4; + ib_cpu[len++] = enc.session.addr >> 32; + ib_cpu[len++] = enc.session.addr; + + memcpy((ib_cpu + len), uve_task_info, sizeof(uve_task_info)); + len += sizeof(uve_task_info) / 4; + ib_cpu[len++] = 0x000000d8; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; + + memcpy((ib_cpu + len), uve_op_init, sizeof(uve_op_init)); + len += sizeof(uve_op_init) / 4; + + memcpy((ib_cpu + len), uve_session_init, sizeof(uve_session_init)); + len += sizeof(uve_session_init) / 4; + + memcpy((ib_cpu + len), uve_layer_ctrl, sizeof(uve_layer_ctrl)); + len += sizeof(uve_layer_ctrl) / 4; + + memcpy((ib_cpu + len), uve_slice_ctrl, sizeof(uve_slice_ctrl)); + len += sizeof(uve_slice_ctrl) / 4; + + memcpy((ib_cpu + len), uve_spec_misc, sizeof(uve_spec_misc)); + len += sizeof(uve_spec_misc) / 4; + + memcpy((ib_cpu + len), uve_rc_session_init, sizeof(uve_rc_session_init)); + len += sizeof(uve_rc_session_init) / 4; + + memcpy((ib_cpu + len), uve_deblocking_filter, sizeof(uve_deblocking_filter)); + len += sizeof(uve_deblocking_filter) / 4; + + memcpy((ib_cpu + len), uve_quality_params, sizeof(uve_quality_params)); + len += sizeof(uve_quality_params) / 4; + + memcpy((ib_cpu + len), uve_op_init_rc, sizeof(uve_op_init_rc)); + len += sizeof(uve_op_init_rc) / 4; + + memcpy((ib_cpu + len), uve_op_init_rc_vbv_level, sizeof(uve_op_init_rc_vbv_level)); + len += sizeof(uve_op_init_rc_vbv_level) / 4; + + r = submit(len, AMDGPU_HW_IP_UVD_ENC); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_cs_uvd_enc_encode(void) +{ + int len, r, i; + uint64_t luma_offset, chroma_offset; + uint32_t vbuf_size, bs_size = 0x003f4800, cpb_size; + unsigned align = (family_id >= AMDGPU_FAMILY_AI) ? 256 : 16; + vbuf_size = ALIGN(enc.width, align) * ALIGN(enc.height, 16) * 1.5; + cpb_size = vbuf_size * 10; + + + num_resources = 0; + alloc_resource(&enc.fb, 4096, AMDGPU_GEM_DOMAIN_VRAM); + resources[num_resources++] = enc.fb.handle; + alloc_resource(&enc.bs, bs_size, AMDGPU_GEM_DOMAIN_VRAM); + resources[num_resources++] = enc.bs.handle; + alloc_resource(&enc.vbuf, vbuf_size, AMDGPU_GEM_DOMAIN_VRAM); + resources[num_resources++] = enc.vbuf.handle; + alloc_resource(&enc.cpb, cpb_size, AMDGPU_GEM_DOMAIN_VRAM); + resources[num_resources++] = enc.cpb.handle; + resources[num_resources++] = ib_handle; + + r = amdgpu_bo_cpu_map(enc.vbuf.handle, (void **)&enc.vbuf.ptr); + CU_ASSERT_EQUAL(r, 0); + + memset(enc.vbuf.ptr, 0, vbuf_size); + for (i = 0; i < enc.height; ++i) { + memcpy(enc.vbuf.ptr, (frame + i * enc.width), enc.width); + enc.vbuf.ptr += ALIGN(enc.width, align); + } + for (i = 0; i < enc.height / 2; ++i) { + memcpy(enc.vbuf.ptr, ((frame + enc.height * enc.width) + i * enc.width), enc.width); + enc.vbuf.ptr += ALIGN(enc.width, align); + } + + r = amdgpu_bo_cpu_unmap(enc.vbuf.handle); + CU_ASSERT_EQUAL(r, 0); + + len = 0; + memcpy((ib_cpu + len), uve_session_info, sizeof(uve_session_info)); + len += sizeof(uve_session_info) / 4; + ib_cpu[len++] = enc.session.addr >> 32; + ib_cpu[len++] = enc.session.addr; + + memcpy((ib_cpu + len), uve_task_info, sizeof(uve_task_info)); + len += sizeof(uve_task_info) / 4; + ib_cpu[len++] = 0x000005e0; + ib_cpu[len++] = 0x00000001; + ib_cpu[len++] = 0x00000001; + + memcpy((ib_cpu + len), uve_nalu_buffer_1, sizeof(uve_nalu_buffer_1)); + len += sizeof(uve_nalu_buffer_1) / 4; + + memcpy((ib_cpu + len), uve_nalu_buffer_2, sizeof(uve_nalu_buffer_2)); + len += sizeof(uve_nalu_buffer_2) / 4; + + memcpy((ib_cpu + len), uve_nalu_buffer_3, sizeof(uve_nalu_buffer_3)); + len += sizeof(uve_nalu_buffer_3) / 4; + + memcpy((ib_cpu + len), uve_nalu_buffer_4, sizeof(uve_nalu_buffer_4)); + len += sizeof(uve_nalu_buffer_4) / 4; + + memcpy((ib_cpu + len), uve_slice_header, sizeof(uve_slice_header)); + len += sizeof(uve_slice_header) / 4; + + ib_cpu[len++] = 0x00000254; + ib_cpu[len++] = 0x00000010; + ib_cpu[len++] = enc.cpb.addr >> 32; + ib_cpu[len++] = enc.cpb.addr; + memcpy((ib_cpu + len), uve_ctx_buffer, sizeof(uve_ctx_buffer)); + len += sizeof(uve_ctx_buffer) / 4; + + memcpy((ib_cpu + len), uve_bitstream_buffer, sizeof(uve_bitstream_buffer)); + len += sizeof(uve_bitstream_buffer) / 4; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = enc.bs.addr >> 32; + ib_cpu[len++] = enc.bs.addr; + ib_cpu[len++] = 0x003f4800; + ib_cpu[len++] = 0x00000000; + + memcpy((ib_cpu + len), uve_feedback_buffer, sizeof(uve_feedback_buffer)); + len += sizeof(uve_feedback_buffer) / 4; + ib_cpu[len++] = enc.fb.addr >> 32; + ib_cpu[len++] = enc.fb.addr; + ib_cpu[len++] = 0x00000010; + ib_cpu[len++] = 0x00000028; + + memcpy((ib_cpu + len), uve_feedback_buffer_additional, sizeof(uve_feedback_buffer_additional)); + len += sizeof(uve_feedback_buffer_additional) / 4; + + memcpy((ib_cpu + len), uve_intra_refresh, sizeof(uve_intra_refresh)); + len += sizeof(uve_intra_refresh) / 4; + + memcpy((ib_cpu + len), uve_layer_select, sizeof(uve_layer_select)); + len += sizeof(uve_layer_select) / 4; + + memcpy((ib_cpu + len), uve_rc_layer_init, sizeof(uve_rc_layer_init)); + len += sizeof(uve_rc_layer_init) / 4; + + memcpy((ib_cpu + len), uve_layer_select, sizeof(uve_layer_select)); + len += sizeof(uve_layer_select) / 4; + + memcpy((ib_cpu + len), uve_rc_per_pic, sizeof(uve_rc_per_pic)); + len += sizeof(uve_rc_per_pic) / 4; + + unsigned luma_size = ALIGN(enc.width, align) * ALIGN(enc.height, 16); + luma_offset = enc.vbuf.addr; + chroma_offset = luma_offset + luma_size; + ib_cpu[len++] = 0x00000054; + ib_cpu[len++] = 0x0000000c; + ib_cpu[len++] = 0x00000002; + ib_cpu[len++] = 0x003f4800; + ib_cpu[len++] = luma_offset >> 32; + ib_cpu[len++] = luma_offset; + ib_cpu[len++] = chroma_offset >> 32; + ib_cpu[len++] = chroma_offset; + memcpy((ib_cpu + len), uve_encode_param, sizeof(uve_encode_param)); + ib_cpu[len] = ALIGN(enc.width, align); + ib_cpu[len + 1] = ALIGN(enc.width, align); + len += sizeof(uve_encode_param) / 4; + + memcpy((ib_cpu + len), uve_op_speed_enc_mode, sizeof(uve_op_speed_enc_mode)); + len += sizeof(uve_op_speed_enc_mode) / 4; + + memcpy((ib_cpu + len), uve_op_encode, sizeof(uve_op_encode)); + len += sizeof(uve_op_encode) / 4; + + r = submit(len, AMDGPU_HW_IP_UVD_ENC); + CU_ASSERT_EQUAL(r, 0); + + check_result(&enc); + + free_resource(&enc.fb); + free_resource(&enc.bs); + free_resource(&enc.vbuf); + free_resource(&enc.cpb); +} + +static void amdgpu_cs_uvd_enc_destroy(void) +{ + int len, r; + + num_resources = 0; + resources[num_resources++] = ib_handle; + + len = 0; + memcpy((ib_cpu + len), uve_session_info, sizeof(uve_session_info)); + len += sizeof(uve_session_info) / 4; + ib_cpu[len++] = enc.session.addr >> 32; + ib_cpu[len++] = enc.session.addr; + + memcpy((ib_cpu + len), uve_task_info, sizeof(uve_task_info)); + len += sizeof(uve_task_info) / 4; + ib_cpu[len++] = 0xffffffff; + ib_cpu[len++] = 0x00000002; + ib_cpu[len++] = 0x00000000; + + memcpy((ib_cpu + len), uve_op_close, sizeof(uve_op_close)); + len += sizeof(uve_op_close) / 4; + + r = submit(len, AMDGPU_HW_IP_UVD_ENC); + CU_ASSERT_EQUAL(r, 0); + + free_resource(&enc.session); +} diff --git a/tests/amdgpu/uve_ib.h b/tests/amdgpu/uve_ib.h new file mode 100644 index 0000000..cb72be2 --- /dev/null +++ b/tests/amdgpu/uve_ib.h @@ -0,0 +1,527 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 _uve_ib_h_ +#define _uve_ib_h_ + +static const uint32_t uve_session_info[] = { + 0x00000018, + 0x00000001, + 0x00000000, + 0x00010000, +}; + +static const uint32_t uve_task_info[] = { + 0x00000014, + 0x00000002, +}; + +static const uint32_t uve_session_init[] = { + 0x00000020, + 0x00000003, + 0x000000c0, + 0x00000080, + 0x00000020, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const uint32_t uve_layer_ctrl[] = { + 0x00000010, + 0x00000004, + 0x00000001, + 0x00000001, +}; + +static const uint32_t uve_layer_select[] = { + 0x0000000c, + 0x00000005, + 0x00000000, +}; + +static const uint32_t uve_slice_ctrl[] = { + 0x00000014, + 0x00000006, + 0x00000000, + 0x00000006, + 0x00000006, +}; + +static const uint32_t uve_spec_misc[] = { + 0x00000024, + 0x00000007, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000001, + 0x00000001, +}; + +static const uint32_t uve_rc_session_init[] = { + 0x00000010, + 0x00000008, + 0x00000000, + 0x00000040, +}; + +static const uint32_t uve_rc_layer_init[] = { + 0x00000028, + 0x00000009, + 0x001e8480, + 0x001e8480, + 0x0000001e, + 0x00000001, + 0x0001046a, + 0x0001046a, + 0x0001046a, + 0xaaaaaaaa, +}; + +static const uint32_t uve_deblocking_filter[] = { + 0x00000020, + 0x0000000e, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const uint32_t uve_quality_params[] = { + 0x00000014, + 0x0000000d, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const uint32_t uve_feedback_buffer[] = { + 0x0000001c, + 0x00000012, + 0x00000000, +}; + +static const uint32_t uve_feedback_buffer_additional[] = { + 0x00000108, + 0x00000014, + 0x00000001, + 0x00000010, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const uint32_t uve_nalu_buffer_1[] = { + 0x00000018, + 0x00000013, + 0x00000001, + 0x00000007, + 0x00000001, + 0x46011000, +}; + +static const uint32_t uve_nalu_buffer_2[] = { + 0x0000002c, + 0x00000013, + 0x00000002, + 0x0000001b, + 0x00000001, + 0x40010c01, + 0xffff0160, + 0x00000300, + 0xb0000003, + 0x00000300, + 0x962c0900, +}; + +static const uint32_t uve_nalu_buffer_3[] = { + 0x00000034, + 0x00000013, + 0x00000003, + 0x00000023, + 0x00000001, + 0x42010101, + 0x60000003, + 0x00b00000, + 0x03000003, + 0x0096a018, + 0x2020708f, + 0xcb924295, + 0x12e08000, +}; + +static const uint32_t uve_nalu_buffer_4[] = { + 0x0000001c, + 0x00000013, + 0x00000004, + 0x0000000b, + 0x00000001, + 0x4401e0f1, + 0x80992000, +}; + +static const uint32_t uve_slice_header[] = { + 0x000000c8, + 0x0000000b, + 0x28010000, + 0x40000000, + 0x60000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000002, + 0x00000010, + 0x00000003, + 0x00000000, + 0x00000002, + 0x00000002, + 0x00000004, + 0x00000000, + 0x00000001, + 0x00000000, + 0x00000002, + 0x00000003, + 0x00000005, + 0x00000000, + 0x00000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const uint32_t uve_encode_param[] = { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xffffffff, + 0x00000001, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const uint32_t uve_intra_refresh[] = { + 0x00000014, + 0x0000000f, + 0x00000000, + 0x00000000, + 0x00000001, +}; + +static const uint32_t uve_ctx_buffer[] = { + 0x00000000, + 0x00000000, + 0x000000a0, + 0x000000a0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const uint32_t uve_bitstream_buffer[] = { + 0x0000001c, + 0x00000011, +}; + +static const uint32_t uve_rc_per_pic[] = { + 0x00000024, + 0x0000000a, + 0x0000001a, + 0x00000000, + 0x00000033, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000001, +}; + +static const uint32_t uve_op_init[] = { + 0x00000008, + 0x08000001, +}; + +static const uint32_t uve_op_close[] = { + 0x00000008, + 0x08000002, +}; + +static const uint32_t uve_op_encode[] = { + 0x00000008, + 0x08000003, +}; + +static const uint32_t uve_op_init_rc[] = { + 0x00000008, + 0x08000004, +}; + +static const uint32_t uve_op_init_rc_vbv_level[] = { + 0x00000008, + 0x08000005, +}; + +static const uint32_t uve_op_speed_enc_mode[] = { + 0x00000008, + 0x08000006, +}; + +static const uint32_t uve_op_balance_enc_mode[] = { + 0x00000008, + 0x08000007, +}; + +static const uint32_t uve_op_quality_enc_mode[] = { + 0x00000008, + 0x08000008, +}; +#endif /*_uve_ib_h*/ diff --git a/tests/amdgpu/vce_ib.h b/tests/amdgpu/vce_ib.h new file mode 100644 index 0000000..f3108a0 --- /dev/null +++ b/tests/amdgpu/vce_ib.h @@ -0,0 +1,335 @@ +/* + * Copyright 2015 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 _vce_ib_h_ +#define _vce_ib_h_ + +static const uint32_t vce_session[] = { + 0x0000000c, + 0x00000001, + 0x400c0001, +}; + +static uint32_t vce_taskinfo[8] = { + 0x00000020, + 0x00000002, + 0xffffffff, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const uint32_t vce_create[] = { + 0x00000030, + 0x01000001, + 0x00000000, + 0x00000042, + 0x0000002a, + 0x00000000, + 0x000000a0, + 0x00000080, + 0x000000a0, + 0x000000a0, + 0x00000010, + 0x00000201, +}; + +static const uint32_t vce_rate_ctrl[] = { + 0x00000070, + 0x04000005, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x0000001c, + 0x0000001c, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000033, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const uint32_t vce_config_ext[] = { + 0x0000000c, + 0x04000001, + 0x00000003, +}; + +static const uint32_t vce_motion_est[] = { + 0x00000068, + 0x04000007, + 0x00000001, + 0x00000001, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000010, + 0x00000010, + 0x00000010, + 0x00000010, + 0x00000000, + 0x00000000, + 0x00000000, + 0x000000fe, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000001, + 0x00000001, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const uint32_t vce_rdo[] = { + 0x0000004c, + 0x04000008, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const uint32_t vce_pic_ctrl[] = { + 0x00000074, + 0x04000002, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000aa0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000040, + 0x00000000, + 0x00000000, + 0x00000001, + 0x00000002, + 0x00000001, + 0x00000001, + 0x00000000, + 0x00000000, +}; + +static const uint32_t vce_feedback[] = { + 0x00000014, + 0x05000005, + 0x00000000, + 0xffffffff, + 0x00000001, +}; + +static const uint32_t vce_context_buffer[] = { + 0x00000010, + 0x05000001, + 0x00000000, + 0xffffffff, +}; + +static const uint32_t vce_bs_buffer[] = { + 0x00000014, + 0x05000004, + 0x00000000, + 0xffffffff, + 0x00154000, +}; + +static const uint32_t vce_aux_buffer[] = { + 0x00000048, + 0x05000002, + 0x0000f000, + 0x00016800, + 0x0001e000, + 0x00025800, + 0x0002d000, + 0x00034800, + 0x0003c000, + 0x00043800, + 0x00007800, + 0x00007800, + 0x00007800, + 0x00007800, + 0x00007800, + 0x00007800, + 0x00007800, + 0x00007800, +}; + +static uint32_t vce_encode[88] = { + 0x00000160, + 0x03000001, + 0x00000011, + 0x00000000, + 0x00154000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xffffffff, + 0x00000000, + 0xffffffff, + 0x00000080, + 0x000000a0, + 0x000000a0, + 0x00010000, + 0x00000000, + 0x00000003, + 0x00000001, + 0x00000000, + 0x00000000, + 0x00000001, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xffffffff, + 0xffffffff, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xffffffff, + 0xffffffff, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0xffffffff, + 0xffffffff, + 0xffffffff, + 0xffffffff, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const uint32_t vce_destroy[] = { + 0x00000008, + 0x02000001, +}; + +static const uint32_t vce_mv_buffer[] = { + 0x00000038, + 0x0500000d, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; +#endif /*_vce_ib_h*/ diff --git a/tests/amdgpu/vce_tests.c b/tests/amdgpu/vce_tests.c new file mode 100644 index 0000000..9aa0a8e --- /dev/null +++ b/tests/amdgpu/vce_tests.c @@ -0,0 +1,764 @@ +/* + * Copyright 2015 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * +*/ + +#include +#include + +#include "CUnit/Basic.h" + +#include "util_math.h" + +#include "amdgpu_test.h" +#include "amdgpu_drm.h" +#include "amdgpu_internal.h" + +#include "vce_ib.h" +#include "frame.h" + +#define IB_SIZE 4096 +#define MAX_RESOURCES 16 +#define FW_53_0_03 ((53 << 24) | (0 << 16) | (03 << 8)) + +struct amdgpu_vce_bo { + amdgpu_bo_handle handle; + amdgpu_va_handle va_handle; + uint64_t addr; + uint64_t size; + uint8_t *ptr; +}; + +struct amdgpu_vce_encode { + unsigned width; + unsigned height; + struct amdgpu_vce_bo vbuf; + struct amdgpu_vce_bo bs[2]; + struct amdgpu_vce_bo fb[2]; + struct amdgpu_vce_bo cpb; + unsigned ib_len; + bool two_instance; + struct amdgpu_vce_bo mvrefbuf; + struct amdgpu_vce_bo mvb; + unsigned mvbuf_size; +}; + +static amdgpu_device_handle device_handle; +static uint32_t major_version; +static uint32_t minor_version; +static uint32_t family_id; +static uint32_t vce_harvest_config; +static uint32_t chip_rev; +static uint32_t chip_id; +static uint32_t ids_flags; +static bool is_mv_supported = true; + +static amdgpu_context_handle context_handle; +static amdgpu_bo_handle ib_handle; +static amdgpu_va_handle ib_va_handle; +static uint64_t ib_mc_address; +static uint32_t *ib_cpu; + +static struct amdgpu_vce_encode enc; +static amdgpu_bo_handle resources[MAX_RESOURCES]; +static unsigned num_resources; + +static void amdgpu_cs_vce_create(void); +static void amdgpu_cs_vce_encode(void); +static void amdgpu_cs_vce_encode_mv(void); +static void amdgpu_cs_vce_destroy(void); + +CU_TestInfo vce_tests[] = { + { "VCE create", amdgpu_cs_vce_create }, + { "VCE encode", amdgpu_cs_vce_encode }, + { "VCE MV dump", amdgpu_cs_vce_encode_mv }, + { "VCE destroy", amdgpu_cs_vce_destroy }, + CU_TEST_INFO_NULL, +}; + +CU_BOOL suite_vce_tests_enable(void) +{ + uint32_t version, feature; + CU_BOOL ret_mv = CU_FALSE; + + if (amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle)) + return CU_FALSE; + + family_id = device_handle->info.family_id; + chip_rev = device_handle->info.chip_rev; + chip_id = device_handle->info.chip_external_rev; + ids_flags = device_handle->info.ids_flags; + + amdgpu_query_firmware_version(device_handle, AMDGPU_INFO_FW_VCE, 0, + 0, &version, &feature); + + if (amdgpu_device_deinitialize(device_handle)) + return CU_FALSE; + + if (family_id >= AMDGPU_FAMILY_RV || family_id == AMDGPU_FAMILY_SI || + asic_is_gfx_pipe_removed(family_id, chip_id, chip_rev)) { + printf("\n\nThe ASIC NOT support VCE, suite disabled\n"); + return CU_FALSE; + } + + if (!(chip_id == (chip_rev + 0x3C) || /* FIJI */ + chip_id == (chip_rev + 0x50) || /* Polaris 10*/ + chip_id == (chip_rev + 0x5A) || /* Polaris 11*/ + chip_id == (chip_rev + 0x64) || /* Polaris 12*/ + (family_id >= AMDGPU_FAMILY_AI && !ids_flags))) /* dGPU > Polaris */ + printf("\n\nThe ASIC NOT support VCE MV, suite disabled\n"); + else if (FW_53_0_03 > version) + printf("\n\nThe ASIC FW version NOT support VCE MV, suite disabled\n"); + else + ret_mv = CU_TRUE; + + if (ret_mv == CU_FALSE) { + amdgpu_set_test_active("VCE Tests", "VCE MV dump", ret_mv); + is_mv_supported = false; + } + + return CU_TRUE; +} + +int suite_vce_tests_init(void) +{ + int r; + + r = amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle); + if (r) { + if ((r == -EACCES) && (errno == EACCES)) + printf("\n\nError:%s. " + "Hint:Try to run this test program as root.", + strerror(errno)); + + return CUE_SINIT_FAILED; + } + + family_id = device_handle->info.family_id; + vce_harvest_config = device_handle->info.vce_harvest_config; + + r = amdgpu_cs_ctx_create(device_handle, &context_handle); + if (r) + return CUE_SINIT_FAILED; + + r = amdgpu_bo_alloc_and_map(device_handle, IB_SIZE, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, + &ib_handle, (void**)&ib_cpu, + &ib_mc_address, &ib_va_handle); + if (r) + return CUE_SINIT_FAILED; + + memset(&enc, 0, sizeof(struct amdgpu_vce_encode)); + + return CUE_SUCCESS; +} + +int suite_vce_tests_clean(void) +{ + int r; + + r = amdgpu_bo_unmap_and_free(ib_handle, ib_va_handle, + ib_mc_address, IB_SIZE); + if (r) + return CUE_SCLEAN_FAILED; + + r = amdgpu_cs_ctx_free(context_handle); + if (r) + return CUE_SCLEAN_FAILED; + + r = amdgpu_device_deinitialize(device_handle); + if (r) + return CUE_SCLEAN_FAILED; + + return CUE_SUCCESS; +} + +static int submit(unsigned ndw, unsigned ip) +{ + struct amdgpu_cs_request ibs_request = {0}; + struct amdgpu_cs_ib_info ib_info = {0}; + struct amdgpu_cs_fence fence_status = {0}; + uint32_t expired; + int r; + + ib_info.ib_mc_address = ib_mc_address; + ib_info.size = ndw; + + ibs_request.ip_type = ip; + + r = amdgpu_bo_list_create(device_handle, num_resources, resources, + NULL, &ibs_request.resources); + if (r) + return r; + + ibs_request.number_of_ibs = 1; + ibs_request.ibs = &ib_info; + ibs_request.fence_info.handle = NULL; + + r = amdgpu_cs_submit(context_handle, 0, &ibs_request, 1); + if (r) + return r; + + r = amdgpu_bo_list_destroy(ibs_request.resources); + if (r) + return r; + + fence_status.context = context_handle; + fence_status.ip_type = ip; + fence_status.fence = ibs_request.seq_no; + + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE, + 0, &expired); + if (r) + return r; + + return 0; +} + +static void alloc_resource(struct amdgpu_vce_bo *vce_bo, unsigned size, unsigned domain) +{ + struct amdgpu_bo_alloc_request req = {0}; + amdgpu_bo_handle buf_handle; + amdgpu_va_handle va_handle; + uint64_t va = 0; + int r; + + req.alloc_size = ALIGN(size, 4096); + req.preferred_heap = domain; + r = amdgpu_bo_alloc(device_handle, &req, &buf_handle); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_va_range_alloc(device_handle, + amdgpu_gpu_va_range_general, + req.alloc_size, 1, 0, &va, + &va_handle, 0); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_bo_va_op(buf_handle, 0, req.alloc_size, va, 0, + AMDGPU_VA_OP_MAP); + CU_ASSERT_EQUAL(r, 0); + vce_bo->addr = va; + vce_bo->handle = buf_handle; + vce_bo->size = req.alloc_size; + vce_bo->va_handle = va_handle; + r = amdgpu_bo_cpu_map(vce_bo->handle, (void **)&vce_bo->ptr); + CU_ASSERT_EQUAL(r, 0); + memset(vce_bo->ptr, 0, size); + r = amdgpu_bo_cpu_unmap(vce_bo->handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void free_resource(struct amdgpu_vce_bo *vce_bo) +{ + int r; + + r = amdgpu_bo_va_op(vce_bo->handle, 0, vce_bo->size, + vce_bo->addr, 0, AMDGPU_VA_OP_UNMAP); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_va_range_free(vce_bo->va_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_free(vce_bo->handle); + CU_ASSERT_EQUAL(r, 0); + memset(vce_bo, 0, sizeof(*vce_bo)); +} + +static void amdgpu_cs_vce_create(void) +{ + unsigned align = (family_id >= AMDGPU_FAMILY_AI) ? 256 : 16; + int len, r; + + enc.width = vce_create[6]; + enc.height = vce_create[7]; + + num_resources = 0; + alloc_resource(&enc.fb[0], 4096, AMDGPU_GEM_DOMAIN_GTT); + resources[num_resources++] = enc.fb[0].handle; + resources[num_resources++] = ib_handle; + + len = 0; + memcpy(ib_cpu, vce_session, sizeof(vce_session)); + len += sizeof(vce_session) / 4; + memcpy((ib_cpu + len), vce_taskinfo, sizeof(vce_taskinfo)); + len += sizeof(vce_taskinfo) / 4; + memcpy((ib_cpu + len), vce_create, sizeof(vce_create)); + ib_cpu[len + 8] = ALIGN(enc.width, align); + ib_cpu[len + 9] = ALIGN(enc.width, align); + if (is_mv_supported == true) {/* disableTwoInstance */ + if (family_id >= AMDGPU_FAMILY_AI) + ib_cpu[len + 11] = 0x01000001; + else + ib_cpu[len + 11] = 0x01000201; + } + len += sizeof(vce_create) / 4; + memcpy((ib_cpu + len), vce_feedback, sizeof(vce_feedback)); + ib_cpu[len + 2] = enc.fb[0].addr >> 32; + ib_cpu[len + 3] = enc.fb[0].addr; + len += sizeof(vce_feedback) / 4; + + r = submit(len, AMDGPU_HW_IP_VCE); + CU_ASSERT_EQUAL(r, 0); + + free_resource(&enc.fb[0]); +} + +static void amdgpu_cs_vce_config(void) +{ + int len = 0, r; + + memcpy((ib_cpu + len), vce_session, sizeof(vce_session)); + len += sizeof(vce_session) / 4; + memcpy((ib_cpu + len), vce_taskinfo, sizeof(vce_taskinfo)); + ib_cpu[len + 3] = 2; + ib_cpu[len + 6] = 0xffffffff; + len += sizeof(vce_taskinfo) / 4; + memcpy((ib_cpu + len), vce_rate_ctrl, sizeof(vce_rate_ctrl)); + len += sizeof(vce_rate_ctrl) / 4; + memcpy((ib_cpu + len), vce_config_ext, sizeof(vce_config_ext)); + len += sizeof(vce_config_ext) / 4; + memcpy((ib_cpu + len), vce_motion_est, sizeof(vce_motion_est)); + len += sizeof(vce_motion_est) / 4; + memcpy((ib_cpu + len), vce_rdo, sizeof(vce_rdo)); + len += sizeof(vce_rdo) / 4; + memcpy((ib_cpu + len), vce_pic_ctrl, sizeof(vce_pic_ctrl)); + if (is_mv_supported == true) + ib_cpu[len + 27] = 0x00000001; /* encSliceMode */ + len += sizeof(vce_pic_ctrl) / 4; + + r = submit(len, AMDGPU_HW_IP_VCE); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_cs_vce_encode_idr(struct amdgpu_vce_encode *enc) +{ + + uint64_t luma_offset, chroma_offset; + unsigned align = (family_id >= AMDGPU_FAMILY_AI) ? 256 : 16; + unsigned luma_size = ALIGN(enc->width, align) * ALIGN(enc->height, 16); + int len = 0, i, r; + + luma_offset = enc->vbuf.addr; + chroma_offset = luma_offset + luma_size; + + memcpy((ib_cpu + len), vce_session, sizeof(vce_session)); + len += sizeof(vce_session) / 4; + memcpy((ib_cpu + len), vce_taskinfo, sizeof(vce_taskinfo)); + len += sizeof(vce_taskinfo) / 4; + memcpy((ib_cpu + len), vce_bs_buffer, sizeof(vce_bs_buffer)); + ib_cpu[len + 2] = enc->bs[0].addr >> 32; + ib_cpu[len + 3] = enc->bs[0].addr; + len += sizeof(vce_bs_buffer) / 4; + memcpy((ib_cpu + len), vce_context_buffer, sizeof(vce_context_buffer)); + ib_cpu[len + 2] = enc->cpb.addr >> 32; + ib_cpu[len + 3] = enc->cpb.addr; + len += sizeof(vce_context_buffer) / 4; + memcpy((ib_cpu + len), vce_aux_buffer, sizeof(vce_aux_buffer)); + for (i = 0; i < 8; ++i) + ib_cpu[len + 2 + i] = luma_size * 1.5 * (i + 2); + for (i = 0; i < 8; ++i) + ib_cpu[len + 10 + i] = luma_size * 1.5; + len += sizeof(vce_aux_buffer) / 4; + memcpy((ib_cpu + len), vce_feedback, sizeof(vce_feedback)); + ib_cpu[len + 2] = enc->fb[0].addr >> 32; + ib_cpu[len + 3] = enc->fb[0].addr; + len += sizeof(vce_feedback) / 4; + memcpy((ib_cpu + len), vce_encode, sizeof(vce_encode)); + ib_cpu[len + 9] = luma_offset >> 32; + ib_cpu[len + 10] = luma_offset; + ib_cpu[len + 11] = chroma_offset >> 32; + ib_cpu[len + 12] = chroma_offset; + ib_cpu[len + 14] = ALIGN(enc->width, align); + ib_cpu[len + 15] = ALIGN(enc->width, align); + ib_cpu[len + 73] = luma_size * 1.5; + ib_cpu[len + 74] = luma_size * 2.5; + len += sizeof(vce_encode) / 4; + enc->ib_len = len; + if (!enc->two_instance) { + r = submit(len, AMDGPU_HW_IP_VCE); + CU_ASSERT_EQUAL(r, 0); + } +} + +static void amdgpu_cs_vce_encode_p(struct amdgpu_vce_encode *enc) +{ + uint64_t luma_offset, chroma_offset; + int len, i, r; + unsigned align = (family_id >= AMDGPU_FAMILY_AI) ? 256 : 16; + unsigned luma_size = ALIGN(enc->width, align) * ALIGN(enc->height, 16); + + len = (enc->two_instance) ? enc->ib_len : 0; + luma_offset = enc->vbuf.addr; + chroma_offset = luma_offset + luma_size; + + if (!enc->two_instance) { + memcpy((ib_cpu + len), vce_session, sizeof(vce_session)); + len += sizeof(vce_session) / 4; + } + memcpy((ib_cpu + len), vce_taskinfo, sizeof(vce_taskinfo)); + len += sizeof(vce_taskinfo) / 4; + memcpy((ib_cpu + len), vce_bs_buffer, sizeof(vce_bs_buffer)); + ib_cpu[len + 2] = enc->bs[1].addr >> 32; + ib_cpu[len + 3] = enc->bs[1].addr; + len += sizeof(vce_bs_buffer) / 4; + memcpy((ib_cpu + len), vce_context_buffer, sizeof(vce_context_buffer)); + ib_cpu[len + 2] = enc->cpb.addr >> 32; + ib_cpu[len + 3] = enc->cpb.addr; + len += sizeof(vce_context_buffer) / 4; + memcpy((ib_cpu + len), vce_aux_buffer, sizeof(vce_aux_buffer)); + for (i = 0; i < 8; ++i) + ib_cpu[len + 2 + i] = luma_size * 1.5 * (i + 2); + for (i = 0; i < 8; ++i) + ib_cpu[len + 10 + i] = luma_size * 1.5; + len += sizeof(vce_aux_buffer) / 4; + memcpy((ib_cpu + len), vce_feedback, sizeof(vce_feedback)); + ib_cpu[len + 2] = enc->fb[1].addr >> 32; + ib_cpu[len + 3] = enc->fb[1].addr; + len += sizeof(vce_feedback) / 4; + memcpy((ib_cpu + len), vce_encode, sizeof(vce_encode)); + ib_cpu[len + 2] = 0; + ib_cpu[len + 9] = luma_offset >> 32; + ib_cpu[len + 10] = luma_offset; + ib_cpu[len + 11] = chroma_offset >> 32; + ib_cpu[len + 12] = chroma_offset; + ib_cpu[len + 14] = ALIGN(enc->width, align); + ib_cpu[len + 15] = ALIGN(enc->width, align); + ib_cpu[len + 18] = 0; + ib_cpu[len + 19] = 0; + ib_cpu[len + 56] = 3; + ib_cpu[len + 57] = 0; + ib_cpu[len + 58] = 0; + ib_cpu[len + 59] = luma_size * 1.5; + ib_cpu[len + 60] = luma_size * 2.5; + ib_cpu[len + 73] = 0; + ib_cpu[len + 74] = luma_size; + ib_cpu[len + 81] = 1; + ib_cpu[len + 82] = 1; + len += sizeof(vce_encode) / 4; + + r = submit(len, AMDGPU_HW_IP_VCE); + CU_ASSERT_EQUAL(r, 0); +} + +static void check_result(struct amdgpu_vce_encode *enc) +{ + uint64_t sum; + uint32_t s[2] = {180325, 15946}; + uint32_t *ptr, size; + int i, j, r; + + for (i = 0; i < 2; ++i) { + r = amdgpu_bo_cpu_map(enc->fb[i].handle, (void **)&enc->fb[i].ptr); + CU_ASSERT_EQUAL(r, 0); + ptr = (uint32_t *)enc->fb[i].ptr; + size = ptr[4] - ptr[9]; + r = amdgpu_bo_cpu_unmap(enc->fb[i].handle); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_bo_cpu_map(enc->bs[i].handle, (void **)&enc->bs[i].ptr); + CU_ASSERT_EQUAL(r, 0); + for (j = 0, sum = 0; j < size; ++j) + sum += enc->bs[i].ptr[j]; + CU_ASSERT_EQUAL(sum, s[i]); + r = amdgpu_bo_cpu_unmap(enc->bs[i].handle); + CU_ASSERT_EQUAL(r, 0); + } +} + +static void amdgpu_cs_vce_encode(void) +{ + uint32_t vbuf_size, bs_size = 0x154000, cpb_size; + unsigned align = (family_id >= AMDGPU_FAMILY_AI) ? 256 : 16; + int i, r; + + vbuf_size = ALIGN(enc.width, align) * ALIGN(enc.height, 16) * 1.5; + cpb_size = vbuf_size * 10; + num_resources = 0; + alloc_resource(&enc.fb[0], 4096, AMDGPU_GEM_DOMAIN_GTT); + resources[num_resources++] = enc.fb[0].handle; + alloc_resource(&enc.fb[1], 4096, AMDGPU_GEM_DOMAIN_GTT); + resources[num_resources++] = enc.fb[1].handle; + alloc_resource(&enc.bs[0], bs_size, AMDGPU_GEM_DOMAIN_GTT); + resources[num_resources++] = enc.bs[0].handle; + alloc_resource(&enc.bs[1], bs_size, AMDGPU_GEM_DOMAIN_GTT); + resources[num_resources++] = enc.bs[1].handle; + alloc_resource(&enc.vbuf, vbuf_size, AMDGPU_GEM_DOMAIN_VRAM); + resources[num_resources++] = enc.vbuf.handle; + alloc_resource(&enc.cpb, cpb_size, AMDGPU_GEM_DOMAIN_VRAM); + resources[num_resources++] = enc.cpb.handle; + resources[num_resources++] = ib_handle; + + r = amdgpu_bo_cpu_map(enc.vbuf.handle, (void **)&enc.vbuf.ptr); + CU_ASSERT_EQUAL(r, 0); + + memset(enc.vbuf.ptr, 0, vbuf_size); + for (i = 0; i < enc.height; ++i) { + memcpy(enc.vbuf.ptr, (frame + i * enc.width), enc.width); + enc.vbuf.ptr += ALIGN(enc.width, align); + } + for (i = 0; i < enc.height / 2; ++i) { + memcpy(enc.vbuf.ptr, ((frame + enc.height * enc.width) + i * enc.width), enc.width); + enc.vbuf.ptr += ALIGN(enc.width, align); + } + + r = amdgpu_bo_cpu_unmap(enc.vbuf.handle); + CU_ASSERT_EQUAL(r, 0); + + amdgpu_cs_vce_config(); + + if (family_id >= AMDGPU_FAMILY_VI) { + vce_taskinfo[3] = 3; + amdgpu_cs_vce_encode_idr(&enc); + amdgpu_cs_vce_encode_p(&enc); + check_result(&enc); + + /* two pipes */ + vce_encode[16] = 0; + amdgpu_cs_vce_encode_idr(&enc); + amdgpu_cs_vce_encode_p(&enc); + check_result(&enc); + + /* two instances */ + if (vce_harvest_config == 0) { + enc.two_instance = true; + vce_taskinfo[2] = 0x83; + vce_taskinfo[4] = 1; + amdgpu_cs_vce_encode_idr(&enc); + vce_taskinfo[2] = 0xffffffff; + vce_taskinfo[4] = 2; + amdgpu_cs_vce_encode_p(&enc); + check_result(&enc); + } + } else { + vce_taskinfo[3] = 3; + vce_encode[16] = 0; + amdgpu_cs_vce_encode_idr(&enc); + amdgpu_cs_vce_encode_p(&enc); + check_result(&enc); + } + + free_resource(&enc.fb[0]); + free_resource(&enc.fb[1]); + free_resource(&enc.bs[0]); + free_resource(&enc.bs[1]); + free_resource(&enc.vbuf); + free_resource(&enc.cpb); +} + +static void amdgpu_cs_vce_mv(struct amdgpu_vce_encode *enc) +{ + uint64_t luma_offset, chroma_offset; + uint64_t mv_ref_luma_offset; + unsigned align = (family_id >= AMDGPU_FAMILY_AI) ? 256 : 16; + unsigned luma_size = ALIGN(enc->width, align) * ALIGN(enc->height, 16); + int len = 0, i, r; + + luma_offset = enc->vbuf.addr; + chroma_offset = luma_offset + luma_size; + mv_ref_luma_offset = enc->mvrefbuf.addr; + + memcpy((ib_cpu + len), vce_session, sizeof(vce_session)); + len += sizeof(vce_session) / 4; + memcpy((ib_cpu + len), vce_taskinfo, sizeof(vce_taskinfo)); + len += sizeof(vce_taskinfo) / 4; + memcpy((ib_cpu + len), vce_bs_buffer, sizeof(vce_bs_buffer)); + ib_cpu[len + 2] = enc->bs[0].addr >> 32; + ib_cpu[len + 3] = enc->bs[0].addr; + len += sizeof(vce_bs_buffer) / 4; + memcpy((ib_cpu + len), vce_context_buffer, sizeof(vce_context_buffer)); + ib_cpu[len + 2] = enc->cpb.addr >> 32; + ib_cpu[len + 3] = enc->cpb.addr; + len += sizeof(vce_context_buffer) / 4; + memcpy((ib_cpu + len), vce_aux_buffer, sizeof(vce_aux_buffer)); + for (i = 0; i < 8; ++i) + ib_cpu[len + 2 + i] = luma_size * 1.5 * (i + 2); + for (i = 0; i < 8; ++i) + ib_cpu[len + 10 + i] = luma_size * 1.5; + len += sizeof(vce_aux_buffer) / 4; + memcpy((ib_cpu + len), vce_feedback, sizeof(vce_feedback)); + ib_cpu[len + 2] = enc->fb[0].addr >> 32; + ib_cpu[len + 3] = enc->fb[0].addr; + len += sizeof(vce_feedback) / 4; + memcpy((ib_cpu + len), vce_mv_buffer, sizeof(vce_mv_buffer)); + ib_cpu[len + 2] = mv_ref_luma_offset >> 32; + ib_cpu[len + 3] = mv_ref_luma_offset; + ib_cpu[len + 4] = ALIGN(enc->width, align); + ib_cpu[len + 5] = ALIGN(enc->width, align); + ib_cpu[len + 6] = luma_size; + ib_cpu[len + 7] = enc->mvb.addr >> 32; + ib_cpu[len + 8] = enc->mvb.addr; + len += sizeof(vce_mv_buffer) / 4; + memcpy((ib_cpu + len), vce_encode, sizeof(vce_encode)); + ib_cpu[len + 2] = 0; + ib_cpu[len + 3] = 0; + ib_cpu[len + 4] = 0x154000; + ib_cpu[len + 9] = luma_offset >> 32; + ib_cpu[len + 10] = luma_offset; + ib_cpu[len + 11] = chroma_offset >> 32; + ib_cpu[len + 12] = chroma_offset; + ib_cpu[len + 13] = ALIGN(enc->height, 16);; + ib_cpu[len + 14] = ALIGN(enc->width, align); + ib_cpu[len + 15] = ALIGN(enc->width, align); + /* encDisableMBOffloading-encDisableTwoPipeMode-encInputPicArrayMode-encInputPicAddrMode */ + ib_cpu[len + 16] = 0x01010000; + ib_cpu[len + 18] = 0; /* encPicType */ + ib_cpu[len + 19] = 0; /* encIdrFlag */ + ib_cpu[len + 20] = 0; /* encIdrPicId */ + ib_cpu[len + 21] = 0; /* encMGSKeyPic */ + ib_cpu[len + 22] = 0; /* encReferenceFlag */ + ib_cpu[len + 23] = 0; /* encTemporalLayerIndex */ + ib_cpu[len + 55] = 0; /* pictureStructure */ + ib_cpu[len + 56] = 0; /* encPicType -ref[0] */ + ib_cpu[len + 61] = 0; /* pictureStructure */ + ib_cpu[len + 62] = 0; /* encPicType -ref[1] */ + ib_cpu[len + 67] = 0; /* pictureStructure */ + ib_cpu[len + 68] = 0; /* encPicType -ref1 */ + ib_cpu[len + 81] = 1; /* frameNumber */ + ib_cpu[len + 82] = 2; /* pictureOrderCount */ + ib_cpu[len + 83] = 0xffffffff; /* numIPicRemainInRCGOP */ + ib_cpu[len + 84] = 0xffffffff; /* numPPicRemainInRCGOP */ + ib_cpu[len + 85] = 0xffffffff; /* numBPicRemainInRCGOP */ + ib_cpu[len + 86] = 0xffffffff; /* numIRPicRemainInRCGOP */ + ib_cpu[len + 87] = 0; /* remainedIntraRefreshPictures */ + len += sizeof(vce_encode) / 4; + + enc->ib_len = len; + r = submit(len, AMDGPU_HW_IP_VCE); + CU_ASSERT_EQUAL(r, 0); +} + +static void check_mv_result(struct amdgpu_vce_encode *enc) +{ + uint64_t sum; + uint32_t s = 140790; + int j, r; + + r = amdgpu_bo_cpu_map(enc->fb[0].handle, (void **)&enc->fb[0].ptr); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_bo_cpu_unmap(enc->fb[0].handle); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_bo_cpu_map(enc->mvb.handle, (void **)&enc->mvb.ptr); + CU_ASSERT_EQUAL(r, 0); + for (j = 0, sum = 0; j < enc->mvbuf_size; ++j) + sum += enc->mvb.ptr[j]; + CU_ASSERT_EQUAL(sum, s); + r = amdgpu_bo_cpu_unmap(enc->mvb.handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_cs_vce_encode_mv(void) +{ + uint32_t vbuf_size, bs_size = 0x154000, cpb_size; + unsigned align = (family_id >= AMDGPU_FAMILY_AI) ? 256 : 16; + int i, r; + + vbuf_size = ALIGN(enc.width, align) * ALIGN(enc.height, 16) * 1.5; + enc.mvbuf_size = ALIGN(enc.width, 16) * ALIGN(enc.height, 16) / 8; + cpb_size = vbuf_size * 10; + num_resources = 0; + alloc_resource(&enc.fb[0], 4096, AMDGPU_GEM_DOMAIN_GTT); + resources[num_resources++] = enc.fb[0].handle; + alloc_resource(&enc.bs[0], bs_size, AMDGPU_GEM_DOMAIN_GTT); + resources[num_resources++] = enc.bs[0].handle; + alloc_resource(&enc.mvb, enc.mvbuf_size, AMDGPU_GEM_DOMAIN_GTT); + resources[num_resources++] = enc.mvb.handle; + alloc_resource(&enc.vbuf, vbuf_size, AMDGPU_GEM_DOMAIN_VRAM); + resources[num_resources++] = enc.vbuf.handle; + alloc_resource(&enc.mvrefbuf, vbuf_size, AMDGPU_GEM_DOMAIN_VRAM); + resources[num_resources++] = enc.mvrefbuf.handle; + alloc_resource(&enc.cpb, cpb_size, AMDGPU_GEM_DOMAIN_VRAM); + resources[num_resources++] = enc.cpb.handle; + resources[num_resources++] = ib_handle; + + r = amdgpu_bo_cpu_map(enc.vbuf.handle, (void **)&enc.vbuf.ptr); + CU_ASSERT_EQUAL(r, 0); + + memset(enc.vbuf.ptr, 0, vbuf_size); + for (i = 0; i < enc.height; ++i) { + memcpy(enc.vbuf.ptr, (frame + i * enc.width), enc.width); + enc.vbuf.ptr += ALIGN(enc.width, align); + } + for (i = 0; i < enc.height / 2; ++i) { + memcpy(enc.vbuf.ptr, ((frame + enc.height * enc.width) + i * enc.width), enc.width); + enc.vbuf.ptr += ALIGN(enc.width, align); + } + + r = amdgpu_bo_cpu_unmap(enc.vbuf.handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_cpu_map(enc.mvrefbuf.handle, (void **)&enc.mvrefbuf.ptr); + CU_ASSERT_EQUAL(r, 0); + + memset(enc.mvrefbuf.ptr, 0, vbuf_size); + for (i = 0; i < enc.height; ++i) { + memcpy(enc.mvrefbuf.ptr, (frame + (enc.height - i -1) * enc.width), enc.width); + enc.mvrefbuf.ptr += ALIGN(enc.width, align); + } + for (i = 0; i < enc.height / 2; ++i) { + memcpy(enc.mvrefbuf.ptr, + ((frame + enc.height * enc.width) + (enc.height / 2 - i -1) * enc.width), enc.width); + enc.mvrefbuf.ptr += ALIGN(enc.width, align); + } + + r = amdgpu_bo_cpu_unmap(enc.mvrefbuf.handle); + CU_ASSERT_EQUAL(r, 0); + + amdgpu_cs_vce_config(); + + vce_taskinfo[3] = 3; + amdgpu_cs_vce_mv(&enc); + check_mv_result(&enc); + + free_resource(&enc.fb[0]); + free_resource(&enc.bs[0]); + free_resource(&enc.vbuf); + free_resource(&enc.cpb); + free_resource(&enc.mvrefbuf); + free_resource(&enc.mvb); +} + +static void amdgpu_cs_vce_destroy(void) +{ + int len, r; + + num_resources = 0; + alloc_resource(&enc.fb[0], 4096, AMDGPU_GEM_DOMAIN_GTT); + resources[num_resources++] = enc.fb[0].handle; + resources[num_resources++] = ib_handle; + + len = 0; + memcpy(ib_cpu, vce_session, sizeof(vce_session)); + len += sizeof(vce_session) / 4; + memcpy((ib_cpu + len), vce_taskinfo, sizeof(vce_taskinfo)); + ib_cpu[len + 3] = 1; + len += sizeof(vce_taskinfo) / 4; + memcpy((ib_cpu + len), vce_feedback, sizeof(vce_feedback)); + ib_cpu[len + 2] = enc.fb[0].addr >> 32; + ib_cpu[len + 3] = enc.fb[0].addr; + len += sizeof(vce_feedback) / 4; + memcpy((ib_cpu + len), vce_destroy, sizeof(vce_destroy)); + len += sizeof(vce_destroy) / 4; + + r = submit(len, AMDGPU_HW_IP_VCE); + CU_ASSERT_EQUAL(r, 0); + + free_resource(&enc.fb[0]); +} diff --git a/tests/amdgpu/vcn_tests.c b/tests/amdgpu/vcn_tests.c new file mode 100644 index 0000000..5e20fb6 --- /dev/null +++ b/tests/amdgpu/vcn_tests.c @@ -0,0 +1,1635 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * +*/ + +#include +#include +#include +#include + +#include "CUnit/Basic.h" + +#include +#include "util_math.h" + +#include "amdgpu_test.h" +#include "amdgpu_drm.h" +#include "amdgpu_internal.h" +#include "decode_messages.h" +#include "frame.h" + +#define IB_SIZE 4096 +#define MAX_RESOURCES 16 + +#define DECODE_CMD_MSG_BUFFER 0x00000000 +#define DECODE_CMD_DPB_BUFFER 0x00000001 +#define DECODE_CMD_DECODING_TARGET_BUFFER 0x00000002 +#define DECODE_CMD_FEEDBACK_BUFFER 0x00000003 +#define DECODE_CMD_PROB_TBL_BUFFER 0x00000004 +#define DECODE_CMD_SESSION_CONTEXT_BUFFER 0x00000005 +#define DECODE_CMD_BITSTREAM_BUFFER 0x00000100 +#define DECODE_CMD_IT_SCALING_TABLE_BUFFER 0x00000204 +#define DECODE_CMD_CONTEXT_BUFFER 0x00000206 + +#define DECODE_IB_PARAM_DECODE_BUFFER (0x00000001) + +#define DECODE_CMDBUF_FLAGS_MSG_BUFFER (0x00000001) +#define DECODE_CMDBUF_FLAGS_DPB_BUFFER (0x00000002) +#define DECODE_CMDBUF_FLAGS_BITSTREAM_BUFFER (0x00000004) +#define DECODE_CMDBUF_FLAGS_DECODING_TARGET_BUFFER (0x00000008) +#define DECODE_CMDBUF_FLAGS_FEEDBACK_BUFFER (0x00000010) +#define DECODE_CMDBUF_FLAGS_IT_SCALING_BUFFER (0x00000200) +#define DECODE_CMDBUF_FLAGS_CONTEXT_BUFFER (0x00000800) +#define DECODE_CMDBUF_FLAGS_PROB_TBL_BUFFER (0x00001000) +#define DECODE_CMDBUF_FLAGS_SESSION_CONTEXT_BUFFER (0x00100000) + +static bool vcn_dec_sw_ring = false; +static bool vcn_unified_ring = false; + +#define H264_NAL_TYPE_NON_IDR_SLICE 1 +#define H264_NAL_TYPE_DP_A_SLICE 2 +#define H264_NAL_TYPE_DP_B_SLICE 3 +#define H264_NAL_TYPE_DP_C_SLICE 0x4 +#define H264_NAL_TYPE_IDR_SLICE 0x5 +#define H264_NAL_TYPE_SEI 0x6 +#define H264_NAL_TYPE_SEQ_PARAM 0x7 +#define H264_NAL_TYPE_PIC_PARAM 0x8 +#define H264_NAL_TYPE_ACCESS_UNIT 0x9 +#define H264_NAL_TYPE_END_OF_SEQ 0xa +#define H264_NAL_TYPE_END_OF_STREAM 0xb +#define H264_NAL_TYPE_FILLER_DATA 0xc +#define H264_NAL_TYPE_SEQ_EXTENSION 0xd + +#define H264_START_CODE 0x000001 + +struct amdgpu_vcn_bo { + amdgpu_bo_handle handle; + amdgpu_va_handle va_handle; + uint64_t addr; + uint64_t size; + uint8_t *ptr; +}; + +typedef struct rvcn_decode_buffer_s { + unsigned int valid_buf_flag; + unsigned int msg_buffer_address_hi; + unsigned int msg_buffer_address_lo; + unsigned int dpb_buffer_address_hi; + unsigned int dpb_buffer_address_lo; + unsigned int target_buffer_address_hi; + unsigned int target_buffer_address_lo; + unsigned int session_contex_buffer_address_hi; + unsigned int session_contex_buffer_address_lo; + unsigned int bitstream_buffer_address_hi; + unsigned int bitstream_buffer_address_lo; + unsigned int context_buffer_address_hi; + unsigned int context_buffer_address_lo; + unsigned int feedback_buffer_address_hi; + unsigned int feedback_buffer_address_lo; + unsigned int luma_hist_buffer_address_hi; + unsigned int luma_hist_buffer_address_lo; + unsigned int prob_tbl_buffer_address_hi; + unsigned int prob_tbl_buffer_address_lo; + unsigned int sclr_coeff_buffer_address_hi; + unsigned int sclr_coeff_buffer_address_lo; + unsigned int it_sclr_table_buffer_address_hi; + unsigned int it_sclr_table_buffer_address_lo; + unsigned int sclr_target_buffer_address_hi; + unsigned int sclr_target_buffer_address_lo; + unsigned int cenc_size_info_buffer_address_hi; + unsigned int cenc_size_info_buffer_address_lo; + unsigned int mpeg2_pic_param_buffer_address_hi; + unsigned int mpeg2_pic_param_buffer_address_lo; + unsigned int mpeg2_mb_control_buffer_address_hi; + unsigned int mpeg2_mb_control_buffer_address_lo; + unsigned int mpeg2_idct_coeff_buffer_address_hi; + unsigned int mpeg2_idct_coeff_buffer_address_lo; +} rvcn_decode_buffer_t; + +typedef struct rvcn_decode_ib_package_s { + unsigned int package_size; + unsigned int package_type; +} rvcn_decode_ib_package_t; + + +struct amdgpu_vcn_reg { + uint32_t data0; + uint32_t data1; + uint32_t cmd; + uint32_t nop; + uint32_t cntl; +}; + +typedef struct BufferInfo_t { + uint32_t numOfBitsInBuffer; + const uint8_t *decBuffer; + uint8_t decData; + uint32_t decBufferSize; + const uint8_t *end; +} bufferInfo; + +typedef struct h264_decode_t { + uint8_t profile; + uint8_t level_idc; + uint8_t nal_ref_idc; + uint8_t nal_unit_type; + uint32_t pic_width, pic_height; + uint32_t slice_type; +} h264_decode; + +static amdgpu_device_handle device_handle; +static uint32_t major_version; +static uint32_t minor_version; +static uint32_t family_id; +static uint32_t chip_rev; +static uint32_t chip_id; +static uint32_t asic_id; +static uint32_t chip_rev; +static struct amdgpu_vcn_bo enc_buf; +static struct amdgpu_vcn_bo cpb_buf; +static uint32_t enc_task_id; + +static amdgpu_context_handle context_handle; +static amdgpu_bo_handle ib_handle; +static amdgpu_va_handle ib_va_handle; +static uint64_t ib_mc_address; +static uint32_t *ib_cpu; +static uint32_t *ib_checksum; +static uint32_t *ib_size_in_dw; + +static rvcn_decode_buffer_t *decode_buffer; + +static amdgpu_bo_handle resources[MAX_RESOURCES]; +static unsigned num_resources; + +static uint8_t vcn_reg_index; +static struct amdgpu_vcn_reg reg[] = { + {0x81c4, 0x81c5, 0x81c3, 0x81ff, 0x81c6}, + {0x504, 0x505, 0x503, 0x53f, 0x506}, + {0x10, 0x11, 0xf, 0x29, 0x26d}, +}; + +uint32_t gWidth, gHeight, gSliceType; +static uint32_t vcn_ip_version_major; +static uint32_t vcn_ip_version_minor; +static void amdgpu_cs_vcn_dec_create(void); +static void amdgpu_cs_vcn_dec_decode(void); +static void amdgpu_cs_vcn_dec_destroy(void); + +static void amdgpu_cs_vcn_enc_create(void); +static void amdgpu_cs_vcn_enc_encode(void); +static void amdgpu_cs_vcn_enc_destroy(void); + +static void amdgpu_cs_sq_head(uint32_t *base, int *offset, bool enc); +static void amdgpu_cs_sq_ib_tail(uint32_t *end); +static void h264_check_0s (bufferInfo * bufInfo, int count); +static int32_t h264_se (bufferInfo * bufInfo); +static inline uint32_t bs_read_u1(bufferInfo *bufinfo); +static inline int bs_eof(bufferInfo *bufinfo); +static inline uint32_t bs_read_u(bufferInfo* bufinfo, int n); +static inline uint32_t bs_read_ue(bufferInfo* bufinfo); +static uint32_t remove_03 (uint8_t *bptr, uint32_t len); +static void scaling_list (uint32_t ix, uint32_t sizeOfScalingList, bufferInfo *bufInfo); +static void h264_parse_sequence_parameter_set (h264_decode * dec, bufferInfo *bufInfo); +static void h264_slice_header (h264_decode *dec, bufferInfo *bufInfo); +static uint8_t h264_parse_nal (h264_decode *dec, bufferInfo *bufInfo); +static uint32_t h264_find_next_start_code (uint8_t *pBuf, uint32_t bufLen); +static int verify_checksum(uint8_t *buffer, uint32_t buffer_size); + +CU_TestInfo vcn_tests[] = { + + { "VCN DEC create", amdgpu_cs_vcn_dec_create }, + { "VCN DEC decode", amdgpu_cs_vcn_dec_decode }, + { "VCN DEC destroy", amdgpu_cs_vcn_dec_destroy }, + + { "VCN ENC create", amdgpu_cs_vcn_enc_create }, + { "VCN ENC encode", amdgpu_cs_vcn_enc_encode }, + { "VCN ENC destroy", amdgpu_cs_vcn_enc_destroy }, + CU_TEST_INFO_NULL, +}; + +CU_BOOL suite_vcn_tests_enable(void) +{ + struct drm_amdgpu_info_hw_ip info; + bool enc_ring, dec_ring; + int r; + + if (amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle)) + return CU_FALSE; + + family_id = device_handle->info.family_id; + asic_id = device_handle->info.asic_id; + chip_rev = device_handle->info.chip_rev; + chip_id = device_handle->info.chip_external_rev; + + r = amdgpu_query_hw_ip_info(device_handle, AMDGPU_HW_IP_VCN_ENC, 0, &info); + if (!r) { + vcn_ip_version_major = info.hw_ip_version_major; + vcn_ip_version_minor = info.hw_ip_version_minor; + enc_ring = !!info.available_rings; + /* in vcn 4.0 it re-uses encoding queue as unified queue */ + if (vcn_ip_version_major >= 4) { + vcn_unified_ring = true; + vcn_dec_sw_ring = true; + dec_ring = enc_ring; + } else { + r = amdgpu_query_hw_ip_info(device_handle, AMDGPU_HW_IP_VCN_DEC, 0, &info); + dec_ring = !!info.available_rings; + } + } + + if (amdgpu_device_deinitialize(device_handle)) + return CU_FALSE; + + if (r) { + printf("\n\nASIC query hw info failed\n"); + return CU_FALSE; + } + + if (!(dec_ring || enc_ring) || + (family_id < AMDGPU_FAMILY_RV && + (family_id == AMDGPU_FAMILY_AI && + (chip_id - chip_rev) < 0x32))) { /* Arcturus */ + printf("\n\nThe ASIC NOT support VCN, suite disabled\n"); + return CU_FALSE; + } + + if (!dec_ring) { + amdgpu_set_test_active("VCN Tests", "VCN DEC create", CU_FALSE); + amdgpu_set_test_active("VCN Tests", "VCN DEC decode", CU_FALSE); + amdgpu_set_test_active("VCN Tests", "VCN DEC destroy", CU_FALSE); + } + + if (family_id == AMDGPU_FAMILY_AI || !enc_ring) { + amdgpu_set_test_active("VCN Tests", "VCN ENC create", CU_FALSE); + amdgpu_set_test_active("VCN Tests", "VCN ENC encode", CU_FALSE); + amdgpu_set_test_active("VCN Tests", "VCN ENC destroy", CU_FALSE); + } + + if (vcn_ip_version_major == 1) + vcn_reg_index = 0; + else if (vcn_ip_version_major == 2 && vcn_ip_version_minor == 0) + vcn_reg_index = 1; + else if ((vcn_ip_version_major == 2 && vcn_ip_version_minor >= 5) || + vcn_ip_version_major == 3) + vcn_reg_index = 2; + + return CU_TRUE; +} + +int suite_vcn_tests_init(void) +{ + int r; + + r = amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle); + if (r) + return CUE_SINIT_FAILED; + + family_id = device_handle->info.family_id; + + r = amdgpu_cs_ctx_create(device_handle, &context_handle); + if (r) + return CUE_SINIT_FAILED; + + r = amdgpu_bo_alloc_and_map(device_handle, IB_SIZE, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, + &ib_handle, (void**)&ib_cpu, + &ib_mc_address, &ib_va_handle); + if (r) + return CUE_SINIT_FAILED; + + return CUE_SUCCESS; +} + +int suite_vcn_tests_clean(void) +{ + int r; + + r = amdgpu_bo_unmap_and_free(ib_handle, ib_va_handle, + ib_mc_address, IB_SIZE); + if (r) + return CUE_SCLEAN_FAILED; + + r = amdgpu_cs_ctx_free(context_handle); + if (r) + return CUE_SCLEAN_FAILED; + + r = amdgpu_device_deinitialize(device_handle); + if (r) + return CUE_SCLEAN_FAILED; + + return CUE_SUCCESS; +} + +static void amdgpu_cs_sq_head(uint32_t *base, int *offset, bool enc) +{ + /* signature */ + *(base + (*offset)++) = 0x00000010; + *(base + (*offset)++) = 0x30000002; + ib_checksum = base + (*offset)++; + ib_size_in_dw = base + (*offset)++; + + /* engine info */ + *(base + (*offset)++) = 0x00000010; + *(base + (*offset)++) = 0x30000001; + *(base + (*offset)++) = enc ? 2 : 3; + *(base + (*offset)++) = 0x00000000; +} + +static void amdgpu_cs_sq_ib_tail(uint32_t *end) +{ + uint32_t size_in_dw; + uint32_t checksum = 0; + + /* if the pointers are invalid, no need to process */ + if (ib_checksum == NULL || ib_size_in_dw == NULL) + return; + + size_in_dw = end - ib_size_in_dw - 1; + *ib_size_in_dw = size_in_dw; + *(ib_size_in_dw + 4) = size_in_dw * sizeof(uint32_t); + + for (int i = 0; i < size_in_dw; i++) + checksum += *(ib_checksum + 2 + i); + + *ib_checksum = checksum; + + ib_checksum = NULL; + ib_size_in_dw = NULL; +} + +static int submit(unsigned ndw, unsigned ip) +{ + struct amdgpu_cs_request ibs_request = {0}; + struct amdgpu_cs_ib_info ib_info = {0}; + struct amdgpu_cs_fence fence_status = {0}; + uint32_t expired; + int r; + + ib_info.ib_mc_address = ib_mc_address; + ib_info.size = ndw; + + ibs_request.ip_type = ip; + + r = amdgpu_bo_list_create(device_handle, num_resources, resources, + NULL, &ibs_request.resources); + if (r) + return r; + + ibs_request.number_of_ibs = 1; + ibs_request.ibs = &ib_info; + ibs_request.fence_info.handle = NULL; + + r = amdgpu_cs_submit(context_handle, 0, &ibs_request, 1); + if (r) + return r; + + r = amdgpu_bo_list_destroy(ibs_request.resources); + if (r) + return r; + + fence_status.context = context_handle; + fence_status.ip_type = ip; + fence_status.fence = ibs_request.seq_no; + + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE, + 0, &expired); + if (r) + return r; + + return 0; +} + +static void alloc_resource(struct amdgpu_vcn_bo *vcn_bo, + unsigned size, unsigned domain) +{ + struct amdgpu_bo_alloc_request req = {0}; + amdgpu_bo_handle buf_handle; + amdgpu_va_handle va_handle; + uint64_t va = 0; + int r; + + req.alloc_size = ALIGN(size, 4096); + req.preferred_heap = domain; + r = amdgpu_bo_alloc(device_handle, &req, &buf_handle); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_va_range_alloc(device_handle, + amdgpu_gpu_va_range_general, + req.alloc_size, 1, 0, &va, + &va_handle, 0); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_bo_va_op(buf_handle, 0, req.alloc_size, va, 0, + AMDGPU_VA_OP_MAP); + CU_ASSERT_EQUAL(r, 0); + vcn_bo->addr = va; + vcn_bo->handle = buf_handle; + vcn_bo->size = req.alloc_size; + vcn_bo->va_handle = va_handle; + r = amdgpu_bo_cpu_map(vcn_bo->handle, (void **)&vcn_bo->ptr); + CU_ASSERT_EQUAL(r, 0); + memset(vcn_bo->ptr, 0, size); + r = amdgpu_bo_cpu_unmap(vcn_bo->handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void free_resource(struct amdgpu_vcn_bo *vcn_bo) +{ + int r; + + r = amdgpu_bo_va_op(vcn_bo->handle, 0, vcn_bo->size, + vcn_bo->addr, 0, AMDGPU_VA_OP_UNMAP); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_va_range_free(vcn_bo->va_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_free(vcn_bo->handle); + CU_ASSERT_EQUAL(r, 0); + memset(vcn_bo, 0, sizeof(*vcn_bo)); +} + +static void vcn_dec_cmd(uint64_t addr, unsigned cmd, int *idx) +{ + if (vcn_dec_sw_ring == false) { + ib_cpu[(*idx)++] = reg[vcn_reg_index].data0; + ib_cpu[(*idx)++] = addr; + ib_cpu[(*idx)++] = reg[vcn_reg_index].data1; + ib_cpu[(*idx)++] = addr >> 32; + ib_cpu[(*idx)++] = reg[vcn_reg_index].cmd; + ib_cpu[(*idx)++] = cmd << 1; + return; + } + + /* Support decode software ring message */ + if (!(*idx)) { + rvcn_decode_ib_package_t *ib_header; + + if (vcn_unified_ring) + amdgpu_cs_sq_head(ib_cpu, idx, false); + + ib_header = (rvcn_decode_ib_package_t *)&ib_cpu[*idx]; + ib_header->package_size = sizeof(struct rvcn_decode_buffer_s) + + sizeof(struct rvcn_decode_ib_package_s); + + (*idx)++; + ib_header->package_type = (DECODE_IB_PARAM_DECODE_BUFFER); + (*idx)++; + + decode_buffer = (rvcn_decode_buffer_t *)&(ib_cpu[*idx]); + *idx += sizeof(struct rvcn_decode_buffer_s) / 4; + memset(decode_buffer, 0, sizeof(struct rvcn_decode_buffer_s)); + } + + switch(cmd) { + case DECODE_CMD_MSG_BUFFER: + decode_buffer->valid_buf_flag |= DECODE_CMDBUF_FLAGS_MSG_BUFFER; + decode_buffer->msg_buffer_address_hi = (addr >> 32); + decode_buffer->msg_buffer_address_lo = (addr); + break; + case DECODE_CMD_DPB_BUFFER: + decode_buffer->valid_buf_flag |= (DECODE_CMDBUF_FLAGS_DPB_BUFFER); + decode_buffer->dpb_buffer_address_hi = (addr >> 32); + decode_buffer->dpb_buffer_address_lo = (addr); + break; + case DECODE_CMD_DECODING_TARGET_BUFFER: + decode_buffer->valid_buf_flag |= (DECODE_CMDBUF_FLAGS_DECODING_TARGET_BUFFER); + decode_buffer->target_buffer_address_hi = (addr >> 32); + decode_buffer->target_buffer_address_lo = (addr); + break; + case DECODE_CMD_FEEDBACK_BUFFER: + decode_buffer->valid_buf_flag |= (DECODE_CMDBUF_FLAGS_FEEDBACK_BUFFER); + decode_buffer->feedback_buffer_address_hi = (addr >> 32); + decode_buffer->feedback_buffer_address_lo = (addr); + break; + case DECODE_CMD_PROB_TBL_BUFFER: + decode_buffer->valid_buf_flag |= (DECODE_CMDBUF_FLAGS_PROB_TBL_BUFFER); + decode_buffer->prob_tbl_buffer_address_hi = (addr >> 32); + decode_buffer->prob_tbl_buffer_address_lo = (addr); + break; + case DECODE_CMD_SESSION_CONTEXT_BUFFER: + decode_buffer->valid_buf_flag |= (DECODE_CMDBUF_FLAGS_SESSION_CONTEXT_BUFFER); + decode_buffer->session_contex_buffer_address_hi = (addr >> 32); + decode_buffer->session_contex_buffer_address_lo = (addr); + break; + case DECODE_CMD_BITSTREAM_BUFFER: + decode_buffer->valid_buf_flag |= (DECODE_CMDBUF_FLAGS_BITSTREAM_BUFFER); + decode_buffer->bitstream_buffer_address_hi = (addr >> 32); + decode_buffer->bitstream_buffer_address_lo = (addr); + break; + case DECODE_CMD_IT_SCALING_TABLE_BUFFER: + decode_buffer->valid_buf_flag |= (DECODE_CMDBUF_FLAGS_IT_SCALING_BUFFER); + decode_buffer->it_sclr_table_buffer_address_hi = (addr >> 32); + decode_buffer->it_sclr_table_buffer_address_lo = (addr); + break; + case DECODE_CMD_CONTEXT_BUFFER: + decode_buffer->valid_buf_flag |= (DECODE_CMDBUF_FLAGS_CONTEXT_BUFFER); + decode_buffer->context_buffer_address_hi = (addr >> 32); + decode_buffer->context_buffer_address_lo = (addr); + break; + default: + printf("Not Support!\n"); + } +} + +static void amdgpu_cs_vcn_dec_create(void) +{ + struct amdgpu_vcn_bo msg_buf; + unsigned ip; + int len, r; + + num_resources = 0; + alloc_resource(&msg_buf, 4096, AMDGPU_GEM_DOMAIN_GTT); + resources[num_resources++] = msg_buf.handle; + resources[num_resources++] = ib_handle; + + r = amdgpu_bo_cpu_map(msg_buf.handle, (void **)&msg_buf.ptr); + CU_ASSERT_EQUAL(r, 0); + + memset(msg_buf.ptr, 0, 4096); + memcpy(msg_buf.ptr, vcn_dec_create_msg, sizeof(vcn_dec_create_msg)); + + len = 0; + if (vcn_dec_sw_ring == true) + vcn_dec_cmd(msg_buf.addr, 0, &len); + else { + ib_cpu[len++] = reg[vcn_reg_index].data0; + ib_cpu[len++] = msg_buf.addr; + ib_cpu[len++] = reg[vcn_reg_index].data1; + ib_cpu[len++] = msg_buf.addr >> 32; + ib_cpu[len++] = reg[vcn_reg_index].cmd; + ib_cpu[len++] = 0; + for (; len % 16; ) { + ib_cpu[len++] = reg[vcn_reg_index].nop; + ib_cpu[len++] = 0; + } + } + + if (vcn_unified_ring) { + amdgpu_cs_sq_ib_tail(ib_cpu + len); + ip = AMDGPU_HW_IP_VCN_ENC; + } else + ip = AMDGPU_HW_IP_VCN_DEC; + + r = submit(len, ip); + + CU_ASSERT_EQUAL(r, 0); + + free_resource(&msg_buf); +} + +static void amdgpu_cs_vcn_dec_decode(void) +{ + const unsigned dpb_size = 15923584, dt_size = 737280; + uint64_t msg_addr, fb_addr, bs_addr, dpb_addr, ctx_addr, dt_addr, it_addr, sum; + struct amdgpu_vcn_bo dec_buf; + int size, len, i, r; + unsigned ip; + uint8_t *dec; + + size = 4*1024; /* msg */ + size += 4*1024; /* fb */ + size += 4096; /*it_scaling_table*/ + size += ALIGN(sizeof(uvd_bitstream), 4*1024); + size += ALIGN(dpb_size, 4*1024); + size += ALIGN(dt_size, 4*1024); + + num_resources = 0; + alloc_resource(&dec_buf, size, AMDGPU_GEM_DOMAIN_GTT); + resources[num_resources++] = dec_buf.handle; + resources[num_resources++] = ib_handle; + + r = amdgpu_bo_cpu_map(dec_buf.handle, (void **)&dec_buf.ptr); + dec = dec_buf.ptr; + + CU_ASSERT_EQUAL(r, 0); + memset(dec_buf.ptr, 0, size); + memcpy(dec_buf.ptr, vcn_dec_decode_msg, sizeof(vcn_dec_decode_msg)); + memcpy(dec_buf.ptr + sizeof(vcn_dec_decode_msg), + avc_decode_msg, sizeof(avc_decode_msg)); + + dec += 4*1024; + memcpy(dec, feedback_msg, sizeof(feedback_msg)); + dec += 4*1024; + memcpy(dec, uvd_it_scaling_table, sizeof(uvd_it_scaling_table)); + + dec += 4*1024; + memcpy(dec, uvd_bitstream, sizeof(uvd_bitstream)); + + dec += ALIGN(sizeof(uvd_bitstream), 4*1024); + + dec += ALIGN(dpb_size, 4*1024); + + msg_addr = dec_buf.addr; + fb_addr = msg_addr + 4*1024; + it_addr = fb_addr + 4*1024; + bs_addr = it_addr + 4*1024; + dpb_addr = ALIGN(bs_addr + sizeof(uvd_bitstream), 4*1024); + ctx_addr = ALIGN(dpb_addr + 0x006B9400, 4*1024); + dt_addr = ALIGN(dpb_addr + dpb_size, 4*1024); + + len = 0; + vcn_dec_cmd(msg_addr, 0x0, &len); + vcn_dec_cmd(dpb_addr, 0x1, &len); + vcn_dec_cmd(dt_addr, 0x2, &len); + vcn_dec_cmd(fb_addr, 0x3, &len); + vcn_dec_cmd(bs_addr, 0x100, &len); + vcn_dec_cmd(it_addr, 0x204, &len); + vcn_dec_cmd(ctx_addr, 0x206, &len); + + if (vcn_dec_sw_ring == false) { + ib_cpu[len++] = reg[vcn_reg_index].cntl; + ib_cpu[len++] = 0x1; + for (; len % 16; ) { + ib_cpu[len++] = reg[vcn_reg_index].nop; + ib_cpu[len++] = 0; + } + } + + if (vcn_unified_ring) { + amdgpu_cs_sq_ib_tail(ib_cpu + len); + ip = AMDGPU_HW_IP_VCN_ENC; + } else + ip = AMDGPU_HW_IP_VCN_DEC; + + r = submit(len, ip); + CU_ASSERT_EQUAL(r, 0); + + for (i = 0, sum = 0; i < dt_size; ++i) + sum += dec[i]; + + CU_ASSERT_EQUAL(sum, SUM_DECODE); + + free_resource(&dec_buf); +} + +static void amdgpu_cs_vcn_dec_destroy(void) +{ + struct amdgpu_vcn_bo msg_buf; + unsigned ip; + int len, r; + + num_resources = 0; + alloc_resource(&msg_buf, 1024, AMDGPU_GEM_DOMAIN_GTT); + resources[num_resources++] = msg_buf.handle; + resources[num_resources++] = ib_handle; + + r = amdgpu_bo_cpu_map(msg_buf.handle, (void **)&msg_buf.ptr); + CU_ASSERT_EQUAL(r, 0); + + memset(msg_buf.ptr, 0, 1024); + memcpy(msg_buf.ptr, vcn_dec_destroy_msg, sizeof(vcn_dec_destroy_msg)); + + len = 0; + if (vcn_dec_sw_ring == true) + vcn_dec_cmd(msg_buf.addr, 0, &len); + else { + ib_cpu[len++] = reg[vcn_reg_index].data0; + ib_cpu[len++] = msg_buf.addr; + ib_cpu[len++] = reg[vcn_reg_index].data1; + ib_cpu[len++] = msg_buf.addr >> 32; + ib_cpu[len++] = reg[vcn_reg_index].cmd; + ib_cpu[len++] = 0; + for (; len % 16; ) { + ib_cpu[len++] = reg[vcn_reg_index].nop; + ib_cpu[len++] = 0; + } + } + + if (vcn_unified_ring) { + amdgpu_cs_sq_ib_tail(ib_cpu + len); + ip = AMDGPU_HW_IP_VCN_ENC; + } else + ip = AMDGPU_HW_IP_VCN_DEC; + + r = submit(len, ip); + CU_ASSERT_EQUAL(r, 0); + + free_resource(&msg_buf); +} + +static void amdgpu_cs_vcn_enc_create(void) +{ + int len, r; + uint32_t *p_task_size = NULL; + uint32_t task_offset = 0, st_offset; + uint32_t *st_size = NULL; + unsigned width = 160, height = 128, buf_size; + uint32_t fw_maj = 1, fw_min = 9; + + if (vcn_ip_version_major == 2) { + fw_maj = 1; + fw_min = 1; + } else if (vcn_ip_version_major == 3) { + fw_maj = 1; + fw_min = 0; + } + + gWidth = width; + gHeight = height; + buf_size = ALIGN(width, 256) * ALIGN(height, 32) * 3 / 2; + enc_task_id = 1; + + num_resources = 0; + alloc_resource(&enc_buf, 128 * 1024, AMDGPU_GEM_DOMAIN_GTT); + alloc_resource(&cpb_buf, buf_size * 2, AMDGPU_GEM_DOMAIN_GTT); + resources[num_resources++] = enc_buf.handle; + resources[num_resources++] = cpb_buf.handle; + resources[num_resources++] = ib_handle; + + r = amdgpu_bo_cpu_map(enc_buf.handle, (void**)&enc_buf.ptr); + memset(enc_buf.ptr, 0, 128 * 1024); + r = amdgpu_bo_cpu_unmap(enc_buf.handle); + + r = amdgpu_bo_cpu_map(cpb_buf.handle, (void**)&enc_buf.ptr); + memset(enc_buf.ptr, 0, buf_size * 2); + r = amdgpu_bo_cpu_unmap(cpb_buf.handle); + + len = 0; + + if (vcn_unified_ring) + amdgpu_cs_sq_head(ib_cpu, &len, true); + + /* session info */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + ib_cpu[len++] = 0x00000001; /* RENCODE_IB_PARAM_SESSION_INFO */ + ib_cpu[len++] = ((fw_maj << 16) | (fw_min << 0)); + ib_cpu[len++] = enc_buf.addr >> 32; + ib_cpu[len++] = enc_buf.addr; + ib_cpu[len++] = 1; /* RENCODE_ENGINE_TYPE_ENCODE; */ + *st_size = (len - st_offset) * 4; + + /* task info */ + task_offset = len; + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + ib_cpu[len++] = 0x00000002; /* RENCODE_IB_PARAM_TASK_INFO */ + p_task_size = &ib_cpu[len++]; + ib_cpu[len++] = enc_task_id++; /* task_id */ + ib_cpu[len++] = 0; /* feedback */ + *st_size = (len - st_offset) * 4; + + /* op init */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + ib_cpu[len++] = 0x01000001; /* RENCODE_IB_OP_INITIALIZE */ + *st_size = (len - st_offset) * 4; + + /* session_init */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + ib_cpu[len++] = 0x00000003; /* RENCODE_IB_PARAM_SESSION_INIT */ + ib_cpu[len++] = 1; /* RENCODE_ENCODE_STANDARD_H264 */ + ib_cpu[len++] = width; + ib_cpu[len++] = height; + ib_cpu[len++] = 0; + ib_cpu[len++] = 0; + ib_cpu[len++] = 0; /* pre encode mode */ + ib_cpu[len++] = 0; /* chroma enabled : false */ + *st_size = (len - st_offset) * 4; + + /* slice control */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + ib_cpu[len++] = 0x00200001; /* RENCODE_H264_IB_PARAM_SLICE_CONTROL */ + ib_cpu[len++] = 0; /* RENCODE_H264_SLICE_CONTROL_MODE_FIXED_MBS */ + ib_cpu[len++] = ALIGN(width, 16) / 16 * ALIGN(height, 16) / 16; + *st_size = (len - st_offset) * 4; + + /* enc spec misc */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + ib_cpu[len++] = 0x00200002; /* RENCODE_H264_IB_PARAM_SPEC_MISC */ + ib_cpu[len++] = 0; /* constrained intra pred flag */ + ib_cpu[len++] = 0; /* cabac enable */ + ib_cpu[len++] = 0; /* cabac init idc */ + ib_cpu[len++] = 1; /* half pel enabled */ + ib_cpu[len++] = 1; /* quarter pel enabled */ + ib_cpu[len++] = 100; /* BASELINE profile */ + ib_cpu[len++] = 11; /* level */ + if (vcn_ip_version_major == 3) { + ib_cpu[len++] = 0; /* b_picture_enabled */ + ib_cpu[len++] = 0; /* weighted_bipred_idc */ + } + *st_size = (len - st_offset) * 4; + + /* deblocking filter */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + ib_cpu[len++] = 0x00200004; /* RENCODE_H264_IB_PARAM_DEBLOCKING_FILTER */ + ib_cpu[len++] = 0; /* disable deblocking filter idc */ + ib_cpu[len++] = 0; /* alpha c0 offset */ + ib_cpu[len++] = 0; /* tc offset */ + ib_cpu[len++] = 0; /* cb offset */ + ib_cpu[len++] = 0; /* cr offset */ + *st_size = (len - st_offset) * 4; + + /* layer control */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + ib_cpu[len++] = 0x00000004; /* RENCODE_IB_PARAM_LAYER_CONTROL */ + ib_cpu[len++] = 1; /* max temporal layer */ + ib_cpu[len++] = 1; /* no of temporal layer */ + *st_size = (len - st_offset) * 4; + + /* rc_session init */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + ib_cpu[len++] = 0x00000006; /* RENCODE_IB_PARAM_RATE_CONTROL_SESSION_INIT */ + ib_cpu[len++] = 0; /* rate control */ + ib_cpu[len++] = 48; /* vbv buffer level */ + *st_size = (len - st_offset) * 4; + + /* quality params */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + ib_cpu[len++] = 0x00000009; /* RENCODE_IB_PARAM_QUALITY_PARAMS */ + ib_cpu[len++] = 0; /* vbaq mode */ + ib_cpu[len++] = 0; /* scene change sensitivity */ + ib_cpu[len++] = 0; /* scene change min idr interval */ + ib_cpu[len++] = 0; + if (vcn_ip_version_major == 3) + ib_cpu[len++] = 0; + *st_size = (len - st_offset) * 4; + + /* layer select */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + ib_cpu[len++] = 0x00000005; /* RENCODE_IB_PARAM_LAYER_SELECT */ + ib_cpu[len++] = 0; /* temporal layer */ + *st_size = (len - st_offset) * 4; + + /* rc layer init */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + ib_cpu[len++] = 0x00000007; /* RENCODE_IB_PARAM_RATE_CONTROL_LAYER_INIT */ + ib_cpu[len++] = 0; + ib_cpu[len++] = 0; + ib_cpu[len++] = 25; + ib_cpu[len++] = 1; + ib_cpu[len++] = 0x01312d00; + ib_cpu[len++] = 0; + ib_cpu[len++] = 0; + ib_cpu[len++] = 0; + *st_size = (len - st_offset) * 4; + + /* layer select */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + ib_cpu[len++] = 0x00000005; /* RENCODE_IB_PARAM_LAYER_SELECT */ + ib_cpu[len++] = 0; /* temporal layer */ + *st_size = (len - st_offset) * 4; + + /* rc per pic */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + ib_cpu[len++] = 0x00000008; /* RENCODE_IB_PARAM_RATE_CONTROL_PER_PICTURE */ + ib_cpu[len++] = 20; + ib_cpu[len++] = 0; + ib_cpu[len++] = 51; + ib_cpu[len++] = 0; + ib_cpu[len++] = 1; + ib_cpu[len++] = 0; + ib_cpu[len++] = 1; + *st_size = (len - st_offset) * 4; + + /* op init rc */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + ib_cpu[len++] = 0x01000004; /* RENCODE_IB_OP_INIT_RC */ + *st_size = (len - st_offset) * 4; + + /* op init rc vbv */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + ib_cpu[len++] = 0x01000005; /* RENCODE_IB_OP_INIT_RC_VBV_BUFFER_LEVEL */ + *st_size = (len - st_offset) * 4; + + *p_task_size = (len - task_offset) * 4; + + if (vcn_unified_ring) + amdgpu_cs_sq_ib_tail(ib_cpu + len); + + r = submit(len, AMDGPU_HW_IP_VCN_ENC); + CU_ASSERT_EQUAL(r, 0); +} + +static int32_t h264_se (bufferInfo * bufInfo) +{ + uint32_t ret; + + ret = bs_read_ue (bufInfo); + if ((ret & 0x1) == 0) { + ret >>= 1; + int32_t temp = 0 - ret; + return temp; + } + + return (ret + 1) >> 1; +} + +static void h264_check_0s (bufferInfo * bufInfo, int count) +{ + uint32_t val; + + val = bs_read_u (bufInfo, count); + if (val != 0) { + printf ("field error - %d bits should be 0 is %x\n", count, val); + } +} + +static inline int bs_eof(bufferInfo * bufinfo) +{ + if (bufinfo->decBuffer >= bufinfo->end) + return 1; + else + return 0; +} + +static inline uint32_t bs_read_u1(bufferInfo *bufinfo) +{ + uint32_t r = 0; + uint32_t temp = 0; + + bufinfo->numOfBitsInBuffer--; + if (! bs_eof(bufinfo)) { + temp = (((bufinfo->decData)) >> bufinfo->numOfBitsInBuffer); + r = temp & 0x01; + } + + if (bufinfo->numOfBitsInBuffer == 0) { + bufinfo->decBuffer++; + bufinfo->decData = *bufinfo->decBuffer; + bufinfo->numOfBitsInBuffer = 8; + } + + return r; +} + +static inline uint32_t bs_read_u(bufferInfo* bufinfo, int n) +{ + uint32_t r = 0; + int i; + + for (i = 0; i < n; i++) { + r |= ( bs_read_u1(bufinfo) << ( n - i - 1 ) ); + } + + return r; +} + +static inline uint32_t bs_read_ue(bufferInfo* bufinfo) +{ + int32_t r = 0; + int i = 0; + + while( (bs_read_u1(bufinfo) == 0) && (i < 32) && (!bs_eof(bufinfo))) { + i++; + } + r = bs_read_u(bufinfo, i); + r += (1 << i) - 1; + return r; +} + +static uint32_t remove_03 (uint8_t * bptr, uint32_t len) +{ + uint32_t nal_len = 0; + while (nal_len + 2 < len) { + if (bptr[0] == 0 && bptr[1] == 0 && bptr[2] == 3) { + bptr += 2; + nal_len += 2; + len--; + memmove (bptr, bptr + 1, len - nal_len); + } else { + bptr++; + nal_len++; + } + } + return len; +} + +static void scaling_list (uint32_t ix, uint32_t sizeOfScalingList, bufferInfo * bufInfo) +{ + uint32_t lastScale = 8, nextScale = 8; + uint32_t jx; + int deltaScale; + + for (jx = 0; jx < sizeOfScalingList; jx++) { + if (nextScale != 0) { + deltaScale = h264_se (bufInfo); + nextScale = (lastScale + deltaScale + 256) % 256; + } + if (nextScale == 0) { + lastScale = lastScale; + } else { + lastScale = nextScale; + } + } +} + +static void h264_parse_sequence_parameter_set (h264_decode * dec, bufferInfo * bufInfo) +{ + uint32_t temp; + + dec->profile = bs_read_u (bufInfo, 8); + bs_read_u (bufInfo, 1); /* constaint_set0_flag */ + bs_read_u (bufInfo, 1); /* constaint_set1_flag */ + bs_read_u (bufInfo, 1); /* constaint_set2_flag */ + bs_read_u (bufInfo, 1); /* constaint_set3_flag */ + bs_read_u (bufInfo, 1); /* constaint_set4_flag */ + bs_read_u (bufInfo, 1); /* constaint_set5_flag */ + + + h264_check_0s (bufInfo, 2); + dec->level_idc = bs_read_u (bufInfo, 8); + bs_read_ue (bufInfo); /* SPS id*/ + + if (dec->profile == 100 || dec->profile == 110 || + dec->profile == 122 || dec->profile == 144) { + uint32_t chroma_format_idc = bs_read_ue (bufInfo); + if (chroma_format_idc == 3) { + bs_read_u (bufInfo, 1); /* residual_colour_transform_flag */ + } + bs_read_ue (bufInfo); /* bit_depth_luma_minus8 */ + bs_read_ue (bufInfo); /* bit_depth_chroma_minus8 */ + bs_read_u (bufInfo, 1); /* qpprime_y_zero_transform_bypass_flag */ + uint32_t seq_scaling_matrix_present_flag = bs_read_u (bufInfo, 1); + + if (seq_scaling_matrix_present_flag) { + for (uint32_t ix = 0; ix < 8; ix++) { + temp = bs_read_u (bufInfo, 1); + if (temp) { + scaling_list (ix, ix < 6 ? 16 : 64, bufInfo); + } + } + } + } + + bs_read_ue (bufInfo); /* log2_max_frame_num_minus4 */ + uint32_t pic_order_cnt_type = bs_read_ue (bufInfo); + + if (pic_order_cnt_type == 0) { + bs_read_ue (bufInfo); /* log2_max_pic_order_cnt_lsb_minus4 */ + } else if (pic_order_cnt_type == 1) { + bs_read_u (bufInfo, 1); /* delta_pic_order_always_zero_flag */ + h264_se (bufInfo); /* offset_for_non_ref_pic */ + h264_se (bufInfo); /* offset_for_top_to_bottom_field */ + temp = bs_read_ue (bufInfo); + for (uint32_t ix = 0; ix < temp; ix++) { + h264_se (bufInfo); /* offset_for_ref_frame[index] */ + } + } + bs_read_ue (bufInfo); /* num_ref_frames */ + bs_read_u (bufInfo, 1); /* gaps_in_frame_num_flag */ + uint32_t PicWidthInMbs = bs_read_ue (bufInfo) + 1; + + dec->pic_width = PicWidthInMbs * 16; + uint32_t PicHeightInMapUnits = bs_read_ue (bufInfo) + 1; + + dec->pic_height = PicHeightInMapUnits * 16; + uint32_t frame_mbs_only_flag = bs_read_u (bufInfo, 1); + if (!frame_mbs_only_flag) { + bs_read_u (bufInfo, 1); /* mb_adaptive_frame_field_flag */ + } + bs_read_u (bufInfo, 1); /* direct_8x8_inference_flag */ + temp = bs_read_u (bufInfo, 1); + if (temp) { + bs_read_ue (bufInfo); /* frame_crop_left_offset */ + bs_read_ue (bufInfo); /* frame_crop_right_offset */ + bs_read_ue (bufInfo); /* frame_crop_top_offset */ + bs_read_ue (bufInfo); /* frame_crop_bottom_offset */ + } + temp = bs_read_u (bufInfo, 1); /* VUI Parameters */ +} + +static void h264_slice_header (h264_decode * dec, bufferInfo * bufInfo) +{ + uint32_t temp; + + bs_read_ue (bufInfo); /* first_mb_in_slice */ + temp = bs_read_ue (bufInfo); + dec->slice_type = ((temp > 5) ? (temp - 5) : temp); +} + +static uint8_t h264_parse_nal (h264_decode * dec, bufferInfo * bufInfo) +{ + uint8_t type = 0; + + h264_check_0s (bufInfo, 1); + dec->nal_ref_idc = bs_read_u (bufInfo, 2); + dec->nal_unit_type = type = bs_read_u (bufInfo, 5); + switch (type) + { + case H264_NAL_TYPE_NON_IDR_SLICE: + case H264_NAL_TYPE_IDR_SLICE: + h264_slice_header (dec, bufInfo); + break; + case H264_NAL_TYPE_SEQ_PARAM: + h264_parse_sequence_parameter_set (dec, bufInfo); + break; + case H264_NAL_TYPE_PIC_PARAM: + case H264_NAL_TYPE_SEI: + case H264_NAL_TYPE_ACCESS_UNIT: + case H264_NAL_TYPE_SEQ_EXTENSION: + /* NOP */ + break; + default: + printf ("Nal type unknown %d \n ", type); + break; + } + return type; +} + +static uint32_t h264_find_next_start_code (uint8_t * pBuf, uint32_t bufLen) +{ + uint32_t val; + uint32_t offset, startBytes; + + offset = startBytes = 0; + if (pBuf[0] == 0 && pBuf[1] == 0 && pBuf[2] == 0 && pBuf[3] == 1) { + pBuf += 4; + offset = 4; + startBytes = 1; + } else if (pBuf[0] == 0 && pBuf[1] == 0 && pBuf[2] == 1) { + pBuf += 3; + offset = 3; + startBytes = 1; + } + val = 0xffffffff; + while (offset < bufLen - 3) { + val <<= 8; + val |= *pBuf++; + offset++; + if (val == H264_START_CODE) + return offset - 4; + + if ((val & 0x00ffffff) == H264_START_CODE) + return offset - 3; + } + if (bufLen - offset <= 3 && startBytes == 0) { + startBytes = 0; + return 0; + } + + return offset; +} + +static int verify_checksum(uint8_t *buffer, uint32_t buffer_size) +{ + uint32_t buffer_pos = 0; + int done = 0; + h264_decode dec; + + memset(&dec, 0, sizeof(h264_decode)); + do { + uint32_t ret; + + ret = h264_find_next_start_code (buffer + buffer_pos, + buffer_size - buffer_pos); + if (ret == 0) { + done = 1; + if (buffer_pos == 0) { + fprintf (stderr, + "couldn't find start code in buffer from 0\n"); + } + } else { + /* have a complete NAL from buffer_pos to end */ + if (ret > 3) { + uint32_t nal_len; + bufferInfo bufinfo; + + nal_len = remove_03 (buffer + buffer_pos, ret); + bufinfo.decBuffer = buffer + buffer_pos + (buffer[buffer_pos + 2] == 1 ? 3 : 4); + bufinfo.decBufferSize = (nal_len - (buffer[buffer_pos + 2] == 1 ? 3 : 4)) * 8; + bufinfo.end = buffer + buffer_pos + nal_len; + bufinfo.numOfBitsInBuffer = 8; + bufinfo.decData = *bufinfo.decBuffer; + h264_parse_nal (&dec, &bufinfo); + } + buffer_pos += ret; /* buffer_pos points to next code */ + } + } while (done == 0); + + if ((dec.pic_width == gWidth) && + (dec.pic_height == gHeight) && + (dec.slice_type == gSliceType)) + return 0; + else + return -1; +} + +static void check_result(struct amdgpu_vcn_bo fb_buf, struct amdgpu_vcn_bo bs_buf, int frame_type) +{ + uint32_t *fb_ptr; + uint8_t *bs_ptr; + uint32_t size; + int r; +/* uint64_t s[3] = {0, 1121279001727, 1059312481445}; */ + + r = amdgpu_bo_cpu_map(fb_buf.handle, (void **)&fb_buf.ptr); + CU_ASSERT_EQUAL(r, 0); + fb_ptr = (uint32_t*)fb_buf.ptr; + size = fb_ptr[6]; + r = amdgpu_bo_cpu_unmap(fb_buf.handle); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_bo_cpu_map(bs_buf.handle, (void **)&bs_buf.ptr); + CU_ASSERT_EQUAL(r, 0); + + bs_ptr = (uint8_t*)bs_buf.ptr; + r = verify_checksum(bs_ptr, size); + CU_ASSERT_EQUAL(r, 0); + r = amdgpu_bo_cpu_unmap(bs_buf.handle); + + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_cs_vcn_enc_encode_frame(int frame_type) +{ + struct amdgpu_vcn_bo bs_buf, fb_buf, vbv_buf; + int len, r, i; + unsigned width = 160, height = 128, buf_size; + uint32_t *p_task_size = NULL; + uint32_t task_offset = 0, st_offset; + uint32_t *st_size = NULL; + uint32_t fw_maj = 1, fw_min = 9; + + if (vcn_ip_version_major == 2) { + fw_maj = 1; + fw_min = 1; + } else if (vcn_ip_version_major == 3) { + fw_maj = 1; + fw_min = 0; + } + gSliceType = frame_type; + buf_size = ALIGN(width, 256) * ALIGN(height, 32) * 3 / 2; + + num_resources = 0; + alloc_resource(&bs_buf, 4096, AMDGPU_GEM_DOMAIN_GTT); + alloc_resource(&fb_buf, 4096, AMDGPU_GEM_DOMAIN_GTT); + alloc_resource(&vbv_buf, buf_size, AMDGPU_GEM_DOMAIN_GTT); + resources[num_resources++] = enc_buf.handle; + resources[num_resources++] = cpb_buf.handle; + resources[num_resources++] = bs_buf.handle; + resources[num_resources++] = fb_buf.handle; + resources[num_resources++] = vbv_buf.handle; + resources[num_resources++] = ib_handle; + + + r = amdgpu_bo_cpu_map(bs_buf.handle, (void**)&bs_buf.ptr); + memset(bs_buf.ptr, 0, 4096); + r = amdgpu_bo_cpu_unmap(bs_buf.handle); + + r = amdgpu_bo_cpu_map(fb_buf.handle, (void**)&fb_buf.ptr); + memset(fb_buf.ptr, 0, 4096); + r = amdgpu_bo_cpu_unmap(fb_buf.handle); + + r = amdgpu_bo_cpu_map(vbv_buf.handle, (void **)&vbv_buf.ptr); + CU_ASSERT_EQUAL(r, 0); + + for (int i = 0; i < ALIGN(height, 32) * 3 / 2; i++) + memcpy(vbv_buf.ptr + i * ALIGN(width, 256), frame + i * width, width); + + r = amdgpu_bo_cpu_unmap(vbv_buf.handle); + CU_ASSERT_EQUAL(r, 0); + + len = 0; + + if (vcn_unified_ring) + amdgpu_cs_sq_head(ib_cpu, &len, true); + + /* session info */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + ib_cpu[len++] = 0x00000001; /* RENCODE_IB_PARAM_SESSION_INFO */ + ib_cpu[len++] = ((fw_maj << 16) | (fw_min << 0)); + ib_cpu[len++] = enc_buf.addr >> 32; + ib_cpu[len++] = enc_buf.addr; + ib_cpu[len++] = 1; /* RENCODE_ENGINE_TYPE_ENCODE */; + *st_size = (len - st_offset) * 4; + + /* task info */ + task_offset = len; + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + ib_cpu[len++] = 0x00000002; /* RENCODE_IB_PARAM_TASK_INFO */ + p_task_size = &ib_cpu[len++]; + ib_cpu[len++] = enc_task_id++; /* task_id */ + ib_cpu[len++] = 1; /* feedback */ + *st_size = (len - st_offset) * 4; + + if (frame_type == 2) { + /* sps */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + if(vcn_ip_version_major == 1) + ib_cpu[len++] = 0x00000020; /* RENCODE_IB_PARAM_DIRECT_OUTPUT_NALU vcn 1 */ + else + ib_cpu[len++] = 0x0000000a; /* RENCODE_IB_PARAM_DIRECT_OUTPUT_NALU vcn 2,3 */ + ib_cpu[len++] = 0x00000002; /* RENCODE_DIRECT_OUTPUT_NALU_TYPE_SPS */ + ib_cpu[len++] = 0x00000011; /* sps len */ + ib_cpu[len++] = 0x00000001; /* start code */ + ib_cpu[len++] = 0x6764440b; + ib_cpu[len++] = 0xac54c284; + ib_cpu[len++] = 0x68078442; + ib_cpu[len++] = 0x37000000; + *st_size = (len - st_offset) * 4; + + /* pps */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + if(vcn_ip_version_major == 1) + ib_cpu[len++] = 0x00000020; /* RENCODE_IB_PARAM_DIRECT_OUTPUT_NALU vcn 1*/ + else + ib_cpu[len++] = 0x0000000a; /* RENCODE_IB_PARAM_DIRECT_OUTPUT_NALU vcn 2,3*/ + ib_cpu[len++] = 0x00000003; /* RENCODE_DIRECT_OUTPUT_NALU_TYPE_PPS */ + ib_cpu[len++] = 0x00000008; /* pps len */ + ib_cpu[len++] = 0x00000001; /* start code */ + ib_cpu[len++] = 0x68ce3c80; + *st_size = (len - st_offset) * 4; + } + + /* slice header */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + if(vcn_ip_version_major == 1) + ib_cpu[len++] = 0x0000000a; /* RENCODE_IB_PARAM_SLICE_HEADER vcn 1 */ + else + ib_cpu[len++] = 0x0000000b; /* RENCODE_IB_PARAM_SLICE_HEADER vcn 2,3 */ + if (frame_type == 2) { + ib_cpu[len++] = 0x65000000; + ib_cpu[len++] = 0x11040000; + } else { + ib_cpu[len++] = 0x41000000; + ib_cpu[len++] = 0x34210000; + } + ib_cpu[len++] = 0xe0000000; + for(i = 0; i < 13; i++) + ib_cpu[len++] = 0x00000000; + + ib_cpu[len++] = 0x00000001; + ib_cpu[len++] = 0x00000008; + ib_cpu[len++] = 0x00020000; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000001; + ib_cpu[len++] = 0x00000015; + ib_cpu[len++] = 0x00020001; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000001; + ib_cpu[len++] = 0x00000003; + for(i = 0; i < 22; i++) + ib_cpu[len++] = 0x00000000; + + *st_size = (len - st_offset) * 4; + + /* encode params */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + if(vcn_ip_version_major == 1) + ib_cpu[len++] = 0x0000000b; /* RENCODE_IB_PARAM_ENCODE_PARAMS vcn 1*/ + else + ib_cpu[len++] = 0x0000000f; /* RENCODE_IB_PARAM_ENCODE_PARAMS vcn 2,3*/ + ib_cpu[len++] = frame_type; + ib_cpu[len++] = 0x0001f000; + ib_cpu[len++] = vbv_buf.addr >> 32; + ib_cpu[len++] = vbv_buf.addr; + ib_cpu[len++] = (vbv_buf.addr + ALIGN(width, 256) * ALIGN(height, 32)) >> 32; + ib_cpu[len++] = vbv_buf.addr + ALIGN(width, 256) * ALIGN(height, 32); + ib_cpu[len++] = 0x00000100; + ib_cpu[len++] = 0x00000080; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0xffffffff; + ib_cpu[len++] = 0x00000000; + *st_size = (len - st_offset) * 4; + + /* encode params h264 */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + ib_cpu[len++] = 0x00200003; /* RENCODE_H264_IB_PARAM_ENCODE_PARAMS */ + if (vcn_ip_version_major != 3) { + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0xffffffff; + } else { + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0xffffffff; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0xffffffff; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; + } + *st_size = (len - st_offset) * 4; + + /* encode context */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + if(vcn_ip_version_major == 1) + ib_cpu[len++] = 0x0000000d; /* ENCODE_CONTEXT_BUFFER vcn 1 */ + else + ib_cpu[len++] = 0x00000011; /* ENCODE_CONTEXT_BUFFER vcn 2,3 */ + ib_cpu[len++] = cpb_buf.addr >> 32; + ib_cpu[len++] = cpb_buf.addr; + ib_cpu[len++] = 0x00000000; /* swizzle mode */ + ib_cpu[len++] = 0x00000100; /* luma pitch */ + ib_cpu[len++] = 0x00000100; /* chroma pitch */ + ib_cpu[len++] = 0x00000003; /* no reconstructed picture */ + ib_cpu[len++] = 0x00000000; /* reconstructed pic 1 luma offset */ + ib_cpu[len++] = ALIGN(width, 256) * ALIGN(height, 32); /* pic1 chroma offset */ + ib_cpu[len++] = ALIGN(width, 256) * ALIGN(height, 32) * 3 / 2; /* pic2 luma offset */ + ib_cpu[len++] = ALIGN(width, 256) * ALIGN(height, 32) * 5 / 2; /* pic2 chroma offset */ + + for (int i = 0; i < 136; i++) + ib_cpu[len++] = 0x00000000; + *st_size = (len - st_offset) * 4; + + /* bitstream buffer */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + if(vcn_ip_version_major == 1) + ib_cpu[len++] = 0x0000000e; /* VIDEO_BITSTREAM_BUFFER vcn 1 */ + else + ib_cpu[len++] = 0x00000012; /* VIDEO_BITSTREAM_BUFFER vcn 2,3 */ + ib_cpu[len++] = 0x00000000; /* mode */ + ib_cpu[len++] = bs_buf.addr >> 32; + ib_cpu[len++] = bs_buf.addr; + ib_cpu[len++] = 0x0001f000; + ib_cpu[len++] = 0x00000000; + *st_size = (len - st_offset) * 4; + + /* feedback */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + if(vcn_ip_version_major == 1) + ib_cpu[len++] = 0x00000010; /* FEEDBACK_BUFFER vcn 1 */ + else + ib_cpu[len++] = 0x00000015; /* FEEDBACK_BUFFER vcn 2,3 */ + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = fb_buf.addr >> 32; + ib_cpu[len++] = fb_buf.addr; + ib_cpu[len++] = 0x00000010; + ib_cpu[len++] = 0x00000028; + *st_size = (len - st_offset) * 4; + + /* intra refresh */ + st_offset = len; + st_size = &ib_cpu[len++]; + if(vcn_ip_version_major == 1) + ib_cpu[len++] = 0x0000000c; /* INTRA_REFRESH vcn 1 */ + else + ib_cpu[len++] = 0x00000010; /* INTRA_REFRESH vcn 2,3 */ + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; + *st_size = (len - st_offset) * 4; + + if(vcn_ip_version_major != 1) { + /* Input Format */ + st_offset = len; + st_size = &ib_cpu[len++]; + ib_cpu[len++] = 0x0000000c; + ib_cpu[len++] = 0x00000000; /* RENCODE_COLOR_VOLUME_G22_BT709 */ + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; /* RENCODE_COLOR_BIT_DEPTH_8_BIT */ + ib_cpu[len++] = 0x00000000; /* RENCODE_COLOR_PACKING_FORMAT_NV12 */ + *st_size = (len - st_offset) * 4; + + /* Output Format */ + st_offset = len; + st_size = &ib_cpu[len++]; + ib_cpu[len++] = 0x0000000d; + ib_cpu[len++] = 0x00000000; /* RENCODE_COLOR_VOLUME_G22_BT709 */ + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; + ib_cpu[len++] = 0x00000000; /* RENCODE_COLOR_BIT_DEPTH_8_BIT */ + *st_size = (len - st_offset) * 4; + } + /* op_speed */ + st_offset = len; + st_size = &ib_cpu[len++]; + ib_cpu[len++] = 0x01000006; /* SPEED_ENCODING_MODE */ + *st_size = (len - st_offset) * 4; + + /* op_enc */ + st_offset = len; + st_size = &ib_cpu[len++]; + ib_cpu[len++] = 0x01000003; + *st_size = (len - st_offset) * 4; + + *p_task_size = (len - task_offset) * 4; + + if (vcn_unified_ring) + amdgpu_cs_sq_ib_tail(ib_cpu + len); + + r = submit(len, AMDGPU_HW_IP_VCN_ENC); + CU_ASSERT_EQUAL(r, 0); + + /* check result */ + check_result(fb_buf, bs_buf, frame_type); + + free_resource(&fb_buf); + free_resource(&bs_buf); + free_resource(&vbv_buf); +} + +static void amdgpu_cs_vcn_enc_encode(void) +{ + amdgpu_cs_vcn_enc_encode_frame(2); /* IDR frame */ +} + +static void amdgpu_cs_vcn_enc_destroy(void) +{ + int len = 0, r; + uint32_t *p_task_size = NULL; + uint32_t task_offset = 0, st_offset; + uint32_t *st_size = NULL; + uint32_t fw_maj = 1, fw_min = 9; + + if (vcn_ip_version_major == 2) { + fw_maj = 1; + fw_min = 1; + } else if (vcn_ip_version_major == 3) { + fw_maj = 1; + fw_min = 0; + } + + num_resources = 0; +/* alloc_resource(&enc_buf, 128 * 1024, AMDGPU_GEM_DOMAIN_GTT); */ + resources[num_resources++] = enc_buf.handle; + resources[num_resources++] = ib_handle; + + if (vcn_unified_ring) + amdgpu_cs_sq_head(ib_cpu, &len, true); + + /* session info */ + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + ib_cpu[len++] = 0x00000001; /* RENCODE_IB_PARAM_SESSION_INFO */ + ib_cpu[len++] = ((fw_maj << 16) | (fw_min << 0)); + ib_cpu[len++] = enc_buf.addr >> 32; + ib_cpu[len++] = enc_buf.addr; + ib_cpu[len++] = 1; /* RENCODE_ENGINE_TYPE_ENCODE; */ + *st_size = (len - st_offset) * 4; + + /* task info */ + task_offset = len; + st_offset = len; + st_size = &ib_cpu[len++]; /* size */ + ib_cpu[len++] = 0x00000002; /* RENCODE_IB_PARAM_TASK_INFO */ + p_task_size = &ib_cpu[len++]; + ib_cpu[len++] = enc_task_id++; /* task_id */ + ib_cpu[len++] = 0; /* feedback */ + *st_size = (len - st_offset) * 4; + + /* op close */ + st_offset = len; + st_size = &ib_cpu[len++]; + ib_cpu[len++] = 0x01000002; /* RENCODE_IB_OP_CLOSE_SESSION */ + *st_size = (len - st_offset) * 4; + + *p_task_size = (len - task_offset) * 4; + + if (vcn_unified_ring) + amdgpu_cs_sq_ib_tail(ib_cpu + len); + + r = submit(len, AMDGPU_HW_IP_VCN_ENC); + CU_ASSERT_EQUAL(r, 0); + + free_resource(&cpb_buf); + free_resource(&enc_buf); +} diff --git a/tests/amdgpu/vm_tests.c b/tests/amdgpu/vm_tests.c new file mode 100644 index 0000000..b94999c --- /dev/null +++ b/tests/amdgpu/vm_tests.c @@ -0,0 +1,270 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * +*/ + +#include "CUnit/Basic.h" + +#include "amdgpu_test.h" +#include "amdgpu_drm.h" +#include "amdgpu_internal.h" + +static amdgpu_device_handle device_handle; +static uint32_t major_version; +static uint32_t minor_version; +static uint32_t family_id; +static uint32_t chip_id; +static uint32_t chip_rev; + +static void amdgpu_vmid_reserve_test(void); +static void amdgpu_vm_unaligned_map(void); +static void amdgpu_vm_mapping_test(void); + +CU_BOOL suite_vm_tests_enable(void) +{ + CU_BOOL enable = CU_TRUE; + + if (amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle)) + return CU_FALSE; + + if (device_handle->info.family_id == AMDGPU_FAMILY_SI) { + printf("\n\nCurrently hangs the CP on this ASIC, VM suite disabled\n"); + enable = CU_FALSE; + } + + if (amdgpu_device_deinitialize(device_handle)) + return CU_FALSE; + + return enable; +} + +int suite_vm_tests_init(void) +{ + int r; + + r = amdgpu_device_initialize(drm_amdgpu[0], &major_version, + &minor_version, &device_handle); + + if (r) { + if ((r == -EACCES) && (errno == EACCES)) + printf("\n\nError:%s. " + "Hint:Try to run this test program as root.", + strerror(errno)); + return CUE_SINIT_FAILED; + } + + return CUE_SUCCESS; +} + +int suite_vm_tests_clean(void) +{ + int r = amdgpu_device_deinitialize(device_handle); + + if (r == 0) + return CUE_SUCCESS; + else + return CUE_SCLEAN_FAILED; +} + + +CU_TestInfo vm_tests[] = { + { "resere vmid test", amdgpu_vmid_reserve_test }, + { "unaligned map", amdgpu_vm_unaligned_map }, + { "vm mapping test", amdgpu_vm_mapping_test }, + CU_TEST_INFO_NULL, +}; + +static void amdgpu_vmid_reserve_test(void) +{ + amdgpu_context_handle context_handle; + amdgpu_bo_handle ib_result_handle; + void *ib_result_cpu; + uint64_t ib_result_mc_address; + struct amdgpu_cs_request ibs_request; + struct amdgpu_cs_ib_info ib_info; + struct amdgpu_cs_fence fence_status; + uint32_t expired, flags; + int i, r; + amdgpu_bo_list_handle bo_list; + amdgpu_va_handle va_handle; + static uint32_t *ptr; + struct amdgpu_gpu_info gpu_info = {0}; + unsigned gc_ip_type; + + r = amdgpu_query_gpu_info(device_handle, &gpu_info); + CU_ASSERT_EQUAL(r, 0); + + family_id = device_handle->info.family_id; + chip_id = device_handle->info.chip_external_rev; + chip_rev = device_handle->info.chip_rev; + + gc_ip_type = (asic_is_gfx_pipe_removed(family_id, chip_id, chip_rev)) ? + AMDGPU_HW_IP_COMPUTE : AMDGPU_HW_IP_GFX; + + r = amdgpu_cs_ctx_create(device_handle, &context_handle); + CU_ASSERT_EQUAL(r, 0); + + flags = 0; + r = amdgpu_vm_reserve_vmid(device_handle, flags); + CU_ASSERT_EQUAL(r, 0); + + + r = amdgpu_bo_alloc_and_map(device_handle, 4096, 4096, + AMDGPU_GEM_DOMAIN_GTT, 0, + &ib_result_handle, &ib_result_cpu, + &ib_result_mc_address, &va_handle); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_get_bo_list(device_handle, ib_result_handle, NULL, + &bo_list); + CU_ASSERT_EQUAL(r, 0); + + ptr = ib_result_cpu; + + for (i = 0; i < 16; ++i) + ptr[i] = 0xffff1000; + + memset(&ib_info, 0, sizeof(struct amdgpu_cs_ib_info)); + ib_info.ib_mc_address = ib_result_mc_address; + ib_info.size = 16; + + memset(&ibs_request, 0, sizeof(struct amdgpu_cs_request)); + ibs_request.ip_type = gc_ip_type; + ibs_request.ring = 0; + ibs_request.number_of_ibs = 1; + ibs_request.ibs = &ib_info; + ibs_request.resources = bo_list; + ibs_request.fence_info.handle = NULL; + + r = amdgpu_cs_submit(context_handle, 0,&ibs_request, 1); + CU_ASSERT_EQUAL(r, 0); + + + memset(&fence_status, 0, sizeof(struct amdgpu_cs_fence)); + fence_status.context = context_handle; + fence_status.ip_type = gc_ip_type; + fence_status.ip_instance = 0; + fence_status.ring = 0; + fence_status.fence = ibs_request.seq_no; + + r = amdgpu_cs_query_fence_status(&fence_status, + AMDGPU_TIMEOUT_INFINITE,0, &expired); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_list_destroy(bo_list); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_bo_unmap_and_free(ib_result_handle, va_handle, + ib_result_mc_address, 4096); + CU_ASSERT_EQUAL(r, 0); + + flags = 0; + r = amdgpu_vm_unreserve_vmid(device_handle, flags); + CU_ASSERT_EQUAL(r, 0); + + + r = amdgpu_cs_ctx_free(context_handle); + CU_ASSERT_EQUAL(r, 0); +} + +static void amdgpu_vm_unaligned_map(void) +{ + const uint64_t map_size = (4ULL << 30) - (2 << 12); + struct amdgpu_bo_alloc_request request = {}; + amdgpu_bo_handle buf_handle; + amdgpu_va_handle handle; + uint64_t vmc_addr; + int r; + + request.alloc_size = 4ULL << 30; + request.phys_alignment = 4096; + request.preferred_heap = AMDGPU_GEM_DOMAIN_VRAM; + request.flags = AMDGPU_GEM_CREATE_NO_CPU_ACCESS; + + r = amdgpu_bo_alloc(device_handle, &request, &buf_handle); + /* Don't let the test fail if the device doesn't have enough VRAM */ + if (r) + return; + + r = amdgpu_va_range_alloc(device_handle, amdgpu_gpu_va_range_general, + 4ULL << 30, 1ULL << 30, 0, &vmc_addr, + &handle, 0); + CU_ASSERT_EQUAL(r, 0); + if (r) + goto error_va_alloc; + + vmc_addr += 1 << 12; + + r = amdgpu_bo_va_op(buf_handle, 0, map_size, vmc_addr, 0, + AMDGPU_VA_OP_MAP); + CU_ASSERT_EQUAL(r, 0); + if (r) + goto error_va_alloc; + + amdgpu_bo_va_op(buf_handle, 0, map_size, vmc_addr, 0, + AMDGPU_VA_OP_UNMAP); + +error_va_alloc: + amdgpu_bo_free(buf_handle); +} + +static void amdgpu_vm_mapping_test(void) +{ + struct amdgpu_bo_alloc_request req = {0}; + struct drm_amdgpu_info_device dev_info; + const uint64_t size = 4096; + amdgpu_bo_handle buf; + uint64_t addr; + int r; + + req.alloc_size = size; + req.phys_alignment = 0; + req.preferred_heap = AMDGPU_GEM_DOMAIN_GTT; + req.flags = 0; + + r = amdgpu_bo_alloc(device_handle, &req, &buf); + CU_ASSERT_EQUAL(r, 0); + + r = amdgpu_query_info(device_handle, AMDGPU_INFO_DEV_INFO, + sizeof(dev_info), &dev_info); + CU_ASSERT_EQUAL(r, 0); + + addr = dev_info.virtual_address_offset; + r = amdgpu_bo_va_op(buf, 0, size, addr, 0, AMDGPU_VA_OP_MAP); + CU_ASSERT_EQUAL(r, 0); + + addr = dev_info.virtual_address_max - size; + r = amdgpu_bo_va_op(buf, 0, size, addr, 0, AMDGPU_VA_OP_MAP); + CU_ASSERT_EQUAL(r, 0); + + if (dev_info.high_va_offset) { + addr = dev_info.high_va_offset; + r = amdgpu_bo_va_op(buf, 0, size, addr, 0, AMDGPU_VA_OP_MAP); + CU_ASSERT_EQUAL(r, 0); + + addr = dev_info.high_va_max - size; + r = amdgpu_bo_va_op(buf, 0, size, addr, 0, AMDGPU_VA_OP_MAP); + CU_ASSERT_EQUAL(r, 0); + } + + amdgpu_bo_free(buf); +} diff --git a/tests/drmdevice.c b/tests/drmdevice.c new file mode 100644 index 0000000..b4b62d9 --- /dev/null +++ b/tests/drmdevice.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2015 Emil Velikov + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static void +print_device_info(drmDevicePtr device, int i, bool print_revision) +{ + printf("device[%i]\n", i); + printf("+-> available_nodes %#04x\n", device->available_nodes); + printf("+-> nodes\n"); + for (int j = 0; j < DRM_NODE_MAX; j++) + if (device->available_nodes & 1 << j) + printf("| +-> nodes[%d] %s\n", j, device->nodes[j]); + + printf("+-> bustype %04x\n", device->bustype); + if (device->bustype == DRM_BUS_PCI) { + printf("| +-> pci\n"); + printf("| +-> domain %04x\n",device->businfo.pci->domain); + printf("| +-> bus %02x\n", device->businfo.pci->bus); + printf("| +-> dev %02x\n", device->businfo.pci->dev); + printf("| +-> func %1u\n", device->businfo.pci->func); + + printf("+-> deviceinfo\n"); + printf(" +-> pci\n"); + printf(" +-> vendor_id %04x\n", device->deviceinfo.pci->vendor_id); + printf(" +-> device_id %04x\n", device->deviceinfo.pci->device_id); + printf(" +-> subvendor_id %04x\n", device->deviceinfo.pci->subvendor_id); + printf(" +-> subdevice_id %04x\n", device->deviceinfo.pci->subdevice_id); + if (print_revision) + printf(" +-> revision_id %02x\n", device->deviceinfo.pci->revision_id); + else + printf(" +-> revision_id IGNORED\n"); + + } else if (device->bustype == DRM_BUS_USB) { + printf("| +-> usb\n"); + printf("| +-> bus %03u\n", device->businfo.usb->bus); + printf("| +-> dev %03u\n", device->businfo.usb->dev); + + printf("+-> deviceinfo\n"); + printf(" +-> usb\n"); + printf(" +-> vendor %04x\n", device->deviceinfo.usb->vendor); + printf(" +-> product %04x\n", device->deviceinfo.usb->product); + } else if (device->bustype == DRM_BUS_PLATFORM) { + char **compatible = device->deviceinfo.platform->compatible; + + printf("| +-> platform\n"); + printf("| +-> fullname\t%s\n", device->businfo.platform->fullname); + + printf("+-> deviceinfo\n"); + printf(" +-> platform\n"); + printf(" +-> compatible\n"); + + while (*compatible) { + printf(" %s\n", *compatible); + compatible++; + } + } else if (device->bustype == DRM_BUS_HOST1X) { + char **compatible = device->deviceinfo.host1x->compatible; + + printf("| +-> host1x\n"); + printf("| +-> fullname\t%s\n", device->businfo.host1x->fullname); + + printf("+-> deviceinfo\n"); + printf(" +-> host1x\n"); + printf(" +-> compatible\n"); + + while (*compatible) { + printf(" %s\n", *compatible); + compatible++; + } + } else { + printf("Unknown/unhandled bustype\n"); + } + printf("\n"); +} + +int +main(void) +{ + drmDevicePtr *devices; + drmDevicePtr device; + int fd, ret, max_devices; + + printf("--- Checking the number of DRM device available ---\n"); + max_devices = drmGetDevices2(0, NULL, 0); + + if (max_devices <= 0) { + printf("drmGetDevices2() has not found any devices (errno=%d)\n", + -max_devices); + return 77; + } + printf("--- Devices reported %d ---\n", max_devices); + + + devices = calloc(max_devices, sizeof(drmDevicePtr)); + if (devices == NULL) { + printf("Failed to allocate memory for the drmDevicePtr array\n"); + return -1; + } + + printf("--- Retrieving devices information (PCI device revision is ignored) ---\n"); + ret = drmGetDevices2(0, devices, max_devices); + if (ret < 0) { + printf("drmGetDevices2() returned an error %d\n", ret); + free(devices); + return -1; + } + + for (int i = 0; i < ret; i++) { + print_device_info(devices[i], i, false); + + for (int j = 0; j < DRM_NODE_MAX; j++) { + if (devices[i]->available_nodes & 1 << j) { + printf("--- Opening device node %s ---\n", devices[i]->nodes[j]); + fd = open(devices[i]->nodes[j], O_RDONLY | O_CLOEXEC); + if (fd < 0) { + printf("Failed - %s (%d)\n", strerror(errno), errno); + continue; + } + + printf("--- Retrieving device info, for node %s ---\n", devices[i]->nodes[j]); + if (drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, &device) == 0) { + print_device_info(device, i, true); + drmFreeDevice(&device); + } + close(fd); + } + } + } + + drmFreeDevices(devices, ret); + free(devices); + return 0; +} diff --git a/tests/drmsl.c b/tests/drmsl.c new file mode 100644 index 0000000..d1b59a8 --- /dev/null +++ b/tests/drmsl.c @@ -0,0 +1,184 @@ +/* drmsl.c -- Skip list test + * Created: Mon May 10 09:28:13 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * 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, 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT 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. + * + * Authors: Rickard E. (Rik) Faith + * + * DESCRIPTION + * + * This file contains a straightforward skip list implementation.n + * + * FUTURE ENHANCEMENTS + * + * REFERENCES + * + * [Pugh90] William Pugh. Skip Lists: A Probabilistic Alternative to + * Balanced Trees. CACM 33(6), June 1990, pp. 668-676. + * + */ + +#include +#include +#include + +#include "xf86drm.h" + +static void print(void* list) +{ + unsigned long key; + void *value; + + if (drmSLFirst(list, &key, &value)) { + do { + printf("key = %5lu, value = %p\n", key, value); + } while (drmSLNext(list, &key, &value)); + } +} + +static double do_time(int size, int iter) +{ + void *list; + int i, j; + unsigned long keys[1000000]; + unsigned long previous; + unsigned long key; + void *value; + struct timeval start, stop; + double usec; + void *ranstate; + + list = drmSLCreate(); + ranstate = drmRandomCreate(12345); + + for (i = 0; i < size; i++) { + keys[i] = drmRandom(ranstate); + drmSLInsert(list, keys[i], NULL); + } + + previous = 0; + if (drmSLFirst(list, &key, &value)) { + do { + if (key <= previous) { + printf( "%lu !< %lu\n", previous, key); + } + previous = key; + } while (drmSLNext(list, &key, &value)); + } + + gettimeofday(&start, NULL); + for (j = 0; j < iter; j++) { + for (i = 0; i < size; i++) { + if (drmSLLookup(list, keys[i], &value)) + printf("Error %lu %d\n", keys[i], i); + } + } + gettimeofday(&stop, NULL); + + usec = (double)(stop.tv_sec * 1000000 + stop.tv_usec + - start.tv_sec * 1000000 - start.tv_usec) / (size * iter); + + printf("%0.2f microseconds for list length %d\n", usec, size); + + drmRandomDouble(ranstate); + drmSLDestroy(list); + + return usec; +} + +static void print_neighbors(void *list, unsigned long key, + unsigned long expected_prev, + unsigned long expected_next) +{ + unsigned long prev_key = 0; + unsigned long next_key = 0; + void *prev_value; + void *next_value; + int retval; + + retval = drmSLLookupNeighbors(list, key, + &prev_key, &prev_value, + &next_key, &next_value); + printf("Neighbors of %5lu: %d %5lu %5lu\n", + key, retval, prev_key, next_key); + if (prev_key != expected_prev) { + fprintf(stderr, "Unexpected neighbor: %5lu. Expected: %5lu\n", + prev_key, expected_prev); + exit(1); + } + if (next_key != expected_next) { + fprintf(stderr, "Unexpected neighbor: %5lu. Expected: %5lu\n", + next_key, expected_next); + exit(1); + } +} + +int main(void) +{ + void* list; + double usec, usec2, usec3, usec4; + + list = drmSLCreate(); + printf( "list at %p\n", list); + + print(list); + printf("\n==============================\n\n"); + + drmSLInsert(list, 123, NULL); + drmSLInsert(list, 213, NULL); + drmSLInsert(list, 50, NULL); + print(list); + printf("\n==============================\n\n"); + + print_neighbors(list, 0, 0, 50); + print_neighbors(list, 50, 0, 50); + print_neighbors(list, 51, 50, 123); + print_neighbors(list, 123, 50, 123); + print_neighbors(list, 200, 123, 213); + print_neighbors(list, 213, 123, 213); + print_neighbors(list, 256, 213, 256); + printf("\n==============================\n\n"); + + drmSLDelete(list, 50); + print(list); + printf("\n==============================\n\n"); + + drmSLDump(list); + drmSLDestroy(list); + printf("\n==============================\n\n"); + + usec = do_time(100, 10000); + usec2 = do_time(1000, 500); + printf("Table size increased by %0.2f, search time increased by %0.2f\n", + 1000.0/100.0, usec2 / usec); + + usec3 = do_time(10000, 50); + printf("Table size increased by %0.2f, search time increased by %0.2f\n", + 10000.0/100.0, usec3 / usec); + + usec4 = do_time(100000, 4); + printf("Table size increased by %0.2f, search time increased by %0.2f\n", + 100000.0/100.0, usec4 / usec); + + return 0; +} diff --git a/tests/etnaviv/cmdstream.xml.h b/tests/etnaviv/cmdstream.xml.h new file mode 100644 index 0000000..109285c --- /dev/null +++ b/tests/etnaviv/cmdstream.xml.h @@ -0,0 +1,242 @@ +#ifndef CMDSTREAM_XML +#define CMDSTREAM_XML + +/* Autogenerated file, DO NOT EDIT manually! + +This file was generated by the rules-ng-ng headergen tool in this git repository: +http://0x04.net/cgit/index.cgi/rules-ng-ng +git clone git://0x04.net/rules-ng-ng + +The rules-ng-ng source files this header was generated from are: +- cmdstream.xml ( 12621 bytes, from 2016-09-06 14:44:16) +- copyright.xml ( 1597 bytes, from 2016-09-06 14:44:16) +- common.xml ( 20583 bytes, from 2016-09-06 14:14:12) + +Copyright (C) 2012-2016 by the following authors: +- Wladimir J. van der Laan +- Christian Gmeiner +- Lucas Stach +- Russell King + +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 +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. +*/ + + +#define FE_OPCODE_LOAD_STATE 0x00000001 +#define FE_OPCODE_END 0x00000002 +#define FE_OPCODE_NOP 0x00000003 +#define FE_OPCODE_DRAW_2D 0x00000004 +#define FE_OPCODE_DRAW_PRIMITIVES 0x00000005 +#define FE_OPCODE_DRAW_INDEXED_PRIMITIVES 0x00000006 +#define FE_OPCODE_WAIT 0x00000007 +#define FE_OPCODE_LINK 0x00000008 +#define FE_OPCODE_STALL 0x00000009 +#define FE_OPCODE_CALL 0x0000000a +#define FE_OPCODE_RETURN 0x0000000b +#define FE_OPCODE_CHIP_SELECT 0x0000000d +#define PRIMITIVE_TYPE_POINTS 0x00000001 +#define PRIMITIVE_TYPE_LINES 0x00000002 +#define PRIMITIVE_TYPE_LINE_STRIP 0x00000003 +#define PRIMITIVE_TYPE_TRIANGLES 0x00000004 +#define PRIMITIVE_TYPE_TRIANGLE_STRIP 0x00000005 +#define PRIMITIVE_TYPE_TRIANGLE_FAN 0x00000006 +#define PRIMITIVE_TYPE_LINE_LOOP 0x00000007 +#define PRIMITIVE_TYPE_QUADS 0x00000008 +#define VIV_FE_LOAD_STATE 0x00000000 + +#define VIV_FE_LOAD_STATE_HEADER 0x00000000 +#define VIV_FE_LOAD_STATE_HEADER_OP__MASK 0xf8000000 +#define VIV_FE_LOAD_STATE_HEADER_OP__SHIFT 27 +#define VIV_FE_LOAD_STATE_HEADER_OP_LOAD_STATE 0x08000000 +#define VIV_FE_LOAD_STATE_HEADER_FIXP 0x04000000 +#define VIV_FE_LOAD_STATE_HEADER_COUNT__MASK 0x03ff0000 +#define VIV_FE_LOAD_STATE_HEADER_COUNT__SHIFT 16 +#define VIV_FE_LOAD_STATE_HEADER_COUNT(x) (((x) << VIV_FE_LOAD_STATE_HEADER_COUNT__SHIFT) & VIV_FE_LOAD_STATE_HEADER_COUNT__MASK) +#define VIV_FE_LOAD_STATE_HEADER_OFFSET__MASK 0x0000ffff +#define VIV_FE_LOAD_STATE_HEADER_OFFSET__SHIFT 0 +#define VIV_FE_LOAD_STATE_HEADER_OFFSET(x) (((x) << VIV_FE_LOAD_STATE_HEADER_OFFSET__SHIFT) & VIV_FE_LOAD_STATE_HEADER_OFFSET__MASK) +#define VIV_FE_LOAD_STATE_HEADER_OFFSET__SHR 2 + +#define VIV_FE_END 0x00000000 + +#define VIV_FE_END_HEADER 0x00000000 +#define VIV_FE_END_HEADER_EVENT_ID__MASK 0x0000001f +#define VIV_FE_END_HEADER_EVENT_ID__SHIFT 0 +#define VIV_FE_END_HEADER_EVENT_ID(x) (((x) << VIV_FE_END_HEADER_EVENT_ID__SHIFT) & VIV_FE_END_HEADER_EVENT_ID__MASK) +#define VIV_FE_END_HEADER_EVENT_ENABLE 0x00000100 +#define VIV_FE_END_HEADER_OP__MASK 0xf8000000 +#define VIV_FE_END_HEADER_OP__SHIFT 27 +#define VIV_FE_END_HEADER_OP_END 0x10000000 + +#define VIV_FE_NOP 0x00000000 + +#define VIV_FE_NOP_HEADER 0x00000000 +#define VIV_FE_NOP_HEADER_OP__MASK 0xf8000000 +#define VIV_FE_NOP_HEADER_OP__SHIFT 27 +#define VIV_FE_NOP_HEADER_OP_NOP 0x18000000 + +#define VIV_FE_DRAW_2D 0x00000000 + +#define VIV_FE_DRAW_2D_HEADER 0x00000000 +#define VIV_FE_DRAW_2D_HEADER_COUNT__MASK 0x0000ff00 +#define VIV_FE_DRAW_2D_HEADER_COUNT__SHIFT 8 +#define VIV_FE_DRAW_2D_HEADER_COUNT(x) (((x) << VIV_FE_DRAW_2D_HEADER_COUNT__SHIFT) & VIV_FE_DRAW_2D_HEADER_COUNT__MASK) +#define VIV_FE_DRAW_2D_HEADER_DATA_COUNT__MASK 0x07ff0000 +#define VIV_FE_DRAW_2D_HEADER_DATA_COUNT__SHIFT 16 +#define VIV_FE_DRAW_2D_HEADER_DATA_COUNT(x) (((x) << VIV_FE_DRAW_2D_HEADER_DATA_COUNT__SHIFT) & VIV_FE_DRAW_2D_HEADER_DATA_COUNT__MASK) +#define VIV_FE_DRAW_2D_HEADER_OP__MASK 0xf8000000 +#define VIV_FE_DRAW_2D_HEADER_OP__SHIFT 27 +#define VIV_FE_DRAW_2D_HEADER_OP_DRAW_2D 0x20000000 + +#define VIV_FE_DRAW_2D_TOP_LEFT 0x00000008 +#define VIV_FE_DRAW_2D_TOP_LEFT_X__MASK 0x0000ffff +#define VIV_FE_DRAW_2D_TOP_LEFT_X__SHIFT 0 +#define VIV_FE_DRAW_2D_TOP_LEFT_X(x) (((x) << VIV_FE_DRAW_2D_TOP_LEFT_X__SHIFT) & VIV_FE_DRAW_2D_TOP_LEFT_X__MASK) +#define VIV_FE_DRAW_2D_TOP_LEFT_Y__MASK 0xffff0000 +#define VIV_FE_DRAW_2D_TOP_LEFT_Y__SHIFT 16 +#define VIV_FE_DRAW_2D_TOP_LEFT_Y(x) (((x) << VIV_FE_DRAW_2D_TOP_LEFT_Y__SHIFT) & VIV_FE_DRAW_2D_TOP_LEFT_Y__MASK) + +#define VIV_FE_DRAW_2D_BOTTOM_RIGHT 0x0000000c +#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__MASK 0x0000ffff +#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__SHIFT 0 +#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_X(x) (((x) << VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__SHIFT) & VIV_FE_DRAW_2D_BOTTOM_RIGHT_X__MASK) +#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__MASK 0xffff0000 +#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__SHIFT 16 +#define VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y(x) (((x) << VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__SHIFT) & VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y__MASK) + +#define VIV_FE_DRAW_PRIMITIVES 0x00000000 + +#define VIV_FE_DRAW_PRIMITIVES_HEADER 0x00000000 +#define VIV_FE_DRAW_PRIMITIVES_HEADER_OP__MASK 0xf8000000 +#define VIV_FE_DRAW_PRIMITIVES_HEADER_OP__SHIFT 27 +#define VIV_FE_DRAW_PRIMITIVES_HEADER_OP_DRAW_PRIMITIVES 0x28000000 + +#define VIV_FE_DRAW_PRIMITIVES_COMMAND 0x00000004 +#define VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__MASK 0x000000ff +#define VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__SHIFT 0 +#define VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE(x) (((x) << VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__SHIFT) & VIV_FE_DRAW_PRIMITIVES_COMMAND_TYPE__MASK) + +#define VIV_FE_DRAW_PRIMITIVES_START 0x00000008 + +#define VIV_FE_DRAW_PRIMITIVES_COUNT 0x0000000c + +#define VIV_FE_DRAW_INDEXED_PRIMITIVES 0x00000000 + +#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER 0x00000000 +#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER_OP__MASK 0xf8000000 +#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER_OP__SHIFT 27 +#define VIV_FE_DRAW_INDEXED_PRIMITIVES_HEADER_OP_DRAW_INDEXED_PRIMITIVES 0x30000000 + +#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND 0x00000004 +#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__MASK 0x000000ff +#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__SHIFT 0 +#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE(x) (((x) << VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__SHIFT) & VIV_FE_DRAW_INDEXED_PRIMITIVES_COMMAND_TYPE__MASK) + +#define VIV_FE_DRAW_INDEXED_PRIMITIVES_START 0x00000008 + +#define VIV_FE_DRAW_INDEXED_PRIMITIVES_COUNT 0x0000000c + +#define VIV_FE_DRAW_INDEXED_PRIMITIVES_OFFSET 0x00000010 + +#define VIV_FE_WAIT 0x00000000 + +#define VIV_FE_WAIT_HEADER 0x00000000 +#define VIV_FE_WAIT_HEADER_DELAY__MASK 0x0000ffff +#define VIV_FE_WAIT_HEADER_DELAY__SHIFT 0 +#define VIV_FE_WAIT_HEADER_DELAY(x) (((x) << VIV_FE_WAIT_HEADER_DELAY__SHIFT) & VIV_FE_WAIT_HEADER_DELAY__MASK) +#define VIV_FE_WAIT_HEADER_OP__MASK 0xf8000000 +#define VIV_FE_WAIT_HEADER_OP__SHIFT 27 +#define VIV_FE_WAIT_HEADER_OP_WAIT 0x38000000 + +#define VIV_FE_LINK 0x00000000 + +#define VIV_FE_LINK_HEADER 0x00000000 +#define VIV_FE_LINK_HEADER_PREFETCH__MASK 0x0000ffff +#define VIV_FE_LINK_HEADER_PREFETCH__SHIFT 0 +#define VIV_FE_LINK_HEADER_PREFETCH(x) (((x) << VIV_FE_LINK_HEADER_PREFETCH__SHIFT) & VIV_FE_LINK_HEADER_PREFETCH__MASK) +#define VIV_FE_LINK_HEADER_OP__MASK 0xf8000000 +#define VIV_FE_LINK_HEADER_OP__SHIFT 27 +#define VIV_FE_LINK_HEADER_OP_LINK 0x40000000 + +#define VIV_FE_LINK_ADDRESS 0x00000004 + +#define VIV_FE_STALL 0x00000000 + +#define VIV_FE_STALL_HEADER 0x00000000 +#define VIV_FE_STALL_HEADER_OP__MASK 0xf8000000 +#define VIV_FE_STALL_HEADER_OP__SHIFT 27 +#define VIV_FE_STALL_HEADER_OP_STALL 0x48000000 + +#define VIV_FE_STALL_TOKEN 0x00000004 +#define VIV_FE_STALL_TOKEN_FROM__MASK 0x0000001f +#define VIV_FE_STALL_TOKEN_FROM__SHIFT 0 +#define VIV_FE_STALL_TOKEN_FROM(x) (((x) << VIV_FE_STALL_TOKEN_FROM__SHIFT) & VIV_FE_STALL_TOKEN_FROM__MASK) +#define VIV_FE_STALL_TOKEN_TO__MASK 0x00001f00 +#define VIV_FE_STALL_TOKEN_TO__SHIFT 8 +#define VIV_FE_STALL_TOKEN_TO(x) (((x) << VIV_FE_STALL_TOKEN_TO__SHIFT) & VIV_FE_STALL_TOKEN_TO__MASK) + +#define VIV_FE_CALL 0x00000000 + +#define VIV_FE_CALL_HEADER 0x00000000 +#define VIV_FE_CALL_HEADER_PREFETCH__MASK 0x0000ffff +#define VIV_FE_CALL_HEADER_PREFETCH__SHIFT 0 +#define VIV_FE_CALL_HEADER_PREFETCH(x) (((x) << VIV_FE_CALL_HEADER_PREFETCH__SHIFT) & VIV_FE_CALL_HEADER_PREFETCH__MASK) +#define VIV_FE_CALL_HEADER_OP__MASK 0xf8000000 +#define VIV_FE_CALL_HEADER_OP__SHIFT 27 +#define VIV_FE_CALL_HEADER_OP_CALL 0x50000000 + +#define VIV_FE_CALL_ADDRESS 0x00000004 + +#define VIV_FE_CALL_RETURN_PREFETCH 0x00000008 + +#define VIV_FE_CALL_RETURN_ADDRESS 0x0000000c + +#define VIV_FE_RETURN 0x00000000 + +#define VIV_FE_RETURN_HEADER 0x00000000 +#define VIV_FE_RETURN_HEADER_OP__MASK 0xf8000000 +#define VIV_FE_RETURN_HEADER_OP__SHIFT 27 +#define VIV_FE_RETURN_HEADER_OP_RETURN 0x58000000 + +#define VIV_FE_CHIP_SELECT 0x00000000 + +#define VIV_FE_CHIP_SELECT_HEADER 0x00000000 +#define VIV_FE_CHIP_SELECT_HEADER_OP__MASK 0xf8000000 +#define VIV_FE_CHIP_SELECT_HEADER_OP__SHIFT 27 +#define VIV_FE_CHIP_SELECT_HEADER_OP_CHIP_SELECT 0x68000000 +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP15 0x00008000 +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP14 0x00004000 +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP13 0x00002000 +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP12 0x00001000 +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP11 0x00000800 +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP10 0x00000400 +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP9 0x00000200 +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP8 0x00000100 +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP7 0x00000080 +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP6 0x00000040 +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP5 0x00000020 +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP4 0x00000010 +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP3 0x00000008 +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP2 0x00000004 +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP1 0x00000002 +#define VIV_FE_CHIP_SELECT_HEADER_ENABLE_CHIP0 0x00000001 + + +#endif /* CMDSTREAM_XML */ diff --git a/tests/etnaviv/etnaviv_2d_test.c b/tests/etnaviv/etnaviv_2d_test.c new file mode 100644 index 0000000..9fcdae1 --- /dev/null +++ b/tests/etnaviv/etnaviv_2d_test.c @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2014-2015 Etnaviv Project + * + * 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 (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 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. + * + * Authors: + * Christian Gmeiner + */ + +#include +#include +#include +#include + +#include "xf86drm.h" +#include "etnaviv_drmif.h" +#include "etnaviv_drm.h" + +#include "state.xml.h" +#include "state_2d.xml.h" +#include "cmdstream.xml.h" + +#include "write_bmp.h" + +static inline void etna_emit_load_state(struct etna_cmd_stream *stream, + const uint16_t offset, const uint16_t count) +{ + uint32_t v; + + v = (VIV_FE_LOAD_STATE_HEADER_OP_LOAD_STATE | VIV_FE_LOAD_STATE_HEADER_OFFSET(offset) | + (VIV_FE_LOAD_STATE_HEADER_COUNT(count) & VIV_FE_LOAD_STATE_HEADER_COUNT__MASK)); + + etna_cmd_stream_emit(stream, v); +} + +static inline void etna_set_state(struct etna_cmd_stream *stream, uint32_t address, uint32_t value) +{ + etna_cmd_stream_reserve(stream, 2); + etna_emit_load_state(stream, address >> 2, 1); + etna_cmd_stream_emit(stream, value); +} + +static inline void etna_set_state_from_bo(struct etna_cmd_stream *stream, + uint32_t address, struct etna_bo *bo) +{ + etna_cmd_stream_reserve(stream, 2); + etna_emit_load_state(stream, address >> 2, 1); + + etna_cmd_stream_reloc(stream, &(struct etna_reloc){ + .bo = bo, + .flags = ETNA_RELOC_READ, + .offset = 0, + }); +} + +static void gen_cmd_stream(struct etna_cmd_stream *stream, struct etna_bo *bmp, const int width, const int height) +{ + int rec; + static int num_rects = 256; + + etna_set_state(stream, VIVS_DE_SRC_STRIDE, 0); + etna_set_state(stream, VIVS_DE_SRC_ROTATION_CONFIG, 0); + etna_set_state(stream, VIVS_DE_SRC_CONFIG, 0); + etna_set_state(stream, VIVS_DE_SRC_ORIGIN, 0); + etna_set_state(stream, VIVS_DE_SRC_SIZE, 0); + etna_set_state(stream, VIVS_DE_SRC_COLOR_BG, 0); + etna_set_state(stream, VIVS_DE_SRC_COLOR_FG, 0); + etna_set_state(stream, VIVS_DE_STRETCH_FACTOR_LOW, 0); + etna_set_state(stream, VIVS_DE_STRETCH_FACTOR_HIGH, 0); + etna_set_state_from_bo(stream, VIVS_DE_DEST_ADDRESS, bmp); + etna_set_state(stream, VIVS_DE_DEST_STRIDE, width*4); + etna_set_state(stream, VIVS_DE_DEST_ROTATION_CONFIG, 0); + etna_set_state(stream, VIVS_DE_DEST_CONFIG, + VIVS_DE_DEST_CONFIG_FORMAT(DE_FORMAT_A8R8G8B8) | + VIVS_DE_DEST_CONFIG_COMMAND_CLEAR | + VIVS_DE_DEST_CONFIG_SWIZZLE(DE_SWIZZLE_ARGB) | + VIVS_DE_DEST_CONFIG_TILED_DISABLE | + VIVS_DE_DEST_CONFIG_MINOR_TILED_DISABLE + ); + etna_set_state(stream, VIVS_DE_ROP, + VIVS_DE_ROP_ROP_FG(0xcc) | VIVS_DE_ROP_ROP_BG(0xcc) | VIVS_DE_ROP_TYPE_ROP4); + etna_set_state(stream, VIVS_DE_CLIP_TOP_LEFT, + VIVS_DE_CLIP_TOP_LEFT_X(0) | + VIVS_DE_CLIP_TOP_LEFT_Y(0) + ); + etna_set_state(stream, VIVS_DE_CLIP_BOTTOM_RIGHT, + VIVS_DE_CLIP_BOTTOM_RIGHT_X(width) | + VIVS_DE_CLIP_BOTTOM_RIGHT_Y(height) + ); + etna_set_state(stream, VIVS_DE_CONFIG, 0); /* TODO */ + etna_set_state(stream, VIVS_DE_SRC_ORIGIN_FRACTION, 0); + etna_set_state(stream, VIVS_DE_ALPHA_CONTROL, 0); + etna_set_state(stream, VIVS_DE_ALPHA_MODES, 0); + etna_set_state(stream, VIVS_DE_DEST_ROTATION_HEIGHT, 0); + etna_set_state(stream, VIVS_DE_SRC_ROTATION_HEIGHT, 0); + etna_set_state(stream, VIVS_DE_ROT_ANGLE, 0); + + /* Clear color PE20 */ + etna_set_state(stream, VIVS_DE_CLEAR_PIXEL_VALUE32, 0xff40ff40); + /* Clear color PE10 */ + etna_set_state(stream, VIVS_DE_CLEAR_BYTE_MASK, 0xff); + etna_set_state(stream, VIVS_DE_CLEAR_PIXEL_VALUE_LOW, 0xff40ff40); + etna_set_state(stream, VIVS_DE_CLEAR_PIXEL_VALUE_HIGH, 0xff40ff40); + + etna_set_state(stream, VIVS_DE_DEST_COLOR_KEY, 0); + etna_set_state(stream, VIVS_DE_GLOBAL_SRC_COLOR, 0); + etna_set_state(stream, VIVS_DE_GLOBAL_DEST_COLOR, 0); + etna_set_state(stream, VIVS_DE_COLOR_MULTIPLY_MODES, 0); + etna_set_state(stream, VIVS_DE_PE_TRANSPARENCY, 0); + etna_set_state(stream, VIVS_DE_PE_CONTROL, 0); + etna_set_state(stream, VIVS_DE_PE_DITHER_LOW, 0xffffffff); + etna_set_state(stream, VIVS_DE_PE_DITHER_HIGH, 0xffffffff); + + /* Queue DE command */ + etna_cmd_stream_emit(stream, + VIV_FE_DRAW_2D_HEADER_OP_DRAW_2D | VIV_FE_DRAW_2D_HEADER_COUNT(num_rects) /* render one rectangle */ + ); + etna_cmd_stream_emit(stream, 0x0); /* rectangles start aligned */ + + for(rec=0; rec < num_rects; ++rec) { + int x = rec%16; + int y = rec/16; + etna_cmd_stream_emit(stream, VIV_FE_DRAW_2D_TOP_LEFT_X(x*8) | VIV_FE_DRAW_2D_TOP_LEFT_Y(y*8)); + etna_cmd_stream_emit(stream, VIV_FE_DRAW_2D_BOTTOM_RIGHT_X(x*8+4) | VIV_FE_DRAW_2D_BOTTOM_RIGHT_Y(y*8+4)); + } + etna_set_state(stream, 1, 0); + etna_set_state(stream, 1, 0); + etna_set_state(stream, 1, 0); + + etna_set_state(stream, VIVS_GL_FLUSH_CACHE, VIVS_GL_FLUSH_CACHE_PE2D); +} + +int etna_check_image(uint32_t *p, int width, int height) +{ + int i; + uint32_t expected; + + for (i = 0; i < width * height; i++) { + if (i%8 < 4 && i%(width*8) < width*4 && i%width < 8*16 && i < width*8*16) + expected = 0xff40ff40; + else + expected = 0x00000000; + + if (p[i] != expected) { + fprintf(stderr, "Offset %d: expected: 0x%08x, got: 0x%08x\n", + i, expected, p[i]); + return -1; + } + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + const int width = 256; + const int height = 256; + const size_t bmp_size = width * height * 4; + + struct etna_device *dev; + struct etna_gpu *gpu; + struct etna_pipe *pipe; + struct etna_bo *bmp; + struct etna_cmd_stream *stream; + + drmVersionPtr version; + int fd, ret = 0; + uint64_t feat; + int core = 0; + + if (argc < 2) { + fprintf(stderr, "Usage: %s /dev/dri/ []\n", argv[0]); + return 1; + } + + fd = open(argv[1], O_RDWR); + if (fd < 0) { + perror(argv[1]); + return 1; + } + + version = drmGetVersion(fd); + if (version) { + printf("Version: %d.%d.%d\n", version->version_major, + version->version_minor, version->version_patchlevel); + printf(" Name: %s\n", version->name); + printf(" Date: %s\n", version->date); + printf(" Description: %s\n", version->desc); + drmFreeVersion(version); + } + + dev = etna_device_new(fd); + if (!dev) { + perror("etna_device_new"); + ret = 2; + goto out; + } + + do { + gpu = etna_gpu_new(dev, core); + if (!gpu) { + perror("etna_gpu_new"); + ret = 3; + goto out_device; + } + + if (etna_gpu_get_param(gpu, ETNA_GPU_FEATURES_0, &feat)) { + perror("etna_gpu_get_param"); + ret = 4; + goto out_device; + } + + if ((feat & (1 << 9)) == 0) { + /* GPU not 2D capable. */ + etna_gpu_del(gpu); + gpu = NULL; + } + + core++; + } while (!gpu); + + pipe = etna_pipe_new(gpu, ETNA_PIPE_2D); + if (!pipe) { + perror("etna_pipe_new"); + ret = 4; + goto out_gpu; + } + + bmp = etna_bo_new(dev, bmp_size, ETNA_BO_UNCACHED); + if (!bmp) { + perror("etna_bo_new"); + ret = 5; + goto out_pipe; + } + memset(etna_bo_map(bmp), 0, bmp_size); + + stream = etna_cmd_stream_new(pipe, 0x300, NULL, NULL); + if (!stream) { + perror("etna_cmd_stream_new"); + ret = 6; + goto out_bo; + } + + /* generate command sequence */ + gen_cmd_stream(stream, bmp, width, height); + + etna_cmd_stream_finish(stream); + + if (argc > 2) + bmp_dump32(etna_bo_map(bmp), width, height, false, argv[2]); + + if (etna_check_image(etna_bo_map(bmp), width, height)) + ret = 7; + + etna_cmd_stream_del(stream); + +out_bo: + etna_bo_del(bmp); + +out_pipe: + etna_pipe_del(pipe); + +out_gpu: + etna_gpu_del(gpu); + +out_device: + etna_device_del(dev); + +out: + close(fd); + + return ret; +} diff --git a/tests/etnaviv/etnaviv_bo_cache_test.c b/tests/etnaviv/etnaviv_bo_cache_test.c new file mode 100644 index 0000000..7fb0629 --- /dev/null +++ b/tests/etnaviv/etnaviv_bo_cache_test.c @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2016 Etnaviv Project + * + * 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 (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 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. + * + * Authors: + * Christian Gmeiner + */ + +#undef NDEBUG +#include + +#include +#include +#include +#include + +#include "xf86drm.h" +#include "etnaviv_drmif.h" +#include "etnaviv_drm.h" + +static void test_cache(struct etna_device *dev) +{ + struct etna_bo *bo, *tmp; + + /* allocate and free some bo's with same size - we must + * get the same bo over and over. */ + printf("testing bo cache ... "); + + bo = tmp = etna_bo_new(dev, 0x100, ETNA_BO_UNCACHED); + assert(bo); + etna_bo_del(bo); + + for (unsigned i = 0; i < 100; i++) { + tmp = etna_bo_new(dev, 0x100, ETNA_BO_UNCACHED); + etna_bo_del(tmp); + assert(tmp == bo); + } + + printf("ok\n"); +} + +static void test_size_rounding(struct etna_device *dev) +{ + struct etna_bo *bo; + + printf("testing size rounding ... "); + + bo = etna_bo_new(dev, 15, ETNA_BO_UNCACHED); + assert(etna_bo_size(bo) == 4096); + etna_bo_del(bo); + + bo = etna_bo_new(dev, 4096, ETNA_BO_UNCACHED); + assert(etna_bo_size(bo) == 4096); + etna_bo_del(bo); + + bo = etna_bo_new(dev, 4100, ETNA_BO_UNCACHED); + assert(etna_bo_size(bo) == 8192); + etna_bo_del(bo); + + printf("ok\n"); +} + +int main(int argc, char *argv[]) +{ + struct etna_device *dev; + + drmVersionPtr version; + int fd, ret = 0; + + fd = open(argv[1], O_RDWR); + if (fd < 0) + return 1; + + version = drmGetVersion(fd); + if (version) { + printf("Version: %d.%d.%d\n", version->version_major, + version->version_minor, version->version_patchlevel); + printf(" Name: %s\n", version->name); + printf(" Date: %s\n", version->date); + printf(" Description: %s\n", version->desc); + drmFreeVersion(version); + } + + dev = etna_device_new(fd); + if (!dev) { + ret = 2; + goto out; + } + + test_cache(dev); + test_size_rounding(dev); + + etna_device_del(dev); + +out: + close(fd); + + return ret; +} diff --git a/tests/etnaviv/etnaviv_cmd_stream_test.c b/tests/etnaviv/etnaviv_cmd_stream_test.c new file mode 100644 index 0000000..b650aae --- /dev/null +++ b/tests/etnaviv/etnaviv_cmd_stream_test.c @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2015 Etnaviv Project + * + * 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 (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 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. + * + * Authors: + * Christian Gmeiner + */ + +#undef NDEBUG +#include +#include +#include + +#include "etnaviv_drmif.h" + +static void test_avail() +{ + struct etna_cmd_stream *stream; + + printf("testing etna_cmd_stream_avail ... "); + + /* invalid size */ + stream = etna_cmd_stream_new(NULL, 0, NULL, NULL); + assert(stream == NULL); + + stream = etna_cmd_stream_new(NULL, 4, NULL, NULL); + assert(stream); + assert(etna_cmd_stream_avail(stream) == 2); + etna_cmd_stream_del(stream); + + stream = etna_cmd_stream_new(NULL, 20, NULL, NULL); + assert(stream); + assert(etna_cmd_stream_avail(stream) == 18); + etna_cmd_stream_del(stream); + + /* odd number of 32 bit words */ + stream = etna_cmd_stream_new(NULL, 1, NULL, NULL); + assert(stream); + assert(etna_cmd_stream_avail(stream) == 0); + etna_cmd_stream_del(stream); + + stream = etna_cmd_stream_new(NULL, 23, NULL, NULL); + assert(stream); + assert(etna_cmd_stream_avail(stream) == 22); + etna_cmd_stream_del(stream); + + printf("ok\n"); +} + +static void test_emit() +{ + struct etna_cmd_stream *stream; + + printf("testing etna_cmd_stream_emit ... "); + + stream = etna_cmd_stream_new(NULL, 6, NULL, NULL); + assert(stream); + assert(etna_cmd_stream_avail(stream) == 4); + + etna_cmd_stream_emit(stream, 0x1); + assert(etna_cmd_stream_avail(stream) == 3); + + etna_cmd_stream_emit(stream, 0x2); + assert(etna_cmd_stream_avail(stream) == 2); + + etna_cmd_stream_emit(stream, 0x3); + assert(etna_cmd_stream_avail(stream) == 1); + + etna_cmd_stream_del(stream); + + printf("ok\n"); +} + +static void test_offset() +{ + struct etna_cmd_stream *stream; + + printf("testing etna_cmd_stream_offset ... "); + + stream = etna_cmd_stream_new(NULL, 6, NULL, NULL); + assert(etna_cmd_stream_offset(stream) == 0); + + etna_cmd_stream_emit(stream, 0x1); + assert(etna_cmd_stream_offset(stream) == 1); + + etna_cmd_stream_emit(stream, 0x2); + assert(etna_cmd_stream_offset(stream) == 2); + + etna_cmd_stream_emit(stream, 0x3); + etna_cmd_stream_emit(stream, 0x4); + assert(etna_cmd_stream_offset(stream) == 4); + + etna_cmd_stream_del(stream); + + printf("ok\n"); +} + +int main(int argc, char *argv[]) +{ + test_avail(); + test_emit(); + test_offset(); + + return 0; +} diff --git a/tests/etnaviv/meson.build b/tests/etnaviv/meson.build new file mode 100644 index 0000000..8b4a3cf --- /dev/null +++ b/tests/etnaviv/meson.build @@ -0,0 +1,45 @@ +# Copyright © 2017-2018 Intel Corporation + +# 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. + +inc_etnaviv_tests = [inc_root, inc_drm, include_directories('../../etnaviv')] + +etnaviv_2d_test = executable( + 'etnaviv_2d_test', + files('etnaviv_2d_test.c', 'write_bmp.c'), + include_directories : inc_etnaviv_tests, + link_with : [libdrm, libdrm_etnaviv], + install : with_install_tests, +) + +etnaviv_cmd_stream_test = executable( + 'etnaviv_cmd_stream_test', + files('etnaviv_cmd_stream_test.c'), + include_directories : inc_etnaviv_tests, + link_with : [libdrm, libdrm_etnaviv], + install : with_install_tests, +) + +etnaviv_bo_cache_test = executable( + 'etnaviv_bo_cache_test', + files('etnaviv_bo_cache_test.c'), + include_directories : inc_etnaviv_tests, + link_with : [libdrm, libdrm_etnaviv], + install : with_install_tests, +) diff --git a/tests/etnaviv/state.xml.h b/tests/etnaviv/state.xml.h new file mode 100644 index 0000000..e1ecbf3 --- /dev/null +++ b/tests/etnaviv/state.xml.h @@ -0,0 +1,375 @@ +#ifndef STATE_XML +#define STATE_XML + +/* Autogenerated file, DO NOT EDIT manually! + +This file was generated by the rules-ng-ng headergen tool in this git repository: +http://0x04.net/cgit/index.cgi/rules-ng-ng +git clone git://0x04.net/rules-ng-ng + +The rules-ng-ng source files this header was generated from are: +- state.xml ( 18940 bytes, from 2016-09-06 14:14:12) +- common.xml ( 20583 bytes, from 2016-09-06 14:14:12) +- state_hi.xml ( 25653 bytes, from 2016-09-06 14:45:17) +- copyright.xml ( 1597 bytes, from 2016-09-06 14:44:16) +- state_2d.xml ( 51552 bytes, from 2016-09-06 14:44:16) +- state_3d.xml ( 54603 bytes, from 2016-09-06 14:44:16) +- state_vg.xml ( 5975 bytes, from 2016-09-06 14:44:16) + +Copyright (C) 2012-2016 by the following authors: +- Wladimir J. van der Laan +- Christian Gmeiner +- Lucas Stach +- Russell King + +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 +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. +*/ + + +#define VARYING_COMPONENT_USE_UNUSED 0x00000000 +#define VARYING_COMPONENT_USE_USED 0x00000001 +#define VARYING_COMPONENT_USE_POINTCOORD_X 0x00000002 +#define VARYING_COMPONENT_USE_POINTCOORD_Y 0x00000003 +#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__MASK 0x000000ff +#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__SHIFT 0 +#define FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE(x) (((x) << FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__SHIFT) & FE_VERTEX_STREAM_CONTROL_VERTEX_STRIDE__MASK) +#define VIVS_FE 0x00000000 + +#define VIVS_FE_VERTEX_ELEMENT_CONFIG(i0) (0x00000600 + 0x4*(i0)) +#define VIVS_FE_VERTEX_ELEMENT_CONFIG__ESIZE 0x00000004 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG__LEN 0x00000010 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE__MASK 0x0000000f +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE__SHIFT 0 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_BYTE 0x00000000 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_BYTE 0x00000001 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_SHORT 0x00000002 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_SHORT 0x00000003 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_INT 0x00000004 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_INT 0x00000005 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_FLOAT 0x00000008 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_HALF_FLOAT 0x00000009 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_FIXED 0x0000000b +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_INT_10_10_10_2 0x0000000c +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_TYPE_UNSIGNED_INT_10_10_10_2 0x0000000d +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__MASK 0x00000030 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__SHIFT 4 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN(x) (((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_ENDIAN__MASK) +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NONCONSECUTIVE 0x00000080 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__MASK 0x00000700 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__SHIFT 8 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM(x) (((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_STREAM__MASK) +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__MASK 0x00003000 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__SHIFT 12 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM(x) (((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_NUM__MASK) +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE__MASK 0x0000c000 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE__SHIFT 14 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_OFF 0x00000000 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_ON 0x00008000 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START__MASK 0x00ff0000 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START__SHIFT 16 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_START(x) (((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_START__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_START__MASK) +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END__MASK 0xff000000 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END__SHIFT 24 +#define VIVS_FE_VERTEX_ELEMENT_CONFIG_END(x) (((x) << VIVS_FE_VERTEX_ELEMENT_CONFIG_END__SHIFT) & VIVS_FE_VERTEX_ELEMENT_CONFIG_END__MASK) + +#define VIVS_FE_CMD_STREAM_BASE_ADDR 0x00000640 + +#define VIVS_FE_INDEX_STREAM_BASE_ADDR 0x00000644 + +#define VIVS_FE_INDEX_STREAM_CONTROL 0x00000648 +#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE__MASK 0x00000003 +#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE__SHIFT 0 +#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_CHAR 0x00000000 +#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_SHORT 0x00000001 +#define VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_INT 0x00000002 + +#define VIVS_FE_VERTEX_STREAM_BASE_ADDR 0x0000064c + +#define VIVS_FE_VERTEX_STREAM_CONTROL 0x00000650 + +#define VIVS_FE_COMMAND_ADDRESS 0x00000654 + +#define VIVS_FE_COMMAND_CONTROL 0x00000658 +#define VIVS_FE_COMMAND_CONTROL_PREFETCH__MASK 0x0000ffff +#define VIVS_FE_COMMAND_CONTROL_PREFETCH__SHIFT 0 +#define VIVS_FE_COMMAND_CONTROL_PREFETCH(x) (((x) << VIVS_FE_COMMAND_CONTROL_PREFETCH__SHIFT) & VIVS_FE_COMMAND_CONTROL_PREFETCH__MASK) +#define VIVS_FE_COMMAND_CONTROL_ENABLE 0x00010000 + +#define VIVS_FE_DMA_STATUS 0x0000065c + +#define VIVS_FE_DMA_DEBUG_STATE 0x00000660 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE__MASK 0x0000001f +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE__SHIFT 0 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_IDLE 0x00000000 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DEC 0x00000001 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_ADR0 0x00000002 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LOAD0 0x00000003 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_ADR1 0x00000004 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LOAD1 0x00000005 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DADR 0x00000006 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DCMD 0x00000007 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DCNTL 0x00000008 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_3DIDXCNTL 0x00000009 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_INITREQDMA 0x0000000a +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DRAWIDX 0x0000000b +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_DRAW 0x0000000c +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DRECT0 0x0000000d +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DRECT1 0x0000000e +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DDATA0 0x0000000f +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_2DDATA1 0x00000010 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_WAITFIFO 0x00000011 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_WAIT 0x00000012 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_LINK 0x00000013 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_END 0x00000014 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_STATE_STALL 0x00000015 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE__MASK 0x00000300 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE__SHIFT 8 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_IDLE 0x00000000 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_START 0x00000100 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_REQ 0x00000200 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_DMA_STATE_END 0x00000300 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE__MASK 0x00000c00 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE__SHIFT 10 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_IDLE 0x00000000 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_RAMVALID 0x00000400 +#define VIVS_FE_DMA_DEBUG_STATE_CMD_FETCH_STATE_VALID 0x00000800 +#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE__MASK 0x00003000 +#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE__SHIFT 12 +#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_IDLE 0x00000000 +#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_WAITIDX 0x00001000 +#define VIVS_FE_DMA_DEBUG_STATE_REQ_DMA_STATE_CAL 0x00002000 +#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE__MASK 0x0000c000 +#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE__SHIFT 14 +#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_IDLE 0x00000000 +#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_LDADR 0x00004000 +#define VIVS_FE_DMA_DEBUG_STATE_CAL_STATE_IDXCALC 0x00008000 +#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE__MASK 0x00030000 +#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE__SHIFT 16 +#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_IDLE 0x00000000 +#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_CKCACHE 0x00010000 +#define VIVS_FE_DMA_DEBUG_STATE_VE_REQ_STATE_MISS 0x00020000 + +#define VIVS_FE_DMA_ADDRESS 0x00000664 + +#define VIVS_FE_DMA_LOW 0x00000668 + +#define VIVS_FE_DMA_HIGH 0x0000066c + +#define VIVS_FE_AUTO_FLUSH 0x00000670 + +#define VIVS_FE_UNK00678 0x00000678 + +#define VIVS_FE_UNK0067C 0x0000067c + +#define VIVS_FE_VERTEX_STREAMS(i0) (0x00000000 + 0x4*(i0)) +#define VIVS_FE_VERTEX_STREAMS__ESIZE 0x00000004 +#define VIVS_FE_VERTEX_STREAMS__LEN 0x00000008 + +#define VIVS_FE_VERTEX_STREAMS_BASE_ADDR(i0) (0x00000680 + 0x4*(i0)) + +#define VIVS_FE_VERTEX_STREAMS_CONTROL(i0) (0x000006a0 + 0x4*(i0)) + +#define VIVS_FE_UNK00700(i0) (0x00000700 + 0x4*(i0)) +#define VIVS_FE_UNK00700__ESIZE 0x00000004 +#define VIVS_FE_UNK00700__LEN 0x00000010 + +#define VIVS_FE_UNK00740(i0) (0x00000740 + 0x4*(i0)) +#define VIVS_FE_UNK00740__ESIZE 0x00000004 +#define VIVS_FE_UNK00740__LEN 0x00000010 + +#define VIVS_FE_UNK00780(i0) (0x00000780 + 0x4*(i0)) +#define VIVS_FE_UNK00780__ESIZE 0x00000004 +#define VIVS_FE_UNK00780__LEN 0x00000010 + +#define VIVS_GL 0x00000000 + +#define VIVS_GL_PIPE_SELECT 0x00003800 +#define VIVS_GL_PIPE_SELECT_PIPE__MASK 0x00000001 +#define VIVS_GL_PIPE_SELECT_PIPE__SHIFT 0 +#define VIVS_GL_PIPE_SELECT_PIPE(x) (((x) << VIVS_GL_PIPE_SELECT_PIPE__SHIFT) & VIVS_GL_PIPE_SELECT_PIPE__MASK) + +#define VIVS_GL_EVENT 0x00003804 +#define VIVS_GL_EVENT_EVENT_ID__MASK 0x0000001f +#define VIVS_GL_EVENT_EVENT_ID__SHIFT 0 +#define VIVS_GL_EVENT_EVENT_ID(x) (((x) << VIVS_GL_EVENT_EVENT_ID__SHIFT) & VIVS_GL_EVENT_EVENT_ID__MASK) +#define VIVS_GL_EVENT_FROM_FE 0x00000020 +#define VIVS_GL_EVENT_FROM_PE 0x00000040 +#define VIVS_GL_EVENT_SOURCE__MASK 0x00001f00 +#define VIVS_GL_EVENT_SOURCE__SHIFT 8 +#define VIVS_GL_EVENT_SOURCE(x) (((x) << VIVS_GL_EVENT_SOURCE__SHIFT) & VIVS_GL_EVENT_SOURCE__MASK) + +#define VIVS_GL_SEMAPHORE_TOKEN 0x00003808 +#define VIVS_GL_SEMAPHORE_TOKEN_FROM__MASK 0x0000001f +#define VIVS_GL_SEMAPHORE_TOKEN_FROM__SHIFT 0 +#define VIVS_GL_SEMAPHORE_TOKEN_FROM(x) (((x) << VIVS_GL_SEMAPHORE_TOKEN_FROM__SHIFT) & VIVS_GL_SEMAPHORE_TOKEN_FROM__MASK) +#define VIVS_GL_SEMAPHORE_TOKEN_TO__MASK 0x00001f00 +#define VIVS_GL_SEMAPHORE_TOKEN_TO__SHIFT 8 +#define VIVS_GL_SEMAPHORE_TOKEN_TO(x) (((x) << VIVS_GL_SEMAPHORE_TOKEN_TO__SHIFT) & VIVS_GL_SEMAPHORE_TOKEN_TO__MASK) + +#define VIVS_GL_FLUSH_CACHE 0x0000380c +#define VIVS_GL_FLUSH_CACHE_DEPTH 0x00000001 +#define VIVS_GL_FLUSH_CACHE_COLOR 0x00000002 +#define VIVS_GL_FLUSH_CACHE_TEXTURE 0x00000004 +#define VIVS_GL_FLUSH_CACHE_PE2D 0x00000008 +#define VIVS_GL_FLUSH_CACHE_TEXTUREVS 0x00000010 +#define VIVS_GL_FLUSH_CACHE_SHADER_L1 0x00000020 +#define VIVS_GL_FLUSH_CACHE_SHADER_L2 0x00000040 + +#define VIVS_GL_FLUSH_MMU 0x00003810 +#define VIVS_GL_FLUSH_MMU_FLUSH_FEMMU 0x00000001 +#define VIVS_GL_FLUSH_MMU_FLUSH_UNK1 0x00000002 +#define VIVS_GL_FLUSH_MMU_FLUSH_UNK2 0x00000004 +#define VIVS_GL_FLUSH_MMU_FLUSH_PEMMU 0x00000008 +#define VIVS_GL_FLUSH_MMU_FLUSH_UNK4 0x00000010 + +#define VIVS_GL_VERTEX_ELEMENT_CONFIG 0x00003814 + +#define VIVS_GL_MULTI_SAMPLE_CONFIG 0x00003818 +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES__MASK 0x00000003 +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES__SHIFT 0 +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_NONE 0x00000000 +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_2X 0x00000001 +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_4X 0x00000002 +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_MASK 0x00000008 +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__MASK 0x000000f0 +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__SHIFT 4 +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES(x) (((x) << VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__SHIFT) & VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES__MASK) +#define VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_ENABLES_MASK 0x00000100 +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__MASK 0x00007000 +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__SHIFT 12 +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12(x) (((x) << VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__SHIFT) & VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12__MASK) +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK12_MASK 0x00008000 +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__MASK 0x00030000 +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__SHIFT 16 +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16(x) (((x) << VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__SHIFT) & VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16__MASK) +#define VIVS_GL_MULTI_SAMPLE_CONFIG_UNK16_MASK 0x00080000 + +#define VIVS_GL_VARYING_TOTAL_COMPONENTS 0x0000381c +#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__MASK 0x000000ff +#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__SHIFT 0 +#define VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM(x) (((x) << VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__SHIFT) & VIVS_GL_VARYING_TOTAL_COMPONENTS_NUM__MASK) + +#define VIVS_GL_VARYING_NUM_COMPONENTS 0x00003820 +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__MASK 0x00000007 +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__SHIFT 0 +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR0(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR0__MASK) +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__MASK 0x00000070 +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__SHIFT 4 +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR1(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR1__MASK) +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__MASK 0x00000700 +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__SHIFT 8 +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR2(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR2__MASK) +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__MASK 0x00007000 +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__SHIFT 12 +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR3(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR3__MASK) +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__MASK 0x00070000 +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__SHIFT 16 +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR4(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR4__MASK) +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__MASK 0x00700000 +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__SHIFT 20 +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR5(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR5__MASK) +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__MASK 0x07000000 +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__SHIFT 24 +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR6(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR6__MASK) +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__MASK 0x70000000 +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__SHIFT 28 +#define VIVS_GL_VARYING_NUM_COMPONENTS_VAR7(x) (((x) << VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__SHIFT) & VIVS_GL_VARYING_NUM_COMPONENTS_VAR7__MASK) + +#define VIVS_GL_VARYING_COMPONENT_USE(i0) (0x00003828 + 0x4*(i0)) +#define VIVS_GL_VARYING_COMPONENT_USE__ESIZE 0x00000004 +#define VIVS_GL_VARYING_COMPONENT_USE__LEN 0x00000002 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP0__MASK 0x00000003 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP0__SHIFT 0 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP0(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP0__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP0__MASK) +#define VIVS_GL_VARYING_COMPONENT_USE_COMP1__MASK 0x0000000c +#define VIVS_GL_VARYING_COMPONENT_USE_COMP1__SHIFT 2 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP1(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP1__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP1__MASK) +#define VIVS_GL_VARYING_COMPONENT_USE_COMP2__MASK 0x00000030 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP2__SHIFT 4 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP2(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP2__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP2__MASK) +#define VIVS_GL_VARYING_COMPONENT_USE_COMP3__MASK 0x000000c0 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP3__SHIFT 6 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP3(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP3__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP3__MASK) +#define VIVS_GL_VARYING_COMPONENT_USE_COMP4__MASK 0x00000300 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP4__SHIFT 8 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP4(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP4__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP4__MASK) +#define VIVS_GL_VARYING_COMPONENT_USE_COMP5__MASK 0x00000c00 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP5__SHIFT 10 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP5(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP5__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP5__MASK) +#define VIVS_GL_VARYING_COMPONENT_USE_COMP6__MASK 0x00003000 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP6__SHIFT 12 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP6(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP6__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP6__MASK) +#define VIVS_GL_VARYING_COMPONENT_USE_COMP7__MASK 0x0000c000 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP7__SHIFT 14 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP7(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP7__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP7__MASK) +#define VIVS_GL_VARYING_COMPONENT_USE_COMP8__MASK 0x00030000 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP8__SHIFT 16 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP8(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP8__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP8__MASK) +#define VIVS_GL_VARYING_COMPONENT_USE_COMP9__MASK 0x000c0000 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP9__SHIFT 18 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP9(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP9__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP9__MASK) +#define VIVS_GL_VARYING_COMPONENT_USE_COMP10__MASK 0x00300000 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP10__SHIFT 20 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP10(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP10__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP10__MASK) +#define VIVS_GL_VARYING_COMPONENT_USE_COMP11__MASK 0x00c00000 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP11__SHIFT 22 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP11(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP11__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP11__MASK) +#define VIVS_GL_VARYING_COMPONENT_USE_COMP12__MASK 0x03000000 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP12__SHIFT 24 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP12(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP12__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP12__MASK) +#define VIVS_GL_VARYING_COMPONENT_USE_COMP13__MASK 0x0c000000 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP13__SHIFT 26 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP13(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP13__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP13__MASK) +#define VIVS_GL_VARYING_COMPONENT_USE_COMP14__MASK 0x30000000 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP14__SHIFT 28 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP14(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP14__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP14__MASK) +#define VIVS_GL_VARYING_COMPONENT_USE_COMP15__MASK 0xc0000000 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP15__SHIFT 30 +#define VIVS_GL_VARYING_COMPONENT_USE_COMP15(x) (((x) << VIVS_GL_VARYING_COMPONENT_USE_COMP15__SHIFT) & VIVS_GL_VARYING_COMPONENT_USE_COMP15__MASK) + +#define VIVS_GL_UNK03834 0x00003834 + +#define VIVS_GL_UNK03838 0x00003838 + +#define VIVS_GL_API_MODE 0x0000384c +#define VIVS_GL_API_MODE_OPENGL 0x00000000 +#define VIVS_GL_API_MODE_OPENVG 0x00000001 +#define VIVS_GL_API_MODE_OPENCL 0x00000002 + +#define VIVS_GL_CONTEXT_POINTER 0x00003850 + +#define VIVS_GL_UNK03A00 0x00003a00 + +#define VIVS_GL_STALL_TOKEN 0x00003c00 +#define VIVS_GL_STALL_TOKEN_FROM__MASK 0x0000001f +#define VIVS_GL_STALL_TOKEN_FROM__SHIFT 0 +#define VIVS_GL_STALL_TOKEN_FROM(x) (((x) << VIVS_GL_STALL_TOKEN_FROM__SHIFT) & VIVS_GL_STALL_TOKEN_FROM__MASK) +#define VIVS_GL_STALL_TOKEN_TO__MASK 0x00001f00 +#define VIVS_GL_STALL_TOKEN_TO__SHIFT 8 +#define VIVS_GL_STALL_TOKEN_TO(x) (((x) << VIVS_GL_STALL_TOKEN_TO__SHIFT) & VIVS_GL_STALL_TOKEN_TO__MASK) +#define VIVS_GL_STALL_TOKEN_FLIP0 0x40000000 +#define VIVS_GL_STALL_TOKEN_FLIP1 0x80000000 + +#define VIVS_DUMMY 0x00000000 + +#define VIVS_DUMMY_DUMMY 0x0003fffc + + +#endif /* STATE_XML */ diff --git a/tests/etnaviv/state_2d.xml.h b/tests/etnaviv/state_2d.xml.h new file mode 100644 index 0000000..715eed4 --- /dev/null +++ b/tests/etnaviv/state_2d.xml.h @@ -0,0 +1,1497 @@ +#ifndef STATE_2D_XML +#define STATE_2D_XML + +/* Autogenerated file, DO NOT EDIT manually! + +This file was generated by the rules-ng-ng headergen tool in this git repository: +http://0x04.net/cgit/index.cgi/rules-ng-ng +git clone git://0x04.net/rules-ng-ng + +The rules-ng-ng source files this header was generated from are: +- state.xml ( 18940 bytes, from 2016-09-06 14:14:12) +- common.xml ( 20583 bytes, from 2016-09-06 14:14:12) +- state_hi.xml ( 25653 bytes, from 2016-09-06 14:45:17) +- copyright.xml ( 1597 bytes, from 2016-09-06 14:44:16) +- state_2d.xml ( 51552 bytes, from 2016-09-06 14:44:16) +- state_3d.xml ( 54603 bytes, from 2016-09-06 14:44:16) +- state_vg.xml ( 5975 bytes, from 2016-09-06 14:44:16) + +Copyright (C) 2012-2016 by the following authors: +- Wladimir J. van der Laan +- Christian Gmeiner +- Lucas Stach +- Russell King + +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 +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. +*/ + + +#define DE_FORMAT_X4R4G4B4 0x00000000 +#define DE_FORMAT_A4R4G4B4 0x00000001 +#define DE_FORMAT_X1R5G5B5 0x00000002 +#define DE_FORMAT_A1R5G5B5 0x00000003 +#define DE_FORMAT_R5G6B5 0x00000004 +#define DE_FORMAT_X8R8G8B8 0x00000005 +#define DE_FORMAT_A8R8G8B8 0x00000006 +#define DE_FORMAT_YUY2 0x00000007 +#define DE_FORMAT_UYVY 0x00000008 +#define DE_FORMAT_INDEX8 0x00000009 +#define DE_FORMAT_MONOCHROME 0x0000000a +#define DE_FORMAT_YV12 0x0000000f +#define DE_FORMAT_A8 0x00000010 +#define DE_FORMAT_NV12 0x00000011 +#define DE_FORMAT_NV16 0x00000012 +#define DE_FORMAT_RG16 0x00000013 +#define DE_SWIZZLE_ARGB 0x00000000 +#define DE_SWIZZLE_RGBA 0x00000001 +#define DE_SWIZZLE_ABGR 0x00000002 +#define DE_SWIZZLE_BGRA 0x00000003 +#define DE_BLENDMODE_ZERO 0x00000000 +#define DE_BLENDMODE_ONE 0x00000001 +#define DE_BLENDMODE_NORMAL 0x00000002 +#define DE_BLENDMODE_INVERSED 0x00000003 +#define DE_BLENDMODE_COLOR 0x00000004 +#define DE_BLENDMODE_COLOR_INVERSED 0x00000005 +#define DE_BLENDMODE_SATURATED_ALPHA 0x00000006 +#define DE_BLENDMODE_SATURATED_DEST_ALPHA 0x00000007 +#define DE_COMPONENT_BLUE 0x00000000 +#define DE_COMPONENT_GREEN 0x00000001 +#define DE_COMPONENT_RED 0x00000002 +#define DE_COMPONENT_ALPHA 0x00000003 +#define DE_ROT_MODE_ROT0 0x00000000 +#define DE_ROT_MODE_FLIP_X 0x00000001 +#define DE_ROT_MODE_FLIP_Y 0x00000002 +#define DE_ROT_MODE_ROT90 0x00000004 +#define DE_ROT_MODE_ROT180 0x00000005 +#define DE_ROT_MODE_ROT270 0x00000006 +#define DE_MIRROR_MODE_NONE 0x00000000 +#define DE_MIRROR_MODE_MIRROR_X 0x00000001 +#define DE_MIRROR_MODE_MIRROR_Y 0x00000002 +#define DE_MIRROR_MODE_MIRROR_XY 0x00000003 +#define DE_COLOR_BLUE__MASK 0x000000ff +#define DE_COLOR_BLUE__SHIFT 0 +#define DE_COLOR_BLUE(x) (((x) << DE_COLOR_BLUE__SHIFT) & DE_COLOR_BLUE__MASK) +#define DE_COLOR_GREEN__MASK 0x0000ff00 +#define DE_COLOR_GREEN__SHIFT 8 +#define DE_COLOR_GREEN(x) (((x) << DE_COLOR_GREEN__SHIFT) & DE_COLOR_GREEN__MASK) +#define DE_COLOR_RED__MASK 0x00ff0000 +#define DE_COLOR_RED__SHIFT 16 +#define DE_COLOR_RED(x) (((x) << DE_COLOR_RED__SHIFT) & DE_COLOR_RED__MASK) +#define DE_COLOR_ALPHA__MASK 0xff000000 +#define DE_COLOR_ALPHA__SHIFT 24 +#define DE_COLOR_ALPHA(x) (((x) << DE_COLOR_ALPHA__SHIFT) & DE_COLOR_ALPHA__MASK) +#define VIVS_DE 0x00000000 + +#define VIVS_DE_SRC_ADDRESS 0x00001200 + +#define VIVS_DE_SRC_STRIDE 0x00001204 +#define VIVS_DE_SRC_STRIDE_STRIDE__MASK 0x0003ffff +#define VIVS_DE_SRC_STRIDE_STRIDE__SHIFT 0 +#define VIVS_DE_SRC_STRIDE_STRIDE(x) (((x) << VIVS_DE_SRC_STRIDE_STRIDE__SHIFT) & VIVS_DE_SRC_STRIDE_STRIDE__MASK) + +#define VIVS_DE_SRC_ROTATION_CONFIG 0x00001208 +#define VIVS_DE_SRC_ROTATION_CONFIG_WIDTH__MASK 0x0000ffff +#define VIVS_DE_SRC_ROTATION_CONFIG_WIDTH__SHIFT 0 +#define VIVS_DE_SRC_ROTATION_CONFIG_WIDTH(x) (((x) << VIVS_DE_SRC_ROTATION_CONFIG_WIDTH__SHIFT) & VIVS_DE_SRC_ROTATION_CONFIG_WIDTH__MASK) +#define VIVS_DE_SRC_ROTATION_CONFIG_ROTATION__MASK 0x00010000 +#define VIVS_DE_SRC_ROTATION_CONFIG_ROTATION__SHIFT 16 +#define VIVS_DE_SRC_ROTATION_CONFIG_ROTATION_DISABLE 0x00000000 +#define VIVS_DE_SRC_ROTATION_CONFIG_ROTATION_ENABLE 0x00010000 + +#define VIVS_DE_SRC_CONFIG 0x0000120c +#define VIVS_DE_SRC_CONFIG_PE10_SOURCE_FORMAT__MASK 0x0000000f +#define VIVS_DE_SRC_CONFIG_PE10_SOURCE_FORMAT__SHIFT 0 +#define VIVS_DE_SRC_CONFIG_PE10_SOURCE_FORMAT(x) (((x) << VIVS_DE_SRC_CONFIG_PE10_SOURCE_FORMAT__SHIFT) & VIVS_DE_SRC_CONFIG_PE10_SOURCE_FORMAT__MASK) +#define VIVS_DE_SRC_CONFIG_TRANSPARENCY__MASK 0x00000030 +#define VIVS_DE_SRC_CONFIG_TRANSPARENCY__SHIFT 4 +#define VIVS_DE_SRC_CONFIG_TRANSPARENCY(x) (((x) << VIVS_DE_SRC_CONFIG_TRANSPARENCY__SHIFT) & VIVS_DE_SRC_CONFIG_TRANSPARENCY__MASK) +#define VIVS_DE_SRC_CONFIG_SRC_RELATIVE__MASK 0x00000040 +#define VIVS_DE_SRC_CONFIG_SRC_RELATIVE__SHIFT 6 +#define VIVS_DE_SRC_CONFIG_SRC_RELATIVE_ABSOLUTE 0x00000000 +#define VIVS_DE_SRC_CONFIG_SRC_RELATIVE_RELATIVE 0x00000040 +#define VIVS_DE_SRC_CONFIG_TILED__MASK 0x00000080 +#define VIVS_DE_SRC_CONFIG_TILED__SHIFT 7 +#define VIVS_DE_SRC_CONFIG_TILED_DISABLE 0x00000000 +#define VIVS_DE_SRC_CONFIG_TILED_ENABLE 0x00000080 +#define VIVS_DE_SRC_CONFIG_LOCATION__MASK 0x00000100 +#define VIVS_DE_SRC_CONFIG_LOCATION__SHIFT 8 +#define VIVS_DE_SRC_CONFIG_LOCATION_MEMORY 0x00000000 +#define VIVS_DE_SRC_CONFIG_LOCATION_STREAM 0x00000100 +#define VIVS_DE_SRC_CONFIG_PACK__MASK 0x00003000 +#define VIVS_DE_SRC_CONFIG_PACK__SHIFT 12 +#define VIVS_DE_SRC_CONFIG_PACK_PACKED8 0x00000000 +#define VIVS_DE_SRC_CONFIG_PACK_PACKED16 0x00001000 +#define VIVS_DE_SRC_CONFIG_PACK_PACKED32 0x00002000 +#define VIVS_DE_SRC_CONFIG_PACK_UNPACKED 0x00003000 +#define VIVS_DE_SRC_CONFIG_MONO_TRANSPARENCY__MASK 0x00008000 +#define VIVS_DE_SRC_CONFIG_MONO_TRANSPARENCY__SHIFT 15 +#define VIVS_DE_SRC_CONFIG_MONO_TRANSPARENCY_BACKGROUND 0x00000000 +#define VIVS_DE_SRC_CONFIG_MONO_TRANSPARENCY_FOREGROUND 0x00008000 +#define VIVS_DE_SRC_CONFIG_UNK16 0x00010000 +#define VIVS_DE_SRC_CONFIG_SWIZZLE__MASK 0x00300000 +#define VIVS_DE_SRC_CONFIG_SWIZZLE__SHIFT 20 +#define VIVS_DE_SRC_CONFIG_SWIZZLE(x) (((x) << VIVS_DE_SRC_CONFIG_SWIZZLE__SHIFT) & VIVS_DE_SRC_CONFIG_SWIZZLE__MASK) +#define VIVS_DE_SRC_CONFIG_SOURCE_FORMAT__MASK 0x1f000000 +#define VIVS_DE_SRC_CONFIG_SOURCE_FORMAT__SHIFT 24 +#define VIVS_DE_SRC_CONFIG_SOURCE_FORMAT(x) (((x) << VIVS_DE_SRC_CONFIG_SOURCE_FORMAT__SHIFT) & VIVS_DE_SRC_CONFIG_SOURCE_FORMAT__MASK) +#define VIVS_DE_SRC_CONFIG_DISABLE420_L2_CACHE 0x20000000 +#define VIVS_DE_SRC_CONFIG_ENDIAN_CONTROL__MASK 0xc0000000 +#define VIVS_DE_SRC_CONFIG_ENDIAN_CONTROL__SHIFT 30 +#define VIVS_DE_SRC_CONFIG_ENDIAN_CONTROL(x) (((x) << VIVS_DE_SRC_CONFIG_ENDIAN_CONTROL__SHIFT) & VIVS_DE_SRC_CONFIG_ENDIAN_CONTROL__MASK) + +#define VIVS_DE_SRC_ORIGIN 0x00001210 +#define VIVS_DE_SRC_ORIGIN_X__MASK 0x0000ffff +#define VIVS_DE_SRC_ORIGIN_X__SHIFT 0 +#define VIVS_DE_SRC_ORIGIN_X(x) (((x) << VIVS_DE_SRC_ORIGIN_X__SHIFT) & VIVS_DE_SRC_ORIGIN_X__MASK) +#define VIVS_DE_SRC_ORIGIN_Y__MASK 0xffff0000 +#define VIVS_DE_SRC_ORIGIN_Y__SHIFT 16 +#define VIVS_DE_SRC_ORIGIN_Y(x) (((x) << VIVS_DE_SRC_ORIGIN_Y__SHIFT) & VIVS_DE_SRC_ORIGIN_Y__MASK) + +#define VIVS_DE_SRC_SIZE 0x00001214 +#define VIVS_DE_SRC_SIZE_X__MASK 0x0000ffff +#define VIVS_DE_SRC_SIZE_X__SHIFT 0 +#define VIVS_DE_SRC_SIZE_X(x) (((x) << VIVS_DE_SRC_SIZE_X__SHIFT) & VIVS_DE_SRC_SIZE_X__MASK) +#define VIVS_DE_SRC_SIZE_Y__MASK 0xffff0000 +#define VIVS_DE_SRC_SIZE_Y__SHIFT 16 +#define VIVS_DE_SRC_SIZE_Y(x) (((x) << VIVS_DE_SRC_SIZE_Y__SHIFT) & VIVS_DE_SRC_SIZE_Y__MASK) + +#define VIVS_DE_SRC_COLOR_BG 0x00001218 + +#define VIVS_DE_SRC_COLOR_FG 0x0000121c + +#define VIVS_DE_STRETCH_FACTOR_LOW 0x00001220 +#define VIVS_DE_STRETCH_FACTOR_LOW_X__MASK 0x7fffffff +#define VIVS_DE_STRETCH_FACTOR_LOW_X__SHIFT 0 +#define VIVS_DE_STRETCH_FACTOR_LOW_X(x) (((x) << VIVS_DE_STRETCH_FACTOR_LOW_X__SHIFT) & VIVS_DE_STRETCH_FACTOR_LOW_X__MASK) + +#define VIVS_DE_STRETCH_FACTOR_HIGH 0x00001224 +#define VIVS_DE_STRETCH_FACTOR_HIGH_Y__MASK 0x7fffffff +#define VIVS_DE_STRETCH_FACTOR_HIGH_Y__SHIFT 0 +#define VIVS_DE_STRETCH_FACTOR_HIGH_Y(x) (((x) << VIVS_DE_STRETCH_FACTOR_HIGH_Y__SHIFT) & VIVS_DE_STRETCH_FACTOR_HIGH_Y__MASK) + +#define VIVS_DE_DEST_ADDRESS 0x00001228 + +#define VIVS_DE_DEST_STRIDE 0x0000122c +#define VIVS_DE_DEST_STRIDE_STRIDE__MASK 0x0003ffff +#define VIVS_DE_DEST_STRIDE_STRIDE__SHIFT 0 +#define VIVS_DE_DEST_STRIDE_STRIDE(x) (((x) << VIVS_DE_DEST_STRIDE_STRIDE__SHIFT) & VIVS_DE_DEST_STRIDE_STRIDE__MASK) + +#define VIVS_DE_DEST_ROTATION_CONFIG 0x00001230 +#define VIVS_DE_DEST_ROTATION_CONFIG_WIDTH__MASK 0x0000ffff +#define VIVS_DE_DEST_ROTATION_CONFIG_WIDTH__SHIFT 0 +#define VIVS_DE_DEST_ROTATION_CONFIG_WIDTH(x) (((x) << VIVS_DE_DEST_ROTATION_CONFIG_WIDTH__SHIFT) & VIVS_DE_DEST_ROTATION_CONFIG_WIDTH__MASK) +#define VIVS_DE_DEST_ROTATION_CONFIG_ROTATION__MASK 0x00010000 +#define VIVS_DE_DEST_ROTATION_CONFIG_ROTATION__SHIFT 16 +#define VIVS_DE_DEST_ROTATION_CONFIG_ROTATION_DISABLE 0x00000000 +#define VIVS_DE_DEST_ROTATION_CONFIG_ROTATION_ENABLE 0x00010000 + +#define VIVS_DE_DEST_CONFIG 0x00001234 +#define VIVS_DE_DEST_CONFIG_FORMAT__MASK 0x0000001f +#define VIVS_DE_DEST_CONFIG_FORMAT__SHIFT 0 +#define VIVS_DE_DEST_CONFIG_FORMAT(x) (((x) << VIVS_DE_DEST_CONFIG_FORMAT__SHIFT) & VIVS_DE_DEST_CONFIG_FORMAT__MASK) +#define VIVS_DE_DEST_CONFIG_TILED__MASK 0x00000100 +#define VIVS_DE_DEST_CONFIG_TILED__SHIFT 8 +#define VIVS_DE_DEST_CONFIG_TILED_DISABLE 0x00000000 +#define VIVS_DE_DEST_CONFIG_TILED_ENABLE 0x00000100 +#define VIVS_DE_DEST_CONFIG_COMMAND__MASK 0x0000f000 +#define VIVS_DE_DEST_CONFIG_COMMAND__SHIFT 12 +#define VIVS_DE_DEST_CONFIG_COMMAND_CLEAR 0x00000000 +#define VIVS_DE_DEST_CONFIG_COMMAND_LINE 0x00001000 +#define VIVS_DE_DEST_CONFIG_COMMAND_BIT_BLT 0x00002000 +#define VIVS_DE_DEST_CONFIG_COMMAND_BIT_BLT_REVERSED 0x00003000 +#define VIVS_DE_DEST_CONFIG_COMMAND_STRETCH_BLT 0x00004000 +#define VIVS_DE_DEST_CONFIG_COMMAND_HOR_FILTER_BLT 0x00005000 +#define VIVS_DE_DEST_CONFIG_COMMAND_VER_FILTER_BLT 0x00006000 +#define VIVS_DE_DEST_CONFIG_COMMAND_ONE_PASS_FILTER_BLT 0x00007000 +#define VIVS_DE_DEST_CONFIG_COMMAND_MULTI_SOURCE_BLT 0x00008000 +#define VIVS_DE_DEST_CONFIG_SWIZZLE__MASK 0x00030000 +#define VIVS_DE_DEST_CONFIG_SWIZZLE__SHIFT 16 +#define VIVS_DE_DEST_CONFIG_SWIZZLE(x) (((x) << VIVS_DE_DEST_CONFIG_SWIZZLE__SHIFT) & VIVS_DE_DEST_CONFIG_SWIZZLE__MASK) +#define VIVS_DE_DEST_CONFIG_ENDIAN_CONTROL__MASK 0x00300000 +#define VIVS_DE_DEST_CONFIG_ENDIAN_CONTROL__SHIFT 20 +#define VIVS_DE_DEST_CONFIG_ENDIAN_CONTROL(x) (((x) << VIVS_DE_DEST_CONFIG_ENDIAN_CONTROL__SHIFT) & VIVS_DE_DEST_CONFIG_ENDIAN_CONTROL__MASK) +#define VIVS_DE_DEST_CONFIG_GDI_STRE__MASK 0x01000000 +#define VIVS_DE_DEST_CONFIG_GDI_STRE__SHIFT 24 +#define VIVS_DE_DEST_CONFIG_GDI_STRE_DISABLE 0x00000000 +#define VIVS_DE_DEST_CONFIG_GDI_STRE_ENABLE 0x01000000 +#define VIVS_DE_DEST_CONFIG_INTER_TILE_PER_FIX__MASK 0x02000000 +#define VIVS_DE_DEST_CONFIG_INTER_TILE_PER_FIX__SHIFT 25 +#define VIVS_DE_DEST_CONFIG_INTER_TILE_PER_FIX_DISABLED 0x02000000 +#define VIVS_DE_DEST_CONFIG_INTER_TILE_PER_FIX_ENABLED 0x00000000 +#define VIVS_DE_DEST_CONFIG_MINOR_TILED__MASK 0x04000000 +#define VIVS_DE_DEST_CONFIG_MINOR_TILED__SHIFT 26 +#define VIVS_DE_DEST_CONFIG_MINOR_TILED_DISABLE 0x00000000 +#define VIVS_DE_DEST_CONFIG_MINOR_TILED_ENABLE 0x04000000 + +#define VIVS_DE_PATTERN_ADDRESS 0x00001238 + +#define VIVS_DE_PATTERN_CONFIG 0x0000123c +#define VIVS_DE_PATTERN_CONFIG_FORMAT__MASK 0x0000000f +#define VIVS_DE_PATTERN_CONFIG_FORMAT__SHIFT 0 +#define VIVS_DE_PATTERN_CONFIG_FORMAT(x) (((x) << VIVS_DE_PATTERN_CONFIG_FORMAT__SHIFT) & VIVS_DE_PATTERN_CONFIG_FORMAT__MASK) +#define VIVS_DE_PATTERN_CONFIG_TYPE__MASK 0x00000010 +#define VIVS_DE_PATTERN_CONFIG_TYPE__SHIFT 4 +#define VIVS_DE_PATTERN_CONFIG_TYPE_SOLID_COLOR 0x00000000 +#define VIVS_DE_PATTERN_CONFIG_TYPE_PATTERN 0x00000010 +#define VIVS_DE_PATTERN_CONFIG_COLOR_CONVERT__MASK 0x00000020 +#define VIVS_DE_PATTERN_CONFIG_COLOR_CONVERT__SHIFT 5 +#define VIVS_DE_PATTERN_CONFIG_COLOR_CONVERT_DISABLE 0x00000000 +#define VIVS_DE_PATTERN_CONFIG_COLOR_CONVERT_ENABLE 0x00000020 +#define VIVS_DE_PATTERN_CONFIG_INIT_TRIGGER__MASK 0x000000c0 +#define VIVS_DE_PATTERN_CONFIG_INIT_TRIGGER__SHIFT 6 +#define VIVS_DE_PATTERN_CONFIG_INIT_TRIGGER(x) (((x) << VIVS_DE_PATTERN_CONFIG_INIT_TRIGGER__SHIFT) & VIVS_DE_PATTERN_CONFIG_INIT_TRIGGER__MASK) +#define VIVS_DE_PATTERN_CONFIG_ORIGIN_X__MASK 0x00070000 +#define VIVS_DE_PATTERN_CONFIG_ORIGIN_X__SHIFT 16 +#define VIVS_DE_PATTERN_CONFIG_ORIGIN_X(x) (((x) << VIVS_DE_PATTERN_CONFIG_ORIGIN_X__SHIFT) & VIVS_DE_PATTERN_CONFIG_ORIGIN_X__MASK) +#define VIVS_DE_PATTERN_CONFIG_ORIGIN_Y__MASK 0x00700000 +#define VIVS_DE_PATTERN_CONFIG_ORIGIN_Y__SHIFT 20 +#define VIVS_DE_PATTERN_CONFIG_ORIGIN_Y(x) (((x) << VIVS_DE_PATTERN_CONFIG_ORIGIN_Y__SHIFT) & VIVS_DE_PATTERN_CONFIG_ORIGIN_Y__MASK) + +#define VIVS_DE_PATTERN_LOW 0x00001240 + +#define VIVS_DE_PATTERN_HIGH 0x00001244 + +#define VIVS_DE_PATTERN_MASK_LOW 0x00001248 + +#define VIVS_DE_PATTERN_MASK_HIGH 0x0000124c + +#define VIVS_DE_PATTERN_BG_COLOR 0x00001250 + +#define VIVS_DE_PATTERN_FG_COLOR 0x00001254 + +#define VIVS_DE_ROP 0x0000125c +#define VIVS_DE_ROP_ROP_FG__MASK 0x000000ff +#define VIVS_DE_ROP_ROP_FG__SHIFT 0 +#define VIVS_DE_ROP_ROP_FG(x) (((x) << VIVS_DE_ROP_ROP_FG__SHIFT) & VIVS_DE_ROP_ROP_FG__MASK) +#define VIVS_DE_ROP_ROP_BG__MASK 0x0000ff00 +#define VIVS_DE_ROP_ROP_BG__SHIFT 8 +#define VIVS_DE_ROP_ROP_BG(x) (((x) << VIVS_DE_ROP_ROP_BG__SHIFT) & VIVS_DE_ROP_ROP_BG__MASK) +#define VIVS_DE_ROP_TYPE__MASK 0x00300000 +#define VIVS_DE_ROP_TYPE__SHIFT 20 +#define VIVS_DE_ROP_TYPE_ROP2_PATTERN 0x00000000 +#define VIVS_DE_ROP_TYPE_ROP2_SOURCE 0x00100000 +#define VIVS_DE_ROP_TYPE_ROP3 0x00200000 +#define VIVS_DE_ROP_TYPE_ROP4 0x00300000 + +#define VIVS_DE_CLIP_TOP_LEFT 0x00001260 +#define VIVS_DE_CLIP_TOP_LEFT_X__MASK 0x00007fff +#define VIVS_DE_CLIP_TOP_LEFT_X__SHIFT 0 +#define VIVS_DE_CLIP_TOP_LEFT_X(x) (((x) << VIVS_DE_CLIP_TOP_LEFT_X__SHIFT) & VIVS_DE_CLIP_TOP_LEFT_X__MASK) +#define VIVS_DE_CLIP_TOP_LEFT_Y__MASK 0x7fff0000 +#define VIVS_DE_CLIP_TOP_LEFT_Y__SHIFT 16 +#define VIVS_DE_CLIP_TOP_LEFT_Y(x) (((x) << VIVS_DE_CLIP_TOP_LEFT_Y__SHIFT) & VIVS_DE_CLIP_TOP_LEFT_Y__MASK) + +#define VIVS_DE_CLIP_BOTTOM_RIGHT 0x00001264 +#define VIVS_DE_CLIP_BOTTOM_RIGHT_X__MASK 0x00007fff +#define VIVS_DE_CLIP_BOTTOM_RIGHT_X__SHIFT 0 +#define VIVS_DE_CLIP_BOTTOM_RIGHT_X(x) (((x) << VIVS_DE_CLIP_BOTTOM_RIGHT_X__SHIFT) & VIVS_DE_CLIP_BOTTOM_RIGHT_X__MASK) +#define VIVS_DE_CLIP_BOTTOM_RIGHT_Y__MASK 0x7fff0000 +#define VIVS_DE_CLIP_BOTTOM_RIGHT_Y__SHIFT 16 +#define VIVS_DE_CLIP_BOTTOM_RIGHT_Y(x) (((x) << VIVS_DE_CLIP_BOTTOM_RIGHT_Y__SHIFT) & VIVS_DE_CLIP_BOTTOM_RIGHT_Y__MASK) + +#define VIVS_DE_CLEAR_BYTE_MASK 0x00001268 + +#define VIVS_DE_CONFIG 0x0000126c +#define VIVS_DE_CONFIG_MIRROR_BLT_ENABLE__MASK 0x00000001 +#define VIVS_DE_CONFIG_MIRROR_BLT_ENABLE__SHIFT 0 +#define VIVS_DE_CONFIG_MIRROR_BLT_ENABLE_OFF 0x00000000 +#define VIVS_DE_CONFIG_MIRROR_BLT_ENABLE_ON 0x00000001 +#define VIVS_DE_CONFIG_MIRROR_BLT_MODE__MASK 0x00000030 +#define VIVS_DE_CONFIG_MIRROR_BLT_MODE__SHIFT 4 +#define VIVS_DE_CONFIG_MIRROR_BLT_MODE_NORMAL 0x00000000 +#define VIVS_DE_CONFIG_MIRROR_BLT_MODE_HMIRROR 0x00000010 +#define VIVS_DE_CONFIG_MIRROR_BLT_MODE_VMIRROR 0x00000020 +#define VIVS_DE_CONFIG_MIRROR_BLT_MODE_FULL_MIRROR 0x00000030 +#define VIVS_DE_CONFIG_SOURCE_SELECT__MASK 0x00070000 +#define VIVS_DE_CONFIG_SOURCE_SELECT__SHIFT 16 +#define VIVS_DE_CONFIG_SOURCE_SELECT(x) (((x) << VIVS_DE_CONFIG_SOURCE_SELECT__SHIFT) & VIVS_DE_CONFIG_SOURCE_SELECT__MASK) +#define VIVS_DE_CONFIG_DESTINATION_SELECT__MASK 0x00300000 +#define VIVS_DE_CONFIG_DESTINATION_SELECT__SHIFT 20 +#define VIVS_DE_CONFIG_DESTINATION_SELECT(x) (((x) << VIVS_DE_CONFIG_DESTINATION_SELECT__SHIFT) & VIVS_DE_CONFIG_DESTINATION_SELECT__MASK) + +#define VIVS_DE_CLEAR_PIXEL_VALUE_LOW 0x00001270 + +#define VIVS_DE_CLEAR_PIXEL_VALUE_HIGH 0x00001274 + +#define VIVS_DE_SRC_ORIGIN_FRACTION 0x00001278 +#define VIVS_DE_SRC_ORIGIN_FRACTION_X__MASK 0x0000ffff +#define VIVS_DE_SRC_ORIGIN_FRACTION_X__SHIFT 0 +#define VIVS_DE_SRC_ORIGIN_FRACTION_X(x) (((x) << VIVS_DE_SRC_ORIGIN_FRACTION_X__SHIFT) & VIVS_DE_SRC_ORIGIN_FRACTION_X__MASK) +#define VIVS_DE_SRC_ORIGIN_FRACTION_Y__MASK 0xffff0000 +#define VIVS_DE_SRC_ORIGIN_FRACTION_Y__SHIFT 16 +#define VIVS_DE_SRC_ORIGIN_FRACTION_Y(x) (((x) << VIVS_DE_SRC_ORIGIN_FRACTION_Y__SHIFT) & VIVS_DE_SRC_ORIGIN_FRACTION_Y__MASK) + +#define VIVS_DE_ALPHA_CONTROL 0x0000127c +#define VIVS_DE_ALPHA_CONTROL_ENABLE__MASK 0x00000001 +#define VIVS_DE_ALPHA_CONTROL_ENABLE__SHIFT 0 +#define VIVS_DE_ALPHA_CONTROL_ENABLE_OFF 0x00000000 +#define VIVS_DE_ALPHA_CONTROL_ENABLE_ON 0x00000001 +#define VIVS_DE_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__MASK 0x00ff0000 +#define VIVS_DE_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__SHIFT 16 +#define VIVS_DE_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA(x) (((x) << VIVS_DE_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__SHIFT) & VIVS_DE_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__MASK) +#define VIVS_DE_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__MASK 0xff000000 +#define VIVS_DE_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__SHIFT 24 +#define VIVS_DE_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA(x) (((x) << VIVS_DE_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__SHIFT) & VIVS_DE_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__MASK) + +#define VIVS_DE_ALPHA_MODES 0x00001280 +#define VIVS_DE_ALPHA_MODES_SRC_ALPHA_MODE__MASK 0x00000001 +#define VIVS_DE_ALPHA_MODES_SRC_ALPHA_MODE__SHIFT 0 +#define VIVS_DE_ALPHA_MODES_SRC_ALPHA_MODE_NORMAL 0x00000000 +#define VIVS_DE_ALPHA_MODES_SRC_ALPHA_MODE_INVERSED 0x00000001 +#define VIVS_DE_ALPHA_MODES_DST_ALPHA_MODE__MASK 0x00000010 +#define VIVS_DE_ALPHA_MODES_DST_ALPHA_MODE__SHIFT 4 +#define VIVS_DE_ALPHA_MODES_DST_ALPHA_MODE_NORMAL 0x00000000 +#define VIVS_DE_ALPHA_MODES_DST_ALPHA_MODE_INVERSED 0x00000010 +#define VIVS_DE_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE__MASK 0x00000300 +#define VIVS_DE_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE__SHIFT 8 +#define VIVS_DE_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE_NORMAL 0x00000000 +#define VIVS_DE_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE_GLOBAL 0x00000100 +#define VIVS_DE_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE_SCALED 0x00000200 +#define VIVS_DE_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE__MASK 0x00003000 +#define VIVS_DE_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE__SHIFT 12 +#define VIVS_DE_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE_NORMAL 0x00000000 +#define VIVS_DE_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE_GLOBAL 0x00001000 +#define VIVS_DE_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE_SCALED 0x00002000 +#define VIVS_DE_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY__MASK 0x00010000 +#define VIVS_DE_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY__SHIFT 16 +#define VIVS_DE_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY_DISABLE 0x00000000 +#define VIVS_DE_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY_ENABLE 0x00010000 +#define VIVS_DE_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY__MASK 0x00100000 +#define VIVS_DE_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY__SHIFT 20 +#define VIVS_DE_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY_DISABLE 0x00000000 +#define VIVS_DE_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY_ENABLE 0x00100000 +#define VIVS_DE_ALPHA_MODES_SRC_BLENDING_MODE__MASK 0x07000000 +#define VIVS_DE_ALPHA_MODES_SRC_BLENDING_MODE__SHIFT 24 +#define VIVS_DE_ALPHA_MODES_SRC_BLENDING_MODE(x) (((x) << VIVS_DE_ALPHA_MODES_SRC_BLENDING_MODE__SHIFT) & VIVS_DE_ALPHA_MODES_SRC_BLENDING_MODE__MASK) +#define VIVS_DE_ALPHA_MODES_SRC_ALPHA_FACTOR__MASK 0x08000000 +#define VIVS_DE_ALPHA_MODES_SRC_ALPHA_FACTOR__SHIFT 27 +#define VIVS_DE_ALPHA_MODES_SRC_ALPHA_FACTOR_DISABLE 0x00000000 +#define VIVS_DE_ALPHA_MODES_SRC_ALPHA_FACTOR_ENABLE 0x08000000 +#define VIVS_DE_ALPHA_MODES_DST_BLENDING_MODE__MASK 0x70000000 +#define VIVS_DE_ALPHA_MODES_DST_BLENDING_MODE__SHIFT 28 +#define VIVS_DE_ALPHA_MODES_DST_BLENDING_MODE(x) (((x) << VIVS_DE_ALPHA_MODES_DST_BLENDING_MODE__SHIFT) & VIVS_DE_ALPHA_MODES_DST_BLENDING_MODE__MASK) +#define VIVS_DE_ALPHA_MODES_DST_ALPHA_FACTOR__MASK 0x80000000 +#define VIVS_DE_ALPHA_MODES_DST_ALPHA_FACTOR__SHIFT 31 +#define VIVS_DE_ALPHA_MODES_DST_ALPHA_FACTOR_DISABLE 0x00000000 +#define VIVS_DE_ALPHA_MODES_DST_ALPHA_FACTOR_ENABLE 0x80000000 + +#define VIVS_DE_UPLANE_ADDRESS 0x00001284 + +#define VIVS_DE_UPLANE_STRIDE 0x00001288 +#define VIVS_DE_UPLANE_STRIDE_STRIDE__MASK 0x0003ffff +#define VIVS_DE_UPLANE_STRIDE_STRIDE__SHIFT 0 +#define VIVS_DE_UPLANE_STRIDE_STRIDE(x) (((x) << VIVS_DE_UPLANE_STRIDE_STRIDE__SHIFT) & VIVS_DE_UPLANE_STRIDE_STRIDE__MASK) + +#define VIVS_DE_VPLANE_ADDRESS 0x0000128c + +#define VIVS_DE_VPLANE_STRIDE 0x00001290 +#define VIVS_DE_VPLANE_STRIDE_STRIDE__MASK 0x0003ffff +#define VIVS_DE_VPLANE_STRIDE_STRIDE__SHIFT 0 +#define VIVS_DE_VPLANE_STRIDE_STRIDE(x) (((x) << VIVS_DE_VPLANE_STRIDE_STRIDE__SHIFT) & VIVS_DE_VPLANE_STRIDE_STRIDE__MASK) + +#define VIVS_DE_VR_CONFIG 0x00001294 +#define VIVS_DE_VR_CONFIG_START__MASK 0x00000003 +#define VIVS_DE_VR_CONFIG_START__SHIFT 0 +#define VIVS_DE_VR_CONFIG_START_HORIZONTAL_BLIT 0x00000000 +#define VIVS_DE_VR_CONFIG_START_VERTICAL_BLIT 0x00000001 +#define VIVS_DE_VR_CONFIG_START_ONE_PASS_BLIT 0x00000002 +#define VIVS_DE_VR_CONFIG_START_MASK 0x00000008 + +#define VIVS_DE_VR_SOURCE_IMAGE_LOW 0x00001298 +#define VIVS_DE_VR_SOURCE_IMAGE_LOW_LEFT__MASK 0x0000ffff +#define VIVS_DE_VR_SOURCE_IMAGE_LOW_LEFT__SHIFT 0 +#define VIVS_DE_VR_SOURCE_IMAGE_LOW_LEFT(x) (((x) << VIVS_DE_VR_SOURCE_IMAGE_LOW_LEFT__SHIFT) & VIVS_DE_VR_SOURCE_IMAGE_LOW_LEFT__MASK) +#define VIVS_DE_VR_SOURCE_IMAGE_LOW_TOP__MASK 0xffff0000 +#define VIVS_DE_VR_SOURCE_IMAGE_LOW_TOP__SHIFT 16 +#define VIVS_DE_VR_SOURCE_IMAGE_LOW_TOP(x) (((x) << VIVS_DE_VR_SOURCE_IMAGE_LOW_TOP__SHIFT) & VIVS_DE_VR_SOURCE_IMAGE_LOW_TOP__MASK) + +#define VIVS_DE_VR_SOURCE_IMAGE_HIGH 0x0000129c +#define VIVS_DE_VR_SOURCE_IMAGE_HIGH_RIGHT__MASK 0x0000ffff +#define VIVS_DE_VR_SOURCE_IMAGE_HIGH_RIGHT__SHIFT 0 +#define VIVS_DE_VR_SOURCE_IMAGE_HIGH_RIGHT(x) (((x) << VIVS_DE_VR_SOURCE_IMAGE_HIGH_RIGHT__SHIFT) & VIVS_DE_VR_SOURCE_IMAGE_HIGH_RIGHT__MASK) +#define VIVS_DE_VR_SOURCE_IMAGE_HIGH_BOTTOM__MASK 0xffff0000 +#define VIVS_DE_VR_SOURCE_IMAGE_HIGH_BOTTOM__SHIFT 16 +#define VIVS_DE_VR_SOURCE_IMAGE_HIGH_BOTTOM(x) (((x) << VIVS_DE_VR_SOURCE_IMAGE_HIGH_BOTTOM__SHIFT) & VIVS_DE_VR_SOURCE_IMAGE_HIGH_BOTTOM__MASK) + +#define VIVS_DE_VR_SOURCE_ORIGIN_LOW 0x000012a0 +#define VIVS_DE_VR_SOURCE_ORIGIN_LOW_X__MASK 0xffffffff +#define VIVS_DE_VR_SOURCE_ORIGIN_LOW_X__SHIFT 0 +#define VIVS_DE_VR_SOURCE_ORIGIN_LOW_X(x) (((x) << VIVS_DE_VR_SOURCE_ORIGIN_LOW_X__SHIFT) & VIVS_DE_VR_SOURCE_ORIGIN_LOW_X__MASK) + +#define VIVS_DE_VR_SOURCE_ORIGIN_HIGH 0x000012a4 +#define VIVS_DE_VR_SOURCE_ORIGIN_HIGH_Y__MASK 0xffffffff +#define VIVS_DE_VR_SOURCE_ORIGIN_HIGH_Y__SHIFT 0 +#define VIVS_DE_VR_SOURCE_ORIGIN_HIGH_Y(x) (((x) << VIVS_DE_VR_SOURCE_ORIGIN_HIGH_Y__SHIFT) & VIVS_DE_VR_SOURCE_ORIGIN_HIGH_Y__MASK) + +#define VIVS_DE_VR_TARGET_WINDOW_LOW 0x000012a8 +#define VIVS_DE_VR_TARGET_WINDOW_LOW_LEFT__MASK 0x0000ffff +#define VIVS_DE_VR_TARGET_WINDOW_LOW_LEFT__SHIFT 0 +#define VIVS_DE_VR_TARGET_WINDOW_LOW_LEFT(x) (((x) << VIVS_DE_VR_TARGET_WINDOW_LOW_LEFT__SHIFT) & VIVS_DE_VR_TARGET_WINDOW_LOW_LEFT__MASK) +#define VIVS_DE_VR_TARGET_WINDOW_LOW_TOP__MASK 0xffff0000 +#define VIVS_DE_VR_TARGET_WINDOW_LOW_TOP__SHIFT 16 +#define VIVS_DE_VR_TARGET_WINDOW_LOW_TOP(x) (((x) << VIVS_DE_VR_TARGET_WINDOW_LOW_TOP__SHIFT) & VIVS_DE_VR_TARGET_WINDOW_LOW_TOP__MASK) + +#define VIVS_DE_VR_TARGET_WINDOW_HIGH 0x000012ac +#define VIVS_DE_VR_TARGET_WINDOW_HIGH_RIGHT__MASK 0x0000ffff +#define VIVS_DE_VR_TARGET_WINDOW_HIGH_RIGHT__SHIFT 0 +#define VIVS_DE_VR_TARGET_WINDOW_HIGH_RIGHT(x) (((x) << VIVS_DE_VR_TARGET_WINDOW_HIGH_RIGHT__SHIFT) & VIVS_DE_VR_TARGET_WINDOW_HIGH_RIGHT__MASK) +#define VIVS_DE_VR_TARGET_WINDOW_HIGH_BOTTOM__MASK 0xffff0000 +#define VIVS_DE_VR_TARGET_WINDOW_HIGH_BOTTOM__SHIFT 16 +#define VIVS_DE_VR_TARGET_WINDOW_HIGH_BOTTOM(x) (((x) << VIVS_DE_VR_TARGET_WINDOW_HIGH_BOTTOM__SHIFT) & VIVS_DE_VR_TARGET_WINDOW_HIGH_BOTTOM__MASK) + +#define VIVS_DE_PE_CONFIG 0x000012b0 +#define VIVS_DE_PE_CONFIG_DESTINATION_FETCH__MASK 0x00000003 +#define VIVS_DE_PE_CONFIG_DESTINATION_FETCH__SHIFT 0 +#define VIVS_DE_PE_CONFIG_DESTINATION_FETCH_DISABLE 0x00000000 +#define VIVS_DE_PE_CONFIG_DESTINATION_FETCH_DEFAULT 0x00000001 +#define VIVS_DE_PE_CONFIG_DESTINATION_FETCH_ALWAYS 0x00000002 +#define VIVS_DE_PE_CONFIG_DESTINATION_FETCH_MASK 0x00000008 + +#define VIVS_DE_DEST_ROTATION_HEIGHT 0x000012b4 +#define VIVS_DE_DEST_ROTATION_HEIGHT_HEIGHT__MASK 0x0000ffff +#define VIVS_DE_DEST_ROTATION_HEIGHT_HEIGHT__SHIFT 0 +#define VIVS_DE_DEST_ROTATION_HEIGHT_HEIGHT(x) (((x) << VIVS_DE_DEST_ROTATION_HEIGHT_HEIGHT__SHIFT) & VIVS_DE_DEST_ROTATION_HEIGHT_HEIGHT__MASK) + +#define VIVS_DE_SRC_ROTATION_HEIGHT 0x000012b8 +#define VIVS_DE_SRC_ROTATION_HEIGHT_HEIGHT__MASK 0x0000ffff +#define VIVS_DE_SRC_ROTATION_HEIGHT_HEIGHT__SHIFT 0 +#define VIVS_DE_SRC_ROTATION_HEIGHT_HEIGHT(x) (((x) << VIVS_DE_SRC_ROTATION_HEIGHT_HEIGHT__SHIFT) & VIVS_DE_SRC_ROTATION_HEIGHT_HEIGHT__MASK) + +#define VIVS_DE_ROT_ANGLE 0x000012bc +#define VIVS_DE_ROT_ANGLE_SRC__MASK 0x00000007 +#define VIVS_DE_ROT_ANGLE_SRC__SHIFT 0 +#define VIVS_DE_ROT_ANGLE_SRC(x) (((x) << VIVS_DE_ROT_ANGLE_SRC__SHIFT) & VIVS_DE_ROT_ANGLE_SRC__MASK) +#define VIVS_DE_ROT_ANGLE_DST__MASK 0x00000038 +#define VIVS_DE_ROT_ANGLE_DST__SHIFT 3 +#define VIVS_DE_ROT_ANGLE_DST(x) (((x) << VIVS_DE_ROT_ANGLE_DST__SHIFT) & VIVS_DE_ROT_ANGLE_DST__MASK) +#define VIVS_DE_ROT_ANGLE_SRC_MASK 0x00000100 +#define VIVS_DE_ROT_ANGLE_DST_MASK 0x00000200 +#define VIVS_DE_ROT_ANGLE_SRC_MIRROR__MASK 0x00003000 +#define VIVS_DE_ROT_ANGLE_SRC_MIRROR__SHIFT 12 +#define VIVS_DE_ROT_ANGLE_SRC_MIRROR(x) (((x) << VIVS_DE_ROT_ANGLE_SRC_MIRROR__SHIFT) & VIVS_DE_ROT_ANGLE_SRC_MIRROR__MASK) +#define VIVS_DE_ROT_ANGLE_SRC_MIRROR_MASK 0x00008000 +#define VIVS_DE_ROT_ANGLE_DST_MIRROR__MASK 0x00030000 +#define VIVS_DE_ROT_ANGLE_DST_MIRROR__SHIFT 16 +#define VIVS_DE_ROT_ANGLE_DST_MIRROR(x) (((x) << VIVS_DE_ROT_ANGLE_DST_MIRROR__SHIFT) & VIVS_DE_ROT_ANGLE_DST_MIRROR__MASK) +#define VIVS_DE_ROT_ANGLE_DST_MIRROR_MASK 0x00080000 + +#define VIVS_DE_CLEAR_PIXEL_VALUE32 0x000012c0 + +#define VIVS_DE_DEST_COLOR_KEY 0x000012c4 + +#define VIVS_DE_GLOBAL_SRC_COLOR 0x000012c8 + +#define VIVS_DE_GLOBAL_DEST_COLOR 0x000012cc + +#define VIVS_DE_COLOR_MULTIPLY_MODES 0x000012d0 +#define VIVS_DE_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY__MASK 0x00000001 +#define VIVS_DE_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY__SHIFT 0 +#define VIVS_DE_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_DISABLE 0x00000000 +#define VIVS_DE_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_ENABLE 0x00000001 +#define VIVS_DE_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY__MASK 0x00000010 +#define VIVS_DE_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY__SHIFT 4 +#define VIVS_DE_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY_DISABLE 0x00000000 +#define VIVS_DE_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY_ENABLE 0x00000010 +#define VIVS_DE_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY__MASK 0x00000300 +#define VIVS_DE_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY__SHIFT 8 +#define VIVS_DE_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY_DISABLE 0x00000000 +#define VIVS_DE_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY_ALPHA 0x00000100 +#define VIVS_DE_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY_COLOR 0x00000200 +#define VIVS_DE_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY__MASK 0x00100000 +#define VIVS_DE_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY__SHIFT 20 +#define VIVS_DE_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY_DISABLE 0x00000000 +#define VIVS_DE_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY_ENABLE 0x00100000 + +#define VIVS_DE_PE_TRANSPARENCY 0x000012d4 +#define VIVS_DE_PE_TRANSPARENCY_SOURCE__MASK 0x00000003 +#define VIVS_DE_PE_TRANSPARENCY_SOURCE__SHIFT 0 +#define VIVS_DE_PE_TRANSPARENCY_SOURCE_OPAQUE 0x00000000 +#define VIVS_DE_PE_TRANSPARENCY_SOURCE_MASK 0x00000001 +#define VIVS_DE_PE_TRANSPARENCY_SOURCE_KEY 0x00000002 +#define VIVS_DE_PE_TRANSPARENCY_PATTERN__MASK 0x00000030 +#define VIVS_DE_PE_TRANSPARENCY_PATTERN__SHIFT 4 +#define VIVS_DE_PE_TRANSPARENCY_PATTERN_OPAQUE 0x00000000 +#define VIVS_DE_PE_TRANSPARENCY_PATTERN_MASK 0x00000010 +#define VIVS_DE_PE_TRANSPARENCY_PATTERN_KEY 0x00000020 +#define VIVS_DE_PE_TRANSPARENCY_DESTINATION__MASK 0x00000300 +#define VIVS_DE_PE_TRANSPARENCY_DESTINATION__SHIFT 8 +#define VIVS_DE_PE_TRANSPARENCY_DESTINATION_OPAQUE 0x00000000 +#define VIVS_DE_PE_TRANSPARENCY_DESTINATION_MASK 0x00000100 +#define VIVS_DE_PE_TRANSPARENCY_DESTINATION_KEY 0x00000200 +#define VIVS_DE_PE_TRANSPARENCY_TRANSPARENCY_MASK 0x00001000 +#define VIVS_DE_PE_TRANSPARENCY_USE_SRC_OVERRIDE__MASK 0x00030000 +#define VIVS_DE_PE_TRANSPARENCY_USE_SRC_OVERRIDE__SHIFT 16 +#define VIVS_DE_PE_TRANSPARENCY_USE_SRC_OVERRIDE_DEFAULT 0x00000000 +#define VIVS_DE_PE_TRANSPARENCY_USE_SRC_OVERRIDE_USE_ENABLE 0x00010000 +#define VIVS_DE_PE_TRANSPARENCY_USE_SRC_OVERRIDE_USE_DISABLE 0x00020000 +#define VIVS_DE_PE_TRANSPARENCY_USE_PAT_OVERRIDE__MASK 0x00300000 +#define VIVS_DE_PE_TRANSPARENCY_USE_PAT_OVERRIDE__SHIFT 20 +#define VIVS_DE_PE_TRANSPARENCY_USE_PAT_OVERRIDE_DEFAULT 0x00000000 +#define VIVS_DE_PE_TRANSPARENCY_USE_PAT_OVERRIDE_USE_ENABLE 0x00100000 +#define VIVS_DE_PE_TRANSPARENCY_USE_PAT_OVERRIDE_USE_DISABLE 0x00200000 +#define VIVS_DE_PE_TRANSPARENCY_USE_DST_OVERRIDE__MASK 0x03000000 +#define VIVS_DE_PE_TRANSPARENCY_USE_DST_OVERRIDE__SHIFT 24 +#define VIVS_DE_PE_TRANSPARENCY_USE_DST_OVERRIDE_DEFAULT 0x00000000 +#define VIVS_DE_PE_TRANSPARENCY_USE_DST_OVERRIDE_USE_ENABLE 0x01000000 +#define VIVS_DE_PE_TRANSPARENCY_USE_DST_OVERRIDE_USE_DISABLE 0x02000000 +#define VIVS_DE_PE_TRANSPARENCY_RESOURCE_OVERRIDE_MASK 0x10000000 +#define VIVS_DE_PE_TRANSPARENCY_DFB_COLOR_KEY__MASK 0x20000000 +#define VIVS_DE_PE_TRANSPARENCY_DFB_COLOR_KEY__SHIFT 29 +#define VIVS_DE_PE_TRANSPARENCY_DFB_COLOR_KEY_DISABLE 0x00000000 +#define VIVS_DE_PE_TRANSPARENCY_DFB_COLOR_KEY_ENABLE 0x20000000 +#define VIVS_DE_PE_TRANSPARENCY_DFB_COLOR_KEY_MASK 0x80000000 + +#define VIVS_DE_PE_CONTROL 0x000012d8 +#define VIVS_DE_PE_CONTROL_YUV__MASK 0x00000001 +#define VIVS_DE_PE_CONTROL_YUV__SHIFT 0 +#define VIVS_DE_PE_CONTROL_YUV_601 0x00000000 +#define VIVS_DE_PE_CONTROL_YUV_709 0x00000001 +#define VIVS_DE_PE_CONTROL_YUV_MASK 0x00000008 +#define VIVS_DE_PE_CONTROL_UV_SWIZZLE__MASK 0x00000010 +#define VIVS_DE_PE_CONTROL_UV_SWIZZLE__SHIFT 4 +#define VIVS_DE_PE_CONTROL_UV_SWIZZLE_UV 0x00000000 +#define VIVS_DE_PE_CONTROL_UV_SWIZZLE_VU 0x00000010 +#define VIVS_DE_PE_CONTROL_UV_SWIZZLE_MASK 0x00000080 +#define VIVS_DE_PE_CONTROL_YUVRGB__MASK 0x00000100 +#define VIVS_DE_PE_CONTROL_YUVRGB__SHIFT 8 +#define VIVS_DE_PE_CONTROL_YUVRGB_DISABLE 0x00000000 +#define VIVS_DE_PE_CONTROL_YUVRGB_ENABLE 0x00000100 +#define VIVS_DE_PE_CONTROL_YUVRGB_MASK 0x00000800 + +#define VIVS_DE_SRC_COLOR_KEY_HIGH 0x000012dc + +#define VIVS_DE_DEST_COLOR_KEY_HIGH 0x000012e0 + +#define VIVS_DE_VR_CONFIG_EX 0x000012e4 +#define VIVS_DE_VR_CONFIG_EX_VERTICAL_LINE_WIDTH__MASK 0x00000003 +#define VIVS_DE_VR_CONFIG_EX_VERTICAL_LINE_WIDTH__SHIFT 0 +#define VIVS_DE_VR_CONFIG_EX_VERTICAL_LINE_WIDTH_AUTO 0x00000000 +#define VIVS_DE_VR_CONFIG_EX_VERTICAL_LINE_WIDTH_PIXELS16 0x00000001 +#define VIVS_DE_VR_CONFIG_EX_VERTICAL_LINE_WIDTH_PIXELS32 0x00000002 +#define VIVS_DE_VR_CONFIG_EX_VERTICAL_LINE_WIDTH_MASK 0x00000008 +#define VIVS_DE_VR_CONFIG_EX_FILTER_TAP__MASK 0x000000f0 +#define VIVS_DE_VR_CONFIG_EX_FILTER_TAP__SHIFT 4 +#define VIVS_DE_VR_CONFIG_EX_FILTER_TAP(x) (((x) << VIVS_DE_VR_CONFIG_EX_FILTER_TAP__SHIFT) & VIVS_DE_VR_CONFIG_EX_FILTER_TAP__MASK) +#define VIVS_DE_VR_CONFIG_EX_FILTER_TAP_MASK 0x00000100 + +#define VIVS_DE_PE_DITHER_LOW 0x000012e8 +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X0_Y0__MASK 0x0000000f +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X0_Y0__SHIFT 0 +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X0_Y0(x) (((x) << VIVS_DE_PE_DITHER_LOW_PIXEL_X0_Y0__SHIFT) & VIVS_DE_PE_DITHER_LOW_PIXEL_X0_Y0__MASK) +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X1_Y0__MASK 0x000000f0 +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X1_Y0__SHIFT 4 +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X1_Y0(x) (((x) << VIVS_DE_PE_DITHER_LOW_PIXEL_X1_Y0__SHIFT) & VIVS_DE_PE_DITHER_LOW_PIXEL_X1_Y0__MASK) +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X2_Y0__MASK 0x00000f00 +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X2_Y0__SHIFT 8 +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X2_Y0(x) (((x) << VIVS_DE_PE_DITHER_LOW_PIXEL_X2_Y0__SHIFT) & VIVS_DE_PE_DITHER_LOW_PIXEL_X2_Y0__MASK) +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X3_Y0__MASK 0x0000f000 +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X3_Y0__SHIFT 12 +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X3_Y0(x) (((x) << VIVS_DE_PE_DITHER_LOW_PIXEL_X3_Y0__SHIFT) & VIVS_DE_PE_DITHER_LOW_PIXEL_X3_Y0__MASK) +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X0_Y1__MASK 0x000f0000 +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X0_Y1__SHIFT 16 +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X0_Y1(x) (((x) << VIVS_DE_PE_DITHER_LOW_PIXEL_X0_Y1__SHIFT) & VIVS_DE_PE_DITHER_LOW_PIXEL_X0_Y1__MASK) +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X1_Y1__MASK 0x00f00000 +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X1_Y1__SHIFT 20 +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X1_Y1(x) (((x) << VIVS_DE_PE_DITHER_LOW_PIXEL_X1_Y1__SHIFT) & VIVS_DE_PE_DITHER_LOW_PIXEL_X1_Y1__MASK) +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X2_Y1__MASK 0x0f000000 +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X2_Y1__SHIFT 24 +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X2_Y1(x) (((x) << VIVS_DE_PE_DITHER_LOW_PIXEL_X2_Y1__SHIFT) & VIVS_DE_PE_DITHER_LOW_PIXEL_X2_Y1__MASK) +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X3_Y1__MASK 0xf0000000 +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X3_Y1__SHIFT 28 +#define VIVS_DE_PE_DITHER_LOW_PIXEL_X3_Y1(x) (((x) << VIVS_DE_PE_DITHER_LOW_PIXEL_X3_Y1__SHIFT) & VIVS_DE_PE_DITHER_LOW_PIXEL_X3_Y1__MASK) + +#define VIVS_DE_PE_DITHER_HIGH 0x000012ec +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X0_Y2__MASK 0x0000000f +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X0_Y2__SHIFT 0 +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X0_Y2(x) (((x) << VIVS_DE_PE_DITHER_HIGH_PIXEL_X0_Y2__SHIFT) & VIVS_DE_PE_DITHER_HIGH_PIXEL_X0_Y2__MASK) +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X1_Y2__MASK 0x000000f0 +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X1_Y2__SHIFT 4 +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X1_Y2(x) (((x) << VIVS_DE_PE_DITHER_HIGH_PIXEL_X1_Y2__SHIFT) & VIVS_DE_PE_DITHER_HIGH_PIXEL_X1_Y2__MASK) +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X2_Y2__MASK 0x00000f00 +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X2_Y2__SHIFT 8 +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X2_Y2(x) (((x) << VIVS_DE_PE_DITHER_HIGH_PIXEL_X2_Y2__SHIFT) & VIVS_DE_PE_DITHER_HIGH_PIXEL_X2_Y2__MASK) +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X3_Y2__MASK 0x0000f000 +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X3_Y2__SHIFT 12 +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X3_Y2(x) (((x) << VIVS_DE_PE_DITHER_HIGH_PIXEL_X3_Y2__SHIFT) & VIVS_DE_PE_DITHER_HIGH_PIXEL_X3_Y2__MASK) +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X0_Y3__MASK 0x000f0000 +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X0_Y3__SHIFT 16 +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X0_Y3(x) (((x) << VIVS_DE_PE_DITHER_HIGH_PIXEL_X0_Y3__SHIFT) & VIVS_DE_PE_DITHER_HIGH_PIXEL_X0_Y3__MASK) +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X1_Y3__MASK 0x00f00000 +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X1_Y3__SHIFT 20 +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X1_Y3(x) (((x) << VIVS_DE_PE_DITHER_HIGH_PIXEL_X1_Y3__SHIFT) & VIVS_DE_PE_DITHER_HIGH_PIXEL_X1_Y3__MASK) +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X2_Y3__MASK 0x0f000000 +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X2_Y3__SHIFT 24 +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X2_Y3(x) (((x) << VIVS_DE_PE_DITHER_HIGH_PIXEL_X2_Y3__SHIFT) & VIVS_DE_PE_DITHER_HIGH_PIXEL_X2_Y3__MASK) +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X3_Y3__MASK 0xf0000000 +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X3_Y3__SHIFT 28 +#define VIVS_DE_PE_DITHER_HIGH_PIXEL_X3_Y3(x) (((x) << VIVS_DE_PE_DITHER_HIGH_PIXEL_X3_Y3__SHIFT) & VIVS_DE_PE_DITHER_HIGH_PIXEL_X3_Y3__MASK) + +#define VIVS_DE_BW_CONFIG 0x000012f0 +#define VIVS_DE_BW_CONFIG_BLOCK_CONFIG__MASK 0x00000001 +#define VIVS_DE_BW_CONFIG_BLOCK_CONFIG__SHIFT 0 +#define VIVS_DE_BW_CONFIG_BLOCK_CONFIG_AUTO 0x00000000 +#define VIVS_DE_BW_CONFIG_BLOCK_CONFIG_CUSTOMIZE 0x00000001 +#define VIVS_DE_BW_CONFIG_BLOCK_CONFIG_MASK 0x00000008 +#define VIVS_DE_BW_CONFIG_BLOCK_WALK_DIRECTION__MASK 0x00000010 +#define VIVS_DE_BW_CONFIG_BLOCK_WALK_DIRECTION__SHIFT 4 +#define VIVS_DE_BW_CONFIG_BLOCK_WALK_DIRECTION_RIGHT_BOTTOM 0x00000000 +#define VIVS_DE_BW_CONFIG_BLOCK_WALK_DIRECTION_BOTTOM_RIGHT 0x00000010 +#define VIVS_DE_BW_CONFIG_BLOCK_WALK_DIRECTION_MASK 0x00000080 +#define VIVS_DE_BW_CONFIG_TILE_WALK_DIRECTION__MASK 0x00000100 +#define VIVS_DE_BW_CONFIG_TILE_WALK_DIRECTION__SHIFT 8 +#define VIVS_DE_BW_CONFIG_TILE_WALK_DIRECTION_RIGHT_BOTTOM 0x00000000 +#define VIVS_DE_BW_CONFIG_TILE_WALK_DIRECTION_BOTTOM_RIGHT 0x00000100 +#define VIVS_DE_BW_CONFIG_TILE_WALK_DIRECTION_MASK 0x00000800 +#define VIVS_DE_BW_CONFIG_PIXEL_WALK_DIRECTION__MASK 0x00001000 +#define VIVS_DE_BW_CONFIG_PIXEL_WALK_DIRECTION__SHIFT 12 +#define VIVS_DE_BW_CONFIG_PIXEL_WALK_DIRECTION_RIGHT_BOTTOM 0x00000000 +#define VIVS_DE_BW_CONFIG_PIXEL_WALK_DIRECTION_BOTTOM_RIGHT 0x00001000 +#define VIVS_DE_BW_CONFIG_PIXEL_WALK_DIRECTION_MASK 0x00008000 + +#define VIVS_DE_BW_BLOCK_SIZE 0x000012f4 +#define VIVS_DE_BW_BLOCK_SIZE_WIDTH__MASK 0x0000ffff +#define VIVS_DE_BW_BLOCK_SIZE_WIDTH__SHIFT 0 +#define VIVS_DE_BW_BLOCK_SIZE_WIDTH(x) (((x) << VIVS_DE_BW_BLOCK_SIZE_WIDTH__SHIFT) & VIVS_DE_BW_BLOCK_SIZE_WIDTH__MASK) +#define VIVS_DE_BW_BLOCK_SIZE_HEIGHT__MASK 0xffff0000 +#define VIVS_DE_BW_BLOCK_SIZE_HEIGHT__SHIFT 16 +#define VIVS_DE_BW_BLOCK_SIZE_HEIGHT(x) (((x) << VIVS_DE_BW_BLOCK_SIZE_HEIGHT__SHIFT) & VIVS_DE_BW_BLOCK_SIZE_HEIGHT__MASK) + +#define VIVS_DE_BW_TILE_SIZE 0x000012f8 +#define VIVS_DE_BW_TILE_SIZE_WIDTH__MASK 0x0000ffff +#define VIVS_DE_BW_TILE_SIZE_WIDTH__SHIFT 0 +#define VIVS_DE_BW_TILE_SIZE_WIDTH(x) (((x) << VIVS_DE_BW_TILE_SIZE_WIDTH__SHIFT) & VIVS_DE_BW_TILE_SIZE_WIDTH__MASK) +#define VIVS_DE_BW_TILE_SIZE_HEIGHT__MASK 0xffff0000 +#define VIVS_DE_BW_TILE_SIZE_HEIGHT__SHIFT 16 +#define VIVS_DE_BW_TILE_SIZE_HEIGHT(x) (((x) << VIVS_DE_BW_TILE_SIZE_HEIGHT__SHIFT) & VIVS_DE_BW_TILE_SIZE_HEIGHT__MASK) + +#define VIVS_DE_BW_BLOCK_MASK 0x000012fc +#define VIVS_DE_BW_BLOCK_MASK_HORIZONTAL__MASK 0x0000ffff +#define VIVS_DE_BW_BLOCK_MASK_HORIZONTAL__SHIFT 0 +#define VIVS_DE_BW_BLOCK_MASK_HORIZONTAL(x) (((x) << VIVS_DE_BW_BLOCK_MASK_HORIZONTAL__SHIFT) & VIVS_DE_BW_BLOCK_MASK_HORIZONTAL__MASK) +#define VIVS_DE_BW_BLOCK_MASK_VERTICAL__MASK 0xffff0000 +#define VIVS_DE_BW_BLOCK_MASK_VERTICAL__SHIFT 16 +#define VIVS_DE_BW_BLOCK_MASK_VERTICAL(x) (((x) << VIVS_DE_BW_BLOCK_MASK_VERTICAL__SHIFT) & VIVS_DE_BW_BLOCK_MASK_VERTICAL__MASK) + +#define VIVS_DE_SRC_EX_CONFIG 0x00001300 +#define VIVS_DE_SRC_EX_CONFIG_MULTI_TILED__MASK 0x00000001 +#define VIVS_DE_SRC_EX_CONFIG_MULTI_TILED__SHIFT 0 +#define VIVS_DE_SRC_EX_CONFIG_MULTI_TILED_DISABLE 0x00000000 +#define VIVS_DE_SRC_EX_CONFIG_MULTI_TILED_ENABLE 0x00000001 +#define VIVS_DE_SRC_EX_CONFIG_SUPER_TILED__MASK 0x00000008 +#define VIVS_DE_SRC_EX_CONFIG_SUPER_TILED__SHIFT 3 +#define VIVS_DE_SRC_EX_CONFIG_SUPER_TILED_DISABLE 0x00000000 +#define VIVS_DE_SRC_EX_CONFIG_SUPER_TILED_ENABLE 0x00000008 +#define VIVS_DE_SRC_EX_CONFIG_MINOR_TILED__MASK 0x00000100 +#define VIVS_DE_SRC_EX_CONFIG_MINOR_TILED__SHIFT 8 +#define VIVS_DE_SRC_EX_CONFIG_MINOR_TILED_DISABLE 0x00000000 +#define VIVS_DE_SRC_EX_CONFIG_MINOR_TILED_ENABLE 0x00000100 + +#define VIVS_DE_SRC_EX_ADDRESS 0x00001304 + +#define VIVS_DE_DE_MULTI_SOURCE 0x00001308 +#define VIVS_DE_DE_MULTI_SOURCE_MAX_SOURCE__MASK 0x00000007 +#define VIVS_DE_DE_MULTI_SOURCE_MAX_SOURCE__SHIFT 0 +#define VIVS_DE_DE_MULTI_SOURCE_MAX_SOURCE(x) (((x) << VIVS_DE_DE_MULTI_SOURCE_MAX_SOURCE__SHIFT) & VIVS_DE_DE_MULTI_SOURCE_MAX_SOURCE__MASK) +#define VIVS_DE_DE_MULTI_SOURCE_HORIZONTAL_BLOCK__MASK 0x00000700 +#define VIVS_DE_DE_MULTI_SOURCE_HORIZONTAL_BLOCK__SHIFT 8 +#define VIVS_DE_DE_MULTI_SOURCE_HORIZONTAL_BLOCK_PIXEL16 0x00000000 +#define VIVS_DE_DE_MULTI_SOURCE_HORIZONTAL_BLOCK_PIXEL32 0x00000100 +#define VIVS_DE_DE_MULTI_SOURCE_HORIZONTAL_BLOCK_PIXEL64 0x00000200 +#define VIVS_DE_DE_MULTI_SOURCE_HORIZONTAL_BLOCK_PIXEL128 0x00000300 +#define VIVS_DE_DE_MULTI_SOURCE_HORIZONTAL_BLOCK_PIXEL256 0x00000400 +#define VIVS_DE_DE_MULTI_SOURCE_HORIZONTAL_BLOCK_PIXEL512 0x00000500 +#define VIVS_DE_DE_MULTI_SOURCE_VERTICAL_BLOCK__MASK 0x00070000 +#define VIVS_DE_DE_MULTI_SOURCE_VERTICAL_BLOCK__SHIFT 16 +#define VIVS_DE_DE_MULTI_SOURCE_VERTICAL_BLOCK_LINE1 0x00000000 +#define VIVS_DE_DE_MULTI_SOURCE_VERTICAL_BLOCK_LINE2 0x00010000 +#define VIVS_DE_DE_MULTI_SOURCE_VERTICAL_BLOCK_LINE4 0x00020000 +#define VIVS_DE_DE_MULTI_SOURCE_VERTICAL_BLOCK_LINE8 0x00030000 +#define VIVS_DE_DE_MULTI_SOURCE_VERTICAL_BLOCK_LINE16 0x00040000 +#define VIVS_DE_DE_MULTI_SOURCE_VERTICAL_BLOCK_LINE32 0x00050000 +#define VIVS_DE_DE_MULTI_SOURCE_VERTICAL_BLOCK_LINE64 0x00060000 +#define VIVS_DE_DE_MULTI_SOURCE_VERTICAL_BLOCK_LINE128 0x00070000 + +#define VIVS_DE_DEYUV_CONVERSION 0x0000130c +#define VIVS_DE_DEYUV_CONVERSION_ENABLE__MASK 0x00000003 +#define VIVS_DE_DEYUV_CONVERSION_ENABLE__SHIFT 0 +#define VIVS_DE_DEYUV_CONVERSION_ENABLE_OFF 0x00000000 +#define VIVS_DE_DEYUV_CONVERSION_ENABLE_PLANE1 0x00000001 +#define VIVS_DE_DEYUV_CONVERSION_ENABLE_PLANE2 0x00000002 +#define VIVS_DE_DEYUV_CONVERSION_ENABLE_PLANE3 0x00000003 +#define VIVS_DE_DEYUV_CONVERSION_PLANE1_COUNT__MASK 0x0000000c +#define VIVS_DE_DEYUV_CONVERSION_PLANE1_COUNT__SHIFT 2 +#define VIVS_DE_DEYUV_CONVERSION_PLANE1_COUNT(x) (((x) << VIVS_DE_DEYUV_CONVERSION_PLANE1_COUNT__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE1_COUNT__MASK) +#define VIVS_DE_DEYUV_CONVERSION_PLANE2_COUNT__MASK 0x00000030 +#define VIVS_DE_DEYUV_CONVERSION_PLANE2_COUNT__SHIFT 4 +#define VIVS_DE_DEYUV_CONVERSION_PLANE2_COUNT(x) (((x) << VIVS_DE_DEYUV_CONVERSION_PLANE2_COUNT__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE2_COUNT__MASK) +#define VIVS_DE_DEYUV_CONVERSION_PLANE3_COUNT__MASK 0x000000c0 +#define VIVS_DE_DEYUV_CONVERSION_PLANE3_COUNT__SHIFT 6 +#define VIVS_DE_DEYUV_CONVERSION_PLANE3_COUNT(x) (((x) << VIVS_DE_DEYUV_CONVERSION_PLANE3_COUNT__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE3_COUNT__MASK) +#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_B__MASK 0x00000300 +#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_B__SHIFT 8 +#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_B(x) (((x) << VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_B__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_B__MASK) +#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_G__MASK 0x00000c00 +#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_G__SHIFT 10 +#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_G(x) (((x) << VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_G__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_G__MASK) +#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_R__MASK 0x00003000 +#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_R__SHIFT 12 +#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_R(x) (((x) << VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_R__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_R__MASK) +#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_A__MASK 0x0000c000 +#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_A__SHIFT 14 +#define VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_A(x) (((x) << VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_A__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE1_SWIZZLE_A__MASK) +#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_B__MASK 0x00030000 +#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_B__SHIFT 16 +#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_B(x) (((x) << VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_B__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_B__MASK) +#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_G__MASK 0x000c0000 +#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_G__SHIFT 18 +#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_G(x) (((x) << VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_G__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_G__MASK) +#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_R__MASK 0x00300000 +#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_R__SHIFT 20 +#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_R(x) (((x) << VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_R__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_R__MASK) +#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_A__MASK 0x00c00000 +#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_A__SHIFT 22 +#define VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_A(x) (((x) << VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_A__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE2_SWIZZLE_A__MASK) +#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_B__MASK 0x03000000 +#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_B__SHIFT 24 +#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_B(x) (((x) << VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_B__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_B__MASK) +#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_G__MASK 0x0c000000 +#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_G__SHIFT 26 +#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_G(x) (((x) << VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_G__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_G__MASK) +#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_R__MASK 0x30000000 +#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_R__SHIFT 28 +#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_R(x) (((x) << VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_R__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_R__MASK) +#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_A__MASK 0xc0000000 +#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_A__SHIFT 30 +#define VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_A(x) (((x) << VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_A__SHIFT) & VIVS_DE_DEYUV_CONVERSION_PLANE3_SWIZZLE_A__MASK) + +#define VIVS_DE_DE_PLANE2_ADDRESS 0x00001310 + +#define VIVS_DE_DE_PLANE2_STRIDE 0x00001314 +#define VIVS_DE_DE_PLANE2_STRIDE_STRIDE__MASK 0x0003ffff +#define VIVS_DE_DE_PLANE2_STRIDE_STRIDE__SHIFT 0 +#define VIVS_DE_DE_PLANE2_STRIDE_STRIDE(x) (((x) << VIVS_DE_DE_PLANE2_STRIDE_STRIDE__SHIFT) & VIVS_DE_DE_PLANE2_STRIDE_STRIDE__MASK) + +#define VIVS_DE_DE_PLANE3_ADDRESS 0x00001318 + +#define VIVS_DE_DE_PLANE3_STRIDE 0x0000131c +#define VIVS_DE_DE_PLANE3_STRIDE_STRIDE__MASK 0x0003ffff +#define VIVS_DE_DE_PLANE3_STRIDE_STRIDE__SHIFT 0 +#define VIVS_DE_DE_PLANE3_STRIDE_STRIDE(x) (((x) << VIVS_DE_DE_PLANE3_STRIDE_STRIDE__SHIFT) & VIVS_DE_DE_PLANE3_STRIDE_STRIDE__MASK) + +#define VIVS_DE_DE_STALL_DE 0x00001320 +#define VIVS_DE_DE_STALL_DE_ENABLE__MASK 0x00000001 +#define VIVS_DE_DE_STALL_DE_ENABLE__SHIFT 0 +#define VIVS_DE_DE_STALL_DE_ENABLE_DISABLE 0x00000000 +#define VIVS_DE_DE_STALL_DE_ENABLE_ENABLE 0x00000001 + +#define VIVS_DE_FILTER_KERNEL(i0) (0x00001800 + 0x4*(i0)) +#define VIVS_DE_FILTER_KERNEL__ESIZE 0x00000004 +#define VIVS_DE_FILTER_KERNEL__LEN 0x00000080 +#define VIVS_DE_FILTER_KERNEL_COEFFICIENT0__MASK 0x0000ffff +#define VIVS_DE_FILTER_KERNEL_COEFFICIENT0__SHIFT 0 +#define VIVS_DE_FILTER_KERNEL_COEFFICIENT0(x) (((x) << VIVS_DE_FILTER_KERNEL_COEFFICIENT0__SHIFT) & VIVS_DE_FILTER_KERNEL_COEFFICIENT0__MASK) +#define VIVS_DE_FILTER_KERNEL_COEFFICIENT1__MASK 0xffff0000 +#define VIVS_DE_FILTER_KERNEL_COEFFICIENT1__SHIFT 16 +#define VIVS_DE_FILTER_KERNEL_COEFFICIENT1(x) (((x) << VIVS_DE_FILTER_KERNEL_COEFFICIENT1__SHIFT) & VIVS_DE_FILTER_KERNEL_COEFFICIENT1__MASK) + +#define VIVS_DE_INDEX_COLOR_TABLE(i0) (0x00001c00 + 0x4*(i0)) +#define VIVS_DE_INDEX_COLOR_TABLE__ESIZE 0x00000004 +#define VIVS_DE_INDEX_COLOR_TABLE__LEN 0x00000100 + +#define VIVS_DE_HORI_FILTER_KERNEL(i0) (0x00002800 + 0x4*(i0)) +#define VIVS_DE_HORI_FILTER_KERNEL__ESIZE 0x00000004 +#define VIVS_DE_HORI_FILTER_KERNEL__LEN 0x00000080 +#define VIVS_DE_HORI_FILTER_KERNEL_COEFFICIENT0__MASK 0x0000ffff +#define VIVS_DE_HORI_FILTER_KERNEL_COEFFICIENT0__SHIFT 0 +#define VIVS_DE_HORI_FILTER_KERNEL_COEFFICIENT0(x) (((x) << VIVS_DE_HORI_FILTER_KERNEL_COEFFICIENT0__SHIFT) & VIVS_DE_HORI_FILTER_KERNEL_COEFFICIENT0__MASK) +#define VIVS_DE_HORI_FILTER_KERNEL_COEFFICIENT1__MASK 0xffff0000 +#define VIVS_DE_HORI_FILTER_KERNEL_COEFFICIENT1__SHIFT 16 +#define VIVS_DE_HORI_FILTER_KERNEL_COEFFICIENT1(x) (((x) << VIVS_DE_HORI_FILTER_KERNEL_COEFFICIENT1__SHIFT) & VIVS_DE_HORI_FILTER_KERNEL_COEFFICIENT1__MASK) + +#define VIVS_DE_VERTI_FILTER_KERNEL(i0) (0x00002a00 + 0x4*(i0)) +#define VIVS_DE_VERTI_FILTER_KERNEL__ESIZE 0x00000004 +#define VIVS_DE_VERTI_FILTER_KERNEL__LEN 0x00000080 +#define VIVS_DE_VERTI_FILTER_KERNEL_COEFFICIENT0__MASK 0x0000ffff +#define VIVS_DE_VERTI_FILTER_KERNEL_COEFFICIENT0__SHIFT 0 +#define VIVS_DE_VERTI_FILTER_KERNEL_COEFFICIENT0(x) (((x) << VIVS_DE_VERTI_FILTER_KERNEL_COEFFICIENT0__SHIFT) & VIVS_DE_VERTI_FILTER_KERNEL_COEFFICIENT0__MASK) +#define VIVS_DE_VERTI_FILTER_KERNEL_COEFFICIENT1__MASK 0xffff0000 +#define VIVS_DE_VERTI_FILTER_KERNEL_COEFFICIENT1__SHIFT 16 +#define VIVS_DE_VERTI_FILTER_KERNEL_COEFFICIENT1(x) (((x) << VIVS_DE_VERTI_FILTER_KERNEL_COEFFICIENT1__SHIFT) & VIVS_DE_VERTI_FILTER_KERNEL_COEFFICIENT1__MASK) + +#define VIVS_DE_INDEX_COLOR_TABLE32(i0) (0x00003400 + 0x4*(i0)) +#define VIVS_DE_INDEX_COLOR_TABLE32__ESIZE 0x00000004 +#define VIVS_DE_INDEX_COLOR_TABLE32__LEN 0x00000100 + +#define VIVS_DE_BLOCK4 0x00000000 + +#define VIVS_DE_BLOCK4_SRC_ADDRESS(i0) (0x00012800 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_SRC_ADDRESS__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_SRC_ADDRESS__LEN 0x00000004 + +#define VIVS_DE_BLOCK4_SRC_STRIDE(i0) (0x00012810 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_SRC_STRIDE__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_SRC_STRIDE__LEN 0x00000004 +#define VIVS_DE_BLOCK4_SRC_STRIDE_STRIDE__MASK 0x0003ffff +#define VIVS_DE_BLOCK4_SRC_STRIDE_STRIDE__SHIFT 0 +#define VIVS_DE_BLOCK4_SRC_STRIDE_STRIDE(x) (((x) << VIVS_DE_BLOCK4_SRC_STRIDE_STRIDE__SHIFT) & VIVS_DE_BLOCK4_SRC_STRIDE_STRIDE__MASK) + +#define VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG(i0) (0x00012820 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG__LEN 0x00000004 +#define VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG_WIDTH__MASK 0x0000ffff +#define VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG_WIDTH__SHIFT 0 +#define VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG_WIDTH(x) (((x) << VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG_WIDTH__SHIFT) & VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG_WIDTH__MASK) +#define VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG_ROTATION__MASK 0x00010000 +#define VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG_ROTATION__SHIFT 16 +#define VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG_ROTATION_DISABLE 0x00000000 +#define VIVS_DE_BLOCK4_SRC_ROTATION_CONFIG_ROTATION_ENABLE 0x00010000 + +#define VIVS_DE_BLOCK4_SRC_CONFIG(i0) (0x00012830 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_SRC_CONFIG__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_SRC_CONFIG__LEN 0x00000004 +#define VIVS_DE_BLOCK4_SRC_CONFIG_PE10_SOURCE_FORMAT__MASK 0x0000000f +#define VIVS_DE_BLOCK4_SRC_CONFIG_PE10_SOURCE_FORMAT__SHIFT 0 +#define VIVS_DE_BLOCK4_SRC_CONFIG_PE10_SOURCE_FORMAT(x) (((x) << VIVS_DE_BLOCK4_SRC_CONFIG_PE10_SOURCE_FORMAT__SHIFT) & VIVS_DE_BLOCK4_SRC_CONFIG_PE10_SOURCE_FORMAT__MASK) +#define VIVS_DE_BLOCK4_SRC_CONFIG_TRANSPARENCY__MASK 0x00000030 +#define VIVS_DE_BLOCK4_SRC_CONFIG_TRANSPARENCY__SHIFT 4 +#define VIVS_DE_BLOCK4_SRC_CONFIG_TRANSPARENCY(x) (((x) << VIVS_DE_BLOCK4_SRC_CONFIG_TRANSPARENCY__SHIFT) & VIVS_DE_BLOCK4_SRC_CONFIG_TRANSPARENCY__MASK) +#define VIVS_DE_BLOCK4_SRC_CONFIG_SRC_RELATIVE__MASK 0x00000040 +#define VIVS_DE_BLOCK4_SRC_CONFIG_SRC_RELATIVE__SHIFT 6 +#define VIVS_DE_BLOCK4_SRC_CONFIG_SRC_RELATIVE_ABSOLUTE 0x00000000 +#define VIVS_DE_BLOCK4_SRC_CONFIG_SRC_RELATIVE_RELATIVE 0x00000040 +#define VIVS_DE_BLOCK4_SRC_CONFIG_TILED__MASK 0x00000080 +#define VIVS_DE_BLOCK4_SRC_CONFIG_TILED__SHIFT 7 +#define VIVS_DE_BLOCK4_SRC_CONFIG_TILED_DISABLE 0x00000000 +#define VIVS_DE_BLOCK4_SRC_CONFIG_TILED_ENABLE 0x00000080 +#define VIVS_DE_BLOCK4_SRC_CONFIG_LOCATION__MASK 0x00000100 +#define VIVS_DE_BLOCK4_SRC_CONFIG_LOCATION__SHIFT 8 +#define VIVS_DE_BLOCK4_SRC_CONFIG_LOCATION_MEMORY 0x00000000 +#define VIVS_DE_BLOCK4_SRC_CONFIG_LOCATION_STREAM 0x00000100 +#define VIVS_DE_BLOCK4_SRC_CONFIG_PACK__MASK 0x00003000 +#define VIVS_DE_BLOCK4_SRC_CONFIG_PACK__SHIFT 12 +#define VIVS_DE_BLOCK4_SRC_CONFIG_PACK_PACKED8 0x00000000 +#define VIVS_DE_BLOCK4_SRC_CONFIG_PACK_PACKED16 0x00001000 +#define VIVS_DE_BLOCK4_SRC_CONFIG_PACK_PACKED32 0x00002000 +#define VIVS_DE_BLOCK4_SRC_CONFIG_PACK_UNPACKED 0x00003000 +#define VIVS_DE_BLOCK4_SRC_CONFIG_MONO_TRANSPARENCY__MASK 0x00008000 +#define VIVS_DE_BLOCK4_SRC_CONFIG_MONO_TRANSPARENCY__SHIFT 15 +#define VIVS_DE_BLOCK4_SRC_CONFIG_MONO_TRANSPARENCY_BACKGROUND 0x00000000 +#define VIVS_DE_BLOCK4_SRC_CONFIG_MONO_TRANSPARENCY_FOREGROUND 0x00008000 +#define VIVS_DE_BLOCK4_SRC_CONFIG_UNK16 0x00010000 +#define VIVS_DE_BLOCK4_SRC_CONFIG_SWIZZLE__MASK 0x00300000 +#define VIVS_DE_BLOCK4_SRC_CONFIG_SWIZZLE__SHIFT 20 +#define VIVS_DE_BLOCK4_SRC_CONFIG_SWIZZLE(x) (((x) << VIVS_DE_BLOCK4_SRC_CONFIG_SWIZZLE__SHIFT) & VIVS_DE_BLOCK4_SRC_CONFIG_SWIZZLE__MASK) +#define VIVS_DE_BLOCK4_SRC_CONFIG_SOURCE_FORMAT__MASK 0x1f000000 +#define VIVS_DE_BLOCK4_SRC_CONFIG_SOURCE_FORMAT__SHIFT 24 +#define VIVS_DE_BLOCK4_SRC_CONFIG_SOURCE_FORMAT(x) (((x) << VIVS_DE_BLOCK4_SRC_CONFIG_SOURCE_FORMAT__SHIFT) & VIVS_DE_BLOCK4_SRC_CONFIG_SOURCE_FORMAT__MASK) +#define VIVS_DE_BLOCK4_SRC_CONFIG_DISABLE420_L2_CACHE 0x20000000 +#define VIVS_DE_BLOCK4_SRC_CONFIG_ENDIAN_CONTROL__MASK 0xc0000000 +#define VIVS_DE_BLOCK4_SRC_CONFIG_ENDIAN_CONTROL__SHIFT 30 +#define VIVS_DE_BLOCK4_SRC_CONFIG_ENDIAN_CONTROL(x) (((x) << VIVS_DE_BLOCK4_SRC_CONFIG_ENDIAN_CONTROL__SHIFT) & VIVS_DE_BLOCK4_SRC_CONFIG_ENDIAN_CONTROL__MASK) + +#define VIVS_DE_BLOCK4_SRC_ORIGIN(i0) (0x00012840 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_SRC_ORIGIN__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_SRC_ORIGIN__LEN 0x00000004 +#define VIVS_DE_BLOCK4_SRC_ORIGIN_X__MASK 0x0000ffff +#define VIVS_DE_BLOCK4_SRC_ORIGIN_X__SHIFT 0 +#define VIVS_DE_BLOCK4_SRC_ORIGIN_X(x) (((x) << VIVS_DE_BLOCK4_SRC_ORIGIN_X__SHIFT) & VIVS_DE_BLOCK4_SRC_ORIGIN_X__MASK) +#define VIVS_DE_BLOCK4_SRC_ORIGIN_Y__MASK 0xffff0000 +#define VIVS_DE_BLOCK4_SRC_ORIGIN_Y__SHIFT 16 +#define VIVS_DE_BLOCK4_SRC_ORIGIN_Y(x) (((x) << VIVS_DE_BLOCK4_SRC_ORIGIN_Y__SHIFT) & VIVS_DE_BLOCK4_SRC_ORIGIN_Y__MASK) + +#define VIVS_DE_BLOCK4_SRC_SIZE(i0) (0x00012850 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_SRC_SIZE__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_SRC_SIZE__LEN 0x00000004 +#define VIVS_DE_BLOCK4_SRC_SIZE_X__MASK 0x0000ffff +#define VIVS_DE_BLOCK4_SRC_SIZE_X__SHIFT 0 +#define VIVS_DE_BLOCK4_SRC_SIZE_X(x) (((x) << VIVS_DE_BLOCK4_SRC_SIZE_X__SHIFT) & VIVS_DE_BLOCK4_SRC_SIZE_X__MASK) +#define VIVS_DE_BLOCK4_SRC_SIZE_Y__MASK 0xffff0000 +#define VIVS_DE_BLOCK4_SRC_SIZE_Y__SHIFT 16 +#define VIVS_DE_BLOCK4_SRC_SIZE_Y(x) (((x) << VIVS_DE_BLOCK4_SRC_SIZE_Y__SHIFT) & VIVS_DE_BLOCK4_SRC_SIZE_Y__MASK) + +#define VIVS_DE_BLOCK4_SRC_COLOR_BG(i0) (0x00012860 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_SRC_COLOR_BG__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_SRC_COLOR_BG__LEN 0x00000004 + +#define VIVS_DE_BLOCK4_ROP(i0) (0x00012870 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_ROP__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_ROP__LEN 0x00000004 +#define VIVS_DE_BLOCK4_ROP_ROP_FG__MASK 0x000000ff +#define VIVS_DE_BLOCK4_ROP_ROP_FG__SHIFT 0 +#define VIVS_DE_BLOCK4_ROP_ROP_FG(x) (((x) << VIVS_DE_BLOCK4_ROP_ROP_FG__SHIFT) & VIVS_DE_BLOCK4_ROP_ROP_FG__MASK) +#define VIVS_DE_BLOCK4_ROP_ROP_BG__MASK 0x0000ff00 +#define VIVS_DE_BLOCK4_ROP_ROP_BG__SHIFT 8 +#define VIVS_DE_BLOCK4_ROP_ROP_BG(x) (((x) << VIVS_DE_BLOCK4_ROP_ROP_BG__SHIFT) & VIVS_DE_BLOCK4_ROP_ROP_BG__MASK) +#define VIVS_DE_BLOCK4_ROP_TYPE__MASK 0x00300000 +#define VIVS_DE_BLOCK4_ROP_TYPE__SHIFT 20 +#define VIVS_DE_BLOCK4_ROP_TYPE_ROP2_PATTERN 0x00000000 +#define VIVS_DE_BLOCK4_ROP_TYPE_ROP2_SOURCE 0x00100000 +#define VIVS_DE_BLOCK4_ROP_TYPE_ROP3 0x00200000 +#define VIVS_DE_BLOCK4_ROP_TYPE_ROP4 0x00300000 + +#define VIVS_DE_BLOCK4_ALPHA_CONTROL(i0) (0x00012880 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_ALPHA_CONTROL__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_ALPHA_CONTROL__LEN 0x00000004 +#define VIVS_DE_BLOCK4_ALPHA_CONTROL_ENABLE__MASK 0x00000001 +#define VIVS_DE_BLOCK4_ALPHA_CONTROL_ENABLE__SHIFT 0 +#define VIVS_DE_BLOCK4_ALPHA_CONTROL_ENABLE_OFF 0x00000000 +#define VIVS_DE_BLOCK4_ALPHA_CONTROL_ENABLE_ON 0x00000001 +#define VIVS_DE_BLOCK4_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__MASK 0x00ff0000 +#define VIVS_DE_BLOCK4_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__SHIFT 16 +#define VIVS_DE_BLOCK4_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA(x) (((x) << VIVS_DE_BLOCK4_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__SHIFT) & VIVS_DE_BLOCK4_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__MASK) +#define VIVS_DE_BLOCK4_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__MASK 0xff000000 +#define VIVS_DE_BLOCK4_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__SHIFT 24 +#define VIVS_DE_BLOCK4_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA(x) (((x) << VIVS_DE_BLOCK4_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__SHIFT) & VIVS_DE_BLOCK4_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__MASK) + +#define VIVS_DE_BLOCK4_ALPHA_MODES(i0) (0x00012890 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_ALPHA_MODES__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_ALPHA_MODES__LEN 0x00000004 +#define VIVS_DE_BLOCK4_ALPHA_MODES_SRC_ALPHA_MODE__MASK 0x00000001 +#define VIVS_DE_BLOCK4_ALPHA_MODES_SRC_ALPHA_MODE__SHIFT 0 +#define VIVS_DE_BLOCK4_ALPHA_MODES_SRC_ALPHA_MODE_NORMAL 0x00000000 +#define VIVS_DE_BLOCK4_ALPHA_MODES_SRC_ALPHA_MODE_INVERSED 0x00000001 +#define VIVS_DE_BLOCK4_ALPHA_MODES_DST_ALPHA_MODE__MASK 0x00000010 +#define VIVS_DE_BLOCK4_ALPHA_MODES_DST_ALPHA_MODE__SHIFT 4 +#define VIVS_DE_BLOCK4_ALPHA_MODES_DST_ALPHA_MODE_NORMAL 0x00000000 +#define VIVS_DE_BLOCK4_ALPHA_MODES_DST_ALPHA_MODE_INVERSED 0x00000010 +#define VIVS_DE_BLOCK4_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE__MASK 0x00000300 +#define VIVS_DE_BLOCK4_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE__SHIFT 8 +#define VIVS_DE_BLOCK4_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE_NORMAL 0x00000000 +#define VIVS_DE_BLOCK4_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE_GLOBAL 0x00000100 +#define VIVS_DE_BLOCK4_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE_SCALED 0x00000200 +#define VIVS_DE_BLOCK4_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE__MASK 0x00003000 +#define VIVS_DE_BLOCK4_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE__SHIFT 12 +#define VIVS_DE_BLOCK4_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE_NORMAL 0x00000000 +#define VIVS_DE_BLOCK4_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE_GLOBAL 0x00001000 +#define VIVS_DE_BLOCK4_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE_SCALED 0x00002000 +#define VIVS_DE_BLOCK4_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY__MASK 0x00010000 +#define VIVS_DE_BLOCK4_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY__SHIFT 16 +#define VIVS_DE_BLOCK4_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY_DISABLE 0x00000000 +#define VIVS_DE_BLOCK4_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY_ENABLE 0x00010000 +#define VIVS_DE_BLOCK4_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY__MASK 0x00100000 +#define VIVS_DE_BLOCK4_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY__SHIFT 20 +#define VIVS_DE_BLOCK4_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY_DISABLE 0x00000000 +#define VIVS_DE_BLOCK4_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY_ENABLE 0x00100000 +#define VIVS_DE_BLOCK4_ALPHA_MODES_SRC_BLENDING_MODE__MASK 0x07000000 +#define VIVS_DE_BLOCK4_ALPHA_MODES_SRC_BLENDING_MODE__SHIFT 24 +#define VIVS_DE_BLOCK4_ALPHA_MODES_SRC_BLENDING_MODE(x) (((x) << VIVS_DE_BLOCK4_ALPHA_MODES_SRC_BLENDING_MODE__SHIFT) & VIVS_DE_BLOCK4_ALPHA_MODES_SRC_BLENDING_MODE__MASK) +#define VIVS_DE_BLOCK4_ALPHA_MODES_SRC_ALPHA_FACTOR__MASK 0x08000000 +#define VIVS_DE_BLOCK4_ALPHA_MODES_SRC_ALPHA_FACTOR__SHIFT 27 +#define VIVS_DE_BLOCK4_ALPHA_MODES_SRC_ALPHA_FACTOR_DISABLE 0x00000000 +#define VIVS_DE_BLOCK4_ALPHA_MODES_SRC_ALPHA_FACTOR_ENABLE 0x08000000 +#define VIVS_DE_BLOCK4_ALPHA_MODES_DST_BLENDING_MODE__MASK 0x70000000 +#define VIVS_DE_BLOCK4_ALPHA_MODES_DST_BLENDING_MODE__SHIFT 28 +#define VIVS_DE_BLOCK4_ALPHA_MODES_DST_BLENDING_MODE(x) (((x) << VIVS_DE_BLOCK4_ALPHA_MODES_DST_BLENDING_MODE__SHIFT) & VIVS_DE_BLOCK4_ALPHA_MODES_DST_BLENDING_MODE__MASK) +#define VIVS_DE_BLOCK4_ALPHA_MODES_DST_ALPHA_FACTOR__MASK 0x80000000 +#define VIVS_DE_BLOCK4_ALPHA_MODES_DST_ALPHA_FACTOR__SHIFT 31 +#define VIVS_DE_BLOCK4_ALPHA_MODES_DST_ALPHA_FACTOR_DISABLE 0x00000000 +#define VIVS_DE_BLOCK4_ALPHA_MODES_DST_ALPHA_FACTOR_ENABLE 0x80000000 + +#define VIVS_DE_BLOCK4_ADDRESS_U(i0) (0x000128a0 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_ADDRESS_U__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_ADDRESS_U__LEN 0x00000004 + +#define VIVS_DE_BLOCK4_STRIDE_U(i0) (0x000128b0 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_STRIDE_U__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_STRIDE_U__LEN 0x00000004 +#define VIVS_DE_BLOCK4_STRIDE_U_STRIDE__MASK 0x0003ffff +#define VIVS_DE_BLOCK4_STRIDE_U_STRIDE__SHIFT 0 +#define VIVS_DE_BLOCK4_STRIDE_U_STRIDE(x) (((x) << VIVS_DE_BLOCK4_STRIDE_U_STRIDE__SHIFT) & VIVS_DE_BLOCK4_STRIDE_U_STRIDE__MASK) + +#define VIVS_DE_BLOCK4_ADDRESS_V(i0) (0x000128c0 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_ADDRESS_V__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_ADDRESS_V__LEN 0x00000004 + +#define VIVS_DE_BLOCK4_STRIDE_V(i0) (0x000128d0 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_STRIDE_V__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_STRIDE_V__LEN 0x00000004 +#define VIVS_DE_BLOCK4_STRIDE_V_STRIDE__MASK 0x0003ffff +#define VIVS_DE_BLOCK4_STRIDE_V_STRIDE__SHIFT 0 +#define VIVS_DE_BLOCK4_STRIDE_V_STRIDE(x) (((x) << VIVS_DE_BLOCK4_STRIDE_V_STRIDE__SHIFT) & VIVS_DE_BLOCK4_STRIDE_V_STRIDE__MASK) + +#define VIVS_DE_BLOCK4_SRC_ROTATION_HEIGHT(i0) (0x000128e0 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_SRC_ROTATION_HEIGHT__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_SRC_ROTATION_HEIGHT__LEN 0x00000004 +#define VIVS_DE_BLOCK4_SRC_ROTATION_HEIGHT_HEIGHT__MASK 0x0000ffff +#define VIVS_DE_BLOCK4_SRC_ROTATION_HEIGHT_HEIGHT__SHIFT 0 +#define VIVS_DE_BLOCK4_SRC_ROTATION_HEIGHT_HEIGHT(x) (((x) << VIVS_DE_BLOCK4_SRC_ROTATION_HEIGHT_HEIGHT__SHIFT) & VIVS_DE_BLOCK4_SRC_ROTATION_HEIGHT_HEIGHT__MASK) + +#define VIVS_DE_BLOCK4_ROT_ANGLE(i0) (0x000128f0 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_ROT_ANGLE__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_ROT_ANGLE__LEN 0x00000004 +#define VIVS_DE_BLOCK4_ROT_ANGLE_SRC__MASK 0x00000007 +#define VIVS_DE_BLOCK4_ROT_ANGLE_SRC__SHIFT 0 +#define VIVS_DE_BLOCK4_ROT_ANGLE_SRC(x) (((x) << VIVS_DE_BLOCK4_ROT_ANGLE_SRC__SHIFT) & VIVS_DE_BLOCK4_ROT_ANGLE_SRC__MASK) +#define VIVS_DE_BLOCK4_ROT_ANGLE_DST__MASK 0x00000038 +#define VIVS_DE_BLOCK4_ROT_ANGLE_DST__SHIFT 3 +#define VIVS_DE_BLOCK4_ROT_ANGLE_DST(x) (((x) << VIVS_DE_BLOCK4_ROT_ANGLE_DST__SHIFT) & VIVS_DE_BLOCK4_ROT_ANGLE_DST__MASK) +#define VIVS_DE_BLOCK4_ROT_ANGLE_SRC_MASK 0x00000100 +#define VIVS_DE_BLOCK4_ROT_ANGLE_DST_MASK 0x00000200 +#define VIVS_DE_BLOCK4_ROT_ANGLE_SRC_MIRROR__MASK 0x00003000 +#define VIVS_DE_BLOCK4_ROT_ANGLE_SRC_MIRROR__SHIFT 12 +#define VIVS_DE_BLOCK4_ROT_ANGLE_SRC_MIRROR(x) (((x) << VIVS_DE_BLOCK4_ROT_ANGLE_SRC_MIRROR__SHIFT) & VIVS_DE_BLOCK4_ROT_ANGLE_SRC_MIRROR__MASK) +#define VIVS_DE_BLOCK4_ROT_ANGLE_SRC_MIRROR_MASK 0x00008000 +#define VIVS_DE_BLOCK4_ROT_ANGLE_DST_MIRROR__MASK 0x00030000 +#define VIVS_DE_BLOCK4_ROT_ANGLE_DST_MIRROR__SHIFT 16 +#define VIVS_DE_BLOCK4_ROT_ANGLE_DST_MIRROR(x) (((x) << VIVS_DE_BLOCK4_ROT_ANGLE_DST_MIRROR__SHIFT) & VIVS_DE_BLOCK4_ROT_ANGLE_DST_MIRROR__MASK) +#define VIVS_DE_BLOCK4_ROT_ANGLE_DST_MIRROR_MASK 0x00080000 + +#define VIVS_DE_BLOCK4_GLOBAL_SRC_COLOR(i0) (0x00012900 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_GLOBAL_SRC_COLOR__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_GLOBAL_SRC_COLOR__LEN 0x00000004 + +#define VIVS_DE_BLOCK4_GLOBAL_DEST_COLOR(i0) (0x00012910 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_GLOBAL_DEST_COLOR__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_GLOBAL_DEST_COLOR__LEN 0x00000004 + +#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES(i0) (0x00012920 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES__LEN 0x00000004 +#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY__MASK 0x00000001 +#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY__SHIFT 0 +#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_DISABLE 0x00000000 +#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_ENABLE 0x00000001 +#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY__MASK 0x00000010 +#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY__SHIFT 4 +#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY_DISABLE 0x00000000 +#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY_ENABLE 0x00000010 +#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY__MASK 0x00000300 +#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY__SHIFT 8 +#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY_DISABLE 0x00000000 +#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY_ALPHA 0x00000100 +#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY_COLOR 0x00000200 +#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY__MASK 0x00100000 +#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY__SHIFT 20 +#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY_DISABLE 0x00000000 +#define VIVS_DE_BLOCK4_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY_ENABLE 0x00100000 + +#define VIVS_DE_BLOCK4_TRANSPARENCY(i0) (0x00012930 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_TRANSPARENCY__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_TRANSPARENCY__LEN 0x00000004 +#define VIVS_DE_BLOCK4_TRANSPARENCY_SOURCE__MASK 0x00000003 +#define VIVS_DE_BLOCK4_TRANSPARENCY_SOURCE__SHIFT 0 +#define VIVS_DE_BLOCK4_TRANSPARENCY_SOURCE_OPAQUE 0x00000000 +#define VIVS_DE_BLOCK4_TRANSPARENCY_SOURCE_MASK 0x00000001 +#define VIVS_DE_BLOCK4_TRANSPARENCY_SOURCE_KEY 0x00000002 +#define VIVS_DE_BLOCK4_TRANSPARENCY_PATTERN__MASK 0x00000030 +#define VIVS_DE_BLOCK4_TRANSPARENCY_PATTERN__SHIFT 4 +#define VIVS_DE_BLOCK4_TRANSPARENCY_PATTERN_OPAQUE 0x00000000 +#define VIVS_DE_BLOCK4_TRANSPARENCY_PATTERN_MASK 0x00000010 +#define VIVS_DE_BLOCK4_TRANSPARENCY_PATTERN_KEY 0x00000020 +#define VIVS_DE_BLOCK4_TRANSPARENCY_DESTINATION__MASK 0x00000300 +#define VIVS_DE_BLOCK4_TRANSPARENCY_DESTINATION__SHIFT 8 +#define VIVS_DE_BLOCK4_TRANSPARENCY_DESTINATION_OPAQUE 0x00000000 +#define VIVS_DE_BLOCK4_TRANSPARENCY_DESTINATION_MASK 0x00000100 +#define VIVS_DE_BLOCK4_TRANSPARENCY_DESTINATION_KEY 0x00000200 +#define VIVS_DE_BLOCK4_TRANSPARENCY_TRANSPARENCY_MASK 0x00001000 +#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_SRC_OVERRIDE__MASK 0x00030000 +#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_SRC_OVERRIDE__SHIFT 16 +#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_SRC_OVERRIDE_DEFAULT 0x00000000 +#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_SRC_OVERRIDE_USE_ENABLE 0x00010000 +#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_SRC_OVERRIDE_USE_DISABLE 0x00020000 +#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_PAT_OVERRIDE__MASK 0x00300000 +#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_PAT_OVERRIDE__SHIFT 20 +#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_PAT_OVERRIDE_DEFAULT 0x00000000 +#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_PAT_OVERRIDE_USE_ENABLE 0x00100000 +#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_PAT_OVERRIDE_USE_DISABLE 0x00200000 +#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_DST_OVERRIDE__MASK 0x03000000 +#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_DST_OVERRIDE__SHIFT 24 +#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_DST_OVERRIDE_DEFAULT 0x00000000 +#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_DST_OVERRIDE_USE_ENABLE 0x01000000 +#define VIVS_DE_BLOCK4_TRANSPARENCY_USE_DST_OVERRIDE_USE_DISABLE 0x02000000 +#define VIVS_DE_BLOCK4_TRANSPARENCY_RESOURCE_OVERRIDE_MASK 0x10000000 +#define VIVS_DE_BLOCK4_TRANSPARENCY_DFB_COLOR_KEY__MASK 0x20000000 +#define VIVS_DE_BLOCK4_TRANSPARENCY_DFB_COLOR_KEY__SHIFT 29 +#define VIVS_DE_BLOCK4_TRANSPARENCY_DFB_COLOR_KEY_DISABLE 0x00000000 +#define VIVS_DE_BLOCK4_TRANSPARENCY_DFB_COLOR_KEY_ENABLE 0x20000000 +#define VIVS_DE_BLOCK4_TRANSPARENCY_DFB_COLOR_KEY_MASK 0x80000000 + +#define VIVS_DE_BLOCK4_CONTROL(i0) (0x00012940 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_CONTROL__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_CONTROL__LEN 0x00000004 +#define VIVS_DE_BLOCK4_CONTROL_YUV__MASK 0x00000001 +#define VIVS_DE_BLOCK4_CONTROL_YUV__SHIFT 0 +#define VIVS_DE_BLOCK4_CONTROL_YUV_601 0x00000000 +#define VIVS_DE_BLOCK4_CONTROL_YUV_709 0x00000001 +#define VIVS_DE_BLOCK4_CONTROL_YUV_MASK 0x00000008 +#define VIVS_DE_BLOCK4_CONTROL_UV_SWIZZLE__MASK 0x00000010 +#define VIVS_DE_BLOCK4_CONTROL_UV_SWIZZLE__SHIFT 4 +#define VIVS_DE_BLOCK4_CONTROL_UV_SWIZZLE_UV 0x00000000 +#define VIVS_DE_BLOCK4_CONTROL_UV_SWIZZLE_VU 0x00000010 +#define VIVS_DE_BLOCK4_CONTROL_UV_SWIZZLE_MASK 0x00000080 +#define VIVS_DE_BLOCK4_CONTROL_YUVRGB__MASK 0x00000100 +#define VIVS_DE_BLOCK4_CONTROL_YUVRGB__SHIFT 8 +#define VIVS_DE_BLOCK4_CONTROL_YUVRGB_DISABLE 0x00000000 +#define VIVS_DE_BLOCK4_CONTROL_YUVRGB_ENABLE 0x00000100 +#define VIVS_DE_BLOCK4_CONTROL_YUVRGB_MASK 0x00000800 + +#define VIVS_DE_BLOCK4_SRC_COLOR_KEY_HIGH(i0) (0x00012950 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_SRC_COLOR_KEY_HIGH__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_SRC_COLOR_KEY_HIGH__LEN 0x00000004 + +#define VIVS_DE_BLOCK4_SRC_EX_CONFIG(i0) (0x00012960 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_SRC_EX_CONFIG__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_SRC_EX_CONFIG__LEN 0x00000004 +#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_MULTI_TILED__MASK 0x00000001 +#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_MULTI_TILED__SHIFT 0 +#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_MULTI_TILED_DISABLE 0x00000000 +#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_MULTI_TILED_ENABLE 0x00000001 +#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_SUPER_TILED__MASK 0x00000008 +#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_SUPER_TILED__SHIFT 3 +#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_SUPER_TILED_DISABLE 0x00000000 +#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_SUPER_TILED_ENABLE 0x00000008 +#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_MINOR_TILED__MASK 0x00000100 +#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_MINOR_TILED__SHIFT 8 +#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_MINOR_TILED_DISABLE 0x00000000 +#define VIVS_DE_BLOCK4_SRC_EX_CONFIG_MINOR_TILED_ENABLE 0x00000100 + +#define VIVS_DE_BLOCK4_SRC_EX_ADDRESS(i0) (0x00012970 + 0x4*(i0)) +#define VIVS_DE_BLOCK4_SRC_EX_ADDRESS__ESIZE 0x00000004 +#define VIVS_DE_BLOCK4_SRC_EX_ADDRESS__LEN 0x00000004 + +#define VIVS_DE_BLOCK8 0x00000000 + +#define VIVS_DE_BLOCK8_SRC_ADDRESS(i0) (0x00012a00 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_SRC_ADDRESS__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_SRC_ADDRESS__LEN 0x00000008 + +#define VIVS_DE_BLOCK8_SRC_STRIDE(i0) (0x00012a20 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_SRC_STRIDE__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_SRC_STRIDE__LEN 0x00000008 +#define VIVS_DE_BLOCK8_SRC_STRIDE_STRIDE__MASK 0x0003ffff +#define VIVS_DE_BLOCK8_SRC_STRIDE_STRIDE__SHIFT 0 +#define VIVS_DE_BLOCK8_SRC_STRIDE_STRIDE(x) (((x) << VIVS_DE_BLOCK8_SRC_STRIDE_STRIDE__SHIFT) & VIVS_DE_BLOCK8_SRC_STRIDE_STRIDE__MASK) + +#define VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG(i0) (0x00012a40 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG__LEN 0x00000008 +#define VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG_WIDTH__MASK 0x0000ffff +#define VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG_WIDTH__SHIFT 0 +#define VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG_WIDTH(x) (((x) << VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG_WIDTH__SHIFT) & VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG_WIDTH__MASK) +#define VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG_ROTATION__MASK 0x00010000 +#define VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG_ROTATION__SHIFT 16 +#define VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG_ROTATION_DISABLE 0x00000000 +#define VIVS_DE_BLOCK8_SRC_ROTATION_CONFIG_ROTATION_ENABLE 0x00010000 + +#define VIVS_DE_BLOCK8_SRC_CONFIG(i0) (0x00012a60 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_SRC_CONFIG__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_SRC_CONFIG__LEN 0x00000008 +#define VIVS_DE_BLOCK8_SRC_CONFIG_PE10_SOURCE_FORMAT__MASK 0x0000000f +#define VIVS_DE_BLOCK8_SRC_CONFIG_PE10_SOURCE_FORMAT__SHIFT 0 +#define VIVS_DE_BLOCK8_SRC_CONFIG_PE10_SOURCE_FORMAT(x) (((x) << VIVS_DE_BLOCK8_SRC_CONFIG_PE10_SOURCE_FORMAT__SHIFT) & VIVS_DE_BLOCK8_SRC_CONFIG_PE10_SOURCE_FORMAT__MASK) +#define VIVS_DE_BLOCK8_SRC_CONFIG_TRANSPARENCY__MASK 0x00000030 +#define VIVS_DE_BLOCK8_SRC_CONFIG_TRANSPARENCY__SHIFT 4 +#define VIVS_DE_BLOCK8_SRC_CONFIG_TRANSPARENCY(x) (((x) << VIVS_DE_BLOCK8_SRC_CONFIG_TRANSPARENCY__SHIFT) & VIVS_DE_BLOCK8_SRC_CONFIG_TRANSPARENCY__MASK) +#define VIVS_DE_BLOCK8_SRC_CONFIG_SRC_RELATIVE__MASK 0x00000040 +#define VIVS_DE_BLOCK8_SRC_CONFIG_SRC_RELATIVE__SHIFT 6 +#define VIVS_DE_BLOCK8_SRC_CONFIG_SRC_RELATIVE_ABSOLUTE 0x00000000 +#define VIVS_DE_BLOCK8_SRC_CONFIG_SRC_RELATIVE_RELATIVE 0x00000040 +#define VIVS_DE_BLOCK8_SRC_CONFIG_TILED__MASK 0x00000080 +#define VIVS_DE_BLOCK8_SRC_CONFIG_TILED__SHIFT 7 +#define VIVS_DE_BLOCK8_SRC_CONFIG_TILED_DISABLE 0x00000000 +#define VIVS_DE_BLOCK8_SRC_CONFIG_TILED_ENABLE 0x00000080 +#define VIVS_DE_BLOCK8_SRC_CONFIG_LOCATION__MASK 0x00000100 +#define VIVS_DE_BLOCK8_SRC_CONFIG_LOCATION__SHIFT 8 +#define VIVS_DE_BLOCK8_SRC_CONFIG_LOCATION_MEMORY 0x00000000 +#define VIVS_DE_BLOCK8_SRC_CONFIG_LOCATION_STREAM 0x00000100 +#define VIVS_DE_BLOCK8_SRC_CONFIG_PACK__MASK 0x00003000 +#define VIVS_DE_BLOCK8_SRC_CONFIG_PACK__SHIFT 12 +#define VIVS_DE_BLOCK8_SRC_CONFIG_PACK_PACKED8 0x00000000 +#define VIVS_DE_BLOCK8_SRC_CONFIG_PACK_PACKED16 0x00001000 +#define VIVS_DE_BLOCK8_SRC_CONFIG_PACK_PACKED32 0x00002000 +#define VIVS_DE_BLOCK8_SRC_CONFIG_PACK_UNPACKED 0x00003000 +#define VIVS_DE_BLOCK8_SRC_CONFIG_MONO_TRANSPARENCY__MASK 0x00008000 +#define VIVS_DE_BLOCK8_SRC_CONFIG_MONO_TRANSPARENCY__SHIFT 15 +#define VIVS_DE_BLOCK8_SRC_CONFIG_MONO_TRANSPARENCY_BACKGROUND 0x00000000 +#define VIVS_DE_BLOCK8_SRC_CONFIG_MONO_TRANSPARENCY_FOREGROUND 0x00008000 +#define VIVS_DE_BLOCK8_SRC_CONFIG_UNK16 0x00010000 +#define VIVS_DE_BLOCK8_SRC_CONFIG_SWIZZLE__MASK 0x00300000 +#define VIVS_DE_BLOCK8_SRC_CONFIG_SWIZZLE__SHIFT 20 +#define VIVS_DE_BLOCK8_SRC_CONFIG_SWIZZLE(x) (((x) << VIVS_DE_BLOCK8_SRC_CONFIG_SWIZZLE__SHIFT) & VIVS_DE_BLOCK8_SRC_CONFIG_SWIZZLE__MASK) +#define VIVS_DE_BLOCK8_SRC_CONFIG_SOURCE_FORMAT__MASK 0x1f000000 +#define VIVS_DE_BLOCK8_SRC_CONFIG_SOURCE_FORMAT__SHIFT 24 +#define VIVS_DE_BLOCK8_SRC_CONFIG_SOURCE_FORMAT(x) (((x) << VIVS_DE_BLOCK8_SRC_CONFIG_SOURCE_FORMAT__SHIFT) & VIVS_DE_BLOCK8_SRC_CONFIG_SOURCE_FORMAT__MASK) +#define VIVS_DE_BLOCK8_SRC_CONFIG_DISABLE420_L2_CACHE 0x20000000 +#define VIVS_DE_BLOCK8_SRC_CONFIG_ENDIAN_CONTROL__MASK 0xc0000000 +#define VIVS_DE_BLOCK8_SRC_CONFIG_ENDIAN_CONTROL__SHIFT 30 +#define VIVS_DE_BLOCK8_SRC_CONFIG_ENDIAN_CONTROL(x) (((x) << VIVS_DE_BLOCK8_SRC_CONFIG_ENDIAN_CONTROL__SHIFT) & VIVS_DE_BLOCK8_SRC_CONFIG_ENDIAN_CONTROL__MASK) + +#define VIVS_DE_BLOCK8_SRC_ORIGIN(i0) (0x00012a80 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_SRC_ORIGIN__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_SRC_ORIGIN__LEN 0x00000008 +#define VIVS_DE_BLOCK8_SRC_ORIGIN_X__MASK 0x0000ffff +#define VIVS_DE_BLOCK8_SRC_ORIGIN_X__SHIFT 0 +#define VIVS_DE_BLOCK8_SRC_ORIGIN_X(x) (((x) << VIVS_DE_BLOCK8_SRC_ORIGIN_X__SHIFT) & VIVS_DE_BLOCK8_SRC_ORIGIN_X__MASK) +#define VIVS_DE_BLOCK8_SRC_ORIGIN_Y__MASK 0xffff0000 +#define VIVS_DE_BLOCK8_SRC_ORIGIN_Y__SHIFT 16 +#define VIVS_DE_BLOCK8_SRC_ORIGIN_Y(x) (((x) << VIVS_DE_BLOCK8_SRC_ORIGIN_Y__SHIFT) & VIVS_DE_BLOCK8_SRC_ORIGIN_Y__MASK) + +#define VIVS_DE_BLOCK8_SRC_SIZE(i0) (0x00012aa0 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_SRC_SIZE__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_SRC_SIZE__LEN 0x00000008 +#define VIVS_DE_BLOCK8_SRC_SIZE_X__MASK 0x0000ffff +#define VIVS_DE_BLOCK8_SRC_SIZE_X__SHIFT 0 +#define VIVS_DE_BLOCK8_SRC_SIZE_X(x) (((x) << VIVS_DE_BLOCK8_SRC_SIZE_X__SHIFT) & VIVS_DE_BLOCK8_SRC_SIZE_X__MASK) +#define VIVS_DE_BLOCK8_SRC_SIZE_Y__MASK 0xffff0000 +#define VIVS_DE_BLOCK8_SRC_SIZE_Y__SHIFT 16 +#define VIVS_DE_BLOCK8_SRC_SIZE_Y(x) (((x) << VIVS_DE_BLOCK8_SRC_SIZE_Y__SHIFT) & VIVS_DE_BLOCK8_SRC_SIZE_Y__MASK) + +#define VIVS_DE_BLOCK8_SRC_COLOR_BG(i0) (0x00012ac0 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_SRC_COLOR_BG__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_SRC_COLOR_BG__LEN 0x00000008 + +#define VIVS_DE_BLOCK8_ROP(i0) (0x00012ae0 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_ROP__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_ROP__LEN 0x00000008 +#define VIVS_DE_BLOCK8_ROP_ROP_FG__MASK 0x000000ff +#define VIVS_DE_BLOCK8_ROP_ROP_FG__SHIFT 0 +#define VIVS_DE_BLOCK8_ROP_ROP_FG(x) (((x) << VIVS_DE_BLOCK8_ROP_ROP_FG__SHIFT) & VIVS_DE_BLOCK8_ROP_ROP_FG__MASK) +#define VIVS_DE_BLOCK8_ROP_ROP_BG__MASK 0x0000ff00 +#define VIVS_DE_BLOCK8_ROP_ROP_BG__SHIFT 8 +#define VIVS_DE_BLOCK8_ROP_ROP_BG(x) (((x) << VIVS_DE_BLOCK8_ROP_ROP_BG__SHIFT) & VIVS_DE_BLOCK8_ROP_ROP_BG__MASK) +#define VIVS_DE_BLOCK8_ROP_TYPE__MASK 0x00300000 +#define VIVS_DE_BLOCK8_ROP_TYPE__SHIFT 20 +#define VIVS_DE_BLOCK8_ROP_TYPE_ROP2_PATTERN 0x00000000 +#define VIVS_DE_BLOCK8_ROP_TYPE_ROP2_SOURCE 0x00100000 +#define VIVS_DE_BLOCK8_ROP_TYPE_ROP3 0x00200000 +#define VIVS_DE_BLOCK8_ROP_TYPE_ROP4 0x00300000 + +#define VIVS_DE_BLOCK8_ALPHA_CONTROL(i0) (0x00012b00 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_ALPHA_CONTROL__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_ALPHA_CONTROL__LEN 0x00000008 +#define VIVS_DE_BLOCK8_ALPHA_CONTROL_ENABLE__MASK 0x00000001 +#define VIVS_DE_BLOCK8_ALPHA_CONTROL_ENABLE__SHIFT 0 +#define VIVS_DE_BLOCK8_ALPHA_CONTROL_ENABLE_OFF 0x00000000 +#define VIVS_DE_BLOCK8_ALPHA_CONTROL_ENABLE_ON 0x00000001 +#define VIVS_DE_BLOCK8_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__MASK 0x00ff0000 +#define VIVS_DE_BLOCK8_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__SHIFT 16 +#define VIVS_DE_BLOCK8_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA(x) (((x) << VIVS_DE_BLOCK8_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__SHIFT) & VIVS_DE_BLOCK8_ALPHA_CONTROL_PE10_GLOBAL_SRC_ALPHA__MASK) +#define VIVS_DE_BLOCK8_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__MASK 0xff000000 +#define VIVS_DE_BLOCK8_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__SHIFT 24 +#define VIVS_DE_BLOCK8_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA(x) (((x) << VIVS_DE_BLOCK8_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__SHIFT) & VIVS_DE_BLOCK8_ALPHA_CONTROL_PE10_GLOBAL_DST_ALPHA__MASK) + +#define VIVS_DE_BLOCK8_ALPHA_MODES(i0) (0x00012b20 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_ALPHA_MODES__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_ALPHA_MODES__LEN 0x00000008 +#define VIVS_DE_BLOCK8_ALPHA_MODES_SRC_ALPHA_MODE__MASK 0x00000001 +#define VIVS_DE_BLOCK8_ALPHA_MODES_SRC_ALPHA_MODE__SHIFT 0 +#define VIVS_DE_BLOCK8_ALPHA_MODES_SRC_ALPHA_MODE_NORMAL 0x00000000 +#define VIVS_DE_BLOCK8_ALPHA_MODES_SRC_ALPHA_MODE_INVERSED 0x00000001 +#define VIVS_DE_BLOCK8_ALPHA_MODES_DST_ALPHA_MODE__MASK 0x00000010 +#define VIVS_DE_BLOCK8_ALPHA_MODES_DST_ALPHA_MODE__SHIFT 4 +#define VIVS_DE_BLOCK8_ALPHA_MODES_DST_ALPHA_MODE_NORMAL 0x00000000 +#define VIVS_DE_BLOCK8_ALPHA_MODES_DST_ALPHA_MODE_INVERSED 0x00000010 +#define VIVS_DE_BLOCK8_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE__MASK 0x00000300 +#define VIVS_DE_BLOCK8_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE__SHIFT 8 +#define VIVS_DE_BLOCK8_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE_NORMAL 0x00000000 +#define VIVS_DE_BLOCK8_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE_GLOBAL 0x00000100 +#define VIVS_DE_BLOCK8_ALPHA_MODES_GLOBAL_SRC_ALPHA_MODE_SCALED 0x00000200 +#define VIVS_DE_BLOCK8_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE__MASK 0x00003000 +#define VIVS_DE_BLOCK8_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE__SHIFT 12 +#define VIVS_DE_BLOCK8_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE_NORMAL 0x00000000 +#define VIVS_DE_BLOCK8_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE_GLOBAL 0x00001000 +#define VIVS_DE_BLOCK8_ALPHA_MODES_GLOBAL_DST_ALPHA_MODE_SCALED 0x00002000 +#define VIVS_DE_BLOCK8_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY__MASK 0x00010000 +#define VIVS_DE_BLOCK8_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY__SHIFT 16 +#define VIVS_DE_BLOCK8_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY_DISABLE 0x00000000 +#define VIVS_DE_BLOCK8_ALPHA_MODES_PE10_SRC_COLOR_MULTIPLY_ENABLE 0x00010000 +#define VIVS_DE_BLOCK8_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY__MASK 0x00100000 +#define VIVS_DE_BLOCK8_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY__SHIFT 20 +#define VIVS_DE_BLOCK8_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY_DISABLE 0x00000000 +#define VIVS_DE_BLOCK8_ALPHA_MODES_PE10_DST_COLOR_MULTIPLY_ENABLE 0x00100000 +#define VIVS_DE_BLOCK8_ALPHA_MODES_SRC_BLENDING_MODE__MASK 0x07000000 +#define VIVS_DE_BLOCK8_ALPHA_MODES_SRC_BLENDING_MODE__SHIFT 24 +#define VIVS_DE_BLOCK8_ALPHA_MODES_SRC_BLENDING_MODE(x) (((x) << VIVS_DE_BLOCK8_ALPHA_MODES_SRC_BLENDING_MODE__SHIFT) & VIVS_DE_BLOCK8_ALPHA_MODES_SRC_BLENDING_MODE__MASK) +#define VIVS_DE_BLOCK8_ALPHA_MODES_SRC_ALPHA_FACTOR__MASK 0x08000000 +#define VIVS_DE_BLOCK8_ALPHA_MODES_SRC_ALPHA_FACTOR__SHIFT 27 +#define VIVS_DE_BLOCK8_ALPHA_MODES_SRC_ALPHA_FACTOR_DISABLE 0x00000000 +#define VIVS_DE_BLOCK8_ALPHA_MODES_SRC_ALPHA_FACTOR_ENABLE 0x08000000 +#define VIVS_DE_BLOCK8_ALPHA_MODES_DST_BLENDING_MODE__MASK 0x70000000 +#define VIVS_DE_BLOCK8_ALPHA_MODES_DST_BLENDING_MODE__SHIFT 28 +#define VIVS_DE_BLOCK8_ALPHA_MODES_DST_BLENDING_MODE(x) (((x) << VIVS_DE_BLOCK8_ALPHA_MODES_DST_BLENDING_MODE__SHIFT) & VIVS_DE_BLOCK8_ALPHA_MODES_DST_BLENDING_MODE__MASK) +#define VIVS_DE_BLOCK8_ALPHA_MODES_DST_ALPHA_FACTOR__MASK 0x80000000 +#define VIVS_DE_BLOCK8_ALPHA_MODES_DST_ALPHA_FACTOR__SHIFT 31 +#define VIVS_DE_BLOCK8_ALPHA_MODES_DST_ALPHA_FACTOR_DISABLE 0x00000000 +#define VIVS_DE_BLOCK8_ALPHA_MODES_DST_ALPHA_FACTOR_ENABLE 0x80000000 + +#define VIVS_DE_BLOCK8_ADDRESS_U(i0) (0x00012b40 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_ADDRESS_U__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_ADDRESS_U__LEN 0x00000008 + +#define VIVS_DE_BLOCK8_STRIDE_U(i0) (0x00012b60 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_STRIDE_U__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_STRIDE_U__LEN 0x00000008 +#define VIVS_DE_BLOCK8_STRIDE_U_STRIDE__MASK 0x0003ffff +#define VIVS_DE_BLOCK8_STRIDE_U_STRIDE__SHIFT 0 +#define VIVS_DE_BLOCK8_STRIDE_U_STRIDE(x) (((x) << VIVS_DE_BLOCK8_STRIDE_U_STRIDE__SHIFT) & VIVS_DE_BLOCK8_STRIDE_U_STRIDE__MASK) + +#define VIVS_DE_BLOCK8_ADDRESS_V(i0) (0x00012b80 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_ADDRESS_V__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_ADDRESS_V__LEN 0x00000008 + +#define VIVS_DE_BLOCK8_STRIDE_V(i0) (0x00012ba0 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_STRIDE_V__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_STRIDE_V__LEN 0x00000008 +#define VIVS_DE_BLOCK8_STRIDE_V_STRIDE__MASK 0x0003ffff +#define VIVS_DE_BLOCK8_STRIDE_V_STRIDE__SHIFT 0 +#define VIVS_DE_BLOCK8_STRIDE_V_STRIDE(x) (((x) << VIVS_DE_BLOCK8_STRIDE_V_STRIDE__SHIFT) & VIVS_DE_BLOCK8_STRIDE_V_STRIDE__MASK) + +#define VIVS_DE_BLOCK8_SRC_ROTATION_HEIGHT(i0) (0x00012bc0 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_SRC_ROTATION_HEIGHT__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_SRC_ROTATION_HEIGHT__LEN 0x00000008 +#define VIVS_DE_BLOCK8_SRC_ROTATION_HEIGHT_HEIGHT__MASK 0x0000ffff +#define VIVS_DE_BLOCK8_SRC_ROTATION_HEIGHT_HEIGHT__SHIFT 0 +#define VIVS_DE_BLOCK8_SRC_ROTATION_HEIGHT_HEIGHT(x) (((x) << VIVS_DE_BLOCK8_SRC_ROTATION_HEIGHT_HEIGHT__SHIFT) & VIVS_DE_BLOCK8_SRC_ROTATION_HEIGHT_HEIGHT__MASK) + +#define VIVS_DE_BLOCK8_ROT_ANGLE(i0) (0x00012be0 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_ROT_ANGLE__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_ROT_ANGLE__LEN 0x00000008 +#define VIVS_DE_BLOCK8_ROT_ANGLE_SRC__MASK 0x00000007 +#define VIVS_DE_BLOCK8_ROT_ANGLE_SRC__SHIFT 0 +#define VIVS_DE_BLOCK8_ROT_ANGLE_SRC(x) (((x) << VIVS_DE_BLOCK8_ROT_ANGLE_SRC__SHIFT) & VIVS_DE_BLOCK8_ROT_ANGLE_SRC__MASK) +#define VIVS_DE_BLOCK8_ROT_ANGLE_DST__MASK 0x00000038 +#define VIVS_DE_BLOCK8_ROT_ANGLE_DST__SHIFT 3 +#define VIVS_DE_BLOCK8_ROT_ANGLE_DST(x) (((x) << VIVS_DE_BLOCK8_ROT_ANGLE_DST__SHIFT) & VIVS_DE_BLOCK8_ROT_ANGLE_DST__MASK) +#define VIVS_DE_BLOCK8_ROT_ANGLE_SRC_MASK 0x00000100 +#define VIVS_DE_BLOCK8_ROT_ANGLE_DST_MASK 0x00000200 +#define VIVS_DE_BLOCK8_ROT_ANGLE_SRC_MIRROR__MASK 0x00003000 +#define VIVS_DE_BLOCK8_ROT_ANGLE_SRC_MIRROR__SHIFT 12 +#define VIVS_DE_BLOCK8_ROT_ANGLE_SRC_MIRROR(x) (((x) << VIVS_DE_BLOCK8_ROT_ANGLE_SRC_MIRROR__SHIFT) & VIVS_DE_BLOCK8_ROT_ANGLE_SRC_MIRROR__MASK) +#define VIVS_DE_BLOCK8_ROT_ANGLE_SRC_MIRROR_MASK 0x00008000 +#define VIVS_DE_BLOCK8_ROT_ANGLE_DST_MIRROR__MASK 0x00030000 +#define VIVS_DE_BLOCK8_ROT_ANGLE_DST_MIRROR__SHIFT 16 +#define VIVS_DE_BLOCK8_ROT_ANGLE_DST_MIRROR(x) (((x) << VIVS_DE_BLOCK8_ROT_ANGLE_DST_MIRROR__SHIFT) & VIVS_DE_BLOCK8_ROT_ANGLE_DST_MIRROR__MASK) +#define VIVS_DE_BLOCK8_ROT_ANGLE_DST_MIRROR_MASK 0x00080000 + +#define VIVS_DE_BLOCK8_GLOBAL_SRC_COLOR(i0) (0x00012c00 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_GLOBAL_SRC_COLOR__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_GLOBAL_SRC_COLOR__LEN 0x00000008 + +#define VIVS_DE_BLOCK8_GLOBAL_DEST_COLOR(i0) (0x00012c20 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_GLOBAL_DEST_COLOR__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_GLOBAL_DEST_COLOR__LEN 0x00000008 + +#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES(i0) (0x00012c40 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES__LEN 0x00000008 +#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY__MASK 0x00000001 +#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY__SHIFT 0 +#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_DISABLE 0x00000000 +#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_SRC_PREMULTIPLY_ENABLE 0x00000001 +#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY__MASK 0x00000010 +#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY__SHIFT 4 +#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY_DISABLE 0x00000000 +#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_DST_PREMULTIPLY_ENABLE 0x00000010 +#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY__MASK 0x00000300 +#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY__SHIFT 8 +#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY_DISABLE 0x00000000 +#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY_ALPHA 0x00000100 +#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_SRC_GLOBAL_PREMULTIPLY_COLOR 0x00000200 +#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY__MASK 0x00100000 +#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY__SHIFT 20 +#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY_DISABLE 0x00000000 +#define VIVS_DE_BLOCK8_COLOR_MULTIPLY_MODES_DST_DEMULTIPLY_ENABLE 0x00100000 + +#define VIVS_DE_BLOCK8_TRANSPARENCY(i0) (0x00012c60 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_TRANSPARENCY__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_TRANSPARENCY__LEN 0x00000008 +#define VIVS_DE_BLOCK8_TRANSPARENCY_SOURCE__MASK 0x00000003 +#define VIVS_DE_BLOCK8_TRANSPARENCY_SOURCE__SHIFT 0 +#define VIVS_DE_BLOCK8_TRANSPARENCY_SOURCE_OPAQUE 0x00000000 +#define VIVS_DE_BLOCK8_TRANSPARENCY_SOURCE_MASK 0x00000001 +#define VIVS_DE_BLOCK8_TRANSPARENCY_SOURCE_KEY 0x00000002 +#define VIVS_DE_BLOCK8_TRANSPARENCY_PATTERN__MASK 0x00000030 +#define VIVS_DE_BLOCK8_TRANSPARENCY_PATTERN__SHIFT 4 +#define VIVS_DE_BLOCK8_TRANSPARENCY_PATTERN_OPAQUE 0x00000000 +#define VIVS_DE_BLOCK8_TRANSPARENCY_PATTERN_MASK 0x00000010 +#define VIVS_DE_BLOCK8_TRANSPARENCY_PATTERN_KEY 0x00000020 +#define VIVS_DE_BLOCK8_TRANSPARENCY_DESTINATION__MASK 0x00000300 +#define VIVS_DE_BLOCK8_TRANSPARENCY_DESTINATION__SHIFT 8 +#define VIVS_DE_BLOCK8_TRANSPARENCY_DESTINATION_OPAQUE 0x00000000 +#define VIVS_DE_BLOCK8_TRANSPARENCY_DESTINATION_MASK 0x00000100 +#define VIVS_DE_BLOCK8_TRANSPARENCY_DESTINATION_KEY 0x00000200 +#define VIVS_DE_BLOCK8_TRANSPARENCY_TRANSPARENCY_MASK 0x00001000 +#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_SRC_OVERRIDE__MASK 0x00030000 +#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_SRC_OVERRIDE__SHIFT 16 +#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_SRC_OVERRIDE_DEFAULT 0x00000000 +#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_SRC_OVERRIDE_USE_ENABLE 0x00010000 +#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_SRC_OVERRIDE_USE_DISABLE 0x00020000 +#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_PAT_OVERRIDE__MASK 0x00300000 +#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_PAT_OVERRIDE__SHIFT 20 +#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_PAT_OVERRIDE_DEFAULT 0x00000000 +#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_PAT_OVERRIDE_USE_ENABLE 0x00100000 +#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_PAT_OVERRIDE_USE_DISABLE 0x00200000 +#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_DST_OVERRIDE__MASK 0x03000000 +#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_DST_OVERRIDE__SHIFT 24 +#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_DST_OVERRIDE_DEFAULT 0x00000000 +#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_DST_OVERRIDE_USE_ENABLE 0x01000000 +#define VIVS_DE_BLOCK8_TRANSPARENCY_USE_DST_OVERRIDE_USE_DISABLE 0x02000000 +#define VIVS_DE_BLOCK8_TRANSPARENCY_RESOURCE_OVERRIDE_MASK 0x10000000 +#define VIVS_DE_BLOCK8_TRANSPARENCY_DFB_COLOR_KEY__MASK 0x20000000 +#define VIVS_DE_BLOCK8_TRANSPARENCY_DFB_COLOR_KEY__SHIFT 29 +#define VIVS_DE_BLOCK8_TRANSPARENCY_DFB_COLOR_KEY_DISABLE 0x00000000 +#define VIVS_DE_BLOCK8_TRANSPARENCY_DFB_COLOR_KEY_ENABLE 0x20000000 +#define VIVS_DE_BLOCK8_TRANSPARENCY_DFB_COLOR_KEY_MASK 0x80000000 + +#define VIVS_DE_BLOCK8_CONTROL(i0) (0x00012c80 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_CONTROL__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_CONTROL__LEN 0x00000008 +#define VIVS_DE_BLOCK8_CONTROL_YUV__MASK 0x00000001 +#define VIVS_DE_BLOCK8_CONTROL_YUV__SHIFT 0 +#define VIVS_DE_BLOCK8_CONTROL_YUV_601 0x00000000 +#define VIVS_DE_BLOCK8_CONTROL_YUV_709 0x00000001 +#define VIVS_DE_BLOCK8_CONTROL_YUV_MASK 0x00000008 +#define VIVS_DE_BLOCK8_CONTROL_UV_SWIZZLE__MASK 0x00000010 +#define VIVS_DE_BLOCK8_CONTROL_UV_SWIZZLE__SHIFT 4 +#define VIVS_DE_BLOCK8_CONTROL_UV_SWIZZLE_UV 0x00000000 +#define VIVS_DE_BLOCK8_CONTROL_UV_SWIZZLE_VU 0x00000010 +#define VIVS_DE_BLOCK8_CONTROL_UV_SWIZZLE_MASK 0x00000080 +#define VIVS_DE_BLOCK8_CONTROL_YUVRGB__MASK 0x00000100 +#define VIVS_DE_BLOCK8_CONTROL_YUVRGB__SHIFT 8 +#define VIVS_DE_BLOCK8_CONTROL_YUVRGB_DISABLE 0x00000000 +#define VIVS_DE_BLOCK8_CONTROL_YUVRGB_ENABLE 0x00000100 +#define VIVS_DE_BLOCK8_CONTROL_YUVRGB_MASK 0x00000800 + +#define VIVS_DE_BLOCK8_SRC_COLOR_KEY_HIGH(i0) (0x00012ca0 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_SRC_COLOR_KEY_HIGH__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_SRC_COLOR_KEY_HIGH__LEN 0x00000008 + +#define VIVS_DE_BLOCK8_SRC_EX_CONFIG(i0) (0x00012cc0 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_SRC_EX_CONFIG__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_SRC_EX_CONFIG__LEN 0x00000008 +#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_MULTI_TILED__MASK 0x00000001 +#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_MULTI_TILED__SHIFT 0 +#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_MULTI_TILED_DISABLE 0x00000000 +#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_MULTI_TILED_ENABLE 0x00000001 +#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_SUPER_TILED__MASK 0x00000008 +#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_SUPER_TILED__SHIFT 3 +#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_SUPER_TILED_DISABLE 0x00000000 +#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_SUPER_TILED_ENABLE 0x00000008 +#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_MINOR_TILED__MASK 0x00000100 +#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_MINOR_TILED__SHIFT 8 +#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_MINOR_TILED_DISABLE 0x00000000 +#define VIVS_DE_BLOCK8_SRC_EX_CONFIG_MINOR_TILED_ENABLE 0x00000100 + +#define VIVS_DE_BLOCK8_SRC_EX_ADDRESS(i0) (0x00012ce0 + 0x4*(i0)) +#define VIVS_DE_BLOCK8_SRC_EX_ADDRESS__ESIZE 0x00000004 +#define VIVS_DE_BLOCK8_SRC_EX_ADDRESS__LEN 0x00000008 + + +#endif /* STATE_2D_XML */ diff --git a/tests/etnaviv/write_bmp.c b/tests/etnaviv/write_bmp.c new file mode 100644 index 0000000..f7b6bc6 --- /dev/null +++ b/tests/etnaviv/write_bmp.c @@ -0,0 +1,149 @@ +/* + * Copyright 2011 Luc Verhaegen + * + * 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 + * 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. + * + */ +/* + * Quick 'n Dirty bitmap dumper. + */ +#include +#include +#include +#include +#include +#include +#include + +#include "write_bmp.h" + +#define FILENAME_SIZE 1024 + +struct bmp_header { + unsigned short magic; + unsigned int size; + unsigned int unused; + unsigned int start; +} __attribute__((__packed__)); + +struct dib_header { + unsigned int size; + unsigned int width; + unsigned int height; + unsigned short planes; + unsigned short bpp; + unsigned int compression; + unsigned int data_size; + unsigned int h_res; + unsigned int v_res; + unsigned int colours; + unsigned int important_colours; + unsigned int red_mask; + unsigned int green_mask; + unsigned int blue_mask; + unsigned int alpha_mask; + unsigned int colour_space; + unsigned int unused[12]; +} __attribute__((__packed__)); + +static void +bmp_header_write(int fd, int width, int height, int bgra, int noflip, int alpha) +{ + struct bmp_header bmp_header = { + .magic = 0x4d42, + .size = (width * height * 4) + + sizeof(struct bmp_header) + sizeof(struct dib_header), + .start = sizeof(struct bmp_header) + sizeof(struct dib_header), + }; + struct dib_header dib_header = { + .size = sizeof(struct dib_header), + .width = width, + .height = noflip ? -height : height, + .planes = 1, + .bpp = 32, + .compression = 3, + .data_size = 4 * width * height, + .h_res = 0xB13, + .v_res = 0xB13, + .colours = 0, + .important_colours = 0, + .red_mask = 0x000000FF, + .green_mask = 0x0000FF00, + .blue_mask = 0x00FF0000, + .alpha_mask = alpha ? 0xFF000000 : 0x00000000, + .colour_space = 0x57696E20, + }; + + if (bgra) { + dib_header.red_mask = 0x00FF0000; + dib_header.blue_mask = 0x000000FF; + } + + write(fd, &bmp_header, sizeof(struct bmp_header)); + write(fd, &dib_header, sizeof(struct dib_header)); +} + +void +bmp_dump32(char *buffer, unsigned width, unsigned height, bool bgra, const char *filename) +{ + int fd; + + fd = open(filename, O_WRONLY| O_TRUNC | O_CREAT, 0666); + if (fd == -1) { + printf("Failed to open %s: %s\n", filename, strerror(errno)); + return; + } + + bmp_header_write(fd, width, height, bgra, false, true); + + write(fd, buffer, width * height * 4); +} + +void +bmp_dump32_noflip(char *buffer, unsigned width, unsigned height, bool bgra, const char *filename) +{ + int fd; + + fd = open(filename, O_WRONLY| O_TRUNC | O_CREAT, 0666); + if (fd == -1) { + printf("Failed to open %s: %s\n", filename, strerror(errno)); + return; + } + + bmp_header_write(fd, width, height, bgra, true, true); + + write(fd, buffer, width * height * 4); +} + +void +bmp_dump32_ex(char *buffer, unsigned width, unsigned height, bool flip, bool bgra, bool alpha, const char *filename) +{ + int fd; + + fd = open(filename, O_WRONLY| O_TRUNC | O_CREAT, 0666); + if (fd == -1) { + printf("Failed to open %s: %s\n", filename, strerror(errno)); + return; + } + + bmp_header_write(fd, width, height, bgra, flip, alpha); + + write(fd, buffer, width * height * 4); +} diff --git a/tests/etnaviv/write_bmp.h b/tests/etnaviv/write_bmp.h new file mode 100644 index 0000000..667fa87 --- /dev/null +++ b/tests/etnaviv/write_bmp.h @@ -0,0 +1,34 @@ +/* + * Copyright 2011 Luc Verhaegen + * + * 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 + * 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. + * + */ +#ifndef BMP_DUMP_H +#define BMP_DUMP_H 1 +#include +/* write 32-bit image (y axis upwards) */ +void bmp_dump32(char *buffer, unsigned width, unsigned height, bool bgra, const char *filename); +/* write 32-bit image (y axis downwards) */ +void bmp_dump32_noflip(char *buffer, unsigned width, unsigned height, bool bgra, const char *filename); +/* write 32-bit image */ +void bmp_dump32_ex(char *buffer, unsigned width, unsigned height, bool flip, bool bgra, bool alpha, const char *filename); + +#endif /* BMP_DUMP_H */ diff --git a/tests/exynos/exynos_fimg2d_event.c b/tests/exynos/exynos_fimg2d_event.c new file mode 100644 index 0000000..353e087 --- /dev/null +++ b/tests/exynos/exynos_fimg2d_event.c @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2015 - Tobias Jakobi + * + * 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS 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. + */ + +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include "exynos_drm.h" +#include "exynos_drmif.h" +#include "exynos_fimg2d.h" + +struct g2d_job { + unsigned int id; + unsigned int busy; +}; + +struct exynos_evhandler { + struct pollfd fds; + struct exynos_event_context evctx; +}; + +struct threaddata { + unsigned int stop; + struct exynos_device *dev; + struct exynos_evhandler evhandler; +}; + +static void g2d_event_handler(int fd, unsigned int cmdlist_no, unsigned int tv_sec, + unsigned int tv_usec, void *user_data) +{ + struct g2d_job *job = user_data; + + fprintf(stderr, "info: g2d job (id = %u, cmdlist number = %u) finished!\n", + job->id, cmdlist_no); + + job->busy = 0; +} + +static void setup_g2d_event_handler(struct exynos_evhandler *evhandler, int fd) +{ + evhandler->fds.fd = fd; + evhandler->fds.events = POLLIN; + evhandler->evctx.base.version = 2; + evhandler->evctx.version = 1; + evhandler->evctx.g2d_event_handler = g2d_event_handler; +} + +static void* threadfunc(void *arg) { + const int timeout = 0; + struct threaddata *data; + + data = arg; + + while (1) { + if (data->stop) break; + + usleep(500); + + data->evhandler.fds.revents = 0; + + if (poll(&data->evhandler.fds, 1, timeout) < 0) + continue; + + if (data->evhandler.fds.revents & (POLLHUP | POLLERR)) + continue; + + if (data->evhandler.fds.revents & POLLIN) + exynos_handle_event(data->dev, &data->evhandler.evctx); + } + + pthread_exit(0); +} + +/* + * We need to wait until all G2D jobs are finished, otherwise we + * potentially remove a BO which the engine still operates on. + * This results in the following kernel message: + * [drm:exynos_drm_gem_put_dma_addr] *ERROR* failed to lookup gem object. + * Also any subsequent BO allocations fail then with: + * [drm:exynos_drm_alloc_buf] *ERROR* failed to allocate buffer. + */ +static void wait_all_jobs(struct g2d_job* jobs, unsigned num_jobs) +{ + unsigned i; + + for (i = 0; i < num_jobs; ++i) { + while (jobs[i].busy) + usleep(500); + } + +} + +static struct g2d_job* free_job(struct g2d_job* jobs, unsigned num_jobs) +{ + unsigned i; + + for (i = 0; i < num_jobs; ++i) { + if (jobs[i].busy == 0) + return &jobs[i]; + } + + return NULL; +} + +static int g2d_work(struct g2d_context *ctx, struct g2d_image *img, + unsigned num_jobs, unsigned iterations) +{ + struct g2d_job *jobs = calloc(num_jobs, sizeof(struct g2d_job)); + int ret; + unsigned i; + + /* setup job ids */ + for (i = 0; i < num_jobs; ++i) + jobs[i].id = i; + + for (i = 0; i < iterations; ++i) { + unsigned x, y, w, h; + + struct g2d_job *j = NULL; + + while (1) { + j = free_job(jobs, num_jobs); + + if (j) + break; + else + usleep(500); + } + + x = rand() % img->width; + y = rand() % img->height; + + if (x == (img->width - 1)) + x -= 1; + if (y == (img->height - 1)) + y -= 1; + + w = rand() % (img->width - x); + h = rand() % (img->height - y); + + if (w == 0) w = 1; + if (h == 0) h = 1; + + img->color = rand(); + + j->busy = 1; + g2d_config_event(ctx, j); + + ret = g2d_solid_fill(ctx, img, x, y, w, h); + + if (ret == 0) + g2d_exec(ctx); + + if (ret != 0) { + fprintf(stderr, "error: iteration %u (x = %u, x = %u, x = %u, x = %u) failed\n", + i, x, y, w, h); + break; + } + } + + wait_all_jobs(jobs, num_jobs); + free(jobs); + + return 0; +} + +static void usage(const char *name) +{ + fprintf(stderr, "usage: %s [-ijwh]\n\n", name); + + fprintf(stderr, "\t-i \n"); + fprintf(stderr, "\t-j (default = 4)\n\n"); + + fprintf(stderr, "\t-w (default = 4096)\n"); + fprintf(stderr, "\t-h (default = 4096)\n"); + + exit(0); +} + +int main(int argc, char **argv) +{ + int fd, ret, c, parsefail; + + pthread_t event_thread; + struct threaddata event_data = {0}; + + struct exynos_device *dev; + struct g2d_context *ctx; + struct exynos_bo *bo; + + struct g2d_image img = {0}; + + unsigned int iters = 0, njobs = 4; + unsigned int bufw = 4096, bufh = 4096; + + ret = 0; + parsefail = 0; + + while ((c = getopt(argc, argv, "i:j:w:h:")) != -1) { + switch (c) { + case 'i': + if (sscanf(optarg, "%u", &iters) != 1) + parsefail = 1; + break; + case 'j': + if (sscanf(optarg, "%u", &njobs) != 1) + parsefail = 1; + break; + case 'w': + if (sscanf(optarg, "%u", &bufw) != 1) + parsefail = 1; + break; + case 'h': + if (sscanf(optarg, "%u", &bufh) != 1) + parsefail = 1; + break; + default: + parsefail = 1; + break; + } + } + + if (parsefail || (argc == 1) || (iters == 0)) + usage(argv[0]); + + if (bufw > 4096 || bufh > 4096) { + fprintf(stderr, "error: buffer width/height should be less than 4096.\n"); + ret = -1; + + goto out; + } + + if (bufw == 0 || bufh == 0) { + fprintf(stderr, "error: buffer width/height should be non-zero.\n"); + ret = -1; + + goto out; + } + + fd = drmOpen("exynos", NULL); + if (fd < 0) { + fprintf(stderr, "error: failed to open drm\n"); + ret = -1; + + goto out; + } + + dev = exynos_device_create(fd); + if (dev == NULL) { + fprintf(stderr, "error: failed to create device\n"); + ret = -2; + + goto fail; + } + + ctx = g2d_init(fd); + if (ctx == NULL) { + fprintf(stderr, "error: failed to init G2D\n"); + ret = -3; + + goto g2d_fail; + } + + bo = exynos_bo_create(dev, bufw * bufh * 4, 0); + if (bo == NULL) { + fprintf(stderr, "error: failed to create bo\n"); + ret = -4; + + goto bo_fail; + } + + /* setup g2d image object */ + img.width = bufw; + img.height = bufh; + img.stride = bufw * 4; + img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + img.buf_type = G2D_IMGBUF_GEM; + img.bo[0] = bo->handle; + + event_data.dev = dev; + setup_g2d_event_handler(&event_data.evhandler, fd); + + pthread_create(&event_thread, NULL, threadfunc, &event_data); + + ret = g2d_work(ctx, &img, njobs, iters); + if (ret != 0) + fprintf(stderr, "error: g2d_work failed\n"); + + event_data.stop = 1; + pthread_join(event_thread, NULL); + + exynos_bo_destroy(bo); + +bo_fail: + g2d_fini(ctx); + +g2d_fail: + exynos_device_destroy(dev); + +fail: + drmClose(fd); + +out: + return ret; +} diff --git a/tests/exynos/exynos_fimg2d_perf.c b/tests/exynos/exynos_fimg2d_perf.c new file mode 100644 index 0000000..97691a7 --- /dev/null +++ b/tests/exynos/exynos_fimg2d_perf.c @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2015 - Tobias Jakobi + * + * 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS 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. + */ + +#include +#include +#include +#include +#include + +#include + +#include "exynos_drm.h" +#include "exynos_drmif.h" +#include "exynos_fimg2d.h" + +static int output_mathematica = 0; + +static int fimg2d_perf_simple(struct exynos_bo *bo, struct g2d_context *ctx, + unsigned buf_width, unsigned buf_height, unsigned iterations) +{ + struct timespec tspec = { 0 }; + struct g2d_image img = { 0 }; + + unsigned long long g2d_time; + unsigned i; + int ret = 0; + + img.width = buf_width; + img.height = buf_height; + img.stride = buf_width * 4; + img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + img.buf_type = G2D_IMGBUF_GEM; + img.bo[0] = bo->handle; + + srand(time(NULL)); + + printf("starting simple G2D performance test\n"); + printf("buffer width = %u, buffer height = %u, iterations = %u\n", + buf_width, buf_height, iterations); + + if (output_mathematica) + putchar('{'); + + for (i = 0; i < iterations; ++i) { + unsigned x, y, w, h; + + x = rand() % buf_width; + y = rand() % buf_height; + + if (x == (buf_width - 1)) + x -= 1; + if (y == (buf_height - 1)) + y -= 1; + + w = rand() % (buf_width - x); + h = rand() % (buf_height - y); + + if (w == 0) w = 1; + if (h == 0) h = 1; + + img.color = rand(); + + ret = g2d_solid_fill(ctx, &img, x, y, w, h); + + clock_gettime(CLOCK_MONOTONIC, &tspec); + + if (ret == 0) + ret = g2d_exec(ctx); + + if (ret != 0) { + fprintf(stderr, "error: iteration %u failed (x = %u, y = %u, w = %u, h = %u)\n", + i, x, y, w, h); + break; + } else { + struct timespec end = { 0 }; + clock_gettime(CLOCK_MONOTONIC, &end); + + g2d_time = (end.tv_sec - tspec.tv_sec) * 1000000000ULL; + g2d_time += (end.tv_nsec - tspec.tv_nsec); + + if (output_mathematica) { + if (i != 0) putchar(','); + printf("{%u,%llu}", w * h, g2d_time); + } else { + printf("num_pixels = %u, usecs = %llu\n", w * h, g2d_time); + } + } + } + + if (output_mathematica) + printf("}\n"); + + return ret; +} + +static int fimg2d_perf_multi(struct exynos_bo *bo, struct g2d_context *ctx, + unsigned buf_width, unsigned buf_height, unsigned iterations, unsigned batch) +{ + struct timespec tspec = { 0 }; + struct g2d_image *images; + + unsigned long long g2d_time; + unsigned i, j; + int ret = 0; + + images = calloc(batch, sizeof(struct g2d_image)); + if (images == NULL) { + fprintf(stderr, "error: failed to allocate G2D images.\n"); + return -ENOMEM; + } + + for (i = 0; i < batch; ++i) { + images[i].width = buf_width; + images[i].height = buf_height; + images[i].stride = buf_width * 4; + images[i].color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + images[i].buf_type = G2D_IMGBUF_GEM; + images[i].bo[0] = bo->handle; + } + + srand(time(NULL)); + + printf("starting multi G2D performance test (batch size = %u)\n", batch); + printf("buffer width = %u, buffer height = %u, iterations = %u\n", + buf_width, buf_height, iterations); + + if (output_mathematica) + putchar('{'); + + for (i = 0; i < iterations; ++i) { + unsigned num_pixels = 0; + + for (j = 0; j < batch; ++j) { + unsigned x, y, w, h; + + x = rand() % buf_width; + y = rand() % buf_height; + + if (x == (buf_width - 1)) + x -= 1; + if (y == (buf_height - 1)) + y -= 1; + + w = rand() % (buf_width - x); + h = rand() % (buf_height - y); + + if (w == 0) w = 1; + if (h == 0) h = 1; + + images[j].color = rand(); + + num_pixels += w * h; + + ret = g2d_solid_fill(ctx, &images[j], x, y, w, h); + if (ret != 0) + break; + } + + clock_gettime(CLOCK_MONOTONIC, &tspec); + + if (ret == 0) + ret = g2d_exec(ctx); + + if (ret != 0) { + fprintf(stderr, "error: iteration %u failed (num_pixels = %u)\n", i, num_pixels); + break; + } else { + struct timespec end = { 0 }; + clock_gettime(CLOCK_MONOTONIC, &end); + + g2d_time = (end.tv_sec - tspec.tv_sec) * 1000000000ULL; + g2d_time += (end.tv_nsec - tspec.tv_nsec); + + if (output_mathematica) { + if (i != 0) putchar(','); + printf("{%u,%llu}", num_pixels, g2d_time); + } else { + printf("num_pixels = %u, usecs = %llu\n", num_pixels, g2d_time); + } + } + } + + if (output_mathematica) + printf("}\n"); + + free(images); + + return ret; +} + +static void usage(const char *name) +{ + fprintf(stderr, "usage: %s [-ibwh]\n\n", name); + + fprintf(stderr, "\t-i \n"); + fprintf(stderr, "\t-b (default = 3)\n\n"); + + fprintf(stderr, "\t-w (default = 4096)\n"); + fprintf(stderr, "\t-h (default = 4096)\n\n"); + + fprintf(stderr, "\t-M \n"); + + exit(0); +} + +int main(int argc, char **argv) +{ + int fd, ret, c, parsefail; + + struct exynos_device *dev; + struct g2d_context *ctx; + struct exynos_bo *bo; + + unsigned int iters = 0, batch = 3; + unsigned int bufw = 4096, bufh = 4096; + + ret = 0; + parsefail = 0; + + while ((c = getopt(argc, argv, "i:b:w:h:M")) != -1) { + switch (c) { + case 'i': + if (sscanf(optarg, "%u", &iters) != 1) + parsefail = 1; + break; + case 'b': + if (sscanf(optarg, "%u", &batch) != 1) + parsefail = 1; + break; + case 'w': + if (sscanf(optarg, "%u", &bufw) != 1) + parsefail = 1; + break; + case 'h': + if (sscanf(optarg, "%u", &bufh) != 1) + parsefail = 1; + break; + case 'M': + output_mathematica = 1; + break; + default: + parsefail = 1; + break; + } + } + + if (parsefail || (argc == 1) || (iters == 0)) + usage(argv[0]); + + if (bufw < 2 || bufw > 4096 || bufh < 2 || bufh > 4096) { + fprintf(stderr, "error: buffer width/height should be in the range 2 to 4096.\n"); + ret = -1; + + goto out; + } + + fd = drmOpen("exynos", NULL); + if (fd < 0) { + fprintf(stderr, "error: failed to open drm\n"); + ret = -1; + + goto out; + } + + dev = exynos_device_create(fd); + if (dev == NULL) { + fprintf(stderr, "error: failed to create device\n"); + ret = -2; + + goto fail; + } + + ctx = g2d_init(fd); + if (ctx == NULL) { + fprintf(stderr, "error: failed to init G2D\n"); + ret = -3; + + goto g2d_fail; + } + + bo = exynos_bo_create(dev, bufw * bufh * 4, 0); + if (bo == NULL) { + fprintf(stderr, "error: failed to create bo\n"); + ret = -4; + + goto bo_fail; + } + + ret = fimg2d_perf_simple(bo, ctx, bufw, bufh, iters); + + if (ret == 0) + ret = fimg2d_perf_multi(bo, ctx, bufw, bufh, iters, batch); + + exynos_bo_destroy(bo); + +bo_fail: + g2d_fini(ctx); + +g2d_fail: + exynos_device_destroy(dev); + +fail: + drmClose(fd); + +out: + return ret; +} diff --git a/tests/exynos/exynos_fimg2d_test.c b/tests/exynos/exynos_fimg2d_test.c new file mode 100644 index 0000000..d85e2f6 --- /dev/null +++ b/tests/exynos/exynos_fimg2d_test.c @@ -0,0 +1,903 @@ +/* + * Copyright (C) 2013 Samsung Electronics Co.Ltd + * Authors: + * Inki Dae + * + * 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * VA LINUX SYSTEMS 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. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "exynos_drm.h" +#include "exynos_drmif.h" +#include "exynos_fimg2d.h" + +#define DRM_MODULE_NAME "exynos" + +static unsigned int screen_width, screen_height; + +struct connector { + uint32_t id; + char mode_str[64]; + drmModeModeInfo *mode; + drmModeEncoder *encoder; + int crtc; +}; + +static void connector_find_mode(int fd, struct connector *c, + drmModeRes *resources) +{ + drmModeConnector *connector; + int i, j; + + /* First, find the connector & mode */ + c->mode = NULL; + for (i = 0; i < resources->count_connectors; i++) { + connector = drmModeGetConnector(fd, resources->connectors[i]); + + if (!connector) { + fprintf(stderr, "could not get connector %i: %s\n", + resources->connectors[i], strerror(errno)); + continue; + } + + if (!connector->count_modes) { + drmModeFreeConnector(connector); + continue; + } + + if (connector->connector_id != c->id) { + drmModeFreeConnector(connector); + continue; + } + + for (j = 0; j < connector->count_modes; j++) { + c->mode = &connector->modes[j]; + if (!strcmp(c->mode->name, c->mode_str)) + break; + } + + /* Found it, break out */ + if (c->mode) + break; + + drmModeFreeConnector(connector); + } + + if (!c->mode) { + fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str); + return; + } + + /* Now get the encoder */ + for (i = 0; i < resources->count_encoders; i++) { + c->encoder = drmModeGetEncoder(fd, resources->encoders[i]); + + if (!c->encoder) { + fprintf(stderr, "could not get encoder %i: %s\n", + resources->encoders[i], strerror(errno)); + continue; + } + + if (c->encoder->encoder_id == connector->encoder_id) + break; + + drmModeFreeEncoder(c->encoder); + } + + if (c->crtc == -1) + c->crtc = c->encoder->crtc_id; +} + +static int drm_set_crtc(struct exynos_device *dev, struct connector *c, + unsigned int fb_id) +{ + int ret; + + ret = drmModeSetCrtc(dev->fd, c->crtc, + fb_id, 0, 0, &c->id, 1, c->mode); + if (ret) + drmMsg("failed to set mode: %s\n", strerror(errno)); + + return ret; +} + +static struct exynos_bo *exynos_create_buffer(struct exynos_device *dev, + unsigned long size, + unsigned int flags) +{ + struct exynos_bo *bo; + + bo = exynos_bo_create(dev, size, flags); + if (!bo) + return bo; + + if (!exynos_bo_map(bo)) { + exynos_bo_destroy(bo); + return NULL; + } + + return bo; +} + +/* Allocate buffer and fill it with checkerboard pattern, where the tiles * + * have a random color. The caller has to free the buffer. */ +static void *create_checkerboard_pattern(unsigned int num_tiles_x, + unsigned int num_tiles_y, unsigned int tile_size) +{ + unsigned int *buf; + unsigned int x, y, i, j; + const unsigned int stride = num_tiles_x * tile_size; + + if (posix_memalign((void*)&buf, 64, num_tiles_y * tile_size * stride * 4) != 0) + return NULL; + + for (x = 0; x < num_tiles_x; ++x) { + for (y = 0; y < num_tiles_y; ++y) { + const unsigned int color = 0xff000000 + (random() & 0xffffff); + + for (i = 0; i < tile_size; ++i) { + for (j = 0; j < tile_size; ++j) { + buf[x * tile_size + y * stride * tile_size + i + j * stride] = color; + } + } + } + } + + return buf; +} + +static void exynos_destroy_buffer(struct exynos_bo *bo) +{ + exynos_bo_destroy(bo); +} + +static void wait_for_user_input(int last) +{ + printf("press to %s\n", last ? "exit test application" : + "skip to next test"); + + getchar(); +} + +static int g2d_solid_fill_test(struct exynos_device *dev, struct exynos_bo *dst) +{ + struct g2d_context *ctx; + struct g2d_image img = {0}; + unsigned int count, img_w, img_h; + int ret = 0; + + ctx = g2d_init(dev->fd); + if (!ctx) + return -EFAULT; + + img.bo[0] = dst->handle; + + printf("solid fill test.\n"); + + srand(time(NULL)); + img_w = screen_width; + img_h = screen_height; + + for (count = 0; count < 2; count++) { + unsigned int x, y, w, h; + + x = rand() % (img_w / 2); + y = rand() % (img_h / 2); + w = rand() % (img_w - x); + h = rand() % (img_h - y); + + img.width = img_w; + img.height = img_h; + img.stride = img.width * 4; + img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + img.color = 0xff000000 + (random() & 0xffffff); + + ret = g2d_solid_fill(ctx, &img, x, y, w, h); + if (ret < 0) + goto err_fini; + + ret = g2d_exec(ctx); + if (ret < 0) + break; + } + +err_fini: + g2d_fini(ctx); + + return ret; +} + +static int g2d_copy_test(struct exynos_device *dev, struct exynos_bo *src, + struct exynos_bo *dst, + enum e_g2d_buf_type type) +{ + struct g2d_context *ctx; + struct g2d_image src_img = {0}, dst_img = {0}; + unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h; + unsigned long userptr, size; + int ret; + + ctx = g2d_init(dev->fd); + if (!ctx) + return -EFAULT; + + dst_img.bo[0] = dst->handle; + + src_x = 0; + src_y = 0; + dst_x = 0; + dst_y = 0; + img_w = screen_width; + img_h = screen_height; + + switch (type) { + case G2D_IMGBUF_GEM: + src_img.bo[0] = src->handle; + break; + case G2D_IMGBUF_USERPTR: + size = img_w * img_h * 4; + + userptr = (unsigned long)malloc(size); + if (!userptr) { + fprintf(stderr, "failed to allocate userptr.\n"); + ret = -EFAULT; + goto fail; + } + + src_img.user_ptr[0].userptr = userptr; + src_img.user_ptr[0].size = size; + break; + case G2D_IMGBUF_COLOR: + default: + ret = -EFAULT; + goto fail; + } + + printf("copy test with %s.\n", + type == G2D_IMGBUF_GEM ? "gem" : "userptr"); + + src_img.width = img_w; + src_img.height = img_h; + src_img.stride = src_img.width * 4; + src_img.buf_type = type; + src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + src_img.color = 0xffff0000; + ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w, img_h); + if (ret < 0) + goto err_free_userptr; + + dst_img.width = img_w; + dst_img.height = img_h; + dst_img.stride = dst_img.width * 4; + dst_img.buf_type = G2D_IMGBUF_GEM; + dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + + ret = g2d_copy(ctx, &src_img, &dst_img, src_x, src_y, dst_x, dst_y, + img_w - 4, img_h - 4); + if (ret < 0) + goto err_free_userptr; + + g2d_exec(ctx); + +err_free_userptr: + if (type == G2D_IMGBUF_USERPTR) + if (userptr) + free((void *)userptr); + +fail: + g2d_fini(ctx); + + return ret; +} + +static int g2d_move_test(struct exynos_device *dev, + struct exynos_bo *tmp, + struct exynos_bo *buf, + enum e_g2d_buf_type type) +{ + struct g2d_context *ctx; + struct g2d_image img = {0}, tmp_img = {0}; + unsigned int img_w, img_h, count; + int cur_x, cur_y; + void *checkerboard; + int ret; + + static const struct g2d_step { + int x, y; + } steps[] = { + { 1, 0}, { 0, 1}, + {-1, 0}, { 0, -1}, + { 1, 1}, {-1, -1}, + { 1, -1}, {-1, 1}, + { 2, 1}, { 1, 2}, + {-2, -1}, {-1, -2}, + { 2, -1}, { 1, -2}, + {-2, 1}, {-1, 2} + }; + static const unsigned int num_steps = + sizeof(steps) / sizeof(struct g2d_step); + + ctx = g2d_init(dev->fd); + if (!ctx) + return -EFAULT; + + img.bo[0] = buf->handle; + + /* create pattern of half the screen size */ + checkerboard = create_checkerboard_pattern(screen_width / 64, screen_height / 64, 32); + if (!checkerboard) { + ret = -EFAULT; + goto fail; + } + + img_w = (screen_width / 64) * 32; + img_h = (screen_height / 64) * 32; + + switch (type) { + case G2D_IMGBUF_GEM: + memcpy(tmp->vaddr, checkerboard, img_w * img_h * 4); + tmp_img.bo[0] = tmp->handle; + break; + case G2D_IMGBUF_USERPTR: + tmp_img.user_ptr[0].userptr = (unsigned long)checkerboard; + tmp_img.user_ptr[0].size = img_w * img_h * 4; + break; + case G2D_IMGBUF_COLOR: + default: + ret = -EFAULT; + goto fail; + } + + /* solid fill framebuffer with white color */ + img.width = screen_width; + img.height = screen_height; + img.stride = screen_width * 4; + img.buf_type = G2D_IMGBUF_GEM; + img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + img.color = 0xffffffff; + + /* put checkerboard pattern in the center of the framebuffer */ + cur_x = (screen_width - img_w) / 2; + cur_y = (screen_height - img_h) / 2; + tmp_img.width = img_w; + tmp_img.height = img_h; + tmp_img.stride = img_w * 4; + tmp_img.buf_type = type; + tmp_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + + ret = g2d_solid_fill(ctx, &img, 0, 0, screen_width, screen_height) || + g2d_copy(ctx, &tmp_img, &img, 0, 0, cur_x, cur_y, img_w, img_h); + + if (!ret) + ret = g2d_exec(ctx); + if (ret < 0) + goto fail; + + printf("move test with %s.\n", + type == G2D_IMGBUF_GEM ? "gem" : "userptr"); + + srand(time(NULL)); + for (count = 0; count < 256; ++count) { + const struct g2d_step *s; + + /* select step and validate it */ + while (1) { + s = &steps[random() % num_steps]; + + if (cur_x + s->x < 0 || cur_y + s->y < 0 || + cur_x + img_w + s->x >= screen_width || + cur_y + img_h + s->y >= screen_height) + continue; + else + break; + } + + ret = g2d_move(ctx, &img, cur_x, cur_y, cur_x + s->x, cur_y + s->y, + img_w, img_h); + if (!ret) + ret = g2d_exec(ctx); + + if (ret < 0) + goto fail; + + cur_x += s->x; + cur_y += s->y; + + usleep(100000); + } + +fail: + g2d_fini(ctx); + + free(checkerboard); + + return ret; +} + +static int g2d_copy_with_scale_test(struct exynos_device *dev, + struct exynos_bo *src, + struct exynos_bo *dst, + enum e_g2d_buf_type type) +{ + struct g2d_context *ctx; + struct g2d_image src_img = {0}, dst_img = {0}; + unsigned int src_x, src_y, img_w, img_h; + unsigned long userptr, size; + int ret; + + ctx = g2d_init(dev->fd); + if (!ctx) + return -EFAULT; + + dst_img.bo[0] = dst->handle; + + src_x = 0; + src_y = 0; + img_w = screen_width; + img_h = screen_height; + + switch (type) { + case G2D_IMGBUF_GEM: + src_img.bo[0] = src->handle; + break; + case G2D_IMGBUF_USERPTR: + size = img_w * img_h * 4; + + userptr = (unsigned long)malloc(size); + if (!userptr) { + fprintf(stderr, "failed to allocate userptr.\n"); + ret = -EFAULT; + goto fail; + } + + src_img.user_ptr[0].userptr = userptr; + src_img.user_ptr[0].size = size; + break; + case G2D_IMGBUF_COLOR: + default: + ret = -EFAULT; + goto fail; + } + + printf("copy and scale test with %s.\n", + type == G2D_IMGBUF_GEM ? "gem" : "userptr"); + + src_img.width = img_w; + src_img.height = img_h; + src_img.stride = src_img.width * 4; + src_img.buf_type = type; + src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + src_img.color = 0xffffffff; + ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w , img_h); + if (ret < 0) + goto err_free_userptr; + + src_img.color = 0xff00ff00; + ret = g2d_solid_fill(ctx, &src_img, 5, 5, 100, 100); + if (ret < 0) + goto err_free_userptr; + + dst_img.width = img_w; + dst_img.height = img_h; + dst_img.buf_type = G2D_IMGBUF_GEM; + dst_img.stride = dst_img.width * 4; + dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + + ret = g2d_copy_with_scale(ctx, &src_img, &dst_img, 5, 5, 100, 100, + 100, 100, 200, 200, 0); + if (ret < 0) + goto err_free_userptr; + + g2d_exec(ctx); + +err_free_userptr: + if (type == G2D_IMGBUF_USERPTR) + if (userptr) + free((void *)userptr); + +fail: + g2d_fini(ctx); + + return ret; +} + +#ifdef EXYNOS_G2D_USERPTR_TEST +static int g2d_blend_test(struct exynos_device *dev, + struct exynos_bo *src, + struct exynos_bo *dst, + enum e_g2d_buf_type type) +{ + struct g2d_context *ctx; + struct g2d_image src_img = {0}, dst_img = {0}; + unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h; + unsigned long userptr, size; + int ret; + + ctx = g2d_init(dev->fd); + if (!ctx) + return -EFAULT; + + dst_img.bo[0] = dst->handle; + + src_x = 0; + src_y = 0; + dst_x = 0; + dst_y = 0; + img_w = screen_width; + img_h = screen_height; + + switch (type) { + case G2D_IMGBUF_GEM: + src_img.bo[0] = src->handle; + break; + case G2D_IMGBUF_USERPTR: + size = img_w * img_h * 4; + + userptr = (unsigned long)malloc(size); + if (!userptr) { + fprintf(stderr, "failed to allocate userptr.\n"); + ret = -EFAULT; + goto fail; + } + + src_img.user_ptr[0].userptr = userptr; + src_img.user_ptr[0].size = size; + break; + case G2D_IMGBUF_COLOR: + default: + ret = -EFAULT; + goto fail; + } + + printf("blend test with %s.\n", + type == G2D_IMGBUF_GEM ? "gem" : "userptr"); + + src_img.width = img_w; + src_img.height = img_h; + src_img.stride = src_img.width * 4; + src_img.buf_type = type; + src_img.select_mode = G2D_SELECT_MODE_NORMAL; + src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + src_img.color = 0xffffffff; + ret = g2d_solid_fill(ctx, &src_img, src_x, src_y, img_w, img_h); + if (ret < 0) + goto err_free_userptr; + + src_img.color = 0x770000ff; + ret = g2d_solid_fill(ctx, &src_img, 5, 5, 200, 200); + if (ret < 0) + goto err_free_userptr; + + dst_img.width = img_w; + dst_img.height = img_h; + dst_img.stride = dst_img.width * 4; + dst_img.buf_type = G2D_IMGBUF_GEM; + dst_img.select_mode = G2D_SELECT_MODE_NORMAL; + dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + dst_img.color = 0xffffffff; + ret = g2d_solid_fill(ctx, &dst_img, dst_x, dst_y, img_w, img_h); + if (ret < 0) + goto err_free_userptr; + + dst_img.color = 0x77ff0000; + ret = g2d_solid_fill(ctx, &dst_img, 105, 105, 200, 200); + if (ret < 0) + goto err_free_userptr; + + ret = g2d_blend(ctx, &src_img, &dst_img, 5, 5, 105, 105, 200, 200, + G2D_OP_OVER); + if (ret < 0) + goto err_free_userptr; + + g2d_exec(ctx); + +err_free_userptr: + if (type == G2D_IMGBUF_USERPTR) + if (userptr) + free((void *)userptr); + +fail: + g2d_fini(ctx); + + return ret; +} +#endif + +static int g2d_checkerboard_test(struct exynos_device *dev, + struct exynos_bo *src, + struct exynos_bo *dst, + enum e_g2d_buf_type type) +{ + struct g2d_context *ctx; + struct g2d_image src_img = {0}, dst_img = {0}; + unsigned int src_x, src_y, dst_x, dst_y, img_w, img_h; + void *checkerboard = NULL; + int ret; + + ctx = g2d_init(dev->fd); + if (!ctx) + return -EFAULT; + + dst_img.bo[0] = dst->handle; + + src_x = 0; + src_y = 0; + dst_x = 0; + dst_y = 0; + + checkerboard = create_checkerboard_pattern(screen_width / 32, screen_height / 32, 32); + if (!checkerboard) { + ret = -EFAULT; + goto fail; + } + + img_w = screen_width - (screen_width % 32); + img_h = screen_height - (screen_height % 32); + + switch (type) { + case G2D_IMGBUF_GEM: + memcpy(src->vaddr, checkerboard, img_w * img_h * 4); + src_img.bo[0] = src->handle; + break; + case G2D_IMGBUF_USERPTR: + src_img.user_ptr[0].userptr = (unsigned long)checkerboard; + src_img.user_ptr[0].size = img_w * img_h * 4; + break; + case G2D_IMGBUF_COLOR: + default: + ret = -EFAULT; + goto fail; + } + + printf("checkerboard test with %s.\n", + type == G2D_IMGBUF_GEM ? "gem" : "userptr"); + + src_img.width = img_w; + src_img.height = img_h; + src_img.stride = src_img.width * 4; + src_img.buf_type = type; + src_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + + dst_img.width = screen_width; + dst_img.height = screen_height; + dst_img.stride = dst_img.width * 4; + dst_img.buf_type = G2D_IMGBUF_GEM; + dst_img.color_mode = G2D_COLOR_FMT_ARGB8888 | G2D_ORDER_AXRGB; + src_img.color = 0xff000000; + ret = g2d_solid_fill(ctx, &dst_img, src_x, src_y, screen_width, screen_height); + if (ret < 0) + goto fail; + + ret = g2d_copy(ctx, &src_img, &dst_img, src_x, src_y, dst_x, dst_y, + img_w, img_h); + if (ret < 0) + goto fail; + + g2d_exec(ctx); + +fail: + free(checkerboard); + g2d_fini(ctx); + + return ret; +} + +static void usage(char *name) +{ + fprintf(stderr, "usage: %s [-s]\n", name); + fprintf(stderr, "-s @:\n"); + exit(0); +} + +extern char *optarg; +static const char optstr[] = "s:"; + +int main(int argc, char **argv) +{ + struct exynos_device *dev; + struct exynos_bo *bo, *src; + struct connector con; + unsigned int fb_id; + uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; + drmModeRes *resources; + int ret, fd, c; + + memset(&con, 0, sizeof(struct connector)); + + if (argc != 3) { + usage(argv[0]); + return -EINVAL; + } + + while ((c = getopt(argc, argv, optstr)) != -1) { + switch (c) { + case 's': + con.crtc = -1; + if (sscanf(optarg, "%d:0x%64s", + &con.id, + con.mode_str) != 2 && + sscanf(optarg, "%d@%d:%64s", + &con.id, + &con.crtc, + con.mode_str) != 3) + usage(argv[0]); + break; + default: + usage(argv[0]); + break; + } + } + + fd = drmOpen(DRM_MODULE_NAME, NULL); + if (fd < 0) { + fprintf(stderr, "failed to open.\n"); + return fd; + } + + dev = exynos_device_create(fd); + if (!dev) { + ret = -EFAULT; + goto err_drm_close; + } + + resources = drmModeGetResources(dev->fd); + if (!resources) { + fprintf(stderr, "drmModeGetResources failed: %s\n", + strerror(errno)); + ret = -EFAULT; + goto err_dev_destory; + } + + connector_find_mode(dev->fd, &con, resources); + drmModeFreeResources(resources); + + if (!con.mode) { + fprintf(stderr, "failed to find usable connector\n"); + ret = -EFAULT; + goto err_dev_destory; + } + + screen_width = con.mode->hdisplay; + screen_height = con.mode->vdisplay; + + if (screen_width == 0 || screen_height == 0) { + fprintf(stderr, "failed to find sane resolution on connector\n"); + ret = -EFAULT; + goto err_dev_destory; + } + + printf("screen width = %d, screen height = %d\n", screen_width, + screen_height); + + bo = exynos_create_buffer(dev, screen_width * screen_height * 4, 0); + if (!bo) { + ret = -EFAULT; + goto err_dev_destory; + } + + handles[0] = bo->handle; + pitches[0] = screen_width * 4; + offsets[0] = 0; + + ret = drmModeAddFB2(dev->fd, screen_width, screen_height, + DRM_FORMAT_XRGB8888, handles, + pitches, offsets, &fb_id, 0); + if (ret < 0) + goto err_destroy_buffer; + + memset(bo->vaddr, 0xff, screen_width * screen_height * 4); + + ret = drm_set_crtc(dev, &con, fb_id); + if (ret < 0) + goto err_rm_fb; + + ret = g2d_solid_fill_test(dev, bo); + if (ret < 0) { + fprintf(stderr, "failed to solid fill operation.\n"); + goto err_rm_fb; + } + + wait_for_user_input(0); + + src = exynos_create_buffer(dev, screen_width * screen_height * 4, 0); + if (!src) { + ret = -EFAULT; + goto err_rm_fb; + } + + ret = g2d_copy_test(dev, src, bo, G2D_IMGBUF_GEM); + if (ret < 0) { + fprintf(stderr, "failed to test copy operation.\n"); + goto err_free_src; + } + + wait_for_user_input(0); + + ret = g2d_move_test(dev, src, bo, G2D_IMGBUF_GEM); + if (ret < 0) { + fprintf(stderr, "failed to test move operation.\n"); + goto err_free_src; + } + + wait_for_user_input(0); + + ret = g2d_copy_with_scale_test(dev, src, bo, G2D_IMGBUF_GEM); + if (ret < 0) { + fprintf(stderr, "failed to test copy and scale operation.\n"); + goto err_free_src; + } + + wait_for_user_input(0); + + ret = g2d_checkerboard_test(dev, src, bo, G2D_IMGBUF_GEM); + if (ret < 0) { + fprintf(stderr, "failed to issue checkerboard test.\n"); + goto err_free_src; + } + + wait_for_user_input(1); + + /* + * The blend test uses the userptr functionality of exynos-drm, which + * is currently not safe to use. If the kernel hasn't been build with + * exynos-iommu support, then the blend test is going to produce (kernel) + * memory corruption, eventually leading to a system crash. + * + * Disable the test for now, until the kernel code has been sanitized. + */ +#ifdef EXYNOS_G2D_USERPTR_TEST + ret = g2d_blend_test(dev, src, bo, G2D_IMGBUF_USERPTR); + if (ret < 0) + fprintf(stderr, "failed to test blend operation.\n"); + + getchar(); +#endif + +err_free_src: + if (src) + exynos_destroy_buffer(src); + +err_rm_fb: + drmModeRmFB(dev->fd, fb_id); + +err_destroy_buffer: + exynos_destroy_buffer(bo); + +err_dev_destory: + exynos_device_destroy(dev); + +err_drm_close: + drmClose(fd); + + return ret; +} diff --git a/tests/exynos/meson.build b/tests/exynos/meson.build new file mode 100644 index 0000000..12259c3 --- /dev/null +++ b/tests/exynos/meson.build @@ -0,0 +1,51 @@ +# Copyright © 2017 Intel Corporation + +# 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. + +inc_exynos = include_directories('../../exynos') + +exynos_fimg2d_test = executable( + 'exynos_fimg2d_test', + files('exynos_fimg2d_test.c'), + c_args : libdrm_c_args, + include_directories : [inc_root, inc_drm, inc_exynos], + link_with : [libdrm, libdrm_exynos], + dependencies : dep_threads, + install : with_install_tests, +) + +exynos_fimg2d_perf = executable( + 'exynos_fimg2d_perf', + files('exynos_fimg2d_perf.c'), + c_args : libdrm_c_args, + include_directories : [inc_root, inc_drm, inc_exynos], + link_with : [libdrm, libdrm_exynos], + dependencies : dep_threads, + install : with_install_tests, +) + +exynos_fimg2d_event = executable( + 'exynos_fimg2d_event', + files('exynos_fimg2d_event.c'), + c_args : libdrm_c_args, + include_directories : [inc_root, inc_drm, inc_exynos], + link_with : [libdrm, libdrm_exynos], + dependencies : dep_threads, + install : with_install_tests, +) diff --git a/tests/hash.c b/tests/hash.c new file mode 100644 index 0000000..4475fba --- /dev/null +++ b/tests/hash.c @@ -0,0 +1,217 @@ +/* xf86drmHash.c -- Small hash table support for integer -> integer mapping + * Created: Sun Apr 18 09:35:45 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * 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, 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT 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. + * + * Authors: Rickard E. (Rik) Faith + * + * DESCRIPTION + * + * This file contains a straightforward implementation of a fixed-sized + * hash table using self-organizing linked lists [Knuth73, pp. 398-399] for + * collision resolution. There are two potentially interesting things + * about this implementation: + * + * 1) The table is power-of-two sized. Prime sized tables are more + * traditional, but do not have a significant advantage over power-of-two + * sized table, especially when double hashing is not used for collision + * resolution. + * + * 2) The hash computation uses a table of random integers [Hanson97, + * pp. 39-41]. + * + * FUTURE ENHANCEMENTS + * + * With a table size of 512, the current implementation is sufficient for a + * few hundred keys. Since this is well above the expected size of the + * tables for which this implementation was designed, the implementation of + * dynamic hash tables was postponed until the need arises. A common (and + * naive) approach to dynamic hash table implementation simply creates a + * new hash table when necessary, rehashes all the data into the new table, + * and destroys the old table. The approach in [Larson88] is superior in + * two ways: 1) only a portion of the table is expanded when needed, + * distributing the expansion cost over several insertions, and 2) portions + * of the table can be locked, enabling a scalable thread-safe + * implementation. + * + * REFERENCES + * + * [Hanson97] David R. Hanson. C Interfaces and Implementations: + * Techniques for Creating Reusable Software. Reading, Massachusetts: + * Addison-Wesley, 1997. + * + * [Knuth73] Donald E. Knuth. The Art of Computer Programming. Volume 3: + * Sorting and Searching. Reading, Massachusetts: Addison-Wesley, 1973. + * + * [Larson88] Per-Ake Larson. "Dynamic Hash Tables". CACM 31(4), April + * 1988, pp. 446-457. + * + */ + +#include +#include + +#include "xf86drm.h" +#include "xf86drmHash.h" + +#define DIST_LIMIT 10 +static int dist[DIST_LIMIT]; + +static void clear_dist(void) { + int i; + + for (i = 0; i < DIST_LIMIT; i++) + dist[i] = 0; +} + +static int count_entries(HashBucketPtr bucket) +{ + int count = 0; + + for (; bucket; bucket = bucket->next) + ++count; + return count; +} + +static void update_dist(int count) +{ + if (count >= DIST_LIMIT) + ++dist[DIST_LIMIT-1]; + else + ++dist[count]; +} + +static void compute_dist(HashTablePtr table) +{ + int i; + HashBucketPtr bucket; + + printf("Entries = %ld, hits = %ld, partials = %ld, misses = %ld\n", + table->entries, table->hits, table->partials, table->misses); + clear_dist(); + for (i = 0; i < HASH_SIZE; i++) { + bucket = table->buckets[i]; + update_dist(count_entries(bucket)); + } + for (i = 0; i < DIST_LIMIT; i++) { + if (i != DIST_LIMIT-1) + printf("%5d %10d\n", i, dist[i]); + else + printf("other %10d\n", dist[i]); + } +} + +static int check_table(HashTablePtr table, + unsigned long key, void * value) +{ + void *retval; + int retcode = drmHashLookup(table, key, &retval); + + switch (retcode) { + case -1: + printf("Bad magic = 0x%08lx:" + " key = %lu, expected = %p, returned = %p\n", + table->magic, key, value, retval); + break; + case 1: + printf("Not found: key = %lu, expected = %p, returned = %p\n", + key, value, retval); + break; + case 0: + if (value != retval) { + printf("Bad value: key = %lu, expected = %p, returned = %p\n", + key, value, retval); + retcode = -1; + } + break; + default: + printf("Bad retcode = %d: key = %lu, expected = %p, returned = %p\n", + retcode, key, value, retval); + break; + } + return retcode; +} + +int main(void) +{ + HashTablePtr table; + unsigned long i; + int ret = 0; + + printf("\n***** 256 consecutive integers ****\n"); + table = drmHashCreate(); + for (i = 0; i < 256; i++) + drmHashInsert(table, i, (void *)(i << 16 | i)); + for (i = 0; i < 256; i++) + ret |= check_table(table, i, (void *)(i << 16 | i)); + compute_dist(table); + drmHashDestroy(table); + + printf("\n***** 1024 consecutive integers ****\n"); + table = drmHashCreate(); + for (i = 0; i < 1024; i++) + drmHashInsert(table, i, (void *)(i << 16 | i)); + for (i = 0; i < 1024; i++) + ret |= check_table(table, i, (void *)(i << 16 | i)); + compute_dist(table); + drmHashDestroy(table); + + printf("\n***** 1024 consecutive page addresses (4k pages) ****\n"); + table = drmHashCreate(); + for (i = 0; i < 1024; i++) + drmHashInsert(table, i*4096, (void *)(i << 16 | i)); + for (i = 0; i < 1024; i++) + ret |= check_table(table, i*4096, (void *)(i << 16 | i)); + compute_dist(table); + drmHashDestroy(table); + + printf("\n***** 1024 random integers ****\n"); + table = drmHashCreate(); + srandom(0xbeefbeef); + for (i = 0; i < 1024; i++) + drmHashInsert(table, random(), (void *)(i << 16 | i)); + srandom(0xbeefbeef); + for (i = 0; i < 1024; i++) + ret |= check_table(table, random(), (void *)(i << 16 | i)); + srandom(0xbeefbeef); + for (i = 0; i < 1024; i++) + ret |= check_table(table, random(), (void *)(i << 16 | i)); + compute_dist(table); + drmHashDestroy(table); + + printf("\n***** 5000 random integers ****\n"); + table = drmHashCreate(); + srandom(0xbeefbeef); + for (i = 0; i < 5000; i++) + drmHashInsert(table, random(), (void *)(i << 16 | i)); + srandom(0xbeefbeef); + for (i = 0; i < 5000; i++) + ret |= check_table(table, random(), (void *)(i << 16 | i)); + srandom(0xbeefbeef); + for (i = 0; i < 5000; i++) + ret |= check_table(table, random(), (void *)(i << 16 | i)); + compute_dist(table); + drmHashDestroy(table); + + return ret; +} diff --git a/tests/meson.build b/tests/meson.build new file mode 100644 index 0000000..ac9e66b --- /dev/null +++ b/tests/meson.build @@ -0,0 +1,74 @@ +# Copyright © 2017-2018 Intel Corporation + +# 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. + +inc_tests = include_directories('.') + +subdir('util') +subdir('modeprint') +subdir('proptest') +subdir('modetest') +subdir('vbltest') +if with_radeon + subdir('radeon') +endif +if with_amdgpu + subdir('amdgpu') +endif +if with_exynos + subdir('exynos') +endif +if with_tegra + subdir('tegra') +endif +if with_etnaviv + subdir('etnaviv') +endif +if with_nouveau + subdir('nouveau') +endif + +drmsl = executable( + 'drmsl', + files('drmsl.c'), + include_directories : [inc_root, inc_drm], + link_with : libdrm, + c_args : libdrm_c_args, +) + +hash = executable( + 'hash', + files('hash.c'), + include_directories : [inc_root, inc_drm], + link_with : libdrm, + c_args : libdrm_c_args, +) + +drmdevice = executable( + 'drmdevice', + files('drmdevice.c'), + include_directories : [inc_root, inc_drm], + link_with : libdrm, + c_args : libdrm_c_args, + install : with_install_tests, +) + +test('hash', hash) +test('drmsl', drmsl) +test('drmdevice', drmdevice) diff --git a/tests/modeprint/meson.build b/tests/modeprint/meson.build new file mode 100644 index 0000000..0801808 --- /dev/null +++ b/tests/modeprint/meson.build @@ -0,0 +1,29 @@ +# Copyright © 2017 Intel Corporation + +# 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. + +modeprint = executable( + 'modeprint', + files('modeprint.c'), + c_args : libdrm_c_args, + include_directories : [inc_root, inc_tests, inc_drm], + link_with : [libdrm, libutil], + dependencies : dep_threads, + install : with_install_tests, +) diff --git a/tests/modeprint/modeprint.c b/tests/modeprint/modeprint.c new file mode 100644 index 0000000..0f644c7 --- /dev/null +++ b/tests/modeprint/modeprint.c @@ -0,0 +1,418 @@ +/* + * \file modedemo.c + * Test program to dump DRM kernel mode setting related information. + * Queries the kernel for all available information and dumps it to stdout. + * + * \author Jakob Bornecrantz + */ + +/* + * Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright (c) 2007-2008 Jakob Bornecrantz + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "xf86drm.h" +#include "xf86drmMode.h" + +#include "util/common.h" +#include "util/kms.h" + +int current; +int connectors; +int full_props; +int edid; +int modes; +int full_modes; +int encoders; +int crtcs; +int fbs; +char *module_name; + +static int printMode(struct drm_mode_modeinfo *mode) +{ + if (full_modes) { + printf("Mode: %s\n", mode->name); + printf("\tclock : %i\n", mode->clock); + printf("\thdisplay : %i\n", mode->hdisplay); + printf("\thsync_start : %i\n", mode->hsync_start); + printf("\thsync_end : %i\n", mode->hsync_end); + printf("\thtotal : %i\n", mode->htotal); + printf("\thskew : %i\n", mode->hskew); + printf("\tvdisplay : %i\n", mode->vdisplay); + printf("\tvsync_start : %i\n", mode->vsync_start); + printf("\tvsync_end : %i\n", mode->vsync_end); + printf("\tvtotal : %i\n", mode->vtotal); + printf("\tvscan : %i\n", mode->vscan); + printf("\tvrefresh : %i\n", mode->vrefresh); + printf("\tflags : %i\n", mode->flags); + } else { + printf("Mode: \"%s\" %ix%i %i\n", mode->name, + mode->hdisplay, mode->vdisplay, mode->vrefresh); + } + return 0; +} + +static int printProperty(int fd, drmModeResPtr res, drmModePropertyPtr props, uint64_t value) +{ + const char *name = NULL; + int j; + + printf("Property: %s\n", props->name); + printf("\tid : %i\n", props->prop_id); + printf("\tflags : %i\n", props->flags); + printf("\tcount_values : %d\n", props->count_values); + + + if (props->count_values) { + printf("\tvalues :"); + for (j = 0; j < props->count_values; j++) + printf(" %" PRIu64, props->values[j]); + printf("\n"); + } + + + printf("\tcount_enums : %d\n", props->count_enums); + + if (props->flags & DRM_MODE_PROP_BLOB) { + drmModePropertyBlobPtr blob; + + blob = drmModeGetPropertyBlob(fd, value); + if (blob) { + printf("blob is %d length, %08X\n", blob->length, *(uint32_t *)blob->data); + drmModeFreePropertyBlob(blob); + } else { + printf("error getting blob %" PRIu64 "\n", value); + } + + } else { + for (j = 0; j < props->count_enums; j++) { + printf("\t\t%" PRIu64" = %s\n", (uint64_t)props->enums[j].value, props->enums[j].name); + if (props->enums[j].value == value) + name = props->enums[j].name; + } + + if (props->count_enums && name) { + printf("\tcon_value : %s\n", name); + } else { + printf("\tcon_value : %" PRIu64 "\n", value); + } + } + + return 0; +} + +static int printConnector(int fd, drmModeResPtr res, drmModeConnectorPtr connector, uint32_t id) +{ + int i = 0; + struct drm_mode_modeinfo *mode = NULL; + drmModePropertyPtr props; + const char *connector_type_name = NULL; + + connector_type_name = drmModeGetConnectorTypeName(connector->connector_type); + + if (connector_type_name) + printf("Connector: %s-%d\n", connector_type_name, + connector->connector_type_id); + else + printf("Connector: %d-%d\n", connector->connector_type, + connector->connector_type_id); + printf("\tid : %i\n", id); + printf("\tencoder id : %i\n", connector->encoder_id); + printf("\tconn : %s\n", util_lookup_connector_status_name(connector->connection)); + printf("\tsize : %ix%i (mm)\n", connector->mmWidth, connector->mmHeight); + printf("\tcount_modes : %i\n", connector->count_modes); + printf("\tcount_props : %i\n", connector->count_props); + if (connector->count_props) { + printf("\tprops :"); + for (i = 0; i < connector->count_props; i++) + printf(" %i", connector->props[i]); + printf("\n"); + } + + printf("\tcount_encoders : %i\n", connector->count_encoders); + if (connector->count_encoders) { + printf("\tencoders :"); + for (i = 0; i < connector->count_encoders; i++) + printf(" %i", connector->encoders[i]); + printf("\n"); + } + + if (modes) { + for (i = 0; i < connector->count_modes; i++) { + mode = (struct drm_mode_modeinfo *)&connector->modes[i]; + printMode(mode); + } + } + + if (full_props) { + for (i = 0; i < connector->count_props; i++) { + props = drmModeGetProperty(fd, connector->props[i]); + if (props) { + printProperty(fd, res, props, connector->prop_values[i]); + drmModeFreeProperty(props); + } + } + } + + return 0; +} + +static int printEncoder(int fd, drmModeResPtr res, drmModeEncoderPtr encoder, uint32_t id) +{ + const char *encoder_name; + + encoder_name = util_lookup_encoder_type_name(encoder->encoder_type); + if (encoder_name) + printf("Encoder: %s\n", encoder_name); + else + printf("Encoder\n"); + printf("\tid :%i\n", id); + printf("\tcrtc_id :%d\n", encoder->crtc_id); + printf("\ttype :%d\n", encoder->encoder_type); + printf("\tpossible_crtcs :0x%x\n", encoder->possible_crtcs); + printf("\tpossible_clones :0x%x\n", encoder->possible_clones); + return 0; +} + +static int printCrtc(int fd, drmModeResPtr res, drmModeCrtcPtr crtc, uint32_t id) +{ + printf("Crtc\n"); + printf("\tid : %i\n", id); + printf("\tx : %i\n", crtc->x); + printf("\ty : %i\n", crtc->y); + printf("\twidth : %i\n", crtc->width); + printf("\theight : %i\n", crtc->height); + printf("\tmode : %p\n", &crtc->mode); + printf("\tgamma size : %d\n", crtc->gamma_size); + + return 0; +} + +static int printFrameBuffer(int fd, drmModeResPtr res, drmModeFBPtr fb) +{ + printf("Framebuffer\n"); + printf("\thandle : %i\n", fb->handle); + printf("\twidth : %i\n", fb->width); + printf("\theight : %i\n", fb->height); + printf("\tpitch : %i\n", fb->pitch); + printf("\tbpp : %i\n", fb->bpp); + printf("\tdepth : %i\n", fb->depth); + printf("\tbuffer_id : %i\n", fb->handle); + + return 0; +} + +static int printRes(int fd, drmModeResPtr res) +{ + int i; + drmModeFBPtr fb; + drmModeCrtcPtr crtc; + drmModeEncoderPtr encoder; + drmModeConnectorPtr connector; + + printf("Resources\n\n"); + + printf("count_connectors : %i\n", res->count_connectors); + printf("count_encoders : %i\n", res->count_encoders); + printf("count_crtcs : %i\n", res->count_crtcs); + printf("count_fbs : %i\n", res->count_fbs); + + printf("\n"); + + if (connectors) { + for (i = 0; i < res->count_connectors; i++) { + connector = (current ? drmModeGetConnectorCurrent : drmModeGetConnector) (fd, res->connectors[i]); + + if (!connector) + printf("Could not get connector %i\n", res->connectors[i]); + else { + printConnector(fd, res, connector, res->connectors[i]); + drmModeFreeConnector(connector); + } + } + printf("\n"); + } + + + if (encoders) { + for (i = 0; i < res->count_encoders; i++) { + encoder = drmModeGetEncoder(fd, res->encoders[i]); + + if (!encoder) + printf("Could not get encoder %i\n", res->encoders[i]); + else { + printEncoder(fd, res, encoder, res->encoders[i]); + drmModeFreeEncoder(encoder); + } + } + printf("\n"); + } + + if (crtcs) { + for (i = 0; i < res->count_crtcs; i++) { + crtc = drmModeGetCrtc(fd, res->crtcs[i]); + + if (!crtc) + printf("Could not get crtc %i\n", res->crtcs[i]); + else { + printCrtc(fd, res, crtc, res->crtcs[i]); + drmModeFreeCrtc(crtc); + } + } + printf("\n"); + } + + if (fbs) { + for (i = 0; i < res->count_fbs; i++) { + fb = drmModeGetFB(fd, res->fbs[i]); + + if (!fb) + printf("Could not get fb %i\n", res->fbs[i]); + else { + printFrameBuffer(fd, res, fb); + drmModeFreeFB(fb); + } + } + } + + return 0; +} + +static void args(int argc, char **argv) +{ + int defaults = 1; + int i; + + fbs = 0; + edid = 0; + crtcs = 0; + modes = 0; + encoders = 0; + full_modes = 0; + full_props = 0; + connectors = 0; + current = 0; + + module_name = argv[1]; + + for (i = 2; i < argc; i++) { + if (strcmp(argv[i], "-fb") == 0) { + fbs = 1; + defaults = 0; + } else if (strcmp(argv[i], "-crtcs") == 0) { + crtcs = 1; + defaults = 0; + } else if (strcmp(argv[i], "-cons") == 0) { + connectors = 1; + modes = 1; + defaults = 0; + } else if (strcmp(argv[i], "-modes") == 0) { + connectors = 1; + modes = 1; + defaults = 0; + } else if (strcmp(argv[i], "-full") == 0) { + connectors = 1; + modes = 1; + full_modes = 1; + defaults = 0; + } else if (strcmp(argv[i], "-props") == 0) { + connectors = 1; + full_props = 1; + defaults = 0; + } else if (strcmp(argv[i], "-edids") == 0) { + connectors = 1; + edid = 1; + defaults = 0; + } else if (strcmp(argv[i], "-encoders") == 0) { + encoders = 1; + defaults = 0; + } else if (strcmp(argv[i], "-v") == 0) { + fbs = 1; + edid = 1; + crtcs = 1; + modes = 1; + encoders = 1; + full_modes = 1; + full_props = 1; + connectors = 1; + defaults = 0; + } else if (strcmp(argv[i], "-current") == 0) { + current = 1; + } + } + + if (defaults) { + fbs = 1; + edid = 1; + crtcs = 1; + modes = 1; + encoders = 1; + full_modes = 0; + full_props = 0; + connectors = 1; + } +} + +int main(int argc, char **argv) +{ + int fd; + drmModeResPtr res; + + if (argc == 1) { + printf("Please add modulename as first argument\n"); + return 1; + } + + args(argc, argv); + + printf("Starting test\n"); + + fd = drmOpen(module_name, NULL); + + if (fd < 0) { + printf("Failed to open the card fd (%d)\n",fd); + return 1; + } + + res = drmModeGetResources(fd); + if (res == 0) { + printf("Failed to get resources from card\n"); + drmClose(fd); + return 1; + } + + printRes(fd, res); + + drmModeFreeResources(res); + + printf("Ok\n"); + + return 0; +} diff --git a/tests/modetest/Android.mk b/tests/modetest/Android.mk new file mode 100644 index 0000000..c1a71fd --- /dev/null +++ b/tests/modetest/Android.mk @@ -0,0 +1,14 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +include $(LOCAL_PATH)/Makefile.sources + +LOCAL_SRC_FILES := $(MODETEST_FILES) + +LOCAL_MODULE := modetest + +LOCAL_SHARED_LIBRARIES := libdrm +LOCAL_STATIC_LIBRARIES := libdrm_util + +include $(LIBDRM_COMMON_MK) +include $(BUILD_EXECUTABLE) diff --git a/tests/modetest/Makefile.sources b/tests/modetest/Makefile.sources new file mode 100644 index 0000000..399af0d --- /dev/null +++ b/tests/modetest/Makefile.sources @@ -0,0 +1,6 @@ +MODETEST_FILES := \ + buffers.c \ + buffers.h \ + cursor.c \ + cursor.h \ + modetest.c diff --git a/tests/modetest/buffers.c b/tests/modetest/buffers.c new file mode 100644 index 0000000..0b55aed --- /dev/null +++ b/tests/modetest/buffers.c @@ -0,0 +1,340 @@ +/* + * DRM based mode setting test program + * Copyright 2008 Tungsten Graphics + * Jakob Bornecrantz + * Copyright 2008 Intel Corporation + * Jesse Barnes + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "drm.h" +#include "drm_fourcc.h" + +#include "libdrm_macros.h" +#include "xf86drm.h" +#include "xf86drmMode.h" + +#include "buffers.h" + +struct bo +{ + int fd; + void *ptr; + uint64_t size; + uint32_t pitch; + uint32_t handle; +}; + +/* ----------------------------------------------------------------------------- + * Buffers management + */ + +static struct bo * +bo_create_dumb(int fd, unsigned int width, unsigned int height, unsigned int bpp) +{ + struct bo *bo; + int ret; + + bo = calloc(1, sizeof(*bo)); + if (bo == NULL) { + fprintf(stderr, "failed to allocate buffer object\n"); + return NULL; + } + + ret = drmModeCreateDumbBuffer(fd, width, height, bpp, 0, &bo->handle, + &bo->pitch, &bo->size); + if (ret) { + fprintf(stderr, "failed to create dumb buffer: %s\n", + strerror(errno)); + free(bo); + return NULL; + } + + bo->fd = fd; + + return bo; +} + +static int bo_map(struct bo *bo, void **out) +{ + void *map; + int ret; + uint64_t offset; + + ret = drmModeMapDumbBuffer(bo->fd, bo->handle, &offset); + if (ret) + return ret; + + map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, + bo->fd, offset); + if (map == MAP_FAILED) + return -EINVAL; + + bo->ptr = map; + *out = map; + + return 0; +} + +static void bo_unmap(struct bo *bo) +{ + if (!bo->ptr) + return; + + drm_munmap(bo->ptr, bo->size); + bo->ptr = NULL; +} + +struct bo * +bo_create(int fd, unsigned int format, + unsigned int width, unsigned int height, + unsigned int handles[4], unsigned int pitches[4], + unsigned int offsets[4], enum util_fill_pattern pattern) +{ + unsigned int virtual_height; + struct bo *bo; + unsigned int bpp; + void *planes[3] = { 0, }; + void *virtual; + int ret; + + switch (format) { + case DRM_FORMAT_C8: + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + bpp = 8; + break; + + case DRM_FORMAT_ARGB4444: + case DRM_FORMAT_XRGB4444: + case DRM_FORMAT_ABGR4444: + case DRM_FORMAT_XBGR4444: + case DRM_FORMAT_RGBA4444: + case DRM_FORMAT_RGBX4444: + case DRM_FORMAT_BGRA4444: + case DRM_FORMAT_BGRX4444: + case DRM_FORMAT_ARGB1555: + case DRM_FORMAT_XRGB1555: + case DRM_FORMAT_ABGR1555: + case DRM_FORMAT_XBGR1555: + case DRM_FORMAT_RGBA5551: + case DRM_FORMAT_RGBX5551: + case DRM_FORMAT_BGRA5551: + case DRM_FORMAT_BGRX5551: + case DRM_FORMAT_RGB565: + case DRM_FORMAT_BGR565: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + bpp = 16; + break; + + case DRM_FORMAT_BGR888: + case DRM_FORMAT_RGB888: + bpp = 24; + break; + + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_RGBA8888: + case DRM_FORMAT_RGBX8888: + case DRM_FORMAT_BGRA8888: + case DRM_FORMAT_BGRX8888: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_RGBA1010102: + case DRM_FORMAT_RGBX1010102: + case DRM_FORMAT_BGRA1010102: + case DRM_FORMAT_BGRX1010102: + bpp = 32; + break; + + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ARGB16161616F: + case DRM_FORMAT_ABGR16161616F: + bpp = 64; + break; + + default: + fprintf(stderr, "unsupported format 0x%08x\n", format); + return NULL; + } + + switch (format) { + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + virtual_height = height * 3 / 2; + break; + + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + virtual_height = height * 2; + break; + + default: + virtual_height = height; + break; + } + + bo = bo_create_dumb(fd, width, virtual_height, bpp); + if (!bo) + return NULL; + + ret = bo_map(bo, &virtual); + if (ret) { + fprintf(stderr, "failed to map buffer: %s\n", + strerror(-errno)); + bo_destroy(bo); + return NULL; + } + + /* just testing a limited # of formats to test single + * and multi-planar path.. would be nice to add more.. + */ + switch (format) { + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + offsets[0] = 0; + handles[0] = bo->handle; + pitches[0] = bo->pitch; + + planes[0] = virtual; + break; + + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + offsets[0] = 0; + handles[0] = bo->handle; + pitches[0] = bo->pitch; + pitches[1] = pitches[0]; + offsets[1] = pitches[0] * height; + handles[1] = bo->handle; + + planes[0] = virtual; + planes[1] = virtual + offsets[1]; + break; + + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + offsets[0] = 0; + handles[0] = bo->handle; + pitches[0] = bo->pitch; + pitches[1] = pitches[0] / 2; + offsets[1] = pitches[0] * height; + handles[1] = bo->handle; + pitches[2] = pitches[1]; + offsets[2] = offsets[1] + pitches[1] * height / 2; + handles[2] = bo->handle; + + planes[0] = virtual; + planes[1] = virtual + offsets[1]; + planes[2] = virtual + offsets[2]; + break; + + case DRM_FORMAT_C8: + case DRM_FORMAT_ARGB4444: + case DRM_FORMAT_XRGB4444: + case DRM_FORMAT_ABGR4444: + case DRM_FORMAT_XBGR4444: + case DRM_FORMAT_RGBA4444: + case DRM_FORMAT_RGBX4444: + case DRM_FORMAT_BGRA4444: + case DRM_FORMAT_BGRX4444: + case DRM_FORMAT_ARGB1555: + case DRM_FORMAT_XRGB1555: + case DRM_FORMAT_ABGR1555: + case DRM_FORMAT_XBGR1555: + case DRM_FORMAT_RGBA5551: + case DRM_FORMAT_RGBX5551: + case DRM_FORMAT_BGRA5551: + case DRM_FORMAT_BGRX5551: + case DRM_FORMAT_RGB565: + case DRM_FORMAT_BGR565: + case DRM_FORMAT_BGR888: + case DRM_FORMAT_RGB888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_RGBA8888: + case DRM_FORMAT_RGBX8888: + case DRM_FORMAT_BGRA8888: + case DRM_FORMAT_BGRX8888: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_RGBA1010102: + case DRM_FORMAT_RGBX1010102: + case DRM_FORMAT_BGRA1010102: + case DRM_FORMAT_BGRX1010102: + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ARGB16161616F: + case DRM_FORMAT_ABGR16161616F: + offsets[0] = 0; + handles[0] = bo->handle; + pitches[0] = bo->pitch; + + planes[0] = virtual; + break; + } + + util_fill_pattern(format, pattern, planes, width, height, pitches[0]); + bo_unmap(bo); + + return bo; +} + +void bo_destroy(struct bo *bo) +{ + int ret; + + ret = drmModeDestroyDumbBuffer(bo->fd, bo->handle); + if (ret) + fprintf(stderr, "failed to destroy dumb buffer: %s\n", + strerror(errno)); + + free(bo); +} diff --git a/tests/modetest/buffers.h b/tests/modetest/buffers.h new file mode 100644 index 0000000..7f95396 --- /dev/null +++ b/tests/modetest/buffers.h @@ -0,0 +1,40 @@ +/* + * DRM based mode setting test program + * Copyright 2008 Tungsten Graphics + * Jakob Bornecrantz + * Copyright 2008 Intel Corporation + * Jesse Barnes + * + * 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. + */ + +#ifndef __BUFFERS_H__ +#define __BUFFERS_H__ + +#include "util/pattern.h" + +struct bo; + +struct bo *bo_create(int fd, unsigned int format, + unsigned int width, unsigned int height, + unsigned int handles[4], unsigned int pitches[4], + unsigned int offsets[4], enum util_fill_pattern pattern); +void bo_destroy(struct bo *bo); + +#endif diff --git a/tests/modetest/cursor.c b/tests/modetest/cursor.c new file mode 100644 index 0000000..829bced --- /dev/null +++ b/tests/modetest/cursor.c @@ -0,0 +1,206 @@ +/* + * DRM based mode setting test program + * Copyright (C) 2013 Red Hat + * Author: Rob Clark + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xf86drm.h" +#include "xf86drmMode.h" + +#include "util/common.h" + +#include "buffers.h" +#include "cursor.h" + +struct cursor { + int fd; + uint32_t bo_handle; + uint32_t crtc_id; + uint32_t crtc_w, crtc_h; + uint32_t w, h; + + /* current state */ + uint32_t enabled, x, y; + int32_t dx, dy; +}; + +#define MAX_CURSORS 8 +static struct cursor cursors[MAX_CURSORS]; +static int ncursors; + +static pthread_t cursor_thread; +static int cursor_running; + +/* + * Timer driven program loops through these steps to move/enable/disable + * the cursor + */ + +struct cursor_step { + void (*run)(struct cursor *cursor, const struct cursor_step *step); + uint32_t msec; + uint32_t repeat; + int arg; +}; + +static uint32_t indx, count; + +static void set_cursor(struct cursor *cursor, const struct cursor_step *step) +{ + int enabled = (step->arg ^ count) & 0x1; + uint32_t handle = 0; + + if (enabled) + handle = cursor->bo_handle; + + cursor->enabled = enabled; + + drmModeSetCursor(cursor->fd, cursor->crtc_id, handle, cursor->w, cursor->h); +} + +static void move_cursor(struct cursor *cursor, const struct cursor_step *step) +{ + int x = cursor->x; + int y = cursor->y; + + if (!cursor->enabled) + drmModeSetCursor(cursor->fd, cursor->crtc_id, + cursor->bo_handle, cursor->w, cursor->h); + + /* calculate new cursor position: */ + x += cursor->dx * step->arg; + y += cursor->dy * step->arg; + + if (x < 0) { + x = 0; + cursor->dx = 1; + } else if (x > (int)cursor->crtc_w) { + x = cursor->crtc_w - 1; + cursor->dx = -1; + } + + if (y < 0) { + y = 0; + cursor->dy = 1; + } else if (y > (int)cursor->crtc_h) { + y = cursor->crtc_h - 1; + cursor->dy = -1; + } + + cursor->x = x; + cursor->y = y; + + drmModeMoveCursor(cursor->fd, cursor->crtc_id, x, y); +} + +static const struct cursor_step steps[] = { + { set_cursor, 10, 0, 1 }, /* enable */ + { move_cursor, 1, 100, 1 }, + { move_cursor, 1, 10, 10 }, + { set_cursor, 1, 100, 0 }, /* disable/enable loop */ + { move_cursor, 1, 10, 10 }, + { move_cursor, 9, 100, 1 }, + { move_cursor, 11, 100, 5 }, + { set_cursor, 17, 10, 0 }, /* disable/enable loop */ + { move_cursor, 9, 100, 1 }, + { set_cursor, 13, 10, 0 }, /* disable/enable loop */ + { move_cursor, 9, 100, 1 }, + { set_cursor, 13, 10, 0 }, /* disable/enable loop */ + { set_cursor, 10, 0, 0 }, /* disable */ +}; + +static void *cursor_thread_func(void *data) +{ + while (cursor_running) { + const struct cursor_step *step = &steps[indx % ARRAY_SIZE(steps)]; + int i; + + for (i = 0; i < ncursors; i++) { + struct cursor *cursor = &cursors[i]; + step->run(cursor, step); + } + + /* iterate to next count/step: */ + if (count < step->repeat) { + count++; + } else { + count = 0; + indx++; + } + + usleep(1000 * step->msec); + } + + return NULL; +} + +int cursor_init(int fd, uint32_t bo_handle, uint32_t crtc_id, + uint32_t crtc_w, uint32_t crtc_h, uint32_t w, uint32_t h) +{ + struct cursor *cursor = &cursors[ncursors]; + + assert(ncursors < MAX_CURSORS); + + cursor->fd = fd; + cursor->bo_handle = bo_handle; + cursor->crtc_id = crtc_id; + cursor->crtc_w = crtc_w; + cursor->crtc_h = crtc_h; + cursor->w = w; + cursor->h = h; + + cursor->enabled = 0; + cursor->x = w/2; + cursor->y = h/2; + cursor->dx = 1; + cursor->dy = 1; + + ncursors++; + + return 0; +} + +int cursor_start(void) +{ + cursor_running = 1; + pthread_create(&cursor_thread, NULL, cursor_thread_func, NULL); + printf("starting cursor\n"); + return 0; +} + +int cursor_stop(void) +{ + cursor_running = 0; + pthread_join(cursor_thread, NULL); + printf("cursor stopped\n"); + return 0; +} diff --git a/tests/modetest/cursor.h b/tests/modetest/cursor.h new file mode 100644 index 0000000..d849f6c --- /dev/null +++ b/tests/modetest/cursor.h @@ -0,0 +1,33 @@ +/* + * DRM based mode setting test program + * Copyright (C) 2014 Red Hat + * Author: Rob Clark + * + * 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. + */ + +#ifndef __CURSOR_H__ +#define __CURSOR_H__ + +int cursor_init(int fd, uint32_t bo_handle, uint32_t crtc_id, + uint32_t crtc_w, uint32_t crtc_h, uint32_t w, uint32_t h); +int cursor_start(void); +int cursor_stop(void); + +#endif diff --git a/tests/modetest/meson.build b/tests/modetest/meson.build new file mode 100644 index 0000000..23d84a1 --- /dev/null +++ b/tests/modetest/meson.build @@ -0,0 +1,29 @@ +# Copyright © 2018 Intel Corporation + +# 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. + +modetest = executable( + 'modetest', + files('buffers.c', 'cursor.c', 'modetest.c'), + c_args : [libdrm_c_args, '-Wno-pointer-arith'], + include_directories : [inc_root, inc_tests, inc_drm], + dependencies : [dep_threads, dep_cairo], + link_with : [libdrm, libutil], + install : with_install_tests, +) diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c new file mode 100644 index 0000000..42e2d1f --- /dev/null +++ b/tests/modetest/modetest.c @@ -0,0 +1,2285 @@ +/* + * DRM based mode setting test program + * Copyright 2008 Tungsten Graphics + * Jakob Bornecrantz + * Copyright 2008 Intel Corporation + * Jesse Barnes + * + * 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. + */ + +/* + * This fairly simple test program dumps output in a similar format to the + * "xrandr" tool everyone knows & loves. It's necessarily slightly different + * since the kernel separates outputs into encoder and connector structures, + * each with their own unique ID. The program also allows test testing of the + * memory management and mode setting APIs by allowing the user to specify a + * connector and mode to use for mode setting. If all works as expected, a + * blue background should be painted on the monitor attached to the specified + * connector after the selected mode is set. + * + * TODO: use cairo to write the mode info on the selected output once + * the mode has been programmed, along with possible test patterns. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if HAVE_SYS_SELECT_H +#include +#endif +#include + +#include "xf86drm.h" +#include "xf86drmMode.h" +#include "drm_fourcc.h" + +#include "util/common.h" +#include "util/format.h" +#include "util/kms.h" +#include "util/pattern.h" + +#include "buffers.h" +#include "cursor.h" + +static enum util_fill_pattern primary_fill = UTIL_PATTERN_SMPTE; +static enum util_fill_pattern secondary_fill = UTIL_PATTERN_TILES; + +struct crtc { + drmModeCrtc *crtc; + drmModeObjectProperties *props; + drmModePropertyRes **props_info; + drmModeModeInfo *mode; +}; + +struct encoder { + drmModeEncoder *encoder; +}; + +struct connector { + drmModeConnector *connector; + drmModeObjectProperties *props; + drmModePropertyRes **props_info; + char *name; +}; + +struct fb { + drmModeFB *fb; +}; + +struct plane { + drmModePlane *plane; + drmModeObjectProperties *props; + drmModePropertyRes **props_info; +}; + +struct resources { + struct crtc *crtcs; + int count_crtcs; + struct encoder *encoders; + int count_encoders; + struct connector *connectors; + int count_connectors; + struct fb *fbs; + int count_fbs; + struct plane *planes; + uint32_t count_planes; +}; + +struct device { + int fd; + + struct resources *resources; + + struct { + unsigned int width; + unsigned int height; + + unsigned int fb_id; + struct bo *bo; + struct bo *cursor_bo; + } mode; + + int use_atomic; + drmModeAtomicReq *req; +}; + +static inline int64_t U642I64(uint64_t val) +{ + return (int64_t)*((int64_t *)&val); +} + +static float mode_vrefresh(drmModeModeInfo *mode) +{ + return mode->clock * 1000.00 + / (mode->htotal * mode->vtotal); +} + +#define bit_name_fn(res) \ +const char * res##_str(int type) { \ + unsigned int i; \ + const char *sep = ""; \ + for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \ + if (type & (1 << i)) { \ + printf("%s%s", sep, res##_names[i]); \ + sep = ", "; \ + } \ + } \ + return NULL; \ +} + +static const char *mode_type_names[] = { + "builtin", + "clock_c", + "crtc_c", + "preferred", + "default", + "userdef", + "driver", +}; + +static bit_name_fn(mode_type) + +static const char *mode_flag_names[] = { + "phsync", + "nhsync", + "pvsync", + "nvsync", + "interlace", + "dblscan", + "csync", + "pcsync", + "ncsync", + "hskew", + "bcast", + "pixmux", + "dblclk", + "clkdiv2" +}; + +static bit_name_fn(mode_flag) + +static void dump_fourcc(uint32_t fourcc) +{ + char *name = drmGetFormatName(fourcc); + printf(" %s", name); + free(name); +} + +static void dump_encoders(struct device *dev) +{ + drmModeEncoder *encoder; + int i; + + printf("Encoders:\n"); + printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n"); + for (i = 0; i < dev->resources->count_encoders; i++) { + encoder = dev->resources->encoders[i].encoder; + if (!encoder) + continue; + + printf("%d\t%d\t%s\t0x%08x\t0x%08x\n", + encoder->encoder_id, + encoder->crtc_id, + util_lookup_encoder_type_name(encoder->encoder_type), + encoder->possible_crtcs, + encoder->possible_clones); + } + printf("\n"); +} + +static void dump_mode(drmModeModeInfo *mode, int index) +{ + printf(" #%i %s %.2f %d %d %d %d %d %d %d %d %d", + index, + mode->name, + mode_vrefresh(mode), + mode->hdisplay, + mode->hsync_start, + mode->hsync_end, + mode->htotal, + mode->vdisplay, + mode->vsync_start, + mode->vsync_end, + mode->vtotal, + mode->clock); + + printf(" flags: "); + mode_flag_str(mode->flags); + printf("; type: "); + mode_type_str(mode->type); + printf("\n"); +} + +static void dump_blob(struct device *dev, uint32_t blob_id) +{ + uint32_t i; + unsigned char *blob_data; + drmModePropertyBlobPtr blob; + + blob = drmModeGetPropertyBlob(dev->fd, blob_id); + if (!blob) { + printf("\n"); + return; + } + + blob_data = blob->data; + + for (i = 0; i < blob->length; i++) { + if (i % 16 == 0) + printf("\n\t\t\t"); + printf("%.2hhx", blob_data[i]); + } + printf("\n"); + + drmModeFreePropertyBlob(blob); +} + +static const char *modifier_to_string(uint64_t modifier) +{ + static char mod_string[4096]; + + char *modifier_name = drmGetFormatModifierName(modifier); + char *vendor_name = drmGetFormatModifierVendor(modifier); + memset(mod_string, 0x00, sizeof(mod_string)); + + if (!modifier_name) { + if (vendor_name) + snprintf(mod_string, sizeof(mod_string), "%s_%s", + vendor_name, "UNKNOWN_MODIFIER"); + else + snprintf(mod_string, sizeof(mod_string), "%s_%s", + "UNKNOWN_VENDOR", "UNKNOWN_MODIFIER"); + /* safe, as free is no-op for NULL */ + free(vendor_name); + return mod_string; + } + + if (modifier == DRM_FORMAT_MOD_LINEAR) { + snprintf(mod_string, sizeof(mod_string), "%s", modifier_name); + free(modifier_name); + free(vendor_name); + return mod_string; + } + + snprintf(mod_string, sizeof(mod_string), "%s_%s", + vendor_name, modifier_name); + + free(modifier_name); + free(vendor_name); + return mod_string; +} + +static void dump_in_formats(struct device *dev, uint32_t blob_id) +{ + drmModeFormatModifierIterator iter = {0}; + drmModePropertyBlobPtr blob; + uint32_t fmt = 0; + + printf("\t\tin_formats blob decoded:\n"); + blob = drmModeGetPropertyBlob(dev->fd, blob_id); + if (!blob) { + printf("\n"); + return; + } + + while (drmModeFormatModifierBlobIterNext(blob, &iter)) { + if (!fmt || fmt != iter.fmt) { + printf("%s\t\t\t", !fmt ? "" : "\n"); + fmt = iter.fmt; + dump_fourcc(fmt); + printf(": "); + } + + printf(" %s", modifier_to_string(iter.mod)); + } + + printf("\n"); + + drmModeFreePropertyBlob(blob); +} + +static void dump_prop(struct device *dev, drmModePropertyPtr prop, + uint32_t prop_id, uint64_t value) +{ + int i; + printf("\t%d", prop_id); + if (!prop) { + printf("\n"); + return; + } + + printf(" %s:\n", prop->name); + + printf("\t\tflags:"); + if (prop->flags & DRM_MODE_PROP_PENDING) + printf(" pending"); + if (prop->flags & DRM_MODE_PROP_IMMUTABLE) + printf(" immutable"); + if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) + printf(" signed range"); + if (drm_property_type_is(prop, DRM_MODE_PROP_RANGE)) + printf(" range"); + if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM)) + printf(" enum"); + if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK)) + printf(" bitmask"); + if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) + printf(" blob"); + if (drm_property_type_is(prop, DRM_MODE_PROP_OBJECT)) + printf(" object"); + printf("\n"); + + if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) { + printf("\t\tvalues:"); + for (i = 0; i < prop->count_values; i++) + printf(" %"PRId64, U642I64(prop->values[i])); + printf("\n"); + } + + if (drm_property_type_is(prop, DRM_MODE_PROP_RANGE)) { + printf("\t\tvalues:"); + for (i = 0; i < prop->count_values; i++) + printf(" %"PRIu64, prop->values[i]); + printf("\n"); + } + + if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM)) { + printf("\t\tenums:"); + for (i = 0; i < prop->count_enums; i++) + printf(" %s=%"PRIu64, prop->enums[i].name, + (uint64_t)prop->enums[i].value); + printf("\n"); + } else if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK)) { + printf("\t\tvalues:"); + for (i = 0; i < prop->count_enums; i++) + printf(" %s=0x%llx", prop->enums[i].name, + (1LL << prop->enums[i].value)); + printf("\n"); + } else { + assert(prop->count_enums == 0); + } + + if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) { + printf("\t\tblobs:\n"); + for (i = 0; i < prop->count_blobs; i++) + dump_blob(dev, prop->blob_ids[i]); + printf("\n"); + } else { + assert(prop->count_blobs == 0); + } + + printf("\t\tvalue:"); + if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) + dump_blob(dev, value); + else if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) + printf(" %"PRId64"\n", value); + else + printf(" %"PRIu64"\n", value); + + if (strcmp(prop->name, "IN_FORMATS") == 0) + dump_in_formats(dev, value); +} + +static void dump_connectors(struct device *dev) +{ + int i, j; + + printf("Connectors:\n"); + printf("id\tencoder\tstatus\t\tname\t\tsize (mm)\tmodes\tencoders\n"); + for (i = 0; i < dev->resources->count_connectors; i++) { + struct connector *_connector = &dev->resources->connectors[i]; + drmModeConnector *connector = _connector->connector; + if (!connector) + continue; + + printf("%d\t%d\t%s\t%-15s\t%dx%d\t\t%d\t", + connector->connector_id, + connector->encoder_id, + util_lookup_connector_status_name(connector->connection), + _connector->name, + connector->mmWidth, connector->mmHeight, + connector->count_modes); + + for (j = 0; j < connector->count_encoders; j++) + printf("%s%d", j > 0 ? ", " : "", connector->encoders[j]); + printf("\n"); + + if (connector->count_modes) { + printf(" modes:\n"); + printf("\tindex name refresh (Hz) hdisp hss hse htot vdisp " + "vss vse vtot\n"); + for (j = 0; j < connector->count_modes; j++) + dump_mode(&connector->modes[j], j); + } + + if (_connector->props) { + printf(" props:\n"); + for (j = 0; j < (int)_connector->props->count_props; j++) + dump_prop(dev, _connector->props_info[j], + _connector->props->props[j], + _connector->props->prop_values[j]); + } + } + printf("\n"); +} + +static void dump_crtcs(struct device *dev) +{ + int i; + uint32_t j; + + printf("CRTCs:\n"); + printf("id\tfb\tpos\tsize\n"); + for (i = 0; i < dev->resources->count_crtcs; i++) { + struct crtc *_crtc = &dev->resources->crtcs[i]; + drmModeCrtc *crtc = _crtc->crtc; + if (!crtc) + continue; + + printf("%d\t%d\t(%d,%d)\t(%dx%d)\n", + crtc->crtc_id, + crtc->buffer_id, + crtc->x, crtc->y, + crtc->width, crtc->height); + dump_mode(&crtc->mode, 0); + + if (_crtc->props) { + printf(" props:\n"); + for (j = 0; j < _crtc->props->count_props; j++) + dump_prop(dev, _crtc->props_info[j], + _crtc->props->props[j], + _crtc->props->prop_values[j]); + } else { + printf(" no properties found\n"); + } + } + printf("\n"); +} + +static void dump_framebuffers(struct device *dev) +{ + drmModeFB *fb; + int i; + + printf("Frame buffers:\n"); + printf("id\tsize\tpitch\n"); + for (i = 0; i < dev->resources->count_fbs; i++) { + fb = dev->resources->fbs[i].fb; + if (!fb) + continue; + + printf("%u\t(%ux%u)\t%u\n", + fb->fb_id, + fb->width, fb->height, + fb->pitch); + } + printf("\n"); +} + +static void dump_planes(struct device *dev) +{ + unsigned int i, j; + + printf("Planes:\n"); + printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\tpossible crtcs\n"); + + for (i = 0; i < dev->resources->count_planes; i++) { + struct plane *plane = &dev->resources->planes[i]; + drmModePlane *ovr = plane->plane; + if (!ovr) + continue; + + printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%-8d\t0x%08x\n", + ovr->plane_id, ovr->crtc_id, ovr->fb_id, + ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y, + ovr->gamma_size, ovr->possible_crtcs); + + if (!ovr->count_formats) + continue; + + printf(" formats:"); + for (j = 0; j < ovr->count_formats; j++) + dump_fourcc(ovr->formats[j]); + printf("\n"); + + if (plane->props) { + printf(" props:\n"); + for (j = 0; j < plane->props->count_props; j++) + dump_prop(dev, plane->props_info[j], + plane->props->props[j], + plane->props->prop_values[j]); + } else { + printf(" no properties found\n"); + } + } + printf("\n"); + + return; +} + +static void free_resources(struct resources *res) +{ + int i; + + if (!res) + return; + +#define free_resource(_res, type, Type) \ + do { \ + if (!(_res)->type##s) \ + break; \ + for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \ + if (!(_res)->type##s[i].type) \ + break; \ + drmModeFree##Type((_res)->type##s[i].type); \ + } \ + free((_res)->type##s); \ + } while (0) + +#define free_properties(_res, type) \ + do { \ + for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \ + unsigned int j; \ + for (j = 0; j < res->type##s[i].props->count_props; ++j)\ + drmModeFreeProperty(res->type##s[i].props_info[j]);\ + free(res->type##s[i].props_info); \ + drmModeFreeObjectProperties(res->type##s[i].props); \ + } \ + } while (0) + + free_properties(res, plane); + free_resource(res, plane, Plane); + + free_properties(res, connector); + free_properties(res, crtc); + + for (i = 0; i < res->count_connectors; i++) + free(res->connectors[i].name); + + free_resource(res, fb, FB); + free_resource(res, connector, Connector); + free_resource(res, encoder, Encoder); + free_resource(res, crtc, Crtc); + + free(res); +} + +static struct resources *get_resources(struct device *dev) +{ + drmModeRes *_res; + drmModePlaneRes *plane_res; + struct resources *res; + int i; + + res = calloc(1, sizeof(*res)); + if (res == 0) + return NULL; + + drmSetClientCap(dev->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); + + _res = drmModeGetResources(dev->fd); + if (!_res) { + fprintf(stderr, "drmModeGetResources failed: %s\n", + strerror(errno)); + free(res); + return NULL; + } + + res->count_crtcs = _res->count_crtcs; + res->count_encoders = _res->count_encoders; + res->count_connectors = _res->count_connectors; + res->count_fbs = _res->count_fbs; + + res->crtcs = calloc(res->count_crtcs, sizeof(*res->crtcs)); + res->encoders = calloc(res->count_encoders, sizeof(*res->encoders)); + res->connectors = calloc(res->count_connectors, sizeof(*res->connectors)); + res->fbs = calloc(res->count_fbs, sizeof(*res->fbs)); + + if (!res->crtcs || !res->encoders || !res->connectors || !res->fbs) { + drmModeFreeResources(_res); + goto error; + } + +#define get_resource(_res, __res, type, Type) \ + do { \ + for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \ + uint32_t type##id = (__res)->type##s[i]; \ + (_res)->type##s[i].type = \ + drmModeGet##Type(dev->fd, type##id); \ + if (!(_res)->type##s[i].type) \ + fprintf(stderr, "could not get %s %i: %s\n", \ + #type, type##id, \ + strerror(errno)); \ + } \ + } while (0) + + get_resource(res, _res, crtc, Crtc); + get_resource(res, _res, encoder, Encoder); + get_resource(res, _res, connector, Connector); + get_resource(res, _res, fb, FB); + + drmModeFreeResources(_res); + + /* Set the name of all connectors based on the type name and the per-type ID. */ + for (i = 0; i < res->count_connectors; i++) { + struct connector *connector = &res->connectors[i]; + drmModeConnector *conn = connector->connector; + int num; + + num = asprintf(&connector->name, "%s-%u", + drmModeGetConnectorTypeName(conn->connector_type), + conn->connector_type_id); + if (num < 0) + goto error; + } + +#define get_properties(_res, type, Type) \ + do { \ + for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \ + struct type *obj = &res->type##s[i]; \ + unsigned int j; \ + obj->props = \ + drmModeObjectGetProperties(dev->fd, obj->type->type##_id, \ + DRM_MODE_OBJECT_##Type); \ + if (!obj->props) { \ + fprintf(stderr, \ + "could not get %s %i properties: %s\n", \ + #type, obj->type->type##_id, \ + strerror(errno)); \ + continue; \ + } \ + obj->props_info = calloc(obj->props->count_props, \ + sizeof(*obj->props_info)); \ + if (!obj->props_info) \ + continue; \ + for (j = 0; j < obj->props->count_props; ++j) \ + obj->props_info[j] = \ + drmModeGetProperty(dev->fd, obj->props->props[j]); \ + } \ + } while (0) + + get_properties(res, crtc, CRTC); + get_properties(res, connector, CONNECTOR); + + for (i = 0; i < res->count_crtcs; ++i) + res->crtcs[i].mode = &res->crtcs[i].crtc->mode; + + plane_res = drmModeGetPlaneResources(dev->fd); + if (!plane_res) { + fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", + strerror(errno)); + return res; + } + + res->count_planes = plane_res->count_planes; + + res->planes = calloc(res->count_planes, sizeof(*res->planes)); + if (!res->planes) { + drmModeFreePlaneResources(plane_res); + goto error; + } + + get_resource(res, plane_res, plane, Plane); + drmModeFreePlaneResources(plane_res); + get_properties(res, plane, PLANE); + + return res; + +error: + free_resources(res); + return NULL; +} + +static struct crtc *get_crtc_by_id(struct device *dev, uint32_t id) +{ + int i; + + for (i = 0; i < dev->resources->count_crtcs; ++i) { + drmModeCrtc *crtc = dev->resources->crtcs[i].crtc; + if (crtc && crtc->crtc_id == id) + return &dev->resources->crtcs[i]; + } + + return NULL; +} + +static uint32_t get_crtc_mask(struct device *dev, struct crtc *crtc) +{ + unsigned int i; + + for (i = 0; i < (unsigned int)dev->resources->count_crtcs; i++) { + if (crtc->crtc->crtc_id == dev->resources->crtcs[i].crtc->crtc_id) + return 1 << i; + } + /* Unreachable: crtc->crtc is one of resources->crtcs[] */ + /* Don't return zero or static analysers will complain */ + abort(); + return 0; +} + +static drmModeConnector *get_connector_by_name(struct device *dev, const char *name) +{ + struct connector *connector; + int i; + + for (i = 0; i < dev->resources->count_connectors; i++) { + connector = &dev->resources->connectors[i]; + + if (strcmp(connector->name, name) == 0) + return connector->connector; + } + + return NULL; +} + +static drmModeConnector *get_connector_by_id(struct device *dev, uint32_t id) +{ + drmModeConnector *connector; + int i; + + for (i = 0; i < dev->resources->count_connectors; i++) { + connector = dev->resources->connectors[i].connector; + if (connector && connector->connector_id == id) + return connector; + } + + return NULL; +} + +static drmModeEncoder *get_encoder_by_id(struct device *dev, uint32_t id) +{ + drmModeEncoder *encoder; + int i; + + for (i = 0; i < dev->resources->count_encoders; i++) { + encoder = dev->resources->encoders[i].encoder; + if (encoder && encoder->encoder_id == id) + return encoder; + } + + return NULL; +} + +/* ----------------------------------------------------------------------------- + * Pipes and planes + */ + +/* + * Mode setting with the kernel interfaces is a bit of a chore. + * First you have to find the connector in question and make sure the + * requested mode is available. + * Then you need to find the encoder attached to that connector so you + * can bind it with a free crtc. + */ +struct pipe_arg { + const char **cons; + uint32_t *con_ids; + unsigned int num_cons; + uint32_t crtc_id; + char mode_str[64]; + char format_str[5]; + float vrefresh; + unsigned int fourcc; + drmModeModeInfo *mode; + struct crtc *crtc; + unsigned int fb_id[2], current_fb_id; + struct timeval start; + + int swap_count; +}; + +struct plane_arg { + uint32_t plane_id; /* the id of plane to use */ + uint32_t crtc_id; /* the id of CRTC to bind to */ + bool has_position; + int32_t x, y; + uint32_t w, h; + double scale; + unsigned int fb_id; + unsigned int old_fb_id; + struct bo *bo; + struct bo *old_bo; + char format_str[5]; /* need to leave room for terminating \0 */ + unsigned int fourcc; +}; + +static drmModeModeInfo * +connector_find_mode(struct device *dev, uint32_t con_id, const char *mode_str, + const float vrefresh) +{ + drmModeConnector *connector; + drmModeModeInfo *mode; + int i; + + connector = get_connector_by_id(dev, con_id); + if (!connector || !connector->count_modes) + return NULL; + + /* Pick by Index */ + if (mode_str[0] == '#') { + int index = atoi(mode_str + 1); + + if (index >= connector->count_modes || index < 0) + return NULL; + return &connector->modes[index]; + } + + /* Pick by Name */ + for (i = 0; i < connector->count_modes; i++) { + mode = &connector->modes[i]; + if (!strcmp(mode->name, mode_str)) { + /* If the vertical refresh frequency is not specified + * then return the first mode that match with the name. + * Else, return the mode that match the name and + * the specified vertical refresh frequency. + */ + if (vrefresh == 0) + return mode; + else if (fabs(mode_vrefresh(mode) - vrefresh) < 0.005) + return mode; + } + } + + return NULL; +} + +static struct crtc *pipe_find_crtc(struct device *dev, struct pipe_arg *pipe) +{ + uint32_t possible_crtcs = ~0; + uint32_t active_crtcs = 0; + unsigned int crtc_idx; + unsigned int i; + int j; + + for (i = 0; i < pipe->num_cons; ++i) { + uint32_t crtcs_for_connector = 0; + drmModeConnector *connector; + drmModeEncoder *encoder; + struct crtc *crtc; + + connector = get_connector_by_id(dev, pipe->con_ids[i]); + if (!connector) + return NULL; + + for (j = 0; j < connector->count_encoders; ++j) { + encoder = get_encoder_by_id(dev, connector->encoders[j]); + if (!encoder) + continue; + + crtcs_for_connector |= encoder->possible_crtcs; + crtc = get_crtc_by_id(dev, encoder->crtc_id); + if (!crtc) + continue; + active_crtcs |= get_crtc_mask(dev, crtc); + } + + possible_crtcs &= crtcs_for_connector; + } + + if (!possible_crtcs) + return NULL; + + /* Return the first possible and active CRTC if one exists, or the first + * possible CRTC otherwise. + */ + if (possible_crtcs & active_crtcs) + crtc_idx = ffs(possible_crtcs & active_crtcs); + else + crtc_idx = ffs(possible_crtcs); + + return &dev->resources->crtcs[crtc_idx - 1]; +} + +static int pipe_find_crtc_and_mode(struct device *dev, struct pipe_arg *pipe) +{ + drmModeModeInfo *mode = NULL; + int i; + + pipe->mode = NULL; + + for (i = 0; i < (int)pipe->num_cons; i++) { + mode = connector_find_mode(dev, pipe->con_ids[i], + pipe->mode_str, pipe->vrefresh); + if (mode == NULL) { + if (pipe->vrefresh) + fprintf(stderr, + "failed to find mode " + "\"%s-%.2fHz\" for connector %s\n", + pipe->mode_str, pipe->vrefresh, pipe->cons[i]); + else + fprintf(stderr, + "failed to find mode \"%s\" for connector %s\n", + pipe->mode_str, pipe->cons[i]); + return -EINVAL; + } + } + + /* If the CRTC ID was specified, get the corresponding CRTC. Otherwise + * locate a CRTC that can be attached to all the connectors. + */ + if (pipe->crtc_id != (uint32_t)-1) { + pipe->crtc = get_crtc_by_id(dev, pipe->crtc_id); + } else { + pipe->crtc = pipe_find_crtc(dev, pipe); + pipe->crtc_id = pipe->crtc->crtc->crtc_id; + } + + if (!pipe->crtc) { + fprintf(stderr, "failed to find CRTC for pipe\n"); + return -EINVAL; + } + + pipe->mode = mode; + pipe->crtc->mode = mode; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Properties + */ + +struct property_arg { + uint32_t obj_id; + uint32_t obj_type; + char name[DRM_PROP_NAME_LEN+1]; + uint32_t prop_id; + uint64_t value; + bool optional; +}; + +static bool set_property(struct device *dev, struct property_arg *p) +{ + drmModeObjectProperties *props = NULL; + drmModePropertyRes **props_info = NULL; + const char *obj_type; + int ret; + int i; + + p->obj_type = 0; + p->prop_id = 0; + +#define find_object(_res, type, Type) \ + do { \ + for (i = 0; i < (int)(_res)->count_##type##s; ++i) { \ + struct type *obj = &(_res)->type##s[i]; \ + if (obj->type->type##_id != p->obj_id) \ + continue; \ + p->obj_type = DRM_MODE_OBJECT_##Type; \ + obj_type = #Type; \ + props = obj->props; \ + props_info = obj->props_info; \ + } \ + } while(0) \ + + find_object(dev->resources, crtc, CRTC); + if (p->obj_type == 0) + find_object(dev->resources, connector, CONNECTOR); + if (p->obj_type == 0) + find_object(dev->resources, plane, PLANE); + if (p->obj_type == 0) { + fprintf(stderr, "Object %i not found, can't set property\n", + p->obj_id); + return false; + } + + if (!props) { + fprintf(stderr, "%s %i has no properties\n", + obj_type, p->obj_id); + return false; + } + + for (i = 0; i < (int)props->count_props; ++i) { + if (!props_info[i]) + continue; + if (strcmp(props_info[i]->name, p->name) == 0) + break; + } + + if (i == (int)props->count_props) { + if (!p->optional) + fprintf(stderr, "%s %i has no %s property\n", + obj_type, p->obj_id, p->name); + return false; + } + + p->prop_id = props->props[i]; + + if (!dev->use_atomic) + ret = drmModeObjectSetProperty(dev->fd, p->obj_id, p->obj_type, + p->prop_id, p->value); + else + ret = drmModeAtomicAddProperty(dev->req, p->obj_id, p->prop_id, p->value); + + if (ret < 0) + fprintf(stderr, "failed to set %s %i property %s to %" PRIu64 ": %s\n", + obj_type, p->obj_id, p->name, p->value, strerror(errno)); + + return true; +} + +/* -------------------------------------------------------------------------- */ + +static void +page_flip_handler(int fd, unsigned int frame, + unsigned int sec, unsigned int usec, void *data) +{ + struct pipe_arg *pipe; + unsigned int new_fb_id; + struct timeval end; + double t; + + pipe = data; + if (pipe->current_fb_id == pipe->fb_id[0]) + new_fb_id = pipe->fb_id[1]; + else + new_fb_id = pipe->fb_id[0]; + + drmModePageFlip(fd, pipe->crtc_id, new_fb_id, + DRM_MODE_PAGE_FLIP_EVENT, pipe); + pipe->current_fb_id = new_fb_id; + pipe->swap_count++; + if (pipe->swap_count == 60) { + gettimeofday(&end, NULL); + t = end.tv_sec + end.tv_usec * 1e-6 - + (pipe->start.tv_sec + pipe->start.tv_usec * 1e-6); + fprintf(stderr, "freq: %.02fHz\n", pipe->swap_count / t); + pipe->swap_count = 0; + pipe->start = end; + } +} + +static bool format_support(const drmModePlanePtr ovr, uint32_t fmt) +{ + unsigned int i; + + for (i = 0; i < ovr->count_formats; ++i) { + if (ovr->formats[i] == fmt) + return true; + } + + return false; +} + +static void add_property(struct device *dev, uint32_t obj_id, + const char *name, uint64_t value) +{ + struct property_arg p; + + p.obj_id = obj_id; + strcpy(p.name, name); + p.value = value; + + set_property(dev, &p); +} + +static bool add_property_optional(struct device *dev, uint32_t obj_id, + const char *name, uint64_t value) +{ + struct property_arg p; + + p.obj_id = obj_id; + strcpy(p.name, name); + p.value = value; + p.optional = true; + + return set_property(dev, &p); +} + +static void set_gamma(struct device *dev, unsigned crtc_id, unsigned fourcc) +{ + unsigned blob_id = 0; + /* TODO: support 1024-sized LUTs, when the use-case arises */ + struct drm_color_lut gamma_lut[256]; + int i, ret; + + if (fourcc == DRM_FORMAT_C8) { + /* TODO: Add C8 support for more patterns */ + util_smpte_c8_gamma(256, gamma_lut); + drmModeCreatePropertyBlob(dev->fd, gamma_lut, sizeof(gamma_lut), &blob_id); + } else { + for (i = 0; i < 256; i++) { + gamma_lut[i].red = + gamma_lut[i].green = + gamma_lut[i].blue = i << 8; + } + } + + add_property_optional(dev, crtc_id, "DEGAMMA_LUT", 0); + add_property_optional(dev, crtc_id, "CTM", 0); + if (!add_property_optional(dev, crtc_id, "GAMMA_LUT", blob_id)) { + uint16_t r[256], g[256], b[256]; + + for (i = 0; i < 256; i++) { + r[i] = gamma_lut[i].red; + g[i] = gamma_lut[i].green; + b[i] = gamma_lut[i].blue; + } + + ret = drmModeCrtcSetGamma(dev->fd, crtc_id, 256, r, g, b); + if (ret) + fprintf(stderr, "failed to set gamma: %s\n", strerror(errno)); + } +} + +static int +bo_fb_create(int fd, unsigned int fourcc, const uint32_t w, const uint32_t h, + enum util_fill_pattern pat, struct bo **out_bo, unsigned int *out_fb_id) +{ + uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; + struct bo *bo; + unsigned int fb_id; + + bo = bo_create(fd, fourcc, w, h, handles, pitches, offsets, pat); + + if (bo == NULL) + return -1; + + if (drmModeAddFB2(fd, w, h, fourcc, handles, pitches, offsets, &fb_id, 0)) { + fprintf(stderr, "failed to add fb (%ux%u): %s\n", w, h, strerror(errno)); + bo_destroy(bo); + return -1; + } + *out_bo = bo; + *out_fb_id = fb_id; + return 0; +} + +static int atomic_set_plane(struct device *dev, struct plane_arg *p, + int pattern, bool update) +{ + struct bo *plane_bo; + int crtc_x, crtc_y, crtc_w, crtc_h; + struct crtc *crtc = NULL; + unsigned int old_fb_id; + + /* Find an unused plane which can be connected to our CRTC. Find the + * CRTC index first, then iterate over available planes. + */ + crtc = get_crtc_by_id(dev, p->crtc_id); + if (!crtc) { + fprintf(stderr, "CRTC %u not found\n", p->crtc_id); + return -1; + } + + if (!update) + fprintf(stderr, "testing %dx%d@%s on plane %u, crtc %u\n", + p->w, p->h, p->format_str, p->plane_id, p->crtc_id); + + plane_bo = p->old_bo; + p->old_bo = p->bo; + + if (!plane_bo) { + if (bo_fb_create(dev->fd, p->fourcc, p->w, p->h, + pattern, &plane_bo, &p->fb_id)) + return -1; + } + + p->bo = plane_bo; + + old_fb_id = p->fb_id; + p->old_fb_id = old_fb_id; + + crtc_w = p->w * p->scale; + crtc_h = p->h * p->scale; + if (!p->has_position) { + /* Default to the middle of the screen */ + crtc_x = (crtc->mode->hdisplay - crtc_w) / 2; + crtc_y = (crtc->mode->vdisplay - crtc_h) / 2; + } else { + crtc_x = p->x; + crtc_y = p->y; + } + + add_property(dev, p->plane_id, "FB_ID", p->fb_id); + add_property(dev, p->plane_id, "CRTC_ID", p->crtc_id); + add_property(dev, p->plane_id, "SRC_X", 0); + add_property(dev, p->plane_id, "SRC_Y", 0); + add_property(dev, p->plane_id, "SRC_W", p->w << 16); + add_property(dev, p->plane_id, "SRC_H", p->h << 16); + add_property(dev, p->plane_id, "CRTC_X", crtc_x); + add_property(dev, p->plane_id, "CRTC_Y", crtc_y); + add_property(dev, p->plane_id, "CRTC_W", crtc_w); + add_property(dev, p->plane_id, "CRTC_H", crtc_h); + + return 0; +} + +static int set_plane(struct device *dev, struct plane_arg *p) +{ + drmModePlane *ovr; + uint32_t plane_id; + int crtc_x, crtc_y, crtc_w, crtc_h; + struct crtc *crtc = NULL; + unsigned int i, crtc_mask; + + /* Find an unused plane which can be connected to our CRTC. Find the + * CRTC index first, then iterate over available planes. + */ + crtc = get_crtc_by_id(dev, p->crtc_id); + if (!crtc) { + fprintf(stderr, "CRTC %u not found\n", p->crtc_id); + return -1; + } + crtc_mask = get_crtc_mask(dev, crtc); + plane_id = p->plane_id; + + for (i = 0; i < dev->resources->count_planes; i++) { + ovr = dev->resources->planes[i].plane; + if (!ovr) + continue; + + if (plane_id && plane_id != ovr->plane_id) + continue; + + if (!format_support(ovr, p->fourcc)) + continue; + + if ((ovr->possible_crtcs & crtc_mask) && + (ovr->crtc_id == 0 || ovr->crtc_id == p->crtc_id)) { + plane_id = ovr->plane_id; + break; + } + } + + if (i == dev->resources->count_planes) { + fprintf(stderr, "no unused plane available for CRTC %u\n", + p->crtc_id); + return -1; + } + + fprintf(stderr, "testing %dx%d@%s overlay plane %u\n", + p->w, p->h, p->format_str, plane_id); + + /* just use single plane format for now.. */ + if (bo_fb_create(dev->fd, p->fourcc, p->w, p->h, + secondary_fill, &p->bo, &p->fb_id)) + return -1; + + crtc_w = p->w * p->scale; + crtc_h = p->h * p->scale; + if (!p->has_position) { + /* Default to the middle of the screen */ + crtc_x = (crtc->mode->hdisplay - crtc_w) / 2; + crtc_y = (crtc->mode->vdisplay - crtc_h) / 2; + } else { + crtc_x = p->x; + crtc_y = p->y; + } + + /* note src coords (last 4 args) are in Q16 format */ + if (drmModeSetPlane(dev->fd, plane_id, p->crtc_id, p->fb_id, + 0, crtc_x, crtc_y, crtc_w, crtc_h, + 0, 0, p->w << 16, p->h << 16)) { + fprintf(stderr, "failed to enable plane: %s\n", + strerror(errno)); + return -1; + } + + ovr->crtc_id = p->crtc_id; + + return 0; +} + +static void atomic_set_planes(struct device *dev, struct plane_arg *p, + unsigned int count, bool update) +{ + unsigned int i, pattern = primary_fill; + + /* set up planes */ + for (i = 0; i < count; i++) { + if (i > 0) + pattern = secondary_fill; + else + set_gamma(dev, p[i].crtc_id, p[i].fourcc); + + if (atomic_set_plane(dev, &p[i], pattern, update)) + return; + } +} + +static void +atomic_test_page_flip(struct device *dev, struct pipe_arg *pipe_args, + struct plane_arg *plane_args, unsigned int plane_count) +{ + int ret; + + gettimeofday(&pipe_args->start, NULL); + pipe_args->swap_count = 0; + + while (true) { + drmModeAtomicFree(dev->req); + dev->req = drmModeAtomicAlloc(); + atomic_set_planes(dev, plane_args, plane_count, true); + + ret = drmModeAtomicCommit(dev->fd, dev->req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); + if (ret) { + fprintf(stderr, "Atomic Commit failed [2]\n"); + return; + } + + pipe_args->swap_count++; + if (pipe_args->swap_count == 60) { + struct timeval end; + double t; + + gettimeofday(&end, NULL); + t = end.tv_sec + end.tv_usec * 1e-6 - + (pipe_args->start.tv_sec + pipe_args->start.tv_usec * 1e-6); + fprintf(stderr, "freq: %.02fHz\n", pipe_args->swap_count / t); + pipe_args->swap_count = 0; + pipe_args->start = end; + } + } +} + +static void atomic_clear_planes(struct device *dev, struct plane_arg *p, unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) { + add_property(dev, p[i].plane_id, "FB_ID", 0); + add_property(dev, p[i].plane_id, "CRTC_ID", 0); + add_property(dev, p[i].plane_id, "SRC_X", 0); + add_property(dev, p[i].plane_id, "SRC_Y", 0); + add_property(dev, p[i].plane_id, "SRC_W", 0); + add_property(dev, p[i].plane_id, "SRC_H", 0); + add_property(dev, p[i].plane_id, "CRTC_X", 0); + add_property(dev, p[i].plane_id, "CRTC_Y", 0); + add_property(dev, p[i].plane_id, "CRTC_W", 0); + add_property(dev, p[i].plane_id, "CRTC_H", 0); + } +} + +static void atomic_clear_FB(struct device *dev, struct plane_arg *p, unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) { + if (p[i].fb_id) { + drmModeRmFB(dev->fd, p[i].fb_id); + p[i].fb_id = 0; + } + if (p[i].old_fb_id) { + drmModeRmFB(dev->fd, p[i].old_fb_id); + p[i].old_fb_id = 0; + } + if (p[i].bo) { + bo_destroy(p[i].bo); + p[i].bo = NULL; + } + if (p[i].old_bo) { + bo_destroy(p[i].old_bo); + p[i].old_bo = NULL; + } + + } +} + +static void clear_planes(struct device *dev, struct plane_arg *p, unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) { + if (p[i].fb_id) + drmModeRmFB(dev->fd, p[i].fb_id); + if (p[i].bo) + bo_destroy(p[i].bo); + } +} + +static int pipe_resolve_connectors(struct device *dev, struct pipe_arg *pipe) +{ + drmModeConnector *connector; + unsigned int i; + uint32_t id; + char *endp; + + for (i = 0; i < pipe->num_cons; i++) { + id = strtoul(pipe->cons[i], &endp, 10); + if (endp == pipe->cons[i]) { + connector = get_connector_by_name(dev, pipe->cons[i]); + if (!connector) { + fprintf(stderr, "no connector named '%s'\n", + pipe->cons[i]); + return -ENODEV; + } + + id = connector->connector_id; + } + + pipe->con_ids[i] = id; + } + + return 0; +} + +static int pipe_attempt_connector(struct device *dev, drmModeConnector *con, + struct pipe_arg *pipe) +{ + char *con_str; + int i; + + con_str = calloc(8, sizeof(char)); + if (!con_str) + return -1; + + sprintf(con_str, "%d", con->connector_id); + strcpy(pipe->format_str, "XR24"); + pipe->fourcc = util_format_fourcc(pipe->format_str); + pipe->num_cons = 1; + pipe->con_ids = calloc(1, sizeof(*pipe->con_ids)); + pipe->cons = calloc(1, sizeof(*pipe->cons)); + + if (!pipe->con_ids || !pipe->cons) + goto free_con_str; + + pipe->con_ids[0] = con->connector_id; + pipe->cons[0] = (const char*)con_str; + + pipe->crtc = pipe_find_crtc(dev, pipe); + if (!pipe->crtc) + goto free_all; + + pipe->crtc_id = pipe->crtc->crtc->crtc_id; + + /* Return the first mode if no preferred. */ + pipe->mode = &con->modes[0]; + + for (i = 0; i < con->count_modes; i++) { + drmModeModeInfo *current_mode = &con->modes[i]; + + if (current_mode->type & DRM_MODE_TYPE_PREFERRED) { + pipe->mode = current_mode; + break; + } + } + + sprintf(pipe->mode_str, "%dx%d", pipe->mode->hdisplay, pipe->mode->vdisplay); + + return 0; + +free_all: + free(pipe->cons); + free(pipe->con_ids); +free_con_str: + free(con_str); + return -1; +} + +static int pipe_find_preferred(struct device *dev, struct pipe_arg **out_pipes) +{ + struct pipe_arg *pipes; + struct resources *res = dev->resources; + drmModeConnector *con = NULL; + int i, connected = 0, attempted = 0; + + for (i = 0; i < res->count_connectors; i++) { + con = res->connectors[i].connector; + if (!con || con->connection != DRM_MODE_CONNECTED) + continue; + connected++; + } + if (!connected) { + printf("no connected connector!\n"); + return 0; + } + + pipes = calloc(connected, sizeof(struct pipe_arg)); + if (!pipes) + return 0; + + for (i = 0; i < res->count_connectors && attempted < connected; i++) { + con = res->connectors[i].connector; + if (!con || con->connection != DRM_MODE_CONNECTED) + continue; + + if (pipe_attempt_connector(dev, con, &pipes[attempted]) < 0) { + printf("failed fetching preferred mode for connector\n"); + continue; + } + attempted++; + } + + *out_pipes = pipes; + return attempted; +} + +static struct plane *get_primary_plane_by_crtc(struct device *dev, struct crtc *crtc) +{ + unsigned int i; + + for (i = 0; i < dev->resources->count_planes; i++) { + struct plane *plane = &dev->resources->planes[i]; + drmModePlane *ovr = plane->plane; + if (!ovr) + continue; + + // XXX: add is_primary_plane and (?) format checks + + if (ovr->possible_crtcs & get_crtc_mask(dev, crtc)) + return plane; + } + return NULL; +} + +static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count) +{ + unsigned int i, j; + int ret, x = 0; + int preferred = count == 0; + + for (i = 0; i < count; i++) { + struct pipe_arg *pipe = &pipes[i]; + + ret = pipe_resolve_connectors(dev, pipe); + if (ret < 0) + return; + + ret = pipe_find_crtc_and_mode(dev, pipe); + if (ret < 0) + continue; + } + if (preferred) { + struct pipe_arg *pipe_args; + + count = pipe_find_preferred(dev, &pipe_args); + if (!count) { + fprintf(stderr, "can't find any preferred connector/mode.\n"); + return; + } + pipes = pipe_args; + } + + if (!dev->use_atomic) { + for (i = 0; i < count; i++) { + struct pipe_arg *pipe = &pipes[i]; + + if (pipe->mode == NULL) + continue; + + if (!preferred) { + dev->mode.width += pipe->mode->hdisplay; + if (dev->mode.height < pipe->mode->vdisplay) + dev->mode.height = pipe->mode->vdisplay; + } else { + /* XXX: Use a clone mode, more like atomic. We could do per + * connector bo/fb, so we don't have the stretched image. + */ + if (dev->mode.width < pipe->mode->hdisplay) + dev->mode.width = pipe->mode->hdisplay; + if (dev->mode.height < pipe->mode->vdisplay) + dev->mode.height = pipe->mode->vdisplay; + } + } + + if (bo_fb_create(dev->fd, pipes[0].fourcc, dev->mode.width, dev->mode.height, + primary_fill, &dev->mode.bo, &dev->mode.fb_id)) + return; + } + + for (i = 0; i < count; i++) { + struct pipe_arg *pipe = &pipes[i]; + uint32_t blob_id; + + if (pipe->mode == NULL) + continue; + + printf("setting mode %s-%.2fHz on connectors ", + pipe->mode->name, mode_vrefresh(pipe->mode)); + for (j = 0; j < pipe->num_cons; ++j) { + printf("%s, ", pipe->cons[j]); + if (dev->use_atomic) + add_property(dev, pipe->con_ids[j], "CRTC_ID", pipe->crtc_id); + } + printf("crtc %d\n", pipe->crtc_id); + + if (!dev->use_atomic) { + ret = drmModeSetCrtc(dev->fd, pipe->crtc_id, dev->mode.fb_id, + x, 0, pipe->con_ids, pipe->num_cons, + pipe->mode); + + /* XXX: Actually check if this is needed */ + drmModeDirtyFB(dev->fd, dev->mode.fb_id, NULL, 0); + + if (!preferred) + x += pipe->mode->hdisplay; + + if (ret) { + fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); + return; + } + + set_gamma(dev, pipe->crtc_id, pipe->fourcc); + } else { + drmModeCreatePropertyBlob(dev->fd, pipe->mode, sizeof(*pipe->mode), &blob_id); + add_property(dev, pipe->crtc_id, "MODE_ID", blob_id); + add_property(dev, pipe->crtc_id, "ACTIVE", 1); + + /* By default atomic modeset does not set a primary plane, shrug */ + if (preferred) { + struct plane *plane = get_primary_plane_by_crtc(dev, pipe->crtc); + struct plane_arg plane_args = { + .plane_id = plane->plane->plane_id, + .crtc_id = pipe->crtc_id, + .w = pipe->mode->hdisplay, + .h = pipe->mode->vdisplay, + .scale = 1.0, + .format_str = "XR24", + .fourcc = util_format_fourcc(pipe->format_str), + }; + + atomic_set_planes(dev, &plane_args, 1, false); + } + } + } +} + +static void atomic_clear_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count) +{ + unsigned int i; + unsigned int j; + + for (i = 0; i < count; i++) { + struct pipe_arg *pipe = &pipes[i]; + + if (pipe->mode == NULL) + continue; + + for (j = 0; j < pipe->num_cons; ++j) + add_property(dev, pipe->con_ids[j], "CRTC_ID",0); + + add_property(dev, pipe->crtc_id, "MODE_ID", 0); + add_property(dev, pipe->crtc_id, "ACTIVE", 0); + } +} + +static void clear_mode(struct device *dev) +{ + if (dev->mode.fb_id) + drmModeRmFB(dev->fd, dev->mode.fb_id); + if (dev->mode.bo) + bo_destroy(dev->mode.bo); +} + +static void set_planes(struct device *dev, struct plane_arg *p, unsigned int count) +{ + unsigned int i; + + /* set up planes/overlays */ + for (i = 0; i < count; i++) + if (set_plane(dev, &p[i])) + return; +} + +static void set_cursors(struct device *dev, struct pipe_arg *pipes, unsigned int count) +{ + uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; + uint32_t cw = 64; + uint32_t ch = 64; + struct bo *bo; + uint64_t value; + unsigned int i; + int ret; + + ret = drmGetCap(dev->fd, DRM_CAP_CURSOR_WIDTH, &value); + if (!ret) + cw = value; + + ret = drmGetCap(dev->fd, DRM_CAP_CURSOR_HEIGHT, &value); + if (!ret) + ch = value; + + + /* create cursor bo.. just using PATTERN_PLAIN as it has + * translucent alpha + */ + bo = bo_create(dev->fd, DRM_FORMAT_ARGB8888, cw, ch, handles, pitches, + offsets, UTIL_PATTERN_PLAIN); + if (bo == NULL) + return; + + dev->mode.cursor_bo = bo; + + for (i = 0; i < count; i++) { + struct pipe_arg *pipe = &pipes[i]; + ret = cursor_init(dev->fd, handles[0], + pipe->crtc_id, + pipe->mode->hdisplay, pipe->mode->vdisplay, + cw, ch); + if (ret) { + fprintf(stderr, "failed to init cursor for CRTC[%u]\n", + pipe->crtc_id); + return; + } + } + + cursor_start(); +} + +static void clear_cursors(struct device *dev) +{ + cursor_stop(); + + if (dev->mode.cursor_bo) + bo_destroy(dev->mode.cursor_bo); +} + +static void test_page_flip(struct device *dev, struct pipe_arg *pipes, unsigned int count) +{ + unsigned int other_fb_id; + struct bo *other_bo; + drmEventContext evctx; + unsigned int i; + int ret; + + if (bo_fb_create(dev->fd, pipes[0].fourcc, dev->mode.width, dev->mode.height, + UTIL_PATTERN_PLAIN, &other_bo, &other_fb_id)) + return; + + for (i = 0; i < count; i++) { + struct pipe_arg *pipe = &pipes[i]; + + if (pipe->mode == NULL) + continue; + + ret = drmModePageFlip(dev->fd, pipe->crtc_id, + other_fb_id, DRM_MODE_PAGE_FLIP_EVENT, + pipe); + if (ret) { + fprintf(stderr, "failed to page flip: %s\n", strerror(errno)); + goto err_rmfb; + } + gettimeofday(&pipe->start, NULL); + pipe->swap_count = 0; + pipe->fb_id[0] = dev->mode.fb_id; + pipe->fb_id[1] = other_fb_id; + pipe->current_fb_id = other_fb_id; + } + + memset(&evctx, 0, sizeof evctx); + evctx.version = DRM_EVENT_CONTEXT_VERSION; + evctx.vblank_handler = NULL; + evctx.page_flip_handler = page_flip_handler; + + while (1) { +#if 0 + struct pollfd pfd[2]; + + pfd[0].fd = 0; + pfd[0].events = POLLIN; + pfd[1].fd = fd; + pfd[1].events = POLLIN; + + if (poll(pfd, 2, -1) < 0) { + fprintf(stderr, "poll error\n"); + break; + } + + if (pfd[0].revents) + break; +#else + struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; + fd_set fds; + + FD_ZERO(&fds); + FD_SET(0, &fds); + FD_SET(dev->fd, &fds); + ret = select(dev->fd + 1, &fds, NULL, NULL, &timeout); + + if (ret <= 0) { + fprintf(stderr, "select timed out or error (ret %d)\n", + ret); + continue; + } else if (FD_ISSET(0, &fds)) { + break; + } +#endif + + drmHandleEvent(dev->fd, &evctx); + } + +err_rmfb: + drmModeRmFB(dev->fd, other_fb_id); + bo_destroy(other_bo); +} + +#define min(a, b) ((a) < (b) ? (a) : (b)) + +static int parse_connector(struct pipe_arg *pipe, const char *arg) +{ + unsigned int len; + unsigned int i; + const char *p; + char *endp; + + pipe->vrefresh = 0; + pipe->crtc_id = (uint32_t)-1; + strcpy(pipe->format_str, "XR24"); + + /* Count the number of connectors and allocate them. */ + pipe->num_cons = 1; + for (p = arg; *p && *p != ':' && *p != '@'; ++p) { + if (*p == ',') + pipe->num_cons++; + } + + pipe->con_ids = calloc(pipe->num_cons, sizeof(*pipe->con_ids)); + pipe->cons = calloc(pipe->num_cons, sizeof(*pipe->cons)); + if (pipe->con_ids == NULL || pipe->cons == NULL) + return -1; + + /* Parse the connectors. */ + for (i = 0, p = arg; i < pipe->num_cons; ++i, p = endp + 1) { + endp = strpbrk(p, ",@:"); + if (!endp) + break; + + pipe->cons[i] = strndup(p, endp - p); + + if (*endp != ',') + break; + } + + if (i != pipe->num_cons - 1) + return -1; + + /* Parse the remaining parameters. */ + if (!endp) + return -1; + if (*endp == '@') { + arg = endp + 1; + pipe->crtc_id = strtoul(arg, &endp, 10); + } + if (*endp != ':') + return -1; + + arg = endp + 1; + + /* Search for the vertical refresh or the format. */ + p = strpbrk(arg, "-@"); + if (p == NULL) + p = arg + strlen(arg); + len = min(sizeof pipe->mode_str - 1, (unsigned int)(p - arg)); + strncpy(pipe->mode_str, arg, len); + pipe->mode_str[len] = '\0'; + + if (*p == '-') { + pipe->vrefresh = strtof(p + 1, &endp); + p = endp; + } + + if (*p == '@') { + strncpy(pipe->format_str, p + 1, 4); + pipe->format_str[4] = '\0'; + } + + pipe->fourcc = util_format_fourcc(pipe->format_str); + if (pipe->fourcc == 0) { + fprintf(stderr, "unknown format %s\n", pipe->format_str); + return -1; + } + + return 0; +} + +static int parse_plane(struct plane_arg *plane, const char *p) +{ + char *end; + + plane->plane_id = strtoul(p, &end, 10); + if (*end != '@') + return -EINVAL; + + p = end + 1; + plane->crtc_id = strtoul(p, &end, 10); + if (*end != ':') + return -EINVAL; + + p = end + 1; + plane->w = strtoul(p, &end, 10); + if (*end != 'x') + return -EINVAL; + + p = end + 1; + plane->h = strtoul(p, &end, 10); + + if (*end == '+' || *end == '-') { + plane->x = strtol(end, &end, 10); + if (*end != '+' && *end != '-') + return -EINVAL; + plane->y = strtol(end, &end, 10); + + plane->has_position = true; + } + + if (*end == '*') { + p = end + 1; + plane->scale = strtod(p, &end); + if (plane->scale <= 0.0) + return -EINVAL; + } else { + plane->scale = 1.0; + } + + if (*end == '@') { + strncpy(plane->format_str, end + 1, 4); + plane->format_str[4] = '\0'; + } else { + strcpy(plane->format_str, "XR24"); + } + + plane->fourcc = util_format_fourcc(plane->format_str); + if (plane->fourcc == 0) { + fprintf(stderr, "unknown format %s\n", plane->format_str); + return -EINVAL; + } + + return 0; +} + +static int parse_property(struct property_arg *p, const char *arg) +{ + if (sscanf(arg, "%d:%32[^:]:%" SCNu64, &p->obj_id, p->name, &p->value) != 3) + return -1; + + p->obj_type = 0; + p->name[DRM_PROP_NAME_LEN] = '\0'; + + return 0; +} + +static void parse_fill_patterns(char *arg) +{ + char *fill = strtok(arg, ","); + if (!fill) + return; + primary_fill = util_pattern_enum(fill); + fill = strtok(NULL, ","); + if (!fill) + return; + secondary_fill = util_pattern_enum(fill); +} + +static void usage(char *name) +{ + fprintf(stderr, "usage: %s [-acDdefMPpsCvrw]\n", name); + + fprintf(stderr, "\n Query options:\n\n"); + fprintf(stderr, "\t-c\tlist connectors\n"); + fprintf(stderr, "\t-e\tlist encoders\n"); + fprintf(stderr, "\t-f\tlist framebuffers\n"); + fprintf(stderr, "\t-p\tlist CRTCs and planes (pipes)\n"); + + fprintf(stderr, "\n Test options:\n\n"); + fprintf(stderr, "\t-P @:x[++][*][@]\tset a plane\n"); + fprintf(stderr, "\t-s [,][@]:[#][-][@]\tset a mode\n"); + fprintf(stderr, "\t-C\ttest hw cursor\n"); + fprintf(stderr, "\t-v\ttest vsynced page flipping\n"); + fprintf(stderr, "\t-r\tset the preferred mode for all connectors\n"); + fprintf(stderr, "\t-w ::\tset property\n"); + fprintf(stderr, "\t-a \tuse atomic API\n"); + fprintf(stderr, "\t-F pattern1,pattern2\tspecify fill patterns\n"); + + fprintf(stderr, "\n Generic options:\n\n"); + fprintf(stderr, "\t-d\tdrop master after mode set\n"); + fprintf(stderr, "\t-M module\tuse the given driver\n"); + fprintf(stderr, "\t-D device\tuse the given device\n"); + + fprintf(stderr, "\n\tDefault is to dump all info.\n"); + exit(0); +} + +static char optstr[] = "acdD:efF:M:P:ps:Cvrw:"; + +int main(int argc, char **argv) +{ + struct device dev; + + int c; + int encoders = 0, connectors = 0, crtcs = 0, planes = 0, framebuffers = 0; + int drop_master = 0; + int test_vsync = 0; + int test_cursor = 0; + int set_preferred = 0; + int use_atomic = 0; + char *device = NULL; + char *module = NULL; + unsigned int i; + unsigned int count = 0, plane_count = 0; + unsigned int prop_count = 0; + struct pipe_arg *pipe_args = NULL; + struct plane_arg *plane_args = NULL; + struct property_arg *prop_args = NULL; + unsigned int args = 0; + int ret; + + memset(&dev, 0, sizeof dev); + + opterr = 0; + while ((c = getopt(argc, argv, optstr)) != -1) { + args++; + + switch (c) { + case 'a': + use_atomic = 1; + /* Preserve the default behaviour of dumping all information. */ + args--; + break; + case 'c': + connectors = 1; + break; + case 'D': + device = optarg; + /* Preserve the default behaviour of dumping all information. */ + args--; + break; + case 'd': + drop_master = 1; + break; + case 'e': + encoders = 1; + break; + case 'f': + framebuffers = 1; + break; + case 'F': + parse_fill_patterns(optarg); + break; + case 'M': + module = optarg; + /* Preserve the default behaviour of dumping all information. */ + args--; + break; + case 'P': + plane_args = realloc(plane_args, + (plane_count + 1) * sizeof *plane_args); + if (plane_args == NULL) { + fprintf(stderr, "memory allocation failed\n"); + return 1; + } + memset(&plane_args[plane_count], 0, sizeof(*plane_args)); + + if (parse_plane(&plane_args[plane_count], optarg) < 0) + usage(argv[0]); + + plane_count++; + break; + case 'p': + crtcs = 1; + planes = 1; + break; + case 's': + pipe_args = realloc(pipe_args, + (count + 1) * sizeof *pipe_args); + if (pipe_args == NULL) { + fprintf(stderr, "memory allocation failed\n"); + return 1; + } + memset(&pipe_args[count], 0, sizeof(*pipe_args)); + + if (parse_connector(&pipe_args[count], optarg) < 0) + usage(argv[0]); + + count++; + break; + case 'C': + test_cursor = 1; + break; + case 'v': + test_vsync = 1; + break; + case 'r': + set_preferred = 1; + break; + case 'w': + prop_args = realloc(prop_args, + (prop_count + 1) * sizeof *prop_args); + if (prop_args == NULL) { + fprintf(stderr, "memory allocation failed\n"); + return 1; + } + memset(&prop_args[prop_count], 0, sizeof(*prop_args)); + + if (parse_property(&prop_args[prop_count], optarg) < 0) + usage(argv[0]); + + prop_count++; + break; + default: + usage(argv[0]); + break; + } + } + + /* Dump all the details when no* arguments are provided. */ + if (!args) + encoders = connectors = crtcs = planes = framebuffers = 1; + + if (test_vsync && !count) { + fprintf(stderr, "page flipping requires at least one -s option.\n"); + return -1; + } + if (set_preferred && count) { + fprintf(stderr, "cannot use -r (preferred) when -s (mode) is set\n"); + return -1; + } + + if (set_preferred && plane_count) { + fprintf(stderr, "cannot use -r (preferred) when -P (plane) is set\n"); + return -1; + } + + dev.fd = util_open(device, module); + if (dev.fd < 0) + return -1; + + if (use_atomic) { + ret = drmSetClientCap(dev.fd, DRM_CLIENT_CAP_ATOMIC, 1); + if (ret) { + fprintf(stderr, "no atomic modesetting support: %s\n", strerror(errno)); + drmClose(dev.fd); + return -1; + } + } + + dev.use_atomic = use_atomic; + + dev.resources = get_resources(&dev); + if (!dev.resources) { + drmClose(dev.fd); + return 1; + } + +#define dump_resource(dev, res) if (res) dump_##res(dev) + + dump_resource(&dev, encoders); + dump_resource(&dev, connectors); + dump_resource(&dev, crtcs); + dump_resource(&dev, planes); + dump_resource(&dev, framebuffers); + + for (i = 0; i < prop_count; ++i) + set_property(&dev, &prop_args[i]); + + if (dev.use_atomic) { + dev.req = drmModeAtomicAlloc(); + + if (set_preferred || (count && plane_count)) { + uint64_t cap = 0; + + ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap); + if (ret || cap == 0) { + fprintf(stderr, "driver doesn't support the dumb buffer API\n"); + return 1; + } + + if (set_preferred || count) + set_mode(&dev, pipe_args, count); + + if (plane_count) + atomic_set_planes(&dev, plane_args, plane_count, false); + + ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); + if (ret) { + fprintf(stderr, "Atomic Commit failed [1]\n"); + return 1; + } + + if (test_vsync) + atomic_test_page_flip(&dev, pipe_args, plane_args, plane_count); + + if (drop_master) + drmDropMaster(dev.fd); + + getchar(); + + drmModeAtomicFree(dev.req); + dev.req = drmModeAtomicAlloc(); + + /* XXX: properly teardown the preferred mode/plane state */ + if (plane_count) + atomic_clear_planes(&dev, plane_args, plane_count); + + if (count) + atomic_clear_mode(&dev, pipe_args, count); + + ret = drmModeAtomicCommit(dev.fd, dev.req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); + if (ret) + fprintf(stderr, "Atomic Commit failed\n"); + + if (plane_count) + atomic_clear_FB(&dev, plane_args, plane_count); + } + + drmModeAtomicFree(dev.req); + } else { + if (set_preferred || count || plane_count) { + uint64_t cap = 0; + + ret = drmGetCap(dev.fd, DRM_CAP_DUMB_BUFFER, &cap); + if (ret || cap == 0) { + fprintf(stderr, "driver doesn't support the dumb buffer API\n"); + return 1; + } + + if (set_preferred || count) + set_mode(&dev, pipe_args, count); + + if (plane_count) + set_planes(&dev, plane_args, plane_count); + + if (test_cursor) + set_cursors(&dev, pipe_args, count); + + if (test_vsync) + test_page_flip(&dev, pipe_args, count); + + if (drop_master) + drmDropMaster(dev.fd); + + getchar(); + + if (test_cursor) + clear_cursors(&dev); + + if (plane_count) + clear_planes(&dev, plane_args, plane_count); + + if (set_preferred || count) + clear_mode(&dev); + } + } + + free_resources(dev.resources); + drmClose(dev.fd); + + return 0; +} diff --git a/tests/nouveau/.gitignore b/tests/nouveau/.gitignore new file mode 100644 index 0000000..837bfb9 --- /dev/null +++ b/tests/nouveau/.gitignore @@ -0,0 +1 @@ +threaded diff --git a/tests/nouveau/meson.build b/tests/nouveau/meson.build new file mode 100644 index 0000000..ca4d44f --- /dev/null +++ b/tests/nouveau/meson.build @@ -0,0 +1,30 @@ +# Copyright © 2017 Intel Corporation + +# 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. + +threaded = executable( + 'threaded', + files('threaded.c'), + dependencies : [dep_dl, dep_threads], + include_directories : [inc_root, inc_drm, include_directories('../../nouveau')], + link_with : [libdrm, libdrm_nouveau], + c_args : libdrm_c_args, +) + +test('threaded', threaded) diff --git a/tests/nouveau/threaded.c b/tests/nouveau/threaded.c new file mode 100644 index 0000000..eaa469e --- /dev/null +++ b/tests/nouveau/threaded.c @@ -0,0 +1,156 @@ +/* + * Copyright © 2015 Canonical Ltd. (Maarten Lankhorst) + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "xf86drm.h" +#include "nouveau.h" + +static __typeof__(ioctl) *old_ioctl; +static int failed; + +static int import_fd; + +#if defined(__GLIBC__) || defined(__FreeBSD__) +int ioctl(int fd, unsigned long request, ...) +#else +int ioctl(int fd, int request, ...) +#endif +{ + va_list va; + int ret; + void *arg; + + va_start(va, request); + arg = va_arg(va, void *); + ret = old_ioctl(fd, request, arg); + va_end(va); + + if (ret < 0 && request == DRM_IOCTL_GEM_CLOSE && errno == EINVAL) + failed = 1; + + return ret; +} + +static void * +openclose(void *dev) +{ + struct nouveau_device *nvdev = dev; + struct nouveau_bo *bo = NULL; + int i; + + for (i = 0; i < 100000; ++i) { + if (!nouveau_bo_prime_handle_ref(nvdev, import_fd, &bo)) + nouveau_bo_ref(NULL, &bo); + } + return NULL; +} + +int main(int argc, char *argv[]) +{ + drmVersionPtr version; + const char *device = NULL; + int err, fd, fd2; + struct nouveau_device *nvdev, *nvdev2; + struct nouveau_bo *bo; + pthread_t t1, t2; + + old_ioctl = dlsym(RTLD_NEXT, "ioctl"); + + if (argc < 2) { + fd = drmOpenWithType("nouveau", NULL, DRM_NODE_RENDER); + if (fd >= 0) + fd2 = drmOpenWithType("nouveau", NULL, DRM_NODE_RENDER); + } else { + device = argv[1]; + + fd = open(device, O_RDWR); + if (fd >= 0) + fd2 = open(device, O_RDWR); + else + fd2 = fd = -errno; + } + + if (fd < 0) { + fprintf(stderr, "Opening nouveau render node failed with %i\n", fd); + return device ? -fd : 77; + } + + if (fd2 < 0) { + fprintf(stderr, "Opening second nouveau render node failed with %i\n", -errno); + return errno; + } + + version = drmGetVersion(fd); + if (version) { + printf("Version: %d.%d.%d\n", version->version_major, + version->version_minor, version->version_patchlevel); + printf(" Name: %s\n", version->name); + printf(" Date: %s\n", version->date); + printf(" Description: %s\n", version->desc); + + drmFreeVersion(version); + } + + err = nouveau_device_wrap(fd, 0, &nvdev); + if (!err) + err = nouveau_device_wrap(fd2, 0, &nvdev2); + if (err < 0) + return 1; + + err = nouveau_bo_new(nvdev2, NOUVEAU_BO_GART, 0, 4096, NULL, &bo); + if (!err) + err = nouveau_bo_set_prime(bo, &import_fd); + + if (!err) { + pthread_create(&t1, NULL, openclose, nvdev); + pthread_create(&t2, NULL, openclose, nvdev); + } + + pthread_join(t1, NULL); + pthread_join(t2, NULL); + + close(import_fd); + nouveau_bo_ref(NULL, &bo); + + nouveau_device_del(&nvdev2); + nouveau_device_del(&nvdev); + if (device) { + close(fd2); + close(fd); + } else { + drmClose(fd2); + drmClose(fd); + } + + if (failed) + fprintf(stderr, "DRM_IOCTL_GEM_CLOSE failed with EINVAL,\n" + "race in opening/closing bo is likely.\n"); + + return failed; +} diff --git a/tests/proptest/Android.mk b/tests/proptest/Android.mk new file mode 100644 index 0000000..91a590f --- /dev/null +++ b/tests/proptest/Android.mk @@ -0,0 +1,14 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +include $(LOCAL_PATH)/Makefile.sources + +LOCAL_SRC_FILES := $(PROPTEST_FILES) + +LOCAL_MODULE := proptest + +LOCAL_SHARED_LIBRARIES := libdrm +LOCAL_STATIC_LIBRARIES := libdrm_util + +include $(LIBDRM_COMMON_MK) +include $(BUILD_EXECUTABLE) diff --git a/tests/proptest/Makefile.sources b/tests/proptest/Makefile.sources new file mode 100644 index 0000000..446110d --- /dev/null +++ b/tests/proptest/Makefile.sources @@ -0,0 +1,2 @@ +PROPTEST_FILES := \ + proptest.c diff --git a/tests/proptest/meson.build b/tests/proptest/meson.build new file mode 100644 index 0000000..9c87965 --- /dev/null +++ b/tests/proptest/meson.build @@ -0,0 +1,28 @@ +# Copyright © 2017 Intel Corporation + +# 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. + +proptest = executable( + 'proptest', + files('proptest.c'), + c_args : libdrm_c_args, + include_directories : [inc_root, inc_tests, inc_drm], + link_with : [libdrm, libutil], + install : with_install_tests, +) diff --git a/tests/proptest/proptest.c b/tests/proptest/proptest.c new file mode 100644 index 0000000..97cb01f --- /dev/null +++ b/tests/proptest/proptest.c @@ -0,0 +1,325 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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 (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 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. + * + * Authors: + * Paulo Zanoni + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "xf86drm.h" +#include "xf86drmMode.h" + +#include "util/common.h" +#include "util/kms.h" + +static inline int64_t U642I64(uint64_t val) +{ + return (int64_t)*((int64_t *)&val); +} + +int fd; +drmModeResPtr res = NULL; + +/* dump_blob and dump_prop shamelessly copied from ../modetest/modetest.c */ +static void +dump_blob(uint32_t blob_id) +{ + uint32_t i; + unsigned char *blob_data; + drmModePropertyBlobPtr blob; + + blob = drmModeGetPropertyBlob(fd, blob_id); + if (!blob) { + printf("\n"); + return; + } + + blob_data = blob->data; + + for (i = 0; i < blob->length; i++) { + if (i % 16 == 0) + printf("\n\t\t\t"); + printf("%.2hhx", blob_data[i]); + } + printf("\n"); + + drmModeFreePropertyBlob(blob); +} + +static void +dump_prop(uint32_t prop_id, uint64_t value) +{ + int i; + drmModePropertyPtr prop; + + prop = drmModeGetProperty(fd, prop_id); + + printf("\t%d", prop_id); + if (!prop) { + printf("\n"); + return; + } + + printf(" %s:\n", prop->name); + + printf("\t\tflags:"); + if (prop->flags & DRM_MODE_PROP_PENDING) + printf(" pending"); + if (prop->flags & DRM_MODE_PROP_IMMUTABLE) + printf(" immutable"); + if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) + printf(" signed range"); + if (drm_property_type_is(prop, DRM_MODE_PROP_RANGE)) + printf(" range"); + if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM)) + printf(" enum"); + if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK)) + printf(" bitmask"); + if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) + printf(" blob"); + if (drm_property_type_is(prop, DRM_MODE_PROP_OBJECT)) + printf(" object"); + printf("\n"); + + + if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) { + printf("\t\tvalues:"); + for (i = 0; i < prop->count_values; i++) + printf(" %"PRId64, U642I64(prop->values[i])); + printf("\n"); + } + + if (drm_property_type_is(prop, DRM_MODE_PROP_RANGE)) { + printf("\t\tvalues:"); + for (i = 0; i < prop->count_values; i++) + printf(" %"PRIu64, prop->values[i]); + printf("\n"); + } + + if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM)) { + printf("\t\tenums:"); + for (i = 0; i < prop->count_enums; i++) + printf(" %s=%"PRIu64, prop->enums[i].name, + (uint64_t)prop->enums[i].value); + printf("\n"); + } else if (drm_property_type_is(prop, DRM_MODE_PROP_BITMASK)) { + printf("\t\tvalues:"); + for (i = 0; i < prop->count_enums; i++) + printf(" %s=0x%llx", prop->enums[i].name, + (1LL << prop->enums[i].value)); + printf("\n"); + } else { + assert(prop->count_enums == 0); + } + + if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) { + printf("\t\tblobs:\n"); + for (i = 0; i < prop->count_blobs; i++) + dump_blob(prop->blob_ids[i]); + printf("\n"); + } else { + assert(prop->count_blobs == 0); + } + + printf("\t\tvalue:"); + if (drm_property_type_is(prop, DRM_MODE_PROP_BLOB)) + dump_blob(value); + else if (drm_property_type_is(prop, DRM_MODE_PROP_SIGNED_RANGE)) + printf(" %"PRId64"\n", value); + else + printf(" %"PRIu64"\n", value); + + drmModeFreeProperty(prop); +} + +static void listObjectProperties(uint32_t id, uint32_t type) +{ + unsigned int i; + drmModeObjectPropertiesPtr props; + + props = drmModeObjectGetProperties(fd, id, type); + + if (!props) { + printf("\tNo properties: %s.\n", strerror(errno)); + return; + } + + for (i = 0; i < props->count_props; i++) + dump_prop(props->props[i], props->prop_values[i]); + + drmModeFreeObjectProperties(props); +} + +static void listConnectorProperties(void) +{ + int i; + drmModeConnectorPtr c; + + for (i = 0; i < res->count_connectors; i++) { + c = drmModeGetConnector(fd, res->connectors[i]); + + if (!c) { + fprintf(stderr, "Could not get connector %u: %s\n", + res->connectors[i], strerror(errno)); + continue; + } + + printf("Connector %u (%s-%u)\n", c->connector_id, + drmModeGetConnectorTypeName(c->connector_type), + c->connector_type_id); + + listObjectProperties(c->connector_id, + DRM_MODE_OBJECT_CONNECTOR); + + drmModeFreeConnector(c); + } +} + +static void listCrtcProperties(void) +{ + int i; + drmModeCrtcPtr c; + + for (i = 0; i < res->count_crtcs; i++) { + c = drmModeGetCrtc(fd, res->crtcs[i]); + + if (!c) { + fprintf(stderr, "Could not get crtc %u: %s\n", + res->crtcs[i], strerror(errno)); + continue; + } + + printf("CRTC %u\n", c->crtc_id); + + listObjectProperties(c->crtc_id, DRM_MODE_OBJECT_CRTC); + + drmModeFreeCrtc(c); + } +} + +static void listAllProperties(void) +{ + listConnectorProperties(); + listCrtcProperties(); +} + +static int setProperty(char *argv[]) +{ + uint32_t obj_id, obj_type, prop_id; + uint64_t value; + + obj_id = atoi(argv[0]); + + if (!strcmp(argv[1], "connector")) { + obj_type = DRM_MODE_OBJECT_CONNECTOR; + } else if (!strcmp(argv[1], "crtc")) { + obj_type = DRM_MODE_OBJECT_CRTC; + } else { + fprintf(stderr, "Invalid object type.\n"); + return 1; + } + + prop_id = atoi(argv[2]); + value = atoll(argv[3]); + + return drmModeObjectSetProperty(fd, obj_id, obj_type, prop_id, value); +} + +static void usage(const char *program) +{ + printf("Usage:\n" +" %s [options]\n" +" %s [options] [obj id] [obj type] [prop id] [value]\n" +"\n" +"options:\n" +" -D DEVICE use the given device\n" +" -M MODULE use the given driver\n" +"\n" +"The first form just prints all the existing properties. The second one is\n" +"used to set the value of a specified property. The object type can be one of\n" +"the following strings:\n" +" connector crtc\n" +"\n" +"Example:\n" +" proptest 7 connector 2 1\n" +"will set property 2 of connector 7 to 1\n", program, program); +} + +int main(int argc, char *argv[]) +{ + static const char optstr[] = "D:M:"; + int c, args, ret = 0; + char *device = NULL; + char *module = NULL; + + while ((c = getopt(argc, argv, optstr)) != -1) { + switch (c) { + case 'D': + device = optarg; + break; + + case 'M': + module = optarg; + break; + + default: + usage(argv[0]); + break; + } + } + + args = argc - optind; + + fd = util_open(device, module); + if (fd < 0) + return 1; + + res = drmModeGetResources(fd); + if (!res) { + fprintf(stderr, "Failed to get resources: %s\n", + strerror(errno)); + ret = 1; + goto done; + } + + if (args < 1) { + listAllProperties(); + } else if (args == 4) { + ret = setProperty(&argv[optind]); + } else { + usage(argv[0]); + ret = 1; + } + + drmModeFreeResources(res); +done: + drmClose(fd); + return ret; +} diff --git a/tests/radeon/meson.build b/tests/radeon/meson.build new file mode 100644 index 0000000..bb345b7 --- /dev/null +++ b/tests/radeon/meson.build @@ -0,0 +1,27 @@ +# Copyright © 2017 Intel Corporation + +# 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. + +radeon_ttm = executable( + 'radeon_ttm', + files('rbo.c', 'radeon_ttm.c'), + include_directories : [inc_root, inc_drm], + link_with : libdrm, + c_args : libdrm_c_args, +) diff --git a/tests/radeon/radeon_ttm.c b/tests/radeon/radeon_ttm.c new file mode 100644 index 0000000..8346e85 --- /dev/null +++ b/tests/radeon/radeon_ttm.c @@ -0,0 +1,77 @@ +/* + * Copyright © 2011 Red Hat + * + * 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 (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 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. + * + * Authors: + * Jerome Glisse + */ +#include +#include +#include +#include "rbo.h" +#include "xf86drm.h" + +/* allocate as many single page bo to try to starve the kernel + * memory zone (below highmem) + */ +static void ttm_starve_kernel_private_memory(int fd) +{ + struct list_head list; + struct rbo *bo, *tmp; + unsigned nbo = 0; + + printf("\n[%s]\n", __func__); + list_inithead(&list); + while (1) { + bo = rbo(fd, 0, 4096, 0, NULL); + if (bo == NULL) { + printf("failing after %d bo\n", nbo); + break; + } + nbo++; + list_add(&bo->list, &list); + } + LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &list, list) { + list_del(&bo->list); + rbo_decref(bo); + } +} + +static int radeon_open_fd(void) +{ + return drmOpen("radeon", NULL); +} + +int main(void) +{ + int radeonfd; + + radeonfd = radeon_open_fd(); + if (radeonfd < 0) { + fprintf(stderr, "failed to open radeon fd\n"); + return -1; + } + + ttm_starve_kernel_private_memory(radeonfd); + + close(radeonfd); + return 0; +} diff --git a/tests/radeon/rbo.c b/tests/radeon/rbo.c new file mode 100644 index 0000000..70a288c --- /dev/null +++ b/tests/radeon/rbo.c @@ -0,0 +1,171 @@ +/* + * Copyright © 2011 Red Hat + * + * 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 (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 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. + * + * Authors: + * Jerome Glisse + */ +#define _FILE_OFFSET_BITS 64 +#include +#include +#include +#include +#include +#include "xf86drm.h" +#include "radeon_drm.h" +#include "rbo.h" + +struct rbo *rbo(int fd, unsigned handle, unsigned size, + unsigned alignment, void *ptr) +{ + struct rbo *bo; + int r; + + bo = calloc(1, sizeof(*bo)); + if (bo == NULL) { + return NULL; + } + list_inithead(&bo->list); + bo->fd = fd; + bo->size = size; + bo->handle = handle; + bo->refcount = 1; + bo->alignment = alignment; + + if (handle) { + struct drm_gem_open open_arg; + + memset(&open_arg, 0, sizeof(open_arg)); + open_arg.name = handle; + r = drmIoctl(fd, DRM_IOCTL_GEM_OPEN, &open_arg); + if (r != 0) { + free(bo); + return NULL; + } + bo->handle = open_arg.handle; + } else { + struct drm_radeon_gem_create args; + + args.size = size; + args.alignment = alignment; + args.initial_domain = RADEON_GEM_DOMAIN_CPU; + args.flags = 0; + args.handle = 0; + r = drmCommandWriteRead(fd, DRM_RADEON_GEM_CREATE, + &args, sizeof(args)); + bo->handle = args.handle; + if (r) { + fprintf(stderr, "Failed to allocate :\n"); + fprintf(stderr, " size : %d bytes\n", size); + fprintf(stderr, " alignment : %d bytes\n", alignment); + free(bo); + return NULL; + } + } + if (ptr) { + if (rbo_map(bo)) { + fprintf(stderr, "%s failed to copy data into bo\n", __func__); + return rbo_decref(bo); + } + memcpy(bo->data, ptr, size); + rbo_unmap(bo); + } + return bo; +} + +int rbo_map(struct rbo *bo) +{ + struct drm_radeon_gem_mmap args; + void *ptr; + int r; + + if (bo->mapcount++ != 0) { + return 0; + } + /* Zero out args to make valgrind happy */ + memset(&args, 0, sizeof(args)); + args.handle = bo->handle; + args.offset = 0; + args.size = (uint64_t)bo->size; + r = drmCommandWriteRead(bo->fd, DRM_RADEON_GEM_MMAP, + &args, sizeof(args)); + if (r) { + fprintf(stderr, "error mapping %p 0x%08X (error = %d)\n", + bo, bo->handle, r); + return r; + } + ptr = mmap(0, args.size, PROT_READ|PROT_WRITE, MAP_SHARED, bo->fd, args.addr_ptr); + if (ptr == MAP_FAILED) { + fprintf(stderr, "%s failed to map bo\n", __func__); + return -errno; + } + bo->data = ptr; + return 0; +} + +void rbo_unmap(struct rbo *bo) +{ + if (--bo->mapcount > 0) { + return; + } + munmap(bo->data, bo->size); + bo->data = NULL; +} + +struct rbo *rbo_incref(struct rbo *bo) +{ + bo->refcount++; + return bo; +} + +struct rbo *rbo_decref(struct rbo *bo) +{ + struct drm_gem_close args; + + if (bo == NULL) + return NULL; + if (--bo->refcount > 0) { + return NULL; + } + + munmap(bo->data, bo->size); + memset(&args, 0, sizeof(args)); + args.handle = bo->handle; + drmIoctl(bo->fd, DRM_IOCTL_GEM_CLOSE, &args); + memset(bo, 0, sizeof(struct rbo)); + free(bo); + return NULL; +} + +int rbo_wait(struct rbo *bo) +{ + struct drm_radeon_gem_wait_idle args; + int ret; + + /* Zero out args to make valgrind happy */ + memset(&args, 0, sizeof(args)); + args.handle = bo->handle; + do { + ret = drmCommandWriteRead(bo->fd, DRM_RADEON_GEM_WAIT_IDLE, + &args, sizeof(args)); + } while (ret == -EBUSY); + return ret; +} diff --git a/tests/radeon/rbo.h b/tests/radeon/rbo.h new file mode 100644 index 0000000..9164091 --- /dev/null +++ b/tests/radeon/rbo.h @@ -0,0 +1,50 @@ +/* + * Copyright © 2011 Red Hat + * + * 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 (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 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. + * + * Authors: + * Jerome Glisse + */ +#ifndef RBO_H +#define RBO_H + +#include "util_double_list.h" + +struct rbo { + struct list_head list; + int fd; + unsigned refcount; + unsigned mapcount; + unsigned handle; + unsigned size; + unsigned alignment; + void *data; +}; + +struct rbo *rbo(int fd, unsigned handle, unsigned size, + unsigned alignment, void *ptr); +int rbo_map(struct rbo *bo); +void rbo_unmap(struct rbo *bo); +struct rbo *rbo_incref(struct rbo *bo); +struct rbo *rbo_decref(struct rbo *bo); +int rbo_wait(struct rbo *bo); + +#endif diff --git a/tests/tegra/.gitignore b/tests/tegra/.gitignore new file mode 100644 index 0000000..0db9e54 --- /dev/null +++ b/tests/tegra/.gitignore @@ -0,0 +1,2 @@ +tegra-gr2d-fill +tegra-openclose diff --git a/tests/tegra/drm-test-tegra.c b/tests/tegra/drm-test-tegra.c new file mode 100644 index 0000000..1a9fa89 --- /dev/null +++ b/tests/tegra/drm-test-tegra.c @@ -0,0 +1,147 @@ +/* + * Copyright © 2014 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include "drm-test-tegra.h" +#include "tegra.h" + +int drm_tegra_gr2d_open(struct drm_tegra *drm, struct drm_tegra_gr2d **gr2dp) +{ + struct drm_tegra_gr2d *gr2d; + int err; + + gr2d = calloc(1, sizeof(*gr2d)); + if (!gr2d) + return -ENOMEM; + + gr2d->drm = drm; + + err = drm_tegra_channel_open(drm, DRM_TEGRA_GR2D, &gr2d->channel); + if (err < 0) { + free(gr2d); + return err; + } + + *gr2dp = gr2d; + + return 0; +} + +int drm_tegra_gr2d_close(struct drm_tegra_gr2d *gr2d) +{ + if (!gr2d) + return -EINVAL; + + drm_tegra_channel_close(gr2d->channel); + free(gr2d); + + return 0; +} + +int drm_tegra_gr2d_fill(struct drm_tegra_gr2d *gr2d, struct drm_framebuffer *fb, + unsigned int x, unsigned int y, unsigned int width, + unsigned int height, uint32_t color) +{ + struct drm_tegra_bo *fbo = fb->data; + struct drm_tegra_pushbuf *pushbuf; + struct drm_tegra_mapping *map; + struct drm_tegra_job *job; + uint32_t *ptr; + int err; + + err = drm_tegra_job_new(gr2d->channel, &job); + if (err < 0) + return err; + + err = drm_tegra_channel_map(gr2d->channel, fbo, 0, &map); + if (err < 0) + return err; + + err = drm_tegra_job_get_pushbuf(job, &pushbuf); + if (err < 0) + return err; + + err = drm_tegra_pushbuf_begin(pushbuf, 32, &ptr); + if (err < 0) + return err; + + *ptr++ = HOST1X_OPCODE_SETCL(0, HOST1X_CLASS_GR2D, 0); + + *ptr++ = HOST1X_OPCODE_MASK(0x9, 0x9); + *ptr++ = 0x0000003a; + *ptr++ = 0x00000000; + + *ptr++ = HOST1X_OPCODE_MASK(0x1e, 0x7); + *ptr++ = 0x00000000; + *ptr++ = (2 << 16) | (1 << 6) | (1 << 2); + *ptr++ = 0x000000cc; + + *ptr++ = HOST1X_OPCODE_MASK(0x2b, 0x9); + + /* relocate destination buffer */ + err = drm_tegra_pushbuf_relocate(pushbuf, &ptr, map, 0, 0, 0); + if (err < 0) { + fprintf(stderr, "failed to relocate buffer object: %d\n", err); + return err; + } + + *ptr++ = fb->pitch; + + *ptr++ = HOST1X_OPCODE_NONINCR(0x35, 1); + *ptr++ = color; + + *ptr++ = HOST1X_OPCODE_NONINCR(0x46, 1); + *ptr++ = 0x00000000; + + *ptr++ = HOST1X_OPCODE_MASK(0x38, 0x5); + *ptr++ = height << 16 | width; + *ptr++ = y << 16 | x; + + err = drm_tegra_pushbuf_end(pushbuf, ptr); + if (err < 0) { + fprintf(stderr, "failed to update push buffer: %d\n", -err); + return err; + } + + err = drm_tegra_job_submit(job, NULL); + if (err < 0) { + fprintf(stderr, "failed to submit job: %d\n", err); + return err; + } + + err = drm_tegra_job_wait(job, 0); + if (err < 0) { + fprintf(stderr, "failed to wait for fence: %d\n", err); + return err; + } + + drm_tegra_channel_unmap(map); + drm_tegra_job_free(job); + + return 0; +} diff --git a/tests/tegra/drm-test-tegra.h b/tests/tegra/drm-test-tegra.h new file mode 100644 index 0000000..eefa954 --- /dev/null +++ b/tests/tegra/drm-test-tegra.h @@ -0,0 +1,55 @@ +/* + * Copyright © 2014 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 TEGRA_DRM_TEST_TEGRA_H +#define TEGRA_DRM_TEST_TEGRA_H + +#include "drm-test.h" +#include "tegra.h" + +#define HOST1X_OPCODE_SETCL(offset, classid, mask) \ + ((0x0 << 28) | (((offset) & 0xfff) << 16) | (((classid) & 0x3ff) << 6) | ((mask) & 0x3f)) +#define HOST1X_OPCODE_INCR(offset, count) \ + ((0x1 << 28) | (((offset) & 0xfff) << 16) | ((count) & 0xffff)) +#define HOST1X_OPCODE_NONINCR(offset, count) \ + ((0x2 << 28) | (((offset) & 0xfff) << 16) | ((count) & 0xffff)) +#define HOST1X_OPCODE_MASK(offset, mask) \ + ((0x3 << 28) | (((offset) & 0xfff) << 16) | ((mask) & 0xffff)) +#define HOST1X_OPCODE_IMM(offset, data) \ + ((0x4 << 28) | (((offset) & 0xfff) << 16) | ((data) & 0xffff)) +#define HOST1X_OPCODE_EXTEND(subop, value) \ + ((0xe << 28) | (((subop) & 0xf) << 24) | ((value) & 0xffffff)) + +#define HOST1X_CLASS_GR2D 0x51 + +struct drm_tegra_gr2d { + struct drm_tegra *drm; + struct drm_tegra_channel *channel; +}; + +int drm_tegra_gr2d_open(struct drm_tegra *drm, struct drm_tegra_gr2d **gr2dp); +int drm_tegra_gr2d_close(struct drm_tegra_gr2d *gr2d); +int drm_tegra_gr2d_fill(struct drm_tegra_gr2d *gr2d, struct drm_framebuffer *fb, + unsigned int x, unsigned int y, unsigned int width, + unsigned int height, uint32_t color); + +#endif diff --git a/tests/tegra/drm-test.c b/tests/tegra/drm-test.c new file mode 100644 index 0000000..b1ded9c --- /dev/null +++ b/tests/tegra/drm-test.c @@ -0,0 +1,248 @@ +/* + * Copyright © 2014 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "xf86drm.h" +#include "xf86drmMode.h" +#include "drm_fourcc.h" + +#include "drm-test.h" + +static int drm_screen_probe_connector(struct drm_screen *screen, + drmModeConnectorPtr connector) +{ + drmModeEncoderPtr encoder; + drmModeCrtcPtr crtc; + drmModeFBPtr fb; + + encoder = drmModeGetEncoder(screen->fd, connector->encoder_id); + if (!encoder) + return -ENODEV; + + crtc = drmModeGetCrtc(screen->fd, encoder->crtc_id); + if (!crtc) { + drmModeFreeEncoder(encoder); + return -ENODEV; + } + + screen->old_fb = crtc->buffer_id; + + fb = drmModeGetFB(screen->fd, crtc->buffer_id); + if (!fb) { + /* TODO: create new framebuffer */ + drmModeFreeEncoder(encoder); + drmModeFreeCrtc(crtc); + return -ENOSYS; + } + + screen->connector = connector->connector_id; + screen->old_fb = crtc->buffer_id; + screen->crtc = encoder->crtc_id; + /* TODO: check crtc->mode_valid */ + screen->mode = crtc->mode; + + screen->width = fb->width; + screen->height = fb->height; + screen->pitch = fb->pitch; + screen->depth = fb->depth; + screen->bpp = fb->bpp; + + drmModeFreeEncoder(encoder); + drmModeFreeCrtc(crtc); + drmModeFreeFB(fb); + + return 0; +} + +int drm_screen_open(struct drm_screen **screenp, int fd) +{ + drmModeConnectorPtr connector; + struct drm_screen *screen; + bool found = false; + drmModeResPtr res; + unsigned int i; + int err; + + if (!screenp || fd < 0) + return -EINVAL; + + screen = calloc(1, sizeof(*screen)); + if (!screen) + return -ENOMEM; + + screen->format = DRM_FORMAT_XRGB8888; + screen->fd = fd; + + res = drmModeGetResources(fd); + if (!res) { + free(screen); + return -ENOMEM; + } + + for (i = 0; i < (unsigned int)res->count_connectors; i++) { + connector = drmModeGetConnector(fd, res->connectors[i]); + if (!connector) + continue; + + if (connector->connection != DRM_MODE_CONNECTED) { + drmModeFreeConnector(connector); + continue; + } + + err = drm_screen_probe_connector(screen, connector); + if (err < 0) { + drmModeFreeConnector(connector); + continue; + } + + drmModeFreeConnector(connector); + found = true; + break; + } + + drmModeFreeResources(res); + + if (!found) { + free(screen); + return -ENODEV; + } + + *screenp = screen; + + return 0; +} + +int drm_screen_close(struct drm_screen *screen) +{ + int err; + + err = drmModeSetCrtc(screen->fd, screen->crtc, screen->old_fb, 0, 0, + &screen->connector, 1, &screen->mode); + if (err < 0) { + fprintf(stderr, "drmModeSetCrtc() failed: %m\n"); + return -errno; + } + + free(screen); + + return 0; +} + +int drm_framebuffer_new(struct drm_framebuffer **fbp, + struct drm_screen *screen, uint32_t handle, + unsigned int width, unsigned int height, + unsigned int pitch, uint32_t format, + void *data) +{ + struct drm_framebuffer *fb; + uint32_t handles[4]; + uint32_t pitches[4]; + uint32_t offsets[4]; + int err; + + fb = calloc(1, sizeof(*fb)); + if (!fb) + return -ENOMEM; + + fb->fd = screen->fd; + fb->width = width; + fb->height = height; + fb->pitch = pitch; + fb->format = format; + fb->data = data; + + handles[0] = handle; + pitches[0] = pitch; + offsets[0] = 0; + + err = drmModeAddFB2(screen->fd, width, height, format, handles, + pitches, offsets, &fb->handle, 0); + if (err < 0) + return -errno; + + *fbp = fb; + + return 0; +} + +int drm_framebuffer_free(struct drm_framebuffer *fb) +{ + int err; + + err = drmModeRmFB(fb->fd, fb->handle); + if (err < 0) + return -errno; + + free(fb); + + return 0; +} + +int drm_screen_set_framebuffer(struct drm_screen *screen, + struct drm_framebuffer *fb) +{ + int err; + + err = drmModeSetCrtc(screen->fd, screen->crtc, fb->handle, 0, 0, + &screen->connector, 1, &screen->mode); + if (err < 0) + return -errno; + + return 0; +} + +int drm_open(const char *path) +{ + int fd, err; + + fd = open(path, O_RDWR); + if (fd < 0) + return -errno; + + err = drmSetMaster(fd); + if (err < 0) { + close(fd); + return -errno; + } + + return fd; +} + +void drm_close(int fd) +{ + drmDropMaster(fd); + close(fd); +} diff --git a/tests/tegra/drm-test.h b/tests/tegra/drm-test.h new file mode 100644 index 0000000..f11aed4 --- /dev/null +++ b/tests/tegra/drm-test.h @@ -0,0 +1,72 @@ +/* + * Copyright © 2014 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 TEGRA_DRM_TEST_H +#define TEGRA_DRM_TEST_H + +#include +#include + +#include "xf86drmMode.h" + +struct drm_screen { + int fd; + + unsigned int width; + unsigned int height; + unsigned int pitch; + unsigned int depth; + unsigned int bpp; + + drmModeModeInfo mode; + uint32_t connector; + uint32_t old_fb; + uint32_t format; + uint32_t crtc; +}; + +struct drm_framebuffer { + unsigned int width; + unsigned int height; + unsigned int pitch; + uint32_t format; + uint32_t handle; + void *data; + int fd; +}; + +int drm_screen_open(struct drm_screen **screenp, int fd); +int drm_screen_close(struct drm_screen *screen); +int drm_screen_set_framebuffer(struct drm_screen *screen, + struct drm_framebuffer *fb); + +int drm_framebuffer_new(struct drm_framebuffer **fbp, + struct drm_screen *screen, uint32_t handle, + unsigned int width, unsigned int height, + unsigned int pitch, uint32_t format, + void *data); +int drm_framebuffer_free(struct drm_framebuffer *fb); + +int drm_open(const char *path); +void drm_close(int fd); + +#endif diff --git a/tests/tegra/gr2d-fill.c b/tests/tegra/gr2d-fill.c new file mode 100644 index 0000000..d138cc4 --- /dev/null +++ b/tests/tegra/gr2d-fill.c @@ -0,0 +1,146 @@ +/* + * Copyright © 2014 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "xf86drm.h" +#include "xf86drmMode.h" +#include "drm_fourcc.h" + +#include "drm-test-tegra.h" +#include "tegra.h" + +int main(int argc, char *argv[]) +{ + uint32_t format = DRM_FORMAT_XRGB8888; + struct drm_tegra_gr2d *gr2d; + struct drm_framebuffer *fb; + struct drm_screen *screen; + unsigned int pitch, size; + struct drm_tegra_bo *bo; + struct drm_tegra *drm; + uint32_t handle; + int fd, err; + void *ptr; + + fd = drm_open(argv[1]); + if (fd < 0) { + fprintf(stderr, "failed to open DRM device %s: %s\n", argv[1], + strerror(errno)); + return 1; + } + + err = drm_screen_open(&screen, fd); + if (err < 0) { + fprintf(stderr, "failed to open screen: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_new(fd, &drm); + if (err < 0) { + fprintf(stderr, "failed to create Tegra DRM context: %s\n", + strerror(-err)); + return 1; + } + + err = drm_tegra_gr2d_open(drm, &gr2d); + if (err < 0) { + fprintf(stderr, "failed to open gr2d channel: %s\n", + strerror(-err)); + return 1; + } + + pitch = screen->width * screen->bpp / 8; + size = pitch * screen->height; + + err = drm_tegra_bo_new(drm, 0, size, &bo); + if (err < 0) { + fprintf(stderr, "failed to create buffer object: %s\n", + strerror(-err)); + return 1; + } + + err = drm_tegra_bo_get_handle(bo, &handle); + if (err < 0) { + fprintf(stderr, "failed to get handle to buffer object: %s\n", + strerror(-err)); + return 1; + } + + err = drm_tegra_bo_map(bo, &ptr); + if (err < 0) { + fprintf(stderr, "failed to map buffer object: %s\n", + strerror(-err)); + return 1; + } + + memset(ptr, 0xff, size); + + err = drm_framebuffer_new(&fb, screen, handle, screen->width, + screen->height, pitch, format, bo); + if (err < 0) { + fprintf(stderr, "failed to create framebuffer: %s\n", + strerror(-err)); + return 1; + } + + err = drm_screen_set_framebuffer(screen, fb); + if (err < 0) { + fprintf(stderr, "failed to display framebuffer: %s\n", + strerror(-err)); + return 1; + } + + sleep(1); + + err = drm_tegra_gr2d_fill(gr2d, fb, fb->width / 4, fb->height / 4, + fb->width / 2, fb->height / 2, 0x00000000); + if (err < 0) { + fprintf(stderr, "failed to fill rectangle: %s\n", + strerror(-err)); + return 1; + } + + sleep(1); + + drm_framebuffer_free(fb); + drm_tegra_bo_unref(bo); + drm_tegra_gr2d_close(gr2d); + drm_tegra_close(drm); + drm_screen_close(screen); + drm_close(fd); + + return 0; +} diff --git a/tests/tegra/host1x.h b/tests/tegra/host1x.h new file mode 100644 index 0000000..902b0c1 --- /dev/null +++ b/tests/tegra/host1x.h @@ -0,0 +1,34 @@ +/* + * Copyright © 2018 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 HOST1X_H +#define HOST1X_H + +#define HOST1X_OPCODE_SETCL(offset, classid, mask) \ + ((0x0 << 28) | (((offset) & 0xfff) << 16) | (((classid) & 0x3ff) << 6) | ((mask) & 0x3f)) + +#define HOST1X_OPCODE_INCR(offset, count) \ + ((0x1 << 28) | (((offset) & 0xfff) << 16) | ((count) & 0xffff)) + +#define HOST1X_CLASS_VIC 0x5d + +#endif diff --git a/tests/tegra/meson.build b/tests/tegra/meson.build new file mode 100644 index 0000000..26a32e8 --- /dev/null +++ b/tests/tegra/meson.build @@ -0,0 +1,111 @@ +# Copyright © 2017 Intel Corporation + +# 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. + +inc_tegra = include_directories('../../tegra') + +libdrm_test = static_library( + 'drm-test', + [files('drm-test.c', 'drm-test.h'), config_file ], + include_directories : [inc_root, inc_drm, inc_tegra], + link_with : libdrm, +) + +libdrm_test_tegra = static_library( + 'drm-test-tegra', + [files( + 'drm-test-tegra.c', + 'drm-test-tegra.h', + 'vic.c', + 'vic.h', + 'vic30.c', + 'vic30.h', + 'vic40.c', + 'vic40.h', + 'vic41.c', + 'vic41.h', + 'vic42.c', + 'vic42.h', + ), config_file ], + include_directories : [inc_root, inc_drm, inc_tegra], + link_with : libdrm, +) + +openclose = executable( + 'tegra-openclose', + files('openclose.c'), + include_directories : [inc_root, inc_drm, inc_tegra], + c_args : libdrm_c_args, + link_with : [libdrm, libdrm_tegra], + install : with_install_tests, +) + +gr2d_fill = executable( + 'tegra-gr2d-fill', + files('gr2d-fill.c'), + include_directories : [inc_root, inc_drm, inc_tegra], + c_args : libdrm_c_args, + link_with : [libdrm, libdrm_tegra, libdrm_test, libdrm_test_tegra], + install : with_install_tests, +) + +syncpt_wait = executable( + 'tegra-syncpt-wait', + files('syncpt-wait.c'), + include_directories : [inc_root, inc_drm, inc_tegra], + c_args : libdrm_c_args, + link_with : [libdrm, libdrm_tegra, libdrm_test, libdrm_test_tegra], + install : with_install_tests, +) + +syncpt_timeout = executable( + 'tegra-syncpt-timeout', + files('syncpt-timeout.c'), + include_directories : [inc_root, inc_drm, inc_tegra], + c_args : libdrm_c_args, + link_with : [libdrm, libdrm_tegra, libdrm_test, libdrm_test_tegra], + install : with_install_tests, +) + +vic_clear = executable( + 'tegra-vic-clear', + files('vic-clear.c'), + include_directories : [inc_root, inc_drm, inc_tegra], + c_args : libdrm_c_args, + link_with : [libdrm, libdrm_tegra, libdrm_test, libdrm_test_tegra], + install : with_install_tests, +) + +vic_blit = executable( + 'tegra-vic-blit', + files('vic-blit.c'), + include_directories : [inc_root, inc_drm, inc_tegra], + c_args : libdrm_c_args, + link_with : [libdrm, libdrm_tegra, libdrm_test, libdrm_test_tegra], + install : with_install_tests, +) + +vic_flip = executable( + 'tegra-vic-flip', + files('vic-flip.c'), + include_directories : [inc_root, inc_drm, inc_tegra], + c_args : libdrm_c_args, + link_with : [libdrm, libdrm_tegra, libdrm_test, libdrm_test_tegra], + install : with_install_tests, +) diff --git a/tests/tegra/openclose.c b/tests/tegra/openclose.c new file mode 100644 index 0000000..61dbc2b --- /dev/null +++ b/tests/tegra/openclose.c @@ -0,0 +1,67 @@ +/* + * Copyright © 2014 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#include +#include +#include + +#include "xf86drm.h" +#include "tegra.h" + +static const char default_device[] = "/dev/dri/card0"; + +int main(int argc, char *argv[]) +{ + struct drm_tegra *tegra; + drmVersionPtr version; + const char *device; + int err, fd; + + if (argc < 2) + device = default_device; + else + device = argv[1]; + + fd = open(device, O_RDWR); + if (fd < 0) + return 1; + + version = drmGetVersion(fd); + if (version) { + printf("Version: %d.%d.%d\n", version->version_major, + version->version_minor, version->version_patchlevel); + printf(" Name: %s\n", version->name); + printf(" Date: %s\n", version->date); + printf(" Description: %s\n", version->desc); + + drmFreeVersion(version); + } + + err = drm_tegra_new(fd, &tegra); + if (err < 0) + return 1; + + drm_tegra_close(tegra); + close(fd); + + return 0; +} diff --git a/tests/tegra/syncpt-timeout.c b/tests/tegra/syncpt-timeout.c new file mode 100644 index 0000000..fea3665 --- /dev/null +++ b/tests/tegra/syncpt-timeout.c @@ -0,0 +1,163 @@ +/* + * Copyright © 2018 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#include +#include +#include +#include +#include + +#include "tegra.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +static int channel_open(struct drm_tegra *drm, + struct drm_tegra_channel **channel) +{ + static const struct { + enum drm_tegra_class class; + const char *name; + } classes[] = { + { DRM_TEGRA_VIC, "VIC" }, + { DRM_TEGRA_GR2D, "GR2D" }, + }; + unsigned int i; + int err; + + for (i = 0; i < ARRAY_SIZE(classes); i++) { + err = drm_tegra_channel_open(drm, classes[i].class, channel); + if (err < 0) { + fprintf(stderr, "failed to open channel to %s: %s\n", + classes[i].name, strerror(-err)); + continue; + } + + break; + } + + return err; +} + +int main(int argc, char *argv[]) +{ + const char *device = "/dev/dri/renderD128"; + struct drm_tegra_syncpoint *syncpt; + struct drm_tegra_channel *channel; + struct drm_tegra_pushbuf *pushbuf; + struct drm_tegra_job *job; + struct drm_tegra *drm; + uint32_t *ptr; + int fd, err; + + if (argc > 1) + device = argv[1]; + + fd = open(device, O_RDWR); + if (fd < 0) { + fprintf(stderr, "open() failed: %s\n", strerror(errno)); + return 1; + } + + err = drm_tegra_new(fd, &drm); + if (err < 0) { + fprintf(stderr, "failed to open Tegra device: %s\n", strerror(-err)); + close(fd); + return 1; + } + + err = drm_tegra_syncpoint_new(drm, &syncpt); + if (err < 0) { + fprintf(stderr, "failed to allocate syncpoint: %s\n", strerror(-err)); + drm_tegra_close(drm); + close(fd); + return 1; + } + + err = channel_open(drm, &channel); + if (err < 0) { + fprintf(stderr, "failed to open channel: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_job_new(channel, &job); + if (err < 0) { + fprintf(stderr, "failed to create job: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_job_get_pushbuf(job, &pushbuf); + if (err < 0) { + fprintf(stderr, "failed to create push buffer: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_pushbuf_begin(pushbuf, 8, &ptr); + if (err < 0) { + fprintf(stderr, "failed to prepare push buffer: %s\n", strerror(-err)); + return 1; + } + + /* + * Empty command streams will be rejected, so we use this as an easy way + * to add something to the command stream. But this could be any other, + * valid command stream. + */ + err = drm_tegra_pushbuf_sync_cond(pushbuf, &ptr, syncpt, + DRM_TEGRA_SYNC_COND_IMMEDIATE); + if (err < 0) { + fprintf(stderr, "failed to push syncpoint: %s\n", strerror(-err)); + return 1; + } + + /* pretend that the syncpoint was incremented a second time */ + err = drm_tegra_pushbuf_sync(pushbuf, syncpt, 1); + if (err < 0) { + fprintf(stderr, "failed to push syncpoint: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_pushbuf_end(pushbuf, ptr); + if (err < 0) { + fprintf(stderr, "failed to update push buffer: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_job_submit(job, NULL); + if (err < 0) { + fprintf(stderr, "failed to submit job: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_job_wait(job, 250000); + if (err < 0) { + fprintf(stderr, "failed to wait for job: %s\n", strerror(-err)); + return 1; + } + + drm_tegra_job_free(job); + drm_tegra_channel_close(channel); + drm_tegra_syncpoint_free(syncpt); + drm_tegra_close(drm); + close(fd); + + return 0; +} diff --git a/tests/tegra/syncpt-wait.c b/tests/tegra/syncpt-wait.c new file mode 100644 index 0000000..f181174 --- /dev/null +++ b/tests/tegra/syncpt-wait.c @@ -0,0 +1,151 @@ +/* + * Copyright © 2018 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#include +#include +#include +#include +#include + +#include "tegra.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +static int channel_open(struct drm_tegra *drm, + struct drm_tegra_channel **channel) +{ + static const struct { + enum drm_tegra_class class; + const char *name; + } classes[] = { + { DRM_TEGRA_VIC, "VIC" }, + { DRM_TEGRA_GR2D, "GR2D" }, + }; + unsigned int i; + int err; + + for (i = 0; i < ARRAY_SIZE(classes); i++) { + err = drm_tegra_channel_open(drm, classes[i].class, channel); + if (err < 0) { + fprintf(stderr, "failed to open channel to %s: %s\n", + classes[i].name, strerror(-err)); + continue; + } + + break; + } + + return err; +} + +int main(int argc, char *argv[]) +{ + const char *device = "/dev/dri/renderD128"; + struct drm_tegra_syncpoint *syncpt; + struct drm_tegra_channel *channel; + struct drm_tegra_pushbuf *pushbuf; + struct drm_tegra_job *job; + struct drm_tegra *drm; + uint32_t *ptr; + int fd, err; + + if (argc > 1) + device = argv[1]; + + fd = open(device, O_RDWR); + if (fd < 0) { + fprintf(stderr, "open() failed: %s\n", strerror(errno)); + return 1; + } + + err = drm_tegra_new(fd, &drm); + if (err < 0) { + fprintf(stderr, "failed to open Tegra device: %s\n", strerror(-err)); + close(fd); + return 1; + } + + err = drm_tegra_syncpoint_new(drm, &syncpt); + if (err < 0) { + fprintf(stderr, "failed to allocate syncpoint: %s\n", strerror(-err)); + drm_tegra_close(drm); + close(fd); + return 1; + } + + err = channel_open(drm, &channel); + if (err < 0) { + fprintf(stderr, "failed to open channel: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_job_new(channel, &job); + if (err < 0) { + fprintf(stderr, "failed to create job: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_job_get_pushbuf(job, &pushbuf); + if (err < 0) { + fprintf(stderr, "failed to create push buffer: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_pushbuf_begin(pushbuf, 4, &ptr); + if (err < 0) { + fprintf(stderr, "failed to prepare push buffer: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_pushbuf_sync_cond(pushbuf, &ptr, syncpt, + DRM_TEGRA_SYNC_COND_IMMEDIATE); + if (err < 0) { + fprintf(stderr, "failed to push syncpoint: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_pushbuf_end(pushbuf, ptr); + if (err < 0) { + fprintf(stderr, "failed to update push buffer: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_job_submit(job, NULL); + if (err < 0) { + fprintf(stderr, "failed to submit job: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_job_wait(job, 250000000); + if (err < 0) { + fprintf(stderr, "failed to wait for job: %s\n", strerror(-err)); + return 1; + } + + drm_tegra_job_free(job); + drm_tegra_channel_close(channel); + drm_tegra_syncpoint_free(syncpt); + drm_tegra_close(drm); + close(fd); + + return 0; +} diff --git a/tests/tegra/vic-blit.c b/tests/tegra/vic-blit.c new file mode 100644 index 0000000..7baf9e7 --- /dev/null +++ b/tests/tegra/vic-blit.c @@ -0,0 +1,333 @@ +/* + * Copyright © 2018 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#include +#include +#include +#include +#include + +#include "tegra.h" + +#include "host1x.h" +#include "vic.h" + +/* clear output image to red */ +static int clear(struct vic *vic, struct drm_tegra_channel *channel, + struct vic_image *output) +{ + struct drm_tegra_pushbuf *pushbuf; + struct drm_tegra_job *job; + uint32_t *ptr; + int err; + + err = drm_tegra_job_new(channel, &job); + if (err < 0) { + fprintf(stderr, "failed to create job: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_job_get_pushbuf(job, &pushbuf); + if (err < 0) { + fprintf(stderr, "failed to create push buffer: %s\n", strerror(-err)); + return 1; + } + + err = vic_clear(vic, output, 1023, 1023, 0, 0); + if (err < 0) { + fprintf(stderr, "failed to clear surface: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_pushbuf_begin(pushbuf, 32, &ptr); + if (err < 0) { + fprintf(stderr, "failed to prepare push buffer: %s\n", strerror(-err)); + return err; + } + + err = vic->ops->execute(vic, pushbuf, &ptr, output, NULL, 0); + if (err < 0) { + fprintf(stderr, "failed to execute operation: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_pushbuf_sync_cond(pushbuf, &ptr, vic->syncpt, + DRM_TEGRA_SYNC_COND_OP_DONE); + if (err < 0) { + fprintf(stderr, "failed to push syncpoint: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_pushbuf_end(pushbuf, ptr); + if (err < 0) { + fprintf(stderr, "failed to update push buffer: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_job_submit(job, NULL); + if (err < 0) { + fprintf(stderr, "failed to submit job: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_job_wait(job, 1000000000); + if (err < 0) { + fprintf(stderr, "failed to wait for job: %s\n", strerror(-err)); + return err; + } + + drm_tegra_job_free(job); + + return 0; +} + +/* fill bottom half of image to blue */ +static int fill(struct vic *vic, struct drm_tegra_channel *channel, + struct vic_image *output) +{ + struct drm_tegra_pushbuf *pushbuf; + struct drm_tegra_job *job; + uint32_t *ptr; + int err; + + err = drm_tegra_job_new(channel, &job); + if (err < 0) { + fprintf(stderr, "failed to create job: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_job_get_pushbuf(job, &pushbuf); + if (err < 0) { + fprintf(stderr, "failed to create push buffer: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_pushbuf_begin(pushbuf, 32, &ptr); + if (err < 0) { + fprintf(stderr, "failed to prepare push buffer: %s\n", strerror(-err)); + return err; + } + + err = vic->ops->fill(vic, output, 0, output->height / 2, output->width - 1, + output->height -1, 1023, 0, 0, 1023); + if (err < 0) { + fprintf(stderr, "failed to fill surface: %s\n", strerror(-err)); + return err; + } + + err = vic->ops->execute(vic, pushbuf, &ptr, output, NULL, 0); + if (err < 0) { + fprintf(stderr, "failed to execute operation: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_pushbuf_sync_cond(pushbuf, &ptr, vic->syncpt, + DRM_TEGRA_SYNC_COND_OP_DONE); + if (err < 0) { + fprintf(stderr, "failed to push syncpoint: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_pushbuf_end(pushbuf, ptr); + if (err < 0) { + fprintf(stderr, "failed to update push buffer: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_job_submit(job, NULL); + if (err < 0) { + fprintf(stderr, "failed to submit job: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_job_wait(job, 1000000000); + if (err < 0) { + fprintf(stderr, "failed to wait for job: %s\n", strerror(-err)); + return err; + } + + drm_tegra_job_free(job); + + return 0; +} + +/* blit image */ +static int blit(struct vic *vic, struct drm_tegra_channel *channel, + struct vic_image *output, struct vic_image *input) +{ + struct drm_tegra_pushbuf *pushbuf; + struct drm_tegra_job *job; + uint32_t *ptr; + int err; + + err = drm_tegra_job_new(channel, &job); + if (err < 0) { + fprintf(stderr, "failed to create job: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_job_get_pushbuf(job, &pushbuf); + if (err < 0) { + fprintf(stderr, "failed to create push buffer: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_pushbuf_begin(pushbuf, 32, &ptr); + if (err < 0) { + fprintf(stderr, "failed to prepare push buffer: %s\n", strerror(-err)); + return err; + } + + err = vic->ops->blit(vic, output, input); + if (err < 0) { + fprintf(stderr, "failed to blit surface: %s\n", strerror(-err)); + return err; + } + + err = vic->ops->execute(vic, pushbuf, &ptr, output, &input, 1); + if (err < 0) { + fprintf(stderr, "failed to execute operation: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_pushbuf_sync_cond(pushbuf, &ptr, vic->syncpt, + DRM_TEGRA_SYNC_COND_OP_DONE); + if (err < 0) { + fprintf(stderr, "failed to push syncpoint: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_pushbuf_end(pushbuf, ptr); + if (err < 0) { + fprintf(stderr, "failed to update push buffer: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_job_submit(job, NULL); + if (err < 0) { + fprintf(stderr, "failed to submit job: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_job_wait(job, 1000000000); + if (err < 0) { + fprintf(stderr, "failed to wait for job: %s\n", strerror(-err)); + return err; + } + + drm_tegra_job_free(job); + + return 0; +} + +int main(int argc, char *argv[]) +{ + const unsigned int format = VIC_PIXEL_FORMAT_A8R8G8B8; + const unsigned int kind = VIC_BLK_KIND_PITCH; + const unsigned int width = 16, height = 16; + const char *device = "/dev/dri/renderD128"; + struct drm_tegra_channel *channel; + struct vic_image *input, *output; + struct drm_tegra *drm; + unsigned int version; + struct vic *vic; + int fd, err; + + if (argc > 1) + device = argv[1]; + + fd = open(device, O_RDWR); + if (fd < 0) { + fprintf(stderr, "open() failed: %s\n", strerror(errno)); + return 1; + } + + err = drm_tegra_new(fd, &drm); + if (err < 0) { + fprintf(stderr, "failed to open Tegra device: %s\n", strerror(-err)); + close(fd); + return 1; + } + + err = drm_tegra_channel_open(drm, DRM_TEGRA_VIC, &channel); + if (err < 0) { + fprintf(stderr, "failed to open channel to VIC: %s\n", strerror(-err)); + return 1; + } + + version = drm_tegra_channel_get_version(channel); + printf("version: %08x\n", version); + + err = vic_new(drm, channel, &vic); + if (err < 0) { + fprintf(stderr, "failed to create VIC: %s\n", strerror(-err)); + return 1; + } + + err = vic_image_new(vic, width, height, format, kind, DRM_TEGRA_CHANNEL_MAP_READ_WRITE, + &input); + if (err < 0) { + fprintf(stderr, "failed to create input image: %d\n", err); + return 1; + } + + err = vic_image_new(vic, width, height, format, kind, DRM_TEGRA_CHANNEL_MAP_READ_WRITE, + &output); + if (err < 0) { + fprintf(stderr, "failed to create output image: %d\n", err); + return 1; + } + + err = clear(vic, channel, input); + if (err < 0) { + fprintf(stderr, "failed to clear image: %s\n", strerror(-err)); + return 1; + } + + err = fill(vic, channel, input); + if (err < 0) { + fprintf(stderr, "failed to fill rectangle: %s\n", strerror(-err)); + return 1; + } + + err = blit(vic, channel, output, input); + if (err < 0) { + fprintf(stderr, "failed to blit image: %s\n", strerror(-err)); + return 1; + } + + printf("input: %ux%u\n", input->width, input->height); + vic_image_dump(input, stdout); + + printf("output: %ux%u\n", output->width, output->height); + vic_image_dump(output, stdout); + + vic_image_free(output); + vic_image_free(input); + + vic_free(vic); + drm_tegra_channel_close(channel); + drm_tegra_close(drm); + close(fd); + + return 0; +} diff --git a/tests/tegra/vic-clear.c b/tests/tegra/vic-clear.c new file mode 100644 index 0000000..da72782 --- /dev/null +++ b/tests/tegra/vic-clear.c @@ -0,0 +1,173 @@ +/* + * Copyright © 2018 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#include +#include +#include +#include +#include + +#include "util_math.h" + +#include "tegra.h" + +#include "host1x.h" +#include "vic.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +int main(int argc, char *argv[]) +{ + const unsigned int format = VIC_PIXEL_FORMAT_A8R8G8B8; + const unsigned int kind = VIC_BLK_KIND_PITCH; + const unsigned int width = 16, height = 16; + const char *device = "/dev/dri/renderD128"; + struct drm_tegra_channel *channel; + struct drm_tegra_pushbuf *pushbuf; + struct drm_tegra_job *job; + struct vic_image *output; + struct drm_tegra *drm; + unsigned int version; + struct vic *vic; + uint32_t *pb; + int fd, err; + void *ptr; + + if (argc > 1) + device = argv[1]; + + fd = open(device, O_RDWR); + if (fd < 0) { + fprintf(stderr, "open() failed: %s\n", strerror(errno)); + return 1; + } + + err = drm_tegra_new(fd, &drm); + if (err < 0) { + fprintf(stderr, "failed to open Tegra device: %s\n", strerror(-err)); + close(fd); + return 1; + } + + err = drm_tegra_channel_open(drm, DRM_TEGRA_VIC, &channel); + if (err < 0) { + fprintf(stderr, "failed to open channel to VIC: %s\n", strerror(-err)); + return 1; + } + + version = drm_tegra_channel_get_version(channel); + printf("version: %08x\n", version); + + err = vic_new(drm, channel, &vic); + if (err < 0) { + fprintf(stderr, "failed to create VIC: %s\n", strerror(-err)); + return 1; + } + + err = vic_image_new(vic, width, height, format, kind, DRM_TEGRA_CHANNEL_MAP_READ_WRITE, + &output); + if (err < 0) { + fprintf(stderr, "failed to create output image: %d\n", err); + return 1; + } + + printf("image: %zu bytes\n", output->size); + + err = drm_tegra_bo_map(output->bo, &ptr); + if (err < 0) { + fprintf(stderr, "failed to map output image: %d\n", err); + return 1; + } + + memset(ptr, 0xff, output->size); + drm_tegra_bo_unmap(output->bo); + + printf("output: %ux%u\n", output->width, output->height); + vic_image_dump(output, stdout); + + err = drm_tegra_job_new(channel, &job); + if (err < 0) { + fprintf(stderr, "failed to create job: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_job_get_pushbuf(job, &pushbuf); + if (err < 0) { + fprintf(stderr, "failed to create push buffer: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_pushbuf_begin(pushbuf, 32, &pb); + if (err < 0) { + fprintf(stderr, "failed to prepare push buffer: %s\n", strerror(-err)); + return 1; + } + + err = vic_clear(vic, output, 1023, 0, 0, 1023); + if (err < 0) { + fprintf(stderr, "failed to clear surface: %s\n", strerror(-err)); + return err; + } + + err = vic->ops->execute(vic, pushbuf, &pb, output, NULL, 0); + if (err < 0) { + fprintf(stderr, "failed to execute operation: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_pushbuf_sync_cond(pushbuf, &pb, vic->syncpt, + DRM_TEGRA_SYNC_COND_OP_DONE); + if (err < 0) { + fprintf(stderr, "failed to push syncpoint: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_pushbuf_end(pushbuf, pb); + if (err < 0) { + fprintf(stderr, "failed to update push buffer: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_job_submit(job, NULL); + if (err < 0) { + fprintf(stderr, "failed to submit job: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_job_wait(job, 1000000000); + if (err < 0) { + fprintf(stderr, "failed to wait for job: %s\n", strerror(-err)); + return 1; + } + + printf("output: %ux%u\n", output->width, output->height); + vic_image_dump(output, stdout); + + drm_tegra_job_free(job); + vic_image_free(output); + vic_free(vic); + drm_tegra_channel_close(channel); + drm_tegra_close(drm); + close(fd); + + return 0; +} diff --git a/tests/tegra/vic-flip.c b/tests/tegra/vic-flip.c new file mode 100644 index 0000000..e94336b --- /dev/null +++ b/tests/tegra/vic-flip.c @@ -0,0 +1,333 @@ +/* + * Copyright © 2018 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#include +#include +#include +#include +#include + +#include "tegra.h" + +#include "host1x.h" +#include "vic.h" + +/* clear output image to red */ +static int clear(struct vic *vic, struct drm_tegra_channel *channel, + struct vic_image *output) +{ + struct drm_tegra_pushbuf *pushbuf; + struct drm_tegra_job *job; + uint32_t *ptr; + int err; + + err = drm_tegra_job_new(channel, &job); + if (err < 0) { + fprintf(stderr, "failed to create job: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_job_get_pushbuf(job, &pushbuf); + if (err < 0) { + fprintf(stderr, "failed to create push buffer: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_pushbuf_begin(pushbuf, 32, &ptr); + if (err < 0) { + fprintf(stderr, "failed to prepare push buffer: %s\n", strerror(-err)); + return err; + } + + err = vic_clear(vic, output, 1023, 0, 0, 1023); + if (err < 0) { + fprintf(stderr, "failed to clear surface: %s\n", strerror(-err)); + return err; + } + + err = vic->ops->execute(vic, pushbuf, &ptr, output, NULL, 0); + if (err < 0) { + fprintf(stderr, "failed to execute operation: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_pushbuf_sync_cond(pushbuf, &ptr, vic->syncpt, + DRM_TEGRA_SYNC_COND_OP_DONE); + if (err < 0) { + fprintf(stderr, "failed to push syncpoint: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_pushbuf_end(pushbuf, ptr); + if (err < 0) { + fprintf(stderr, "failed to update push buffer: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_job_submit(job, NULL); + if (err < 0) { + fprintf(stderr, "failed to submit job: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_job_wait(job, 1000000000); + if (err < 0) { + fprintf(stderr, "failed to wait for job: %s\n", strerror(-err)); + return err; + } + + drm_tegra_job_free(job); + + return 0; +} + +/* fill bottom half of image to blue */ +static int fill(struct vic *vic, struct drm_tegra_channel *channel, + struct vic_image *output) +{ + struct drm_tegra_pushbuf *pushbuf; + struct drm_tegra_job *job; + uint32_t *ptr; + int err; + + err = drm_tegra_job_new(channel, &job); + if (err < 0) { + fprintf(stderr, "failed to create job: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_job_get_pushbuf(job, &pushbuf); + if (err < 0) { + fprintf(stderr, "failed to create push buffer: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_pushbuf_begin(pushbuf, 32, &ptr); + if (err < 0) { + fprintf(stderr, "failed to prepare push buffer: %s\n", strerror(-err)); + return err; + } + + err = vic->ops->fill(vic, output, 0, output->height / 2, output->width - 1, + output->height - 1, 0, 0, 1023, 1023); + if (err < 0) { + fprintf(stderr, "failed ot fill surface: %s\n", strerror(-err)); + return err; + } + + err = vic->ops->execute(vic, pushbuf, &ptr, output, NULL, 0); + if (err < 0) { + fprintf(stderr, "failed to execute operation: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_pushbuf_sync_cond(pushbuf, &ptr, vic->syncpt, + DRM_TEGRA_SYNC_COND_OP_DONE); + if (err < 0) { + fprintf(stderr, "failed to push syncpoint: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_pushbuf_end(pushbuf, ptr); + if (err < 0) { + fprintf(stderr, "failed to update push buffer: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_job_submit(job, NULL); + if (err < 0) { + fprintf(stderr, "failed to submit job: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_job_wait(job, 1000000000); + if (err < 0) { + fprintf(stderr, "failed to wait for job: %s\n", strerror(-err)); + return err; + } + + drm_tegra_job_free(job); + + return 0; +} + +/* flip image vertically */ +static int flip(struct vic *vic, struct drm_tegra_channel *channel, + struct vic_image *output, struct vic_image *input) +{ + struct drm_tegra_pushbuf *pushbuf; + struct drm_tegra_job *job; + uint32_t *ptr; + int err; + + err = drm_tegra_job_new(channel, &job); + if (err < 0) { + fprintf(stderr, "failed to create job: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_job_get_pushbuf(job, &pushbuf); + if (err < 0) { + fprintf(stderr, "failed to create push buffer: %s\n", strerror(-err)); + return 1; + } + + err = drm_tegra_pushbuf_begin(pushbuf, 32, &ptr); + if (err < 0) { + fprintf(stderr, "failed to prepare push buffer: %s\n", strerror(-err)); + return err; + } + + err = vic->ops->flip(vic, output, input); + if (err < 0) { + fprintf(stderr, "failed to flip: %s\n", strerror(-err)); + return err; + } + + err = vic->ops->execute(vic, pushbuf, &ptr, output, &input, 1); + if (err < 0) { + fprintf(stderr, "failed to execute operation: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_pushbuf_sync_cond(pushbuf, &ptr, vic->syncpt, + DRM_TEGRA_SYNC_COND_OP_DONE); + if (err < 0) { + fprintf(stderr, "failed to push syncpoint: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_pushbuf_end(pushbuf, ptr); + if (err < 0) { + fprintf(stderr, "failed to update push buffer: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_job_submit(job, NULL); + if (err < 0) { + fprintf(stderr, "failed to submit job: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_job_wait(job, 1000000000); + if (err < 0) { + fprintf(stderr, "failed to wait for job: %s\n", strerror(-err)); + return err; + } + + drm_tegra_job_free(job); + + return 0; +} + +int main(int argc, char *argv[]) +{ + const unsigned int format = VIC_PIXEL_FORMAT_A8R8G8B8; + const unsigned int kind = VIC_BLK_KIND_PITCH; + const unsigned int width = 16, height = 16; + const char *device = "/dev/dri/renderD128"; + struct drm_tegra_channel *channel; + struct vic_image *input, *output; + struct drm_tegra *drm; + unsigned int version; + struct vic *vic; + int fd, err; + + if (argc > 1) + device = argv[1]; + + fd = open(device, O_RDWR); + if (fd < 0) { + fprintf(stderr, "open() failed: %s\n", strerror(errno)); + return 1; + } + + err = drm_tegra_new(fd, &drm); + if (err < 0) { + fprintf(stderr, "failed to open Tegra device: %s\n", strerror(-err)); + close(fd); + return 1; + } + + err = drm_tegra_channel_open(drm, DRM_TEGRA_VIC, &channel); + if (err < 0) { + fprintf(stderr, "failed to open channel to VIC: %s\n", strerror(-err)); + return 1; + } + + version = drm_tegra_channel_get_version(channel); + printf("version: %08x\n", version); + + err = vic_new(drm, channel, &vic); + if (err < 0) { + fprintf(stderr, "failed to create VIC: %s\n", strerror(-err)); + return 1; + } + + err = vic_image_new(vic, width, height, format, kind, DRM_TEGRA_CHANNEL_MAP_READ_WRITE, + &input); + if (err < 0) { + fprintf(stderr, "failed to create input image: %d\n", err); + return 1; + } + + err = vic_image_new(vic, width, height, format, kind, DRM_TEGRA_CHANNEL_MAP_READ_WRITE, + &output); + if (err < 0) { + fprintf(stderr, "failed to create output image: %d\n", err); + return 1; + } + + err = clear(vic, channel, input); + if (err < 0) { + fprintf(stderr, "failed to clear image: %s\n", strerror(-err)); + return 1; + } + + err = fill(vic, channel, input); + if (err < 0) { + fprintf(stderr, "failed to fill rectangle: %s\n", strerror(-err)); + return 1; + } + + err = flip(vic, channel, output, input); + if (err < 0) { + fprintf(stderr, "failed to flip image: %s\n", strerror(-err)); + return 1; + } + + printf("input: %ux%u\n", input->width, input->height); + vic_image_dump(input, stdout); + + printf("output: %ux%u\n", output->width, output->height); + vic_image_dump(output, stdout); + + vic_image_free(output); + vic_image_free(input); + + vic_free(vic); + drm_tegra_channel_close(channel); + drm_tegra_close(drm); + close(fd); + + return 0; +} diff --git a/tests/tegra/vic.c b/tests/tegra/vic.c new file mode 100644 index 0000000..4163e18 --- /dev/null +++ b/tests/tegra/vic.c @@ -0,0 +1,184 @@ +/* + * Copyright © 2018 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#include +#include /* XXX remove */ +#include + +#include "util_math.h" + +#include "tegra.h" +#include "host1x.h" +#include "vic.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +const struct vic_format_info *vic_format_get_info(unsigned int format) +{ + static const struct vic_format_info formats[] = { + { .format = VIC_PIXEL_FORMAT_A8R8G8B8, .cpp = 4 }, + }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(formats); i++) { + if (formats[i].format == format) + return &formats[i]; + } + + return 0; +} + +int vic_image_new(struct vic *vic, unsigned int width, unsigned int height, + unsigned int format, unsigned int kind, uint32_t flags, + struct vic_image **imagep) +{ + const struct vic_format_info *info = vic_format_get_info(format); + struct vic_image *image; + int err; + + if (!info) + return -EINVAL; + + image = calloc(1, sizeof(*image)); + if (!image) + return -ENOMEM; + + if (kind == VIC_BLK_KIND_PITCH) + image->align = 256; + else + image->align = 256; /* XXX */ + + image->width = width; + image->stride = ALIGN(width, image->align); + image->pitch = image->stride * info->cpp; + image->height = height; + image->format = format; + image->kind = kind; + + image->size = image->pitch * image->height; + + printf("image: %ux%u align: %zu stride: %u pitch: %u size: %zu\n", + image->width, image->height, image->align, image->stride, + image->pitch, image->size); + + err = drm_tegra_bo_new(vic->drm, 0, image->size, &image->bo); + if (err < 0) { + free(image); + return err; + } + + err = drm_tegra_channel_map(vic->channel, image->bo, flags, &image->map); + if (err < 0) { + drm_tegra_bo_unref(image->bo); + free(image); + return err; + } + + *imagep = image; + return 0; +} + +void vic_image_free(struct vic_image *image) +{ + if (image) { + drm_tegra_channel_unmap(image->map); + drm_tegra_bo_unref(image->bo); + free(image); + } +} + +void vic_image_dump(struct vic_image *image, FILE *fp) +{ + unsigned int i, j; + void *ptr; + int err; + + err = drm_tegra_bo_map(image->bo, &ptr); + if (err < 0) + return; + + for (j = 0; j < image->height; j++) { + uint32_t *pixels = (uint32_t *)((unsigned long)ptr + j * image->pitch); + + printf(" "); + + for (i = 0; i < image->width; i++) + printf(" %08x", pixels[i]); + + printf("\n"); + } + + drm_tegra_bo_unmap(image->bo); +} + +/* from vic30.c */ +int vic30_new(struct drm_tegra *drm, struct drm_tegra_channel *channel, + struct vic **vicp); + +/* from vic40.c */ +int vic40_new(struct drm_tegra *drm, struct drm_tegra_channel *channel, + struct vic **vicp); + +/* from vic41.c */ +int vic41_new(struct drm_tegra *drm, struct drm_tegra_channel *channel, + struct vic **vicp); + +/* from vic42.c */ +int vic42_new(struct drm_tegra *drm, struct drm_tegra_channel *channel, + struct vic **vicp); + +int vic_new(struct drm_tegra *drm, struct drm_tegra_channel *channel, + struct vic **vicp) +{ + unsigned int version; + + version = drm_tegra_channel_get_version(channel); + + switch (version) { + case 0x40: + return vic30_new(drm, channel, vicp); + + case 0x21: + return vic40_new(drm, channel, vicp); + + case 0x18: + return vic41_new(drm, channel, vicp); + + case 0x19: + return vic42_new(drm, channel, vicp); + } + + return -ENOTSUP; +} + +void vic_free(struct vic *vic) +{ + if (vic) + vic->ops->free(vic); +} + +int vic_clear(struct vic *vic, struct vic_image *output, unsigned int alpha, + unsigned int red, unsigned int green, unsigned int blue) +{ + return vic->ops->fill(vic, output, 0, 0, output->width - 1, + output->height - 1, alpha, red, green, blue); +} diff --git a/tests/tegra/vic.h b/tests/tegra/vic.h new file mode 100644 index 0000000..c205666 --- /dev/null +++ b/tests/tegra/vic.h @@ -0,0 +1,181 @@ +/* + * Copyright © 2018 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 VIC_H +#define VIC_H + +#include + +#include "host1x.h" + +#define DXVAHD_FRAME_FORMAT_PROGRESSIVE 0 +#define DXVAHD_FRAME_FORMAT_INTERLACED_TOP_FIELD_FIRST 1 +#define DXVAHD_FRAME_FORMAT_INTERLACED_BOTTOM_FIELD_FIRST 2 +#define DXVAHD_FRAME_FORMAT_TOP_FIELD 3 +#define DXVAHD_FRAME_FORMAT_BOTTOM_FIELD 4 +#define DXVAHD_FRAME_FORMAT_SUBPIC_PROGRESSIVE 5 +#define DXVAHD_FRAME_FORMAT_SUBPIC_INTERLACED_TOP_FIELD_FIRST 6 +#define DXVAHD_FRAME_FORMAT_SUBPIC_INTERLACED_BOTTOM_FIELD_FIRST 7 +#define DXVAHD_FRAME_FORMAT_SUBPIC_TOP_FIELD 8 +#define DXVAHD_FRAME_FORMAT_SUBPIC_BOTTOM_FIELD 9 +#define DXVAHD_FRAME_FORMAT_TOP_FIELD_CHROMA_BOTTOM 10 +#define DXVAHD_FRAME_FORMAT_BOTTOM_FIELD_CHROMA_TOP 11 +#define DXVAHD_FRAME_FORMAT_SUBPIC_TOP_FIELD_CHROMA_BOTTOM 12 +#define DXVAHD_FRAME_FORMAT_SUBPIC_BOTTOM_FIELD_CHROMA_TOP 13 + +#define DXVAHD_ALPHA_FILL_MODE_OPAQUE 0 +#define DXVAHD_ALPHA_FILL_MODE_BACKGROUND 1 +#define DXVAHD_ALPHA_FILL_MODE_DESTINATION 2 +#define DXVAHD_ALPHA_FILL_MODE_SOURCE_STREAM 3 +#define DXVAHD_ALPHA_FILL_MODE_COMPOSITED 4 +#define DXVAHD_ALPHA_FILL_MODE_SOURCE_ALPHA 5 + +#define VIC_BLEND_SRCFACTC_K1 0 +#define VIC_BLEND_SRCFACTC_K1_TIMES_DST 1 +#define VIC_BLEND_SRCFACTC_NEG_K1_TIMES_DST 2 +#define VIC_BLEND_SRCFACTC_K1_TIMES_SRC 3 +#define VIC_BLEND_SRCFACTC_ZERO 4 + +#define VIC_BLEND_DSTFACTC_K1 0 +#define VIC_BLEND_DSTFACTC_K2 1 +#define VIC_BLEND_DSTFACTC_K1_TIMES_DST 2 +#define VIC_BLEND_DSTFACTC_NEG_K1_TIMES_DST 3 +#define VIC_BLEND_DSTFACTC_NEG_K1_TIMES_SRC 4 +#define VIC_BLEND_DSTFACTC_ZERO 5 +#define VIC_BLEND_DSTFACTC_ONE 6 + +#define VIC_BLEND_SRCFACTA_K1 0 +#define VIC_BLEND_SRCFACTA_K2 1 +#define VIC_BLEND_SRCFACTA_NEG_K1_TIMES_DST 2 +#define VIC_BLEND_SRCFACTA_ZERO 3 + +#define VIC_BLEND_DSTFACTA_K2 0 +#define VIC_BLEND_DSTFACTA_NEG_K1_TIMES_SRC 1 +#define VIC_BLEND_DSTFACTA_ZERO 2 +#define VIC_BLEND_DSTFACTA_ONE 3 + +#define VIC_BLK_KIND_PITCH 0 +#define VIC_BLK_KIND_GENERIC_16Bx2 1 + +#define VIC_PIXEL_FORMAT_L8 1 +#define VIC_PIXEL_FORMAT_R8 4 +#define VIC_PIXEL_FORMAT_A8R8G8B8 32 +#define VIC_PIXEL_FORMAT_R8G8B8A8 34 +#define VIC_PIXEL_FORMAT_Y8_U8V8_N420 67 +#define VIC_PIXEL_FORMAT_Y8_V8U8_N420 68 + +#define VIC_CACHE_WIDTH_16Bx16 0 /* BL16Bx2 */ +#define VIC_CACHE_WIDTH_32Bx8 1 /* BL16Bx2 */ +#define VIC_CACHE_WIDTH_64Bx4 2 /* BL16Bx2, PL */ +#define VIC_CACHE_WIDTH_128Bx2 3 /* BL16Bx2, PL */ +#define VIC_CACHE_WIDTH_256Bx1 4 /* PL */ + +struct vic_format_info { + unsigned int format; + unsigned int cpp; +}; + + +#define VIC_UCLASS_INCR_SYNCPT 0x00 +#define VIC_UCLASS_METHOD_OFFSET 0x10 +#define VIC_UCLASS_METHOD_DATA 0x11 + +static inline void VIC_PUSH_METHOD(struct drm_tegra_pushbuf *pushbuf, + uint32_t **ptrp, uint32_t method, + uint32_t value) +{ + *(*ptrp)++ = HOST1X_OPCODE_INCR(VIC_UCLASS_METHOD_OFFSET, 2); + *(*ptrp)++ = method >> 2; + *(*ptrp)++ = value; +} + +static inline void VIC_PUSH_BUFFER(struct drm_tegra_pushbuf *pushbuf, + uint32_t **ptrp, uint32_t method, + struct drm_tegra_mapping *map, + unsigned long offset, unsigned long flags) +{ + *(*ptrp)++ = HOST1X_OPCODE_INCR(VIC_UCLASS_METHOD_OFFSET, 2); + *(*ptrp)++ = method >> 2; + + drm_tegra_pushbuf_relocate(pushbuf, ptrp, map, offset, 8, flags); +} + +struct vic_image; +struct vic; + +struct vic_ops { + int (*fill)(struct vic *vic, struct vic_image *output, + unsigned int left, unsigned int top, + unsigned int right, unsigned int bottom, + unsigned int alpha, unsigned red, + unsigned int green, unsigned int blue); + int (*blit)(struct vic *vic, struct vic_image *output, + struct vic_image *input); + int (*flip)(struct vic *vic, struct vic_image *output, + struct vic_image *input); + int (*execute)(struct vic *vic, + struct drm_tegra_pushbuf *pushbuf, + uint32_t **ptrp, + struct vic_image *output, + struct vic_image **inputs, + unsigned int num_inputs); + void (*free)(struct vic *vic); +}; + +struct vic { + struct drm_tegra *drm; + struct drm_tegra_channel *channel; + struct drm_tegra_syncpoint *syncpt; + const struct vic_ops *ops; + unsigned int version; +}; + +int vic_new(struct drm_tegra *drm, struct drm_tegra_channel *channel, + struct vic **vicp); +void vic_free(struct vic *vic); + +int vic_clear(struct vic *vic, struct vic_image *output, unsigned int alpha, + unsigned int red, unsigned int green, unsigned int blue); + +struct vic_image { + struct drm_tegra_bo *bo; + struct drm_tegra_mapping *map; + unsigned int width; + unsigned int stride; + unsigned int pitch; + unsigned int height; + unsigned int format; + unsigned int kind; + + size_t align; + size_t size; +}; + +const struct vic_format_info *vic_format_get_info(unsigned int format); + +int vic_image_new(struct vic *vic, unsigned int width, unsigned int height, + unsigned int format, unsigned int kind, uint32_t flags, + struct vic_image **imagep); +void vic_image_free(struct vic_image *image); +void vic_image_dump(struct vic_image *image, FILE *fp); + +#endif diff --git a/tests/tegra/vic30.c b/tests/tegra/vic30.c new file mode 100644 index 0000000..1bea6e7 --- /dev/null +++ b/tests/tegra/vic30.c @@ -0,0 +1,458 @@ +/* + * Copyright © 2018 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#include +#include + +#include "private.h" +#include "tegra.h" +#include "vic.h" +#include "vic30.h" + +struct vic30 { + struct vic base; + + struct { + struct drm_tegra_mapping *map; + struct drm_tegra_bo *bo; + } config; + + struct { + struct drm_tegra_mapping *map; + struct drm_tegra_bo *bo; + } filter; + + struct { + struct drm_tegra_mapping *map; + struct drm_tegra_bo *bo; + } hist; +}; + +static int vic30_fill(struct vic *v, struct vic_image *output, + unsigned int left, unsigned int top, + unsigned int right, unsigned int bottom, + unsigned int alpha, unsigned int red, + unsigned int green, unsigned int blue) +{ + struct vic30 *vic = container_of(v, struct vic30, base); + ConfigStruct *c; + int err; + + err = drm_tegra_bo_map(vic->config.bo, (void **)&c); + if (err < 0) { + fprintf(stderr, "failed to map configuration structure: %s\n", + strerror(-err)); + return err; + } + + memset(c, 0, sizeof(*c)); + + c->surfaceList0Struct.TargetRectLeft = left; + c->surfaceList0Struct.TargetRectTop = top; + c->surfaceList0Struct.TargetRectRight = right; + c->surfaceList0Struct.TargetRectBottom = bottom; + + c->blending0Struct.PixelFormat = output->format; + c->blending0Struct.BackgroundAlpha = alpha; + c->blending0Struct.BackgroundR = red; + c->blending0Struct.BackgroundG = green; + c->blending0Struct.BackgroundB = blue; + c->blending0Struct.LumaWidth = output->stride - 1; + c->blending0Struct.LumaHeight = output->height - 1; + c->blending0Struct.ChromaWidth = 16383; + c->blending0Struct.ChromaWidth = 16383; + c->blending0Struct.TargetRectLeft = left; + c->blending0Struct.TargetRectTop = top; + c->blending0Struct.TargetRectRight = right; + c->blending0Struct.TargetRectBottom = bottom; + c->blending0Struct.SurfaceWidth = output->width - 1; + c->blending0Struct.SurfaceHeight = output->height - 1; + c->blending0Struct.BlkKind = output->kind; + c->blending0Struct.BlkHeight = 0; + + c->fetchControl0Struct.TargetRectLeft = left; + c->fetchControl0Struct.TargetRectTop = top; + c->fetchControl0Struct.TargetRectRight = right; + c->fetchControl0Struct.TargetRectBottom = bottom; + + drm_tegra_bo_unmap(vic->config.bo); + + return 0; +} + +static int vic30_blit(struct vic *v, struct vic_image *output, + struct vic_image *input) +{ + struct vic30 *vic = container_of(v, struct vic30, base); + ColorConversionLumaAlphaStruct *ccla; + ColorConversionMatrixStruct *ccm; + ColorConversionClampStruct *ccc; + SurfaceListSurfaceStruct *s; + BlendingSurfaceStruct *b; + SurfaceCache0Struct *sc; + ConfigStruct *c; + int err; + + err = drm_tegra_bo_map(vic->config.bo, (void **)&c); + if (err < 0) { + fprintf(stderr, "failed to map configuration structure: %s\n", + strerror(-err)); + return err; + } + + memset(c, 0, sizeof(*c)); + + c->surfaceList0Struct.TargetRectLeft = 0; + c->surfaceList0Struct.TargetRectTop = 0; + c->surfaceList0Struct.TargetRectRight = output->width - 1; + c->surfaceList0Struct.TargetRectBottom = output->height - 1; + + c->blending0Struct.PixelFormat = output->format; + c->blending0Struct.BackgroundAlpha = 0; + c->blending0Struct.BackgroundR = 0; + c->blending0Struct.BackgroundG = 0; + c->blending0Struct.BackgroundB = 0; + c->blending0Struct.LumaWidth = output->stride - 1; + c->blending0Struct.LumaHeight = output->height - 1; + c->blending0Struct.ChromaWidth = 16383; + c->blending0Struct.ChromaWidth = 16383; + c->blending0Struct.TargetRectLeft = 0; + c->blending0Struct.TargetRectTop = 0; + c->blending0Struct.TargetRectRight = output->width - 1; + c->blending0Struct.TargetRectBottom = output->height - 1; + c->blending0Struct.SurfaceWidth = output->width - 1; + c->blending0Struct.SurfaceHeight = output->height - 1; + c->blending0Struct.BlkKind = output->kind; + c->blending0Struct.BlkHeight = 0; + + c->fetchControl0Struct.TargetRectLeft = 0; + c->fetchControl0Struct.TargetRectTop = 0; + c->fetchControl0Struct.TargetRectRight = output->width - 1; + c->fetchControl0Struct.TargetRectBottom = output->height - 1; + + /* setup fetch parameters for slot 0 */ + c->fetchControl0Struct.Enable0 = 0x1; + c->fetchControl0Struct.Iir0 = 0x300; + + /* setup cache parameters for slot 0 */ + sc = &c->surfaceCache0Struct; + sc->PixelFormat0 = input->format; + + /* setup surface configuration for slot 0 */ + s = &c->surfaceListSurfaceStruct[0]; + s->Enable = 1; + s->FrameFormat = DXVAHD_FRAME_FORMAT_PROGRESSIVE; + s->PixelFormat = input->format; + s->SurfaceWidth = input->width - 1; + s->SurfaceHeight = input->height - 1; + s->LumaWidth = input->stride - 1; + s->LumaHeight = input->height - 1; + s->ChromaWidth = 16383; + s->ChromaHeight = 16383; + s->CacheWidth = VIC_CACHE_WIDTH_256Bx1; //VIC_CACHE_WIDTH_16Bx16; + s->BlkKind = input->kind; + s->BlkHeight = 0; + s->DestRectLeft = 0; + s->DestRectTop = 0; + s->DestRectRight = output->width - 1; + s->DestRectBottom = output->height - 1; + s->SourceRectLeft = 0 << 16; + s->SourceRectTop = 0 << 16; + s->SourceRectRight = (input->width - 1) << 16; + s->SourceRectBottom = (input->height - 1) << 16; + + /* setup color conversion for slot 0 */ + ccla = &c->colorConversionLumaAlphaStruct[0]; + ccla->PlanarAlpha = 1023; + ccla->ConstantAlpha = 0; + + ccm = &c->colorConversionMatrixStruct[0]; + ccm->c00 = 1023; + ccm->c11 = 1023; + ccm->c22 = 1023; + + ccc = &c->colorConversionClampStruct[0]; + ccc->low = 0; + ccc->high = 1023; + + /* setup blending for slot 0 */ + b = &c->blendingSurfaceStruct[0]; + b->AlphaK1 = 1023; + b->SrcFactCMatchSelect = VIC_BLEND_SRCFACTC_K1; + b->SrcFactAMatchSelect = VIC_BLEND_SRCFACTA_K1; + b->DstFactCMatchSelect = VIC_BLEND_DSTFACTC_NEG_K1_TIMES_SRC; + b->DstFactAMatchSelect = VIC_BLEND_DSTFACTA_NEG_K1_TIMES_SRC; + + drm_tegra_bo_unmap(vic->config.bo); + + return 0; +} + +static int vic30_flip(struct vic *v, struct vic_image *output, + struct vic_image *input) +{ + struct vic30 *vic = container_of(v, struct vic30, base); + ColorConversionLumaAlphaStruct *ccla; + ColorConversionMatrixStruct *ccm; + ColorConversionClampStruct *ccc; + SurfaceListSurfaceStruct *s; + BlendingSurfaceStruct *b; + SurfaceCache0Struct *sc; + ConfigStruct *c; + int err; + + err = drm_tegra_bo_map(vic->config.bo, (void **)&c); + if (err < 0) { + fprintf(stderr, "failed to map configuration structure: %s\n", + strerror(-err)); + return err; + } + + memset(c, 0, sizeof(*c)); + + c->surfaceList0Struct.TargetRectLeft = 0; + c->surfaceList0Struct.TargetRectTop = 0; + c->surfaceList0Struct.TargetRectRight = output->width - 1; + c->surfaceList0Struct.TargetRectBottom = output->height - 1; + + c->blending0Struct.PixelFormat = output->format; + c->blending0Struct.BackgroundAlpha = 0; + c->blending0Struct.BackgroundR = 0; + c->blending0Struct.BackgroundG = 0; + c->blending0Struct.BackgroundB = 0; + c->blending0Struct.LumaWidth = output->stride - 1; + c->blending0Struct.LumaHeight = output->height - 1; + c->blending0Struct.ChromaWidth = 16383; + c->blending0Struct.ChromaWidth = 16383; + c->blending0Struct.TargetRectLeft = 0; + c->blending0Struct.TargetRectTop = 0; + c->blending0Struct.TargetRectRight = output->width - 1; + c->blending0Struct.TargetRectBottom = output->height - 1; + c->blending0Struct.SurfaceWidth = output->width - 1; + c->blending0Struct.SurfaceHeight = output->height - 1; + c->blending0Struct.BlkKind = output->kind; + c->blending0Struct.BlkHeight = 0; + c->blending0Struct.OutputFlipY = 1; + + c->fetchControl0Struct.TargetRectLeft = 0; + c->fetchControl0Struct.TargetRectTop = 0; + c->fetchControl0Struct.TargetRectRight = output->width - 1; + c->fetchControl0Struct.TargetRectBottom = output->height - 1; + + /* setup fetch parameters for slot 0 */ + c->fetchControl0Struct.Enable0 = 0x1; + c->fetchControl0Struct.Iir0 = 0x300; + + /* setup cache parameters for slot 0 */ + sc = &c->surfaceCache0Struct; + sc->PixelFormat0 = input->format; + + /* setup surface configuration for slot 0 */ + s = &c->surfaceListSurfaceStruct[0]; + s->Enable = 1; + s->FrameFormat = DXVAHD_FRAME_FORMAT_PROGRESSIVE; + s->PixelFormat = input->format; + s->SurfaceWidth = input->width - 1; + s->SurfaceHeight = input->height - 1; + s->LumaWidth = input->stride - 1; + s->LumaHeight = input->height - 1; + s->ChromaWidth = 16383; + s->ChromaHeight = 16383; + s->CacheWidth = VIC_CACHE_WIDTH_256Bx1; + s->BlkKind = input->kind; + s->BlkHeight = 0; + s->DestRectLeft = 0; + s->DestRectTop = 0; + s->DestRectRight = output->width - 1; + s->DestRectBottom = output->height - 1; + s->SourceRectLeft = 0 << 16; + s->SourceRectTop = 0 << 16; + s->SourceRectRight = (input->width - 1) << 16; + s->SourceRectBottom = (input->height - 1) << 16; + + /* setup color conversion for slot 0 */ + ccla = &c->colorConversionLumaAlphaStruct[0]; + ccla->PlanarAlpha = 1023; + ccla->ConstantAlpha = 0; + + ccm = &c->colorConversionMatrixStruct[0]; + ccm->c00 = 1023; + ccm->c11 = 1023; + ccm->c22 = 1023; + + ccc = &c->colorConversionClampStruct[0]; + ccc->low = 0; + ccc->high = 1023; + + /* setup blending for slot 0 */ + b = &c->blendingSurfaceStruct[0]; + b->AlphaK1 = 1023; + b->SrcFactCMatchSelect = VIC_BLEND_SRCFACTC_K1; + b->SrcFactAMatchSelect = VIC_BLEND_SRCFACTA_K1; + b->DstFactCMatchSelect = VIC_BLEND_DSTFACTC_NEG_K1_TIMES_SRC; + b->DstFactAMatchSelect = VIC_BLEND_DSTFACTA_NEG_K1_TIMES_SRC; + + drm_tegra_bo_unmap(vic->config.bo); + + return 0; +} + +static int vic30_execute(struct vic *v, struct drm_tegra_pushbuf *pushbuf, + uint32_t **ptrp, struct vic_image *output, + struct vic_image **inputs, unsigned int num_inputs) +{ + struct vic30 *vic = container_of(v, struct vic30, base); + unsigned int i; + + if (num_inputs > 1) + return -EINVAL; + + VIC_PUSH_METHOD(pushbuf, ptrp, NVA0B6_VIDEO_COMPOSITOR_SET_APPLICATION_ID, 1); + VIC_PUSH_METHOD(pushbuf, ptrp, NVA0B6_VIDEO_COMPOSITOR_SET_CONTROL_PARAMS, (sizeof(ConfigStruct) / 16) << 16); + VIC_PUSH_BUFFER(pushbuf, ptrp, NVA0B6_VIDEO_COMPOSITOR_SET_CONFIG_STRUCT_OFFSET, vic->config.map, 0, 0); + VIC_PUSH_BUFFER(pushbuf, ptrp, NVA0B6_VIDEO_COMPOSITOR_SET_HIST_OFFSET, vic->hist.map, 0, 0); + VIC_PUSH_BUFFER(pushbuf, ptrp, NVA0B6_VIDEO_COMPOSITOR_SET_OUTPUT_SURFACE_LUMA_OFFSET, output->map, 0, 0); + + for (i = 0; i < num_inputs; i++) + VIC_PUSH_BUFFER(pushbuf, ptrp, NVA0B6_VIDEO_COMPOSITOR_SET_SURFACE0_SLOT0_LUMA_OFFSET, inputs[i]->map, 0, 0); + + VIC_PUSH_METHOD(pushbuf, ptrp, NVA0B6_VIDEO_COMPOSITOR_EXECUTE, 1 << 8); + + return 0; +} + +static void vic30_free(struct vic *v) +{ + struct vic30 *vic = container_of(v, struct vic30, base); + + drm_tegra_channel_unmap(vic->hist.map); + drm_tegra_bo_unref(vic->hist.bo); + + drm_tegra_channel_unmap(vic->filter.map); + drm_tegra_bo_unref(vic->filter.bo); + + drm_tegra_channel_unmap(vic->config.map); + drm_tegra_bo_unref(vic->config.bo); + + drm_tegra_syncpoint_free(v->syncpt); + + free(vic); +} + +static const struct vic_ops vic30_ops = { + .fill = vic30_fill, + .blit = vic30_blit, + .flip = vic30_flip, + .execute = vic30_execute, + .free = vic30_free, +}; + +int vic30_new(struct drm_tegra *drm, struct drm_tegra_channel *channel, + struct vic **vicp) +{ + struct vic30 *vic; + void *ptr; + int err; + + vic = calloc(1, sizeof(*vic)); + if (!vic) + return -ENOMEM; + + vic->base.drm = drm; + vic->base.channel = channel; + vic->base.ops = &vic30_ops; + vic->base.version = 0x40; + + err = drm_tegra_syncpoint_new(drm, &vic->base.syncpt); + if (err < 0) { + fprintf(stderr, "failed to allocate syncpoint: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_bo_new(drm, 0, 16384, &vic->config.bo); + if (err < 0) { + fprintf(stderr, "failed to allocate configuration structure: %s\n", + strerror(-err)); + return err; + } + + err = drm_tegra_channel_map(channel, vic->config.bo, DRM_TEGRA_CHANNEL_MAP_READ, + &vic->config.map); + if (err < 0) { + fprintf(stderr, "failed to map configuration structure: %s\n", + strerror(-err)); + return err; + } + + err = drm_tegra_bo_new(drm, 0, 16384, &vic->filter.bo); + if (err < 0) { + fprintf(stderr, "failed to allocate filter buffer: %s\n", + strerror(-err)); + return err; + } + + err = drm_tegra_bo_map(vic->filter.bo, &ptr); + if (err < 0) { + fprintf(stderr, "failed to map filter buffer: %s\n", strerror(-err)); + return err; + } + + memset(ptr, 0, 16384); + drm_tegra_bo_unmap(vic->filter.bo); + + err = drm_tegra_channel_map(channel, vic->filter.bo, DRM_TEGRA_CHANNEL_MAP_READ, + &vic->filter.map); + if (err < 0) { + fprintf(stderr, "failed to map filter buffer: %s\n", + strerror(-err)); + return err; + } + + err = drm_tegra_bo_new(drm, 0, 4096, &vic->hist.bo); + if (err < 0) { + fprintf(stderr, "failed to allocate history buffer: %s\n", + strerror(-err)); + return err; + } + + err = drm_tegra_bo_map(vic->hist.bo, &ptr); + if (err < 0) { + fprintf(stderr, "failed to map history buffer: %s\n", strerror(-err)); + return err; + } + + memset(ptr, 0, 4096); + drm_tegra_bo_unmap(vic->hist.bo); + + err = drm_tegra_channel_map(channel, vic->hist.bo, DRM_TEGRA_CHANNEL_MAP_READ_WRITE, + &vic->hist.map); + if (err < 0) { + fprintf(stderr, "failed to map histogram buffer: %s\n", + strerror(-err)); + return err; + } + + if (vicp) + *vicp = &vic->base; + + return 0; +} diff --git a/tests/tegra/vic30.h b/tests/tegra/vic30.h new file mode 100644 index 0000000..d095c0d --- /dev/null +++ b/tests/tegra/vic30.h @@ -0,0 +1,439 @@ +/* + * Copyright © 2018 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 VIC30_H +#define VIC30_H + +#include + +#define NVA0B6_VIDEO_COMPOSITOR_SET_APPLICATION_ID 0x200 +#define NVA0B6_VIDEO_COMPOSITOR_EXECUTE 0x300 +#define NVA0B6_VIDEO_COMPOSITOR_EXECUTE_AWAKEN (1 << 8) +#define NVA0B6_VIDEO_COMPOSITOR_SET_SURFACE0_SLOT0_LUMA_OFFSET 0x400 +#define NVA0B6_VIDEO_COMPOSITOR_SET_SURFACE0_SLOT0_CHROMA_U_OFFSET 0x404 +#define NVA0B6_VIDEO_COMPOSITOR_SET_SURFACE0_SLOT0_CHROMA_V_OFFSET 0x408 +#define NVA0B6_VIDEO_COMPOSITOR_SET_CONTROL_PARAMS 0x700 +#define NVA0B6_VIDEO_COMPOSITOR_SET_CONFIG_STRUCT_OFFSET 0x720 +#define NVA0B6_VIDEO_COMPOSITOR_SET_PALETTE_OFFSET 0x724 +#define NVA0B6_VIDEO_COMPOSITOR_SET_HIST_OFFSET 0x728 +#define NVA0B6_VIDEO_COMPOSITOR_SET_OUTPUT_SURFACE_LUMA_OFFSET 0x730 +#define NVA0B6_VIDEO_COMPOSITOR_SET_OUTPUT_SURFACE_CHROMA_U_OFFSET 0x734 +#define NVA0B6_VIDEO_COMPOSITOR_SET_OUTPUT_SURFACE_CHROMA_V_OFFSET 0x738 + +#define VIC_PIXEL_FORMAT_L8 1 +#define VIC_PIXEL_FORMAT_R8 4 +#define VIC_PIXEL_FORMAT_A8R8G8B8 32 +#define VIC_PIXEL_FORMAT_R8G8B8A8 34 +#define VIC_PIXEL_FORMAT_Y8_U8V8_N420 67 +#define VIC_PIXEL_FORMAT_Y8_V8U8_N420 68 + +#define VIC_BLK_KIND_PITCH 0 +#define VIC_BLK_KIND_GENERIC_16Bx2 1 + +typedef struct { + uint64_t DeNoise0 : 1; /* 0 */ + uint64_t CadenceDetect0 : 1; /* 1 */ + uint64_t MotionMap0 : 1; /* 2 */ + uint64_t MedianFilter0 : 1; /* 3 */ + uint64_t DeNoise1 : 1; /* 4 */ + uint64_t CadenceDetect1 : 1; /* 5 */ + uint64_t MotionMap1 : 1; /* 6 */ + uint64_t MedianFilter1 : 1; /* 7 */ + uint64_t DeNoise2 : 1; /* 8 */ + uint64_t CadenceDetect2 : 1; /* 9 */ + uint64_t MotionMap2 : 1; /* 10 */ + uint64_t MedianFilter2 : 1; /* 11 */ + uint64_t DeNoise3 : 1; /* 12 */ + uint64_t CadenceDetect3 : 1; /* 13 */ + uint64_t MotionMap3 : 1; /* 14 */ + uint64_t MedianFilter3 : 1; /* 15 */ + uint64_t DeNoise4 : 1; /* 16 */ + uint64_t CadenceDetect4 : 1; /* 17 */ + uint64_t MotionMap4 : 1; /* 18 */ + uint64_t MedianFilter4 : 1; /* 19 */ + uint64_t IsEven0 : 1; /* 20 */ + uint64_t IsEven1 : 1; /* 21 */ + uint64_t IsEven2 : 1; /* 22 */ + uint64_t IsEven3 : 1; /* 23 */ + uint64_t IsEven4 : 1; /* 24 */ + uint64_t MMapCombine0 : 1; /* 25 */ + uint64_t MMapCombine1 : 1; /* 26 */ + uint64_t MMapCombine2 : 1; /* 27 */ + uint64_t MMapCombine3 : 1; /* 28 */ + uint64_t MMapCombine4 : 1; /* 29 */ + uint64_t reserved0 : 2; /* 31..30 */ + uint64_t PixelFormat0 : 7; /* 38..32 */ + uint64_t reserved1 : 1; /* 39 */ + uint64_t PixelFormat1 : 7; /* 46..40 */ + uint64_t reserved2 : 1; /* 47 */ + uint64_t PixelFormat2 : 7; /* 54..48 */ + uint64_t reserved3 : 1; /* 55 */ + uint64_t PixelFormat3 : 7; /* 62..56 */ + uint64_t reserved4 : 1; /* 63 */ + uint64_t PixelFormat4 : 7; /* 70..64 */ + uint64_t reserved5 : 1; /* 71 */ + uint64_t reserved6 : 24; /* 95..72 */ + uint64_t PPMotion0 : 1; /* 96 */ + uint64_t PPMotion1 : 1; /* 97 */ + uint64_t PPMotion2 : 1; /* 98 */ + uint64_t PPMotion3 : 1; /* 99 */ + uint64_t PPMotion4 : 1; /* 100 */ + uint64_t reserved7 : 3; /* 103..101 */ + uint64_t ChromaEven0 : 1; /* 104 */ + uint64_t ChromaEven1 : 1; /* 105 */ + uint64_t ChromaEven2 : 1; /* 106 */ + uint64_t ChromaEven3 : 1; /* 107 */ + uint64_t ChromaEven4 : 1; /* 108 */ + uint64_t reserved8 : 3; /* 111..109 */ + uint64_t AdvancedDenoise0 : 1; /* 112 */ + uint64_t AdvancedDenoise1 : 1; /* 113 */ + uint64_t AdvancedDenoise2 : 1; /* 114 */ + uint64_t AdvancedDenoise3 : 1; /* 115 */ + uint64_t AdvancedDenoise4 : 1; /* 116 */ + uint64_t reserved9 : 3; /* 119..117 */ + uint64_t reserved10 : 8; /* 127..120 */ +} SurfaceCache0Struct; + +typedef struct { + uint64_t ClearRectMask0 : 8; /* 7..0 */ + uint64_t ClearRectMask1 : 8; /* 15..8 */ + uint64_t ClearRectMask2 : 8; /* 23..16 */ + uint64_t ClearRectMask3 : 8; /* 31..24 */ + uint64_t ClearRectMask4 : 8; /* 39..32 */ + uint64_t reserved0 : 22; /* 61..40 */ + uint64_t OutputFlipX : 1; /* 62 */ + uint64_t OutputFlipY : 1; /* 63 */ + uint64_t TargetRectLeft : 14; /* 77..64 */ + uint64_t reserved1 : 2; /* 79..78 */ + uint64_t TargetRectRight : 14; /* 93..80 */ + uint64_t reserved2 : 2; /* 95..94 */ + uint64_t TargetRectTop : 14; /* 109..96 */ + uint64_t reserved3 : 2; /* 111..110 */ + uint64_t TargetRectBottom : 14; /* 125..112 */ + uint64_t reserved4 : 2; /* 127..126 */ +} SurfaceList0Struct; + +typedef struct { + uint64_t ClearRect0Left : 14; /* 13..0 */ + uint64_t reserved0 : 2; /* 15..14 */ + uint64_t ClearRect0Right : 14; /* 29..16 */ + uint64_t reserved1 : 2; /* 31..30 */ + uint64_t ClearRect0Top : 14; /* 45..32 */ + uint64_t reserved2 : 2; /* 47..46 */ + uint64_t ClearRect0Bottom : 14; /* 61..48 */ + uint64_t reserved3 : 2; /* 63..62 */ + uint64_t ClearRect1Left : 14; /* 77..64 */ + uint64_t reserved4 : 2; /* 79..78 */ + uint64_t ClearRect1Right : 14; /* 93..80 */ + uint64_t reserved5 : 2; /* 95..94 */ + uint64_t ClearRect1Top : 14; /* 109..96 */ + uint64_t reserved6 : 2; /* 111..110 */ + uint64_t ClearRect1Bottom : 14; /* 125..112 */ + uint64_t reserved7 : 2; /* 127..126 */ +} SurfaceListClearRectStruct; + +typedef struct { + uint64_t Enable : 1; /* 0 */ + uint64_t FrameFormat : 4; /* 4..1 */ + uint64_t PixelFormat : 7; /* 11..5 */ + uint64_t reserved0 : 2; /* 13..12 */ + uint64_t ChromaLocHoriz : 2; /* 15..14 */ + uint64_t ChromaLocVert : 2; /* 17..16 */ + uint64_t Panoramic : 12; /* 29..18 */ + uint64_t reserved1 : 4; /* 33..30 */ + uint64_t SurfaceWidth : 14; /* 47..34 */ + uint64_t reserved2 : 1; /* 48 */ + uint64_t SurfaceHeight : 14; /* 62..49 */ + uint64_t reserved3 : 1; /* 63 */ + uint64_t LumaWidth : 14; /* 77..64 */ + uint64_t reserved4 : 1; /* 78 */ + uint64_t LumaHeight : 14; /* 92..79 */ + uint64_t reserved5 : 1; /* 93 */ + uint64_t ChromaWidth : 14; /* 107..94 */ + uint64_t reserved6 : 1; /* 108 */ + uint64_t ChromaHeight : 14; /* 122..109 */ + uint64_t reserved7 : 1; /* 123 */ + uint64_t CacheWidth : 3; /* 126..124 */ + uint64_t reserved8 : 1; /* 127 */ + /* 128 */ + uint64_t FilterLengthY : 2; /* 1..0 */ + uint64_t FilterLengthX : 2; /* 3..2 */ + uint64_t DetailFltClamp : 6; /* 9..4 */ + uint64_t reserved9 : 2; /* 11..10 */ + uint64_t LightLevel : 4; /* 15..12 */ + uint64_t reserved10 : 4; /* 19..16 */ + uint64_t reserved11 : 8; /* 27..20 */ + uint64_t reserved12 : 32; /* 59..28 */ + uint64_t BlkKind : 4; /* 63..60 */ + uint64_t DestRectLeft : 14; /* 77..64 */ + uint64_t reserved13 : 1; /* 78 */ + uint64_t DestRectRight : 14; /* 92..79 */ + uint64_t reserved14 : 1; /* 93 */ + uint64_t DestRectTop : 14; /* 107..94 */ + uint64_t reserved15 : 1; /* 108 */ + uint64_t DestRectBottom : 14; /* 122..109 */ + uint64_t reserved16 : 1; /* 123 */ + uint64_t BlkHeight : 4; /* 127..124 */ + /* 256 */ + uint64_t SourceRectLeft : 30; /* 29..0 */ + uint64_t reserved17 : 2; /* 31..30 */ + uint64_t SourceRectRight : 30; /* 61..32 */ + uint64_t reserved18 : 2; /* 63..62 */ + uint64_t SourceRectTop : 30; /* 93..64 */ + uint64_t reserved19 : 2; /* 95..94 */ + uint64_t SourceRectBottom : 30; /* 125..96 */ + uint64_t reserved20 : 2; /* 127..126 */ +} SurfaceListSurfaceStruct; + +typedef struct { + uint64_t l0 : 20; /* 19..0 */ + uint64_t l1 : 20; /* 39..20 */ + uint64_t l2 : 20; /* 59..40 */ + uint64_t r_shift : 4; /* 63..60 */ + uint64_t l3 : 20; /* 83..64 */ + uint64_t PlanarAlpha : 10; /* 93..84 */ + uint64_t ConstantAlpha : 1; /* 94 */ + uint64_t ClipEnabled : 1; /* 95 */ + uint64_t LumaKeyLower : 10; /* 105..96 */ + uint64_t reserved6 : 3; /* 108..106 */ + uint64_t StereoInterleave : 3; /* 111..109 */ + uint64_t LumaKeyUpper : 10; /* 121..112 */ + uint64_t reserved7 : 2; /* 123..122 */ + uint64_t reserved8 : 1; /* 124 */ + uint64_t LumaKeyEnabled : 1; /* 125 */ + uint64_t reserved9 : 2; /* 127..126 */ +} ColorConversionLumaAlphaStruct; + +typedef struct { + uint64_t c00 : 20; /* 19..0 */ + uint64_t c10 : 20; /* 39..20 */ + uint64_t c20 : 20; /* 59..40 */ + uint64_t r_shift : 4; /* 63..60 */ + uint64_t c01 : 20; /* 83..64 */ + uint64_t c11 : 20; /* 103..84 */ + uint64_t c21 : 20; /* 123..104 */ + uint64_t reserved0 : 4; /* 127..124 */ + /* 128 */ + uint64_t c02 : 20; /* 19..0 */ + uint64_t c12 : 20; /* 39..20 */ + uint64_t c22 : 20; /* 59..40 */ + uint64_t reserved1 : 4; /* 63..60 */ + uint64_t c03 : 20; /* 83..64 */ + uint64_t c13 : 20; /* 103..84 */ + uint64_t c23 : 20; /* 123..104 */ + uint64_t reserved2 : 4; /* 127..124 */ +} ColorConversionMatrixStruct; + +typedef struct { + uint64_t low : 10; /* 9..0 */ + uint64_t reserved0 : 6; /* 15..10 */ + uint64_t high : 10; /* 25..16 */ + uint64_t reserved1 : 6; /* 31..26 */ + uint64_t reserved2 : 32; /* 63..32 */ + uint64_t reserved3 : 32; /* 95..64 */ + uint64_t reserved4 : 32; /* 127..96 */ +} ColorConversionClampStruct; + +typedef struct { + uint64_t PixelFormat : 7; /* 6..0 */ + uint64_t reserved0 : 1; /* 7 */ + uint64_t AlphaFillMode : 3; /* 10..8 */ + uint64_t AlphaFillSlot : 3; /* 13..11 */ + uint64_t BackgroundAlpha : 10; /* 23..14 */ + uint64_t BackgroundR : 10; /* 33..24 */ + uint64_t BackgroundG : 10; /* 43..34 */ + uint64_t BackgroundB : 10; /* 53..44 */ + uint64_t ChromaLocHoriz : 2; /* 55..54 */ + uint64_t ChromaLocVert : 2; /* 57..56 */ + uint64_t reserved1 : 6; /* 63..58 */ + uint64_t LumaWidth : 14; /* 77..64 */ + uint64_t reserved2 : 2; /* 79..78 */ + uint64_t LumaHeight : 14; /* 93..80 */ + uint64_t reserved3 : 2; /* 95..94 */ + uint64_t ChromaWidth : 14; /* 109..96 */ + uint64_t reserved4 : 2; /* 111..110 */ + uint64_t ChromaHeight : 14; /* 125..112 */ + uint64_t reserved5 : 2; /* 127..126 */ + /* 128 */ + uint64_t TargetRectLeft : 14; /* 13..0 */ + uint64_t reserved6 : 2; /* 15..14 */ + uint64_t TargetRectRight : 14; /* 29..16 */ + uint64_t reserved7 : 2; /* 31..30 */ + uint64_t TargetRectTop : 14; /* 45..32 */ + uint64_t reserved8 : 2; /* 47..46 */ + uint64_t TargetRectBottom : 14; /* 61..48 */ + uint64_t reserved9 : 2; /* 63..62 */ + uint64_t SurfaceWidth : 14; /* 77..64 */ + uint64_t reserved10 : 2; /* 79..78 */ + uint64_t SurfaceHeight : 14; /* 93..80 */ + uint64_t reserved11 : 2; /* 95..94 */ + uint64_t BlkKind : 4; /* 99..96 */ + uint64_t BlkHeight : 4; /* 103..100 */ + uint64_t OutputFlipX : 1; /* 104 */ + uint64_t OutputFlipY : 1; /* 105 */ + uint64_t OutputTranspose : 1; /* 106 */ + uint64_t reserved12 : 21; /* 127..107 */ +} Blending0Struct; + +typedef struct { + uint64_t AlphaK1 : 10; /* 9..0 */ + uint64_t reserved0 : 6; /* 15..10 */ + uint64_t AlphaK2 : 10; /* 25..16 */ + uint64_t reserved1 : 6; /* 31..26 */ + uint64_t SrcFactCMatchSelect : 3; /* 34..32 */ + uint64_t reserved2 : 1; /* 35 */ + uint64_t DstFactCMatchSelect : 3; /* 38..36 */ + uint64_t reserved3 : 1; /* 39 */ + uint64_t SrcFactAMatchSelect : 3; /* 42..40 */ + uint64_t reserved4 : 1; /* 43 */ + uint64_t DstFactAMatchSelect : 3; /* 46..44 */ + uint64_t reserved5 : 1; /* 47 */ + uint64_t reserved6 : 4; /* 51..48 */ + uint64_t reserved7 : 4; /* 55..52 */ + uint64_t reserved8 : 4; /* 59..56 */ + uint64_t reserved9 : 4; /* 63..60 */ + uint64_t reserved10 : 2; /* 65..64 */ + uint64_t OverrideR : 10; /* 75..66 */ + uint64_t OverrideG : 10; /* 85..76 */ + uint64_t OverrideB : 10; /* 95..86 */ + uint64_t OverrideA : 10; /* 105..96 */ + uint64_t reserved11 : 2; /* 107..106 */ + uint64_t UseOverrideR : 1; /* 108 */ + uint64_t UseOverrideG : 1; /* 109 */ + uint64_t UseOverrideB : 1; /* 110 */ + uint64_t UseOverrideA : 1; /* 111 */ + uint64_t MaskR : 1; /* 112 */ + uint64_t MaskG : 1; /* 113 */ + uint64_t MaskB : 1; /* 114 */ + uint64_t MaskA : 1; /* 115 */ + uint64_t reserved12 : 12; /* 127..116 */ +} BlendingSurfaceStruct; + +typedef struct { + uint64_t TargetRectLeft : 14; /* 13..0 */ + uint64_t reserved0 : 2; /* 15..14 */ + uint64_t TargetRectRight : 14; /* 29..16 */ + uint64_t reserved1 : 2; /* 31..30 */ + uint64_t TargetRectTop : 14; /* 45..32 */ + uint64_t reserved2 : 2; /* 47..46 */ + uint64_t TargetRectBottom : 14; /* 61..48 */ + uint64_t reserved3 : 2; /* 63..62 */ + uint64_t Enable0 : 8; /* 71..64 */ + uint64_t Enable1 : 8; /* 79..72 */ + uint64_t Enable2 : 8; /* 87..80 */ + uint64_t Enable3 : 8; /* 95..88 */ + uint64_t Enable4 : 8; /* 103..96 */ + uint64_t DownsampleHoriz : 11; /* 114..104 */ + uint64_t reserved4 : 1; /* 115 */ + uint64_t DownsampleVert : 11; /* 126..116 */ + uint64_t reserved5 : 1; /* 127 */ + /* 128 */ + uint64_t FilterNoise0 : 10; /* 9..0 */ + uint64_t FilterDetail0 : 10; /* 19..10 */ + uint64_t FilterNoise1 : 10; /* 29..20 */ + uint64_t reserved6 : 2; /* 31..30 */ + uint64_t FilterDetail1 : 10; /* 41..32 */ + uint64_t FilterNoise2 : 10; /* 51..42 */ + uint64_t FilterDetail2 : 10; /* 61..52 */ + uint64_t reserved7 : 2; /* 63..62 */ + uint64_t FilterNoise3 : 10; /* 73..64 */ + uint64_t FilterDetail3 : 10; /* 83..74 */ + uint64_t FilterNoise4 : 10; /* 93..84 */ + uint64_t reserved8 : 2; /* 95..94 */ + uint64_t FilterDetail4 : 10; /* 105..96 */ + uint64_t reserved9 : 22; /* 127..106 */ + /* 256 */ + uint64_t ChromaNoise0 : 10; /* 9..0 */ + uint64_t ChromaDetail0 : 10; /* 19..10 */ + uint64_t ChromaNoise1 : 10; /* 29..20 */ + uint64_t reserved10 : 2; /* 31..30 */ + uint64_t ChromaDetail1 : 10; /* 41..32 */ + uint64_t ChromaNoise2 : 10; /* 51..42 */ + uint64_t ChromaDetail2 : 10; /* 61..52 */ + uint64_t reserved11 : 2; /* 63..62 */ + uint64_t ChromaNoise3 : 10; /* 73..64 */ + uint64_t ChromaDetail3 : 10; /* 83..74 */ + uint64_t ChromaNoise4 : 10; /* 93..84 */ + uint64_t reserved12 : 2; /* 95..94 */ + uint64_t ChromaDetail4 : 10; /* 105..96 */ + uint64_t reserved13 : 22; /* 127..106 */ + /* 384 */ + uint64_t Mode0 : 4; /* 3..0 */ + uint64_t AccumWeight0 : 3; /* 6..4 */ + uint64_t Iir0 : 11; /* 17..7 */ + uint64_t reserved14 : 2; /* 19..18 */ + uint64_t Mode1 : 4; /* 23..20 */ + uint64_t AccumWeight1 : 3; /* 26..24 */ + uint64_t Iir1 : 11; /* 37..27 */ + uint64_t reserved15 : 2; /* 39..38 */ + uint64_t Mode2 : 4; /* 43..40 */ + uint64_t AccumWeight2 : 3; /* 46..44 */ + uint64_t Iir2 : 11; /* 57..47 */ + uint64_t reserved16 : 6; /* 63..58 */ + uint64_t Mode3 : 4; /* 67..64 */ + uint64_t AccumWeight3 : 3; /* 70..68 */ + uint64_t Iir3 : 11; /* 81..71 */ + uint64_t reserved17 : 2; /* 83..82 */ + uint64_t Mode4 : 4; /* 87..84 */ + uint64_t AccumWeight4 : 3; /* 90..88 */ + uint64_t Iir4 : 11; /* 101..91 */ + uint64_t reserved18 : 8; /* 109..102 */ + uint64_t OutputFlipX : 1; /* 110 */ + uint64_t OutputFlipY : 1; /* 111 */ + uint64_t reserved19 : 10; /* 121..112 */ + uint64_t reserved20 : 6; /* 127..122 */ +} FetchControl0Struct; + +typedef struct { + uint64_t f00 : 10; /* 9..0 */ + uint64_t f10 : 10; /* 19..10 */ + uint64_t f20 : 10; /* 29..20 */ + uint64_t reserved0 : 2; /* 31..30 */ + uint64_t f01 : 10; /* 41..32 */ + uint64_t f11 : 10; /* 51..42 */ + uint64_t f21 : 10; /* 61..52 */ + uint64_t reserved1 : 2; /* 63..62 */ + uint64_t f02 : 10; /* 73..64 */ + uint64_t f12 : 10; /* 83..74 */ + uint64_t f22 : 10; /* 93..84 */ + uint64_t reserved2 : 2; /* 95..94 */ + uint64_t f03 : 10; /* 105..96 */ + uint64_t f13 : 10; /* 115..106 */ + uint64_t f23 : 10; /* 125..116 */ + uint64_t reserved3 : 2; /* 127..126 */ +} FetchControlCoeffStruct; + +typedef struct { + SurfaceCache0Struct surfaceCache0Struct; + SurfaceList0Struct surfaceList0Struct; + SurfaceListClearRectStruct surfaceListClearRectStruct[4]; + SurfaceListSurfaceStruct surfaceListSurfaceStruct[5]; + ColorConversionLumaAlphaStruct colorConversionLumaAlphaStruct[5]; + ColorConversionMatrixStruct colorConversionMatrixStruct[5]; + ColorConversionClampStruct colorConversionClampStruct[5]; + Blending0Struct blending0Struct; + BlendingSurfaceStruct blendingSurfaceStruct[5]; + FetchControl0Struct fetchControl0Struct; + FetchControlCoeffStruct fetchControlCoeffStruct[520]; +} ConfigStruct; + +#endif diff --git a/tests/tegra/vic40.c b/tests/tegra/vic40.c new file mode 100644 index 0000000..1af0925 --- /dev/null +++ b/tests/tegra/vic40.c @@ -0,0 +1,338 @@ +/* + * Copyright © 2018 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#include +#include + +#include "private.h" +#include "tegra.h" +#include "vic.h" +#include "vic40.h" + +struct vic40 { + struct vic base; + + struct { + struct drm_tegra_mapping *map; + struct drm_tegra_bo *bo; + } config; + + struct { + struct drm_tegra_mapping *map; + struct drm_tegra_bo *bo; + } filter; +}; + +static int vic40_fill(struct vic *v, struct vic_image *output, + unsigned int left, unsigned int top, + unsigned int right, unsigned int bottom, + unsigned int alpha, unsigned int red, + unsigned int green, unsigned int blue) +{ + struct vic40 *vic = container_of(v, struct vic40, base); + ConfigStruct *c; + int err; + + err = drm_tegra_bo_map(vic->config.bo, (void **)&c); + if (err < 0) { + fprintf(stderr, "failed to map configuration structure: %s\n", + strerror(-err)); + return err; + } + + memset(c, 0, sizeof(*c)); + + c->outputConfig.TargetRectTop = top; + c->outputConfig.TargetRectLeft = left; + c->outputConfig.TargetRectRight = right; + c->outputConfig.TargetRectBottom = bottom; + c->outputConfig.BackgroundAlpha = alpha; + c->outputConfig.BackgroundR = red; + c->outputConfig.BackgroundG = green; + c->outputConfig.BackgroundB = blue; + + c->outputSurfaceConfig.OutPixelFormat = output->format; + c->outputSurfaceConfig.OutBlkKind = output->kind; + c->outputSurfaceConfig.OutBlkHeight = 0; + c->outputSurfaceConfig.OutSurfaceWidth = output->width - 1; + c->outputSurfaceConfig.OutSurfaceHeight = output->height - 1; + c->outputSurfaceConfig.OutLumaWidth = output->stride - 1; + c->outputSurfaceConfig.OutLumaHeight = output->height - 1; + c->outputSurfaceConfig.OutChromaWidth = 16383; + c->outputSurfaceConfig.OutChromaHeight = 16383; + + drm_tegra_bo_unmap(vic->config.bo); + + return 0; +} + +static int vic40_blit(struct vic *v, struct vic_image *output, + struct vic_image *input) +{ + struct vic40 *vic = container_of(v, struct vic40, base); + SlotSurfaceConfig *surface; + SlotConfig *slot; + ConfigStruct *c; + int err; + + err = drm_tegra_bo_map(vic->config.bo, (void **)&c); + if (err < 0) { + fprintf(stderr, "failed to map configuration structure: %s\n", + strerror(-err)); + return err; + } + + memset(c, 0, sizeof(*c)); + + c->outputConfig.TargetRectTop = 0; + c->outputConfig.TargetRectLeft = 0; + c->outputConfig.TargetRectRight = output->width - 1; + c->outputConfig.TargetRectBottom = output->height - 1; + c->outputConfig.BackgroundAlpha = 1023; + c->outputConfig.BackgroundR = 1023; + c->outputConfig.BackgroundG = 1023; + c->outputConfig.BackgroundB = 1023; + + c->outputSurfaceConfig.OutPixelFormat = output->format; + c->outputSurfaceConfig.OutBlkKind = output->kind; + c->outputSurfaceConfig.OutBlkHeight = 0; + c->outputSurfaceConfig.OutSurfaceWidth = output->width - 1; + c->outputSurfaceConfig.OutSurfaceHeight = output->height - 1; + c->outputSurfaceConfig.OutLumaWidth = output->stride - 1; + c->outputSurfaceConfig.OutLumaHeight = output->height - 1; + c->outputSurfaceConfig.OutChromaWidth = 16383; + c->outputSurfaceConfig.OutChromaHeight = 16383; + + slot = &c->slotStruct[0].slotConfig; + slot->SlotEnable = 1; + slot->CurrentFieldEnable = 1; + slot->PlanarAlpha = 1023; + slot->ConstantAlpha = 1; + slot->SourceRectLeft = 0 << 16; + slot->SourceRectRight = (input->width - 1) << 16; + slot->SourceRectTop = 0 << 16; + slot->SourceRectBottom = (input->height - 1) << 16; + slot->DestRectLeft = 0; + slot->DestRectRight = output->width - 1; + slot->DestRectTop = 0; + slot->DestRectBottom = output->height - 1; + slot->SoftClampHigh = 1023; + + surface = &c->slotStruct[0].slotSurfaceConfig; + surface->SlotPixelFormat = input->format; + surface->SlotBlkKind = input->kind; + surface->SlotBlkHeight = 0; /* XXX */ + surface->SlotCacheWidth = VIC_CACHE_WIDTH_64Bx4; /* XXX */ + surface->SlotSurfaceWidth = input->width - 1; + surface->SlotSurfaceHeight = input->height - 1; + surface->SlotLumaWidth = input->stride - 1; + surface->SlotLumaHeight = input->height - 1; + surface->SlotChromaWidth = 16383; + surface->SlotChromaHeight = 16383; + + drm_tegra_bo_unmap(vic->config.bo); + + return 0; +} + +static int vic40_flip(struct vic *v, struct vic_image *output, + struct vic_image *input) +{ + struct vic40 *vic = container_of(v, struct vic40, base); + SlotSurfaceConfig *surface; + SlotConfig *slot; + ConfigStruct *c; + int err; + + err = drm_tegra_bo_map(vic->config.bo, (void **)&c); + if (err < 0) { + fprintf(stderr, "failed to map configuration structure: %s\n", + strerror(-err)); + return err; + } + + memset(c, 0, sizeof(*c)); + + c->outputConfig.TargetRectTop = 0; + c->outputConfig.TargetRectLeft = 0; + c->outputConfig.TargetRectRight = output->width - 1; + c->outputConfig.TargetRectBottom = output->height - 1; + c->outputConfig.BackgroundAlpha = 1023; + c->outputConfig.BackgroundR = 1023; + c->outputConfig.BackgroundG = 1023; + c->outputConfig.BackgroundB = 1023; + c->outputConfig.OutputFlipY = 1; + + c->outputSurfaceConfig.OutPixelFormat = output->format; + c->outputSurfaceConfig.OutBlkKind = output->kind; + c->outputSurfaceConfig.OutBlkHeight = 0; + c->outputSurfaceConfig.OutSurfaceWidth = output->width - 1; + c->outputSurfaceConfig.OutSurfaceHeight = output->height - 1; + c->outputSurfaceConfig.OutLumaWidth = output->stride - 1; + c->outputSurfaceConfig.OutLumaHeight = output->height - 1; + c->outputSurfaceConfig.OutChromaWidth = 16383; + c->outputSurfaceConfig.OutChromaHeight = 16383; + + slot = &c->slotStruct[0].slotConfig; + slot->SlotEnable = 1; + slot->CurrentFieldEnable = 1; + slot->PlanarAlpha = 1023; + slot->ConstantAlpha = 1; + slot->SourceRectLeft = 0 << 16; + slot->SourceRectRight = (input->width - 1) << 16; + slot->SourceRectTop = 0 << 16; + slot->SourceRectBottom = (input->height - 1) << 16; + slot->DestRectLeft = 0; + slot->DestRectRight = output->width - 1; + slot->DestRectTop = 0; + slot->DestRectBottom = output->height - 1; + slot->SoftClampHigh = 1023; + + surface = &c->slotStruct[0].slotSurfaceConfig; + surface->SlotPixelFormat = input->format; + surface->SlotBlkKind = input->kind; + surface->SlotBlkHeight = 0; /* XXX */ + surface->SlotCacheWidth = VIC_CACHE_WIDTH_64Bx4; /* XXX */ + surface->SlotSurfaceWidth = input->width - 1; + surface->SlotSurfaceHeight = input->height - 1; + surface->SlotLumaWidth = input->stride - 1; + surface->SlotLumaHeight = input->height - 1; + surface->SlotChromaWidth = 16383; + surface->SlotChromaHeight = 16383; + + drm_tegra_bo_unmap(vic->config.bo); + + return 0; +} + +static int vic40_execute(struct vic *v, struct drm_tegra_pushbuf *pushbuf, + uint32_t **ptrp, struct vic_image *output, + struct vic_image **inputs, unsigned int num_inputs) +{ + struct vic40 *vic = container_of(v, struct vic40, base); + unsigned int i; + + if (num_inputs > 1) + return -EINVAL; + + VIC_PUSH_METHOD(pushbuf, ptrp, NVB0B6_VIDEO_COMPOSITOR_SET_APPLICATION_ID, 1); + VIC_PUSH_METHOD(pushbuf, ptrp, NVB0B6_VIDEO_COMPOSITOR_SET_CONTROL_PARAMS, (sizeof(ConfigStruct) / 16) << 16); + VIC_PUSH_BUFFER(pushbuf, ptrp, NVB0B6_VIDEO_COMPOSITOR_SET_CONFIG_STRUCT_OFFSET, vic->config.map, 0, 0); + VIC_PUSH_BUFFER(pushbuf, ptrp, NVB0B6_VIDEO_COMPOSITOR_SET_OUTPUT_SURFACE_LUMA_OFFSET, output->map, 0, 0); + + for (i = 0; i < num_inputs; i++) + VIC_PUSH_BUFFER(pushbuf, ptrp, NVB0B6_VIDEO_COMPOSITOR_SET_SURFACE0_SLOT0_LUMA_OFFSET, inputs[i]->map, 0, 0); + + VIC_PUSH_METHOD(pushbuf, ptrp, NVB0B6_VIDEO_COMPOSITOR_EXECUTE, 1 << 8); + + return 0; +} + +static void vic40_free(struct vic *v) +{ + struct vic40 *vic = container_of(v, struct vic40, base); + + drm_tegra_channel_unmap(vic->filter.map); + drm_tegra_bo_unref(vic->filter.bo); + + drm_tegra_channel_unmap(vic->config.map); + drm_tegra_bo_unref(vic->config.bo); + + drm_tegra_syncpoint_free(v->syncpt); + + free(vic); +} + +static const struct vic_ops vic40_ops = { + .fill = vic40_fill, + .blit = vic40_blit, + .flip = vic40_flip, + .execute = vic40_execute, + .free = vic40_free, +}; + +int vic40_new(struct drm_tegra *drm, struct drm_tegra_channel *channel, + struct vic **vicp) +{ + struct vic40 *vic; + void *ptr; + int err; + + vic = calloc(1, sizeof(*vic)); + if (!vic) + return -ENOMEM; + + vic->base.drm = drm; + vic->base.channel = channel; + vic->base.ops = &vic40_ops; + vic->base.version = 0x21; + + err = drm_tegra_syncpoint_new(drm, &vic->base.syncpt); + if (err < 0) { + fprintf(stderr, "failed to allocate syncpoint: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_bo_new(drm, 0, 16384, &vic->config.bo); + if (err < 0) { + fprintf(stderr, "failed to allocate configuration structurer: %s\n", + strerror(-err)); + return err; + } + + err = drm_tegra_channel_map(channel, vic->config.bo, DRM_TEGRA_CHANNEL_MAP_READ, + &vic->config.map); + if (err < 0) { + fprintf(stderr, "failed to map configuration structure: %s\n", + strerror(-err)); + return err; + } + + err = drm_tegra_bo_new(drm, 0, 16384, &vic->filter.bo); + if (err < 0) { + fprintf(stderr, "failed to allocate filter buffer: %s\n", + strerror(-err)); + return err; + } + + err = drm_tegra_bo_map(vic->filter.bo, &ptr); + if (err < 0) { + fprintf(stderr, "failed to map filter buffer: %s\n", strerror(-err)); + return err; + } + + memset(ptr, 0, 16384); + drm_tegra_bo_unmap(vic->filter.bo); + + err = drm_tegra_channel_map(channel, vic->filter.bo, DRM_TEGRA_CHANNEL_MAP_READ, + &vic->filter.map); + if (err < 0) { + fprintf(stderr, "failed to map filter buffer: %s\n", + strerror(-err)); + return err; + } + + if (vicp) + *vicp = &vic->base; + + return 0; +} diff --git a/tests/tegra/vic40.h b/tests/tegra/vic40.h new file mode 100644 index 0000000..a62301a --- /dev/null +++ b/tests/tegra/vic40.h @@ -0,0 +1,285 @@ +/* + * Copyright © 2016-2018 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 VIC40_H +#define VIC40_H + +#include + +#define NVB0B6_VIDEO_COMPOSITOR_SET_APPLICATION_ID 0x00000200 +#define NVB0B6_VIDEO_COMPOSITOR_EXECUTE 0x00000300 +#define NVB0B6_VIDEO_COMPOSITOR_SET_SURFACE0_SLOT0_LUMA_OFFSET 0x00000400 +#define NVB0B6_VIDEO_COMPOSITOR_SET_SURFACE0_SLOT0_CHROMA_U_OFFSET 0x00000404 +#define NVB0B6_VIDEO_COMPOSITOR_SET_SURFACE0_SLOT0_CHROMA_V_OFFSET 0x00000408 +#define NVB0B6_VIDEO_COMPOSITOR_SET_CONTROL_PARAMS 0x00000704 +#define NVB0B6_VIDEO_COMPOSITOR_SET_CONFIG_STRUCT_OFFSET 0x00000708 +#define NVB0B6_VIDEO_COMPOSITOR_SET_HIST_OFFSET 0x00000714 +#define NVB0B6_VIDEO_COMPOSITOR_SET_OUTPUT_SURFACE_LUMA_OFFSET 0x00000720 + +typedef struct { + uint64_t SlotEnable : 1; /* 0 */ + uint64_t DeNoise : 1; /* 1 */ + uint64_t AdvancedDenoise : 1; /* 2 */ + uint64_t CadenceDetect : 1; /* 3 */ + uint64_t MotionMap : 1; /* 4 */ + uint64_t MMapCombine : 1; /* 5 */ + uint64_t IsEven : 1; /* 6 */ + uint64_t ChromaEven : 1; /* 7 */ + uint64_t CurrentFieldEnable : 1; /* 8 */ + uint64_t PrevFieldEnable : 1; /* 9 */ + uint64_t NextFieldEnable : 1; /* 10 */ + uint64_t NextNrFieldEnable : 1; /* 11 */ + uint64_t CurMotionFieldEnable : 1; /* 12 */ + uint64_t PrevMotionFieldEnable : 1; /* 13 */ + uint64_t PpMotionFieldEnable : 1; /* 14 */ + uint64_t CombMotionFieldEnable : 1; /* 15 */ + uint64_t FrameFormat : 4; /* 19..16 */ + uint64_t FilterLengthY : 2; /* 21..20 */ + uint64_t FilterLengthX : 2; /* 23..22 */ + uint64_t Panoramic : 12; /* 35..24 */ + uint64_t reserved1 : 22; /* 57..36 */ + uint64_t DetailFltClamp : 6; /* 63..58 */ + uint64_t FilterNoise : 10; /* 73..64 */ + uint64_t FilterDetail : 10; /* 83..74 */ + uint64_t ChromaNoise : 10; /* 93..84 */ + uint64_t ChromaDetail : 10; /* 103..94 */ + uint64_t DeinterlaceMode : 4; /* 107..104 */ + uint64_t MotionAccumWeight : 3; /* 110..108 */ + uint64_t NoiseIir : 11; /* 121..111 */ + uint64_t LightLevel : 4; /* 125..122 */ + uint64_t reserved4 : 2; /* 127..126 */ + /* 128 */ + uint64_t SoftClampLow : 10; /* 9..0 */ + uint64_t SoftClampHigh : 10; /* 19..10 */ + uint64_t reserved5 : 3; /* 22..20 */ + uint64_t reserved6 : 9; /* 31..23 */ + uint64_t PlanarAlpha : 10; /* 41..32 */ + uint64_t ConstantAlpha : 1; /* 42 */ + uint64_t StereoInterleave : 3; /* 45..43 */ + uint64_t ClipEnabled : 1; /* 46 */ + uint64_t ClearRectMask : 8; /* 54..47 */ + uint64_t DegammaMode : 2; /* 56..55 */ + uint64_t reserved7 : 1; /* 57 */ + uint64_t DecompressEnable : 1; /* 58 */ + uint64_t reserved9 : 5; /* 63..59 */ + uint64_t DecompressCtbCount : 8; /* 71..64 */ + uint64_t DecompressZbcColor : 32; /* 103..72 */ + uint64_t reserved12 : 24; /* 127..104 */ + /* 256 */ + uint64_t SourceRectLeft : 30; /* 29..0 */ + uint64_t reserved14 : 2; /* 31..30 */ + uint64_t SourceRectRight : 30; /* 61..32 */ + uint64_t reserved15 : 2; /* 63..62 */ + uint64_t SourceRectTop : 30; /* 93..64 */ + uint64_t reserved16 : 2; /* 95..94 */ + uint64_t SourceRectBottom : 30; /* 125..96 */ + uint64_t reserved17 : 2; /* 127..126 */ + /* 384 */ + uint64_t DestRectLeft : 14; /* 13..0 */ + uint64_t reserved18 : 2; /* 15..14 */ + uint64_t DestRectRight : 14; /* 29..16 */ + uint64_t reserved19 : 2; /* 31..30 */ + uint64_t DestRectTop : 14; /* 45..32 */ + uint64_t reserved20 : 2; /* 47..46 */ + uint64_t DestRectBottom : 14; /* 61..48 */ + uint64_t reserved21 : 2; /* 63..62 */ + uint64_t reserved22 : 32; /* 95..64 */ + uint64_t reserved23 : 32; /* 127..96 */ +} SlotConfig; + +typedef struct { + uint64_t SlotPixelFormat : 7; /* 6..0 */ + uint64_t SlotChromaLocHoriz : 2; /* 8..7 */ + uint64_t SlotChromaLocVert : 2; /* 10..9 */ + uint64_t SlotBlkKind : 4; /* 14..11 */ + uint64_t SlotBlkHeight : 4; /* 18..15 */ + uint64_t SlotCacheWidth : 3; /* 21..19 */ + uint64_t reserved0 : 10; /* 31..22 */ + uint64_t SlotSurfaceWidth : 14; /* 45..32 */ + uint64_t SlotSurfaceHeight : 14; /* 59..46 */ + uint64_t reserved1 : 4; /* 63..60 */ + uint64_t SlotLumaWidth : 14; /* 77..64 */ + uint64_t SlotLumaHeight : 14; /* 91..78 */ + uint64_t reserved2 : 4; /* 95..92 */ + uint64_t SlotChromaWidth : 14; /* 109..96 */ + uint64_t SlotChromaHeight : 14; /* 123..110 */ + uint64_t reserved3 : 4; /* 127..124 */ +} SlotSurfaceConfig; + +typedef struct { + uint64_t luma_coeff0 : 20; /* 19..0 */ + uint64_t luma_coeff1 : 20; /* 39..20 */ + uint64_t luma_coeff2 : 20; /* 59..40 */ + uint64_t luma_r_shift : 4; /* 63..60 */ + uint64_t luma_coeff3 : 20; /* 83..64 */ + uint64_t LumaKeyLower : 10; /* 93..84 */ + uint64_t LumaKeyUpper : 10; /* 103..94 */ + uint64_t LumaKeyEnabled : 1; /* 104 */ + uint64_t reserved0 : 2; /* 106..105 */ + uint64_t reserved1 : 21; /* 127..107 */ +} LumaKeyStruct; + +typedef struct { + uint64_t matrix_coeff00 : 20; /* 19..0 */ + uint64_t matrix_coeff10 : 20; /* 39..20 */ + uint64_t matrix_coeff20 : 20; /* 59..40 */ + uint64_t matrix_r_shift : 4; /* 63..60 */ + uint64_t matrix_coeff01 : 20; /* 83..64 */ + uint64_t matrix_coeff11 : 20; /* 103..84 */ + uint64_t matrix_coeff21 : 20; /* 123..104 */ + uint64_t reserved0 : 3; /* 126..124 */ + uint64_t matrix_enable : 1; /* 127 */ + /* 128 */ + uint64_t matrix_coeff02 : 20; /* 19..0 */ + uint64_t matrix_coeff12 : 20; /* 39..20 */ + uint64_t matrix_coeff22 : 20; /* 59..40 */ + uint64_t reserved1 : 4; /* 63..60 */ + uint64_t matrix_coeff03 : 20; /* 83..64 */ + uint64_t matrix_coeff13 : 20; /* 103..84 */ + uint64_t matrix_coeff23 : 20; /* 123..104 */ + uint64_t reserved2 : 4; /* 127..124 */ +} MatrixStruct; + +typedef struct { + uint64_t ClearRect0Left : 14; /* 13..0 */ + uint64_t reserved0 : 2; /* 15..14 */ + uint64_t ClearRect0Right : 14; /* 29..16 */ + uint64_t reserved1 : 2; /* 31..30 */ + uint64_t ClearRect0Top : 14; /* 45..32 */ + uint64_t reserved2 : 2; /* 47..46 */ + uint64_t ClearRect0Bottom : 14; /* 61..48 */ + uint64_t reserved3 : 2; /* 63..62 */ + uint64_t ClearRect1Left : 14; /* 77..64 */ + uint64_t reserved4 : 2; /* 79..78 */ + uint64_t ClearRect1Right : 14; /* 93..80 */ + uint64_t reserved5 : 2; /* 95..94 */ + uint64_t ClearRect1Top : 14; /* 109..96 */ + uint64_t reserved6 : 2; /* 111..110 */ + uint64_t ClearRect1Bottom : 14; /* 125..112 */ + uint64_t reserved7 : 2; /* 127..126 */ +} ClearRectStruct; + +typedef struct { + uint64_t AlphaK1 : 10; /* 9..0 */ + uint64_t reserved0 : 6; /* 15..10 */ + uint64_t AlphaK2 : 10; /* 25..16 */ + uint64_t reserved1 : 6; /* 31..26 */ + uint64_t SrcFactCMatchSelect : 3; /* 34..32 */ + uint64_t reserved2 : 1; /* 35 */ + uint64_t DstFactCMatchSelect : 3; /* 38..36 */ + uint64_t reserved3 : 1; /* 39 */ + uint64_t SrcFactAMatchSelect : 3; /* 42..40 */ + uint64_t reserved4 : 1; /* 43 */ + uint64_t DstFactAMatchSelect : 3; /* 46..44 */ + uint64_t reserved5 : 1; /* 47 */ + uint64_t reserved6 : 4; /* 51..48 */ + uint64_t reserved7 : 4; /* 55..52 */ + uint64_t reserved8 : 4; /* 59..56 */ + uint64_t reserved9 : 4; /* 63..60 */ + uint64_t reserved10 : 2; /* 65..64 */ + uint64_t OverrideR : 10; /* 75..66 */ + uint64_t OverrideG : 10; /* 85..76 */ + uint64_t OverrideB : 10; /* 95..86 */ + uint64_t OverrideA : 10; /* 105..96 */ + uint64_t reserved11 : 2; /* 107..106 */ + uint64_t UseOverrideR : 1; /* 108 */ + uint64_t UseOverrideG : 1; /* 109 */ + uint64_t UseOverrideB : 1; /* 110 */ + uint64_t UseOverrideA : 1; /* 111 */ + uint64_t MaskR : 1; /* 112 */ + uint64_t MaskG : 1; /* 113 */ + uint64_t MaskB : 1; /* 114 */ + uint64_t MaskA : 1; /* 115 */ + uint64_t reserved12 : 12; /* 127..116 */ +} BlendingSlotStruct; + +typedef struct { + uint64_t AlphaFillMode : 3; /* 2..0 */ + uint64_t AlphaFillSlot : 3; /* 5..3 */ + uint64_t BackgroundAlpha : 10; /* 15..6 */ + uint64_t BackgroundR : 10; /* 25..16 */ + uint64_t BackgroundG : 10; /* 35..26 */ + uint64_t BackgroundB : 10; /* 45..36 */ + uint64_t RegammaMode : 2; /* 47..46 */ + uint64_t OutputFlipX : 1; /* 48 */ + uint64_t OutputFlipY : 1; /* 49 */ + uint64_t OutputTranspose : 1; /* 50 */ + uint64_t reserved1 : 1; /* 51 */ + uint64_t reserved2 : 12; /* 63..52 */ + uint64_t TargetRectLeft : 14; /* 77..64 */ + uint64_t reserved3 : 2; /* 79..78 */ + uint64_t TargetRectRight : 14; /* 93..80 */ + uint64_t reserved4 : 2; /* 95..94 */ + uint64_t TargetRectTop : 14; /* 109..96 */ + uint64_t reserved5 : 2; /* 111..110 */ + uint64_t TargetRectBottom : 14; /* 125..112 */ + uint64_t reserved6 : 2; /* 127..126 */ +} OutputConfig; + +typedef struct { + uint64_t OutPixelFormat : 7; /* 6..0 */ + uint64_t OutChromaLocHoriz : 2; /* 8..7 */ + uint64_t OutChromaLocVert : 2; /* 10..9 */ + uint64_t OutBlkKind : 4; /* 14..11 */ + uint64_t OutBlkHeight : 4; /* 18..15 */ + uint64_t reserved0 : 3; /* 21..19 */ + uint64_t reserved1 : 10; /* 31..22 */ + uint64_t OutSurfaceWidth : 14; /* 45..32 */ + uint64_t OutSurfaceHeight : 14; /* 59..46 */ + uint64_t reserved2 : 4; /* 63..60 */ + uint64_t OutLumaWidth : 14; /* 77..64 */ + uint64_t OutLumaHeight : 14; /* 91..78 */ + uint64_t reserved3 : 4; /* 95..92 */ + uint64_t OutChromaWidth : 14; /* 109..96 */ + uint64_t OutChromaHeight : 14; /* 123..110 */ + uint64_t reserved4 : 4; /* 127..124 */ +} OutputSurfaceConfig; + +typedef struct { + uint64_t DownsampleHoriz : 11; /* 10..0 */ + uint64_t reserved0 : 5; /* 15..11 */ + uint64_t DownsampleVert : 11; /* 26..16 */ + uint64_t reserved1 : 5; /* 31..27 */ + uint64_t reserved2 : 32; /* 63..32 */ + uint64_t reserved3 : 32; /* 95..64 */ + uint64_t reserved4 : 32; /* 127..96 */ +} PipeConfig; + +typedef struct { + SlotConfig slotConfig; + SlotSurfaceConfig slotSurfaceConfig; + LumaKeyStruct lumaKeyStruct; + MatrixStruct colorMatrixStruct; + MatrixStruct gamutMatrixStruct; + BlendingSlotStruct blendingSlotStruct; +} SlotStruct; + +typedef struct { + PipeConfig pipeConfig; + OutputConfig outputConfig; + OutputSurfaceConfig outputSurfaceConfig; + MatrixStruct outColorMatrixStruct; + ClearRectStruct clearRectStruct[4]; + SlotStruct slotStruct[8]; +} ConfigStruct; + +#endif diff --git a/tests/tegra/vic41.c b/tests/tegra/vic41.c new file mode 100644 index 0000000..edbc748 --- /dev/null +++ b/tests/tegra/vic41.c @@ -0,0 +1,342 @@ +/* + * Copyright © 2018 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#include +#include + +#include "private.h" +#include "tegra.h" +#include "vic.h" +#include "vic41.h" + +struct vic41 { + struct vic base; + + struct { + struct drm_tegra_mapping *map; + struct drm_tegra_bo *bo; + } config; + + struct { + struct drm_tegra_mapping *map; + struct drm_tegra_bo *bo; + } filter; +}; + +static int vic41_fill(struct vic *v, struct vic_image *output, + unsigned int left, unsigned int top, + unsigned int right, unsigned int bottom, + unsigned int alpha, unsigned int red, + unsigned int green, unsigned int blue) +{ + struct vic41 *vic = container_of(v, struct vic41, base); + ConfigStruct *c; + int err; + + err = drm_tegra_bo_map(vic->config.bo, (void **)&c); + if (err < 0) { + fprintf(stderr, "failed to map configuration structure: %s\n", + strerror(-err)); + return err; + } + + memset(c, 0, sizeof(*c)); + + c->outputConfig.TargetRectTop = top; + c->outputConfig.TargetRectLeft = left; + c->outputConfig.TargetRectRight = right; + c->outputConfig.TargetRectBottom = bottom; + c->outputConfig.BackgroundAlpha = alpha; + c->outputConfig.BackgroundR = red; + c->outputConfig.BackgroundG = green; + c->outputConfig.BackgroundB = blue; + + c->outputSurfaceConfig.OutPixelFormat = output->format; + c->outputSurfaceConfig.OutBlkKind = output->kind; + c->outputSurfaceConfig.OutBlkHeight = 0; + c->outputSurfaceConfig.OutSurfaceWidth = output->width - 1; + c->outputSurfaceConfig.OutSurfaceHeight = output->height - 1; + c->outputSurfaceConfig.OutLumaWidth = output->stride - 1; + c->outputSurfaceConfig.OutLumaHeight = output->height - 1; + c->outputSurfaceConfig.OutChromaWidth = 16383; + c->outputSurfaceConfig.OutChromaHeight = 16383; + + drm_tegra_bo_unmap(vic->config.bo); + + return 0; +} + +static int vic41_blit(struct vic *v, struct vic_image *output, + struct vic_image *input) +{ + struct vic41 *vic = container_of(v, struct vic41, base); + SlotSurfaceConfig *surface; + SlotConfig *slot; + ConfigStruct *c; + int err; + + err = drm_tegra_bo_map(vic->config.bo, (void **)&c); + if (err < 0) { + fprintf(stderr, "failed to map configuration structure: %s\n", + strerror(-err)); + return err; + } + + memset(c, 0, sizeof(*c)); + + c->outputConfig.TargetRectTop = 0; + c->outputConfig.TargetRectLeft = 0; + c->outputConfig.TargetRectRight = output->width - 1; + c->outputConfig.TargetRectBottom = output->height - 1; + c->outputConfig.BackgroundAlpha = 255; + c->outputConfig.BackgroundR = 1023; + c->outputConfig.BackgroundG = 1023; + c->outputConfig.BackgroundB = 1023; + + c->outputSurfaceConfig.OutPixelFormat = output->format; + c->outputSurfaceConfig.OutBlkKind = output->kind; + c->outputSurfaceConfig.OutBlkHeight = 0; + c->outputSurfaceConfig.OutSurfaceWidth = output->width - 1; + c->outputSurfaceConfig.OutSurfaceHeight = output->height - 1; + c->outputSurfaceConfig.OutLumaWidth = output->stride - 1; + c->outputSurfaceConfig.OutLumaHeight = output->height - 1; + c->outputSurfaceConfig.OutChromaWidth = 16383; + c->outputSurfaceConfig.OutChromaHeight = 16383; + + slot = &c->slotStruct[0].slotConfig; + slot->SlotEnable = 1; + slot->CurrentFieldEnable = 1; + slot->PlanarAlpha = 255; + slot->ConstantAlpha = 1; + slot->SourceRectLeft = 0 << 16; + slot->SourceRectRight = (input->width - 1) << 16; + slot->SourceRectTop = 0 << 16; + slot->SourceRectBottom = (input->height - 1) << 16; + slot->DestRectLeft = 0; + slot->DestRectRight = output->width - 1; + slot->DestRectTop = 0; + slot->DestRectBottom = output->height - 1; + slot->SoftClampHigh = 1023; + + surface = &c->slotStruct[0].slotSurfaceConfig; + surface->SlotPixelFormat = input->format; + surface->SlotBlkKind = input->kind; + surface->SlotBlkHeight = 0; /* XXX */ + surface->SlotCacheWidth = VIC_CACHE_WIDTH_64Bx4; /* XXX */ + surface->SlotSurfaceWidth = input->width - 1; + surface->SlotSurfaceHeight = input->height - 1; + surface->SlotLumaWidth = input->stride - 1; + surface->SlotLumaHeight = input->height - 1; + surface->SlotChromaWidth = 16383; + surface->SlotChromaHeight = 16383; + + drm_tegra_bo_unmap(vic->config.bo); + + return 0; +} + +static int vic41_flip(struct vic *v, struct vic_image *output, + struct vic_image *input) +{ + struct vic41 *vic = container_of(v, struct vic41, base); + SlotSurfaceConfig *surface; + SlotConfig *slot; + ConfigStruct *c; + int err; + + err = drm_tegra_bo_map(vic->config.bo, (void **)&c); + if (err < 0) { + fprintf(stderr, "failed to map configuration structure: %s\n", + strerror(-err)); + return err; + } + + memset(c, 0, sizeof(*c)); + + c->outputConfig.TargetRectTop = 0; + c->outputConfig.TargetRectLeft = 0; + c->outputConfig.TargetRectRight = output->width - 1; + c->outputConfig.TargetRectBottom = output->height - 1; + c->outputConfig.BackgroundAlpha = 255; + c->outputConfig.BackgroundR = 1023; + c->outputConfig.BackgroundG = 1023; + c->outputConfig.BackgroundB = 1023; + c->outputConfig.OutputFlipY = 1; + + c->outputSurfaceConfig.OutPixelFormat = output->format; + c->outputSurfaceConfig.OutBlkKind = output->kind; + c->outputSurfaceConfig.OutBlkHeight = 0; + c->outputSurfaceConfig.OutSurfaceWidth = output->width - 1; + c->outputSurfaceConfig.OutSurfaceHeight = output->height - 1; + c->outputSurfaceConfig.OutLumaWidth = output->stride - 1; + c->outputSurfaceConfig.OutLumaHeight = output->height - 1; + c->outputSurfaceConfig.OutChromaWidth = 16383; + c->outputSurfaceConfig.OutChromaHeight = 16383; + + slot = &c->slotStruct[0].slotConfig; + slot->SlotEnable = 1; + slot->CurrentFieldEnable = 1; + slot->PlanarAlpha = 255; + slot->ConstantAlpha = 1; + slot->SourceRectLeft = 0 << 16; + slot->SourceRectRight = (input->width - 1) << 16; + slot->SourceRectTop = 0 << 16; + slot->SourceRectBottom = (input->height - 1) << 16; + slot->DestRectLeft = 0; + slot->DestRectRight = output->width - 1; + slot->DestRectTop = 0; + slot->DestRectBottom = output->height - 1; + slot->SoftClampHigh = 1023; + + surface = &c->slotStruct[0].slotSurfaceConfig; + surface->SlotPixelFormat = input->format; + surface->SlotBlkKind = input->kind; + surface->SlotBlkHeight = 0; /* XXX */ + surface->SlotCacheWidth = VIC_CACHE_WIDTH_64Bx4; /* XXX */ + surface->SlotSurfaceWidth = input->width - 1; + surface->SlotSurfaceHeight = input->height - 1; + surface->SlotLumaWidth = input->stride - 1; + surface->SlotLumaHeight = input->height - 1; + surface->SlotChromaWidth = 16383; + surface->SlotChromaHeight = 16383; + + drm_tegra_bo_unmap(vic->config.bo); + + return 0; +} + +static int vic41_execute(struct vic *v, struct drm_tegra_pushbuf *pushbuf, + uint32_t **ptrp, struct vic_image *output, + struct vic_image **inputs, unsigned int num_inputs) +{ + struct vic41 *vic = container_of(v, struct vic41, base); + unsigned int i; + + if (num_inputs > 1) + return -EINVAL; + + VIC_PUSH_METHOD(pushbuf, ptrp, NVB1B6_VIDEO_COMPOSITOR_SET_APPLICATION_ID, 1); + VIC_PUSH_METHOD(pushbuf, ptrp, NVB1B6_VIDEO_COMPOSITOR_SET_CONTROL_PARAMS, (sizeof(ConfigStruct) / 16) << 16); + VIC_PUSH_BUFFER(pushbuf, ptrp, NVB1B6_VIDEO_COMPOSITOR_SET_CONFIG_STRUCT_OFFSET, vic->config.map, 0, 0); + VIC_PUSH_BUFFER(pushbuf, ptrp, NVB1B6_VIDEO_COMPOSITOR_SET_FILTER_STRUCT_OFFSET, vic->filter.map, 0, 0); + VIC_PUSH_BUFFER(pushbuf, ptrp, NVB1B6_VIDEO_COMPOSITOR_SET_OUTPUT_SURFACE_LUMA_OFFSET, output->map, 0, 0); + + for (i = 0; i < num_inputs; i++) { + uint32_t method = NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE0_LUMA_OFFSET(0) + (i * 3) * 4; + + VIC_PUSH_BUFFER(pushbuf, ptrp, method, inputs[i]->map, 0, 0); + } + + VIC_PUSH_METHOD(pushbuf, ptrp, NVB1B6_VIDEO_COMPOSITOR_EXECUTE, 1 << 8); + + return 0; +} + +static void vic41_free(struct vic *v) +{ + struct vic41 *vic = container_of(v, struct vic41, base); + + drm_tegra_channel_unmap(vic->filter.map); + drm_tegra_bo_unref(vic->filter.bo); + + drm_tegra_channel_unmap(vic->config.map); + drm_tegra_bo_unref(vic->config.bo); + + drm_tegra_syncpoint_free(v->syncpt); + + free(vic); +} + +static const struct vic_ops vic41_ops = { + .fill = vic41_fill, + .blit = vic41_blit, + .flip = vic41_flip, + .execute = vic41_execute, + .free = vic41_free, +}; + +int vic41_new(struct drm_tegra *drm, struct drm_tegra_channel *channel, + struct vic **vicp) +{ + struct vic41 *vic; + void *ptr; + int err; + + vic = calloc(1, sizeof(*vic)); + if (!vic) + return -ENOMEM; + + vic->base.drm = drm; + vic->base.channel = channel; + vic->base.ops = &vic41_ops; + vic->base.version = 0x18; + + err = drm_tegra_syncpoint_new(drm, &vic->base.syncpt); + if (err < 0) { + fprintf(stderr, "failed to allocate syncpoint: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_bo_new(drm, 0, 16384, &vic->config.bo); + if (err < 0) { + fprintf(stderr, "failed to allocate configuration structurer: %s\n", + strerror(-err)); + return err; + } + + err = drm_tegra_channel_map(channel, vic->config.bo, DRM_TEGRA_CHANNEL_MAP_READ, + &vic->config.map); + if (err < 0) { + fprintf(stderr, "failed to map configuration structure: %s\n", + strerror(-err)); + return err; + } + + err = drm_tegra_bo_new(drm, 0, 16384, &vic->filter.bo); + if (err < 0) { + fprintf(stderr, "failed to allocate filter buffer: %s\n", + strerror(-err)); + return err; + } + + err = drm_tegra_bo_map(vic->filter.bo, &ptr); + if (err < 0) { + fprintf(stderr, "failed to map filter buffer: %s\n", strerror(-err)); + return err; + } + + memset(ptr, 0, 16384); + drm_tegra_bo_unmap(vic->filter.bo); + + err = drm_tegra_channel_map(channel, vic->filter.bo, DRM_TEGRA_CHANNEL_MAP_READ, + &vic->filter.map); + if (err < 0) { + fprintf(stderr, "failed to map filter buffer: %s\n", + strerror(-err)); + return err; + } + + if (vicp) + *vicp = &vic->base; + + return 0; +} diff --git a/tests/tegra/vic41.h b/tests/tegra/vic41.h new file mode 100644 index 0000000..07d7019 --- /dev/null +++ b/tests/tegra/vic41.h @@ -0,0 +1,372 @@ +/* + * Copyright © 2018 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 VIC41_H +#define VIC41_H + +#include + +#define NVB1B6_VIDEO_COMPOSITOR_SET_APPLICATION_ID 0x00000200 +#define NVB1B6_VIDEO_COMPOSITOR_EXECUTE 0x00000300 +#define NVB1B6_VIDEO_COMPOSITOR_SET_PICTURE_INDEX 0x00000700 +#define NVB1B6_VIDEO_COMPOSITOR_SET_CONTROL_PARAMS 0x00000704 +#define NVB1B6_VIDEO_COMPOSITOR_SET_CONFIG_STRUCT_OFFSET 0x00000708 +#define NVB1B6_VIDEO_COMPOSITOR_SET_FILTER_STRUCT_OFFSET 0x0000070c +#define NVB1B6_VIDEO_COMPOSITOR_SET_HIST_OFFSET 0x00000714 +#define NVB1B6_VIDEO_COMPOSITOR_SET_OUTPUT_SURFACE_LUMA_OFFSET 0x00000720 +#define NVB1B6_VIDEO_COMPOSITOR_SET_HISTORY_BUFFER_OFFSET(slot) (0x00000780 + (slot) * 4) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE0_LUMA_OFFSET(slot) (0x00001200 + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE0_CHROMA_U_OFFSET(slot) (0x00001204 + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE0_CHROMA_V_OFFSET(slot) (0x00001208 + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE1_LUMA_OFFSET(slot) (0x0000120c + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE1_CHROMA_U_OFFSET(slot) (0x00001210 + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE1_CHROMA_V_OFFSET(slot) (0x00001214 + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE2_LUMA_OFFSET(slot) (0x00001218 + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE2_CHROMA_U_OFFSET(slot) (0x0000121c + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE2_CHROMA_V_OFFSET(slot) (0x00001220 + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE3_LUMA_OFFSET(slot) (0x00001224 + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE3_CHROMA_U_OFFSET(slot) (0x00001228 + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE3_CHROMA_V_OFFSET(slot) (0x0000122c + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE4_LUMA_OFFSET(slot) (0x00001230 + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE4_CHROMA_U_OFFSET(slot) (0x00001234 + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE4_CHROMA_V_OFFSET(slot) (0x00001238 + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE5_LUMA_OFFSET(slot) (0x0000123c + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE5_CHROMA_U_OFFSET(slot) (0x00001240 + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE5_CHROMA_V_OFFSET(slot) (0x00001244 + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE6_LUMA_OFFSET(slot) (0x00001248 + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE6_CHROMA_U_OFFSET(slot) (0x0000124c + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE6_CHROMA_V_OFFSET(slot) (0x00001250 + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE7_LUMA_OFFSET(slot) (0x00001254 + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE7_CHROMA_U_OFFSET(slot) (0x00001258 + (slot) * 0x00000060) +#define NVB1B6_VIDEO_COMPOSITOR_SET_SURFACE7_CHROMA_V_OFFSET(slot) (0x0000125c + (slot) * 0x00000060) + +typedef struct { + uint64_t SlotEnable : 1; /* 0 */ + uint64_t DeNoise : 1; /* 1 */ + uint64_t AdvancedDenoise : 1; /* 2 */ + uint64_t CadenceDetect : 1; /* 3 */ + uint64_t MotionMap : 1; /* 4 */ + uint64_t MMapCombine : 1; /* 5 */ + uint64_t IsEven : 1; /* 6 */ + uint64_t ChromaEven : 1; /* 7 */ + uint64_t CurrentFieldEnable : 1; /* 8 */ + uint64_t PrevFieldEnable : 1; /* 9 */ + uint64_t NextFieldEnable : 1; /* 10 */ + uint64_t NextNrFieldEnable : 1; /* 11 */ + uint64_t CurMotionFieldEnable : 1; /* 12 */ + uint64_t PrevMotionFieldEnable : 1; /* 13 */ + uint64_t PpMotionFieldEnable : 1; /* 14 */ + uint64_t CombMotionFieldEnable : 1; /* 15 */ + uint64_t FrameFormat : 4; /* 19..16 */ + uint64_t FilterLengthY : 2; /* 21..20 */ + uint64_t FilterLengthX : 2; /* 23..22 */ + uint64_t Panoramic : 12; /* 35..24 */ + uint64_t ChromaUpLengthY : 2; /* 37..36 */ + uint64_t ChromaUpLengthX : 2; /* 39..38 */ + uint64_t reserved1 : 18; /* 57..40 */ + uint64_t DetailFltClamp : 6; /* 63..58 */ + uint64_t FilterNoise : 10; /* 73..64 */ + uint64_t FilterDetail : 10; /* 83..74 */ + uint64_t ChromaNoise : 10; /* 93..84 */ + uint64_t ChromaDetail : 10; /* 103..94 */ + uint64_t DeinterlaceMode : 4; /* 107..104 */ + uint64_t MotionAccumWeight : 3; /* 110..108 */ + uint64_t NoiseIir : 11; /* 121..111 */ + uint64_t LightLevel : 4; /* 125..122 */ + uint64_t reserved4 : 2; /* 127..126 */ + /* 128 */ + uint64_t SoftClampLow : 10; /* 9..0 */ + uint64_t SoftClampHigh : 10; /* 19..10 */ + uint64_t reserved5 : 12; /* 31..20 */ + uint64_t reserved6 : 2; /* 33..32 */ + uint64_t PlanarAlpha : 8; /* 41..34 */ + uint64_t ConstantAlpha : 1; /* 42 */ + uint64_t StereoInterleave : 3; /* 45..43 */ + uint64_t ClipEnabled : 1; /* 46 */ + uint64_t ClearRectMask : 8; /* 54..47 */ + uint64_t DegammaMode : 2; /* 56..55 */ + uint64_t reserved7 : 1; /* 57 */ + uint64_t DecompressEnable : 1; /* 58 */ + uint64_t DecompressKind : 4; /* 62..59 */ + uint64_t reserved9 : 1; /* 63 */ + uint64_t DecompressCtbCount : 8; /* 71..64 */ + uint64_t DecompressZbcColor : 32; /* 103..72 */ + uint64_t reserved12 : 24; /* 127..104 */ + /* 256 */ + uint64_t SourceRectLeft : 30; /* 29..0 */ + uint64_t reserved14 : 2; /* 31..30 */ + uint64_t SourceRectRight : 30; /* 61..32 */ + uint64_t reserved15 : 2; /* 63..62 */ + uint64_t SourceRectTop : 30; /* 93..64 */ + uint64_t reserved16 : 2; /* 95..94 */ + uint64_t SourceRectBottom : 30; /* 125..96 */ + uint64_t reserved17 : 2; /* 127..126 */ + /* 384 */ + uint64_t DestRectLeft : 14; /* 13..0 */ + uint64_t reserved18 : 2; /* 15..14 */ + uint64_t DestRectRight : 14; /* 29..16 */ + uint64_t reserved19 : 2; /* 31..30 */ + uint64_t DestRectTop : 14; /* 45..32 */ + uint64_t reserved20 : 2; /* 47..46 */ + uint64_t DestRectBottom : 14; /* 61..48 */ + uint64_t reserved21 : 2; /* 63..62 */ + uint64_t reserved22 : 32; /* 95..64 */ + uint64_t reserved23 : 32; /* 127..96 */ +} SlotConfig; + +typedef struct { + uint64_t SlotPixelFormat : 7; /* 6..0 */ + uint64_t SlotChromaLocHoriz : 2; /* 8..7 */ + uint64_t SlotChromaLocVert : 2; /* 10..9 */ + uint64_t SlotBlkKind : 4; /* 14..11 */ + uint64_t SlotBlkHeight : 4; /* 18..15 */ + uint64_t SlotCacheWidth : 3; /* 21..19 */ + uint64_t reserved0 : 10; /* 31..22 */ + uint64_t SlotSurfaceWidth : 14; /* 45..32 */ + uint64_t SlotSurfaceHeight : 14; /* 59..46 */ + uint64_t reserved1 : 4; /* 63..60 */ + uint64_t SlotLumaWidth : 14; /* 77..64 */ + uint64_t SlotLumaHeight : 14; /* 91..78 */ + uint64_t reserved2 : 4; /* 95..92 */ + uint64_t SlotChromaWidth : 14; /* 109..96 */ + uint64_t SlotChromaHeight : 14; /* 123..110 */ + uint64_t reserved3 : 4; /* 127..124 */ +} SlotSurfaceConfig; + +typedef struct { + uint64_t luma_coeff0 : 20; /* 19..0 */ + uint64_t luma_coeff1 : 20; /* 39..20 */ + uint64_t luma_coeff2 : 20; /* 59..40 */ + uint64_t luma_r_shift : 4; /* 63..60 */ + uint64_t luma_coeff3 : 20; /* 83..64 */ + uint64_t LumaKeyLower : 10; /* 93..84 */ + uint64_t LumaKeyUpper : 10; /* 103..94 */ + uint64_t LumaKeyEnabled : 1; /* 104 */ + uint64_t reserved0 : 2; /* 106..105 */ + uint64_t reserved1 : 21; /* 127..107 */ +} LumaKeyStruct; + +typedef struct { + uint64_t matrix_coeff00 : 20; /* 19..0 */ + uint64_t matrix_coeff10 : 20; /* 39..20 */ + uint64_t matrix_coeff20 : 20; /* 59..40 */ + uint64_t matrix_r_shift : 4; /* 63..60 */ + uint64_t matrix_coeff01 : 20; /* 83..64 */ + uint64_t matrix_coeff11 : 20; /* 103..84 */ + uint64_t matrix_coeff21 : 20; /* 123..104 */ + uint64_t reserved0 : 3; /* 126..124 */ + uint64_t matrix_enable : 1; /* 127 */ + /* 128 */ + uint64_t matrix_coeff02 : 20; /* 19..0 */ + uint64_t matrix_coeff12 : 20; /* 39..20 */ + uint64_t matrix_coeff22 : 20; /* 59..40 */ + uint64_t reserved1 : 4; /* 63..60 */ + uint64_t matrix_coeff03 : 20; /* 83..64 */ + uint64_t matrix_coeff13 : 20; /* 103..84 */ + uint64_t matrix_coeff23 : 20; /* 123..104 */ + uint64_t reserved2 : 4; /* 127..124 */ +} MatrixStruct; + +typedef struct { + uint64_t ClearRect0Left : 14; /* 13..0 */ + uint64_t reserved0 : 2; /* 15..14 */ + uint64_t ClearRect0Right : 14; /* 29..16 */ + uint64_t reserved1 : 2; /* 31..30 */ + uint64_t ClearRect0Top : 14; /* 45..32 */ + uint64_t reserved2 : 2; /* 47..46 */ + uint64_t ClearRect0Bottom : 14; /* 61..48 */ + uint64_t reserved3 : 2; /* 63..62 */ + uint64_t ClearRect1Left : 14; /* 77..64 */ + uint64_t reserved4 : 2; /* 79..78 */ + uint64_t ClearRect1Right : 14; /* 93..80 */ + uint64_t reserved5 : 2; /* 95..94 */ + uint64_t ClearRect1Top : 14; /* 109..96 */ + uint64_t reserved6 : 2; /* 111..110 */ + uint64_t ClearRect1Bottom : 14; /* 125..112 */ + uint64_t reserved7 : 2; /* 127..126 */ +} ClearRectStruct; + +typedef struct { + uint64_t reserved0 : 2; /* 1..0 */ + uint64_t AlphaK1 : 8; /* 9..2 */ + uint64_t reserved1 : 6; /* 17..10 */ + uint64_t AlphaK2 : 8; /* 25..18 */ + uint64_t reserved2 : 6; /* 31..26 */ + uint64_t SrcFactCMatchSelect : 3; /* 34..32 */ + uint64_t reserved3 : 1; /* 35 */ + uint64_t DstFactCMatchSelect : 3; /* 38..36 */ + uint64_t reserved4 : 1; /* 39 */ + uint64_t SrcFactAMatchSelect : 3; /* 42..40 */ + uint64_t reserved5 : 1; /* 43 */ + uint64_t DstFactAMatchSelect : 3; /* 46..44 */ + uint64_t reserved6 : 1; /* 47 */ + uint64_t reserved7 : 4; /* 51..48 */ + uint64_t reserved8 : 4; /* 55..52 */ + uint64_t reserved9 : 4; /* 59..56 */ + uint64_t reserved10 : 4; /* 63..60 */ + uint64_t reserved11 : 2; /* 65..64 */ + uint64_t OverrideR : 10; /* 75..66 */ + uint64_t OverrideG : 10; /* 85..76 */ + uint64_t OverrideB : 10; /* 95..86 */ + uint64_t reserved12 : 2; /* 97..96 */ + uint64_t OverrideA : 8; /* 105..98 */ + uint64_t reserved13 : 2; /* 107..106 */ + uint64_t UseOverrideR : 1; /* 108 */ + uint64_t UseOverrideG : 1; /* 109 */ + uint64_t UseOverrideB : 1; /* 110 */ + uint64_t UseOverrideA : 1; /* 111 */ + uint64_t MaskR : 1; /* 112 */ + uint64_t MaskG : 1; /* 113 */ + uint64_t MaskB : 1; /* 114 */ + uint64_t MaskA : 1; /* 115 */ + uint64_t reserved14 : 12; /* 127..116 */ +} BlendingSlotStruct; + +typedef struct { + uint64_t AlphaFillMode : 3; /* 2..0 */ + uint64_t AlphaFillSlot : 3; /* 5..3 */ + uint64_t reserved0 : 2; /* 6..5 */ + uint64_t BackgroundAlpha : 8; /* 15..7 */ + uint64_t BackgroundR : 10; /* 25..16 */ + uint64_t BackgroundG : 10; /* 35..26 */ + uint64_t BackgroundB : 10; /* 45..36 */ + uint64_t RegammaMode : 2; /* 47..46 */ + uint64_t OutputFlipX : 1; /* 48 */ + uint64_t OutputFlipY : 1; /* 49 */ + uint64_t OutputTranspose : 1; /* 50 */ + uint64_t reserved1 : 1; /* 51 */ + uint64_t reserved2 : 12; /* 63..52 */ + uint64_t TargetRectLeft : 14; /* 77..64 */ + uint64_t reserved3 : 2; /* 79..78 */ + uint64_t TargetRectRight : 14; /* 93..80 */ + uint64_t reserved4 : 2; /* 95..94 */ + uint64_t TargetRectTop : 14; /* 109..96 */ + uint64_t reserved5 : 2; /* 111..110 */ + uint64_t TargetRectBottom : 14; /* 125..112 */ + uint64_t reserved6 : 2; /* 127..126 */ +} OutputConfig; + +typedef struct { + uint64_t OutPixelFormat : 7; /* 6..0 */ + uint64_t OutChromaLocHoriz : 2; /* 8..7 */ + uint64_t OutChromaLocVert : 2; /* 10..9 */ + uint64_t OutBlkKind : 4; /* 14..11 */ + uint64_t OutBlkHeight : 4; /* 18..15 */ + uint64_t reserved0 : 3; /* 21..19 */ + uint64_t reserved1 : 10; /* 31..22 */ + uint64_t OutSurfaceWidth : 14; /* 45..32 */ + uint64_t OutSurfaceHeight : 14; /* 59..46 */ + uint64_t reserved2 : 4; /* 63..60 */ + uint64_t OutLumaWidth : 14; /* 77..64 */ + uint64_t OutLumaHeight : 14; /* 91..78 */ + uint64_t reserved3 : 4; /* 95..92 */ + uint64_t OutChromaWidth : 14; /* 109..96 */ + uint64_t OutChromaHeight : 14; /* 123..110 */ + uint64_t reserved4 : 4; /* 127..124 */ +} OutputSurfaceConfig; + +typedef struct { + uint64_t f00 : 10; /* 9..0 */ + uint64_t f10 : 10; /* 19..10 */ + uint64_t f20 : 10; /* 29..20 */ + uint64_t reserved0 : 2; /* 31..30 */ + uint64_t f01 : 10; /* 41..32 */ + uint64_t f11 : 10; /* 51..42 */ + uint64_t f21 : 10; /* 61..52 */ + uint64_t reserved1 : 2; /* 63..62 */ + uint64_t f02 : 10; /* 73..64 */ + uint64_t f12 : 10; /* 83..74 */ + uint64_t f22 : 10; /* 93..84 */ + uint64_t reserved2 : 2; /* 95..94 */ + uint64_t f03 : 10; /* 105..96 */ + uint64_t f13 : 10; /* 115..106 */ + uint64_t f23 : 10; /* 125..116 */ + uint64_t reserved3 : 2; /* 127..126 */ +} FilterCoeffStruct; + +typedef struct { + uint64_t DownsampleHoriz : 11; /* 10..0 */ + uint64_t reserved0 : 5; /* 15..11 */ + uint64_t DownsampleVert : 11; /* 26..16 */ + uint64_t reserved1 : 5; /* 31..27 */ + uint64_t reserved2 : 32; /* 63..32 */ + uint64_t reserved3 : 32; /* 95..64 */ + uint64_t reserved4 : 32; /* 127..96 */ +} PipeConfig; + +typedef struct { + uint64_t OldCadence : 32; /* 31..0 */ + uint64_t OldDiff : 32; /* 63..32 */ + uint64_t OldWeave : 32; /* 95..64 */ + uint64_t OlderWeave : 32; /* 127..96 */ +} SlotHistoryBuffer; + +typedef struct { + uint64_t crc0 : 32; /* 31..0 */ + uint64_t crc1 : 32; /* 63..32 */ + uint64_t crc2 : 32; /* 95..64 */ + uint64_t crc3 : 32; /* 127..96 */ +} PartitionCrcStruct; + +typedef struct { + uint64_t crc0 : 32; /* 31..0 */ + uint64_t crc1 : 32; /* 63..32 */ +} SlotCrcStruct; + +typedef struct { + uint64_t ErrorStatus : 32; /* 31..0 */ + uint64_t CycleCount : 32; /* 63..32 */ + uint64_t reserved0 : 32; /* 95..64 */ + uint64_t reserved1 : 32; /* 127..96 */ +} StatusStruct; + +typedef struct { + SlotConfig slotConfig; + SlotSurfaceConfig slotSurfaceConfig; + LumaKeyStruct lumaKeyStruct; + MatrixStruct colorMatrixStruct; + MatrixStruct gamutMatrixStruct; + BlendingSlotStruct blendingSlotStruct; +} SlotStruct; + +typedef struct { + FilterCoeffStruct filterCoeffStruct[520]; +} FilterStruct; + +typedef struct { + PipeConfig pipeConfig; + OutputConfig outputConfig; + OutputSurfaceConfig outputSurfaceConfig; + MatrixStruct outColorMatrixStruct; + ClearRectStruct clearRectStruct[4]; + SlotStruct slotStruct[16]; +} ConfigStruct; + +typedef struct { + PartitionCrcStruct partitionCrcStruct[4]; +} InterfaceCrcStruct; + +typedef struct { + SlotCrcStruct slotCrcStruct[16]; +} InputCrcStruct; + +#endif diff --git a/tests/tegra/vic42.c b/tests/tegra/vic42.c new file mode 100644 index 0000000..068b712 --- /dev/null +++ b/tests/tegra/vic42.c @@ -0,0 +1,342 @@ +/* + * Copyright © 2018 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#include +#include + +#include "private.h" +#include "tegra.h" +#include "vic.h" +#include "vic42.h" + +struct vic42 { + struct vic base; + + struct { + struct drm_tegra_mapping *map; + struct drm_tegra_bo *bo; + } config; + + struct { + struct drm_tegra_mapping *map; + struct drm_tegra_bo *bo; + } filter; +}; + +static int vic42_fill(struct vic *v, struct vic_image *output, + unsigned int left, unsigned int top, + unsigned int right, unsigned int bottom, + unsigned int alpha, unsigned int red, + unsigned int green, unsigned int blue) +{ + struct vic42 *vic = container_of(v, struct vic42, base); + ConfigStruct *c; + int err; + + err = drm_tegra_bo_map(vic->config.bo, (void **)&c); + if (err < 0) { + fprintf(stderr, "failed to map configuration structure: %s\n", + strerror(-err)); + return err; + } + + memset(c, 0, sizeof(*c)); + + c->outputConfig.TargetRectTop = top; + c->outputConfig.TargetRectLeft = left; + c->outputConfig.TargetRectRight = right; + c->outputConfig.TargetRectBottom = bottom; + c->outputConfig.BackgroundAlpha = alpha; + c->outputConfig.BackgroundR = red; + c->outputConfig.BackgroundG = green; + c->outputConfig.BackgroundB = blue; + + c->outputSurfaceConfig.OutPixelFormat = output->format; + c->outputSurfaceConfig.OutBlkKind = output->kind; + c->outputSurfaceConfig.OutBlkHeight = 0; + c->outputSurfaceConfig.OutSurfaceWidth = output->width - 1; + c->outputSurfaceConfig.OutSurfaceHeight = output->height - 1; + c->outputSurfaceConfig.OutLumaWidth = output->stride - 1; + c->outputSurfaceConfig.OutLumaHeight = output->height - 1; + c->outputSurfaceConfig.OutChromaWidth = 16383; + c->outputSurfaceConfig.OutChromaHeight = 16383; + + drm_tegra_bo_unmap(vic->config.bo); + + return 0; +} + +static int vic42_blit(struct vic *v, struct vic_image *output, + struct vic_image *input) +{ + struct vic42 *vic = container_of(v, struct vic42, base); + SlotSurfaceConfig *surface; + SlotConfig *slot; + ConfigStruct *c; + int err; + + err = drm_tegra_bo_map(vic->config.bo, (void **)&c); + if (err < 0) { + fprintf(stderr, "failed to map configuration structure: %s\n", + strerror(-err)); + return err; + } + + memset(c, 0, sizeof(*c)); + + c->outputConfig.TargetRectTop = 0; + c->outputConfig.TargetRectLeft = 0; + c->outputConfig.TargetRectRight = output->width - 1; + c->outputConfig.TargetRectBottom = output->height - 1; + c->outputConfig.BackgroundAlpha = 255; + c->outputConfig.BackgroundR = 1023; + c->outputConfig.BackgroundG = 1023; + c->outputConfig.BackgroundB = 1023; + + c->outputSurfaceConfig.OutPixelFormat = output->format; + c->outputSurfaceConfig.OutBlkKind = output->kind; + c->outputSurfaceConfig.OutBlkHeight = 0; + c->outputSurfaceConfig.OutSurfaceWidth = output->width - 1; + c->outputSurfaceConfig.OutSurfaceHeight = output->height - 1; + c->outputSurfaceConfig.OutLumaWidth = output->stride - 1; + c->outputSurfaceConfig.OutLumaHeight = output->height - 1; + c->outputSurfaceConfig.OutChromaWidth = 16383; + c->outputSurfaceConfig.OutChromaHeight = 16383; + + slot = &c->slotStruct[0].slotConfig; + slot->SlotEnable = 1; + slot->CurrentFieldEnable = 1; + slot->PlanarAlpha = 255; + slot->ConstantAlpha = 1; + slot->SourceRectLeft = 0 << 16; + slot->SourceRectRight = (input->width - 1) << 16; + slot->SourceRectTop = 0 << 16; + slot->SourceRectBottom = (input->height - 1) << 16; + slot->DestRectLeft = 0; + slot->DestRectRight = output->width - 1; + slot->DestRectTop = 0; + slot->DestRectBottom = output->height - 1; + slot->SoftClampHigh = 1023; + + surface = &c->slotStruct[0].slotSurfaceConfig; + surface->SlotPixelFormat = input->format; + surface->SlotBlkKind = input->kind; + surface->SlotBlkHeight = 0; /* XXX */ + surface->SlotCacheWidth = VIC_CACHE_WIDTH_64Bx4; /* XXX */ + surface->SlotSurfaceWidth = input->width - 1; + surface->SlotSurfaceHeight = input->height - 1; + surface->SlotLumaWidth = input->stride - 1; + surface->SlotLumaHeight = input->height - 1; + surface->SlotChromaWidth = 16383; + surface->SlotChromaHeight = 16383; + + drm_tegra_bo_unmap(vic->config.bo); + + return 0; +} + +static int vic42_flip(struct vic *v, struct vic_image *output, + struct vic_image *input) +{ + struct vic42 *vic = container_of(v, struct vic42, base); + SlotSurfaceConfig *surface; + SlotConfig *slot; + ConfigStruct *c; + int err; + + err = drm_tegra_bo_map(vic->config.bo, (void **)&c); + if (err < 0) { + fprintf(stderr, "failed to map configuration structure: %s\n", + strerror(-err)); + return err; + } + + memset(c, 0, sizeof(*c)); + + c->outputConfig.TargetRectTop = 0; + c->outputConfig.TargetRectLeft = 0; + c->outputConfig.TargetRectRight = output->width - 1; + c->outputConfig.TargetRectBottom = output->height - 1; + c->outputConfig.BackgroundAlpha = 255; + c->outputConfig.BackgroundR = 1023; + c->outputConfig.BackgroundG = 1023; + c->outputConfig.BackgroundB = 1023; + c->outputConfig.OutputFlipY = 1; + + c->outputSurfaceConfig.OutPixelFormat = output->format; + c->outputSurfaceConfig.OutBlkKind = output->kind; + c->outputSurfaceConfig.OutBlkHeight = 0; + c->outputSurfaceConfig.OutSurfaceWidth = output->width - 1; + c->outputSurfaceConfig.OutSurfaceHeight = output->height - 1; + c->outputSurfaceConfig.OutLumaWidth = output->stride - 1; + c->outputSurfaceConfig.OutLumaHeight = output->height - 1; + c->outputSurfaceConfig.OutChromaWidth = 16383; + c->outputSurfaceConfig.OutChromaHeight = 16383; + + slot = &c->slotStruct[0].slotConfig; + slot->SlotEnable = 1; + slot->CurrentFieldEnable = 1; + slot->PlanarAlpha = 255; + slot->ConstantAlpha = 1; + slot->SourceRectLeft = 0 << 16; + slot->SourceRectRight = (input->width - 1) << 16; + slot->SourceRectTop = 0 << 16; + slot->SourceRectBottom = (input->height - 1) << 16; + slot->DestRectLeft = 0; + slot->DestRectRight = output->width - 1; + slot->DestRectTop = 0; + slot->DestRectBottom = output->height - 1; + slot->SoftClampHigh = 1023; + + surface = &c->slotStruct[0].slotSurfaceConfig; + surface->SlotPixelFormat = input->format; + surface->SlotBlkKind = input->kind; + surface->SlotBlkHeight = 0; /* XXX */ + surface->SlotCacheWidth = VIC_CACHE_WIDTH_64Bx4; /* XXX */ + surface->SlotSurfaceWidth = input->width - 1; + surface->SlotSurfaceHeight = input->height - 1; + surface->SlotLumaWidth = input->stride - 1; + surface->SlotLumaHeight = input->height - 1; + surface->SlotChromaWidth = 16383; + surface->SlotChromaHeight = 16383; + + drm_tegra_bo_unmap(vic->config.bo); + + return 0; +} + +static int vic42_execute(struct vic *v, struct drm_tegra_pushbuf *pushbuf, + uint32_t **ptrp, struct vic_image *output, + struct vic_image **inputs, unsigned int num_inputs) +{ + struct vic42 *vic = container_of(v, struct vic42, base); + unsigned int i; + + if (num_inputs > 1) + return -EINVAL; + + VIC_PUSH_METHOD(pushbuf, ptrp, NVC5B6_VIDEO_COMPOSITOR_SET_APPLICATION_ID, 1); + VIC_PUSH_METHOD(pushbuf, ptrp, NVC5B6_VIDEO_COMPOSITOR_SET_CONTROL_PARAMS, (sizeof(ConfigStruct) / 16) << 16); + VIC_PUSH_BUFFER(pushbuf, ptrp, NVC5B6_VIDEO_COMPOSITOR_SET_CONFIG_STRUCT_OFFSET, vic->config.map, 0, 0); + VIC_PUSH_BUFFER(pushbuf, ptrp, NVC5B6_VIDEO_COMPOSITOR_SET_FILTER_STRUCT_OFFSET, vic->filter.map, 0, 0); + VIC_PUSH_BUFFER(pushbuf, ptrp, NVC5B6_VIDEO_COMPOSITOR_SET_OUTPUT_SURFACE_LUMA_OFFSET, output->map, 0, 0); + + for (i = 0; i < num_inputs; i++) { + uint32_t method = NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE0_LUMA_OFFSET(0) + (i * 3) * 4; + + VIC_PUSH_BUFFER(pushbuf, ptrp, method, inputs[i]->map, 0, 0); + } + + VIC_PUSH_METHOD(pushbuf, ptrp, NVC5B6_VIDEO_COMPOSITOR_EXECUTE, 1 << 8); + + return 0; +} + +static void vic42_free(struct vic *v) +{ + struct vic42 *vic = container_of(v, struct vic42, base); + + drm_tegra_channel_unmap(vic->filter.map); + drm_tegra_bo_unref(vic->filter.bo); + + drm_tegra_channel_unmap(vic->config.map); + drm_tegra_bo_unref(vic->config.bo); + + drm_tegra_syncpoint_free(v->syncpt); + + free(vic); +} + +static const struct vic_ops vic42_ops = { + .fill = vic42_fill, + .blit = vic42_blit, + .flip = vic42_flip, + .execute = vic42_execute, + .free = vic42_free, +}; + +int vic42_new(struct drm_tegra *drm, struct drm_tegra_channel *channel, + struct vic **vicp) +{ + struct vic42 *vic; + void *ptr; + int err; + + vic = calloc(1, sizeof(*vic)); + if (!vic) + return -ENOMEM; + + vic->base.drm = drm; + vic->base.channel = channel; + vic->base.ops = &vic42_ops; + vic->base.version = 0x19; + + err = drm_tegra_syncpoint_new(drm, &vic->base.syncpt); + if (err < 0) { + fprintf(stderr, "failed to allocate syncpoint: %s\n", strerror(-err)); + return err; + } + + err = drm_tegra_bo_new(drm, 0, 16384, &vic->config.bo); + if (err < 0) { + fprintf(stderr, "failed to allocate configuration structurer: %s\n", + strerror(-err)); + return err; + } + + err = drm_tegra_channel_map(channel, vic->config.bo, DRM_TEGRA_CHANNEL_MAP_READ, + &vic->config.map); + if (err < 0) { + fprintf(stderr, "failed to map configuration structure: %s\n", + strerror(-err)); + return err; + } + + err = drm_tegra_bo_new(drm, 0, 16384, &vic->filter.bo); + if (err < 0) { + fprintf(stderr, "failed to allocate filter buffer: %s\n", + strerror(-err)); + return err; + } + + err = drm_tegra_bo_map(vic->filter.bo, &ptr); + if (err < 0) { + fprintf(stderr, "failed to map filter buffer: %s\n", strerror(-err)); + return err; + } + + memset(ptr, 0, 16384); + drm_tegra_bo_unmap(vic->filter.bo); + + err = drm_tegra_channel_map(channel, vic->filter.bo, DRM_TEGRA_CHANNEL_MAP_READ, + &vic->filter.map); + if (err < 0) { + fprintf(stderr, "failed to map filter buffer: %s\n", + strerror(-err)); + return err; + } + + if (vicp) + *vicp = &vic->base; + + return 0; +} diff --git a/tests/tegra/vic42.h b/tests/tegra/vic42.h new file mode 100644 index 0000000..3ed5cdb --- /dev/null +++ b/tests/tegra/vic42.h @@ -0,0 +1,597 @@ +/* + * Copyright © 2018 NVIDIA Corporation + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 VIC42_H +#define VIC42_H + +#include + +#define NVC5B6_VIDEO_COMPOSITOR_SET_APPLICATION_ID 0x00000200 +#define NVC5B6_VIDEO_COMPOSITOR_EXECUTE 0x00000300 +#define NVC5B6_VIDEO_COMPOSITOR_SET_CONTROL_PARAMS 0x00000704 +#define NVC5B6_VIDEO_COMPOSITOR_SET_CONFIG_STRUCT_OFFSET 0x00000708 +#define NVC5B6_VIDEO_COMPOSITOR_SET_FILTER_STRUCT_OFFSET 0x0000070c +#define NVC5B6_VIDEO_COMPOSITOR_SET_HIST_OFFSET 0x00000714 +#define NVC5B6_VIDEO_COMPOSITOR_SET_OUTPUT_SURFACE_LUMA_OFFSET 0x00000720 +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE0_LUMA_OFFSET(slot) (0x00001200 + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE0_CHROMA_U_OFFSET(slot) (0x00001204 + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE0_CHROMA_V_OFFSET(slot) (0x00001208 + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE1_LUMA_OFFSET(slot) (0x0000120c + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE1_CHROMA_U_OFFSET(slot) (0x00001210 + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE1_CHROMA_V_OFFSET(slot) (0x00001214 + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE2_LUMA_OFFSET(slot) (0x00001218 + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE2_CHROMA_U_OFFSET(slot) (0x0000121c + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE2_CHROMA_V_OFFSET(slot) (0x00001220 + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE3_LUMA_OFFSET(slot) (0x00001224 + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE3_CHROMA_U_OFFSET(slot) (0x00001228 + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE3_CHROMA_V_OFFSET(slot) (0x0000122c + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE4_LUMA_OFFSET(slot) (0x00001230 + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE4_CHROMA_U_OFFSET(slot) (0x00001234 + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE4_CHROMA_V_OFFSET(slot) (0x00001238 + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE5_LUMA_OFFSET(slot) (0x0000123c + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE5_CHROMA_U_OFFSET(slot) (0x00001240 + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE5_CHROMA_V_OFFSET(slot) (0x00001244 + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE6_LUMA_OFFSET(slot) (0x00001248 + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE6_CHROMA_U_OFFSET(slot) (0x0000124c + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE6_CHROMA_V_OFFSET(slot) (0x00001250 + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE7_LUMA_OFFSET(slot) (0x00001254 + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE7_CHROMA_U_OFFSET(slot) (0x00001258 + (slot) * 0x00000060) +#define NVC5B6_VIDEO_COMPOSITOR_SET_SURFACE7_CHROMA_V_OFFSET(slot) (0x0000125c + (slot) * 0x00000060) + +typedef struct { + uint64_t SlotEnable : 1; /* 0 */ + uint64_t DeNoise : 1; /* 1 */ + uint64_t AdvancedDenoise : 1; /* 2 */ + uint64_t CadenceDetect : 1; /* 3 */ + uint64_t MotionMap : 1; /* 4 */ + uint64_t MMapCombine : 1; /* 5 */ + uint64_t IsEven : 1; /* 6 */ + uint64_t ChromaEven : 1; /* 7 */ + uint64_t CurrentFieldEnable : 1; /* 8 */ + uint64_t PrevFieldEnable : 1; /* 9 */ + uint64_t NextFieldEnable : 1; /* 10 */ + uint64_t NextNrFieldEnable : 1; /* 11 */ + uint64_t CurMotionFieldEnable : 1; /* 12 */ + uint64_t PrevMotionFieldEnable : 1; /* 13 */ + uint64_t PpMotionFieldEnable : 1; /* 14 */ + uint64_t CombMotionFieldEnable : 1; /* 15 */ + uint64_t FrameFormat : 4; /* 19..16 */ + uint64_t FilterLengthY : 2; /* 21..20 */ + uint64_t FilterLengthX : 2; /* 23..22 */ + uint64_t Panoramic : 12; /* 35..24 */ + uint64_t ChromaUpLengthY : 2; /* 37..36 */ + uint64_t ChromaUpLengthX : 2; /* 39..38 */ + uint64_t reserved1 : 18; /* 57..40 */ + uint64_t DetailFltClamp : 6; /* 63..58 */ + uint64_t FilterNoise : 10; /* 73..64 */ + uint64_t FilterDetail : 10; /* 83..74 */ + uint64_t ChromaNoise : 10; /* 93..84 */ + uint64_t ChromaDetail : 10; /* 103..94 */ + uint64_t DeinterlaceMode : 4; /* 107..104 */ + uint64_t MotionAccumWeight : 3; /* 110..108 */ + uint64_t NoiseIir : 11; /* 121..111 */ + uint64_t LightLevel : 4; /* 125..122 */ + uint64_t reserved4 : 2; /* 127..126 */ + /* 128 */ + uint64_t SoftClampLow : 10; /* 9..0 */ + uint64_t SoftClampHigh : 10; /* 19..10 */ + uint64_t reserved5 : 12; /* 31..20 */ + uint64_t reserved6 : 2; /* 33..32 */ + uint64_t PlanarAlpha : 8; /* 41..34 */ + uint64_t ConstantAlpha : 1; /* 42 */ + uint64_t StereoInterleave : 3; /* 45..43 */ + uint64_t ClipEnabled : 1; /* 46 */ + uint64_t ClearRectMask : 8; /* 54..47 */ + uint64_t DegammaMode : 2; /* 56..55 */ + uint64_t reserved7 : 1; /* 57 */ + uint64_t DecompressEnable : 1; /* 58 */ + uint64_t DecompressKind : 4; /* 62..59 */ + uint64_t reserved9 : 1; /* 63 */ + uint64_t DecompressCtbCount : 8; /* 71..64 */ + uint64_t DecompressZbcColor : 32; /* 103..72 */ + uint64_t reserved12 : 24; /* 127..104 */ + /* 256 */ + uint64_t SourceRectLeft : 30; /* 29..0 */ + uint64_t reserved14 : 2; /* 31..30 */ + uint64_t SourceRectRight : 30; /* 61..32 */ + uint64_t reserved15 : 2; /* 63..62 */ + uint64_t SourceRectTop : 30; /* 93..64 */ + uint64_t reserved16 : 2; /* 95..94 */ + uint64_t SourceRectBottom : 30; /* 125..96 */ + uint64_t reserved17 : 2; /* 127..126 */ + /* 384 */ + uint64_t DestRectLeft : 14; /* 13..0 */ + uint64_t reserved18 : 2; /* 15..14 */ + uint64_t DestRectRight : 14; /* 29..16 */ + uint64_t reserved19 : 2; /* 31..30 */ + uint64_t DestRectTop : 14; /* 45..32 */ + uint64_t reserved20 : 2; /* 47..46 */ + uint64_t DestRectBottom : 14; /* 61..48 */ + uint64_t reserved21 : 2; /* 63..62 */ + uint64_t B16ScalerEnable : 1; /* 64 */ + uint64_t reserved22 : 31; /* 95..65 */ + uint64_t reserved23 : 32; /* 127..96 */ +} SlotConfig; + +typedef struct { + uint64_t SlotPixelFormat : 7; /* 6..0 */ + uint64_t SlotChromaLocHORIZ : 2; /* 8..7 */ + uint64_t SlotChromaLocVert : 2; /* 10..9 */ + uint64_t SlotBlkKind : 4; /* 14..11 */ + uint64_t SlotBlkHeight : 4; /* 18..15 */ + uint64_t SlotCacheWidth : 3; /* 21..19 */ + uint64_t reserved0 : 10; /* 31..22 */ + uint64_t SlotSurfaceWidth : 14; /* 45..32 */ + uint64_t SlotSurfaceHeight : 14; /* 59..46 */ + uint64_t reserved1 : 4; /* 63..60 */ + uint64_t SlotLumaWidth : 14; /* 77..64 */ + uint64_t SlotLumaHeight : 14; /* 91..78 */ + uint64_t reserved2 : 4; /* 95..92 */ + uint64_t SlotChromaWidth : 14; /* 109..96 */ + uint64_t SlotChromaHeight : 14; /* 123..110 */ + uint64_t reserved3 : 4; /* 127..124 */ +} SlotSurfaceConfig; + +typedef struct { + uint64_t luma_coeff0 : 20; /* 19..0 */ + uint64_t luma_coeff1 : 20; /* 39..20 */ + uint64_t luma_coeff2 : 20; /* 59..40 */ + uint64_t luma_r_shift : 4; /* 63..60 */ + uint64_t luma_coeff3 : 20; /* 83..64 */ + uint64_t LumaKeyLower : 10; /* 93..84 */ + uint64_t LumaKeyUpper : 10; /* 103..94 */ + uint64_t LumaKeyEnabled : 1; /* 104 */ + uint64_t reserved0 : 2; /* 106..105 */ + uint64_t reserved1 : 21; /* 127..107 */ +} LumaKeyStruct; + +typedef struct { + uint64_t matrix_coeff00 : 20; /* 19..0 */ + uint64_t matrix_coeff10 : 20; /* 39..20 */ + uint64_t matrix_coeff20 : 20; /* 59..40 */ + uint64_t matrix_r_shift : 4; /* 63..60 */ + uint64_t matrix_coeff01 : 20; /* 83..64 */ + uint64_t matrix_coeff11 : 20; /* 103..84 */ + uint64_t matrix_coeff21 : 20; /* 123..104 */ + uint64_t reserved0 : 3; /* 126..124 */ + uint64_t matrix_enable : 1; /* 127 */ + /* 128 */ + uint64_t matrix_coeff02 : 20; /* 19..0 */ + uint64_t matrix_coeff12 : 20; /* 39..20 */ + uint64_t matrix_coeff22 : 20; /* 59..40 */ + uint64_t reserved1 : 4; /* 63..60 */ + uint64_t matrix_coeff03 : 20; /* 83..64 */ + uint64_t matrix_coeff13 : 20; /* 103..84 */ + uint64_t matrix_coeff23 : 20; /* 123..104 */ + uint64_t reserved2 : 4; /* 127..124 */ +} MatrixStruct; + +typedef struct { + uint64_t ClearRect0Left : 14; /* 13..0 */ + uint64_t reserved0 : 2; /* 15..14 */ + uint64_t ClearRect0Right : 14; /* 29..16 */ + uint64_t reserved1 : 2; /* 31..30 */ + uint64_t ClearRect0Top : 14; /* 45..32 */ + uint64_t reserved2 : 2; /* 47..46 */ + uint64_t ClearRect0Bottom : 14; /* 61..48 */ + uint64_t reserved3 : 2; /* 63..62 */ + uint64_t ClearRect1Left : 14; /* 77..64 */ + uint64_t reserved4 : 2; /* 79..78 */ + uint64_t ClearRect1Right : 14; /* 93..80 */ + uint64_t reserved5 : 2; /* 95..94 */ + uint64_t ClearRect1Top : 14; /* 109..96 */ + uint64_t reserved6 : 2; /* 111..110 */ + uint64_t ClearRect1Bottom : 14; /* 125..112 */ + uint64_t reserved7 : 2; /* 127..126 */ +} ClearRectStruct; + +typedef struct { + uint64_t reserved0 : 2; /* 1..0 */ + uint64_t AlphaK1 : 8; /* 9..2 */ + uint64_t reserved1 : 6; /* 17..10 */ + uint64_t AlphaK2 : 8; /* 25..18 */ + uint64_t reserved2 : 6; /* 31..26 */ + uint64_t SrcFactCMatchSelect : 3; /* 34..32 */ + uint64_t reserved3 : 1; /* 35 */ + uint64_t DstFactCMatchSelect : 3; /* 38..36 */ + uint64_t reserved4 : 1; /* 39 */ + uint64_t SrcFactAMatchSelect : 3; /* 42..40 */ + uint64_t reserved5 : 1; /* 43 */ + uint64_t DstFactAMatchSelect : 3; /* 46..44 */ + uint64_t reserved6 : 1; /* 47 */ + uint64_t reserved7 : 4; /* 51..48 */ + uint64_t reserved8 : 4; /* 55..52 */ + uint64_t reserved9 : 4; /* 59..56 */ + uint64_t reserved10 : 4; /* 63..60 */ + uint64_t reserved11 : 2; /* 65..64 */ + uint64_t OverrideR : 10; /* 75..66 */ + uint64_t OverrideG : 10; /* 85..76 */ + uint64_t OverrideB : 10; /* 95..86 */ + uint64_t reserved12 : 2; /* 97..96 */ + uint64_t OverrideA : 8; /* 105..98 */ + uint64_t reserved13 : 2; /* 107..106 */ + uint64_t UseOverrideR : 1; /* 108 */ + uint64_t UseOverrideG : 1; /* 109 */ + uint64_t UseOverrideB : 1; /* 110 */ + uint64_t UseOverrideA : 1; /* 111 */ + uint64_t MaskR : 1; /* 112 */ + uint64_t MaskG : 1; /* 113 */ + uint64_t MaskB : 1; /* 114 */ + uint64_t MaskA : 1; /* 115 */ + uint64_t reserved14 : 12; /* 127..116 */ +} BlendingSlotStruct; + +typedef struct { + uint64_t AlphaFillMode : 3; /* 2..0 */ + uint64_t AlphaFillSlot : 3; /* 5..3 */ + uint64_t reserved0 : 2; /* 6..5 */ + uint64_t BackgroundAlpha : 8; /* 15..7 */ + uint64_t BackgroundR : 10; /* 25..16 */ + uint64_t BackgroundG : 10; /* 35..26 */ + uint64_t BackgroundB : 10; /* 45..36 */ + uint64_t RegammaMode : 2; /* 47..46 */ + uint64_t OutputFlipX : 1; /* 48 */ + uint64_t OutputFlipY : 1; /* 49 */ + uint64_t OutputTranspose : 1; /* 50 */ + uint64_t reserved1 : 1; /* 51 */ + uint64_t reserved2 : 12; /* 63..52 */ + uint64_t TargetRectLeft : 14; /* 77..64 */ + uint64_t reserved3 : 2; /* 79..78 */ + uint64_t TargetRectRight : 14; /* 93..80 */ + uint64_t reserved4 : 2; /* 95..94 */ + uint64_t TargetRectTop : 14; /* 109..96 */ + uint64_t reserved5 : 2; /* 111..110 */ + uint64_t TargetRectBottom : 14; /* 125..112 */ + uint64_t reserved6 : 2; /* 127..126 */ +} OutputConfig; + +typedef struct { + uint64_t OutPixelFormat : 7; /* 6..0 */ + uint64_t OutChromaLocHoriz : 2; /* 8..7 */ + uint64_t OutChromaLocVert : 2; /* 10..9 */ + uint64_t OutBlkKind : 4; /* 14..11 */ + uint64_t OutBlkHeight : 4; /* 18..15 */ + uint64_t reserved0 : 3; /* 21..19 */ + uint64_t reserved1 : 10; /* 31..22 */ + uint64_t OutSurfaceWidth : 14; /* 45..32 */ + uint64_t OutSurfaceHeight : 14; /* 59..46 */ + uint64_t reserved2 : 4; /* 63..60 */ + uint64_t OutLumaWidth : 14; /* 77..64 */ + uint64_t OutLumaHeight : 14; /* 91..78 */ + uint64_t reserved3 : 4; /* 95..92 */ + uint64_t OutChromaWidth : 14; /* 109..96 */ + uint64_t OutChromaHeight : 14; /* 123..110 */ + uint64_t reserved4 : 4; /* 127..124 */ +} OutputSurfaceConfig; + +typedef struct { + uint64_t f00 : 10; /* 9..0 */ + uint64_t f10 : 10; /* 19..10 */ + uint64_t f20 : 10; /* 29..20 */ + uint64_t reserved0 : 2; /* 31..30 */ + uint64_t f01 : 10; /* 41..32 */ + uint64_t f11 : 10; /* 51..42 */ + uint64_t f21 : 10; /* 61..52 */ + uint64_t reserved1 : 2; /* 63..62 */ + uint64_t f02 : 10; /* 73..64 */ + uint64_t f12 : 10; /* 83..74 */ + uint64_t f22 : 10; /* 93..84 */ + uint64_t reserved2 : 2; /* 95..94 */ + uint64_t f03 : 10; /* 105..96 */ + uint64_t f13 : 10; /* 115..106 */ + uint64_t f23 : 10; /* 125..116 */ + uint64_t reserved3 : 2; /* 127..126 */ +} FilterCoeffStruct; + +typedef struct { + uint64_t DownsampleHoriz : 11; /* 10..0 */ + uint64_t reserved0 : 5; /* 15..11 */ + uint64_t DownsampleVert : 11; /* 26..16 */ + uint64_t reserved1 : 5; /* 31..27 */ + uint64_t reserved2 : 32; /* 63..32 */ + uint64_t reserved3 : 32; /* 95..64 */ + uint64_t reserved4 : 32; /* 127..96 */ +} PipeConfig; + +typedef struct { + uint64_t OldCadence : 32; /* 31..0 */ + uint64_t OldDiff : 32; /* 63..32 */ + uint64_t OldWeave : 32; /* 95..64 */ + uint64_t OlderWeave : 32; /* 127..96 */ +} SlotHistoryBuffer; + +typedef struct { + uint64_t crc0 : 32; /* 31..0 */ + uint64_t crc1 : 32; /* 63..32 */ + uint64_t crc2 : 32; /* 95..64 */ + uint64_t crc3 : 32; /* 127..96 */ +} PartitionCrcStruct; + +typedef struct { + uint64_t crc0 : 32; /* 31..0 */ + uint64_t crc1 : 32; /* 63..32 */ +} SlotCrcStruct; + +typedef struct { + uint64_t ErrorStatus : 32; /* 31..0 */ + uint64_t CycleCount : 32; /* 63..32 */ + uint64_t reserved0 : 32; /* 95..64 */ + uint64_t reserved1 : 32; /* 127..96 */ +} StatusStruct; + +typedef struct { + uint64_t coeff_0 : 10; /* 9..0 */ + uint64_t reserved0 : 6; /* 15..10 */ + uint64_t coeff_1 : 10; /* 25..16 */ + uint64_t reserved1 : 6; /* 31..26 */ + uint64_t coeff_2 : 10; /* 41..32 */ + uint64_t reserved2 : 6; /* 47..42 */ + uint64_t coeff_3 : 10; /* 57..48 */ + uint64_t reserved3 : 6; /* 63..58 */ +} CoeffPhaseParamStruct; + +typedef struct { + uint64_t GeoTranEn : 1; /* 0 */ + uint64_t GeoTranMode : 2; /* 2..1 */ + uint64_t IPTMode : 1; /* 3 */ + uint64_t PixelFilterType : 2; /* 5..4 */ + uint64_t PixelFormat : 7; /* 12..6 */ + uint64_t CacheWidth : 3; /* 15..13 */ + uint64_t SrcBlkKind : 4; /* 19..16 */ + uint64_t SrcBlkHeight : 4; /* 23..20 */ + uint64_t DestBlkKind : 4; /* 27..24 */ + uint64_t DestBlkHeight : 4; /* 31..28 */ + uint64_t MskBitMapEn : 1; /* 32 */ + uint64_t MaskedPixelFillMode : 1; /* 33 */ + uint64_t XSobelMode : 2; /* 35..34 */ + uint64_t SubFrameEn : 1; /* 36 */ + uint64_t reserved0 : 3; /* 39..37 */ + uint64_t XSobelBlkKind : 4; /* 43..40 */ + uint64_t XSobelBlkHeight : 4; /* 47..44 */ + uint64_t XSobelDSBlkKind : 4; /* 51..48 */ + uint64_t XSobelDSBlkHeight : 4; /* 55..52 */ + uint64_t reserved1 : 8; /* 63..56 */ + uint64_t NonFixedPatchEn : 1; /* 64 */ + uint64_t HorRegionNum : 2; /* 66..65 */ + uint64_t VerRegionNum : 2; /* 68..67 */ + uint64_t reserved2 : 3; /* 71..69 */ + uint64_t log2HorSpace_0 : 3; /* 74..72 */ + uint64_t log2VerSpace_0 : 3; /* 77..75 */ + uint64_t log2HorSpace_1 : 3; /* 80..78 */ + uint64_t log2VerSpace_1 : 3; /* 83..81 */ + uint64_t log2HorSpace_2 : 3; /* 86..84 */ + uint64_t log2VerSpace_2 : 3; /* 89..87 */ + uint64_t log2HorSpace_3 : 3; /* 92..90 */ + uint64_t log2VerSpace_3 : 3; /* 95..93 */ + uint64_t horRegionWidth_0 : 14; /* 109..96 */ + uint64_t reserved3 : 2; /* 111..110 */ + uint64_t horRegionWidth_1 : 14; /* 125..112 */ + uint64_t reserved4 : 2; /* 127..126 */ + uint64_t horRegionWidth_2 : 14; /* 141..128 */ + uint64_t reserved5 : 2; /* 143..142 */ + uint64_t horRegionWidth_3 : 14; /* 157..144 */ + uint64_t reserved6 : 2; /* 159..158 */ + uint64_t verRegionHeight_0 : 14; /* 173..160 */ + uint64_t reserved7 : 2; /* 175..174 */ + uint64_t verRegionHeight_1 : 14; /* 189..176 */ + uint64_t reserved8 : 2; /* 191..190 */ + uint64_t verRegionHeight_2 : 14; /* 205..192 */ + uint64_t reserved9 : 2; /* 207..206 */ + uint64_t verRegionHeight_3 : 14; /* 221..208 */ + uint64_t reserved10 : 2; /* 223..222 */ + uint64_t IPT_M11 : 32; /* 255..224 */ + uint64_t IPT_M12 : 32; /* 287..256 */ + uint64_t IPT_M13 : 32; /* 319..288 */ + uint64_t IPT_M21 : 32; /* 351..320 */ + uint64_t IPT_M22 : 32; /* 383..352 */ + uint64_t IPT_M23 : 32; /* 415..384 */ + uint64_t IPT_M31 : 32; /* 447..416 */ + uint64_t IPT_M32 : 32; /* 479..448 */ + uint64_t IPT_M33 : 32; /* 511..480 */ + uint64_t SourceRectLeft : 14; /* 525..512 */ + uint64_t reserved11 : 2; /* 527..526 */ + uint64_t SourceRectRight : 14; /* 541..528 */ + uint64_t reserved12 : 2; /* 543..542 */ + uint64_t SourceRectTop : 14; /* 557..544 */ + uint64_t reserved13 : 2; /* 559..558 */ + uint64_t SourceRectBottom : 14; /* 573..560 */ + uint64_t reserved14; /* 575..574 */ + uint64_t SrcImgWidth : 14; /* 589..576 */ + uint64_t reserved15 : 2; /* 591..590 */ + uint64_t SrcImgHeight : 14; /* 605..592 */ + uint64_t reserved16 : 2; /* 607..606 */ + uint64_t SrcSfcLumaWidth : 14; /* 621..608 */ + uint64_t reserved17 : 2; /* 623..622 */ + uint64_t SrcSfcLumaHeight : 14; /* 637..624 */ + uint64_t reserved18 : 2; /* 639..638 */ + uint64_t SrcSfcChromaWidth : 14; /* 653..640 */ + uint64_t reserved19 : 2; /* 655..654 */ + uint64_t SrcSfcChromaHeight : 14; /* 669..656 */ + uint64_t reserved20 : 2; /* 671..670 */ + uint64_t DestRectLeft : 14; /* 685..672 */ + uint64_t reserved21 : 2; /* 687..686 */ + uint64_t DestRectRight : 14; /* 701..688 */ + uint64_t reserved22 : 2; /* 703..702 */ + uint64_t DestRectTop : 14; /* 717..704 */ + uint64_t reserved23 : 2; /* 719..718 */ + uint64_t DestRectBottom : 14; /* 733..720 */ + uint64_t reserved24 : 2; /* 735..734 */ + uint64_t SubFrameRectTop : 14; /* 749..736 */ + uint64_t reserved25 : 2; /* 751..750 */ + uint64_t SubFrameRectBottom : 14; /* 765..752 */ + uint64_t reserved26 : 2; /* 767..766 */ + uint64_t DestSfcLumaWidth : 14; /* 781..768 */ + uint64_t reserved27 : 2; /* 783..782 */ + uint64_t DestSfcLumaHeight : 14; /* 797..784 */ + uint64_t reserved28 : 2; /* 799..798 */ + uint64_t DestSfcChromaWidth : 14; /* 813..800 */ + uint64_t reserved29 : 2; /* 815..814 */ + uint64_t DestSfcChromaHeight : 14; /* 829..816 */ + uint64_t reserved30 : 2; /* 831..830 */ + uint64_t SparseWarpMapWidth : 14; /* 845..832 */ + uint64_t reserved31 : 2; /* 847..846 */ + uint64_t SparseWarpMapHeight : 14; /* 861..848 */ + uint64_t reserved32 : 2; /* 863..862 */ + uint64_t SparseWarpMapStride : 14; /* 877..864 */ + uint64_t reserved33 : 2; /* 879..878 */ + uint64_t MaskBitMapWidth : 14; /* 893..880 */ + uint64_t reserved34 : 2; /* 895..894 */ + uint64_t MaskBitMapHeight : 14; /* 909..896 */ + uint64_t reserved35 : 2; /* 911..910 */ + uint64_t MaskBitMapStride : 14; /* 925..912 */ + uint64_t reserved36 : 2; /* 927..926 */ + uint64_t XSobelWidth : 14; /* 941..928 */ + uint64_t reserved37 : 2; /* 943..942 */ + uint64_t XSobelHeight : 14; /* 957..944 */ + uint64_t reserved38 : 2; /* 959..958 */ + uint64_t XSobelStride : 14; /* 973..960 */ + uint64_t reserved39 : 2; /* 975..974 */ + uint64_t DSStride : 14; /* 989..976 */ + uint64_t reserved40 : 2; /* 991..990 */ + uint64_t XSobelTopOffset : 32; /* 1023..992 */ + uint64_t reserved41 : 32; /* 1055..1024 */ + uint64_t maskY : 16; /* 1071..1056 */ + uint64_t maskU : 16; /* 1087..1072 */ + uint64_t maskV : 16; /* 1103..1088 */ + uint64_t reserved42 : 16; /* 1119..1104 */ +} GeoTranConfigParamStruct; + +typedef struct { + uint64_t TNR3En : 1; /* 0 */ + uint64_t BetaBlendingEn : 1; /* 1 */ + uint64_t AlphaBlendingEn : 1; /* 2 */ + uint64_t AlphaSmoothEn : 1; /* 3 */ + uint64_t TempAlphaRestrictEn : 1; /* 4 */ + uint64_t AlphaClipEn : 1; /* 5 */ + uint64_t BFRangeEn : 1; /* 6 */ + uint64_t BFDomainEn : 1; /* 7 */ + uint64_t BFRangeLumaShift : 4; /* 11..8 */ + uint64_t BFRangeChromaShift : 4; /* 15..12 */ + uint64_t SADMultiplier : 6; /* 21..16 */ + uint64_t reserved1 : 2; /* 23..22 */ + uint64_t SADWeightLuma : 6; /* 29..24 */ + uint64_t reserved2 : 2; /* 31..30 */ + uint64_t TempAlphaRestrictIncCap : 11; /* 42..32 */ + uint64_t reserved3 : 5; /* 47..43 */ + uint64_t AlphaScaleIIR : 11; /* 58..48 */ + uint64_t reserved4 : 5; /* 63..59 */ + uint64_t AlphaClipMaxLuma : 11; /* 74..64 */ + uint64_t reserved5 : 5; /* 79..75 */ + uint64_t AlphaClipMinLuma : 11; /* 90..80 */ + uint64_t reserved6 : 5; /* 95..91 */ + uint64_t AlphaClipMaxChroma : 11; /* 106..96 */ + uint64_t reserved7 : 5; /* 111..107 */ + uint64_t AlphaClipMinChroma : 11; /* 122..112 */ + uint64_t reserved8 : 5; /* 127..123 */ + uint64_t BetaCalcMaxBeta : 11; /* 138..128 */ + uint64_t reserved9 : 5; /* 143..139 */ + uint64_t BetaCalcMinBeta : 11; /* 154..144 */ + uint64_t reserved10 : 5; /* 159..155 */ + uint64_t BetaCalcBetaX1 : 11; /* 170..160 */ + uint64_t reserved11 : 5; /* 175..171 */ + uint64_t BetaCalcBetaX2 : 11; /* 186..176 */ + uint64_t reserved12 : 5; /* 191..187 */ + uint64_t BetaCalcStepBeta : 11; /* 202..192 */ + uint64_t reserved13 : 5; /* 207..203 */ + uint64_t reserved14 : 16; /* 223..208 */ + uint64_t BFDomainLumaCoeffC00 : 7; /* 230..224 */ + uint64_t reserved15 : 1; /* 231 */ + uint64_t BFDomainLumaCoeffC01 : 7; /* 238..232 */ + uint64_t reserved16 : 1; /* 239 */ + uint64_t BFDomainLumaCoeffC02 : 7; /* 246..240 */ + uint64_t reserved17 : 1; /* 247 */ + uint64_t BFDomainLumaCoeffC11 : 7; /* 254..248 */ + uint64_t reserved18 : 1; /* 255 */ + uint64_t BFDomainLumaCoeffC12 : 7; /* 262..256 */ + uint64_t reserved19 : 1; /* 263 */ + uint64_t BFDomainLumaCoeffC22 : 7; /* 270..264 */ + uint64_t reserved20 : 1; /* 271 */ + uint64_t reserved21 : 16; /* 287..272 */ + uint64_t BFDomainChromaCoeffC00 : 7; /* 294..288 */ + uint64_t reserved22 : 1; /* 295 */ + uint64_t BFDomainChromaCoeffC01 : 7; /* 302..296 */ + uint64_t reserved23 : 1; /* 303 */ + uint64_t BFDomainChromaCoeffC02 : 7; /* 310..304 */ + uint64_t reserved24 : 1; /* 311 */ + uint64_t BFDomainChromaCoeffC11 : 7; /* 318..312 */ + uint64_t reserved25 : 1; /* 319 */ + uint64_t BFDomainChromaCoeffC12 : 7; /* 326..320 */ + uint64_t reserved26 : 1; /* 327 */ + uint64_t BFDomainChromaCoeffC22 : 7; /* 334..328 */ + uint64_t reserved27 : 1; /* 335 */ + uint64_t reserved28 : 16; /* 351..336 */ + uint64_t LeftBufSize : 32; /* 383..352 */ + uint64_t TopBufSize : 32; /* 415..384 */ + uint64_t AlphaSufStride : 14; /* 429..416 */ + uint64_t reserved29 : 18; /* 447..430 */ +} TNR3ConfigParamStruct; + +typedef struct { + uint64_t item0 : 7; /* 6..0 */ + uint64_t reserved0 : 9; /* 15..7 */ + uint64_t item1 : 7; /* 22..16 */ + uint64_t reserved1 : 9; /* 31..23 */ + uint64_t item2 : 7; /* 38..32 */ + uint64_t reserved2 : 9; /* 47..39 */ + uint64_t item3 : 7; /* 54..48 */ + uint64_t reserved3 : 9; /* 63..55 */ +} BFRangeTableItems; + +typedef struct { + SlotConfig slotConfig; + SlotSurfaceConfig slotSurfaceConfig; + LumaKeyStruct lumaKeyStruct; + MatrixStruct colorMatrixStruct; + MatrixStruct gamutMatrixStruct; + BlendingSlotStruct blendingSlotStruct; +} SlotStruct; + +typedef struct { + FilterCoeffStruct filterCoeffStruct[520]; +} FilterStruct; + +typedef struct { + PipeConfig pipeConfig; + OutputConfig outputConfig; + OutputSurfaceConfig outputSurfaceConfig; + MatrixStruct outColorMatrixStruct; + ClearRectStruct clearRectStruct[4]; + SlotStruct slotStruct[16]; +} ConfigStruct; + +typedef struct { + PartitionCrcStruct partitionCrcStruct[2]; +} InterfaceCrcStruct; + +typedef struct { + SlotCrcStruct slotCrcStruct[16]; +} InputCrcStruct; + +typedef struct { + GeoTranConfigParamStruct paramConfig; + CoeffPhaseParamStruct FilterCoeff[17]; + TNR3ConfigParamStruct tnr3Config; + BFRangeTableItems BFRangeTableLuma[16]; + BFRangeTableItems BFRangeTableChroma[16]; +} GeoTranConfigStruct; + +#endif diff --git a/tests/ttmtest/AUTHORS b/tests/ttmtest/AUTHORS new file mode 100644 index 0000000..fa4a089 --- /dev/null +++ b/tests/ttmtest/AUTHORS @@ -0,0 +1 @@ +Thomas Hellstrm and others. diff --git a/tests/ttmtest/ChangeLog b/tests/ttmtest/ChangeLog new file mode 100644 index 0000000..4588c8d --- /dev/null +++ b/tests/ttmtest/ChangeLog @@ -0,0 +1,23 @@ +2006-01-24 Thomas Hellstrm + + * configure.ac: + * src/ttmtest.c: + + Fixed include path. + +2006-01-24 Thomas Hellstrm + + * AUTHORS: + * Makefile.am: + * configure.ac: + * reconf: + * src/Makefile.am: + * src/ttmtest.c: (fastrdtsc), (time_diff), (releaseContext), + (testAGP), (main): + * src/xf86dri.c: (uniDRIDestroyContext), (uniDRICreateDrawable), + (uniDRIDestroyDrawable), (uniDRIGetDrawableInfo): + * src/xf86dri.h: + * src/xf86dristr.h: + + Initial import of the ttmtest utility. + \ No newline at end of file diff --git a/tests/ttmtest/Makefile.am b/tests/ttmtest/Makefile.am new file mode 100644 index 0000000..af437a6 --- /dev/null +++ b/tests/ttmtest/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/tests/ttmtest/NEWS b/tests/ttmtest/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/tests/ttmtest/README b/tests/ttmtest/README new file mode 100644 index 0000000..e69de29 diff --git a/tests/ttmtest/configure.ac b/tests/ttmtest/configure.ac new file mode 100644 index 0000000..c41e91a --- /dev/null +++ b/tests/ttmtest/configure.ac @@ -0,0 +1,33 @@ +AC_INIT +AC_PROG_CC +AC_PATH_X +if test "x$no_x" != "xyes"; then + savecpp="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS -I$x_includes" + AC_CHECK_HEADER($x_includes/X11/Xlib.h,,\ + [AC_MSG_ERROR(Could not find X installation.)]) + CPPFLAGS="$savecpp" + MDRIINC="-I$x_includes" + LIBS="-L$x_libraries $LIBS" +else + AC_MSG_ERROR(Could not find X installation. Aborting.) +fi +AC_ARG_WITH(libdrm, + AC_HELP_STRING([--with-libdrm=DIR], + [Installation prefix of libdrm [[default=/usr]]]), + [libdrmpref="$withval"], + [libdrmpref="/usr"]) +savecpp="$CPPFLAGS" +MDRIINC="-I$libdrmpref/include -I$libdrmpref/include/drm -I$x_includes" +CPPFLAGS="$CPPFLAGS $MDRIINC" +AC_CHECK_HEADER(xf86drm.h,,\ + [AC_MSG_ERROR(Could not find libdrm installation. Use --with-libdrm=)]) +AC_CHECK_HEADER(drm.h,,\ + [AC_MSG_ERROR(Could not find libdrm installation. Use --with-libdrm=)]) +CPPFLAGS="$savecpp" +LIBS="-L$libdrmpref/lib64 -L$libdrmpref/lib $LIBS" +AC_SUBST(MDRIINC) +AC_SYS_LARGEFILE +AM_INIT_AUTOMAKE(minidri,0.1.0) +AM_CONFIG_HEADER(config.h) +AC_OUTPUT([Makefile src/Makefile]) diff --git a/tests/ttmtest/reconf b/tests/ttmtest/reconf new file mode 100755 index 0000000..e64d00a --- /dev/null +++ b/tests/ttmtest/reconf @@ -0,0 +1,2 @@ +#!/bin/sh +autoreconf -v --install || exit 1 \ No newline at end of file diff --git a/tests/ttmtest/src/Makefile.am b/tests/ttmtest/src/Makefile.am new file mode 100644 index 0000000..b7ee829 --- /dev/null +++ b/tests/ttmtest/src/Makefile.am @@ -0,0 +1,8 @@ +INCLUDES = @MDRIINC@ +bin_PROGRAMS = ttmtest +ttmtest_SOURCES = \ + ttmtest.c \ + xf86dri.c \ + xf86dri.h \ + xf86dristr.h +ttmtest_LDADD = -ldrm -lXext -lX11 diff --git a/tests/ttmtest/src/ttmtest.c b/tests/ttmtest/src/ttmtest.c new file mode 100644 index 0000000..36df242 --- /dev/null +++ b/tests/ttmtest/src/ttmtest.c @@ -0,0 +1,430 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, TX., USA + * 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 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 + * THE COPYRIGHT HOLDERS, AUTHORS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * + **************************************************************************/ +/* + * Authors: Thomas Hellstrm + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include "xf86dri.h" +#include "xf86drm.h" +#include "stdio.h" +#include "sys/types.h" +#include +#include +#include +#include +#include "sys/mman.h" + +typedef struct +{ + enum + { + haveNothing, + haveDisplay, + haveConnection, + haveDriverName, + haveDeviceInfo, + haveDRM, + haveContext + } + state; + + Display *display; + int screen; + drm_handle_t sAreaOffset; + char *curBusID; + char *driverName; + int drmFD; + XVisualInfo visualInfo; + XID id; + drm_context_t hwContext; + void *driPriv; + int driPrivSize; + int fbSize; + int fbOrigin; + int fbStride; + drm_handle_t fbHandle; + int ddxDriverMajor; + int ddxDriverMinor; + int ddxDriverPatch; +} TinyDRIContext; + +#ifndef __x86_64__ +static unsigned +fastrdtsc(void) +{ + unsigned eax; + __asm__ volatile ("\t" + "pushl %%ebx\n\t" + "cpuid\n\t" ".byte 0x0f, 0x31\n\t" "popl %%ebx\n":"=a" (eax) + :"0"(0) + :"ecx", "edx", "cc"); + + return eax; +} +#else +static unsigned +fastrdtsc(void) +{ + unsigned eax; + __asm__ volatile ("\t" "cpuid\n\t" ".byte 0x0f, 0x31\n\t":"=a" (eax) + :"0"(0) + :"ecx", "edx", "ebx", "cc"); + + return eax; +} +#endif + +void +bmError(int val, const char *file, const char *function, int line) +{ + fprintf(stderr, "Fatal video memory manager error \"%s\".\n" + "Check kernel logs or set the LIBGL_DEBUG\n" + "environment variable to \"verbose\" for more info.\n" + "Detected in file %s, line %d, function %s.\n", + strerror(-val), file, line, function); + abort(); +} + +#define BM_CKFATAL(val) \ + do{ \ + int tstVal = (val); \ + if (tstVal) \ + bmError(tstVal, __FILE__, __FUNCTION__, __LINE__); \ + } while(0); + +static unsigned +time_diff(unsigned t, unsigned t2) +{ + return ((t < t2) ? t2 - t : 0xFFFFFFFFU - (t - t2 - 1)); +} + +static int +releaseContext(TinyDRIContext * ctx) +{ + switch (ctx->state) { + case haveContext: + uniDRIDestroyContext(ctx->display, ctx->screen, ctx->id); + case haveDRM: + drmClose(ctx->drmFD); + case haveDeviceInfo: + XFree(ctx->driPriv); + case haveDriverName: + XFree(ctx->driverName); + case haveConnection: + XFree(ctx->curBusID); + uniDRICloseConnection(ctx->display, ctx->screen); + case haveDisplay: + XCloseDisplay(ctx->display); + default: + break; + } + return -1; +} + +static void +readBuf(void *buf, unsigned long size) +{ + volatile unsigned *buf32 = (unsigned *)buf; + unsigned *end = (unsigned *)buf32 + size / sizeof(*buf32); + + while (buf32 < end) { + (void)*buf32++; + } +} + +static int +benchmarkBuffer(TinyDRIContext * ctx, unsigned long size, + unsigned long *ticks) +{ + unsigned long curTime, oldTime; + int ret; + drmBO buf; + void *virtual; + + /* + * Test system memory objects. + */ + oldTime = fastrdtsc(); + BM_CKFATAL(drmBOCreate(ctx->drmFD, size, 0, NULL, + DRM_BO_FLAG_READ | + DRM_BO_FLAG_WRITE | + DRM_BO_FLAG_MEM_LOCAL, 0, &buf)); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + BM_CKFATAL(drmBOMap(ctx->drmFD, &buf, + DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &virtual)); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + memset(virtual, 0xF0, buf.size); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + memset(virtual, 0x0F, buf.size); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + readBuf(virtual, buf.size); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + BM_CKFATAL(drmBOUnmap(ctx->drmFD, &buf)); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + /* + * Test TT bound buffer objects. + */ + + oldTime = fastrdtsc(); + BM_CKFATAL(drmBOSetStatus(ctx->drmFD, &buf, + DRM_BO_FLAG_MEM_TT, + DRM_BO_MASK_MEM, + 0,0,0)); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + BM_CKFATAL(drmBOMap(ctx->drmFD, &buf, + DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &virtual)); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + memset(virtual, 0xF0, buf.size); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + memset(virtual, 0x0F, buf.size); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + readBuf(virtual, buf.size); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + BM_CKFATAL(drmBOUnmap(ctx->drmFD, &buf)); + + oldTime = fastrdtsc(); + BM_CKFATAL(drmBOSetStatus(ctx->drmFD, &buf, + DRM_BO_FLAG_MEM_LOCAL, DRM_BO_MASK_MEM, 0, 0,0)); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + /* + * Test cached buffers objects. + */ + + oldTime = fastrdtsc(); + ret = drmBOSetStatus(ctx->drmFD, &buf, + DRM_BO_FLAG_MEM_TT | + DRM_BO_FLAG_CACHED | + DRM_BO_FLAG_FORCE_CACHING, + DRM_BO_MASK_MEMTYPE | + DRM_BO_FLAG_FORCE_CACHING, + 0, 0, 0); + curTime = fastrdtsc(); + + if (ret) { + printf("Couldn't bind cached. Probably no support\n"); + BM_CKFATAL(drmBOUnreference(ctx->drmFD, &buf)); + return 1; + } + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + BM_CKFATAL(drmBOMap(ctx->drmFD, &buf, + DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &virtual)); + + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + memset(virtual, 0xF0, buf.size); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + memset(virtual, 0x0F, buf.size); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + oldTime = fastrdtsc(); + readBuf(virtual, buf.size); + curTime = fastrdtsc(); + *ticks++ = time_diff(oldTime, curTime); + + BM_CKFATAL(drmBOUnmap(ctx->drmFD, &buf)); + BM_CKFATAL(drmBOUnreference(ctx->drmFD, &buf)); + + return 0; +} + +static void +testAGP(TinyDRIContext * ctx) +{ + unsigned long ticks[128], *pTicks; + unsigned long size = 8 * 1024; + int ret; + + ret = benchmarkBuffer(ctx, size, ticks); + if (ret < 0) { + fprintf(stderr, "Buffer error %s\n", strerror(-ret)); + return; + } + pTicks = ticks; + + printf("Buffer size %d bytes\n", size); + printf("System memory timings ********************************\n"); + printf("Creation took %12lu ticks\n", *pTicks++); + printf("Mapping took %12lu ticks\n", *pTicks++); + printf("Writing took %12lu ticks\n", *pTicks++); + printf("Writing Again took %12lu ticks\n", *pTicks++); + printf("Reading took %12lu ticks\n", *pTicks++); + printf("Unmapping took %12lu ticks\n", *pTicks++); + + printf("\nTT Memory timings ************************************\n"); + printf("Moving to TT took %12lu ticks\n", *pTicks++); + printf("Mapping in TT took %12lu ticks\n", *pTicks++); + printf("Writing to TT took %12lu ticks\n", *pTicks++); + printf("Writing again to TT took %12lu ticks\n", *pTicks++); + printf("Reading from TT took %12lu ticks\n", *pTicks++); + printf("Moving to system took %12lu ticks\n", *pTicks++); + + if (ret == 1) + return; + + printf("\nCached TT Memory timings *****************************\n"); + printf("Moving to CTT took %12lu ticks\n", *pTicks++); + printf("Mapping in CTT took %12lu ticks\n", *pTicks++); + printf("Writing to CTT took %12lu ticks\n", *pTicks++); + printf("Re-writing to CTT took %12lu ticks\n", *pTicks++); + printf("Reading from CTT took %12lu ticks\n", *pTicks++); + printf("\n\n"); +} + +int +main() +{ + int ret, screen, isCapable; + char *displayName = ":0"; + TinyDRIContext ctx; + unsigned magic; + + ctx.screen = 0; + ctx.state = haveNothing; + ctx.display = XOpenDisplay(displayName); + if (!ctx.display) { + fprintf(stderr, "Could not open display\n"); + return releaseContext(&ctx); + } + ctx.state = haveDisplay; + + ret = + uniDRIQueryDirectRenderingCapable(ctx.display, ctx.screen, + &isCapable); + if (!ret || !isCapable) { + fprintf(stderr, "No DRI on this display:sceen\n"); + return releaseContext(&ctx); + } + + if (!uniDRIOpenConnection(ctx.display, ctx.screen, &ctx.sAreaOffset, + &ctx.curBusID)) { + fprintf(stderr, "Could not open DRI connection.\n"); + return releaseContext(&ctx); + } + ctx.state = haveConnection; + + if (!uniDRIGetClientDriverName(ctx.display, ctx.screen, + &ctx.ddxDriverMajor, &ctx.ddxDriverMinor, + &ctx.ddxDriverPatch, &ctx.driverName)) { + fprintf(stderr, "Could not get DRI driver name.\n"); + return releaseContext(&ctx); + } + ctx.state = haveDriverName; + + if (!uniDRIGetDeviceInfo(ctx.display, ctx.screen, + &ctx.fbHandle, &ctx.fbOrigin, &ctx.fbSize, + &ctx.fbStride, &ctx.driPrivSize, &ctx.driPriv)) { + fprintf(stderr, "Could not get DRI device info.\n"); + return releaseContext(&ctx); + } + ctx.state = haveDriverName; + + if ((ctx.drmFD = drmOpen(NULL, ctx.curBusID)) < 0) { + perror("DRM Device could not be opened"); + return releaseContext(&ctx); + } + ctx.state = haveDRM; + + drmGetMagic(ctx.drmFD, &magic); + if (!uniDRIAuthConnection(ctx.display, ctx.screen, magic)) { + fprintf(stderr, "Could not get X server to authenticate us.\n"); + return releaseContext(&ctx); + } + + ret = XMatchVisualInfo(ctx.display, ctx.screen, 24, TrueColor, + &ctx.visualInfo); + if (!ret) { + ret = XMatchVisualInfo(ctx.display, ctx.screen, 16, TrueColor, + &ctx.visualInfo); + if (!ret) { + fprintf(stderr, "Could not find a matching visual.\n"); + return releaseContext(&ctx); + } + } + + if (!uniDRICreateContext(ctx.display, ctx.screen, ctx.visualInfo.visual, + &ctx.id, &ctx.hwContext)) { + fprintf(stderr, "Could not create DRI context.\n"); + return releaseContext(&ctx); + } + ctx.state = haveContext; + + testAGP(&ctx); + + releaseContext(&ctx); + printf("Terminating normally\n"); + return 0; +} diff --git a/tests/ttmtest/src/xf86dri.c b/tests/ttmtest/src/xf86dri.c new file mode 100644 index 0000000..e6e0b89 --- /dev/null +++ b/tests/ttmtest/src/xf86dri.c @@ -0,0 +1,603 @@ +/* $XFree86: xc/lib/GL/dri/XF86dri.c,v 1.13 2002/10/30 12:51:25 alanh Exp $ */ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright 2000 VA Linux Systems, Inc. +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 PRECISION INSIGHT 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin + * Jens Owen + * Rickard E. (Rik) Faith + * + */ + +/* THIS IS NOT AN X CONSORTIUM STANDARD */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include "xf86dristr.h" + +static XExtensionInfo _xf86dri_info_data; +static XExtensionInfo *xf86dri_info = &_xf86dri_info_data; +static char xf86dri_extension_name[] = XF86DRINAME; + +#define uniDRICheckExtension(dpy,i,val) \ + XextCheckExtension (dpy, i, xf86dri_extension_name, val) + +/***************************************************************************** + * * + * private utility routines * + * * + *****************************************************************************/ + +static int close_display(Display * dpy, XExtCodes * extCodes); +static /* const */ XExtensionHooks xf86dri_extension_hooks = { + NULL, /* create_gc */ + NULL, /* copy_gc */ + NULL, /* flush_gc */ + NULL, /* free_gc */ + NULL, /* create_font */ + NULL, /* free_font */ + close_display, /* close_display */ + NULL, /* wire_to_event */ + NULL, /* event_to_wire */ + NULL, /* error */ + NULL, /* error_string */ +}; + +static +XEXT_GENERATE_FIND_DISPLAY(find_display, xf86dri_info, + xf86dri_extension_name, &xf86dri_extension_hooks, 0, NULL) + + static XEXT_GENERATE_CLOSE_DISPLAY(close_display, xf86dri_info) + +/***************************************************************************** + * * + * public XFree86-DRI Extension routines * + * * + *****************************************************************************/ +#if 0 +#include +#define TRACE(msg) fprintf(stderr,"uniDRI%s\n", msg); +#else +#define TRACE(msg) +#endif + Bool uniDRIQueryExtension(dpy, event_basep, error_basep) + Display *dpy; + int *event_basep, *error_basep; +{ + XExtDisplayInfo *info = find_display(dpy); + + TRACE("QueryExtension..."); + if (XextHasExtension(info)) { + *event_basep = info->codes->first_event; + *error_basep = info->codes->first_error; + TRACE("QueryExtension... return True"); + return True; + } else { + TRACE("QueryExtension... return False"); + return False; + } +} + +Bool +uniDRIQueryVersion(dpy, majorVersion, minorVersion, patchVersion) + Display *dpy; + int *majorVersion; + int *minorVersion; + int *patchVersion; +{ + XExtDisplayInfo *info = find_display(dpy); + xXF86DRIQueryVersionReply rep; + xXF86DRIQueryVersionReq *req; + + TRACE("QueryVersion..."); + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIQueryVersion, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIQueryVersion; + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("QueryVersion... return False"); + return False; + } + *majorVersion = rep.majorVersion; + *minorVersion = rep.minorVersion; + *patchVersion = rep.patchVersion; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("QueryVersion... return True"); + return True; +} + +Bool +uniDRIQueryDirectRenderingCapable(dpy, screen, isCapable) + Display *dpy; + int screen; + Bool *isCapable; +{ + XExtDisplayInfo *info = find_display(dpy); + xXF86DRIQueryDirectRenderingCapableReply rep; + xXF86DRIQueryDirectRenderingCapableReq *req; + + TRACE("QueryDirectRenderingCapable..."); + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIQueryDirectRenderingCapable, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIQueryDirectRenderingCapable; + req->screen = screen; + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("QueryDirectRenderingCapable... return False"); + return False; + } + *isCapable = rep.isCapable; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("QueryDirectRenderingCapable... return True"); + return True; +} + +Bool +uniDRIOpenConnection(dpy, screen, hSAREA, busIdString) + Display *dpy; + int screen; + drm_handle_t *hSAREA; + char **busIdString; +{ + XExtDisplayInfo *info = find_display(dpy); + xXF86DRIOpenConnectionReply rep; + xXF86DRIOpenConnectionReq *req; + + TRACE("OpenConnection..."); + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIOpenConnection, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIOpenConnection; + req->screen = screen; + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("OpenConnection... return False"); + return False; + } + + *hSAREA = rep.hSAREALow; +#ifdef LONG64 + if (sizeof(drm_handle_t) == 8) { + *hSAREA |= ((unsigned long)rep.hSAREAHigh) << 32; + } +#endif + if (rep.length) { + if (!(*busIdString = (char *)Xcalloc(rep.busIdStringLength + 1, 1))) { + _XEatData(dpy, ((rep.busIdStringLength + 3) & ~3)); + UnlockDisplay(dpy); + SyncHandle(); + TRACE("OpenConnection... return False"); + return False; + } + _XReadPad(dpy, *busIdString, rep.busIdStringLength); + } else { + *busIdString = NULL; + } + UnlockDisplay(dpy); + SyncHandle(); + TRACE("OpenConnection... return True"); + return True; +} + +Bool +uniDRIAuthConnection(dpy, screen, magic) + Display *dpy; + int screen; + drm_magic_t magic; +{ + XExtDisplayInfo *info = find_display(dpy); + xXF86DRIAuthConnectionReq *req; + xXF86DRIAuthConnectionReply rep; + + TRACE("AuthConnection..."); + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIAuthConnection, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIAuthConnection; + req->screen = screen; + req->magic = magic; + rep.authenticated = 0; + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse) || !rep.authenticated) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("AuthConnection... return False"); + return False; + } + UnlockDisplay(dpy); + SyncHandle(); + TRACE("AuthConnection... return True"); + return True; +} + +Bool +uniDRICloseConnection(dpy, screen) + Display *dpy; + int screen; +{ + XExtDisplayInfo *info = find_display(dpy); + xXF86DRICloseConnectionReq *req; + + TRACE("CloseConnection..."); + + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRICloseConnection, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRICloseConnection; + req->screen = screen; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("CloseConnection... return True"); + return True; +} + +Bool +uniDRIGetClientDriverName(dpy, screen, ddxDriverMajorVersion, + ddxDriverMinorVersion, ddxDriverPatchVersion, clientDriverName) + Display *dpy; + int screen; + int *ddxDriverMajorVersion; + int *ddxDriverMinorVersion; + int *ddxDriverPatchVersion; + char **clientDriverName; +{ + XExtDisplayInfo *info = find_display(dpy); + xXF86DRIGetClientDriverNameReply rep; + xXF86DRIGetClientDriverNameReq *req; + + TRACE("GetClientDriverName..."); + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIGetClientDriverName, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIGetClientDriverName; + req->screen = screen; + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetClientDriverName... return False"); + return False; + } + + *ddxDriverMajorVersion = rep.ddxDriverMajorVersion; + *ddxDriverMinorVersion = rep.ddxDriverMinorVersion; + *ddxDriverPatchVersion = rep.ddxDriverPatchVersion; + + if (rep.length) { + if (!(*clientDriverName = + (char *)Xcalloc(rep.clientDriverNameLength + 1, 1))) { + _XEatData(dpy, ((rep.clientDriverNameLength + 3) & ~3)); + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetClientDriverName... return False"); + return False; + } + _XReadPad(dpy, *clientDriverName, rep.clientDriverNameLength); + } else { + *clientDriverName = NULL; + } + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetClientDriverName... return True"); + return True; +} + +Bool +uniDRICreateContextWithConfig(dpy, screen, configID, context, hHWContext) + Display *dpy; + int screen; + int configID; + XID *context; + drm_context_t *hHWContext; +{ + XExtDisplayInfo *info = find_display(dpy); + xXF86DRICreateContextReply rep; + xXF86DRICreateContextReq *req; + + TRACE("CreateContext..."); + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRICreateContext, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRICreateContext; + req->visual = configID; + req->screen = screen; + *context = XAllocID(dpy); + req->context = *context; + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("CreateContext... return False"); + return False; + } + *hHWContext = rep.hHWContext; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("CreateContext... return True"); + return True; +} + +Bool +uniDRICreateContext(dpy, screen, visual, context, hHWContext) + Display *dpy; + int screen; + Visual *visual; + XID *context; + drm_context_t *hHWContext; +{ + return uniDRICreateContextWithConfig(dpy, screen, visual->visualid, + context, hHWContext); +} + +Bool +uniDRIDestroyContext(Display * ndpy, int screen, XID context) +{ + Display *const dpy = (Display *) ndpy; + XExtDisplayInfo *info = find_display(dpy); + xXF86DRIDestroyContextReq *req; + + TRACE("DestroyContext..."); + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIDestroyContext, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIDestroyContext; + req->screen = screen; + req->context = context; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("DestroyContext... return True"); + return True; +} + +Bool +uniDRICreateDrawable(Display * ndpy, int screen, + Drawable drawable, drm_drawable_t * hHWDrawable) +{ + Display *const dpy = (Display *) ndpy; + XExtDisplayInfo *info = find_display(dpy); + xXF86DRICreateDrawableReply rep; + xXF86DRICreateDrawableReq *req; + + TRACE("CreateDrawable..."); + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRICreateDrawable, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRICreateDrawable; + req->screen = screen; + req->drawable = drawable; + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("CreateDrawable... return False"); + return False; + } + *hHWDrawable = rep.hHWDrawable; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("CreateDrawable... return True"); + return True; +} + +Bool +uniDRIDestroyDrawable(Display * ndpy, int screen, Drawable drawable) +{ + Display *const dpy = (Display *) ndpy; + XExtDisplayInfo *info = find_display(dpy); + xXF86DRIDestroyDrawableReq *req; + + TRACE("DestroyDrawable..."); + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIDestroyDrawable, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIDestroyDrawable; + req->screen = screen; + req->drawable = drawable; + UnlockDisplay(dpy); + SyncHandle(); + TRACE("DestroyDrawable... return True"); + return True; +} + +Bool +uniDRIGetDrawableInfo(Display * dpy, int screen, Drawable drawable, + unsigned int *index, unsigned int *stamp, + int *X, int *Y, int *W, int *H, + int *numClipRects, drm_clip_rect_t ** pClipRects, + int *backX, int *backY, + int *numBackClipRects, drm_clip_rect_t ** pBackClipRects) +{ + XExtDisplayInfo *info = find_display(dpy); + xXF86DRIGetDrawableInfoReply rep; + xXF86DRIGetDrawableInfoReq *req; + int total_rects; + + TRACE("GetDrawableInfo..."); + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIGetDrawableInfo, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIGetDrawableInfo; + req->screen = screen; + req->drawable = drawable; + + if (!_XReply(dpy, (xReply *) & rep, 1, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDrawableInfo... return False"); + return False; + } + *index = rep.drawableTableIndex; + *stamp = rep.drawableTableStamp; + *X = (int)rep.drawableX; + *Y = (int)rep.drawableY; + *W = (int)rep.drawableWidth; + *H = (int)rep.drawableHeight; + *numClipRects = rep.numClipRects; + total_rects = *numClipRects; + + *backX = rep.backX; + *backY = rep.backY; + *numBackClipRects = rep.numBackClipRects; + total_rects += *numBackClipRects; + +#if 0 + /* Because of the fix in Xserver/GL/dri/xf86dri.c, this check breaks + * backwards compatibility (Because of the >> 2 shift) but the fix + * enables multi-threaded apps to work. + */ + if (rep.length != ((((SIZEOF(xXF86DRIGetDrawableInfoReply) - + SIZEOF(xGenericReply) + + total_rects * sizeof(drm_clip_rect_t)) + + 3) & ~3) >> 2)) { + _XEatData(dpy, rep.length); + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDrawableInfo... return False"); + return False; + } +#endif + + if (*numClipRects) { + int len = sizeof(drm_clip_rect_t) * (*numClipRects); + + *pClipRects = (drm_clip_rect_t *) Xcalloc(len, 1); + if (*pClipRects) + _XRead(dpy, (char *)*pClipRects, len); + } else { + *pClipRects = NULL; + } + + if (*numBackClipRects) { + int len = sizeof(drm_clip_rect_t) * (*numBackClipRects); + + *pBackClipRects = (drm_clip_rect_t *) Xcalloc(len, 1); + if (*pBackClipRects) + _XRead(dpy, (char *)*pBackClipRects, len); + } else { + *pBackClipRects = NULL; + } + + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDrawableInfo... return True"); + return True; +} + +Bool +uniDRIGetDeviceInfo(dpy, screen, hFrameBuffer, + fbOrigin, fbSize, fbStride, devPrivateSize, pDevPrivate) + Display *dpy; + int screen; + drm_handle_t *hFrameBuffer; + int *fbOrigin; + int *fbSize; + int *fbStride; + int *devPrivateSize; + void **pDevPrivate; +{ + XExtDisplayInfo *info = find_display(dpy); + xXF86DRIGetDeviceInfoReply rep; + xXF86DRIGetDeviceInfoReq *req; + + TRACE("GetDeviceInfo..."); + uniDRICheckExtension(dpy, info, False); + + LockDisplay(dpy); + GetReq(XF86DRIGetDeviceInfo, req); + req->reqType = info->codes->major_opcode; + req->driReqType = X_XF86DRIGetDeviceInfo; + req->screen = screen; + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDeviceInfo... return False"); + return False; + } + + *hFrameBuffer = rep.hFrameBufferLow; +#ifdef LONG64 + if (sizeof(drm_handle_t) == 8) { + *hFrameBuffer |= ((unsigned long)rep.hFrameBufferHigh) << 32; + } +#endif + + *fbOrigin = rep.framebufferOrigin; + *fbSize = rep.framebufferSize; + *fbStride = rep.framebufferStride; + *devPrivateSize = rep.devPrivateSize; + + if (rep.length) { + if (!(*pDevPrivate = (void *)Xcalloc(rep.devPrivateSize, 1))) { + _XEatData(dpy, ((rep.devPrivateSize + 3) & ~3)); + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDeviceInfo... return False"); + return False; + } + _XRead(dpy, (char *)*pDevPrivate, rep.devPrivateSize); + } else { + *pDevPrivate = NULL; + } + + UnlockDisplay(dpy); + SyncHandle(); + TRACE("GetDeviceInfo... return True"); + return True; +} diff --git a/tests/ttmtest/src/xf86dri.h b/tests/ttmtest/src/xf86dri.h new file mode 100644 index 0000000..8fb7896 --- /dev/null +++ b/tests/ttmtest/src/xf86dri.h @@ -0,0 +1,116 @@ +/* $XFree86: xc/lib/GL/dri/xf86dri.h,v 1.8 2002/10/30 12:51:25 alanh Exp $ */ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright 2000 VA Linux Systems, Inc. +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 PRECISION INSIGHT 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. + +**************************************************************************/ + +/** + * \file xf86dri.h + * Protocol numbers and function prototypes for DRI X protocol. + * + * \author Kevin E. Martin + * \author Jens Owen + * \author Rickard E. (Rik) Faith + */ + +#ifndef _XF86DRI_H_ +#define _XF86DRI_H_ + +#include +#include + +#define X_XF86DRIQueryVersion 0 +#define X_XF86DRIQueryDirectRenderingCapable 1 +#define X_XF86DRIOpenConnection 2 +#define X_XF86DRICloseConnection 3 +#define X_XF86DRIGetClientDriverName 4 +#define X_XF86DRICreateContext 5 +#define X_XF86DRIDestroyContext 6 +#define X_XF86DRICreateDrawable 7 +#define X_XF86DRIDestroyDrawable 8 +#define X_XF86DRIGetDrawableInfo 9 +#define X_XF86DRIGetDeviceInfo 10 +#define X_XF86DRIAuthConnection 11 +#define X_XF86DRIOpenFullScreen 12 /* Deprecated */ +#define X_XF86DRICloseFullScreen 13 /* Deprecated */ + +#define XF86DRINumberEvents 0 + +#define XF86DRIClientNotLocal 0 +#define XF86DRIOperationNotSupported 1 +#define XF86DRINumberErrors (XF86DRIOperationNotSupported + 1) + +#ifndef _XF86DRI_SERVER_ + +_XFUNCPROTOBEGIN + Bool uniDRIQueryExtension(Display * dpy, int *event_base, + int *error_base); + +Bool uniDRIQueryVersion(Display * dpy, int *majorVersion, int *minorVersion, + int *patchVersion); + +Bool uniDRIQueryDirectRenderingCapable(Display * dpy, int screen, + Bool * isCapable); + +Bool uniDRIOpenConnection(Display * dpy, int screen, drm_handle_t * hSAREA, + char **busIDString); + +Bool uniDRIAuthConnection(Display * dpy, int screen, drm_magic_t magic); + +Bool uniDRICloseConnection(Display * dpy, int screen); + +Bool uniDRIGetClientDriverName(Display * dpy, int screen, + int *ddxDriverMajorVersion, int *ddxDriverMinorVersion, + int *ddxDriverPatchVersion, char **clientDriverName); + +Bool uniDRICreateContext(Display * dpy, int screen, Visual * visual, + XID * ptr_to_returned_context_id, drm_context_t * hHWContext); + +Bool uniDRICreateContextWithConfig(Display * dpy, int screen, int configID, + XID * ptr_to_returned_context_id, drm_context_t * hHWContext); + +extern Bool uniDRIDestroyContext(Display * dpy, int screen, XID context_id); + +extern Bool uniDRICreateDrawable(Display * dpy, int screen, + Drawable drawable, drm_drawable_t * hHWDrawable); + +extern Bool uniDRIDestroyDrawable(Display * dpy, int screen, + Drawable drawable); + +Bool uniDRIGetDrawableInfo(Display * dpy, int screen, Drawable drawable, + unsigned int *index, unsigned int *stamp, + int *X, int *Y, int *W, int *H, + int *numClipRects, drm_clip_rect_t ** pClipRects, + int *backX, int *backY, + int *numBackClipRects, drm_clip_rect_t ** pBackClipRects); + +Bool uniDRIGetDeviceInfo(Display * dpy, int screen, + drm_handle_t * hFrameBuffer, int *fbOrigin, int *fbSize, + int *fbStride, int *devPrivateSize, void **pDevPrivate); + +_XFUNCPROTOEND +#endif /* _XF86DRI_SERVER_ */ +#endif /* _XF86DRI_H_ */ diff --git a/tests/ttmtest/src/xf86dristr.h b/tests/ttmtest/src/xf86dristr.h new file mode 100644 index 0000000..2730d1a --- /dev/null +++ b/tests/ttmtest/src/xf86dristr.h @@ -0,0 +1,390 @@ +/* $XFree86: xc/lib/GL/dri/xf86dristr.h,v 1.10 2002/10/30 12:51:25 alanh Exp $ */ +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +Copyright 2000 VA Linux Systems, Inc. +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 PRECISION INSIGHT 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin + * Jens Owen + * Rickard E. (Rik) Fiath + * + */ + +#ifndef _XF86DRISTR_H_ +#define _XF86DRISTR_H_ + +#include "xf86dri.h" + +#define XF86DRINAME "XFree86-DRI" + +/* The DRI version number. This was originally set to be the same as the + * XFree86 version number. However, this version is really independent of + * the XFree86 version. + * + * Version History: + * 4.0.0: Original + * 4.0.1: Patch to bump clipstamp when windows are destroyed, 28 May 02 + * 4.1.0: Add transition from single to multi in DRMInfo rec, 24 Jun 02 + */ +#define XF86DRI_MAJOR_VERSION 4 +#define XF86DRI_MINOR_VERSION 1 +#define XF86DRI_PATCH_VERSION 0 + +typedef struct _XF86DRIQueryVersion +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIQueryVersion */ + CARD16 length B16; +} xXF86DRIQueryVersionReq; + +#define sz_xXF86DRIQueryVersionReq 4 + +typedef struct +{ + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD16 majorVersion B16; /* major version of DRI protocol */ + CARD16 minorVersion B16; /* minor version of DRI protocol */ + CARD32 patchVersion B32; /* patch version of DRI protocol */ + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRIQueryVersionReply; + +#define sz_xXF86DRIQueryVersionReply 32 + +typedef struct _XF86DRIQueryDirectRenderingCapable +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* X_DRIQueryDirectRenderingCapable */ + CARD16 length B16; + CARD32 screen B32; +} xXF86DRIQueryDirectRenderingCapableReq; + +#define sz_xXF86DRIQueryDirectRenderingCapableReq 8 + +typedef struct +{ + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + BOOL isCapable; + BOOL pad2; + BOOL pad3; + BOOL pad4; + CARD32 pad5 B32; + CARD32 pad6 B32; + CARD32 pad7 B32; + CARD32 pad8 B32; + CARD32 pad9 B32; +} xXF86DRIQueryDirectRenderingCapableReply; + +#define sz_xXF86DRIQueryDirectRenderingCapableReply 32 + +typedef struct _XF86DRIOpenConnection +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIOpenConnection */ + CARD16 length B16; + CARD32 screen B32; +} xXF86DRIOpenConnectionReq; + +#define sz_xXF86DRIOpenConnectionReq 8 + +typedef struct +{ + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 hSAREALow B32; + CARD32 hSAREAHigh B32; + CARD32 busIdStringLength B32; + CARD32 pad6 B32; + CARD32 pad7 B32; + CARD32 pad8 B32; +} xXF86DRIOpenConnectionReply; + +#define sz_xXF86DRIOpenConnectionReply 32 + +typedef struct _XF86DRIAuthConnection +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRICloseConnection */ + CARD16 length B16; + CARD32 screen B32; + CARD32 magic B32; +} xXF86DRIAuthConnectionReq; + +#define sz_xXF86DRIAuthConnectionReq 12 + +typedef struct +{ + BYTE type; + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 authenticated B32; + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRIAuthConnectionReply; + +#define zx_xXF86DRIAuthConnectionReply 32 + +typedef struct _XF86DRICloseConnection +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRICloseConnection */ + CARD16 length B16; + CARD32 screen B32; +} xXF86DRICloseConnectionReq; + +#define sz_xXF86DRICloseConnectionReq 8 + +typedef struct _XF86DRIGetClientDriverName +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIGetClientDriverName */ + CARD16 length B16; + CARD32 screen B32; +} xXF86DRIGetClientDriverNameReq; + +#define sz_xXF86DRIGetClientDriverNameReq 8 + +typedef struct +{ + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 ddxDriverMajorVersion B32; + CARD32 ddxDriverMinorVersion B32; + CARD32 ddxDriverPatchVersion B32; + CARD32 clientDriverNameLength B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRIGetClientDriverNameReply; + +#define sz_xXF86DRIGetClientDriverNameReply 32 + +typedef struct _XF86DRICreateContext +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRICreateContext */ + CARD16 length B16; + CARD32 screen B32; + CARD32 visual B32; + CARD32 context B32; +} xXF86DRICreateContextReq; + +#define sz_xXF86DRICreateContextReq 16 + +typedef struct +{ + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 hHWContext B32; + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRICreateContextReply; + +#define sz_xXF86DRICreateContextReply 32 + +typedef struct _XF86DRIDestroyContext +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIDestroyContext */ + CARD16 length B16; + CARD32 screen B32; + CARD32 context B32; +} xXF86DRIDestroyContextReq; + +#define sz_xXF86DRIDestroyContextReq 12 + +typedef struct _XF86DRICreateDrawable +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRICreateDrawable */ + CARD16 length B16; + CARD32 screen B32; + CARD32 drawable B32; +} xXF86DRICreateDrawableReq; + +#define sz_xXF86DRICreateDrawableReq 12 + +typedef struct +{ + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 hHWDrawable B32; + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRICreateDrawableReply; + +#define sz_xXF86DRICreateDrawableReply 32 + +typedef struct _XF86DRIDestroyDrawable +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIDestroyDrawable */ + CARD16 length B16; + CARD32 screen B32; + CARD32 drawable B32; +} xXF86DRIDestroyDrawableReq; + +#define sz_xXF86DRIDestroyDrawableReq 12 + +typedef struct _XF86DRIGetDrawableInfo +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIGetDrawableInfo */ + CARD16 length B16; + CARD32 screen B32; + CARD32 drawable B32; +} xXF86DRIGetDrawableInfoReq; + +#define sz_xXF86DRIGetDrawableInfoReq 12 + +typedef struct +{ + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 drawableTableIndex B32; + CARD32 drawableTableStamp B32; + INT16 drawableX B16; + INT16 drawableY B16; + INT16 drawableWidth B16; + INT16 drawableHeight B16; + CARD32 numClipRects B32; + INT16 backX B16; + INT16 backY B16; + CARD32 numBackClipRects B32; +} xXF86DRIGetDrawableInfoReply; + +#define sz_xXF86DRIGetDrawableInfoReply 36 + +typedef struct _XF86DRIGetDeviceInfo +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIGetDeviceInfo */ + CARD16 length B16; + CARD32 screen B32; +} xXF86DRIGetDeviceInfoReq; + +#define sz_xXF86DRIGetDeviceInfoReq 8 + +typedef struct +{ + BYTE type; /* X_Reply */ + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 hFrameBufferLow B32; + CARD32 hFrameBufferHigh B32; + CARD32 framebufferOrigin B32; + CARD32 framebufferSize B32; + CARD32 framebufferStride B32; + CARD32 devPrivateSize B32; +} xXF86DRIGetDeviceInfoReply; + +#define sz_xXF86DRIGetDeviceInfoReply 32 + +typedef struct _XF86DRIOpenFullScreen +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRIOpenFullScreen */ + CARD16 length B16; + CARD32 screen B32; + CARD32 drawable B32; +} xXF86DRIOpenFullScreenReq; + +#define sz_xXF86DRIOpenFullScreenReq 12 + +typedef struct +{ + BYTE type; + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 isFullScreen B32; + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xXF86DRIOpenFullScreenReply; + +#define sz_xXF86DRIOpenFullScreenReply 32 + +typedef struct _XF86DRICloseFullScreen +{ + CARD8 reqType; /* always DRIReqCode */ + CARD8 driReqType; /* always X_DRICloseFullScreen */ + CARD16 length B16; + CARD32 screen B32; + CARD32 drawable B32; +} xXF86DRICloseFullScreenReq; + +#define sz_xXF86DRICloseFullScreenReq 12 + +typedef struct +{ + BYTE type; + BOOL pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; + CARD32 pad7 B32; +} xXF86DRICloseFullScreenReply; + +#define sz_xXF86DRICloseFullScreenReply 32 + +#endif /* _XF86DRISTR_H_ */ diff --git a/tests/util/Android.mk b/tests/util/Android.mk new file mode 100644 index 0000000..12eccb4 --- /dev/null +++ b/tests/util/Android.mk @@ -0,0 +1,38 @@ +# +# Copyright © 2015 NVIDIA Corporation +# +# 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 (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 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +include $(LOCAL_PATH)/Makefile.sources + +LOCAL_MODULE := libdrm_util + +LOCAL_SHARED_LIBRARIES := libdrm + +LOCAL_SRC_FILES := $(UTIL_FILES) + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LIBDRM_TOP)/tests + +include $(LIBDRM_COMMON_MK) +include $(BUILD_STATIC_LIBRARY) diff --git a/tests/util/Makefile.sources b/tests/util/Makefile.sources new file mode 100644 index 0000000..e5f8511 --- /dev/null +++ b/tests/util/Makefile.sources @@ -0,0 +1,8 @@ +UTIL_FILES := \ + common.h \ + format.c \ + format.h \ + kms.c \ + kms.h \ + pattern.c \ + pattern.h diff --git a/tests/util/common.h b/tests/util/common.h new file mode 100644 index 0000000..5d572c2 --- /dev/null +++ b/tests/util/common.h @@ -0,0 +1,33 @@ +/* + * Copyright 2008 Tungsten Graphics + * Jakob Bornecrantz + * Copyright 2008 Intel Corporation + * Jesse Barnes + * + * 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. + */ + +#ifndef UTIL_COMMON_H +#define UTIL_COMMON_H + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#endif + +#endif /* UTIL_COMMON_H */ diff --git a/tests/util/format.c b/tests/util/format.c new file mode 100644 index 0000000..1ca1b82 --- /dev/null +++ b/tests/util/format.c @@ -0,0 +1,123 @@ +/* + * Copyright 2008 Tungsten Graphics + * Jakob Bornecrantz + * Copyright 2008 Intel Corporation + * Jesse Barnes + * + * 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. + */ + +#include +#include +#include + +#include + +#include "common.h" +#include "format.h" + +#define MAKE_RGB_INFO(rl, ro, gl, go, bl, bo, al, ao) \ + .rgb = { { (rl), (ro) }, { (gl), (go) }, { (bl), (bo) }, { (al), (ao) } } + +#define MAKE_YUV_INFO(order, xsub, ysub, chroma_stride) \ + .yuv = { (order), (xsub), (ysub), (chroma_stride) } + +static const struct util_format_info format_info[] = { + /* Indexed */ + { DRM_FORMAT_C8, "C8" }, + /* YUV packed */ + { DRM_FORMAT_UYVY, "UYVY", MAKE_YUV_INFO(YUV_YCbCr | YUV_CY, 2, 2, 2) }, + { DRM_FORMAT_VYUY, "VYUY", MAKE_YUV_INFO(YUV_YCrCb | YUV_CY, 2, 2, 2) }, + { DRM_FORMAT_YUYV, "YUYV", MAKE_YUV_INFO(YUV_YCbCr | YUV_YC, 2, 2, 2) }, + { DRM_FORMAT_YVYU, "YVYU", MAKE_YUV_INFO(YUV_YCrCb | YUV_YC, 2, 2, 2) }, + /* YUV semi-planar */ + { DRM_FORMAT_NV12, "NV12", MAKE_YUV_INFO(YUV_YCbCr, 2, 2, 2) }, + { DRM_FORMAT_NV21, "NV21", MAKE_YUV_INFO(YUV_YCrCb, 2, 2, 2) }, + { DRM_FORMAT_NV16, "NV16", MAKE_YUV_INFO(YUV_YCbCr, 2, 1, 2) }, + { DRM_FORMAT_NV61, "NV61", MAKE_YUV_INFO(YUV_YCrCb, 2, 1, 2) }, + /* YUV planar */ + { DRM_FORMAT_YUV420, "YU12", MAKE_YUV_INFO(YUV_YCbCr, 2, 2, 1) }, + { DRM_FORMAT_YVU420, "YV12", MAKE_YUV_INFO(YUV_YCrCb, 2, 2, 1) }, + /* RGB16 */ + { DRM_FORMAT_ARGB4444, "AR12", MAKE_RGB_INFO(4, 8, 4, 4, 4, 0, 4, 12) }, + { DRM_FORMAT_XRGB4444, "XR12", MAKE_RGB_INFO(4, 8, 4, 4, 4, 0, 0, 0) }, + { DRM_FORMAT_ABGR4444, "AB12", MAKE_RGB_INFO(4, 0, 4, 4, 4, 8, 4, 12) }, + { DRM_FORMAT_XBGR4444, "XB12", MAKE_RGB_INFO(4, 0, 4, 4, 4, 8, 0, 0) }, + { DRM_FORMAT_RGBA4444, "RA12", MAKE_RGB_INFO(4, 12, 4, 8, 4, 4, 4, 0) }, + { DRM_FORMAT_RGBX4444, "RX12", MAKE_RGB_INFO(4, 12, 4, 8, 4, 4, 0, 0) }, + { DRM_FORMAT_BGRA4444, "BA12", MAKE_RGB_INFO(4, 4, 4, 8, 4, 12, 4, 0) }, + { DRM_FORMAT_BGRX4444, "BX12", MAKE_RGB_INFO(4, 4, 4, 8, 4, 12, 0, 0) }, + { DRM_FORMAT_ARGB1555, "AR15", MAKE_RGB_INFO(5, 10, 5, 5, 5, 0, 1, 15) }, + { DRM_FORMAT_XRGB1555, "XR15", MAKE_RGB_INFO(5, 10, 5, 5, 5, 0, 0, 0) }, + { DRM_FORMAT_ABGR1555, "AB15", MAKE_RGB_INFO(5, 0, 5, 5, 5, 10, 1, 15) }, + { DRM_FORMAT_XBGR1555, "XB15", MAKE_RGB_INFO(5, 0, 5, 5, 5, 10, 0, 0) }, + { DRM_FORMAT_RGBA5551, "RA15", MAKE_RGB_INFO(5, 11, 5, 6, 5, 1, 1, 0) }, + { DRM_FORMAT_RGBX5551, "RX15", MAKE_RGB_INFO(5, 11, 5, 6, 5, 1, 0, 0) }, + { DRM_FORMAT_BGRA5551, "BA15", MAKE_RGB_INFO(5, 1, 5, 6, 5, 11, 1, 0) }, + { DRM_FORMAT_BGRX5551, "BX15", MAKE_RGB_INFO(5, 1, 5, 6, 5, 11, 0, 0) }, + { DRM_FORMAT_RGB565, "RG16", MAKE_RGB_INFO(5, 11, 6, 5, 5, 0, 0, 0) }, + { DRM_FORMAT_BGR565, "BG16", MAKE_RGB_INFO(5, 0, 6, 5, 5, 11, 0, 0) }, + /* RGB24 */ + { DRM_FORMAT_BGR888, "BG24", MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 0, 0) }, + { DRM_FORMAT_RGB888, "RG24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 0, 0) }, + /* RGB32 */ + { DRM_FORMAT_ARGB8888, "AR24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 8, 24) }, + { DRM_FORMAT_XRGB8888, "XR24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 0, 0) }, + { DRM_FORMAT_ABGR8888, "AB24", MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 8, 24) }, + { DRM_FORMAT_XBGR8888, "XB24", MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 0, 0) }, + { DRM_FORMAT_RGBA8888, "RA24", MAKE_RGB_INFO(8, 24, 8, 16, 8, 8, 8, 0) }, + { DRM_FORMAT_RGBX8888, "RX24", MAKE_RGB_INFO(8, 24, 8, 16, 8, 8, 0, 0) }, + { DRM_FORMAT_BGRA8888, "BA24", MAKE_RGB_INFO(8, 8, 8, 16, 8, 24, 8, 0) }, + { DRM_FORMAT_BGRX8888, "BX24", MAKE_RGB_INFO(8, 8, 8, 16, 8, 24, 0, 0) }, + { DRM_FORMAT_ARGB2101010, "AR30", MAKE_RGB_INFO(10, 20, 10, 10, 10, 0, 2, 30) }, + { DRM_FORMAT_XRGB2101010, "XR30", MAKE_RGB_INFO(10, 20, 10, 10, 10, 0, 0, 0) }, + { DRM_FORMAT_ABGR2101010, "AB30", MAKE_RGB_INFO(10, 0, 10, 10, 10, 20, 2, 30) }, + { DRM_FORMAT_XBGR2101010, "XB30", MAKE_RGB_INFO(10, 0, 10, 10, 10, 20, 0, 0) }, + { DRM_FORMAT_RGBA1010102, "RA30", MAKE_RGB_INFO(10, 22, 10, 12, 10, 2, 2, 0) }, + { DRM_FORMAT_RGBX1010102, "RX30", MAKE_RGB_INFO(10, 22, 10, 12, 10, 2, 0, 0) }, + { DRM_FORMAT_BGRA1010102, "BA30", MAKE_RGB_INFO(10, 2, 10, 12, 10, 22, 2, 0) }, + { DRM_FORMAT_BGRX1010102, "BX30", MAKE_RGB_INFO(10, 2, 10, 12, 10, 22, 0, 0) }, + { DRM_FORMAT_XRGB16161616F, "XR4H", MAKE_RGB_INFO(16, 32, 16, 16, 16, 0, 0, 0) }, + { DRM_FORMAT_XBGR16161616F, "XB4H", MAKE_RGB_INFO(16, 0, 16, 16, 16, 32, 0, 0) }, + { DRM_FORMAT_ARGB16161616F, "AR4H", MAKE_RGB_INFO(16, 32, 16, 16, 16, 0, 16, 48) }, + { DRM_FORMAT_ABGR16161616F, "AB4H", MAKE_RGB_INFO(16, 0, 16, 16, 16, 32, 16, 48) }, + +}; + +uint32_t util_format_fourcc(const char *name) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(format_info); i++) + if (!strcmp(format_info[i].name, name)) + return format_info[i].format; + + return 0; +} + +const struct util_format_info *util_format_info_find(uint32_t format) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(format_info); i++) + if (format_info[i].format == format) + return &format_info[i]; + + return NULL; +} diff --git a/tests/util/format.h b/tests/util/format.h new file mode 100644 index 0000000..2ce1c02 --- /dev/null +++ b/tests/util/format.h @@ -0,0 +1,65 @@ +/* + * Copyright 2008 Tungsten Graphics + * Jakob Bornecrantz + * Copyright 2008 Intel Corporation + * Jesse Barnes + * + * 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. + */ + +#ifndef UTIL_FORMAT_H +#define UTIL_FORMAT_H + +struct util_color_component { + unsigned int length; + unsigned int offset; +}; + +struct util_rgb_info { + struct util_color_component red; + struct util_color_component green; + struct util_color_component blue; + struct util_color_component alpha; +}; + +enum util_yuv_order { + YUV_YCbCr = 1, + YUV_YCrCb = 2, + YUV_YC = 4, + YUV_CY = 8, +}; + +struct util_yuv_info { + enum util_yuv_order order; + unsigned int xsub; + unsigned int ysub; + unsigned int chroma_stride; +}; + +struct util_format_info { + uint32_t format; + const char *name; + const struct util_rgb_info rgb; + const struct util_yuv_info yuv; +}; + +uint32_t util_format_fourcc(const char *name); +const struct util_format_info *util_format_info_find(uint32_t format); + +#endif /* UTIL_FORMAT_H */ diff --git a/tests/util/kms.c b/tests/util/kms.c new file mode 100644 index 0000000..95b7a45 --- /dev/null +++ b/tests/util/kms.c @@ -0,0 +1,163 @@ +/* + * Copyright 2008 Tungsten Graphics + * Jakob Bornecrantz + * Copyright 2008 Intel Corporation + * Jesse Barnes + * + * 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. + */ + +/* + * This fairly simple test program dumps output in a similar format to the + * "xrandr" tool everyone knows & loves. It's necessarily slightly different + * since the kernel separates outputs into encoder and connector structures, + * each with their own unique ID. The program also allows test testing of the + * memory management and mode setting APIs by allowing the user to specify a + * connector and mode to use for mode setting. If all works as expected, a + * blue background should be painted on the monitor attached to the specified + * connector after the selected mode is set. + * + * TODO: use cairo to write the mode info on the selected output once + * the mode has been programmed, along with possible test patterns. + */ + +#include +#include +#include +#include +#include + +#include "xf86drm.h" +#include "xf86drmMode.h" + +#include "common.h" + +struct type_name { + unsigned int type; + const char *name; +}; + +static const char *util_lookup_type_name(unsigned int type, + const struct type_name *table, + unsigned int count) +{ + unsigned int i; + + for (i = 0; i < count; i++) + if (table[i].type == type) + return table[i].name; + + return NULL; +} + +static const struct type_name encoder_type_names[] = { + { DRM_MODE_ENCODER_NONE, "none" }, + { DRM_MODE_ENCODER_DAC, "DAC" }, + { DRM_MODE_ENCODER_TMDS, "TMDS" }, + { DRM_MODE_ENCODER_LVDS, "LVDS" }, + { DRM_MODE_ENCODER_TVDAC, "TVDAC" }, + { DRM_MODE_ENCODER_VIRTUAL, "Virtual" }, + { DRM_MODE_ENCODER_DSI, "DSI" }, + { DRM_MODE_ENCODER_DPMST, "DPMST" }, + { DRM_MODE_ENCODER_DPI, "DPI" }, +}; + +const char *util_lookup_encoder_type_name(unsigned int type) +{ + return util_lookup_type_name(type, encoder_type_names, + ARRAY_SIZE(encoder_type_names)); +} + +static const struct type_name connector_status_names[] = { + { DRM_MODE_CONNECTED, "connected" }, + { DRM_MODE_DISCONNECTED, "disconnected" }, + { DRM_MODE_UNKNOWNCONNECTION, "unknown" }, +}; + +const char *util_lookup_connector_status_name(unsigned int status) +{ + return util_lookup_type_name(status, connector_status_names, + ARRAY_SIZE(connector_status_names)); +} + +static const char * const modules[] = { + "i915", + "amdgpu", + "radeon", + "nouveau", + "vmwgfx", + "omapdrm", + "exynos", + "tilcdc", + "msm", + "sti", + "tegra", + "imx-drm", + "rockchip", + "atmel-hlcdc", + "fsl-dcu-drm", + "vc4", + "virtio_gpu", + "mediatek", + "meson", + "pl111", + "stm", + "sun4i-drm", + "armada-drm", + "komeda", + "imx-dcss", + "mxsfb-drm", + "simpledrm", + "imx-lcdif", +}; + +int util_open(const char *device, const char *module) +{ + int fd; + + if (module) { + fd = drmOpen(module, device); + if (fd < 0) { + fprintf(stderr, "failed to open device '%s': %s\n", + module, strerror(errno)); + return -errno; + } + } else { + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(modules); i++) { + printf("trying to open device '%s'...", modules[i]); + + fd = drmOpen(modules[i], device); + if (fd < 0) { + printf("failed\n"); + } else { + printf("done\n"); + break; + } + } + + if (fd < 0) { + fprintf(stderr, "no device found\n"); + return -ENODEV; + } + } + + return fd; +} diff --git a/tests/util/kms.h b/tests/util/kms.h new file mode 100644 index 0000000..f79f461 --- /dev/null +++ b/tests/util/kms.h @@ -0,0 +1,34 @@ +/* + * Copyright 2008 Tungsten Graphics + * Jakob Bornecrantz + * Copyright 2008 Intel Corporation + * Jesse Barnes + * + * 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. + */ + +#ifndef UTIL_KMS_H +#define UTIL_KMS_H + +const char *util_lookup_encoder_type_name(unsigned int type); +const char *util_lookup_connector_status_name(unsigned int type); + +int util_open(const char *device, const char *module); + +#endif /* UTIL_KMS_H */ diff --git a/tests/util/meson.build b/tests/util/meson.build new file mode 100644 index 0000000..7fa1a4b --- /dev/null +++ b/tests/util/meson.build @@ -0,0 +1,28 @@ +# Copyright © 2017-2018 Intel Corporation + +# 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. + + +libutil = static_library( + 'util', + [files('format.c', 'kms.c', 'pattern.c'), config_file], + include_directories : [inc_root, inc_drm], + link_with : libdrm, + dependencies : dep_cairo +) diff --git a/tests/util/pattern.c b/tests/util/pattern.c new file mode 100644 index 0000000..158c0b1 --- /dev/null +++ b/tests/util/pattern.c @@ -0,0 +1,1282 @@ +/* + * Copyright 2008 Tungsten Graphics + * Jakob Bornecrantz + * Copyright 2008 Intel Corporation + * Jesse Barnes + * + * 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. + */ + +#include +#include +#include +#include + +#include + +#if HAVE_CAIRO +#include +#include +#endif + +#include "common.h" +#include "format.h" +#include "pattern.h" + +struct color_rgb24 { + unsigned int value:24; +} __attribute__((__packed__)); + +struct color_yuv { + unsigned char y; + unsigned char u; + unsigned char v; +}; + +#define MAKE_YUV_601_Y(r, g, b) \ + ((( 66 * (r) + 129 * (g) + 25 * (b) + 128) >> 8) + 16) +#define MAKE_YUV_601_U(r, g, b) \ + (((-38 * (r) - 74 * (g) + 112 * (b) + 128) >> 8) + 128) +#define MAKE_YUV_601_V(r, g, b) \ + (((112 * (r) - 94 * (g) - 18 * (b) + 128) >> 8) + 128) + +#define MAKE_YUV_601(r, g, b) \ + { .y = MAKE_YUV_601_Y(r, g, b), \ + .u = MAKE_YUV_601_U(r, g, b), \ + .v = MAKE_YUV_601_V(r, g, b) } + +/* This function takes 8-bit color values */ +static inline uint32_t shiftcolor8(const struct util_color_component *comp, + uint32_t value) +{ + value &= 0xff; + /* Fill the low bits with the high bits. */ + value = (value << 8) | value; + /* Shift down to remove unwanted low bits */ + value = value >> (16 - comp->length); + /* Shift back up to where the value should be */ + return value << comp->offset; +} + +/* This function takes 10-bit color values */ +static inline uint32_t shiftcolor10(const struct util_color_component *comp, + uint32_t value) +{ + value &= 0x3ff; + /* Fill the low bits with the high bits. */ + value = (value << 6) | (value >> 4); + /* Shift down to remove unwanted low bits */ + value = value >> (16 - comp->length); + /* Shift back up to where the value should be */ + return value << comp->offset; +} + +/* This function takes 16-bit color values */ +static inline uint64_t shiftcolor16(const struct util_color_component *comp, + uint64_t value) +{ + value &= 0xffff; + /* Shift down to remove unwanted low bits */ + value = value >> (16 - comp->length); + /* Shift back up to where the value should be */ + return value << comp->offset; +} + +#define MAKE_RGBA10(rgb, r, g, b, a) \ + (shiftcolor10(&(rgb)->red, (r)) | \ + shiftcolor10(&(rgb)->green, (g)) | \ + shiftcolor10(&(rgb)->blue, (b)) | \ + shiftcolor10(&(rgb)->alpha, (a))) + +#define MAKE_RGBA(rgb, r, g, b, a) \ + (shiftcolor8(&(rgb)->red, (r)) | \ + shiftcolor8(&(rgb)->green, (g)) | \ + shiftcolor8(&(rgb)->blue, (b)) | \ + shiftcolor8(&(rgb)->alpha, (a))) + +#define MAKE_RGB24(rgb, r, g, b) \ + { .value = MAKE_RGBA(rgb, r, g, b, 0) } + + +/** + * Takes a uint16_t, divides by 65536, converts the infinite-precision + * result to fp16 with round-to-zero. + * + * Copied from mesa:src/util/half_float.c + */ +static uint16_t uint16_div_64k_to_half(uint16_t v) +{ + /* Zero or subnormal. Set the mantissa to (v << 8) and return. */ + if (v < 4) + return v << 8; + + /* Count the leading 0s in the uint16_t */ + int n = __builtin_clz(v) - 16; + + /* Shift the mantissa up so bit 16 is the hidden 1 bit, + * mask it off, then shift back down to 10 bits + */ + int m = ( ((uint32_t)v << (n + 1)) & 0xffff ) >> 6; + + /* (0{n} 1 X{15-n}) * 2^-16 + * = 1.X * 2^(15-n-16) + * = 1.X * 2^(14-n - 15) + * which is the FP16 form with e = 14 - n + */ + int e = 14 - n; + + return (e << 10) | m; +} + +#define MAKE_RGBA8FP16(rgb, r, g, b, a) \ + (shiftcolor16(&(rgb)->red, uint16_div_64k_to_half((r) << 8)) | \ + shiftcolor16(&(rgb)->green, uint16_div_64k_to_half((g) << 8)) | \ + shiftcolor16(&(rgb)->blue, uint16_div_64k_to_half((b) << 8)) | \ + shiftcolor16(&(rgb)->alpha, uint16_div_64k_to_half((a) << 8))) + +#define MAKE_RGBA10FP16(rgb, r, g, b, a) \ + (shiftcolor16(&(rgb)->red, uint16_div_64k_to_half((r) << 6)) | \ + shiftcolor16(&(rgb)->green, uint16_div_64k_to_half((g) << 6)) | \ + shiftcolor16(&(rgb)->blue, uint16_div_64k_to_half((b) << 6)) | \ + shiftcolor16(&(rgb)->alpha, uint16_div_64k_to_half((a) << 6))) + +static void fill_smpte_yuv_planar(const struct util_yuv_info *yuv, + unsigned char *y_mem, unsigned char *u_mem, + unsigned char *v_mem, unsigned int width, + unsigned int height, unsigned int stride) +{ + const struct color_yuv colors_top[] = { + MAKE_YUV_601(191, 192, 192), /* grey */ + MAKE_YUV_601(192, 192, 0), /* yellow */ + MAKE_YUV_601(0, 192, 192), /* cyan */ + MAKE_YUV_601(0, 192, 0), /* green */ + MAKE_YUV_601(192, 0, 192), /* magenta */ + MAKE_YUV_601(192, 0, 0), /* red */ + MAKE_YUV_601(0, 0, 192), /* blue */ + }; + const struct color_yuv colors_middle[] = { + MAKE_YUV_601(0, 0, 192), /* blue */ + MAKE_YUV_601(19, 19, 19), /* black */ + MAKE_YUV_601(192, 0, 192), /* magenta */ + MAKE_YUV_601(19, 19, 19), /* black */ + MAKE_YUV_601(0, 192, 192), /* cyan */ + MAKE_YUV_601(19, 19, 19), /* black */ + MAKE_YUV_601(192, 192, 192), /* grey */ + }; + const struct color_yuv colors_bottom[] = { + MAKE_YUV_601(0, 33, 76), /* in-phase */ + MAKE_YUV_601(255, 255, 255), /* super white */ + MAKE_YUV_601(50, 0, 106), /* quadrature */ + MAKE_YUV_601(19, 19, 19), /* black */ + MAKE_YUV_601(9, 9, 9), /* 3.5% */ + MAKE_YUV_601(19, 19, 19), /* 7.5% */ + MAKE_YUV_601(29, 29, 29), /* 11.5% */ + MAKE_YUV_601(19, 19, 19), /* black */ + }; + unsigned int cs = yuv->chroma_stride; + unsigned int xsub = yuv->xsub; + unsigned int ysub = yuv->ysub; + unsigned int x; + unsigned int y; + + /* Luma */ + for (y = 0; y < height * 6 / 9; ++y) { + for (x = 0; x < width; ++x) + y_mem[x] = colors_top[x * 7 / width].y; + y_mem += stride; + } + + for (; y < height * 7 / 9; ++y) { + for (x = 0; x < width; ++x) + y_mem[x] = colors_middle[x * 7 / width].y; + y_mem += stride; + } + + for (; y < height; ++y) { + for (x = 0; x < width * 5 / 7; ++x) + y_mem[x] = colors_bottom[x * 4 / (width * 5 / 7)].y; + for (; x < width * 6 / 7; ++x) + y_mem[x] = colors_bottom[(x - width * 5 / 7) * 3 + / (width / 7) + 4].y; + for (; x < width; ++x) + y_mem[x] = colors_bottom[7].y; + y_mem += stride; + } + + /* Chroma */ + for (y = 0; y < height / ysub * 6 / 9; ++y) { + for (x = 0; x < width; x += xsub) { + u_mem[x*cs/xsub] = colors_top[x * 7 / width].u; + v_mem[x*cs/xsub] = colors_top[x * 7 / width].v; + } + u_mem += stride * cs / xsub; + v_mem += stride * cs / xsub; + } + + for (; y < height / ysub * 7 / 9; ++y) { + for (x = 0; x < width; x += xsub) { + u_mem[x*cs/xsub] = colors_middle[x * 7 / width].u; + v_mem[x*cs/xsub] = colors_middle[x * 7 / width].v; + } + u_mem += stride * cs / xsub; + v_mem += stride * cs / xsub; + } + + for (; y < height / ysub; ++y) { + for (x = 0; x < width * 5 / 7; x += xsub) { + u_mem[x*cs/xsub] = + colors_bottom[x * 4 / (width * 5 / 7)].u; + v_mem[x*cs/xsub] = + colors_bottom[x * 4 / (width * 5 / 7)].v; + } + for (; x < width * 6 / 7; x += xsub) { + u_mem[x*cs/xsub] = colors_bottom[(x - width * 5 / 7) * + 3 / (width / 7) + 4].u; + v_mem[x*cs/xsub] = colors_bottom[(x - width * 5 / 7) * + 3 / (width / 7) + 4].v; + } + for (; x < width; x += xsub) { + u_mem[x*cs/xsub] = colors_bottom[7].u; + v_mem[x*cs/xsub] = colors_bottom[7].v; + } + u_mem += stride * cs / xsub; + v_mem += stride * cs / xsub; + } +} + +static void fill_smpte_yuv_packed(const struct util_yuv_info *yuv, void *mem, + unsigned int width, unsigned int height, + unsigned int stride) +{ + const struct color_yuv colors_top[] = { + MAKE_YUV_601(191, 192, 192), /* grey */ + MAKE_YUV_601(192, 192, 0), /* yellow */ + MAKE_YUV_601(0, 192, 192), /* cyan */ + MAKE_YUV_601(0, 192, 0), /* green */ + MAKE_YUV_601(192, 0, 192), /* magenta */ + MAKE_YUV_601(192, 0, 0), /* red */ + MAKE_YUV_601(0, 0, 192), /* blue */ + }; + const struct color_yuv colors_middle[] = { + MAKE_YUV_601(0, 0, 192), /* blue */ + MAKE_YUV_601(19, 19, 19), /* black */ + MAKE_YUV_601(192, 0, 192), /* magenta */ + MAKE_YUV_601(19, 19, 19), /* black */ + MAKE_YUV_601(0, 192, 192), /* cyan */ + MAKE_YUV_601(19, 19, 19), /* black */ + MAKE_YUV_601(192, 192, 192), /* grey */ + }; + const struct color_yuv colors_bottom[] = { + MAKE_YUV_601(0, 33, 76), /* in-phase */ + MAKE_YUV_601(255, 255, 255), /* super white */ + MAKE_YUV_601(50, 0, 106), /* quadrature */ + MAKE_YUV_601(19, 19, 19), /* black */ + MAKE_YUV_601(9, 9, 9), /* 3.5% */ + MAKE_YUV_601(19, 19, 19), /* 7.5% */ + MAKE_YUV_601(29, 29, 29), /* 11.5% */ + MAKE_YUV_601(19, 19, 19), /* black */ + }; + unsigned char *y_mem = (yuv->order & YUV_YC) ? mem : mem + 1; + unsigned char *c_mem = (yuv->order & YUV_CY) ? mem : mem + 1; + unsigned int u = (yuv->order & YUV_YCrCb) ? 2 : 0; + unsigned int v = (yuv->order & YUV_YCbCr) ? 2 : 0; + unsigned int x; + unsigned int y; + + /* Luma */ + for (y = 0; y < height * 6 / 9; ++y) { + for (x = 0; x < width; ++x) + y_mem[2*x] = colors_top[x * 7 / width].y; + y_mem += stride; + } + + for (; y < height * 7 / 9; ++y) { + for (x = 0; x < width; ++x) + y_mem[2*x] = colors_middle[x * 7 / width].y; + y_mem += stride; + } + + for (; y < height; ++y) { + for (x = 0; x < width * 5 / 7; ++x) + y_mem[2*x] = colors_bottom[x * 4 / (width * 5 / 7)].y; + for (; x < width * 6 / 7; ++x) + y_mem[2*x] = colors_bottom[(x - width * 5 / 7) * 3 + / (width / 7) + 4].y; + for (; x < width; ++x) + y_mem[2*x] = colors_bottom[7].y; + y_mem += stride; + } + + /* Chroma */ + for (y = 0; y < height * 6 / 9; ++y) { + for (x = 0; x < width; x += 2) { + c_mem[2*x+u] = colors_top[x * 7 / width].u; + c_mem[2*x+v] = colors_top[x * 7 / width].v; + } + c_mem += stride; + } + + for (; y < height * 7 / 9; ++y) { + for (x = 0; x < width; x += 2) { + c_mem[2*x+u] = colors_middle[x * 7 / width].u; + c_mem[2*x+v] = colors_middle[x * 7 / width].v; + } + c_mem += stride; + } + + for (; y < height; ++y) { + for (x = 0; x < width * 5 / 7; x += 2) { + c_mem[2*x+u] = colors_bottom[x * 4 / (width * 5 / 7)].u; + c_mem[2*x+v] = colors_bottom[x * 4 / (width * 5 / 7)].v; + } + for (; x < width * 6 / 7; x += 2) { + c_mem[2*x+u] = colors_bottom[(x - width * 5 / 7) * + 3 / (width / 7) + 4].u; + c_mem[2*x+v] = colors_bottom[(x - width * 5 / 7) * + 3 / (width / 7) + 4].v; + } + for (; x < width; x += 2) { + c_mem[2*x+u] = colors_bottom[7].u; + c_mem[2*x+v] = colors_bottom[7].v; + } + c_mem += stride; + } +} + +static void fill_smpte_rgb16(const struct util_rgb_info *rgb, void *mem, + unsigned int width, unsigned int height, + unsigned int stride) +{ + const uint16_t colors_top[] = { + MAKE_RGBA(rgb, 192, 192, 192, 255), /* grey */ + MAKE_RGBA(rgb, 192, 192, 0, 255), /* yellow */ + MAKE_RGBA(rgb, 0, 192, 192, 255), /* cyan */ + MAKE_RGBA(rgb, 0, 192, 0, 255), /* green */ + MAKE_RGBA(rgb, 192, 0, 192, 255), /* magenta */ + MAKE_RGBA(rgb, 192, 0, 0, 255), /* red */ + MAKE_RGBA(rgb, 0, 0, 192, 255), /* blue */ + }; + const uint16_t colors_middle[] = { + MAKE_RGBA(rgb, 0, 0, 192, 127), /* blue */ + MAKE_RGBA(rgb, 19, 19, 19, 127), /* black */ + MAKE_RGBA(rgb, 192, 0, 192, 127), /* magenta */ + MAKE_RGBA(rgb, 19, 19, 19, 127), /* black */ + MAKE_RGBA(rgb, 0, 192, 192, 127), /* cyan */ + MAKE_RGBA(rgb, 19, 19, 19, 127), /* black */ + MAKE_RGBA(rgb, 192, 192, 192, 127), /* grey */ + }; + const uint16_t colors_bottom[] = { + MAKE_RGBA(rgb, 0, 33, 76, 255), /* in-phase */ + MAKE_RGBA(rgb, 255, 255, 255, 255), /* super white */ + MAKE_RGBA(rgb, 50, 0, 106, 255), /* quadrature */ + MAKE_RGBA(rgb, 19, 19, 19, 255), /* black */ + MAKE_RGBA(rgb, 9, 9, 9, 255), /* 3.5% */ + MAKE_RGBA(rgb, 19, 19, 19, 255), /* 7.5% */ + MAKE_RGBA(rgb, 29, 29, 29, 255), /* 11.5% */ + MAKE_RGBA(rgb, 19, 19, 19, 255), /* black */ + }; + unsigned int x; + unsigned int y; + + for (y = 0; y < height * 6 / 9; ++y) { + for (x = 0; x < width; ++x) + ((uint16_t *)mem)[x] = colors_top[x * 7 / width]; + mem += stride; + } + + for (; y < height * 7 / 9; ++y) { + for (x = 0; x < width; ++x) + ((uint16_t *)mem)[x] = colors_middle[x * 7 / width]; + mem += stride; + } + + for (; y < height; ++y) { + for (x = 0; x < width * 5 / 7; ++x) + ((uint16_t *)mem)[x] = + colors_bottom[x * 4 / (width * 5 / 7)]; + for (; x < width * 6 / 7; ++x) + ((uint16_t *)mem)[x] = + colors_bottom[(x - width * 5 / 7) * 3 + / (width / 7) + 4]; + for (; x < width; ++x) + ((uint16_t *)mem)[x] = colors_bottom[7]; + mem += stride; + } +} + +static void fill_smpte_rgb24(const struct util_rgb_info *rgb, void *mem, + unsigned int width, unsigned int height, + unsigned int stride) +{ + const struct color_rgb24 colors_top[] = { + MAKE_RGB24(rgb, 192, 192, 192), /* grey */ + MAKE_RGB24(rgb, 192, 192, 0), /* yellow */ + MAKE_RGB24(rgb, 0, 192, 192), /* cyan */ + MAKE_RGB24(rgb, 0, 192, 0), /* green */ + MAKE_RGB24(rgb, 192, 0, 192), /* magenta */ + MAKE_RGB24(rgb, 192, 0, 0), /* red */ + MAKE_RGB24(rgb, 0, 0, 192), /* blue */ + }; + const struct color_rgb24 colors_middle[] = { + MAKE_RGB24(rgb, 0, 0, 192), /* blue */ + MAKE_RGB24(rgb, 19, 19, 19), /* black */ + MAKE_RGB24(rgb, 192, 0, 192), /* magenta */ + MAKE_RGB24(rgb, 19, 19, 19), /* black */ + MAKE_RGB24(rgb, 0, 192, 192), /* cyan */ + MAKE_RGB24(rgb, 19, 19, 19), /* black */ + MAKE_RGB24(rgb, 192, 192, 192), /* grey */ + }; + const struct color_rgb24 colors_bottom[] = { + MAKE_RGB24(rgb, 0, 33, 76), /* in-phase */ + MAKE_RGB24(rgb, 255, 255, 255), /* super white */ + MAKE_RGB24(rgb, 50, 0, 106), /* quadrature */ + MAKE_RGB24(rgb, 19, 19, 19), /* black */ + MAKE_RGB24(rgb, 9, 9, 9), /* 3.5% */ + MAKE_RGB24(rgb, 19, 19, 19), /* 7.5% */ + MAKE_RGB24(rgb, 29, 29, 29), /* 11.5% */ + MAKE_RGB24(rgb, 19, 19, 19), /* black */ + }; + unsigned int x; + unsigned int y; + + for (y = 0; y < height * 6 / 9; ++y) { + for (x = 0; x < width; ++x) + ((struct color_rgb24 *)mem)[x] = + colors_top[x * 7 / width]; + mem += stride; + } + + for (; y < height * 7 / 9; ++y) { + for (x = 0; x < width; ++x) + ((struct color_rgb24 *)mem)[x] = + colors_middle[x * 7 / width]; + mem += stride; + } + + for (; y < height; ++y) { + for (x = 0; x < width * 5 / 7; ++x) + ((struct color_rgb24 *)mem)[x] = + colors_bottom[x * 4 / (width * 5 / 7)]; + for (; x < width * 6 / 7; ++x) + ((struct color_rgb24 *)mem)[x] = + colors_bottom[(x - width * 5 / 7) * 3 + / (width / 7) + 4]; + for (; x < width; ++x) + ((struct color_rgb24 *)mem)[x] = colors_bottom[7]; + mem += stride; + } +} + +static void fill_smpte_rgb32(const struct util_rgb_info *rgb, void *mem, + unsigned int width, unsigned int height, + unsigned int stride) +{ + const uint32_t colors_top[] = { + MAKE_RGBA(rgb, 192, 192, 192, 255), /* grey */ + MAKE_RGBA(rgb, 192, 192, 0, 255), /* yellow */ + MAKE_RGBA(rgb, 0, 192, 192, 255), /* cyan */ + MAKE_RGBA(rgb, 0, 192, 0, 255), /* green */ + MAKE_RGBA(rgb, 192, 0, 192, 255), /* magenta */ + MAKE_RGBA(rgb, 192, 0, 0, 255), /* red */ + MAKE_RGBA(rgb, 0, 0, 192, 255), /* blue */ + }; + const uint32_t colors_middle[] = { + MAKE_RGBA(rgb, 0, 0, 192, 127), /* blue */ + MAKE_RGBA(rgb, 19, 19, 19, 127), /* black */ + MAKE_RGBA(rgb, 192, 0, 192, 127), /* magenta */ + MAKE_RGBA(rgb, 19, 19, 19, 127), /* black */ + MAKE_RGBA(rgb, 0, 192, 192, 127), /* cyan */ + MAKE_RGBA(rgb, 19, 19, 19, 127), /* black */ + MAKE_RGBA(rgb, 192, 192, 192, 127), /* grey */ + }; + const uint32_t colors_bottom[] = { + MAKE_RGBA(rgb, 0, 33, 76, 255), /* in-phase */ + MAKE_RGBA(rgb, 255, 255, 255, 255), /* super white */ + MAKE_RGBA(rgb, 50, 0, 106, 255), /* quadrature */ + MAKE_RGBA(rgb, 19, 19, 19, 255), /* black */ + MAKE_RGBA(rgb, 9, 9, 9, 255), /* 3.5% */ + MAKE_RGBA(rgb, 19, 19, 19, 255), /* 7.5% */ + MAKE_RGBA(rgb, 29, 29, 29, 255), /* 11.5% */ + MAKE_RGBA(rgb, 19, 19, 19, 255), /* black */ + }; + unsigned int x; + unsigned int y; + + for (y = 0; y < height * 6 / 9; ++y) { + for (x = 0; x < width; ++x) + ((uint32_t *)mem)[x] = colors_top[x * 7 / width]; + mem += stride; + } + + for (; y < height * 7 / 9; ++y) { + for (x = 0; x < width; ++x) + ((uint32_t *)mem)[x] = colors_middle[x * 7 / width]; + mem += stride; + } + + for (; y < height; ++y) { + for (x = 0; x < width * 5 / 7; ++x) + ((uint32_t *)mem)[x] = + colors_bottom[x * 4 / (width * 5 / 7)]; + for (; x < width * 6 / 7; ++x) + ((uint32_t *)mem)[x] = + colors_bottom[(x - width * 5 / 7) * 3 + / (width / 7) + 4]; + for (; x < width; ++x) + ((uint32_t *)mem)[x] = colors_bottom[7]; + mem += stride; + } +} + +static void fill_smpte_rgb16fp(const struct util_rgb_info *rgb, void *mem, + unsigned int width, unsigned int height, + unsigned int stride) +{ + const uint64_t colors_top[] = { + MAKE_RGBA8FP16(rgb, 192, 192, 192, 255),/* grey */ + MAKE_RGBA8FP16(rgb, 192, 192, 0, 255), /* yellow */ + MAKE_RGBA8FP16(rgb, 0, 192, 192, 255), /* cyan */ + MAKE_RGBA8FP16(rgb, 0, 192, 0, 255), /* green */ + MAKE_RGBA8FP16(rgb, 192, 0, 192, 255), /* magenta */ + MAKE_RGBA8FP16(rgb, 192, 0, 0, 255), /* red */ + MAKE_RGBA8FP16(rgb, 0, 0, 192, 255), /* blue */ + }; + const uint64_t colors_middle[] = { + MAKE_RGBA8FP16(rgb, 0, 0, 192, 127), /* blue */ + MAKE_RGBA8FP16(rgb, 19, 19, 19, 127), /* black */ + MAKE_RGBA8FP16(rgb, 192, 0, 192, 127), /* magenta */ + MAKE_RGBA8FP16(rgb, 19, 19, 19, 127), /* black */ + MAKE_RGBA8FP16(rgb, 0, 192, 192, 127), /* cyan */ + MAKE_RGBA8FP16(rgb, 19, 19, 19, 127), /* black */ + MAKE_RGBA8FP16(rgb, 192, 192, 192, 127),/* grey */ + }; + const uint64_t colors_bottom[] = { + MAKE_RGBA8FP16(rgb, 0, 33, 76, 255), /* in-phase */ + MAKE_RGBA8FP16(rgb, 255, 255, 255, 255),/* super white */ + MAKE_RGBA8FP16(rgb, 50, 0, 106, 255), /* quadrature */ + MAKE_RGBA8FP16(rgb, 19, 19, 19, 255), /* black */ + MAKE_RGBA8FP16(rgb, 9, 9, 9, 255), /* 3.5% */ + MAKE_RGBA8FP16(rgb, 19, 19, 19, 255), /* 7.5% */ + MAKE_RGBA8FP16(rgb, 29, 29, 29, 255), /* 11.5% */ + MAKE_RGBA8FP16(rgb, 19, 19, 19, 255), /* black */ + }; + unsigned int x; + unsigned int y; + + for (y = 0; y < height * 6 / 9; ++y) { + for (x = 0; x < width; ++x) + ((uint64_t *)mem)[x] = colors_top[x * 7 / width]; + mem += stride; + } + + for (; y < height * 7 / 9; ++y) { + for (x = 0; x < width; ++x) + ((uint64_t *)mem)[x] = colors_middle[x * 7 / width]; + mem += stride; + } + + for (; y < height; ++y) { + for (x = 0; x < width * 5 / 7; ++x) + ((uint64_t *)mem)[x] = + colors_bottom[x * 4 / (width * 5 / 7)]; + for (; x < width * 6 / 7; ++x) + ((uint64_t *)mem)[x] = + colors_bottom[(x - width * 5 / 7) * 3 + / (width / 7) + 4]; + for (; x < width; ++x) + ((uint64_t *)mem)[x] = colors_bottom[7]; + mem += stride; + } +} + +static void fill_smpte_c8(void *mem, unsigned int width, unsigned int height, + unsigned int stride) +{ + unsigned int x; + unsigned int y; + + for (y = 0; y < height * 6 / 9; ++y) { + for (x = 0; x < width; ++x) + ((uint8_t *)mem)[x] = x * 7 / width; + mem += stride; + } + + for (; y < height * 7 / 9; ++y) { + for (x = 0; x < width; ++x) + ((uint8_t *)mem)[x] = 7 + (x * 7 / width); + mem += stride; + } + + for (; y < height; ++y) { + for (x = 0; x < width * 5 / 7; ++x) + ((uint8_t *)mem)[x] = + 14 + (x * 4 / (width * 5 / 7)); + for (; x < width * 6 / 7; ++x) + ((uint8_t *)mem)[x] = + 14 + ((x - width * 5 / 7) * 3 + / (width / 7) + 4); + for (; x < width; ++x) + ((uint8_t *)mem)[x] = 14 + 7; + mem += stride; + } +} + +void util_smpte_c8_gamma(unsigned size, struct drm_color_lut *lut) +{ + if (size < 7 + 7 + 8) { + printf("Error: gamma too small: %d < %d\n", size, 7 + 7 + 8); + return; + } + memset(lut, 0, size * sizeof(struct drm_color_lut)); + +#define FILL_COLOR(idx, r, g, b) \ + lut[idx].red = (r) << 8; \ + lut[idx].green = (g) << 8; \ + lut[idx].blue = (b) << 8 + + FILL_COLOR( 0, 192, 192, 192); /* grey */ + FILL_COLOR( 1, 192, 192, 0 ); /* yellow */ + FILL_COLOR( 2, 0, 192, 192); /* cyan */ + FILL_COLOR( 3, 0, 192, 0 ); /* green */ + FILL_COLOR( 4, 192, 0, 192); /* magenta */ + FILL_COLOR( 5, 192, 0, 0 ); /* red */ + FILL_COLOR( 6, 0, 0, 192); /* blue */ + + FILL_COLOR( 7, 0, 0, 192); /* blue */ + FILL_COLOR( 8, 19, 19, 19 ); /* black */ + FILL_COLOR( 9, 192, 0, 192); /* magenta */ + FILL_COLOR(10, 19, 19, 19 ); /* black */ + FILL_COLOR(11, 0, 192, 192); /* cyan */ + FILL_COLOR(12, 19, 19, 19 ); /* black */ + FILL_COLOR(13, 192, 192, 192); /* grey */ + + FILL_COLOR(14, 0, 33, 76); /* in-phase */ + FILL_COLOR(15, 255, 255, 255); /* super white */ + FILL_COLOR(16, 50, 0, 106); /* quadrature */ + FILL_COLOR(17, 19, 19, 19); /* black */ + FILL_COLOR(18, 9, 9, 9); /* 3.5% */ + FILL_COLOR(19, 19, 19, 19); /* 7.5% */ + FILL_COLOR(20, 29, 29, 29); /* 11.5% */ + FILL_COLOR(21, 19, 19, 19); /* black */ + +#undef FILL_COLOR +} + +static void fill_smpte(const struct util_format_info *info, void *planes[3], + unsigned int width, unsigned int height, + unsigned int stride) +{ + unsigned char *u, *v; + + switch (info->format) { + case DRM_FORMAT_C8: + return fill_smpte_c8(planes[0], width, height, stride); + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + return fill_smpte_yuv_packed(&info->yuv, planes[0], width, + height, stride); + + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + u = info->yuv.order & YUV_YCbCr ? planes[1] : planes[1] + 1; + v = info->yuv.order & YUV_YCrCb ? planes[1] : planes[1] + 1; + return fill_smpte_yuv_planar(&info->yuv, planes[0], u, v, + width, height, stride); + + case DRM_FORMAT_YUV420: + return fill_smpte_yuv_planar(&info->yuv, planes[0], planes[1], + planes[2], width, height, stride); + + case DRM_FORMAT_YVU420: + return fill_smpte_yuv_planar(&info->yuv, planes[0], planes[2], + planes[1], width, height, stride); + + case DRM_FORMAT_ARGB4444: + case DRM_FORMAT_XRGB4444: + case DRM_FORMAT_ABGR4444: + case DRM_FORMAT_XBGR4444: + case DRM_FORMAT_RGBA4444: + case DRM_FORMAT_RGBX4444: + case DRM_FORMAT_BGRA4444: + case DRM_FORMAT_BGRX4444: + case DRM_FORMAT_RGB565: + case DRM_FORMAT_BGR565: + case DRM_FORMAT_ARGB1555: + case DRM_FORMAT_XRGB1555: + case DRM_FORMAT_ABGR1555: + case DRM_FORMAT_XBGR1555: + case DRM_FORMAT_RGBA5551: + case DRM_FORMAT_RGBX5551: + case DRM_FORMAT_BGRA5551: + case DRM_FORMAT_BGRX5551: + return fill_smpte_rgb16(&info->rgb, planes[0], + width, height, stride); + + case DRM_FORMAT_BGR888: + case DRM_FORMAT_RGB888: + return fill_smpte_rgb24(&info->rgb, planes[0], + width, height, stride); + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_RGBA8888: + case DRM_FORMAT_RGBX8888: + case DRM_FORMAT_BGRA8888: + case DRM_FORMAT_BGRX8888: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_RGBA1010102: + case DRM_FORMAT_RGBX1010102: + case DRM_FORMAT_BGRA1010102: + case DRM_FORMAT_BGRX1010102: + return fill_smpte_rgb32(&info->rgb, planes[0], + width, height, stride); + + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ARGB16161616F: + case DRM_FORMAT_ABGR16161616F: + return fill_smpte_rgb16fp(&info->rgb, planes[0], + width, height, stride); + } +} + +/* swap these for big endian.. */ +#define RED 2 +#define GREEN 1 +#define BLUE 0 + +static void make_pwetty(void *data, unsigned int width, unsigned int height, + unsigned int stride, uint32_t format) +{ +#if HAVE_CAIRO + cairo_surface_t *surface; + cairo_t *cr; + cairo_format_t cairo_format; + + /* we can ignore the order of R,G,B channels */ + switch (format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + cairo_format = CAIRO_FORMAT_ARGB32; + break; + case DRM_FORMAT_RGB565: + case DRM_FORMAT_BGR565: + cairo_format = CAIRO_FORMAT_RGB16_565; + break; +#if CAIRO_VERSION_MAJOR > 1 || (CAIRO_VERSION_MAJOR == 1 && CAIRO_VERSION_MINOR >= 12) + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_XBGR2101010: + cairo_format = CAIRO_FORMAT_RGB30; + break; +#endif + default: + return; + } + + surface = cairo_image_surface_create_for_data(data, + cairo_format, + width, height, + stride); + cr = cairo_create(surface); + cairo_surface_destroy(surface); + + cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE); + for (unsigned x = 0; x < width; x += 250) + for (unsigned y = 0; y < height; y += 250) { + char buf[64]; + + cairo_move_to(cr, x, y - 20); + cairo_line_to(cr, x, y + 20); + cairo_move_to(cr, x - 20, y); + cairo_line_to(cr, x + 20, y); + cairo_new_sub_path(cr); + cairo_arc(cr, x, y, 10, 0, M_PI * 2); + cairo_set_line_width(cr, 4); + cairo_set_source_rgb(cr, 0, 0, 0); + cairo_stroke_preserve(cr); + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_set_line_width(cr, 2); + cairo_stroke(cr); + + snprintf(buf, sizeof buf, "%d, %d", x, y); + cairo_move_to(cr, x + 20, y + 20); + cairo_text_path(cr, buf); + cairo_set_source_rgb(cr, 0, 0, 0); + cairo_stroke_preserve(cr); + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_fill(cr); + } + + cairo_destroy(cr); +#endif +} + +static void fill_tiles_yuv_planar(const struct util_format_info *info, + unsigned char *y_mem, unsigned char *u_mem, + unsigned char *v_mem, unsigned int width, + unsigned int height, unsigned int stride) +{ + const struct util_yuv_info *yuv = &info->yuv; + unsigned int cs = yuv->chroma_stride; + unsigned int xsub = yuv->xsub; + unsigned int ysub = yuv->ysub; + unsigned int x; + unsigned int y; + + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + div_t d = div(x+y, width); + uint32_t rgb32 = 0x00130502 * (d.quot >> 6) + + 0x000a1120 * (d.rem >> 6); + struct color_yuv color = + MAKE_YUV_601((rgb32 >> 16) & 0xff, + (rgb32 >> 8) & 0xff, rgb32 & 0xff); + + y_mem[x] = color.y; + u_mem[x/xsub*cs] = color.u; + v_mem[x/xsub*cs] = color.v; + } + + y_mem += stride; + if ((y + 1) % ysub == 0) { + u_mem += stride * cs / xsub; + v_mem += stride * cs / xsub; + } + } +} + +static void fill_tiles_yuv_packed(const struct util_format_info *info, + void *mem, unsigned int width, + unsigned int height, unsigned int stride) +{ + const struct util_yuv_info *yuv = &info->yuv; + unsigned char *y_mem = (yuv->order & YUV_YC) ? mem : mem + 1; + unsigned char *c_mem = (yuv->order & YUV_CY) ? mem : mem + 1; + unsigned int u = (yuv->order & YUV_YCrCb) ? 2 : 0; + unsigned int v = (yuv->order & YUV_YCbCr) ? 2 : 0; + unsigned int x; + unsigned int y; + + for (y = 0; y < height; ++y) { + for (x = 0; x < width; x += 2) { + div_t d = div(x+y, width); + uint32_t rgb32 = 0x00130502 * (d.quot >> 6) + + 0x000a1120 * (d.rem >> 6); + struct color_yuv color = + MAKE_YUV_601((rgb32 >> 16) & 0xff, + (rgb32 >> 8) & 0xff, rgb32 & 0xff); + + y_mem[2*x] = color.y; + c_mem[2*x+u] = color.u; + y_mem[2*x+2] = color.y; + c_mem[2*x+v] = color.v; + } + + y_mem += stride; + c_mem += stride; + } +} + +static void fill_tiles_rgb16(const struct util_format_info *info, void *mem, + unsigned int width, unsigned int height, + unsigned int stride) +{ + const struct util_rgb_info *rgb = &info->rgb; + void *mem_base = mem; + unsigned int x, y; + + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + div_t d = div(x+y, width); + uint32_t rgb32 = 0x00130502 * (d.quot >> 6) + + 0x000a1120 * (d.rem >> 6); + uint16_t color = + MAKE_RGBA(rgb, (rgb32 >> 16) & 0xff, + (rgb32 >> 8) & 0xff, rgb32 & 0xff, + 255); + + ((uint16_t *)mem)[x] = color; + } + mem += stride; + } + + make_pwetty(mem_base, width, height, stride, info->format); +} + +static void fill_tiles_rgb24(const struct util_format_info *info, void *mem, + unsigned int width, unsigned int height, + unsigned int stride) +{ + const struct util_rgb_info *rgb = &info->rgb; + unsigned int x, y; + + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + div_t d = div(x+y, width); + uint32_t rgb32 = 0x00130502 * (d.quot >> 6) + + 0x000a1120 * (d.rem >> 6); + struct color_rgb24 color = + MAKE_RGB24(rgb, (rgb32 >> 16) & 0xff, + (rgb32 >> 8) & 0xff, rgb32 & 0xff); + + ((struct color_rgb24 *)mem)[x] = color; + } + mem += stride; + } +} + +static void fill_tiles_rgb32(const struct util_format_info *info, void *mem, + unsigned int width, unsigned int height, + unsigned int stride) +{ + const struct util_rgb_info *rgb = &info->rgb; + void *mem_base = mem; + unsigned int x, y; + + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + div_t d = div(x+y, width); + uint32_t rgb32 = 0x00130502 * (d.quot >> 6) + + 0x000a1120 * (d.rem >> 6); + uint32_t alpha = ((y < height/2) && (x < width/2)) ? 127 : 255; + uint32_t color = + MAKE_RGBA(rgb, (rgb32 >> 16) & 0xff, + (rgb32 >> 8) & 0xff, rgb32 & 0xff, + alpha); + + ((uint32_t *)mem)[x] = color; + } + mem += stride; + } + + make_pwetty(mem_base, width, height, stride, info->format); +} + +static void fill_tiles_rgb16fp(const struct util_format_info *info, void *mem, + unsigned int width, unsigned int height, + unsigned int stride) +{ + const struct util_rgb_info *rgb = &info->rgb; + unsigned int x, y; + + /* TODO: Give this actual fp16 precision */ + for (y = 0; y < height; ++y) { + for (x = 0; x < width; ++x) { + div_t d = div(x+y, width); + uint32_t rgb32 = 0x00130502 * (d.quot >> 6) + + 0x000a1120 * (d.rem >> 6); + uint32_t alpha = ((y < height/2) && (x < width/2)) ? 127 : 255; + uint64_t color = + MAKE_RGBA8FP16(rgb, (rgb32 >> 16) & 0xff, + (rgb32 >> 8) & 0xff, rgb32 & 0xff, + alpha); + + ((uint64_t *)mem)[x] = color; + } + mem += stride; + } +} + +static void fill_tiles(const struct util_format_info *info, void *planes[3], + unsigned int width, unsigned int height, + unsigned int stride) +{ + unsigned char *u, *v; + + switch (info->format) { + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + return fill_tiles_yuv_packed(info, planes[0], + width, height, stride); + + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV61: + u = info->yuv.order & YUV_YCbCr ? planes[1] : planes[1] + 1; + v = info->yuv.order & YUV_YCrCb ? planes[1] : planes[1] + 1; + return fill_tiles_yuv_planar(info, planes[0], u, v, + width, height, stride); + + case DRM_FORMAT_YUV420: + return fill_tiles_yuv_planar(info, planes[0], planes[1], + planes[2], width, height, stride); + + case DRM_FORMAT_YVU420: + return fill_tiles_yuv_planar(info, planes[0], planes[2], + planes[1], width, height, stride); + + case DRM_FORMAT_ARGB4444: + case DRM_FORMAT_XRGB4444: + case DRM_FORMAT_ABGR4444: + case DRM_FORMAT_XBGR4444: + case DRM_FORMAT_RGBA4444: + case DRM_FORMAT_RGBX4444: + case DRM_FORMAT_BGRA4444: + case DRM_FORMAT_BGRX4444: + case DRM_FORMAT_RGB565: + case DRM_FORMAT_BGR565: + case DRM_FORMAT_ARGB1555: + case DRM_FORMAT_XRGB1555: + case DRM_FORMAT_ABGR1555: + case DRM_FORMAT_XBGR1555: + case DRM_FORMAT_RGBA5551: + case DRM_FORMAT_RGBX5551: + case DRM_FORMAT_BGRA5551: + case DRM_FORMAT_BGRX5551: + return fill_tiles_rgb16(info, planes[0], + width, height, stride); + + case DRM_FORMAT_BGR888: + case DRM_FORMAT_RGB888: + return fill_tiles_rgb24(info, planes[0], + width, height, stride); + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_RGBA8888: + case DRM_FORMAT_RGBX8888: + case DRM_FORMAT_BGRA8888: + case DRM_FORMAT_BGRX8888: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_RGBA1010102: + case DRM_FORMAT_RGBX1010102: + case DRM_FORMAT_BGRA1010102: + case DRM_FORMAT_BGRX1010102: + return fill_tiles_rgb32(info, planes[0], + width, height, stride); + + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ARGB16161616F: + case DRM_FORMAT_ABGR16161616F: + return fill_tiles_rgb16fp(info, planes[0], + width, height, stride); + } +} + +static void fill_plain(const struct util_format_info *info, void *planes[3], + unsigned int height, + unsigned int stride) +{ + switch (info->format) { + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ARGB16161616F: + case DRM_FORMAT_ABGR16161616F: + /* 0x3838 = 0.5273 */ + memset(planes[0], 0x38, stride * height); + break; + default: + memset(planes[0], 0x77, stride * height); + break; + } +} + +static void fill_gradient_rgb32(const struct util_rgb_info *rgb, + void *mem, + unsigned int width, unsigned int height, + unsigned int stride) +{ + unsigned int i, j; + + for (i = 0; i < height / 2; i++) { + uint32_t *row = mem; + + for (j = 0; j < width / 2; j++) { + uint32_t value = MAKE_RGBA10(rgb, j & 0x3ff, j & 0x3ff, j & 0x3ff, 0); + row[2*j] = row[2*j+1] = value; + } + mem += stride; + } + + for (; i < height; i++) { + uint32_t *row = mem; + + for (j = 0; j < width / 2; j++) { + uint32_t value = MAKE_RGBA10(rgb, j & 0x3fc, j & 0x3fc, j & 0x3fc, 0); + row[2*j] = row[2*j+1] = value; + } + mem += stride; + } +} + +static void fill_gradient_rgb16fp(const struct util_rgb_info *rgb, + void *mem, + unsigned int width, unsigned int height, + unsigned int stride) +{ + unsigned int i, j; + + for (i = 0; i < height / 2; i++) { + uint64_t *row = mem; + + for (j = 0; j < width / 2; j++) { + uint64_t value = MAKE_RGBA10FP16(rgb, j & 0x3ff, j & 0x3ff, j & 0x3ff, 0); + row[2*j] = row[2*j+1] = value; + } + mem += stride; + } + + for (; i < height; i++) { + uint64_t *row = mem; + + for (j = 0; j < width / 2; j++) { + uint64_t value = MAKE_RGBA10FP16(rgb, j & 0x3fc, j & 0x3fc, j & 0x3fc, 0); + row[2*j] = row[2*j+1] = value; + } + mem += stride; + } +} + +/* The gradient pattern creates two horizontal gray gradients, split + * into two halves. The top half has 10bpc precision, the bottom half + * has 8bpc precision. When using with a 10bpc fb format, there are 3 + * possible outcomes: + * + * - Pixel data is encoded as 8bpc to the display, no dithering. This + * would lead to the top and bottom halves looking identical. + * + * - Pixel data is encoded as 8bpc to the display, with dithering. This + * would lead to there being a visible difference between the two halves, + * but the top half would look a little speck-y due to the dithering. + * + * - Pixel data is encoded at 10bpc+ to the display (which implies + * the display is able to show this level of depth). This should + * lead to the top half being a very clean gradient, and visibly different + * from the bottom half. + * + * Once we support additional fb formats, this approach could be extended + * to distinguish even higher bpc precisions. + * + * Note that due to practical size considerations, for the screens + * where this matters, the pattern actually emits stripes 2-pixels + * wide for each gradient color. Otherwise the difference may be a bit + * hard to notice. + */ +static void fill_gradient(const struct util_format_info *info, void *planes[3], + unsigned int width, unsigned int height, + unsigned int stride) +{ + switch (info->format) { + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_RGBA8888: + case DRM_FORMAT_RGBX8888: + case DRM_FORMAT_BGRA8888: + case DRM_FORMAT_BGRX8888: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_RGBA1010102: + case DRM_FORMAT_RGBX1010102: + case DRM_FORMAT_BGRA1010102: + case DRM_FORMAT_BGRX1010102: + return fill_gradient_rgb32(&info->rgb, planes[0], + width, height, stride); + + case DRM_FORMAT_XRGB16161616F: + case DRM_FORMAT_XBGR16161616F: + case DRM_FORMAT_ARGB16161616F: + case DRM_FORMAT_ABGR16161616F: + return fill_gradient_rgb16fp(&info->rgb, planes[0], + width, height, stride); + } +} + +/* + * util_fill_pattern - Fill a buffer with a test pattern + * @format: Pixel format + * @pattern: Test pattern + * @planes: Array of buffers + * @width: Width in pixels + * @height: Height in pixels + * @stride: Line stride (pitch) in bytes + * + * Fill the buffers with the test pattern specified by the pattern parameter. + * Supported formats vary depending on the selected pattern. + */ +void util_fill_pattern(uint32_t format, enum util_fill_pattern pattern, + void *planes[3], unsigned int width, + unsigned int height, unsigned int stride) +{ + const struct util_format_info *info; + + info = util_format_info_find(format); + if (info == NULL) + return; + + switch (pattern) { + case UTIL_PATTERN_TILES: + return fill_tiles(info, planes, width, height, stride); + + case UTIL_PATTERN_SMPTE: + return fill_smpte(info, planes, width, height, stride); + + case UTIL_PATTERN_PLAIN: + return fill_plain(info, planes, height, stride); + + case UTIL_PATTERN_GRADIENT: + return fill_gradient(info, planes, width, height, stride); + + default: + printf("Error: unsupported test pattern %u.\n", pattern); + break; + } +} + +static const char *pattern_names[] = { + [UTIL_PATTERN_TILES] = "tiles", + [UTIL_PATTERN_SMPTE] = "smpte", + [UTIL_PATTERN_PLAIN] = "plain", + [UTIL_PATTERN_GRADIENT] = "gradient", +}; + +enum util_fill_pattern util_pattern_enum(const char *name) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(pattern_names); i++) + if (!strcmp(pattern_names[i], name)) + return (enum util_fill_pattern)i; + + printf("Error: unsupported test pattern %s.\n", name); + return UTIL_PATTERN_SMPTE; +} diff --git a/tests/util/pattern.h b/tests/util/pattern.h new file mode 100644 index 0000000..ea38caf --- /dev/null +++ b/tests/util/pattern.h @@ -0,0 +1,46 @@ +/* + * Copyright 2008 Tungsten Graphics + * Jakob Bornecrantz + * Copyright 2008 Intel Corporation + * Jesse Barnes + * + * 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. + */ + +#ifndef UTIL_PATTERN_H +#define UTIL_PATTERN_H + +#include + +enum util_fill_pattern { + UTIL_PATTERN_TILES, + UTIL_PATTERN_PLAIN, + UTIL_PATTERN_SMPTE, + UTIL_PATTERN_GRADIENT, +}; + +void util_fill_pattern(uint32_t format, enum util_fill_pattern pattern, + void *planes[3], unsigned int width, + unsigned int height, unsigned int stride); + +void util_smpte_c8_gamma(unsigned size, struct drm_color_lut *lut); + +enum util_fill_pattern util_pattern_enum(const char *name); + +#endif /* UTIL_PATTERN_H */ diff --git a/tests/vbltest/meson.build b/tests/vbltest/meson.build new file mode 100644 index 0000000..6339feb --- /dev/null +++ b/tests/vbltest/meson.build @@ -0,0 +1,28 @@ +# Copyright © 2017-2018 Intel Corporation + +# 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. + +vbltest = executable( + 'vbltest', + files('vbltest.c'), + c_args : libdrm_c_args, + include_directories : [inc_root, inc_tests, inc_drm], + link_with : [libdrm, libutil], + install : with_install_tests, +) diff --git a/tests/vbltest/vbltest.c b/tests/vbltest/vbltest.c new file mode 100644 index 0000000..1c2b519 --- /dev/null +++ b/tests/vbltest/vbltest.c @@ -0,0 +1,186 @@ +/* + * DRM based vblank test program + * Copyright 2008 Tungsten Graphics + * Jakob Bornecrantz + * Copyright 2008 Intel Corporation + * Jesse Barnes + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if HAVE_SYS_SELECT_H +#include +#endif + +#include "xf86drm.h" +#include "xf86drmMode.h" + +#include "util/common.h" +#include "util/kms.h" + +extern char *optarg; +extern int optind, opterr, optopt; +static char optstr[] = "D:M:s"; + +int secondary = 0; + +struct vbl_info { + unsigned int vbl_count; + struct timeval start; +}; + +static void vblank_handler(int fd, unsigned int frame, unsigned int sec, + unsigned int usec, void *data) +{ + drmVBlank vbl; + struct timeval end; + struct vbl_info *info = data; + double t; + + vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT; + if (secondary) + vbl.request.type |= DRM_VBLANK_SECONDARY; + vbl.request.sequence = 1; + vbl.request.signal = (unsigned long)data; + + drmWaitVBlank(fd, &vbl); + + info->vbl_count++; + + if (info->vbl_count == 60) { + gettimeofday(&end, NULL); + t = end.tv_sec + end.tv_usec * 1e-6 - + (info->start.tv_sec + info->start.tv_usec * 1e-6); + fprintf(stderr, "freq: %.02fHz\n", info->vbl_count / t); + info->vbl_count = 0; + info->start = end; + } +} + +static void usage(char *name) +{ + fprintf(stderr, "usage: %s [-DMs]\n", name); + fprintf(stderr, "\n"); + fprintf(stderr, "options:\n"); + fprintf(stderr, " -D DEVICE open the given device\n"); + fprintf(stderr, " -M MODULE open the given module\n"); + fprintf(stderr, " -s use secondary pipe\n"); + exit(0); +} + +int main(int argc, char **argv) +{ + const char *device = NULL, *module = NULL; + int c, fd, ret; + drmVBlank vbl; + drmEventContext evctx; + struct vbl_info handler_info; + + opterr = 0; + while ((c = getopt(argc, argv, optstr)) != -1) { + switch (c) { + case 'D': + device = optarg; + break; + case 'M': + module = optarg; + break; + case 's': + secondary = 1; + break; + default: + usage(argv[0]); + break; + } + } + + fd = util_open(device, module); + if (fd < 0) + return 1; + + /* Get current count first */ + vbl.request.type = DRM_VBLANK_RELATIVE; + if (secondary) + vbl.request.type |= DRM_VBLANK_SECONDARY; + vbl.request.sequence = 0; + ret = drmWaitVBlank(fd, &vbl); + if (ret != 0) { + printf("drmWaitVBlank (relative) failed ret: %i\n", ret); + return -1; + } + + printf("starting count: %d\n", vbl.request.sequence); + + handler_info.vbl_count = 0; + gettimeofday(&handler_info.start, NULL); + + /* Queue an event for frame + 1 */ + vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT; + if (secondary) + vbl.request.type |= DRM_VBLANK_SECONDARY; + vbl.request.sequence = 1; + vbl.request.signal = (unsigned long)&handler_info; + ret = drmWaitVBlank(fd, &vbl); + if (ret != 0) { + printf("drmWaitVBlank (relative, event) failed ret: %i\n", ret); + return -1; + } + + /* Set up our event handler */ + memset(&evctx, 0, sizeof evctx); + evctx.version = DRM_EVENT_CONTEXT_VERSION; + evctx.vblank_handler = vblank_handler; + evctx.page_flip_handler = NULL; + + /* Poll for events */ + while (1) { + struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; + fd_set fds; + + FD_ZERO(&fds); + FD_SET(0, &fds); + FD_SET(fd, &fds); + ret = select(fd + 1, &fds, NULL, NULL, &timeout); + + if (ret <= 0) { + fprintf(stderr, "select timed out or error (ret %d)\n", + ret); + continue; + } else if (FD_ISSET(0, &fds)) { + break; + } + + ret = drmHandleEvent(fd, &evctx); + if (ret != 0) { + printf("drmHandleEvent failed: %i\n", ret); + return -1; + } + } + + return 0; +} diff --git a/util_double_list.h b/util_double_list.h new file mode 100644 index 0000000..9bdca13 --- /dev/null +++ b/util_double_list.h @@ -0,0 +1,143 @@ +/* + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA. + * 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 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 + * THE COPYRIGHT HOLDERS, AUTHORS 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. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + */ + +/** + * \file + * List macros heavily inspired by the Linux kernel + * list handling. No list looping yet. + * + * Is not threadsafe, so common operations need to + * be protected using an external mutex. + */ +#ifndef _U_DOUBLE_LIST_H_ +#define _U_DOUBLE_LIST_H_ + +#include + +struct list_head +{ + struct list_head *prev; + struct list_head *next; +}; + +static inline void list_inithead(struct list_head *item) +{ + item->prev = item; + item->next = item; +} + +static inline void list_add(struct list_head *item, struct list_head *list) +{ + item->prev = list; + item->next = list->next; + list->next->prev = item; + list->next = item; +} + +static inline void list_addtail(struct list_head *item, struct list_head *list) +{ + item->next = list; + item->prev = list->prev; + list->prev->next = item; + list->prev = item; +} + +static inline void list_replace(struct list_head *from, struct list_head *to) +{ + to->prev = from->prev; + to->next = from->next; + from->next->prev = to; + from->prev->next = to; +} + +static inline void list_del(struct list_head *item) +{ + item->prev->next = item->next; + item->next->prev = item->prev; +} + +static inline void list_delinit(struct list_head *item) +{ + item->prev->next = item->next; + item->next->prev = item->prev; + item->next = item; + item->prev = item; +} + +#define LIST_INITHEAD(__item) list_inithead(__item) +#define LIST_ADD(__item, __list) list_add(__item, __list) +#define LIST_ADDTAIL(__item, __list) list_addtail(__item, __list) +#define LIST_REPLACE(__from, __to) list_replace(__from, __to) +#define LIST_DEL(__item) list_del(__item) +#define LIST_DELINIT(__item) list_delinit(__item) + +#define LIST_ENTRY(__type, __item, __field) \ + ((__type *)(((char *)(__item)) - offsetof(__type, __field))) + +#define LIST_FIRST_ENTRY(__ptr, __type, __field) \ + LIST_ENTRY(__type, (__ptr)->next, __field) + +#define LIST_LAST_ENTRY(__ptr, __type, __field) \ + LIST_ENTRY(__type, (__ptr)->prev, __field) + +#define LIST_IS_EMPTY(__list) \ + ((__list)->next == (__list)) + +#ifndef container_of +#define container_of(ptr, sample, member) \ + (void *)((char *)(ptr) \ + - ((char *)&((__typeof__(sample))0)->member)) +#endif + +#define LIST_FOR_EACH_ENTRY(pos, head, member) \ + for (pos = container_of((head)->next, pos, member); \ + &pos->member != (head); \ + pos = container_of(pos->member.next, pos, member)) + +#define LIST_FOR_EACH_ENTRY_SAFE(pos, storage, head, member) \ + for (pos = container_of((head)->next, pos, member), \ + storage = container_of(pos->member.next, pos, member); \ + &pos->member != (head); \ + pos = storage, storage = container_of(storage->member.next, storage, member)) + +#define LIST_FOR_EACH_ENTRY_SAFE_REV(pos, storage, head, member) \ + for (pos = container_of((head)->prev, pos, member), \ + storage = container_of(pos->member.prev, pos, member); \ + &pos->member != (head); \ + pos = storage, storage = container_of(storage->member.prev, storage, member)) + +#define LIST_FOR_EACH_ENTRY_FROM(pos, start, head, member) \ + for (pos = container_of((start), pos, member); \ + &pos->member != (head); \ + pos = container_of(pos->member.next, pos, member)) + +#define LIST_FOR_EACH_ENTRY_FROM_REV(pos, start, head, member) \ + for (pos = container_of((start), pos, member); \ + &pos->member != (head); \ + pos = container_of(pos->member.prev, pos, member)) + +#endif /*_U_DOUBLE_LIST_H_*/ diff --git a/util_math.h b/util_math.h new file mode 100644 index 0000000..35bf451 --- /dev/null +++ b/util_math.h @@ -0,0 +1,34 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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 _UTIL_MATH_H_ +#define _UTIL_MATH_H_ + +#define MIN2( A, B ) ( (A)<(B) ? (A) : (B) ) +#define MAX2( A, B ) ( (A)>(B) ? (A) : (B) ) +#define MAX3( A, B, C ) ((A) > (B) ? MAX2(A, C) : MAX2(B, C)) + +#define __align_mask(value, mask) (((value) + (mask)) & ~(mask)) +#define ALIGN(value, alignment) __align_mask(value, (__typeof__(value))((alignment) - 1)) + +#endif /*_UTIL_MATH_H_*/ diff --git a/vc4/Makefile.sources b/vc4/Makefile.sources new file mode 100644 index 0000000..8bf97ff --- /dev/null +++ b/vc4/Makefile.sources @@ -0,0 +1,3 @@ +LIBDRM_VC4_H_FILES := \ + vc4_packet.h \ + vc4_qpu_defines.h diff --git a/vc4/libdrm_vc4.pc.in b/vc4/libdrm_vc4.pc.in new file mode 100644 index 0000000..a92678e --- /dev/null +++ b/vc4/libdrm_vc4.pc.in @@ -0,0 +1,9 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libdrm_vc4 +Description: Userspace interface to vc4 kernel DRM services +Version: @PACKAGE_VERSION@ +Requires.private: libdrm diff --git a/vc4/meson.build b/vc4/meson.build new file mode 100644 index 0000000..0136987 --- /dev/null +++ b/vc4/meson.build @@ -0,0 +1,28 @@ +# Copyright © 2017 Intel Corporation + +# 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. + +install_headers('vc4_packet.h', 'vc4_qpu_defines.h', subdir : 'libdrm') + +pkg.generate( + name : 'libdrm_vc4', + version : meson.project_version(), + requires_private : 'libdrm', + description : 'Userspace interface to vc4 kernel DRM services', +) diff --git a/vc4/vc4_packet.h b/vc4/vc4_packet.h new file mode 100644 index 0000000..e18e0bd --- /dev/null +++ b/vc4/vc4_packet.h @@ -0,0 +1,397 @@ +/* + * Copyright © 2014 Broadcom + * + * 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 (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 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. + */ + +#ifndef VC4_PACKET_H +#define VC4_PACKET_H + +enum vc4_packet { + VC4_PACKET_HALT = 0, + VC4_PACKET_NOP = 1, + + VC4_PACKET_FLUSH = 4, + VC4_PACKET_FLUSH_ALL = 5, + VC4_PACKET_START_TILE_BINNING = 6, + VC4_PACKET_INCREMENT_SEMAPHORE = 7, + VC4_PACKET_WAIT_ON_SEMAPHORE = 8, + + VC4_PACKET_BRANCH = 16, + VC4_PACKET_BRANCH_TO_SUB_LIST = 17, + VC4_PACKET_RETURN_FROM_SUB_LIST = 18, + + VC4_PACKET_STORE_MS_TILE_BUFFER = 24, + VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF = 25, + VC4_PACKET_STORE_FULL_RES_TILE_BUFFER = 26, + VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER = 27, + VC4_PACKET_STORE_TILE_BUFFER_GENERAL = 28, + VC4_PACKET_LOAD_TILE_BUFFER_GENERAL = 29, + + VC4_PACKET_GL_INDEXED_PRIMITIVE = 32, + VC4_PACKET_GL_ARRAY_PRIMITIVE = 33, + + VC4_PACKET_COMPRESSED_PRIMITIVE = 48, + VC4_PACKET_CLIPPED_COMPRESSED_PRIMITIVE = 49, + + VC4_PACKET_PRIMITIVE_LIST_FORMAT = 56, + + VC4_PACKET_GL_SHADER_STATE = 64, + VC4_PACKET_NV_SHADER_STATE = 65, + VC4_PACKET_VG_SHADER_STATE = 66, + + VC4_PACKET_CONFIGURATION_BITS = 96, + VC4_PACKET_FLAT_SHADE_FLAGS = 97, + VC4_PACKET_POINT_SIZE = 98, + VC4_PACKET_LINE_WIDTH = 99, + VC4_PACKET_RHT_X_BOUNDARY = 100, + VC4_PACKET_DEPTH_OFFSET = 101, + VC4_PACKET_CLIP_WINDOW = 102, + VC4_PACKET_VIEWPORT_OFFSET = 103, + VC4_PACKET_Z_CLIPPING = 104, + VC4_PACKET_CLIPPER_XY_SCALING = 105, + VC4_PACKET_CLIPPER_Z_SCALING = 106, + + VC4_PACKET_TILE_BINNING_MODE_CONFIG = 112, + VC4_PACKET_TILE_RENDERING_MODE_CONFIG = 113, + VC4_PACKET_CLEAR_COLORS = 114, + VC4_PACKET_TILE_COORDINATES = 115, + + /* Not an actual hardware packet -- this is what we use to put + * references to GEM bos in the command stream, since we need the u32 + * int the actual address packet in order to store the offset from the + * start of the BO. + */ + VC4_PACKET_GEM_HANDLES = 254, +} __attribute__ ((__packed__)); + +#define VC4_PACKET_HALT_SIZE 1 +#define VC4_PACKET_NOP_SIZE 1 +#define VC4_PACKET_FLUSH_SIZE 1 +#define VC4_PACKET_FLUSH_ALL_SIZE 1 +#define VC4_PACKET_START_TILE_BINNING_SIZE 1 +#define VC4_PACKET_INCREMENT_SEMAPHORE_SIZE 1 +#define VC4_PACKET_WAIT_ON_SEMAPHORE_SIZE 1 +#define VC4_PACKET_BRANCH_SIZE 5 +#define VC4_PACKET_BRANCH_TO_SUB_LIST_SIZE 5 +#define VC4_PACKET_RETURN_FROM_SUB_LIST_SIZE 1 +#define VC4_PACKET_STORE_MS_TILE_BUFFER_SIZE 1 +#define VC4_PACKET_STORE_MS_TILE_BUFFER_AND_EOF_SIZE 1 +#define VC4_PACKET_STORE_FULL_RES_TILE_BUFFER_SIZE 5 +#define VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER_SIZE 5 +#define VC4_PACKET_STORE_TILE_BUFFER_GENERAL_SIZE 7 +#define VC4_PACKET_LOAD_TILE_BUFFER_GENERAL_SIZE 7 +#define VC4_PACKET_GL_INDEXED_PRIMITIVE_SIZE 14 +#define VC4_PACKET_GL_ARRAY_PRIMITIVE_SIZE 10 +#define VC4_PACKET_COMPRESSED_PRIMITIVE_SIZE 1 +#define VC4_PACKET_CLIPPED_COMPRESSED_PRIMITIVE_SIZE 1 +#define VC4_PACKET_PRIMITIVE_LIST_FORMAT_SIZE 2 +#define VC4_PACKET_GL_SHADER_STATE_SIZE 5 +#define VC4_PACKET_NV_SHADER_STATE_SIZE 5 +#define VC4_PACKET_VG_SHADER_STATE_SIZE 5 +#define VC4_PACKET_CONFIGURATION_BITS_SIZE 4 +#define VC4_PACKET_FLAT_SHADE_FLAGS_SIZE 5 +#define VC4_PACKET_POINT_SIZE_SIZE 5 +#define VC4_PACKET_LINE_WIDTH_SIZE 5 +#define VC4_PACKET_RHT_X_BOUNDARY_SIZE 3 +#define VC4_PACKET_DEPTH_OFFSET_SIZE 5 +#define VC4_PACKET_CLIP_WINDOW_SIZE 9 +#define VC4_PACKET_VIEWPORT_OFFSET_SIZE 5 +#define VC4_PACKET_Z_CLIPPING_SIZE 9 +#define VC4_PACKET_CLIPPER_XY_SCALING_SIZE 9 +#define VC4_PACKET_CLIPPER_Z_SCALING_SIZE 9 +#define VC4_PACKET_TILE_BINNING_MODE_CONFIG_SIZE 16 +#define VC4_PACKET_TILE_RENDERING_MODE_CONFIG_SIZE 11 +#define VC4_PACKET_CLEAR_COLORS_SIZE 14 +#define VC4_PACKET_TILE_COORDINATES_SIZE 3 +#define VC4_PACKET_GEM_HANDLES_SIZE 9 + +#define VC4_MASK(high, low) (((1 << ((high) - (low) + 1)) - 1) << (low)) +/* Using the GNU statement expression extension */ +#define VC4_SET_FIELD(value, field) \ + ({ \ + uint32_t fieldval = (value) << field ## _SHIFT; \ + assert((fieldval & ~ field ## _MASK) == 0); \ + fieldval & field ## _MASK; \ + }) + +#define VC4_GET_FIELD(word, field) (((word) & field ## _MASK) >> field ## _SHIFT) + +/** @{ + * Bits used by packets like VC4_PACKET_STORE_TILE_BUFFER_GENERAL and + * VC4_PACKET_TILE_RENDERING_MODE_CONFIG. +*/ +#define VC4_TILING_FORMAT_LINEAR 0 +#define VC4_TILING_FORMAT_T 1 +#define VC4_TILING_FORMAT_LT 2 +/** @} */ + +/** @{ + * + * low bits of VC4_PACKET_STORE_FULL_RES_TILE_BUFFER and + * VC4_PACKET_LOAD_FULL_RES_TILE_BUFFER. + */ +#define VC4_LOADSTORE_FULL_RES_EOF (1 << 3) +#define VC4_LOADSTORE_FULL_RES_DISABLE_CLEAR_ALL (1 << 2) +#define VC4_LOADSTORE_FULL_RES_DISABLE_ZS (1 << 1) +#define VC4_LOADSTORE_FULL_RES_DISABLE_COLOR (1 << 0) + +/** @{ + * + * byte 2 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and + * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL (low bits of the address) + */ + +#define VC4_LOADSTORE_TILE_BUFFER_EOF (1 << 3) +#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_VG_MASK (1 << 2) +#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_ZS (1 << 1) +#define VC4_LOADSTORE_TILE_BUFFER_DISABLE_FULL_COLOR (1 << 0) + +/** @} */ + +/** @{ + * + * byte 0-1 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and + * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL + */ +#define VC4_STORE_TILE_BUFFER_DISABLE_VG_MASK_CLEAR (1 << 15) +#define VC4_STORE_TILE_BUFFER_DISABLE_ZS_CLEAR (1 << 14) +#define VC4_STORE_TILE_BUFFER_DISABLE_COLOR_CLEAR (1 << 13) +#define VC4_STORE_TILE_BUFFER_DISABLE_SWAP (1 << 12) + +#define VC4_LOADSTORE_TILE_BUFFER_FORMAT_MASK VC4_MASK(9, 8) +#define VC4_LOADSTORE_TILE_BUFFER_FORMAT_SHIFT 8 +#define VC4_LOADSTORE_TILE_BUFFER_RGBA8888 0 +#define VC4_LOADSTORE_TILE_BUFFER_BGR565_DITHER 1 +#define VC4_LOADSTORE_TILE_BUFFER_BGR565 2 +/** @} */ + +/** @{ + * + * byte 0 of VC4_PACKET_STORE_TILE_BUFFER_GENERAL and + * VC4_PACKET_LOAD_TILE_BUFFER_GENERAL + */ +#define VC4_STORE_TILE_BUFFER_MODE_MASK VC4_MASK(7, 6) +#define VC4_STORE_TILE_BUFFER_MODE_SHIFT 6 +#define VC4_STORE_TILE_BUFFER_MODE_SAMPLE0 (0 << 6) +#define VC4_STORE_TILE_BUFFER_MODE_DECIMATE_X4 (1 << 6) +#define VC4_STORE_TILE_BUFFER_MODE_DECIMATE_X16 (2 << 6) + +/** The values of the field are VC4_TILING_FORMAT_* */ +#define VC4_LOADSTORE_TILE_BUFFER_TILING_MASK VC4_MASK(5, 4) +#define VC4_LOADSTORE_TILE_BUFFER_TILING_SHIFT 4 + +#define VC4_LOADSTORE_TILE_BUFFER_BUFFER_MASK VC4_MASK(2, 0) +#define VC4_LOADSTORE_TILE_BUFFER_BUFFER_SHIFT 0 +#define VC4_LOADSTORE_TILE_BUFFER_NONE 0 +#define VC4_LOADSTORE_TILE_BUFFER_COLOR 1 +#define VC4_LOADSTORE_TILE_BUFFER_ZS 2 +#define VC4_LOADSTORE_TILE_BUFFER_Z 3 +#define VC4_LOADSTORE_TILE_BUFFER_VG_MASK 4 +#define VC4_LOADSTORE_TILE_BUFFER_FULL 5 +/** @} */ + +#define VC4_INDEX_BUFFER_U8 (0 << 4) +#define VC4_INDEX_BUFFER_U16 (1 << 4) + +/* This flag is only present in NV shader state. */ +#define VC4_SHADER_FLAG_SHADED_CLIP_COORDS (1 << 3) +#define VC4_SHADER_FLAG_ENABLE_CLIPPING (1 << 2) +#define VC4_SHADER_FLAG_VS_POINT_SIZE (1 << 1) +#define VC4_SHADER_FLAG_FS_SINGLE_THREAD (1 << 0) + +/** @{ byte 2 of config bits. */ +#define VC4_CONFIG_BITS_EARLY_Z_UPDATE (1 << 1) +#define VC4_CONFIG_BITS_EARLY_Z (1 << 0) +/** @} */ + +/** @{ byte 1 of config bits. */ +#define VC4_CONFIG_BITS_Z_UPDATE (1 << 7) +/** same values in this 3-bit field as PIPE_FUNC_* */ +#define VC4_CONFIG_BITS_DEPTH_FUNC_SHIFT 4 +#define VC4_CONFIG_BITS_COVERAGE_READ_LEAVE (1 << 3) + +#define VC4_CONFIG_BITS_COVERAGE_UPDATE_NONZERO (0 << 1) +#define VC4_CONFIG_BITS_COVERAGE_UPDATE_ODD (1 << 1) +#define VC4_CONFIG_BITS_COVERAGE_UPDATE_OR (2 << 1) +#define VC4_CONFIG_BITS_COVERAGE_UPDATE_ZERO (3 << 1) + +#define VC4_CONFIG_BITS_COVERAGE_PIPE_SELECT (1 << 0) +/** @} */ + +/** @{ byte 0 of config bits. */ +#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_NONE (0 << 6) +#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_4X (1 << 6) +#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_16X (2 << 6) +#define VC4_CONFIG_BITS_RASTERIZER_OVERSAMPLE_MASK (3 << 6) + +#define VC4_CONFIG_BITS_AA_POINTS_AND_LINES (1 << 4) +#define VC4_CONFIG_BITS_ENABLE_DEPTH_OFFSET (1 << 3) +#define VC4_CONFIG_BITS_CW_PRIMITIVES (1 << 2) +#define VC4_CONFIG_BITS_ENABLE_PRIM_BACK (1 << 1) +#define VC4_CONFIG_BITS_ENABLE_PRIM_FRONT (1 << 0) +/** @} */ + +/** @{ bits in the last u8 of VC4_PACKET_TILE_BINNING_MODE_CONFIG */ +#define VC4_BIN_CONFIG_DB_NON_MS (1 << 7) + +#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_MASK VC4_MASK(6, 5) +#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_SHIFT 5 +#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_32 0 +#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_64 1 +#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_128 2 +#define VC4_BIN_CONFIG_ALLOC_BLOCK_SIZE_256 3 + +#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_MASK VC4_MASK(4, 3) +#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_SHIFT 3 +#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_32 0 +#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_64 1 +#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_128 2 +#define VC4_BIN_CONFIG_ALLOC_INIT_BLOCK_SIZE_256 3 + +#define VC4_BIN_CONFIG_AUTO_INIT_TSDA (1 << 2) +#define VC4_BIN_CONFIG_TILE_BUFFER_64BIT (1 << 1) +#define VC4_BIN_CONFIG_MS_MODE_4X (1 << 0) +/** @} */ + +/** @{ bits in the last u16 of VC4_PACKET_TILE_RENDERING_MODE_CONFIG */ +#define VC4_RENDER_CONFIG_DB_NON_MS (1 << 12) +#define VC4_RENDER_CONFIG_EARLY_Z_COVERAGE_DISABLE (1 << 11) +#define VC4_RENDER_CONFIG_EARLY_Z_DIRECTION_G (1 << 10) +#define VC4_RENDER_CONFIG_COVERAGE_MODE (1 << 9) +#define VC4_RENDER_CONFIG_ENABLE_VG_MASK (1 << 8) + +/** The values of the field are VC4_TILING_FORMAT_* */ +#define VC4_RENDER_CONFIG_MEMORY_FORMAT_MASK VC4_MASK(7, 6) +#define VC4_RENDER_CONFIG_MEMORY_FORMAT_SHIFT 6 + +#define VC4_RENDER_CONFIG_DECIMATE_MODE_1X (0 << 4) +#define VC4_RENDER_CONFIG_DECIMATE_MODE_4X (1 << 4) +#define VC4_RENDER_CONFIG_DECIMATE_MODE_16X (2 << 4) +#define VC4_RENDER_CONFIG_DECIMATE_MODE_MASK (3 << 4) + +#define VC4_RENDER_CONFIG_FORMAT_MASK VC4_MASK(3, 2) +#define VC4_RENDER_CONFIG_FORMAT_SHIFT 2 +#define VC4_RENDER_CONFIG_FORMAT_BGR565_DITHERED 0 +#define VC4_RENDER_CONFIG_FORMAT_RGBA8888 1 +#define VC4_RENDER_CONFIG_FORMAT_BGR565 2 + +#define VC4_RENDER_CONFIG_TILE_BUFFER_64BIT (1 << 1) +#define VC4_RENDER_CONFIG_MS_MODE_4X (1 << 0) + +#define VC4_PRIMITIVE_LIST_FORMAT_16_INDEX (1 << 4) +#define VC4_PRIMITIVE_LIST_FORMAT_32_XY (3 << 4) +#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_POINTS (0 << 0) +#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_LINES (1 << 0) +#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_TRIANGLES (2 << 0) +#define VC4_PRIMITIVE_LIST_FORMAT_TYPE_RHT (3 << 0) + +enum vc4_texture_data_type { + VC4_TEXTURE_TYPE_RGBA8888 = 0, + VC4_TEXTURE_TYPE_RGBX8888 = 1, + VC4_TEXTURE_TYPE_RGBA4444 = 2, + VC4_TEXTURE_TYPE_RGBA5551 = 3, + VC4_TEXTURE_TYPE_RGB565 = 4, + VC4_TEXTURE_TYPE_LUMINANCE = 5, + VC4_TEXTURE_TYPE_ALPHA = 6, + VC4_TEXTURE_TYPE_LUMALPHA = 7, + VC4_TEXTURE_TYPE_ETC1 = 8, + VC4_TEXTURE_TYPE_S16F = 9, + VC4_TEXTURE_TYPE_S8 = 10, + VC4_TEXTURE_TYPE_S16 = 11, + VC4_TEXTURE_TYPE_BW1 = 12, + VC4_TEXTURE_TYPE_A4 = 13, + VC4_TEXTURE_TYPE_A1 = 14, + VC4_TEXTURE_TYPE_RGBA64 = 15, + VC4_TEXTURE_TYPE_RGBA32R = 16, + VC4_TEXTURE_TYPE_YUV422R = 17, +}; + +#define VC4_TEX_P0_OFFSET_MASK VC4_MASK(31, 12) +#define VC4_TEX_P0_OFFSET_SHIFT 12 +#define VC4_TEX_P0_CSWIZ_MASK VC4_MASK(11, 10) +#define VC4_TEX_P0_CSWIZ_SHIFT 10 +#define VC4_TEX_P0_CMMODE_MASK VC4_MASK(9, 9) +#define VC4_TEX_P0_CMMODE_SHIFT 9 +#define VC4_TEX_P0_FLIPY_MASK VC4_MASK(8, 8) +#define VC4_TEX_P0_FLIPY_SHIFT 8 +#define VC4_TEX_P0_TYPE_MASK VC4_MASK(7, 4) +#define VC4_TEX_P0_TYPE_SHIFT 4 +#define VC4_TEX_P0_MIPLVLS_MASK VC4_MASK(3, 0) +#define VC4_TEX_P0_MIPLVLS_SHIFT 0 + +#define VC4_TEX_P1_TYPE4_MASK VC4_MASK(31, 31) +#define VC4_TEX_P1_TYPE4_SHIFT 31 +#define VC4_TEX_P1_HEIGHT_MASK VC4_MASK(30, 20) +#define VC4_TEX_P1_HEIGHT_SHIFT 20 +#define VC4_TEX_P1_ETCFLIP_MASK VC4_MASK(19, 19) +#define VC4_TEX_P1_ETCFLIP_SHIFT 19 +#define VC4_TEX_P1_WIDTH_MASK VC4_MASK(18, 8) +#define VC4_TEX_P1_WIDTH_SHIFT 8 + +#define VC4_TEX_P1_MAGFILT_MASK VC4_MASK(7, 7) +#define VC4_TEX_P1_MAGFILT_SHIFT 7 +# define VC4_TEX_P1_MAGFILT_LINEAR 0 +# define VC4_TEX_P1_MAGFILT_NEAREST 1 + +#define VC4_TEX_P1_MINFILT_MASK VC4_MASK(6, 4) +#define VC4_TEX_P1_MINFILT_SHIFT 4 +# define VC4_TEX_P1_MINFILT_LINEAR 0 +# define VC4_TEX_P1_MINFILT_NEAREST 1 +# define VC4_TEX_P1_MINFILT_NEAR_MIP_NEAR 2 +# define VC4_TEX_P1_MINFILT_NEAR_MIP_LIN 3 +# define VC4_TEX_P1_MINFILT_LIN_MIP_NEAR 4 +# define VC4_TEX_P1_MINFILT_LIN_MIP_LIN 5 + +#define VC4_TEX_P1_WRAP_T_MASK VC4_MASK(3, 2) +#define VC4_TEX_P1_WRAP_T_SHIFT 2 +#define VC4_TEX_P1_WRAP_S_MASK VC4_MASK(1, 0) +#define VC4_TEX_P1_WRAP_S_SHIFT 0 +# define VC4_TEX_P1_WRAP_REPEAT 0 +# define VC4_TEX_P1_WRAP_CLAMP 1 +# define VC4_TEX_P1_WRAP_MIRROR 2 +# define VC4_TEX_P1_WRAP_BORDER 3 + +#define VC4_TEX_P2_PTYPE_MASK VC4_MASK(31, 30) +#define VC4_TEX_P2_PTYPE_SHIFT 30 +# define VC4_TEX_P2_PTYPE_IGNORED 0 +# define VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE 1 +# define VC4_TEX_P2_PTYPE_CHILD_IMAGE_DIMENSIONS 2 +# define VC4_TEX_P2_PTYPE_CHILD_IMAGE_OFFSETS 3 + +/* VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE bits */ +#define VC4_TEX_P2_CMST_MASK VC4_MASK(29, 12) +#define VC4_TEX_P2_CMST_SHIFT 12 +#define VC4_TEX_P2_BSLOD_MASK VC4_MASK(0, 0) +#define VC4_TEX_P2_BSLOD_SHIFT 0 + +/* VC4_TEX_P2_PTYPE_CHILD_IMAGE_DIMENSIONS */ +#define VC4_TEX_P2_CHEIGHT_MASK VC4_MASK(22, 12) +#define VC4_TEX_P2_CHEIGHT_SHIFT 12 +#define VC4_TEX_P2_CWIDTH_MASK VC4_MASK(10, 0) +#define VC4_TEX_P2_CWIDTH_SHIFT 0 + +/* VC4_TEX_P2_PTYPE_CHILD_IMAGE_OFFSETS */ +#define VC4_TEX_P2_CYOFF_MASK VC4_MASK(22, 12) +#define VC4_TEX_P2_CYOFF_SHIFT 12 +#define VC4_TEX_P2_CXOFF_MASK VC4_MASK(10, 0) +#define VC4_TEX_P2_CXOFF_SHIFT 0 + +#endif /* VC4_PACKET_H */ diff --git a/vc4/vc4_qpu_defines.h b/vc4/vc4_qpu_defines.h new file mode 100644 index 0000000..26fcf50 --- /dev/null +++ b/vc4/vc4_qpu_defines.h @@ -0,0 +1,274 @@ +/* + * Copyright © 2014 Broadcom + * + * 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 (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 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. + */ + +#ifndef VC4_QPU_DEFINES_H +#define VC4_QPU_DEFINES_H + +enum qpu_op_add { + QPU_A_NOP, + QPU_A_FADD, + QPU_A_FSUB, + QPU_A_FMIN, + QPU_A_FMAX, + QPU_A_FMINABS, + QPU_A_FMAXABS, + QPU_A_FTOI, + QPU_A_ITOF, + QPU_A_ADD = 12, + QPU_A_SUB, + QPU_A_SHR, + QPU_A_ASR, + QPU_A_ROR, + QPU_A_SHL, + QPU_A_MIN, + QPU_A_MAX, + QPU_A_AND, + QPU_A_OR, + QPU_A_XOR, + QPU_A_NOT, + QPU_A_CLZ, + QPU_A_V8ADDS = 30, + QPU_A_V8SUBS = 31, +}; + +enum qpu_op_mul { + QPU_M_NOP, + QPU_M_FMUL, + QPU_M_MUL24, + QPU_M_V8MULD, + QPU_M_V8MIN, + QPU_M_V8MAX, + QPU_M_V8ADDS, + QPU_M_V8SUBS, +}; + +enum qpu_raddr { + QPU_R_FRAG_PAYLOAD_ZW = 15, /* W for A file, Z for B file */ + /* 0-31 are the plain regfile a or b fields */ + QPU_R_UNIF = 32, + QPU_R_VARY = 35, + QPU_R_ELEM_QPU = 38, + QPU_R_NOP, + QPU_R_XY_PIXEL_COORD = 41, + QPU_R_MS_REV_FLAGS = 42, + QPU_R_VPM = 48, + QPU_R_VPM_LD_BUSY, + QPU_R_VPM_LD_WAIT, + QPU_R_MUTEX_ACQUIRE, +}; + +enum qpu_waddr { + /* 0-31 are the plain regfile a or b fields */ + QPU_W_ACC0 = 32, /* aka r0 */ + QPU_W_ACC1, + QPU_W_ACC2, + QPU_W_ACC3, + QPU_W_TMU_NOSWAP, + QPU_W_ACC5, + QPU_W_HOST_INT, + QPU_W_NOP, + QPU_W_UNIFORMS_ADDRESS, + QPU_W_QUAD_XY, /* X for regfile a, Y for regfile b */ + QPU_W_MS_FLAGS = 42, + QPU_W_REV_FLAG = 42, + QPU_W_TLB_STENCIL_SETUP = 43, + QPU_W_TLB_Z, + QPU_W_TLB_COLOR_MS, + QPU_W_TLB_COLOR_ALL, + QPU_W_TLB_ALPHA_MASK, + QPU_W_VPM, + QPU_W_VPMVCD_SETUP, /* LD for regfile a, ST for regfile b */ + QPU_W_VPM_ADDR, /* LD for regfile a, ST for regfile b */ + QPU_W_MUTEX_RELEASE, + QPU_W_SFU_RECIP, + QPU_W_SFU_RECIPSQRT, + QPU_W_SFU_EXP, + QPU_W_SFU_LOG, + QPU_W_TMU0_S, + QPU_W_TMU0_T, + QPU_W_TMU0_R, + QPU_W_TMU0_B, + QPU_W_TMU1_S, + QPU_W_TMU1_T, + QPU_W_TMU1_R, + QPU_W_TMU1_B, +}; + +enum qpu_sig_bits { + QPU_SIG_SW_BREAKPOINT, + QPU_SIG_NONE, + QPU_SIG_THREAD_SWITCH, + QPU_SIG_PROG_END, + QPU_SIG_WAIT_FOR_SCOREBOARD, + QPU_SIG_SCOREBOARD_UNLOCK, + QPU_SIG_LAST_THREAD_SWITCH, + QPU_SIG_COVERAGE_LOAD, + QPU_SIG_COLOR_LOAD, + QPU_SIG_COLOR_LOAD_END, + QPU_SIG_LOAD_TMU0, + QPU_SIG_LOAD_TMU1, + QPU_SIG_ALPHA_MASK_LOAD, + QPU_SIG_SMALL_IMM, + QPU_SIG_LOAD_IMM, + QPU_SIG_BRANCH +}; + +enum qpu_mux { + /* hardware mux values */ + QPU_MUX_R0, + QPU_MUX_R1, + QPU_MUX_R2, + QPU_MUX_R3, + QPU_MUX_R4, + QPU_MUX_R5, + QPU_MUX_A, + QPU_MUX_B, + + /** + * Non-hardware mux value, stores a small immediate field to be + * programmed into raddr_b in the qpu_reg.index. + */ + QPU_MUX_SMALL_IMM, +}; + +enum qpu_cond { + QPU_COND_NEVER, + QPU_COND_ALWAYS, + QPU_COND_ZS, + QPU_COND_ZC, + QPU_COND_NS, + QPU_COND_NC, + QPU_COND_CS, + QPU_COND_CC, +}; + +enum qpu_pack_mul { + QPU_PACK_MUL_NOP, + QPU_PACK_MUL_8888 = 3, /* replicated to each 8 bits of the 32-bit dst. */ + QPU_PACK_MUL_8A, + QPU_PACK_MUL_8B, + QPU_PACK_MUL_8C, + QPU_PACK_MUL_8D, +}; + +enum qpu_pack_a { + QPU_PACK_A_NOP, + /* convert to 16 bit float if float input, or to int16. */ + QPU_PACK_A_16A, + QPU_PACK_A_16B, + /* replicated to each 8 bits of the 32-bit dst. */ + QPU_PACK_A_8888, + /* Convert to 8-bit unsigned int. */ + QPU_PACK_A_8A, + QPU_PACK_A_8B, + QPU_PACK_A_8C, + QPU_PACK_A_8D, + + /* Saturating variants of the previous instructions. */ + QPU_PACK_A_32_SAT, /* int-only */ + QPU_PACK_A_16A_SAT, /* int or float */ + QPU_PACK_A_16B_SAT, + QPU_PACK_A_8888_SAT, + QPU_PACK_A_8A_SAT, + QPU_PACK_A_8B_SAT, + QPU_PACK_A_8C_SAT, + QPU_PACK_A_8D_SAT, +}; + +enum qpu_unpack { + QPU_UNPACK_NOP, + QPU_UNPACK_16A, + QPU_UNPACK_16B, + QPU_UNPACK_8D_REP, + QPU_UNPACK_8A, + QPU_UNPACK_8B, + QPU_UNPACK_8C, + QPU_UNPACK_8D, +}; + +#define QPU_MASK(high, low) ((((uint64_t)1<<((high)-(low)+1))-1)<<(low)) +/* Using the GNU statement expression extension */ +#define QPU_SET_FIELD(value, field) \ + ({ \ + uint64_t fieldval = (uint64_t)(value) << field ## _SHIFT; \ + assert((fieldval & ~ field ## _MASK) == 0); \ + fieldval & field ## _MASK; \ + }) + +#define QPU_GET_FIELD(word, field) ((uint32_t)(((word) & field ## _MASK) >> field ## _SHIFT)) + +#define QPU_UPDATE_FIELD(inst, value, field) \ + (((inst) & ~(field ## _MASK)) | QPU_SET_FIELD(value, field)) + +#define QPU_SIG_SHIFT 60 +#define QPU_SIG_MASK QPU_MASK(63, 60) + +#define QPU_UNPACK_SHIFT 57 +#define QPU_UNPACK_MASK QPU_MASK(59, 57) + +/** + * If set, the pack field means PACK_MUL or R4 packing, instead of normal + * regfile a packing. + */ +#define QPU_PM ((uint64_t)1 << 56) + +#define QPU_PACK_SHIFT 52 +#define QPU_PACK_MASK QPU_MASK(55, 52) + +#define QPU_COND_ADD_SHIFT 49 +#define QPU_COND_ADD_MASK QPU_MASK(51, 49) +#define QPU_COND_MUL_SHIFT 46 +#define QPU_COND_MUL_MASK QPU_MASK(48, 46) + +#define QPU_SF ((uint64_t)1 << 45) + +#define QPU_WADDR_ADD_SHIFT 38 +#define QPU_WADDR_ADD_MASK QPU_MASK(43, 38) +#define QPU_WADDR_MUL_SHIFT 32 +#define QPU_WADDR_MUL_MASK QPU_MASK(37, 32) + +#define QPU_OP_MUL_SHIFT 29 +#define QPU_OP_MUL_MASK QPU_MASK(31, 29) + +#define QPU_RADDR_A_SHIFT 18 +#define QPU_RADDR_A_MASK QPU_MASK(23, 18) +#define QPU_RADDR_B_SHIFT 12 +#define QPU_RADDR_B_MASK QPU_MASK(17, 12) +#define QPU_SMALL_IMM_SHIFT 12 +#define QPU_SMALL_IMM_MASK QPU_MASK(17, 12) + +#define QPU_ADD_A_SHIFT 9 +#define QPU_ADD_A_MASK QPU_MASK(11, 9) +#define QPU_ADD_B_SHIFT 6 +#define QPU_ADD_B_MASK QPU_MASK(8, 6) +#define QPU_MUL_A_SHIFT 3 +#define QPU_MUL_A_MASK QPU_MASK(5, 3) +#define QPU_MUL_B_SHIFT 0 +#define QPU_MUL_B_MASK QPU_MASK(2, 0) + +#define QPU_WS ((uint64_t)1 << 44) + +#define QPU_OP_ADD_SHIFT 24 +#define QPU_OP_ADD_MASK QPU_MASK(28, 24) + +#endif /* VC4_QPU_DEFINES_H */ diff --git a/xf86atomic.h b/xf86atomic.h new file mode 100644 index 0000000..c19e493 --- /dev/null +++ b/xf86atomic.h @@ -0,0 +1,114 @@ +/* + * Copyright © 2009 Intel Corporation + * + * 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 (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 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. + * + * Authors: + * Chris Wilson + * + */ + +/** + * @file xf86atomics.h + * + * Private definitions for atomic operations + */ + +#ifndef LIBDRM_ATOMICS_H +#define LIBDRM_ATOMICS_H + +#if HAVE_LIBDRM_ATOMIC_PRIMITIVES + +#define HAS_ATOMIC_OPS 1 + +typedef struct { + int atomic; +} atomic_t; + +# define atomic_read(x) ((x)->atomic) +# define atomic_set(x, val) ((x)->atomic = (val)) +# define atomic_inc(x) ((void) __sync_fetch_and_add (&(x)->atomic, 1)) +# define atomic_inc_return(x) (__sync_add_and_fetch (&(x)->atomic, 1)) +# define atomic_dec_and_test(x) (__sync_add_and_fetch (&(x)->atomic, -1) == 0) +# define atomic_add(x, v) ((void) __sync_add_and_fetch(&(x)->atomic, (v))) +# define atomic_dec(x, v) ((void) __sync_sub_and_fetch(&(x)->atomic, (v))) +# define atomic_cmpxchg(x, oldv, newv) __sync_val_compare_and_swap (&(x)->atomic, oldv, newv) + +#endif + +#if HAVE_LIB_ATOMIC_OPS +#define AO_REQUIRE_CAS +#include + +#define HAS_ATOMIC_OPS 1 + +typedef struct { + AO_t atomic; +} atomic_t; + +# define atomic_read(x) AO_load_full(&(x)->atomic) +# define atomic_set(x, val) AO_store_full(&(x)->atomic, (val)) +# define atomic_inc(x) ((void) AO_fetch_and_add1_full(&(x)->atomic)) +# define atomic_inc_return(x) (AO_fetch_and_add1_full(&(x)->atomic) + 1) +# define atomic_add(x, v) ((void) AO_fetch_and_add_full(&(x)->atomic, (v))) +# define atomic_dec(x, v) ((void) AO_fetch_and_add_full(&(x)->atomic, -(v))) +# define atomic_dec_and_test(x) (AO_fetch_and_sub1_full(&(x)->atomic) == 1) +# define atomic_cmpxchg(x, oldv, newv) AO_compare_and_swap_full(&(x)->atomic, oldv, newv) + +#endif + +#if (defined(__sun) || defined(__NetBSD__)) && !defined(HAS_ATOMIC_OPS) /* Solaris & OpenSolaris & NetBSD */ + +#include +#define HAS_ATOMIC_OPS 1 + +#if defined(__NetBSD__) +#define LIBDRM_ATOMIC_TYPE int +#else +#define LIBDRM_ATOMIC_TYPE uint_t +#endif + +typedef struct { LIBDRM_ATOMIC_TYPE atomic; } atomic_t; + +# define atomic_read(x) (int) ((x)->atomic) +# define atomic_set(x, val) ((x)->atomic = (LIBDRM_ATOMIC_TYPE)(val)) +# define atomic_inc(x) (atomic_inc_uint (&(x)->atomic)) +# define atomic_inc_return(x) (atomic_inc_uint_nv(&(x)->atomic)) +# define atomic_dec_and_test(x) (atomic_dec_uint_nv(&(x)->atomic) == 0) +# define atomic_add(x, v) (atomic_add_int(&(x)->atomic, (v))) +# define atomic_dec(x, v) (atomic_add_int(&(x)->atomic, -(v))) +# define atomic_cmpxchg(x, oldv, newv) atomic_cas_uint (&(x)->atomic, oldv, newv) + +#endif + +#if !defined(HAS_ATOMIC_OPS) +#error libdrm requires atomic operations, please define them for your CPU/compiler. +#endif + +static inline int atomic_add_unless(atomic_t *v, int add, int unless) +{ + int c, old; + c = atomic_read(v); + while (c != unless && (old = atomic_cmpxchg(v, c, c + add)) != c) + c = old; + return c != unless; +} + +#endif diff --git a/xf86drm.c b/xf86drm.c new file mode 100644 index 0000000..0faa597 --- /dev/null +++ b/xf86drm.c @@ -0,0 +1,5148 @@ +/** + * \file xf86drm.c + * User-level interface to DRM device + * + * \author Rickard E. (Rik) Faith + * \author Kevin E. Martin + */ + +/* + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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, 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define stat_t struct stat +#include +#include +#include +#ifdef MAJOR_IN_MKDEV +#include +#endif +#ifdef MAJOR_IN_SYSMACROS +#include +#endif +#if HAVE_SYS_SYSCTL_H +#include +#endif +#include +#include + +#if defined(__FreeBSD__) +#include +#include +#endif + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +/* Not all systems have MAP_FAILED defined */ +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)-1) +#endif + +#include "xf86drm.h" +#include "libdrm_macros.h" +#include "drm_fourcc.h" + +#include "util_math.h" + +#ifdef __DragonFly__ +#define DRM_MAJOR 145 +#endif + +#ifdef __NetBSD__ +#define DRM_MAJOR 34 +#endif + +#ifdef __OpenBSD__ +#ifdef __i386__ +#define DRM_MAJOR 88 +#else +#define DRM_MAJOR 87 +#endif +#endif /* __OpenBSD__ */ + +#ifndef DRM_MAJOR +#define DRM_MAJOR 226 /* Linux */ +#endif + +#if defined(__OpenBSD__) || defined(__DragonFly__) +struct drm_pciinfo { + uint16_t domain; + uint8_t bus; + uint8_t dev; + uint8_t func; + uint16_t vendor_id; + uint16_t device_id; + uint16_t subvendor_id; + uint16_t subdevice_id; + uint8_t revision_id; +}; + +#define DRM_IOCTL_GET_PCIINFO DRM_IOR(0x15, struct drm_pciinfo) +#endif + +#define DRM_MSG_VERBOSITY 3 + +#define memclear(s) memset(&s, 0, sizeof(s)) + +static drmServerInfoPtr drm_server_info; + +static bool drmNodeIsDRM(int maj, int min); +static char *drmGetMinorNameForFD(int fd, int type); + +#define DRM_MODIFIER(v, f, f_name) \ + .modifier = DRM_FORMAT_MOD_##v ## _ ##f, \ + .modifier_name = #f_name + +#define DRM_MODIFIER_INVALID(v, f_name) \ + .modifier = DRM_FORMAT_MOD_INVALID, .modifier_name = #f_name + +#define DRM_MODIFIER_LINEAR(v, f_name) \ + .modifier = DRM_FORMAT_MOD_LINEAR, .modifier_name = #f_name + +/* Intel is abit special as the format doesn't follow other vendors naming + * scheme */ +#define DRM_MODIFIER_INTEL(f, f_name) \ + .modifier = I915_FORMAT_MOD_##f, .modifier_name = #f_name + +struct drmFormatModifierInfo { + uint64_t modifier; + const char *modifier_name; +}; + +struct drmFormatModifierVendorInfo { + uint8_t vendor; + const char *vendor_name; +}; + +#include "generated_static_table_fourcc.h" + +struct drmVendorInfo { + uint8_t vendor; + char *(*vendor_cb)(uint64_t modifier); +}; + +struct drmFormatVendorModifierInfo { + uint64_t modifier; + const char *modifier_name; +}; + +static char * +drmGetFormatModifierNameFromArm(uint64_t modifier); + +static char * +drmGetFormatModifierNameFromNvidia(uint64_t modifier); + +static char * +drmGetFormatModifierNameFromAmd(uint64_t modifier); + +static char * +drmGetFormatModifierNameFromAmlogic(uint64_t modifier); + +static const struct drmVendorInfo modifier_format_vendor_table[] = { + { DRM_FORMAT_MOD_VENDOR_ARM, drmGetFormatModifierNameFromArm }, + { DRM_FORMAT_MOD_VENDOR_NVIDIA, drmGetFormatModifierNameFromNvidia }, + { DRM_FORMAT_MOD_VENDOR_AMD, drmGetFormatModifierNameFromAmd }, + { DRM_FORMAT_MOD_VENDOR_AMLOGIC, drmGetFormatModifierNameFromAmlogic }, +}; + +#ifndef AFBC_FORMAT_MOD_MODE_VALUE_MASK +#define AFBC_FORMAT_MOD_MODE_VALUE_MASK 0x000fffffffffffffULL +#endif + +static const struct drmFormatVendorModifierInfo arm_mode_value_table[] = { + { AFBC_FORMAT_MOD_YTR, "YTR" }, + { AFBC_FORMAT_MOD_SPLIT, "SPLIT" }, + { AFBC_FORMAT_MOD_SPARSE, "SPARSE" }, + { AFBC_FORMAT_MOD_CBR, "CBR" }, + { AFBC_FORMAT_MOD_TILED, "TILED" }, + { AFBC_FORMAT_MOD_SC, "SC" }, + { AFBC_FORMAT_MOD_DB, "DB" }, + { AFBC_FORMAT_MOD_BCH, "BCH" }, + { AFBC_FORMAT_MOD_USM, "USM" }, +}; + +static bool is_x_t_amd_gfx9_tile(uint64_t tile) +{ + switch (tile) { + case AMD_FMT_MOD_TILE_GFX9_64K_S_X: + case AMD_FMT_MOD_TILE_GFX9_64K_D_X: + case AMD_FMT_MOD_TILE_GFX9_64K_R_X: + return true; + } + + return false; +} + +static bool +drmGetAfbcFormatModifierNameFromArm(uint64_t modifier, FILE *fp) +{ + uint64_t mode_value = modifier & AFBC_FORMAT_MOD_MODE_VALUE_MASK; + uint64_t block_size = mode_value & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK; + + const char *block = NULL; + const char *mode = NULL; + bool did_print_mode = false; + + /* add block, can only have a (single) block */ + switch (block_size) { + case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16: + block = "16x16"; + break; + case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8: + block = "32x8"; + break; + case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4: + block = "64x4"; + break; + case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4: + block = "32x8_64x4"; + break; + } + + if (!block) { + return false; + } + + fprintf(fp, "BLOCK_SIZE=%s,", block); + + /* add mode */ + for (unsigned int i = 0; i < ARRAY_SIZE(arm_mode_value_table); i++) { + if (arm_mode_value_table[i].modifier & mode_value) { + mode = arm_mode_value_table[i].modifier_name; + if (!did_print_mode) { + fprintf(fp, "MODE=%s", mode); + did_print_mode = true; + } else { + fprintf(fp, "|%s", mode); + } + } + } + + return true; +} + +static bool +drmGetAfrcFormatModifierNameFromArm(uint64_t modifier, FILE *fp) +{ + bool scan_layout; + for (unsigned int i = 0; i < 2; ++i) { + uint64_t coding_unit_block = + (modifier >> (i * 4)) & AFRC_FORMAT_MOD_CU_SIZE_MASK; + const char *coding_unit_size = NULL; + + switch (coding_unit_block) { + case AFRC_FORMAT_MOD_CU_SIZE_16: + coding_unit_size = "CU_16"; + break; + case AFRC_FORMAT_MOD_CU_SIZE_24: + coding_unit_size = "CU_24"; + break; + case AFRC_FORMAT_MOD_CU_SIZE_32: + coding_unit_size = "CU_32"; + break; + } + + if (!coding_unit_size) { + if (i == 0) { + return false; + } + break; + } + + if (i == 0) { + fprintf(fp, "P0=%s,", coding_unit_size); + } else { + fprintf(fp, "P12=%s,", coding_unit_size); + } + } + + scan_layout = + (modifier & AFRC_FORMAT_MOD_LAYOUT_SCAN) == AFRC_FORMAT_MOD_LAYOUT_SCAN; + if (scan_layout) { + fprintf(fp, "SCAN"); + } else { + fprintf(fp, "ROT"); + } + return true; +} + +static char * +drmGetFormatModifierNameFromArm(uint64_t modifier) +{ + uint64_t type = (modifier >> 52) & 0xf; + + FILE *fp; + size_t size = 0; + char *modifier_name = NULL; + bool result = false; + + fp = open_memstream(&modifier_name, &size); + if (!fp) + return NULL; + + switch (type) { + case DRM_FORMAT_MOD_ARM_TYPE_AFBC: + result = drmGetAfbcFormatModifierNameFromArm(modifier, fp); + break; + case DRM_FORMAT_MOD_ARM_TYPE_AFRC: + result = drmGetAfrcFormatModifierNameFromArm(modifier, fp); + break; + /* misc type is already handled by the static table */ + case DRM_FORMAT_MOD_ARM_TYPE_MISC: + default: + result = false; + break; + } + + fclose(fp); + if (!result) { + free(modifier_name); + return NULL; + } + + return modifier_name; +} + +static char * +drmGetFormatModifierNameFromNvidia(uint64_t modifier) +{ + uint64_t height, kind, gen, sector, compression; + + height = modifier & 0xf; + kind = (modifier >> 12) & 0xff; + + gen = (modifier >> 20) & 0x3; + sector = (modifier >> 22) & 0x1; + compression = (modifier >> 23) & 0x7; + + /* just in case there could other simpler modifiers, not yet added, avoid + * testing against TEGRA_TILE */ + if ((modifier & 0x10) == 0x10) { + char *mod_nvidia; + asprintf(&mod_nvidia, "BLOCK_LINEAR_2D,HEIGHT=%"PRIu64",KIND=%"PRIu64"," + "GEN=%"PRIu64",SECTOR=%"PRIu64",COMPRESSION=%"PRIu64"", height, + kind, gen, sector, compression); + return mod_nvidia; + } + + return NULL; +} + +static void +drmGetFormatModifierNameFromAmdDcc(uint64_t modifier, FILE *fp) +{ + uint64_t dcc_max_compressed_block = + AMD_FMT_MOD_GET(DCC_MAX_COMPRESSED_BLOCK, modifier); + uint64_t dcc_retile = AMD_FMT_MOD_GET(DCC_RETILE, modifier); + + const char *dcc_max_compressed_block_str = NULL; + + fprintf(fp, ",DCC"); + + if (dcc_retile) + fprintf(fp, ",DCC_RETILE"); + + if (!dcc_retile && AMD_FMT_MOD_GET(DCC_PIPE_ALIGN, modifier)) + fprintf(fp, ",DCC_PIPE_ALIGN"); + + if (AMD_FMT_MOD_GET(DCC_INDEPENDENT_64B, modifier)) + fprintf(fp, ",DCC_INDEPENDENT_64B"); + + if (AMD_FMT_MOD_GET(DCC_INDEPENDENT_128B, modifier)) + fprintf(fp, ",DCC_INDEPENDENT_128B"); + + switch (dcc_max_compressed_block) { + case AMD_FMT_MOD_DCC_BLOCK_64B: + dcc_max_compressed_block_str = "64B"; + break; + case AMD_FMT_MOD_DCC_BLOCK_128B: + dcc_max_compressed_block_str = "128B"; + break; + case AMD_FMT_MOD_DCC_BLOCK_256B: + dcc_max_compressed_block_str = "256B"; + break; + } + + if (dcc_max_compressed_block_str) + fprintf(fp, ",DCC_MAX_COMPRESSED_BLOCK=%s", + dcc_max_compressed_block_str); + + if (AMD_FMT_MOD_GET(DCC_CONSTANT_ENCODE, modifier)) + fprintf(fp, ",DCC_CONSTANT_ENCODE"); +} + +static void +drmGetFormatModifierNameFromAmdTile(uint64_t modifier, FILE *fp) +{ + uint64_t pipe_xor_bits, bank_xor_bits, packers, rb; + uint64_t pipe, pipe_align, dcc, dcc_retile, tile_version; + + pipe_align = AMD_FMT_MOD_GET(DCC_PIPE_ALIGN, modifier); + pipe_xor_bits = AMD_FMT_MOD_GET(PIPE_XOR_BITS, modifier); + dcc = AMD_FMT_MOD_GET(DCC, modifier); + dcc_retile = AMD_FMT_MOD_GET(DCC_RETILE, modifier); + tile_version = AMD_FMT_MOD_GET(TILE_VERSION, modifier); + + fprintf(fp, ",PIPE_XOR_BITS=%"PRIu64, pipe_xor_bits); + + if (tile_version == AMD_FMT_MOD_TILE_VER_GFX9) { + bank_xor_bits = AMD_FMT_MOD_GET(BANK_XOR_BITS, modifier); + fprintf(fp, ",BANK_XOR_BITS=%"PRIu64, bank_xor_bits); + } + + if (tile_version == AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS) { + packers = AMD_FMT_MOD_GET(PACKERS, modifier); + fprintf(fp, ",PACKERS=%"PRIu64, packers); + } + + if (dcc && tile_version == AMD_FMT_MOD_TILE_VER_GFX9) { + rb = AMD_FMT_MOD_GET(RB, modifier); + fprintf(fp, ",RB=%"PRIu64, rb); + } + + if (dcc && tile_version == AMD_FMT_MOD_TILE_VER_GFX9 && + (dcc_retile || pipe_align)) { + pipe = AMD_FMT_MOD_GET(PIPE, modifier); + fprintf(fp, ",PIPE_%"PRIu64, pipe); + } +} + +static char * +drmGetFormatModifierNameFromAmd(uint64_t modifier) +{ + uint64_t tile, tile_version, dcc; + FILE *fp; + char *mod_amd = NULL; + size_t size = 0; + + const char *str_tile = NULL; + const char *str_tile_version = NULL; + + tile = AMD_FMT_MOD_GET(TILE, modifier); + tile_version = AMD_FMT_MOD_GET(TILE_VERSION, modifier); + dcc = AMD_FMT_MOD_GET(DCC, modifier); + + fp = open_memstream(&mod_amd, &size); + if (!fp) + return NULL; + + /* add tile */ + switch (tile_version) { + case AMD_FMT_MOD_TILE_VER_GFX9: + str_tile_version = "GFX9"; + break; + case AMD_FMT_MOD_TILE_VER_GFX10: + str_tile_version = "GFX10"; + break; + case AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS: + str_tile_version = "GFX10_RBPLUS"; + break; + } + + if (str_tile_version) { + fprintf(fp, "%s", str_tile_version); + } else { + fclose(fp); + free(mod_amd); + return NULL; + } + + /* add tile str */ + switch (tile) { + case AMD_FMT_MOD_TILE_GFX9_64K_S: + str_tile = "GFX9_64K_S"; + break; + case AMD_FMT_MOD_TILE_GFX9_64K_D: + str_tile = "GFX9_64K_D"; + break; + case AMD_FMT_MOD_TILE_GFX9_64K_S_X: + str_tile = "GFX9_64K_S_X"; + break; + case AMD_FMT_MOD_TILE_GFX9_64K_D_X: + str_tile = "GFX9_64K_D_X"; + break; + case AMD_FMT_MOD_TILE_GFX9_64K_R_X: + str_tile = "GFX9_64K_R_X"; + break; + } + + if (str_tile) + fprintf(fp, ",%s", str_tile); + + if (dcc) + drmGetFormatModifierNameFromAmdDcc(modifier, fp); + + if (tile_version >= AMD_FMT_MOD_TILE_VER_GFX9 && is_x_t_amd_gfx9_tile(tile)) + drmGetFormatModifierNameFromAmdTile(modifier, fp); + + fclose(fp); + return mod_amd; +} + +static char * +drmGetFormatModifierNameFromAmlogic(uint64_t modifier) +{ + uint64_t layout = modifier & 0xff; + uint64_t options = (modifier >> 8) & 0xff; + char *mod_amlogic = NULL; + + const char *layout_str; + const char *opts_str; + + switch (layout) { + case AMLOGIC_FBC_LAYOUT_BASIC: + layout_str = "BASIC"; + break; + case AMLOGIC_FBC_LAYOUT_SCATTER: + layout_str = "SCATTER"; + break; + default: + layout_str = "INVALID_LAYOUT"; + break; + } + + if (options & AMLOGIC_FBC_OPTION_MEM_SAVING) + opts_str = "MEM_SAVING"; + else + opts_str = "0"; + + asprintf(&mod_amlogic, "FBC,LAYOUT=%s,OPTIONS=%s", layout_str, opts_str); + return mod_amlogic; +} + +static unsigned log2_int(unsigned x) +{ + unsigned l; + + if (x < 2) { + return 0; + } + for (l = 2; ; l++) { + if ((unsigned)(1 << l) > x) { + return l - 1; + } + } + return 0; +} + + +drm_public void drmSetServerInfo(drmServerInfoPtr info) +{ + drm_server_info = info; +} + +/** + * Output a message to stderr. + * + * \param format printf() like format string. + * + * \internal + * This function is a wrapper around vfprintf(). + */ + +static int DRM_PRINTFLIKE(1, 0) +drmDebugPrint(const char *format, va_list ap) +{ + return vfprintf(stderr, format, ap); +} + +drm_public void +drmMsg(const char *format, ...) +{ + va_list ap; + const char *env; + if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) || + (drm_server_info && drm_server_info->debug_print)) + { + va_start(ap, format); + if (drm_server_info) { + drm_server_info->debug_print(format,ap); + } else { + drmDebugPrint(format, ap); + } + va_end(ap); + } +} + +static void *drmHashTable = NULL; /* Context switch callbacks */ + +drm_public void *drmGetHashTable(void) +{ + return drmHashTable; +} + +drm_public void *drmMalloc(int size) +{ + return calloc(1, size); +} + +drm_public void drmFree(void *pt) +{ + free(pt); +} + +/** + * Call ioctl, restarting if it is interrupted + */ +drm_public int +drmIoctl(int fd, unsigned long request, void *arg) +{ + int ret; + + do { + ret = ioctl(fd, request, arg); + } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); + return ret; +} + +static unsigned long drmGetKeyFromFd(int fd) +{ + stat_t st; + + st.st_rdev = 0; + fstat(fd, &st); + return st.st_rdev; +} + +drm_public drmHashEntry *drmGetEntry(int fd) +{ + unsigned long key = drmGetKeyFromFd(fd); + void *value; + drmHashEntry *entry; + + if (!drmHashTable) + drmHashTable = drmHashCreate(); + + if (drmHashLookup(drmHashTable, key, &value)) { + entry = drmMalloc(sizeof(*entry)); + entry->fd = fd; + entry->f = NULL; + entry->tagTable = drmHashCreate(); + drmHashInsert(drmHashTable, key, entry); + } else { + entry = value; + } + return entry; +} + +/** + * Compare two busid strings + * + * \param first + * \param second + * + * \return 1 if matched. + * + * \internal + * This function compares two bus ID strings. It understands the older + * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format. In the format, o is + * domain, b is bus, d is device, f is function. + */ +static int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok) +{ + /* First, check if the IDs are exactly the same */ + if (strcasecmp(id1, id2) == 0) + return 1; + + /* Try to match old/new-style PCI bus IDs. */ + if (strncasecmp(id1, "pci", 3) == 0) { + unsigned int o1, b1, d1, f1; + unsigned int o2, b2, d2, f2; + int ret; + + ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1); + if (ret != 4) { + o1 = 0; + ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1); + if (ret != 3) + return 0; + } + + ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2); + if (ret != 4) { + o2 = 0; + ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2); + if (ret != 3) + return 0; + } + + /* If domains aren't properly supported by the kernel interface, + * just ignore them, which sucks less than picking a totally random + * card with "open by name" + */ + if (!pci_domain_ok) + o1 = o2 = 0; + + if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2)) + return 0; + else + return 1; + } + return 0; +} + +/** + * Handles error checking for chown call. + * + * \param path to file. + * \param id of the new owner. + * \param id of the new group. + * + * \return zero if success or -1 if failure. + * + * \internal + * Checks for failure. If failure was caused by signal call chown again. + * If any other failure happened then it will output error message using + * drmMsg() call. + */ +#if !UDEV +static int chown_check_return(const char *path, uid_t owner, gid_t group) +{ + int rv; + + do { + rv = chown(path, owner, group); + } while (rv != 0 && errno == EINTR); + + if (rv == 0) + return 0; + + drmMsg("Failed to change owner or group for file %s! %d: %s\n", + path, errno, strerror(errno)); + return -1; +} +#endif + +static const char *drmGetDeviceName(int type) +{ + switch (type) { + case DRM_NODE_PRIMARY: + return DRM_DEV_NAME; + case DRM_NODE_CONTROL: + return DRM_CONTROL_DEV_NAME; + case DRM_NODE_RENDER: + return DRM_RENDER_DEV_NAME; + } + return NULL; +} + +/** + * Open the DRM device, creating it if necessary. + * + * \param dev major and minor numbers of the device. + * \param minor minor number of the device. + * + * \return a file descriptor on success, or a negative value on error. + * + * \internal + * Assembles the device name from \p minor and opens it, creating the device + * special file node with the major and minor numbers specified by \p dev and + * parent directory if necessary and was called by root. + */ +static int drmOpenDevice(dev_t dev, int minor, int type) +{ + stat_t st; + const char *dev_name = drmGetDeviceName(type); + char buf[DRM_NODE_NAME_MAX]; + int fd; + mode_t devmode = DRM_DEV_MODE, serv_mode; + gid_t serv_group; +#if !UDEV + int isroot = !geteuid(); + uid_t user = DRM_DEV_UID; + gid_t group = DRM_DEV_GID; +#endif + + if (!dev_name) + return -EINVAL; + + sprintf(buf, dev_name, DRM_DIR_NAME, minor); + drmMsg("drmOpenDevice: node name is %s\n", buf); + + if (drm_server_info && drm_server_info->get_perms) { + drm_server_info->get_perms(&serv_group, &serv_mode); + devmode = serv_mode ? serv_mode : DRM_DEV_MODE; + devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH); + } + +#if !UDEV + if (stat(DRM_DIR_NAME, &st)) { + if (!isroot) + return DRM_ERR_NOT_ROOT; + mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE); + chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */ + chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE); + } + + /* Check if the device node exists and create it if necessary. */ + if (stat(buf, &st)) { + if (!isroot) + return DRM_ERR_NOT_ROOT; + remove(buf); + mknod(buf, S_IFCHR | devmode, dev); + } + + if (drm_server_info && drm_server_info->get_perms) { + group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID; + chown_check_return(buf, user, group); + chmod(buf, devmode); + } +#else + /* if we modprobed then wait for udev */ + { + int udev_count = 0; +wait_for_udev: + if (stat(DRM_DIR_NAME, &st)) { + usleep(20); + udev_count++; + + if (udev_count == 50) + return -1; + goto wait_for_udev; + } + + if (stat(buf, &st)) { + usleep(20); + udev_count++; + + if (udev_count == 50) + return -1; + goto wait_for_udev; + } + } +#endif + + fd = open(buf, O_RDWR | O_CLOEXEC); + drmMsg("drmOpenDevice: open result is %d, (%s)\n", + fd, fd < 0 ? strerror(errno) : "OK"); + if (fd >= 0) + return fd; + +#if !UDEV + /* Check if the device node is not what we expect it to be, and recreate it + * and try again if so. + */ + if (st.st_rdev != dev) { + if (!isroot) + return DRM_ERR_NOT_ROOT; + remove(buf); + mknod(buf, S_IFCHR | devmode, dev); + if (drm_server_info && drm_server_info->get_perms) { + chown_check_return(buf, user, group); + chmod(buf, devmode); + } + } + fd = open(buf, O_RDWR | O_CLOEXEC); + drmMsg("drmOpenDevice: open result is %d, (%s)\n", + fd, fd < 0 ? strerror(errno) : "OK"); + if (fd >= 0) + return fd; + + drmMsg("drmOpenDevice: Open failed\n"); + remove(buf); +#endif + return -errno; +} + + +/** + * Open the DRM device + * + * \param minor device minor number. + * \param create allow to create the device if set. + * + * \return a file descriptor on success, or a negative value on error. + * + * \internal + * Calls drmOpenDevice() if \p create is set, otherwise assembles the device + * name from \p minor and opens it. + */ +static int drmOpenMinor(int minor, int create, int type) +{ + int fd; + char buf[DRM_NODE_NAME_MAX]; + const char *dev_name = drmGetDeviceName(type); + + if (create) + return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type); + + if (!dev_name) + return -EINVAL; + + sprintf(buf, dev_name, DRM_DIR_NAME, minor); + if ((fd = open(buf, O_RDWR | O_CLOEXEC)) >= 0) + return fd; + return -errno; +} + + +/** + * Determine whether the DRM kernel driver has been loaded. + * + * \return 1 if the DRM driver is loaded, 0 otherwise. + * + * \internal + * Determine the presence of the kernel driver by attempting to open the 0 + * minor and get version information. For backward compatibility with older + * Linux implementations, /proc/dri is also checked. + */ +drm_public int drmAvailable(void) +{ + drmVersionPtr version; + int retval = 0; + int fd; + + if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) { +#ifdef __linux__ + /* Try proc for backward Linux compatibility */ + if (!access("/proc/dri/0", R_OK)) + return 1; +#endif + return 0; + } + + if ((version = drmGetVersion(fd))) { + retval = 1; + drmFreeVersion(version); + } + close(fd); + + return retval; +} + +static int drmGetMinorBase(int type) +{ + switch (type) { + case DRM_NODE_PRIMARY: + return 0; + case DRM_NODE_CONTROL: + return 64; + case DRM_NODE_RENDER: + return 128; + default: + return -1; + }; +} + +static int drmGetMinorType(int major, int minor) +{ +#ifdef __FreeBSD__ + char name[SPECNAMELEN]; + int id; + + if (!devname_r(makedev(major, minor), S_IFCHR, name, sizeof(name))) + return -1; + + if (sscanf(name, "drm/%d", &id) != 1) { + // If not in /dev/drm/ we have the type in the name + if (sscanf(name, "dri/card%d\n", &id) >= 1) + return DRM_NODE_PRIMARY; + else if (sscanf(name, "dri/control%d\n", &id) >= 1) + return DRM_NODE_CONTROL; + else if (sscanf(name, "dri/renderD%d\n", &id) >= 1) + return DRM_NODE_RENDER; + return -1; + } + + minor = id; +#endif + int type = minor >> 6; + + if (minor < 0) + return -1; + + switch (type) { + case DRM_NODE_PRIMARY: + case DRM_NODE_CONTROL: + case DRM_NODE_RENDER: + return type; + default: + return -1; + } +} + +static const char *drmGetMinorName(int type) +{ + switch (type) { + case DRM_NODE_PRIMARY: + return DRM_PRIMARY_MINOR_NAME; + case DRM_NODE_CONTROL: + return DRM_CONTROL_MINOR_NAME; + case DRM_NODE_RENDER: + return DRM_RENDER_MINOR_NAME; + default: + return NULL; + } +} + +/** + * Open the device by bus ID. + * + * \param busid bus ID. + * \param type device node type. + * + * \return a file descriptor on success, or a negative value on error. + * + * \internal + * This function attempts to open every possible minor (up to DRM_MAX_MINOR), + * comparing the device bus ID with the one supplied. + * + * \sa drmOpenMinor() and drmGetBusid(). + */ +static int drmOpenByBusid(const char *busid, int type) +{ + int i, pci_domain_ok = 1; + int fd; + const char *buf; + drmSetVersion sv; + int base = drmGetMinorBase(type); + + if (base < 0) + return -1; + + drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid); + for (i = base; i < base + DRM_MAX_MINOR; i++) { + fd = drmOpenMinor(i, 1, type); + drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd); + if (fd >= 0) { + /* We need to try for 1.4 first for proper PCI domain support + * and if that fails, we know the kernel is busted + */ + sv.drm_di_major = 1; + sv.drm_di_minor = 4; + sv.drm_dd_major = -1; /* Don't care */ + sv.drm_dd_minor = -1; /* Don't care */ + if (drmSetInterfaceVersion(fd, &sv)) { +#ifndef __alpha__ + pci_domain_ok = 0; +#endif + sv.drm_di_major = 1; + sv.drm_di_minor = 1; + sv.drm_dd_major = -1; /* Don't care */ + sv.drm_dd_minor = -1; /* Don't care */ + drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n"); + drmSetInterfaceVersion(fd, &sv); + } + buf = drmGetBusid(fd); + drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf); + if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) { + drmFreeBusid(buf); + return fd; + } + if (buf) + drmFreeBusid(buf); + close(fd); + } + } + return -1; +} + + +/** + * Open the device by name. + * + * \param name driver name. + * \param type the device node type. + * + * \return a file descriptor on success, or a negative value on error. + * + * \internal + * This function opens the first minor number that matches the driver name and + * isn't already in use. If it's in use it then it will already have a bus ID + * assigned. + * + * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid(). + */ +static int drmOpenByName(const char *name, int type) +{ + int i; + int fd; + drmVersionPtr version; + char * id; + int base = drmGetMinorBase(type); + + if (base < 0) + return -1; + + /* + * Open the first minor number that matches the driver name and isn't + * already in use. If it's in use it will have a busid assigned already. + */ + for (i = base; i < base + DRM_MAX_MINOR; i++) { + if ((fd = drmOpenMinor(i, 1, type)) >= 0) { + if ((version = drmGetVersion(fd))) { + if (!strcmp(version->name, name)) { + drmFreeVersion(version); + id = drmGetBusid(fd); + drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL"); + if (!id || !*id) { + if (id) + drmFreeBusid(id); + return fd; + } else { + drmFreeBusid(id); + } + } else { + drmFreeVersion(version); + } + } + close(fd); + } + } + +#ifdef __linux__ + /* Backward-compatibility /proc support */ + for (i = 0; i < 8; i++) { + char proc_name[64], buf[512]; + char *driver, *pt, *devstring; + int retcode; + + sprintf(proc_name, "/proc/dri/%d/name", i); + if ((fd = open(proc_name, O_RDONLY)) >= 0) { + retcode = read(fd, buf, sizeof(buf)-1); + close(fd); + if (retcode) { + buf[retcode-1] = '\0'; + for (driver = pt = buf; *pt && *pt != ' '; ++pt) + ; + if (*pt) { /* Device is next */ + *pt = '\0'; + if (!strcmp(driver, name)) { /* Match */ + for (devstring = ++pt; *pt && *pt != ' '; ++pt) + ; + if (*pt) { /* Found busid */ + return drmOpenByBusid(++pt, type); + } else { /* No busid */ + return drmOpenDevice(strtol(devstring, NULL, 0),i, type); + } + } + } + } + } + } +#endif + + return -1; +} + + +/** + * Open the DRM device. + * + * Looks up the specified name and bus ID, and opens the device found. The + * entry in /dev/dri is created if necessary and if called by root. + * + * \param name driver name. Not referenced if bus ID is supplied. + * \param busid bus ID. Zero if not known. + * + * \return a file descriptor on success, or a negative value on error. + * + * \internal + * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() + * otherwise. + */ +drm_public int drmOpen(const char *name, const char *busid) +{ + return drmOpenWithType(name, busid, DRM_NODE_PRIMARY); +} + +/** + * Open the DRM device with specified type. + * + * Looks up the specified name and bus ID, and opens the device found. The + * entry in /dev/dri is created if necessary and if called by root. + * + * \param name driver name. Not referenced if bus ID is supplied. + * \param busid bus ID. Zero if not known. + * \param type the device node type to open, PRIMARY, CONTROL or RENDER + * + * \return a file descriptor on success, or a negative value on error. + * + * \internal + * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName() + * otherwise. + */ +drm_public int drmOpenWithType(const char *name, const char *busid, int type) +{ + if (name != NULL && drm_server_info && + drm_server_info->load_module && !drmAvailable()) { + /* try to load the kernel module */ + if (!drm_server_info->load_module(name)) { + drmMsg("[drm] failed to load kernel module \"%s\"\n", name); + return -1; + } + } + + if (busid) { + int fd = drmOpenByBusid(busid, type); + if (fd >= 0) + return fd; + } + + if (name) + return drmOpenByName(name, type); + + return -1; +} + +drm_public int drmOpenControl(int minor) +{ + return drmOpenMinor(minor, 0, DRM_NODE_CONTROL); +} + +drm_public int drmOpenRender(int minor) +{ + return drmOpenMinor(minor, 0, DRM_NODE_RENDER); +} + +/** + * Free the version information returned by drmGetVersion(). + * + * \param v pointer to the version information. + * + * \internal + * It frees the memory pointed by \p %v as well as all the non-null strings + * pointers in it. + */ +drm_public void drmFreeVersion(drmVersionPtr v) +{ + if (!v) + return; + drmFree(v->name); + drmFree(v->date); + drmFree(v->desc); + drmFree(v); +} + + +/** + * Free the non-public version information returned by the kernel. + * + * \param v pointer to the version information. + * + * \internal + * Used by drmGetVersion() to free the memory pointed by \p %v as well as all + * the non-null strings pointers in it. + */ +static void drmFreeKernelVersion(drm_version_t *v) +{ + if (!v) + return; + drmFree(v->name); + drmFree(v->date); + drmFree(v->desc); + drmFree(v); +} + + +/** + * Copy version information. + * + * \param d destination pointer. + * \param s source pointer. + * + * \internal + * Used by drmGetVersion() to translate the information returned by the ioctl + * interface in a private structure into the public structure counterpart. + */ +static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s) +{ + d->version_major = s->version_major; + d->version_minor = s->version_minor; + d->version_patchlevel = s->version_patchlevel; + d->name_len = s->name_len; + d->name = strdup(s->name); + d->date_len = s->date_len; + d->date = strdup(s->date); + d->desc_len = s->desc_len; + d->desc = strdup(s->desc); +} + + +/** + * Query the driver version information. + * + * \param fd file descriptor. + * + * \return pointer to a drmVersion structure which should be freed with + * drmFreeVersion(). + * + * \note Similar information is available via /proc/dri. + * + * \internal + * It gets the version information via successive DRM_IOCTL_VERSION ioctls, + * first with zeros to get the string lengths, and then the actually strings. + * It also null-terminates them since they might not be already. + */ +drm_public drmVersionPtr drmGetVersion(int fd) +{ + drmVersionPtr retval; + drm_version_t *version = drmMalloc(sizeof(*version)); + + if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) { + drmFreeKernelVersion(version); + return NULL; + } + + if (version->name_len) + version->name = drmMalloc(version->name_len + 1); + if (version->date_len) + version->date = drmMalloc(version->date_len + 1); + if (version->desc_len) + version->desc = drmMalloc(version->desc_len + 1); + + if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) { + drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno)); + drmFreeKernelVersion(version); + return NULL; + } + + /* The results might not be null-terminated strings, so terminate them. */ + if (version->name_len) version->name[version->name_len] = '\0'; + if (version->date_len) version->date[version->date_len] = '\0'; + if (version->desc_len) version->desc[version->desc_len] = '\0'; + + retval = drmMalloc(sizeof(*retval)); + drmCopyVersion(retval, version); + drmFreeKernelVersion(version); + return retval; +} + + +/** + * Get version information for the DRM user space library. + * + * This version number is driver independent. + * + * \param fd file descriptor. + * + * \return version information. + * + * \internal + * This function allocates and fills a drm_version structure with a hard coded + * version number. + */ +drm_public drmVersionPtr drmGetLibVersion(int fd) +{ + drm_version_t *version = drmMalloc(sizeof(*version)); + + /* Version history: + * NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it + * revision 1.0.x = original DRM interface with no drmGetLibVersion + * entry point and many drm extensions + * revision 1.1.x = added drmCommand entry points for device extensions + * added drmGetLibVersion to identify libdrm.a version + * revision 1.2.x = added drmSetInterfaceVersion + * modified drmOpen to handle both busid and name + * revision 1.3.x = added server + memory manager + */ + version->version_major = 1; + version->version_minor = 3; + version->version_patchlevel = 0; + + return (drmVersionPtr)version; +} + +drm_public int drmGetCap(int fd, uint64_t capability, uint64_t *value) +{ + struct drm_get_cap cap; + int ret; + + memclear(cap); + cap.capability = capability; + + ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap); + if (ret) + return ret; + + *value = cap.value; + return 0; +} + +drm_public int drmSetClientCap(int fd, uint64_t capability, uint64_t value) +{ + struct drm_set_client_cap cap; + + memclear(cap); + cap.capability = capability; + cap.value = value; + + return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap); +} + +/** + * Free the bus ID information. + * + * \param busid bus ID information string as given by drmGetBusid(). + * + * \internal + * This function is just frees the memory pointed by \p busid. + */ +drm_public void drmFreeBusid(const char *busid) +{ + drmFree((void *)busid); +} + + +/** + * Get the bus ID of the device. + * + * \param fd file descriptor. + * + * \return bus ID string. + * + * \internal + * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to + * get the string length and data, passing the arguments in a drm_unique + * structure. + */ +drm_public char *drmGetBusid(int fd) +{ + drm_unique_t u; + + memclear(u); + + if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) + return NULL; + u.unique = drmMalloc(u.unique_len + 1); + if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) { + drmFree(u.unique); + return NULL; + } + u.unique[u.unique_len] = '\0'; + + return u.unique; +} + + +/** + * Set the bus ID of the device. + * + * \param fd file descriptor. + * \param busid bus ID string. + * + * \return zero on success, negative on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing + * the arguments in a drm_unique structure. + */ +drm_public int drmSetBusid(int fd, const char *busid) +{ + drm_unique_t u; + + memclear(u); + u.unique = (char *)busid; + u.unique_len = strlen(busid); + + if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) { + return -errno; + } + return 0; +} + +drm_public int drmGetMagic(int fd, drm_magic_t * magic) +{ + drm_auth_t auth; + + memclear(auth); + + *magic = 0; + if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth)) + return -errno; + *magic = auth.magic; + return 0; +} + +drm_public int drmAuthMagic(int fd, drm_magic_t magic) +{ + drm_auth_t auth; + + memclear(auth); + auth.magic = magic; + if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth)) + return -errno; + return 0; +} + +/** + * Specifies a range of memory that is available for mapping by a + * non-root process. + * + * \param fd file descriptor. + * \param offset usually the physical address. The actual meaning depends of + * the \p type parameter. See below. + * \param size of the memory in bytes. + * \param type type of the memory to be mapped. + * \param flags combination of several flags to modify the function actions. + * \param handle will be set to a value that may be used as the offset + * parameter for mmap(). + * + * \return zero on success or a negative value on error. + * + * \par Mapping the frame buffer + * For the frame buffer + * - \p offset will be the physical address of the start of the frame buffer, + * - \p size will be the size of the frame buffer in bytes, and + * - \p type will be DRM_FRAME_BUFFER. + * + * \par + * The area mapped will be uncached. If MTRR support is available in the + * kernel, the frame buffer area will be set to write combining. + * + * \par Mapping the MMIO register area + * For the MMIO register area, + * - \p offset will be the physical address of the start of the register area, + * - \p size will be the size of the register area bytes, and + * - \p type will be DRM_REGISTERS. + * \par + * The area mapped will be uncached. + * + * \par Mapping the SAREA + * For the SAREA, + * - \p offset will be ignored and should be set to zero, + * - \p size will be the desired size of the SAREA in bytes, + * - \p type will be DRM_SHM. + * + * \par + * A shared memory area of the requested size will be created and locked in + * kernel memory. This area may be mapped into client-space by using the handle + * returned. + * + * \note May only be called by root. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing + * the arguments in a drm_map structure. + */ +drm_public int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type, + drmMapFlags flags, drm_handle_t *handle) +{ + drm_map_t map; + + memclear(map); + map.offset = offset; + map.size = size; + map.type = (enum drm_map_type)type; + map.flags = (enum drm_map_flags)flags; + if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map)) + return -errno; + if (handle) + *handle = (drm_handle_t)(uintptr_t)map.handle; + return 0; +} + +drm_public int drmRmMap(int fd, drm_handle_t handle) +{ + drm_map_t map; + + memclear(map); + map.handle = (void *)(uintptr_t)handle; + + if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map)) + return -errno; + return 0; +} + +/** + * Make buffers available for DMA transfers. + * + * \param fd file descriptor. + * \param count number of buffers. + * \param size size of each buffer. + * \param flags buffer allocation flags. + * \param agp_offset offset in the AGP aperture + * + * \return number of buffers allocated, negative on error. + * + * \internal + * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl. + * + * \sa drm_buf_desc. + */ +drm_public int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags, + int agp_offset) +{ + drm_buf_desc_t request; + + memclear(request); + request.count = count; + request.size = size; + request.flags = (int)flags; + request.agp_start = agp_offset; + + if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request)) + return -errno; + return request.count; +} + +drm_public int drmMarkBufs(int fd, double low, double high) +{ + drm_buf_info_t info; + int i; + + memclear(info); + + if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) + return -EINVAL; + + if (!info.count) + return -EINVAL; + + if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) + return -ENOMEM; + + if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { + int retval = -errno; + drmFree(info.list); + return retval; + } + + for (i = 0; i < info.count; i++) { + info.list[i].low_mark = low * info.list[i].count; + info.list[i].high_mark = high * info.list[i].count; + if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) { + int retval = -errno; + drmFree(info.list); + return retval; + } + } + drmFree(info.list); + + return 0; +} + +/** + * Free buffers. + * + * \param fd file descriptor. + * \param count number of buffers to free. + * \param list list of buffers to be freed. + * + * \return zero on success, or a negative value on failure. + * + * \note This function is primarily used for debugging. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing + * the arguments in a drm_buf_free structure. + */ +drm_public int drmFreeBufs(int fd, int count, int *list) +{ + drm_buf_free_t request; + + memclear(request); + request.count = count; + request.list = list; + if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request)) + return -errno; + return 0; +} + + +/** + * Close the device. + * + * \param fd file descriptor. + * + * \internal + * This function closes the file descriptor. + */ +drm_public int drmClose(int fd) +{ + unsigned long key = drmGetKeyFromFd(fd); + drmHashEntry *entry = drmGetEntry(fd); + + drmHashDestroy(entry->tagTable); + entry->fd = 0; + entry->f = NULL; + entry->tagTable = NULL; + + drmHashDelete(drmHashTable, key); + drmFree(entry); + + return close(fd); +} + + +/** + * Map a region of memory. + * + * \param fd file descriptor. + * \param handle handle returned by drmAddMap(). + * \param size size in bytes. Must match the size used by drmAddMap(). + * \param address will contain the user-space virtual address where the mapping + * begins. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper for mmap(). + */ +drm_public int drmMap(int fd, drm_handle_t handle, drmSize size, + drmAddressPtr address) +{ + static unsigned long pagesize_mask = 0; + + if (fd < 0) + return -EINVAL; + + if (!pagesize_mask) + pagesize_mask = getpagesize() - 1; + + size = (size + pagesize_mask) & ~pagesize_mask; + + *address = drm_mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle); + if (*address == MAP_FAILED) + return -errno; + return 0; +} + + +/** + * Unmap mappings obtained with drmMap(). + * + * \param address address as given by drmMap(). + * \param size size in bytes. Must match the size used by drmMap(). + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper for munmap(). + */ +drm_public int drmUnmap(drmAddress address, drmSize size) +{ + return drm_munmap(address, size); +} + +drm_public drmBufInfoPtr drmGetBufInfo(int fd) +{ + drm_buf_info_t info; + drmBufInfoPtr retval; + int i; + + memclear(info); + + if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) + return NULL; + + if (info.count) { + if (!(info.list = drmMalloc(info.count * sizeof(*info.list)))) + return NULL; + + if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) { + drmFree(info.list); + return NULL; + } + + retval = drmMalloc(sizeof(*retval)); + retval->count = info.count; + if (!(retval->list = drmMalloc(info.count * sizeof(*retval->list)))) { + drmFree(retval); + drmFree(info.list); + return NULL; + } + + for (i = 0; i < info.count; i++) { + retval->list[i].count = info.list[i].count; + retval->list[i].size = info.list[i].size; + retval->list[i].low_mark = info.list[i].low_mark; + retval->list[i].high_mark = info.list[i].high_mark; + } + drmFree(info.list); + return retval; + } + return NULL; +} + +/** + * Map all DMA buffers into client-virtual space. + * + * \param fd file descriptor. + * + * \return a pointer to a ::drmBufMap structure. + * + * \note The client may not use these buffers until obtaining buffer indices + * with drmDMA(). + * + * \internal + * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned + * information about the buffers in a drm_buf_map structure into the + * client-visible data structures. + */ +drm_public drmBufMapPtr drmMapBufs(int fd) +{ + drm_buf_map_t bufs; + drmBufMapPtr retval; + int i; + + memclear(bufs); + if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) + return NULL; + + if (!bufs.count) + return NULL; + + if (!(bufs.list = drmMalloc(bufs.count * sizeof(*bufs.list)))) + return NULL; + + if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) { + drmFree(bufs.list); + return NULL; + } + + retval = drmMalloc(sizeof(*retval)); + retval->count = bufs.count; + retval->list = drmMalloc(bufs.count * sizeof(*retval->list)); + for (i = 0; i < bufs.count; i++) { + retval->list[i].idx = bufs.list[i].idx; + retval->list[i].total = bufs.list[i].total; + retval->list[i].used = 0; + retval->list[i].address = bufs.list[i].address; + } + + drmFree(bufs.list); + return retval; +} + + +/** + * Unmap buffers allocated with drmMapBufs(). + * + * \return zero on success, or negative value on failure. + * + * \internal + * Calls munmap() for every buffer stored in \p bufs and frees the + * memory allocated by drmMapBufs(). + */ +drm_public int drmUnmapBufs(drmBufMapPtr bufs) +{ + int i; + + for (i = 0; i < bufs->count; i++) { + drm_munmap(bufs->list[i].address, bufs->list[i].total); + } + + drmFree(bufs->list); + drmFree(bufs); + return 0; +} + + +#define DRM_DMA_RETRY 16 + +/** + * Reserve DMA buffers. + * + * \param fd file descriptor. + * \param request + * + * \return zero on success, or a negative value on failure. + * + * \internal + * Assemble the arguments into a drm_dma structure and keeps issuing the + * DRM_IOCTL_DMA ioctl until success or until maximum number of retries. + */ +drm_public int drmDMA(int fd, drmDMAReqPtr request) +{ + drm_dma_t dma; + int ret, i = 0; + + dma.context = request->context; + dma.send_count = request->send_count; + dma.send_indices = request->send_list; + dma.send_sizes = request->send_sizes; + dma.flags = (enum drm_dma_flags)request->flags; + dma.request_count = request->request_count; + dma.request_size = request->request_size; + dma.request_indices = request->request_list; + dma.request_sizes = request->request_sizes; + dma.granted_count = 0; + + do { + ret = ioctl( fd, DRM_IOCTL_DMA, &dma ); + } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY ); + + if ( ret == 0 ) { + request->granted_count = dma.granted_count; + return 0; + } else { + return -errno; + } +} + + +/** + * Obtain heavyweight hardware lock. + * + * \param fd file descriptor. + * \param context context. + * \param flags flags that determine the state of the hardware when the function + * returns. + * + * \return always zero. + * + * \internal + * This function translates the arguments into a drm_lock structure and issue + * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired. + */ +drm_public int drmGetLock(int fd, drm_context_t context, drmLockFlags flags) +{ + drm_lock_t lock; + + memclear(lock); + lock.context = context; + lock.flags = 0; + if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY; + if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT; + if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH; + if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; + if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; + if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; + + while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock)) + ; + return 0; +} + +/** + * Release the hardware lock. + * + * \param fd file descriptor. + * \param context context. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the + * argument in a drm_lock structure. + */ +drm_public int drmUnlock(int fd, drm_context_t context) +{ + drm_lock_t lock; + + memclear(lock); + lock.context = context; + return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock); +} + +drm_public drm_context_t *drmGetReservedContextList(int fd, int *count) +{ + drm_ctx_res_t res; + drm_ctx_t *list; + drm_context_t * retval; + int i; + + memclear(res); + if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res)) + return NULL; + + if (!res.count) + return NULL; + + if (!(list = drmMalloc(res.count * sizeof(*list)))) + return NULL; + if (!(retval = drmMalloc(res.count * sizeof(*retval)))) + goto err_free_list; + + res.contexts = list; + if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res)) + goto err_free_context; + + for (i = 0; i < res.count; i++) + retval[i] = list[i].handle; + drmFree(list); + + *count = res.count; + return retval; + +err_free_list: + drmFree(list); +err_free_context: + drmFree(retval); + return NULL; +} + +drm_public void drmFreeReservedContextList(drm_context_t *pt) +{ + drmFree(pt); +} + +/** + * Create context. + * + * Used by the X server during GLXContext initialization. This causes + * per-context kernel-level resources to be allocated. + * + * \param fd file descriptor. + * \param handle is set on success. To be used by the client when requesting DMA + * dispatch with drmDMA(). + * + * \return zero on success, or a negative value on failure. + * + * \note May only be called by root. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the + * argument in a drm_ctx structure. + */ +drm_public int drmCreateContext(int fd, drm_context_t *handle) +{ + drm_ctx_t ctx; + + memclear(ctx); + if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx)) + return -errno; + *handle = ctx.handle; + return 0; +} + +drm_public int drmSwitchToContext(int fd, drm_context_t context) +{ + drm_ctx_t ctx; + + memclear(ctx); + ctx.handle = context; + if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx)) + return -errno; + return 0; +} + +drm_public int drmSetContextFlags(int fd, drm_context_t context, + drm_context_tFlags flags) +{ + drm_ctx_t ctx; + + /* + * Context preserving means that no context switches are done between DMA + * buffers from one context and the next. This is suitable for use in the + * X server (which promises to maintain hardware context), or in the + * client-side library when buffers are swapped on behalf of two threads. + */ + memclear(ctx); + ctx.handle = context; + if (flags & DRM_CONTEXT_PRESERVED) + ctx.flags |= _DRM_CONTEXT_PRESERVED; + if (flags & DRM_CONTEXT_2DONLY) + ctx.flags |= _DRM_CONTEXT_2DONLY; + if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx)) + return -errno; + return 0; +} + +drm_public int drmGetContextFlags(int fd, drm_context_t context, + drm_context_tFlagsPtr flags) +{ + drm_ctx_t ctx; + + memclear(ctx); + ctx.handle = context; + if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx)) + return -errno; + *flags = 0; + if (ctx.flags & _DRM_CONTEXT_PRESERVED) + *flags |= DRM_CONTEXT_PRESERVED; + if (ctx.flags & _DRM_CONTEXT_2DONLY) + *flags |= DRM_CONTEXT_2DONLY; + return 0; +} + +/** + * Destroy context. + * + * Free any kernel-level resources allocated with drmCreateContext() associated + * with the context. + * + * \param fd file descriptor. + * \param handle handle given by drmCreateContext(). + * + * \return zero on success, or a negative value on failure. + * + * \note May only be called by root. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the + * argument in a drm_ctx structure. + */ +drm_public int drmDestroyContext(int fd, drm_context_t handle) +{ + drm_ctx_t ctx; + + memclear(ctx); + ctx.handle = handle; + if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx)) + return -errno; + return 0; +} + +drm_public int drmCreateDrawable(int fd, drm_drawable_t *handle) +{ + drm_draw_t draw; + + memclear(draw); + if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw)) + return -errno; + *handle = draw.handle; + return 0; +} + +drm_public int drmDestroyDrawable(int fd, drm_drawable_t handle) +{ + drm_draw_t draw; + + memclear(draw); + draw.handle = handle; + if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw)) + return -errno; + return 0; +} + +drm_public int drmUpdateDrawableInfo(int fd, drm_drawable_t handle, + drm_drawable_info_type_t type, + unsigned int num, void *data) +{ + drm_update_draw_t update; + + memclear(update); + update.handle = handle; + update.type = type; + update.num = num; + update.data = (unsigned long long)(unsigned long)data; + + if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update)) + return -errno; + + return 0; +} + +drm_public int drmCrtcGetSequence(int fd, uint32_t crtcId, uint64_t *sequence, + uint64_t *ns) +{ + struct drm_crtc_get_sequence get_seq; + int ret; + + memclear(get_seq); + get_seq.crtc_id = crtcId; + ret = drmIoctl(fd, DRM_IOCTL_CRTC_GET_SEQUENCE, &get_seq); + if (ret) + return ret; + + if (sequence) + *sequence = get_seq.sequence; + if (ns) + *ns = get_seq.sequence_ns; + return 0; +} + +drm_public int drmCrtcQueueSequence(int fd, uint32_t crtcId, uint32_t flags, + uint64_t sequence, + uint64_t *sequence_queued, + uint64_t user_data) +{ + struct drm_crtc_queue_sequence queue_seq; + int ret; + + memclear(queue_seq); + queue_seq.crtc_id = crtcId; + queue_seq.flags = flags; + queue_seq.sequence = sequence; + queue_seq.user_data = user_data; + + ret = drmIoctl(fd, DRM_IOCTL_CRTC_QUEUE_SEQUENCE, &queue_seq); + if (ret == 0 && sequence_queued) + *sequence_queued = queue_seq.sequence; + + return ret; +} + +/** + * Acquire the AGP device. + * + * Must be called before any of the other AGP related calls. + * + * \param fd file descriptor. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl. + */ +drm_public int drmAgpAcquire(int fd) +{ + if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL)) + return -errno; + return 0; +} + + +/** + * Release the AGP device. + * + * \param fd file descriptor. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl. + */ +drm_public int drmAgpRelease(int fd) +{ + if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL)) + return -errno; + return 0; +} + + +/** + * Set the AGP mode. + * + * \param fd file descriptor. + * \param mode AGP mode. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the + * argument in a drm_agp_mode structure. + */ +drm_public int drmAgpEnable(int fd, unsigned long mode) +{ + drm_agp_mode_t m; + + memclear(m); + m.mode = mode; + if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m)) + return -errno; + return 0; +} + + +/** + * Allocate a chunk of AGP memory. + * + * \param fd file descriptor. + * \param size requested memory size in bytes. Will be rounded to page boundary. + * \param type type of memory to allocate. + * \param address if not zero, will be set to the physical address of the + * allocated memory. + * \param handle on success will be set to a handle of the allocated memory. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the + * arguments in a drm_agp_buffer structure. + */ +drm_public int drmAgpAlloc(int fd, unsigned long size, unsigned long type, + unsigned long *address, drm_handle_t *handle) +{ + drm_agp_buffer_t b; + + memclear(b); + *handle = DRM_AGP_NO_HANDLE; + b.size = size; + b.type = type; + if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b)) + return -errno; + if (address != 0UL) + *address = b.physical; + *handle = b.handle; + return 0; +} + + +/** + * Free a chunk of AGP memory. + * + * \param fd file descriptor. + * \param handle handle to the allocated memory, as given by drmAgpAllocate(). + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the + * argument in a drm_agp_buffer structure. + */ +drm_public int drmAgpFree(int fd, drm_handle_t handle) +{ + drm_agp_buffer_t b; + + memclear(b); + b.handle = handle; + if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b)) + return -errno; + return 0; +} + + +/** + * Bind a chunk of AGP memory. + * + * \param fd file descriptor. + * \param handle handle to the allocated memory, as given by drmAgpAllocate(). + * \param offset offset in bytes. It will round to page boundary. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the + * argument in a drm_agp_binding structure. + */ +drm_public int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset) +{ + drm_agp_binding_t b; + + memclear(b); + b.handle = handle; + b.offset = offset; + if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b)) + return -errno; + return 0; +} + + +/** + * Unbind a chunk of AGP memory. + * + * \param fd file descriptor. + * \param handle handle to the allocated memory, as given by drmAgpAllocate(). + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing + * the argument in a drm_agp_binding structure. + */ +drm_public int drmAgpUnbind(int fd, drm_handle_t handle) +{ + drm_agp_binding_t b; + + memclear(b); + b.handle = handle; + if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b)) + return -errno; + return 0; +} + + +/** + * Get AGP driver major version number. + * + * \param fd file descriptor. + * + * \return major version number on success, or a negative value on failure.. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +drm_public int drmAgpVersionMajor(int fd) +{ + drm_agp_info_t i; + + memclear(i); + + if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) + return -errno; + return i.agp_version_major; +} + + +/** + * Get AGP driver minor version number. + * + * \param fd file descriptor. + * + * \return minor version number on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +drm_public int drmAgpVersionMinor(int fd) +{ + drm_agp_info_t i; + + memclear(i); + + if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) + return -errno; + return i.agp_version_minor; +} + + +/** + * Get AGP mode. + * + * \param fd file descriptor. + * + * \return mode on success, or zero on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +drm_public unsigned long drmAgpGetMode(int fd) +{ + drm_agp_info_t i; + + memclear(i); + + if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) + return 0; + return i.mode; +} + + +/** + * Get AGP aperture base. + * + * \param fd file descriptor. + * + * \return aperture base on success, zero on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +drm_public unsigned long drmAgpBase(int fd) +{ + drm_agp_info_t i; + + memclear(i); + + if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) + return 0; + return i.aperture_base; +} + + +/** + * Get AGP aperture size. + * + * \param fd file descriptor. + * + * \return aperture size on success, zero on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +drm_public unsigned long drmAgpSize(int fd) +{ + drm_agp_info_t i; + + memclear(i); + + if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) + return 0; + return i.aperture_size; +} + + +/** + * Get used AGP memory. + * + * \param fd file descriptor. + * + * \return memory used on success, or zero on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +drm_public unsigned long drmAgpMemoryUsed(int fd) +{ + drm_agp_info_t i; + + memclear(i); + + if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) + return 0; + return i.memory_used; +} + + +/** + * Get available AGP memory. + * + * \param fd file descriptor. + * + * \return memory available on success, or zero on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +drm_public unsigned long drmAgpMemoryAvail(int fd) +{ + drm_agp_info_t i; + + memclear(i); + + if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) + return 0; + return i.memory_allowed; +} + + +/** + * Get hardware vendor ID. + * + * \param fd file descriptor. + * + * \return vendor ID on success, or zero on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +drm_public unsigned int drmAgpVendorId(int fd) +{ + drm_agp_info_t i; + + memclear(i); + + if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) + return 0; + return i.id_vendor; +} + + +/** + * Get hardware device ID. + * + * \param fd file descriptor. + * + * \return zero on success, or zero on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the + * necessary information in a drm_agp_info structure. + */ +drm_public unsigned int drmAgpDeviceId(int fd) +{ + drm_agp_info_t i; + + memclear(i); + + if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i)) + return 0; + return i.id_device; +} + +drm_public int drmScatterGatherAlloc(int fd, unsigned long size, + drm_handle_t *handle) +{ + drm_scatter_gather_t sg; + + memclear(sg); + + *handle = 0; + sg.size = size; + if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg)) + return -errno; + *handle = sg.handle; + return 0; +} + +drm_public int drmScatterGatherFree(int fd, drm_handle_t handle) +{ + drm_scatter_gather_t sg; + + memclear(sg); + sg.handle = handle; + if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg)) + return -errno; + return 0; +} + +/** + * Wait for VBLANK. + * + * \param fd file descriptor. + * \param vbl pointer to a drmVBlank structure. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl. + */ +drm_public int drmWaitVBlank(int fd, drmVBlankPtr vbl) +{ + struct timespec timeout, cur; + int ret; + + ret = clock_gettime(CLOCK_MONOTONIC, &timeout); + if (ret < 0) { + fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno)); + goto out; + } + timeout.tv_sec++; + + do { + ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl); + vbl->request.type &= ~DRM_VBLANK_RELATIVE; + if (ret && errno == EINTR) { + clock_gettime(CLOCK_MONOTONIC, &cur); + /* Timeout after 1s */ + if (cur.tv_sec > timeout.tv_sec + 1 || + (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >= + timeout.tv_nsec)) { + errno = EBUSY; + ret = -1; + break; + } + } + } while (ret && errno == EINTR); + +out: + return ret; +} + +drm_public int drmError(int err, const char *label) +{ + switch (err) { + case DRM_ERR_NO_DEVICE: + fprintf(stderr, "%s: no device\n", label); + break; + case DRM_ERR_NO_ACCESS: + fprintf(stderr, "%s: no access\n", label); + break; + case DRM_ERR_NOT_ROOT: + fprintf(stderr, "%s: not root\n", label); + break; + case DRM_ERR_INVALID: + fprintf(stderr, "%s: invalid args\n", label); + break; + default: + if (err < 0) + err = -err; + fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) ); + break; + } + + return 1; +} + +/** + * Install IRQ handler. + * + * \param fd file descriptor. + * \param irq IRQ number. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the + * argument in a drm_control structure. + */ +drm_public int drmCtlInstHandler(int fd, int irq) +{ + drm_control_t ctl; + + memclear(ctl); + ctl.func = DRM_INST_HANDLER; + ctl.irq = irq; + if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl)) + return -errno; + return 0; +} + + +/** + * Uninstall IRQ handler. + * + * \param fd file descriptor. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the + * argument in a drm_control structure. + */ +drm_public int drmCtlUninstHandler(int fd) +{ + drm_control_t ctl; + + memclear(ctl); + ctl.func = DRM_UNINST_HANDLER; + ctl.irq = 0; + if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl)) + return -errno; + return 0; +} + +drm_public int drmFinish(int fd, int context, drmLockFlags flags) +{ + drm_lock_t lock; + + memclear(lock); + lock.context = context; + if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY; + if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT; + if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH; + if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL; + if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES; + if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES; + if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock)) + return -errno; + return 0; +} + +/** + * Get IRQ from bus ID. + * + * \param fd file descriptor. + * \param busnum bus number. + * \param devnum device number. + * \param funcnum function number. + * + * \return IRQ number on success, or a negative value on failure. + * + * \internal + * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the + * arguments in a drm_irq_busid structure. + */ +drm_public int drmGetInterruptFromBusID(int fd, int busnum, int devnum, + int funcnum) +{ + drm_irq_busid_t p; + + memclear(p); + p.busnum = busnum; + p.devnum = devnum; + p.funcnum = funcnum; + if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p)) + return -errno; + return p.irq; +} + +drm_public int drmAddContextTag(int fd, drm_context_t context, void *tag) +{ + drmHashEntry *entry = drmGetEntry(fd); + + if (drmHashInsert(entry->tagTable, context, tag)) { + drmHashDelete(entry->tagTable, context); + drmHashInsert(entry->tagTable, context, tag); + } + return 0; +} + +drm_public int drmDelContextTag(int fd, drm_context_t context) +{ + drmHashEntry *entry = drmGetEntry(fd); + + return drmHashDelete(entry->tagTable, context); +} + +drm_public void *drmGetContextTag(int fd, drm_context_t context) +{ + drmHashEntry *entry = drmGetEntry(fd); + void *value; + + if (drmHashLookup(entry->tagTable, context, &value)) + return NULL; + + return value; +} + +drm_public int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id, + drm_handle_t handle) +{ + drm_ctx_priv_map_t map; + + memclear(map); + map.ctx_id = ctx_id; + map.handle = (void *)(uintptr_t)handle; + + if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map)) + return -errno; + return 0; +} + +drm_public int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id, + drm_handle_t *handle) +{ + drm_ctx_priv_map_t map; + + memclear(map); + map.ctx_id = ctx_id; + + if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map)) + return -errno; + if (handle) + *handle = (drm_handle_t)(uintptr_t)map.handle; + + return 0; +} + +drm_public int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size, + drmMapType *type, drmMapFlags *flags, + drm_handle_t *handle, int *mtrr) +{ + drm_map_t map; + + memclear(map); + map.offset = idx; + if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map)) + return -errno; + *offset = map.offset; + *size = map.size; + *type = (drmMapType)map.type; + *flags = (drmMapFlags)map.flags; + *handle = (unsigned long)map.handle; + *mtrr = map.mtrr; + return 0; +} + +drm_public int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid, + unsigned long *magic, unsigned long *iocs) +{ + drm_client_t client; + + memclear(client); + client.idx = idx; + if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client)) + return -errno; + *auth = client.auth; + *pid = client.pid; + *uid = client.uid; + *magic = client.magic; + *iocs = client.iocs; + return 0; +} + +drm_public int drmGetStats(int fd, drmStatsT *stats) +{ + drm_stats_t s; + unsigned i; + + memclear(s); + if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s)) + return -errno; + + stats->count = 0; + memset(stats, 0, sizeof(*stats)); + if (s.count > sizeof(stats->data)/sizeof(stats->data[0])) + return -1; + +#define SET_VALUE \ + stats->data[i].long_format = "%-20.20s"; \ + stats->data[i].rate_format = "%8.8s"; \ + stats->data[i].isvalue = 1; \ + stats->data[i].verbose = 0 + +#define SET_COUNT \ + stats->data[i].long_format = "%-20.20s"; \ + stats->data[i].rate_format = "%5.5s"; \ + stats->data[i].isvalue = 0; \ + stats->data[i].mult_names = "kgm"; \ + stats->data[i].mult = 1000; \ + stats->data[i].verbose = 0 + +#define SET_BYTE \ + stats->data[i].long_format = "%-20.20s"; \ + stats->data[i].rate_format = "%5.5s"; \ + stats->data[i].isvalue = 0; \ + stats->data[i].mult_names = "KGM"; \ + stats->data[i].mult = 1024; \ + stats->data[i].verbose = 0 + + + stats->count = s.count; + for (i = 0; i < s.count; i++) { + stats->data[i].value = s.data[i].value; + switch (s.data[i].type) { + case _DRM_STAT_LOCK: + stats->data[i].long_name = "Lock"; + stats->data[i].rate_name = "Lock"; + SET_VALUE; + break; + case _DRM_STAT_OPENS: + stats->data[i].long_name = "Opens"; + stats->data[i].rate_name = "O"; + SET_COUNT; + stats->data[i].verbose = 1; + break; + case _DRM_STAT_CLOSES: + stats->data[i].long_name = "Closes"; + stats->data[i].rate_name = "Lock"; + SET_COUNT; + stats->data[i].verbose = 1; + break; + case _DRM_STAT_IOCTLS: + stats->data[i].long_name = "Ioctls"; + stats->data[i].rate_name = "Ioc/s"; + SET_COUNT; + break; + case _DRM_STAT_LOCKS: + stats->data[i].long_name = "Locks"; + stats->data[i].rate_name = "Lck/s"; + SET_COUNT; + break; + case _DRM_STAT_UNLOCKS: + stats->data[i].long_name = "Unlocks"; + stats->data[i].rate_name = "Unl/s"; + SET_COUNT; + break; + case _DRM_STAT_IRQ: + stats->data[i].long_name = "IRQs"; + stats->data[i].rate_name = "IRQ/s"; + SET_COUNT; + break; + case _DRM_STAT_PRIMARY: + stats->data[i].long_name = "Primary Bytes"; + stats->data[i].rate_name = "PB/s"; + SET_BYTE; + break; + case _DRM_STAT_SECONDARY: + stats->data[i].long_name = "Secondary Bytes"; + stats->data[i].rate_name = "SB/s"; + SET_BYTE; + break; + case _DRM_STAT_DMA: + stats->data[i].long_name = "DMA"; + stats->data[i].rate_name = "DMA/s"; + SET_COUNT; + break; + case _DRM_STAT_SPECIAL: + stats->data[i].long_name = "Special DMA"; + stats->data[i].rate_name = "dma/s"; + SET_COUNT; + break; + case _DRM_STAT_MISSED: + stats->data[i].long_name = "Miss"; + stats->data[i].rate_name = "Ms/s"; + SET_COUNT; + break; + case _DRM_STAT_VALUE: + stats->data[i].long_name = "Value"; + stats->data[i].rate_name = "Value"; + SET_VALUE; + break; + case _DRM_STAT_BYTE: + stats->data[i].long_name = "Bytes"; + stats->data[i].rate_name = "B/s"; + SET_BYTE; + break; + case _DRM_STAT_COUNT: + default: + stats->data[i].long_name = "Count"; + stats->data[i].rate_name = "Cnt/s"; + SET_COUNT; + break; + } + } + return 0; +} + +/** + * Issue a set-version ioctl. + * + * \param fd file descriptor. + * \param drmCommandIndex command index + * \param data source pointer of the data to be read and written. + * \param size size of the data to be read and written. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * It issues a read-write ioctl given by + * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. + */ +drm_public int drmSetInterfaceVersion(int fd, drmSetVersion *version) +{ + int retcode = 0; + drm_set_version_t sv; + + memclear(sv); + sv.drm_di_major = version->drm_di_major; + sv.drm_di_minor = version->drm_di_minor; + sv.drm_dd_major = version->drm_dd_major; + sv.drm_dd_minor = version->drm_dd_minor; + + if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) { + retcode = -errno; + } + + version->drm_di_major = sv.drm_di_major; + version->drm_di_minor = sv.drm_di_minor; + version->drm_dd_major = sv.drm_dd_major; + version->drm_dd_minor = sv.drm_dd_minor; + + return retcode; +} + +/** + * Send a device-specific command. + * + * \param fd file descriptor. + * \param drmCommandIndex command index + * + * \return zero on success, or a negative value on failure. + * + * \internal + * It issues a ioctl given by + * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. + */ +drm_public int drmCommandNone(int fd, unsigned long drmCommandIndex) +{ + unsigned long request; + + request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex); + + if (drmIoctl(fd, request, NULL)) { + return -errno; + } + return 0; +} + + +/** + * Send a device-specific read command. + * + * \param fd file descriptor. + * \param drmCommandIndex command index + * \param data destination pointer of the data to be read. + * \param size size of the data to be read. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * It issues a read ioctl given by + * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. + */ +drm_public int drmCommandRead(int fd, unsigned long drmCommandIndex, + void *data, unsigned long size) +{ + unsigned long request; + + request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE, + DRM_COMMAND_BASE + drmCommandIndex, size); + + if (drmIoctl(fd, request, data)) { + return -errno; + } + return 0; +} + + +/** + * Send a device-specific write command. + * + * \param fd file descriptor. + * \param drmCommandIndex command index + * \param data source pointer of the data to be written. + * \param size size of the data to be written. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * It issues a write ioctl given by + * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. + */ +drm_public int drmCommandWrite(int fd, unsigned long drmCommandIndex, + void *data, unsigned long size) +{ + unsigned long request; + + request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE, + DRM_COMMAND_BASE + drmCommandIndex, size); + + if (drmIoctl(fd, request, data)) { + return -errno; + } + return 0; +} + + +/** + * Send a device-specific read-write command. + * + * \param fd file descriptor. + * \param drmCommandIndex command index + * \param data source pointer of the data to be read and written. + * \param size size of the data to be read and written. + * + * \return zero on success, or a negative value on failure. + * + * \internal + * It issues a read-write ioctl given by + * \code DRM_COMMAND_BASE + drmCommandIndex \endcode. + */ +drm_public int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, + void *data, unsigned long size) +{ + unsigned long request; + + request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE, + DRM_COMMAND_BASE + drmCommandIndex, size); + + if (drmIoctl(fd, request, data)) + return -errno; + return 0; +} + +#define DRM_MAX_FDS 16 +static struct { + char *BusID; + int fd; + int refcount; + int type; +} connection[DRM_MAX_FDS]; + +static int nr_fds = 0; + +drm_public int drmOpenOnce(void *unused, const char *BusID, int *newlyopened) +{ + return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY); +} + +drm_public int drmOpenOnceWithType(const char *BusID, int *newlyopened, + int type) +{ + int i; + int fd; + + for (i = 0; i < nr_fds; i++) + if ((strcmp(BusID, connection[i].BusID) == 0) && + (connection[i].type == type)) { + connection[i].refcount++; + *newlyopened = 0; + return connection[i].fd; + } + + fd = drmOpenWithType(NULL, BusID, type); + if (fd < 0 || nr_fds == DRM_MAX_FDS) + return fd; + + connection[nr_fds].BusID = strdup(BusID); + connection[nr_fds].fd = fd; + connection[nr_fds].refcount = 1; + connection[nr_fds].type = type; + *newlyopened = 1; + + if (0) + fprintf(stderr, "saved connection %d for %s %d\n", + nr_fds, connection[nr_fds].BusID, + strcmp(BusID, connection[nr_fds].BusID)); + + nr_fds++; + + return fd; +} + +drm_public void drmCloseOnce(int fd) +{ + int i; + + for (i = 0; i < nr_fds; i++) { + if (fd == connection[i].fd) { + if (--connection[i].refcount == 0) { + drmClose(connection[i].fd); + free(connection[i].BusID); + + if (i < --nr_fds) + connection[i] = connection[nr_fds]; + + return; + } + } + } +} + +drm_public int drmSetMaster(int fd) +{ + return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL); +} + +drm_public int drmDropMaster(int fd) +{ + return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL); +} + +drm_public int drmIsMaster(int fd) +{ + /* Detect master by attempting something that requires master. + * + * Authenticating magic tokens requires master and 0 is an + * internal kernel detail which we could use. Attempting this on + * a master fd would fail therefore fail with EINVAL because 0 + * is invalid. + * + * A non-master fd will fail with EACCES, as the kernel checks + * for master before attempting to do anything else. + * + * Since we don't want to leak implementation details, use + * EACCES. + */ + return drmAuthMagic(fd, 0) != -EACCES; +} + +drm_public char *drmGetDeviceNameFromFd(int fd) +{ +#ifdef __FreeBSD__ + struct stat sbuf; + int maj, min; + int nodetype; + + if (fstat(fd, &sbuf)) + return NULL; + + maj = major(sbuf.st_rdev); + min = minor(sbuf.st_rdev); + nodetype = drmGetMinorType(maj, min); + return drmGetMinorNameForFD(fd, nodetype); +#else + char name[128]; + struct stat sbuf; + dev_t d; + int i; + + /* The whole drmOpen thing is a fiasco and we need to find a way + * back to just using open(2). For now, however, lets just make + * things worse with even more ad hoc directory walking code to + * discover the device file name. */ + + fstat(fd, &sbuf); + d = sbuf.st_rdev; + + for (i = 0; i < DRM_MAX_MINOR; i++) { + snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i); + if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d) + break; + } + if (i == DRM_MAX_MINOR) + return NULL; + + return strdup(name); +#endif +} + +static bool drmNodeIsDRM(int maj, int min) +{ +#ifdef __linux__ + char path[64]; + struct stat sbuf; + + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/drm", + maj, min); + return stat(path, &sbuf) == 0; +#elif defined(__FreeBSD__) + char name[SPECNAMELEN]; + + if (!devname_r(makedev(maj, min), S_IFCHR, name, sizeof(name))) + return 0; + /* Handle drm/ and dri/ as both are present in different FreeBSD version + * FreeBSD on amd64/i386/powerpc external kernel modules create node in + * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates + * only device nodes in /dev/dri/ */ + return (!strncmp(name, "drm/", 4) || !strncmp(name, "dri/", 4)); +#else + return maj == DRM_MAJOR; +#endif +} + +drm_public int drmGetNodeTypeFromFd(int fd) +{ + struct stat sbuf; + int maj, min, type; + + if (fstat(fd, &sbuf)) + return -1; + + maj = major(sbuf.st_rdev); + min = minor(sbuf.st_rdev); + + if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) { + errno = EINVAL; + return -1; + } + + type = drmGetMinorType(maj, min); + if (type == -1) + errno = ENODEV; + return type; +} + +drm_public int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, + int *prime_fd) +{ + struct drm_prime_handle args; + int ret; + + memclear(args); + args.fd = -1; + args.handle = handle; + args.flags = flags; + ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args); + if (ret) + return ret; + + *prime_fd = args.fd; + return 0; +} + +drm_public int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle) +{ + struct drm_prime_handle args; + int ret; + + memclear(args); + args.fd = prime_fd; + ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args); + if (ret) + return ret; + + *handle = args.handle; + return 0; +} + +drm_public int drmCloseBufferHandle(int fd, uint32_t handle) +{ + struct drm_gem_close args; + + memclear(args); + args.handle = handle; + return drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &args); +} + +static char *drmGetMinorNameForFD(int fd, int type) +{ +#ifdef __linux__ + DIR *sysdir; + struct dirent *ent; + struct stat sbuf; + const char *name = drmGetMinorName(type); + int len; + char dev_name[64], buf[64]; + int maj, min; + + if (!name) + return NULL; + + len = strlen(name); + + if (fstat(fd, &sbuf)) + return NULL; + + maj = major(sbuf.st_rdev); + min = minor(sbuf.st_rdev); + + if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) + return NULL; + + snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min); + + sysdir = opendir(buf); + if (!sysdir) + return NULL; + + while ((ent = readdir(sysdir))) { + if (strncmp(ent->d_name, name, len) == 0) { + if (snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s", + ent->d_name) < 0) + return NULL; + + closedir(sysdir); + return strdup(dev_name); + } + } + + closedir(sysdir); + return NULL; +#elif defined(__FreeBSD__) + struct stat sbuf; + char dname[SPECNAMELEN]; + const char *mname; + char name[SPECNAMELEN]; + int id, maj, min, nodetype, i; + + if (fstat(fd, &sbuf)) + return NULL; + + maj = major(sbuf.st_rdev); + min = minor(sbuf.st_rdev); + + if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) + return NULL; + + if (!devname_r(sbuf.st_rdev, S_IFCHR, dname, sizeof(dname))) + return NULL; + + /* Handle both /dev/drm and /dev/dri + * FreeBSD on amd64/i386/powerpc external kernel modules create node in + * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates + * only device nodes in /dev/dri/ */ + + /* Get the node type represented by fd so we can deduce the target name */ + nodetype = drmGetMinorType(maj, min); + if (nodetype == -1) + return (NULL); + mname = drmGetMinorName(type); + + for (i = 0; i < SPECNAMELEN; i++) { + if (isalpha(dname[i]) == 0 && dname[i] != '/') + break; + } + if (dname[i] == '\0') + return (NULL); + + id = (int)strtol(&dname[i], NULL, 10); + id -= drmGetMinorBase(nodetype); + snprintf(name, sizeof(name), DRM_DIR_NAME "/%s%d", mname, + id + drmGetMinorBase(type)); + + return strdup(name); +#else + struct stat sbuf; + char buf[PATH_MAX + 1]; + const char *dev_name = drmGetDeviceName(type); + unsigned int maj, min; + int n; + + if (fstat(fd, &sbuf)) + return NULL; + + maj = major(sbuf.st_rdev); + min = minor(sbuf.st_rdev); + + if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) + return NULL; + + if (!dev_name) + return NULL; + + n = snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, min); + if (n == -1 || n >= sizeof(buf)) + return NULL; + + return strdup(buf); +#endif +} + +drm_public char *drmGetPrimaryDeviceNameFromFd(int fd) +{ + return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY); +} + +drm_public char *drmGetRenderDeviceNameFromFd(int fd) +{ + return drmGetMinorNameForFD(fd, DRM_NODE_RENDER); +} + +#ifdef __linux__ +static char * DRM_PRINTFLIKE(2, 3) +sysfs_uevent_get(const char *path, const char *fmt, ...) +{ + char filename[PATH_MAX + 1], *key, *line = NULL, *value = NULL; + size_t size = 0, len; + ssize_t num; + va_list ap; + FILE *fp; + + va_start(ap, fmt); + num = vasprintf(&key, fmt, ap); + va_end(ap); + len = num; + + snprintf(filename, sizeof(filename), "%s/uevent", path); + + fp = fopen(filename, "r"); + if (!fp) { + free(key); + return NULL; + } + + while ((num = getline(&line, &size, fp)) >= 0) { + if ((strncmp(line, key, len) == 0) && (line[len] == '=')) { + char *start = line + len + 1, *end = line + num - 1; + + if (*end != '\n') + end++; + + value = strndup(start, end - start); + break; + } + } + + free(line); + fclose(fp); + + free(key); + + return value; +} +#endif + +/* Little white lie to avoid major rework of the existing code */ +#define DRM_BUS_VIRTIO 0x10 + +#ifdef __linux__ +static int get_subsystem_type(const char *device_path) +{ + char path[PATH_MAX + 1] = ""; + char link[PATH_MAX + 1] = ""; + char *name; + struct { + const char *name; + int bus_type; + } bus_types[] = { + { "/pci", DRM_BUS_PCI }, + { "/usb", DRM_BUS_USB }, + { "/platform", DRM_BUS_PLATFORM }, + { "/spi", DRM_BUS_PLATFORM }, + { "/host1x", DRM_BUS_HOST1X }, + { "/virtio", DRM_BUS_VIRTIO }, + }; + + strncpy(path, device_path, PATH_MAX); + strncat(path, "/subsystem", PATH_MAX); + + if (readlink(path, link, PATH_MAX) < 0) + return -errno; + + name = strrchr(link, '/'); + if (!name) + return -EINVAL; + + for (unsigned i = 0; i < ARRAY_SIZE(bus_types); i++) { + if (strncmp(name, bus_types[i].name, strlen(bus_types[i].name)) == 0) + return bus_types[i].bus_type; + } + + return -EINVAL; +} +#endif + +static int drmParseSubsystemType(int maj, int min) +{ +#ifdef __linux__ + char path[PATH_MAX + 1] = ""; + char real_path[PATH_MAX + 1] = ""; + int subsystem_type; + + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); + + subsystem_type = get_subsystem_type(path); + /* Try to get the parent (underlying) device type */ + if (subsystem_type == DRM_BUS_VIRTIO) { + /* Assume virtio-pci on error */ + if (!realpath(path, real_path)) + return DRM_BUS_VIRTIO; + strncat(path, "/..", PATH_MAX); + subsystem_type = get_subsystem_type(path); + if (subsystem_type < 0) + return DRM_BUS_VIRTIO; + } + return subsystem_type; +#elif defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD__) + return DRM_BUS_PCI; +#else +#warning "Missing implementation of drmParseSubsystemType" + return -EINVAL; +#endif +} + +#ifdef __linux__ +static void +get_pci_path(int maj, int min, char *pci_path) +{ + char path[PATH_MAX + 1], *term; + + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); + if (!realpath(path, pci_path)) { + strcpy(pci_path, path); + return; + } + + term = strrchr(pci_path, '/'); + if (term && strncmp(term, "/virtio", 7) == 0) + *term = 0; +} +#endif + +#ifdef __FreeBSD__ +static int get_sysctl_pci_bus_info(int maj, int min, drmPciBusInfoPtr info) +{ + char dname[SPECNAMELEN]; + char sysctl_name[16]; + char sysctl_val[256]; + size_t sysctl_len; + int id, type, nelem; + unsigned int rdev, majmin, domain, bus, dev, func; + + rdev = makedev(maj, min); + if (!devname_r(rdev, S_IFCHR, dname, sizeof(dname))) + return -EINVAL; + + if (sscanf(dname, "drm/%d\n", &id) != 1) + return -EINVAL; + type = drmGetMinorType(maj, min); + if (type == -1) + return -EINVAL; + + /* BUG: This above section is iffy, since it mandates that a driver will + * create both card and render node. + * If it does not, the next DRM device will create card#X and + * renderD#(128+X)-1. + * This is a possibility in FreeBSD but for now there is no good way for + * obtaining the info. + */ + switch (type) { + case DRM_NODE_PRIMARY: + break; + case DRM_NODE_CONTROL: + id -= 64; + break; + case DRM_NODE_RENDER: + id -= 128; + break; + } + if (id < 0) + return -EINVAL; + + if (snprintf(sysctl_name, sizeof(sysctl_name), "hw.dri.%d.busid", id) <= 0) + return -EINVAL; + sysctl_len = sizeof(sysctl_val); + if (sysctlbyname(sysctl_name, sysctl_val, &sysctl_len, NULL, 0)) + return -EINVAL; + + #define bus_fmt "pci:%04x:%02x:%02x.%u" + + nelem = sscanf(sysctl_val, bus_fmt, &domain, &bus, &dev, &func); + if (nelem != 4) + return -EINVAL; + info->domain = domain; + info->bus = bus; + info->dev = dev; + info->func = func; + + return 0; +} +#endif + +static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info) +{ +#ifdef __linux__ + unsigned int domain, bus, dev, func; + char pci_path[PATH_MAX + 1], *value; + int num; + + get_pci_path(maj, min, pci_path); + + value = sysfs_uevent_get(pci_path, "PCI_SLOT_NAME"); + if (!value) + return -ENOENT; + + num = sscanf(value, "%04x:%02x:%02x.%1u", &domain, &bus, &dev, &func); + free(value); + + if (num != 4) + return -EINVAL; + + info->domain = domain; + info->bus = bus; + info->dev = dev; + info->func = func; + + return 0; +#elif defined(__OpenBSD__) || defined(__DragonFly__) + struct drm_pciinfo pinfo; + int fd, type; + + type = drmGetMinorType(maj, min); + if (type == -1) + return -ENODEV; + + fd = drmOpenMinor(min, 0, type); + if (fd < 0) + return -errno; + + if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) { + close(fd); + return -errno; + } + close(fd); + + info->domain = pinfo.domain; + info->bus = pinfo.bus; + info->dev = pinfo.dev; + info->func = pinfo.func; + + return 0; +#elif defined(__FreeBSD__) + return get_sysctl_pci_bus_info(maj, min, info); +#else +#warning "Missing implementation of drmParsePciBusInfo" + return -EINVAL; +#endif +} + +drm_public int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b) +{ + if (a == NULL || b == NULL) + return 0; + + if (a->bustype != b->bustype) + return 0; + + switch (a->bustype) { + case DRM_BUS_PCI: + return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0; + + case DRM_BUS_USB: + return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo)) == 0; + + case DRM_BUS_PLATFORM: + return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo)) == 0; + + case DRM_BUS_HOST1X: + return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo)) == 0; + + default: + break; + } + + return 0; +} + +static int drmGetNodeType(const char *name) +{ + if (strncmp(name, DRM_CONTROL_MINOR_NAME, + sizeof(DRM_CONTROL_MINOR_NAME ) - 1) == 0) + return DRM_NODE_CONTROL; + + if (strncmp(name, DRM_RENDER_MINOR_NAME, + sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0) + return DRM_NODE_RENDER; + + if (strncmp(name, DRM_PRIMARY_MINOR_NAME, + sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0) + return DRM_NODE_PRIMARY; + + return -EINVAL; +} + +static int drmGetMaxNodeName(void) +{ + return sizeof(DRM_DIR_NAME) + + MAX3(sizeof(DRM_PRIMARY_MINOR_NAME), + sizeof(DRM_CONTROL_MINOR_NAME), + sizeof(DRM_RENDER_MINOR_NAME)) + + 3 /* length of the node number */; +} + +#ifdef __linux__ +static int parse_separate_sysfs_files(int maj, int min, + drmPciDeviceInfoPtr device, + bool ignore_revision) +{ + static const char *attrs[] = { + "revision", /* Older kernels are missing the file, so check for it first */ + "vendor", + "device", + "subsystem_vendor", + "subsystem_device", + }; + char path[PATH_MAX + 1], pci_path[PATH_MAX + 1]; + unsigned int data[ARRAY_SIZE(attrs)]; + FILE *fp; + int ret; + + get_pci_path(maj, min, pci_path); + + for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) { + if (snprintf(path, PATH_MAX, "%s/%s", pci_path, attrs[i]) < 0) + return -errno; + + fp = fopen(path, "r"); + if (!fp) + return -errno; + + ret = fscanf(fp, "%x", &data[i]); + fclose(fp); + if (ret != 1) + return -errno; + + } + + device->revision_id = ignore_revision ? 0xff : data[0] & 0xff; + device->vendor_id = data[1] & 0xffff; + device->device_id = data[2] & 0xffff; + device->subvendor_id = data[3] & 0xffff; + device->subdevice_id = data[4] & 0xffff; + + return 0; +} + +static int parse_config_sysfs_file(int maj, int min, + drmPciDeviceInfoPtr device) +{ + char path[PATH_MAX + 1], pci_path[PATH_MAX + 1]; + unsigned char config[64]; + int fd, ret; + + get_pci_path(maj, min, pci_path); + + if (snprintf(path, PATH_MAX, "%s/config", pci_path) < 0) + return -errno; + + fd = open(path, O_RDONLY); + if (fd < 0) + return -errno; + + ret = read(fd, config, sizeof(config)); + close(fd); + if (ret < 0) + return -errno; + + device->vendor_id = config[0] | (config[1] << 8); + device->device_id = config[2] | (config[3] << 8); + device->revision_id = config[8]; + device->subvendor_id = config[44] | (config[45] << 8); + device->subdevice_id = config[46] | (config[47] << 8); + + return 0; +} +#endif + +static int drmParsePciDeviceInfo(int maj, int min, + drmPciDeviceInfoPtr device, + uint32_t flags) +{ +#ifdef __linux__ + if (!(flags & DRM_DEVICE_GET_PCI_REVISION)) + return parse_separate_sysfs_files(maj, min, device, true); + + if (parse_separate_sysfs_files(maj, min, device, false)) + return parse_config_sysfs_file(maj, min, device); + + return 0; +#elif defined(__OpenBSD__) || defined(__DragonFly__) + struct drm_pciinfo pinfo; + int fd, type; + + type = drmGetMinorType(maj, min); + if (type == -1) + return -ENODEV; + + fd = drmOpenMinor(min, 0, type); + if (fd < 0) + return -errno; + + if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) { + close(fd); + return -errno; + } + close(fd); + + device->vendor_id = pinfo.vendor_id; + device->device_id = pinfo.device_id; + device->revision_id = pinfo.revision_id; + device->subvendor_id = pinfo.subvendor_id; + device->subdevice_id = pinfo.subdevice_id; + + return 0; +#elif defined(__FreeBSD__) + drmPciBusInfo info; + struct pci_conf_io pc; + struct pci_match_conf patterns[1]; + struct pci_conf results[1]; + int fd, error; + + if (get_sysctl_pci_bus_info(maj, min, &info) != 0) + return -EINVAL; + + fd = open("/dev/pci", O_RDONLY); + if (fd < 0) + return -errno; + + bzero(&patterns, sizeof(patterns)); + patterns[0].pc_sel.pc_domain = info.domain; + patterns[0].pc_sel.pc_bus = info.bus; + patterns[0].pc_sel.pc_dev = info.dev; + patterns[0].pc_sel.pc_func = info.func; + patterns[0].flags = PCI_GETCONF_MATCH_DOMAIN | PCI_GETCONF_MATCH_BUS + | PCI_GETCONF_MATCH_DEV | PCI_GETCONF_MATCH_FUNC; + bzero(&pc, sizeof(struct pci_conf_io)); + pc.num_patterns = 1; + pc.pat_buf_len = sizeof(patterns); + pc.patterns = patterns; + pc.match_buf_len = sizeof(results); + pc.matches = results; + + if (ioctl(fd, PCIOCGETCONF, &pc) || pc.status == PCI_GETCONF_ERROR) { + error = errno; + close(fd); + return -error; + } + close(fd); + + device->vendor_id = results[0].pc_vendor; + device->device_id = results[0].pc_device; + device->subvendor_id = results[0].pc_subvendor; + device->subdevice_id = results[0].pc_subdevice; + device->revision_id = results[0].pc_revid; + + return 0; +#else +#warning "Missing implementation of drmParsePciDeviceInfo" + return -EINVAL; +#endif +} + +static void drmFreePlatformDevice(drmDevicePtr device) +{ + if (device->deviceinfo.platform) { + if (device->deviceinfo.platform->compatible) { + char **compatible = device->deviceinfo.platform->compatible; + + while (*compatible) { + free(*compatible); + compatible++; + } + + free(device->deviceinfo.platform->compatible); + } + } +} + +static void drmFreeHost1xDevice(drmDevicePtr device) +{ + if (device->deviceinfo.host1x) { + if (device->deviceinfo.host1x->compatible) { + char **compatible = device->deviceinfo.host1x->compatible; + + while (*compatible) { + free(*compatible); + compatible++; + } + + free(device->deviceinfo.host1x->compatible); + } + } +} + +drm_public void drmFreeDevice(drmDevicePtr *device) +{ + if (device == NULL) + return; + + if (*device) { + switch ((*device)->bustype) { + case DRM_BUS_PLATFORM: + drmFreePlatformDevice(*device); + break; + + case DRM_BUS_HOST1X: + drmFreeHost1xDevice(*device); + break; + } + } + + free(*device); + *device = NULL; +} + +drm_public void drmFreeDevices(drmDevicePtr devices[], int count) +{ + int i; + + if (devices == NULL) + return; + + for (i = 0; i < count; i++) + if (devices[i]) + drmFreeDevice(&devices[i]); +} + +static drmDevicePtr drmDeviceAlloc(unsigned int type, const char *node, + size_t bus_size, size_t device_size, + char **ptrp) +{ + size_t max_node_length, extra, size; + drmDevicePtr device; + unsigned int i; + char *ptr; + + max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *)); + extra = DRM_NODE_MAX * (sizeof(void *) + max_node_length); + + size = sizeof(*device) + extra + bus_size + device_size; + + device = calloc(1, size); + if (!device) + return NULL; + + device->available_nodes = 1 << type; + + ptr = (char *)device + sizeof(*device); + device->nodes = (char **)ptr; + + ptr += DRM_NODE_MAX * sizeof(void *); + + for (i = 0; i < DRM_NODE_MAX; i++) { + device->nodes[i] = ptr; + ptr += max_node_length; + } + + memcpy(device->nodes[type], node, max_node_length); + + *ptrp = ptr; + + return device; +} + +static int drmProcessPciDevice(drmDevicePtr *device, + const char *node, int node_type, + int maj, int min, bool fetch_deviceinfo, + uint32_t flags) +{ + drmDevicePtr dev; + char *addr; + int ret; + + dev = drmDeviceAlloc(node_type, node, sizeof(drmPciBusInfo), + sizeof(drmPciDeviceInfo), &addr); + if (!dev) + return -ENOMEM; + + dev->bustype = DRM_BUS_PCI; + + dev->businfo.pci = (drmPciBusInfoPtr)addr; + + ret = drmParsePciBusInfo(maj, min, dev->businfo.pci); + if (ret) + goto free_device; + + // Fetch the device info if the user has requested it + if (fetch_deviceinfo) { + addr += sizeof(drmPciBusInfo); + dev->deviceinfo.pci = (drmPciDeviceInfoPtr)addr; + + ret = drmParsePciDeviceInfo(maj, min, dev->deviceinfo.pci, flags); + if (ret) + goto free_device; + } + + *device = dev; + + return 0; + +free_device: + free(dev); + return ret; +} + +#ifdef __linux__ +static int drm_usb_dev_path(int maj, int min, char *path, size_t len) +{ + char *value, *tmp_path, *slash; + bool usb_device, usb_interface; + + snprintf(path, len, "/sys/dev/char/%d:%d/device", maj, min); + + value = sysfs_uevent_get(path, "DEVTYPE"); + if (!value) + return -ENOENT; + + usb_device = strcmp(value, "usb_device") == 0; + usb_interface = strcmp(value, "usb_interface") == 0; + free(value); + + if (usb_device) + return 0; + if (!usb_interface) + return -ENOTSUP; + + /* The parent of a usb_interface is a usb_device */ + + tmp_path = realpath(path, NULL); + if (!tmp_path) + return -errno; + + slash = strrchr(tmp_path, '/'); + if (!slash) { + free(tmp_path); + return -EINVAL; + } + + *slash = '\0'; + + if (snprintf(path, len, "%s", tmp_path) >= (int)len) { + free(tmp_path); + return -EINVAL; + } + + free(tmp_path); + return 0; +} +#endif + +static int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info) +{ +#ifdef __linux__ + char path[PATH_MAX + 1], *value; + unsigned int bus, dev; + int ret; + + ret = drm_usb_dev_path(maj, min, path, sizeof(path)); + if (ret < 0) + return ret; + + value = sysfs_uevent_get(path, "BUSNUM"); + if (!value) + return -ENOENT; + + ret = sscanf(value, "%03u", &bus); + free(value); + + if (ret <= 0) + return -errno; + + value = sysfs_uevent_get(path, "DEVNUM"); + if (!value) + return -ENOENT; + + ret = sscanf(value, "%03u", &dev); + free(value); + + if (ret <= 0) + return -errno; + + info->bus = bus; + info->dev = dev; + + return 0; +#else +#warning "Missing implementation of drmParseUsbBusInfo" + return -EINVAL; +#endif +} + +static int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info) +{ +#ifdef __linux__ + char path[PATH_MAX + 1], *value; + unsigned int vendor, product; + int ret; + + ret = drm_usb_dev_path(maj, min, path, sizeof(path)); + if (ret < 0) + return ret; + + value = sysfs_uevent_get(path, "PRODUCT"); + if (!value) + return -ENOENT; + + ret = sscanf(value, "%x/%x", &vendor, &product); + free(value); + + if (ret <= 0) + return -errno; + + info->vendor = vendor; + info->product = product; + + return 0; +#else +#warning "Missing implementation of drmParseUsbDeviceInfo" + return -EINVAL; +#endif +} + +static int drmProcessUsbDevice(drmDevicePtr *device, const char *node, + int node_type, int maj, int min, + bool fetch_deviceinfo, uint32_t flags) +{ + drmDevicePtr dev; + char *ptr; + int ret; + + dev = drmDeviceAlloc(node_type, node, sizeof(drmUsbBusInfo), + sizeof(drmUsbDeviceInfo), &ptr); + if (!dev) + return -ENOMEM; + + dev->bustype = DRM_BUS_USB; + + dev->businfo.usb = (drmUsbBusInfoPtr)ptr; + + ret = drmParseUsbBusInfo(maj, min, dev->businfo.usb); + if (ret < 0) + goto free_device; + + if (fetch_deviceinfo) { + ptr += sizeof(drmUsbBusInfo); + dev->deviceinfo.usb = (drmUsbDeviceInfoPtr)ptr; + + ret = drmParseUsbDeviceInfo(maj, min, dev->deviceinfo.usb); + if (ret < 0) + goto free_device; + } + + *device = dev; + + return 0; + +free_device: + free(dev); + return ret; +} + +static int drmParseOFBusInfo(int maj, int min, char *fullname) +{ +#ifdef __linux__ + char path[PATH_MAX + 1], *name, *tmp_name; + + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); + + name = sysfs_uevent_get(path, "OF_FULLNAME"); + tmp_name = name; + if (!name) { + /* If the device lacks OF data, pick the MODALIAS info */ + name = sysfs_uevent_get(path, "MODALIAS"); + if (!name) + return -ENOENT; + + /* .. and strip the MODALIAS=[platform,usb...]: part. */ + tmp_name = strrchr(name, ':'); + if (!tmp_name) { + free(name); + return -ENOENT; + } + tmp_name++; + } + + strncpy(fullname, tmp_name, DRM_PLATFORM_DEVICE_NAME_LEN); + fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0'; + free(name); + + return 0; +#else +#warning "Missing implementation of drmParseOFBusInfo" + return -EINVAL; +#endif +} + +static int drmParseOFDeviceInfo(int maj, int min, char ***compatible) +{ +#ifdef __linux__ + char path[PATH_MAX + 1], *value, *tmp_name; + unsigned int count, i; + int err; + + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); + + value = sysfs_uevent_get(path, "OF_COMPATIBLE_N"); + if (value) { + sscanf(value, "%u", &count); + free(value); + } else { + /* Assume one entry if the device lack OF data */ + count = 1; + } + + *compatible = calloc(count + 1, sizeof(char *)); + if (!*compatible) + return -ENOMEM; + + for (i = 0; i < count; i++) { + value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i); + tmp_name = value; + if (!value) { + /* If the device lacks OF data, pick the MODALIAS info */ + value = sysfs_uevent_get(path, "MODALIAS"); + if (!value) { + err = -ENOENT; + goto free; + } + + /* .. and strip the MODALIAS=[platform,usb...]: part. */ + tmp_name = strrchr(value, ':'); + if (!tmp_name) { + free(value); + return -ENOENT; + } + tmp_name = strdup(tmp_name + 1); + free(value); + } + + (*compatible)[i] = tmp_name; + } + + return 0; + +free: + while (i--) + free((*compatible)[i]); + + free(*compatible); + return err; +#else +#warning "Missing implementation of drmParseOFDeviceInfo" + return -EINVAL; +#endif +} + +static int drmProcessPlatformDevice(drmDevicePtr *device, + const char *node, int node_type, + int maj, int min, bool fetch_deviceinfo, + uint32_t flags) +{ + drmDevicePtr dev; + char *ptr; + int ret; + + dev = drmDeviceAlloc(node_type, node, sizeof(drmPlatformBusInfo), + sizeof(drmPlatformDeviceInfo), &ptr); + if (!dev) + return -ENOMEM; + + dev->bustype = DRM_BUS_PLATFORM; + + dev->businfo.platform = (drmPlatformBusInfoPtr)ptr; + + ret = drmParseOFBusInfo(maj, min, dev->businfo.platform->fullname); + if (ret < 0) + goto free_device; + + if (fetch_deviceinfo) { + ptr += sizeof(drmPlatformBusInfo); + dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr; + + ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.platform->compatible); + if (ret < 0) + goto free_device; + } + + *device = dev; + + return 0; + +free_device: + free(dev); + return ret; +} + +static int drmProcessHost1xDevice(drmDevicePtr *device, + const char *node, int node_type, + int maj, int min, bool fetch_deviceinfo, + uint32_t flags) +{ + drmDevicePtr dev; + char *ptr; + int ret; + + dev = drmDeviceAlloc(node_type, node, sizeof(drmHost1xBusInfo), + sizeof(drmHost1xDeviceInfo), &ptr); + if (!dev) + return -ENOMEM; + + dev->bustype = DRM_BUS_HOST1X; + + dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr; + + ret = drmParseOFBusInfo(maj, min, dev->businfo.host1x->fullname); + if (ret < 0) + goto free_device; + + if (fetch_deviceinfo) { + ptr += sizeof(drmHost1xBusInfo); + dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr; + + ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.host1x->compatible); + if (ret < 0) + goto free_device; + } + + *device = dev; + + return 0; + +free_device: + free(dev); + return ret; +} + +static int +process_device(drmDevicePtr *device, const char *d_name, + int req_subsystem_type, + bool fetch_deviceinfo, uint32_t flags) +{ + struct stat sbuf; + char node[PATH_MAX + 1]; + int node_type, subsystem_type; + unsigned int maj, min; + + node_type = drmGetNodeType(d_name); + if (node_type < 0) + return -1; + + snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, d_name); + if (stat(node, &sbuf)) + return -1; + + maj = major(sbuf.st_rdev); + min = minor(sbuf.st_rdev); + + if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) + return -1; + + subsystem_type = drmParseSubsystemType(maj, min); + if (req_subsystem_type != -1 && req_subsystem_type != subsystem_type) + return -1; + + switch (subsystem_type) { + case DRM_BUS_PCI: + case DRM_BUS_VIRTIO: + return drmProcessPciDevice(device, node, node_type, maj, min, + fetch_deviceinfo, flags); + case DRM_BUS_USB: + return drmProcessUsbDevice(device, node, node_type, maj, min, + fetch_deviceinfo, flags); + case DRM_BUS_PLATFORM: + return drmProcessPlatformDevice(device, node, node_type, maj, min, + fetch_deviceinfo, flags); + case DRM_BUS_HOST1X: + return drmProcessHost1xDevice(device, node, node_type, maj, min, + fetch_deviceinfo, flags); + default: + return -1; + } +} + +/* Consider devices located on the same bus as duplicate and fold the respective + * entries into a single one. + * + * Note: this leaves "gaps" in the array, while preserving the length. + */ +static void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count) +{ + int node_type, i, j; + + for (i = 0; i < count; i++) { + for (j = i + 1; j < count; j++) { + if (drmDevicesEqual(local_devices[i], local_devices[j])) { + local_devices[i]->available_nodes |= local_devices[j]->available_nodes; + node_type = log2_int(local_devices[j]->available_nodes); + memcpy(local_devices[i]->nodes[node_type], + local_devices[j]->nodes[node_type], drmGetMaxNodeName()); + drmFreeDevice(&local_devices[j]); + } + } + } +} + +/* Check that the given flags are valid returning 0 on success */ +static int +drm_device_validate_flags(uint32_t flags) +{ + return (flags & ~DRM_DEVICE_GET_PCI_REVISION); +} + +static bool +drm_device_has_rdev(drmDevicePtr device, dev_t find_rdev) +{ + struct stat sbuf; + + for (int i = 0; i < DRM_NODE_MAX; i++) { + if (device->available_nodes & 1 << i) { + if (stat(device->nodes[i], &sbuf) == 0 && + sbuf.st_rdev == find_rdev) + return true; + } + } + return false; +} + +/* + * The kernel drm core has a number of places that assume maximum of + * 3x64 devices nodes. That's 64 for each of primary, control and + * render nodes. Rounded it up to 256 for simplicity. + */ +#define MAX_DRM_NODES 256 + +/** + * Get information about a device from its dev_t identifier + * + * \param find_rdev dev_t identifier of the device + * \param flags feature/behaviour bitmask + * \param device the address of a drmDevicePtr where the information + * will be allocated in stored + * + * \return zero on success, negative error code otherwise. + */ +drm_public int drmGetDeviceFromDevId(dev_t find_rdev, uint32_t flags, drmDevicePtr *device) +{ +#ifdef __OpenBSD__ + /* + * DRI device nodes on OpenBSD are not in their own directory, they reside + * in /dev along with a large number of statically generated /dev nodes. + * Avoid stat'ing all of /dev needlessly by implementing this custom path. + */ + drmDevicePtr d; + char node[PATH_MAX + 1]; + const char *dev_name; + int node_type, subsystem_type; + int maj, min, n, ret; + + if (device == NULL) + return -EINVAL; + + maj = major(find_rdev); + min = minor(find_rdev); + + if (!drmNodeIsDRM(maj, min)) + return -EINVAL; + + node_type = drmGetMinorType(maj, min); + if (node_type == -1) + return -ENODEV; + + dev_name = drmGetDeviceName(node_type); + if (!dev_name) + return -EINVAL; + + n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min); + if (n == -1 || n >= PATH_MAX) + return -errno; + if (stat(node, &sbuf)) + return -EINVAL; + + subsystem_type = drmParseSubsystemType(maj, min); + if (subsystem_type != DRM_BUS_PCI) + return -ENODEV; + + ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags); + if (ret) + return ret; + + *device = d; + + return 0; +#else + drmDevicePtr local_devices[MAX_DRM_NODES]; + drmDevicePtr d; + DIR *sysdir; + struct dirent *dent; + int subsystem_type; + int maj, min; + int ret, i, node_count; + + if (drm_device_validate_flags(flags)) + return -EINVAL; + + if (device == NULL) + return -EINVAL; + + maj = major(find_rdev); + min = minor(find_rdev); + + if (!drmNodeIsDRM(maj, min)) + return -EINVAL; + + subsystem_type = drmParseSubsystemType(maj, min); + if (subsystem_type < 0) + return subsystem_type; + + sysdir = opendir(DRM_DIR_NAME); + if (!sysdir) + return -errno; + + i = 0; + while ((dent = readdir(sysdir))) { + ret = process_device(&d, dent->d_name, subsystem_type, true, flags); + if (ret) + continue; + + if (i >= MAX_DRM_NODES) { + fprintf(stderr, "More than %d drm nodes detected. " + "Please report a bug - that should not happen.\n" + "Skipping extra nodes\n", MAX_DRM_NODES); + break; + } + local_devices[i] = d; + i++; + } + node_count = i; + + drmFoldDuplicatedDevices(local_devices, node_count); + + *device = NULL; + + for (i = 0; i < node_count; i++) { + if (!local_devices[i]) + continue; + + if (drm_device_has_rdev(local_devices[i], find_rdev)) + *device = local_devices[i]; + else + drmFreeDevice(&local_devices[i]); + } + + closedir(sysdir); + if (*device == NULL) + return -ENODEV; + return 0; +#endif +} + +/** + * Get information about the opened drm device + * + * \param fd file descriptor of the drm device + * \param flags feature/behaviour bitmask + * \param device the address of a drmDevicePtr where the information + * will be allocated in stored + * + * \return zero on success, negative error code otherwise. + * + * \note Unlike drmGetDevice it does not retrieve the pci device revision field + * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set. + */ +drm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device) +{ + struct stat sbuf; + + if (fd == -1) + return -EINVAL; + + if (fstat(fd, &sbuf)) + return -errno; + + if (!S_ISCHR(sbuf.st_mode)) + return -EINVAL; + + return drmGetDeviceFromDevId(sbuf.st_rdev, flags, device); +} + +/** + * Get information about the opened drm device + * + * \param fd file descriptor of the drm device + * \param device the address of a drmDevicePtr where the information + * will be allocated in stored + * + * \return zero on success, negative error code otherwise. + */ +drm_public int drmGetDevice(int fd, drmDevicePtr *device) +{ + return drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, device); +} + +/** + * Get drm devices on the system + * + * \param flags feature/behaviour bitmask + * \param devices the array of devices with drmDevicePtr elements + * can be NULL to get the device number first + * \param max_devices the maximum number of devices for the array + * + * \return on error - negative error code, + * if devices is NULL - total number of devices available on the system, + * alternatively the number of devices stored in devices[], which is + * capped by the max_devices. + * + * \note Unlike drmGetDevices it does not retrieve the pci device revision field + * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set. + */ +drm_public int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], + int max_devices) +{ + drmDevicePtr local_devices[MAX_DRM_NODES]; + drmDevicePtr device; + DIR *sysdir; + struct dirent *dent; + int ret, i, node_count, device_count; + + if (drm_device_validate_flags(flags)) + return -EINVAL; + + sysdir = opendir(DRM_DIR_NAME); + if (!sysdir) + return -errno; + + i = 0; + while ((dent = readdir(sysdir))) { + ret = process_device(&device, dent->d_name, -1, devices != NULL, flags); + if (ret) + continue; + + if (i >= MAX_DRM_NODES) { + fprintf(stderr, "More than %d drm nodes detected. " + "Please report a bug - that should not happen.\n" + "Skipping extra nodes\n", MAX_DRM_NODES); + break; + } + local_devices[i] = device; + i++; + } + node_count = i; + + drmFoldDuplicatedDevices(local_devices, node_count); + + device_count = 0; + for (i = 0; i < node_count; i++) { + if (!local_devices[i]) + continue; + + if ((devices != NULL) && (device_count < max_devices)) + devices[device_count] = local_devices[i]; + else + drmFreeDevice(&local_devices[i]); + + device_count++; + } + + closedir(sysdir); + + if (devices != NULL) + return MIN2(device_count, max_devices); + + return device_count; +} + +/** + * Get drm devices on the system + * + * \param devices the array of devices with drmDevicePtr elements + * can be NULL to get the device number first + * \param max_devices the maximum number of devices for the array + * + * \return on error - negative error code, + * if devices is NULL - total number of devices available on the system, + * alternatively the number of devices stored in devices[], which is + * capped by the max_devices. + */ +drm_public int drmGetDevices(drmDevicePtr devices[], int max_devices) +{ + return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION, devices, max_devices); +} + +drm_public char *drmGetDeviceNameFromFd2(int fd) +{ +#ifdef __linux__ + struct stat sbuf; + char path[PATH_MAX + 1], *value; + unsigned int maj, min; + + if (fstat(fd, &sbuf)) + return NULL; + + maj = major(sbuf.st_rdev); + min = minor(sbuf.st_rdev); + + if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) + return NULL; + + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min); + + value = sysfs_uevent_get(path, "DEVNAME"); + if (!value) + return NULL; + + snprintf(path, sizeof(path), "/dev/%s", value); + free(value); + + return strdup(path); +#elif defined(__FreeBSD__) + return drmGetDeviceNameFromFd(fd); +#else + struct stat sbuf; + char node[PATH_MAX + 1]; + const char *dev_name; + int node_type; + int maj, min, n; + + if (fstat(fd, &sbuf)) + return NULL; + + maj = major(sbuf.st_rdev); + min = minor(sbuf.st_rdev); + + if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) + return NULL; + + node_type = drmGetMinorType(maj, min); + if (node_type == -1) + return NULL; + + dev_name = drmGetDeviceName(node_type); + if (!dev_name) + return NULL; + + n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min); + if (n == -1 || n >= PATH_MAX) + return NULL; + + return strdup(node); +#endif +} + +drm_public int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle) +{ + struct drm_syncobj_create args; + int ret; + + memclear(args); + args.flags = flags; + args.handle = 0; + ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &args); + if (ret) + return ret; + *handle = args.handle; + return 0; +} + +drm_public int drmSyncobjDestroy(int fd, uint32_t handle) +{ + struct drm_syncobj_destroy args; + + memclear(args); + args.handle = handle; + return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args); +} + +drm_public int drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd) +{ + struct drm_syncobj_handle args; + int ret; + + memclear(args); + args.fd = -1; + args.handle = handle; + ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args); + if (ret) + return ret; + *obj_fd = args.fd; + return 0; +} + +drm_public int drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle) +{ + struct drm_syncobj_handle args; + int ret; + + memclear(args); + args.fd = obj_fd; + args.handle = 0; + ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args); + if (ret) + return ret; + *handle = args.handle; + return 0; +} + +drm_public int drmSyncobjImportSyncFile(int fd, uint32_t handle, + int sync_file_fd) +{ + struct drm_syncobj_handle args; + + memclear(args); + args.fd = sync_file_fd; + args.handle = handle; + args.flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE; + return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args); +} + +drm_public int drmSyncobjExportSyncFile(int fd, uint32_t handle, + int *sync_file_fd) +{ + struct drm_syncobj_handle args; + int ret; + + memclear(args); + args.fd = -1; + args.handle = handle; + args.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE; + ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args); + if (ret) + return ret; + *sync_file_fd = args.fd; + return 0; +} + +drm_public int drmSyncobjWait(int fd, uint32_t *handles, unsigned num_handles, + int64_t timeout_nsec, unsigned flags, + uint32_t *first_signaled) +{ + struct drm_syncobj_wait args; + int ret; + + memclear(args); + args.handles = (uintptr_t)handles; + args.timeout_nsec = timeout_nsec; + args.count_handles = num_handles; + args.flags = flags; + + ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_WAIT, &args); + if (ret < 0) + return -errno; + + if (first_signaled) + *first_signaled = args.first_signaled; + return ret; +} + +drm_public int drmSyncobjReset(int fd, const uint32_t *handles, + uint32_t handle_count) +{ + struct drm_syncobj_array args; + int ret; + + memclear(args); + args.handles = (uintptr_t)handles; + args.count_handles = handle_count; + + ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_RESET, &args); + return ret; +} + +drm_public int drmSyncobjSignal(int fd, const uint32_t *handles, + uint32_t handle_count) +{ + struct drm_syncobj_array args; + int ret; + + memclear(args); + args.handles = (uintptr_t)handles; + args.count_handles = handle_count; + + ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &args); + return ret; +} + +drm_public int drmSyncobjTimelineSignal(int fd, const uint32_t *handles, + uint64_t *points, uint32_t handle_count) +{ + struct drm_syncobj_timeline_array args; + int ret; + + memclear(args); + args.handles = (uintptr_t)handles; + args.points = (uintptr_t)points; + args.count_handles = handle_count; + + ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &args); + return ret; +} + +drm_public int drmSyncobjTimelineWait(int fd, uint32_t *handles, uint64_t *points, + unsigned num_handles, + int64_t timeout_nsec, unsigned flags, + uint32_t *first_signaled) +{ + struct drm_syncobj_timeline_wait args; + int ret; + + memclear(args); + args.handles = (uintptr_t)handles; + args.points = (uintptr_t)points; + args.timeout_nsec = timeout_nsec; + args.count_handles = num_handles; + args.flags = flags; + + ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, &args); + if (ret < 0) + return -errno; + + if (first_signaled) + *first_signaled = args.first_signaled; + return ret; +} + + +drm_public int drmSyncobjQuery(int fd, uint32_t *handles, uint64_t *points, + uint32_t handle_count) +{ + struct drm_syncobj_timeline_array args; + int ret; + + memclear(args); + args.handles = (uintptr_t)handles; + args.points = (uintptr_t)points; + args.count_handles = handle_count; + + ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args); + if (ret) + return ret; + return 0; +} + +drm_public int drmSyncobjQuery2(int fd, uint32_t *handles, uint64_t *points, + uint32_t handle_count, uint32_t flags) +{ + struct drm_syncobj_timeline_array args; + + memclear(args); + args.handles = (uintptr_t)handles; + args.points = (uintptr_t)points; + args.count_handles = handle_count; + args.flags = flags; + + return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args); +} + + +drm_public int drmSyncobjTransfer(int fd, + uint32_t dst_handle, uint64_t dst_point, + uint32_t src_handle, uint64_t src_point, + uint32_t flags) +{ + struct drm_syncobj_transfer args; + int ret; + + memclear(args); + args.src_handle = src_handle; + args.dst_handle = dst_handle; + args.src_point = src_point; + args.dst_point = dst_point; + args.flags = flags; + + ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TRANSFER, &args); + + return ret; +} + +static char * +drmGetFormatModifierFromSimpleTokens(uint64_t modifier) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(drm_format_modifier_table); i++) { + if (drm_format_modifier_table[i].modifier == modifier) + return strdup(drm_format_modifier_table[i].modifier_name); + } + + return NULL; +} + +/** Retrieves a human-readable representation of a vendor (as a string) from + * the format token modifier + * + * \param modifier the format modifier token + * \return a char pointer to the human-readable form of the vendor. Caller is + * responsible for freeing it. + */ +drm_public char * +drmGetFormatModifierVendor(uint64_t modifier) +{ + unsigned int i; + uint8_t vendor = fourcc_mod_get_vendor(modifier); + + for (i = 0; i < ARRAY_SIZE(drm_format_modifier_vendor_table); i++) { + if (drm_format_modifier_vendor_table[i].vendor == vendor) + return strdup(drm_format_modifier_vendor_table[i].vendor_name); + } + + return NULL; +} + +/** Retrieves a human-readable representation string from a format token + * modifier + * + * If the dedicated function was not able to extract a valid name or searching + * the format modifier was not in the table, this function would return NULL. + * + * \param modifier the token format + * \return a malloc'ed string representation of the modifier. Caller is + * responsible for freeing the string returned. + * + */ +drm_public char * +drmGetFormatModifierName(uint64_t modifier) +{ + uint8_t vendorid = fourcc_mod_get_vendor(modifier); + char *modifier_found = NULL; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(modifier_format_vendor_table); i++) { + if (modifier_format_vendor_table[i].vendor == vendorid) + modifier_found = modifier_format_vendor_table[i].vendor_cb(modifier); + } + + if (!modifier_found) + return drmGetFormatModifierFromSimpleTokens(modifier); + + return modifier_found; +} + +/** + * Get a human-readable name for a DRM FourCC format. + * + * \param format The format. + * \return A malloc'ed string containing the format name. Caller is responsible + * for freeing it. + */ +drm_public char * +drmGetFormatName(uint32_t format) +{ + char *str, code[5]; + const char *be; + size_t str_size, i; + + be = (format & DRM_FORMAT_BIG_ENDIAN) ? "_BE" : ""; + format &= ~DRM_FORMAT_BIG_ENDIAN; + + if (format == DRM_FORMAT_INVALID) + return strdup("INVALID"); + + code[0] = (char) ((format >> 0) & 0xFF); + code[1] = (char) ((format >> 8) & 0xFF); + code[2] = (char) ((format >> 16) & 0xFF); + code[3] = (char) ((format >> 24) & 0xFF); + code[4] = '\0'; + + /* Trim spaces at the end */ + for (i = 3; i > 0 && code[i] == ' '; i--) + code[i] = '\0'; + + str_size = strlen(code) + strlen(be) + 1; + str = malloc(str_size); + if (!str) + return NULL; + + snprintf(str, str_size, "%s%s", code, be); + + return str; +} diff --git a/xf86drm.h b/xf86drm.h new file mode 100644 index 0000000..4badaae --- /dev/null +++ b/xf86drm.h @@ -0,0 +1,969 @@ +/** + * \file xf86drm.h + * OS-independent header for DRM user-level library interface. + * + * \author Rickard E. (Rik) Faith + */ + +/* + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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, 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT 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 _XF86DRM_H_ +#define _XF86DRM_H_ + +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +#ifndef DRM_MAX_MINOR +#define DRM_MAX_MINOR 16 +#endif + +#if defined(__linux__) + +#define DRM_IOCTL_NR(n) _IOC_NR(n) +#define DRM_IOC_VOID _IOC_NONE +#define DRM_IOC_READ _IOC_READ +#define DRM_IOC_WRITE _IOC_WRITE +#define DRM_IOC_READWRITE _IOC_READ|_IOC_WRITE +#define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size) + +#else /* One of the *BSDs */ + +#include +#define DRM_IOCTL_NR(n) ((n) & 0xff) +#define DRM_IOC_VOID IOC_VOID +#define DRM_IOC_READ IOC_OUT +#define DRM_IOC_WRITE IOC_IN +#define DRM_IOC_READWRITE IOC_INOUT +#define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size) + +#endif + + /* Defaults, if nothing set in xf86config */ +#define DRM_DEV_UID 0 +#define DRM_DEV_GID 0 +/* Default /dev/dri directory permissions 0755 */ +#define DRM_DEV_DIRMODE \ + (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) +#define DRM_DEV_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) + +#ifdef __OpenBSD__ +#define DRM_DIR_NAME "/dev" +#define DRM_PRIMARY_MINOR_NAME "drm" +#define DRM_CONTROL_MINOR_NAME "drmC" +#define DRM_RENDER_MINOR_NAME "drmR" +#else +#define DRM_DIR_NAME "/dev/dri" +#define DRM_PRIMARY_MINOR_NAME "card" +#define DRM_CONTROL_MINOR_NAME "controlD" +#define DRM_RENDER_MINOR_NAME "renderD" +#define DRM_PROC_NAME "/proc/dri/" /* For backward Linux compatibility */ +#endif + +#define DRM_DEV_NAME "%s/" DRM_PRIMARY_MINOR_NAME "%d" +#define DRM_CONTROL_DEV_NAME "%s/" DRM_CONTROL_MINOR_NAME "%d" +#define DRM_RENDER_DEV_NAME "%s/" DRM_RENDER_MINOR_NAME "%d" + +#define DRM_NODE_NAME_MAX \ + (sizeof(DRM_DIR_NAME) + 1 /* slash */ \ + + MAX3(sizeof(DRM_PRIMARY_MINOR_NAME), \ + sizeof(DRM_CONTROL_MINOR_NAME), \ + sizeof(DRM_RENDER_MINOR_NAME)) \ + + sizeof("144") /* highest possible node number */ \ + + 1) /* NULL-terminator */ + +#define DRM_ERR_NO_DEVICE (-1001) +#define DRM_ERR_NO_ACCESS (-1002) +#define DRM_ERR_NOT_ROOT (-1003) +#define DRM_ERR_INVALID (-1004) +#define DRM_ERR_NO_FD (-1005) + +#define DRM_AGP_NO_HANDLE 0 + +typedef unsigned int drmSize, *drmSizePtr; /**< For mapped regions */ +typedef void *drmAddress, **drmAddressPtr; /**< For mapped regions */ + +#if (__GNUC__ >= 3) +#define DRM_PRINTFLIKE(f, a) __attribute__ ((format(__printf__, f, a))) +#else +#define DRM_PRINTFLIKE(f, a) +#endif + +typedef struct _drmServerInfo { + int (*debug_print)(const char *format, va_list ap) DRM_PRINTFLIKE(1,0); + int (*load_module)(const char *name); + void (*get_perms)(gid_t *, mode_t *); +} drmServerInfo, *drmServerInfoPtr; + +typedef struct drmHashEntry { + int fd; + void (*f)(int, void *, void *); + void *tagTable; +} drmHashEntry; + +extern int drmIoctl(int fd, unsigned long request, void *arg); +extern void *drmGetHashTable(void); +extern drmHashEntry *drmGetEntry(int fd); + +/** + * Driver version information. + * + * \sa drmGetVersion() and drmSetVersion(). + */ +typedef struct _drmVersion { + int version_major; /**< Major version */ + int version_minor; /**< Minor version */ + int version_patchlevel; /**< Patch level */ + int name_len; /**< Length of name buffer */ + char *name; /**< Name of driver */ + int date_len; /**< Length of date buffer */ + char *date; /**< User-space buffer to hold date */ + int desc_len; /**< Length of desc buffer */ + char *desc; /**< User-space buffer to hold desc */ +} drmVersion, *drmVersionPtr; + +typedef struct _drmStats { + unsigned long count; /**< Number of data */ + struct { + unsigned long value; /**< Value from kernel */ + const char *long_format; /**< Suggested format for long_name */ + const char *long_name; /**< Long name for value */ + const char *rate_format; /**< Suggested format for rate_name */ + const char *rate_name; /**< Short name for value per second */ + int isvalue; /**< True if value (vs. counter) */ + const char *mult_names; /**< Multiplier names (e.g., "KGM") */ + int mult; /**< Multiplier value (e.g., 1024) */ + int verbose; /**< Suggest only in verbose output */ + } data[15]; +} drmStatsT; + + + /* All of these enums *MUST* match with the + kernel implementation -- so do *NOT* + change them! (The drmlib implementation + will just copy the flags instead of + translating them.) */ +typedef enum { + DRM_FRAME_BUFFER = 0, /**< WC, no caching, no core dump */ + DRM_REGISTERS = 1, /**< no caching, no core dump */ + DRM_SHM = 2, /**< shared, cached */ + DRM_AGP = 3, /**< AGP/GART */ + DRM_SCATTER_GATHER = 4, /**< PCI scatter/gather */ + DRM_CONSISTENT = 5 /**< PCI consistent */ +} drmMapType; + +typedef enum { + DRM_RESTRICTED = 0x0001, /**< Cannot be mapped to client-virtual */ + DRM_READ_ONLY = 0x0002, /**< Read-only in client-virtual */ + DRM_LOCKED = 0x0004, /**< Physical pages locked */ + DRM_KERNEL = 0x0008, /**< Kernel requires access */ + DRM_WRITE_COMBINING = 0x0010, /**< Use write-combining, if available */ + DRM_CONTAINS_LOCK = 0x0020, /**< SHM page that contains lock */ + DRM_REMOVABLE = 0x0040 /**< Removable mapping */ +} drmMapFlags; + +/** + * \warning These values *MUST* match drm.h + */ +typedef enum { + /** \name Flags for DMA buffer dispatch */ + /*@{*/ + DRM_DMA_BLOCK = 0x01, /**< + * Block until buffer dispatched. + * + * \note the buffer may not yet have been + * processed by the hardware -- getting a + * hardware lock with the hardware quiescent + * will ensure that the buffer has been + * processed. + */ + DRM_DMA_WHILE_LOCKED = 0x02, /**< Dispatch while lock held */ + DRM_DMA_PRIORITY = 0x04, /**< High priority dispatch */ + /*@}*/ + + /** \name Flags for DMA buffer request */ + /*@{*/ + DRM_DMA_WAIT = 0x10, /**< Wait for free buffers */ + DRM_DMA_SMALLER_OK = 0x20, /**< Smaller-than-requested buffers OK */ + DRM_DMA_LARGER_OK = 0x40 /**< Larger-than-requested buffers OK */ + /*@}*/ +} drmDMAFlags; + +typedef enum { + DRM_PAGE_ALIGN = 0x01, + DRM_AGP_BUFFER = 0x02, + DRM_SG_BUFFER = 0x04, + DRM_FB_BUFFER = 0x08, + DRM_PCI_BUFFER_RO = 0x10 +} drmBufDescFlags; + +typedef enum { + DRM_LOCK_READY = 0x01, /**< Wait until hardware is ready for DMA */ + DRM_LOCK_QUIESCENT = 0x02, /**< Wait until hardware quiescent */ + DRM_LOCK_FLUSH = 0x04, /**< Flush this context's DMA queue first */ + DRM_LOCK_FLUSH_ALL = 0x08, /**< Flush all DMA queues first */ + /* These *HALT* flags aren't supported yet + -- they will be used to support the + full-screen DGA-like mode. */ + DRM_HALT_ALL_QUEUES = 0x10, /**< Halt all current and future queues */ + DRM_HALT_CUR_QUEUES = 0x20 /**< Halt all current queues */ +} drmLockFlags; + +typedef enum { + DRM_CONTEXT_PRESERVED = 0x01, /**< This context is preserved and + never swapped. */ + DRM_CONTEXT_2DONLY = 0x02 /**< This context is for 2D rendering only. */ +} drm_context_tFlags, *drm_context_tFlagsPtr; + +typedef struct _drmBufDesc { + int count; /**< Number of buffers of this size */ + int size; /**< Size in bytes */ + int low_mark; /**< Low water mark */ + int high_mark; /**< High water mark */ +} drmBufDesc, *drmBufDescPtr; + +typedef struct _drmBufInfo { + int count; /**< Number of buffers described in list */ + drmBufDescPtr list; /**< List of buffer descriptions */ +} drmBufInfo, *drmBufInfoPtr; + +typedef struct _drmBuf { + int idx; /**< Index into the master buffer list */ + int total; /**< Buffer size */ + int used; /**< Amount of buffer in use (for DMA) */ + drmAddress address; /**< Address */ +} drmBuf, *drmBufPtr; + +/** + * Buffer mapping information. + * + * Used by drmMapBufs() and drmUnmapBufs() to store information about the + * mapped buffers. + */ +typedef struct _drmBufMap { + int count; /**< Number of buffers mapped */ + drmBufPtr list; /**< Buffers */ +} drmBufMap, *drmBufMapPtr; + +typedef struct _drmLock { + volatile unsigned int lock; + char padding[60]; + /* This is big enough for most current (and future?) architectures: + DEC Alpha: 32 bytes + Intel Merced: ? + Intel P5/PPro/PII/PIII: 32 bytes + Intel StrongARM: 32 bytes + Intel i386/i486: 16 bytes + MIPS: 32 bytes (?) + Motorola 68k: 16 bytes + Motorola PowerPC: 32 bytes + Sun SPARC: 32 bytes + */ +} drmLock, *drmLockPtr; + +/** + * Indices here refer to the offset into + * list in drmBufInfo + */ +typedef struct _drmDMAReq { + drm_context_t context; /**< Context handle */ + int send_count; /**< Number of buffers to send */ + int *send_list; /**< List of handles to buffers */ + int *send_sizes; /**< Lengths of data to send, in bytes */ + drmDMAFlags flags; /**< Flags */ + int request_count; /**< Number of buffers requested */ + int request_size; /**< Desired size of buffers requested */ + int *request_list; /**< Buffer information */ + int *request_sizes; /**< Minimum acceptable sizes */ + int granted_count; /**< Number of buffers granted at this size */ +} drmDMAReq, *drmDMAReqPtr; + +typedef struct _drmRegion { + drm_handle_t handle; + unsigned int offset; + drmSize size; + drmAddress map; +} drmRegion, *drmRegionPtr; + +typedef struct _drmTextureRegion { + unsigned char next; + unsigned char prev; + unsigned char in_use; + unsigned char padding; /**< Explicitly pad this out */ + unsigned int age; +} drmTextureRegion, *drmTextureRegionPtr; + + +typedef enum { + DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ + DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + /* bits 1-6 are reserved for high crtcs */ + DRM_VBLANK_HIGH_CRTC_MASK = 0x0000003e, + DRM_VBLANK_EVENT = 0x4000000, /**< Send event instead of blocking */ + DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ + DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ + DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ + DRM_VBLANK_SIGNAL = 0x40000000 /* Send signal instead of blocking */ +} drmVBlankSeqType; +#define DRM_VBLANK_HIGH_CRTC_SHIFT 1 + +typedef struct _drmVBlankReq { + drmVBlankSeqType type; + unsigned int sequence; + unsigned long signal; +} drmVBlankReq, *drmVBlankReqPtr; + +typedef struct _drmVBlankReply { + drmVBlankSeqType type; + unsigned int sequence; + long tval_sec; + long tval_usec; +} drmVBlankReply, *drmVBlankReplyPtr; + +typedef union _drmVBlank { + drmVBlankReq request; + drmVBlankReply reply; +} drmVBlank, *drmVBlankPtr; + +typedef struct _drmSetVersion { + int drm_di_major; + int drm_di_minor; + int drm_dd_major; + int drm_dd_minor; +} drmSetVersion, *drmSetVersionPtr; + +#define __drm_dummy_lock(lock) (*(__volatile__ unsigned int *)lock) + +#define DRM_LOCK_HELD 0x80000000U /**< Hardware lock is held */ +#define DRM_LOCK_CONT 0x40000000U /**< Hardware lock is contended */ + +#if defined(__GNUC__) && (__GNUC__ >= 2) +# if defined(__i386) || defined(__AMD64__) || defined(__x86_64__) || defined(__amd64__) + /* Reflect changes here to drmP.h */ +#define DRM_CAS(lock,old,new,__ret) \ + do { \ + int __dummy; /* Can't mark eax as clobbered */ \ + __asm__ __volatile__( \ + "lock ; cmpxchg %4,%1\n\t" \ + "setnz %0" \ + : "=d" (__ret), \ + "=m" (__drm_dummy_lock(lock)), \ + "=a" (__dummy) \ + : "2" (old), \ + "r" (new)); \ + } while (0) + +#elif defined(__alpha__) + +#define DRM_CAS(lock, old, new, ret) \ + do { \ + int tmp, old32; \ + __asm__ __volatile__( \ + " addl $31, %5, %3\n" \ + "1: ldl_l %0, %2\n" \ + " cmpeq %0, %3, %1\n" \ + " beq %1, 2f\n" \ + " mov %4, %0\n" \ + " stl_c %0, %2\n" \ + " beq %0, 3f\n" \ + " mb\n" \ + "2: cmpeq %1, 0, %1\n" \ + ".subsection 2\n" \ + "3: br 1b\n" \ + ".previous" \ + : "=&r"(tmp), "=&r"(ret), \ + "=m"(__drm_dummy_lock(lock)), \ + "=&r"(old32) \ + : "r"(new), "r"(old) \ + : "memory"); \ + } while (0) + +#elif defined(__sparc__) + +#define DRM_CAS(lock,old,new,__ret) \ +do { register unsigned int __old __asm("o0"); \ + register unsigned int __new __asm("o1"); \ + register volatile unsigned int *__lock __asm("o2"); \ + __old = old; \ + __new = new; \ + __lock = (volatile unsigned int *)lock; \ + __asm__ __volatile__( \ + /*"cas [%2], %3, %0"*/ \ + ".word 0xd3e29008\n\t" \ + /*"membar #StoreStore | #StoreLoad"*/ \ + ".word 0x8143e00a" \ + : "=&r" (__new) \ + : "0" (__new), \ + "r" (__lock), \ + "r" (__old) \ + : "memory"); \ + __ret = (__new != __old); \ +} while(0) + +#elif defined(__ia64__) + +#ifdef __INTEL_COMPILER +/* this currently generates bad code (missing stop bits)... */ +#include + +#define DRM_CAS(lock,old,new,__ret) \ + do { \ + unsigned long __result, __old = (old) & 0xffffffff; \ + __mf(); \ + __result = _InterlockedCompareExchange_acq(&__drm_dummy_lock(lock), (new), __old);\ + __ret = (__result) != (__old); \ +/* __ret = (__sync_val_compare_and_swap(&__drm_dummy_lock(lock), \ + (old), (new)) \ + != (old)); */\ + } while (0) + +#else +#define DRM_CAS(lock,old,new,__ret) \ + do { \ + unsigned int __result, __old = (old); \ + __asm__ __volatile__( \ + "mf\n" \ + "mov ar.ccv=%2\n" \ + ";;\n" \ + "cmpxchg4.acq %0=%1,%3,ar.ccv" \ + : "=r" (__result), "=m" (__drm_dummy_lock(lock)) \ + : "r" ((unsigned long)__old), "r" (new) \ + : "memory"); \ + __ret = (__result) != (__old); \ + } while (0) + +#endif + +#elif defined(__powerpc__) + +#define DRM_CAS(lock,old,new,__ret) \ + do { \ + __asm__ __volatile__( \ + "sync;" \ + "0: lwarx %0,0,%1;" \ + " xor. %0,%3,%0;" \ + " bne 1f;" \ + " stwcx. %2,0,%1;" \ + " bne- 0b;" \ + "1: " \ + "sync;" \ + : "=&r"(__ret) \ + : "r"(lock), "r"(new), "r"(old) \ + : "cr0", "memory"); \ + } while (0) + +# elif defined (__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \ + || defined (__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) \ + || defined (__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) \ + || defined (__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \ + || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \ + || defined(__ARM_ARCH_7EM__) + /* excluding ARMv4/ARMv5 and lower (lacking ldrex/strex support) */ + #undef DRM_DEV_MODE + #define DRM_DEV_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) + + #define DRM_CAS(lock,old,new,__ret) \ + do { \ + __asm__ __volatile__ ( \ + "1: ldrex %0, [%1]\n" \ + " teq %0, %2\n" \ + " ite eq\n" \ + " strexeq %0, %3, [%1]\n" \ + " movne %0, #1\n" \ + : "=&r" (__ret) \ + : "r" (lock), "r" (old), "r" (new) \ + : "cc","memory"); \ + } while (0) + +#endif /* architecture */ +#endif /* __GNUC__ >= 2 */ + +#ifndef DRM_CAS +#define DRM_CAS(lock,old,new,ret) do { ret=1; } while (0) /* FAST LOCK FAILS */ +#endif + +#if defined(__alpha__) +#define DRM_CAS_RESULT(_result) long _result +#elif defined(__powerpc__) +#define DRM_CAS_RESULT(_result) int _result +#else +#define DRM_CAS_RESULT(_result) char _result +#endif + +#define DRM_LIGHT_LOCK(fd,lock,context) \ + do { \ + DRM_CAS_RESULT(__ret); \ + DRM_CAS(lock,context,DRM_LOCK_HELD|context,__ret); \ + if (__ret) drmGetLock(fd,context,0); \ + } while(0) + + /* This one counts fast locks -- for + benchmarking only. */ +#define DRM_LIGHT_LOCK_COUNT(fd,lock,context,count) \ + do { \ + DRM_CAS_RESULT(__ret); \ + DRM_CAS(lock,context,DRM_LOCK_HELD|context,__ret); \ + if (__ret) drmGetLock(fd,context,0); \ + else ++count; \ + } while(0) + +#define DRM_LOCK(fd,lock,context,flags) \ + do { \ + if (flags) drmGetLock(fd,context,flags); \ + else DRM_LIGHT_LOCK(fd,lock,context); \ + } while(0) + +#define DRM_UNLOCK(fd,lock,context) \ + do { \ + DRM_CAS_RESULT(__ret); \ + DRM_CAS(lock,DRM_LOCK_HELD|context,context,__ret); \ + if (__ret) drmUnlock(fd,context); \ + } while(0) + + /* Simple spin locks */ +#define DRM_SPINLOCK(spin,val) \ + do { \ + DRM_CAS_RESULT(__ret); \ + do { \ + DRM_CAS(spin,0,val,__ret); \ + if (__ret) while ((spin)->lock); \ + } while (__ret); \ + } while(0) + +#define DRM_SPINLOCK_TAKE(spin,val) \ + do { \ + DRM_CAS_RESULT(__ret); \ + int cur; \ + do { \ + cur = (*spin).lock; \ + DRM_CAS(spin,cur,val,__ret); \ + } while (__ret); \ + } while(0) + +#define DRM_SPINLOCK_COUNT(spin,val,count,__ret) \ + do { \ + int __i; \ + __ret = 1; \ + for (__i = 0; __ret && __i < count; __i++) { \ + DRM_CAS(spin,0,val,__ret); \ + if (__ret) for (;__i < count && (spin)->lock; __i++); \ + } \ + } while(0) + +#define DRM_SPINUNLOCK(spin,val) \ + do { \ + DRM_CAS_RESULT(__ret); \ + if ((*spin).lock == val) { /* else server stole lock */ \ + do { \ + DRM_CAS(spin,val,0,__ret); \ + } while (__ret); \ + } \ + } while(0) + + + +/* General user-level programmer's API: unprivileged */ +extern int drmAvailable(void); +extern int drmOpen(const char *name, const char *busid); + +#define DRM_NODE_PRIMARY 0 +#define DRM_NODE_CONTROL 1 +#define DRM_NODE_RENDER 2 +#define DRM_NODE_MAX 3 + +extern int drmOpenWithType(const char *name, const char *busid, + int type); + +extern int drmOpenControl(int minor); +extern int drmOpenRender(int minor); +extern int drmClose(int fd); +extern drmVersionPtr drmGetVersion(int fd); +extern drmVersionPtr drmGetLibVersion(int fd); +extern int drmGetCap(int fd, uint64_t capability, uint64_t *value); +extern void drmFreeVersion(drmVersionPtr); +extern int drmGetMagic(int fd, drm_magic_t * magic); +extern char *drmGetBusid(int fd); +extern int drmGetInterruptFromBusID(int fd, int busnum, int devnum, + int funcnum); +extern int drmGetMap(int fd, int idx, drm_handle_t *offset, + drmSize *size, drmMapType *type, + drmMapFlags *flags, drm_handle_t *handle, + int *mtrr); +extern int drmGetClient(int fd, int idx, int *auth, int *pid, + int *uid, unsigned long *magic, + unsigned long *iocs); +extern int drmGetStats(int fd, drmStatsT *stats); +extern int drmSetInterfaceVersion(int fd, drmSetVersion *version); +extern int drmCommandNone(int fd, unsigned long drmCommandIndex); +extern int drmCommandRead(int fd, unsigned long drmCommandIndex, + void *data, unsigned long size); +extern int drmCommandWrite(int fd, unsigned long drmCommandIndex, + void *data, unsigned long size); +extern int drmCommandWriteRead(int fd, unsigned long drmCommandIndex, + void *data, unsigned long size); + +/* General user-level programmer's API: X server (root) only */ +extern void drmFreeBusid(const char *busid); +extern int drmSetBusid(int fd, const char *busid); +extern int drmAuthMagic(int fd, drm_magic_t magic); +extern int drmAddMap(int fd, + drm_handle_t offset, + drmSize size, + drmMapType type, + drmMapFlags flags, + drm_handle_t * handle); +extern int drmRmMap(int fd, drm_handle_t handle); +extern int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id, + drm_handle_t handle); + +extern int drmAddBufs(int fd, int count, int size, + drmBufDescFlags flags, + int agp_offset); +extern int drmMarkBufs(int fd, double low, double high); +extern int drmCreateContext(int fd, drm_context_t * handle); +extern int drmSetContextFlags(int fd, drm_context_t context, + drm_context_tFlags flags); +extern int drmGetContextFlags(int fd, drm_context_t context, + drm_context_tFlagsPtr flags); +extern int drmAddContextTag(int fd, drm_context_t context, void *tag); +extern int drmDelContextTag(int fd, drm_context_t context); +extern void *drmGetContextTag(int fd, drm_context_t context); +extern drm_context_t * drmGetReservedContextList(int fd, int *count); +extern void drmFreeReservedContextList(drm_context_t *); +extern int drmSwitchToContext(int fd, drm_context_t context); +extern int drmDestroyContext(int fd, drm_context_t handle); +extern int drmCreateDrawable(int fd, drm_drawable_t * handle); +extern int drmDestroyDrawable(int fd, drm_drawable_t handle); +extern int drmUpdateDrawableInfo(int fd, drm_drawable_t handle, + drm_drawable_info_type_t type, + unsigned int num, void *data); +extern int drmCtlInstHandler(int fd, int irq); +extern int drmCtlUninstHandler(int fd); +extern int drmSetClientCap(int fd, uint64_t capability, + uint64_t value); + +extern int drmCrtcGetSequence(int fd, uint32_t crtcId, + uint64_t *sequence, uint64_t *ns); +extern int drmCrtcQueueSequence(int fd, uint32_t crtcId, + uint32_t flags, uint64_t sequence, + uint64_t *sequence_queued, + uint64_t user_data); +/* General user-level programmer's API: authenticated client and/or X */ +extern int drmMap(int fd, + drm_handle_t handle, + drmSize size, + drmAddressPtr address); +extern int drmUnmap(drmAddress address, drmSize size); +extern drmBufInfoPtr drmGetBufInfo(int fd); +extern drmBufMapPtr drmMapBufs(int fd); +extern int drmUnmapBufs(drmBufMapPtr bufs); +extern int drmDMA(int fd, drmDMAReqPtr request); +extern int drmFreeBufs(int fd, int count, int *list); +extern int drmGetLock(int fd, + drm_context_t context, + drmLockFlags flags); +extern int drmUnlock(int fd, drm_context_t context); +extern int drmFinish(int fd, int context, drmLockFlags flags); +extern int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id, + drm_handle_t * handle); + +/* AGP/GART support: X server (root) only */ +extern int drmAgpAcquire(int fd); +extern int drmAgpRelease(int fd); +extern int drmAgpEnable(int fd, unsigned long mode); +extern int drmAgpAlloc(int fd, unsigned long size, + unsigned long type, unsigned long *address, + drm_handle_t *handle); +extern int drmAgpFree(int fd, drm_handle_t handle); +extern int drmAgpBind(int fd, drm_handle_t handle, + unsigned long offset); +extern int drmAgpUnbind(int fd, drm_handle_t handle); + +/* AGP/GART info: authenticated client and/or X */ +extern int drmAgpVersionMajor(int fd); +extern int drmAgpVersionMinor(int fd); +extern unsigned long drmAgpGetMode(int fd); +extern unsigned long drmAgpBase(int fd); /* Physical location */ +extern unsigned long drmAgpSize(int fd); /* Bytes */ +extern unsigned long drmAgpMemoryUsed(int fd); +extern unsigned long drmAgpMemoryAvail(int fd); +extern unsigned int drmAgpVendorId(int fd); +extern unsigned int drmAgpDeviceId(int fd); + +/* PCI scatter/gather support: X server (root) only */ +extern int drmScatterGatherAlloc(int fd, unsigned long size, + drm_handle_t *handle); +extern int drmScatterGatherFree(int fd, drm_handle_t handle); + +extern int drmWaitVBlank(int fd, drmVBlankPtr vbl); + +/* Support routines */ +extern void drmSetServerInfo(drmServerInfoPtr info); +extern int drmError(int err, const char *label); +extern void *drmMalloc(int size); +extern void drmFree(void *pt); + +/* Hash table routines */ +extern void *drmHashCreate(void); +extern int drmHashDestroy(void *t); +extern int drmHashLookup(void *t, unsigned long key, void **value); +extern int drmHashInsert(void *t, unsigned long key, void *value); +extern int drmHashDelete(void *t, unsigned long key); +extern int drmHashFirst(void *t, unsigned long *key, void **value); +extern int drmHashNext(void *t, unsigned long *key, void **value); + +/* PRNG routines */ +extern void *drmRandomCreate(unsigned long seed); +extern int drmRandomDestroy(void *state); +extern unsigned long drmRandom(void *state); +extern double drmRandomDouble(void *state); + +/* Skip list routines */ + +extern void *drmSLCreate(void); +extern int drmSLDestroy(void *l); +extern int drmSLLookup(void *l, unsigned long key, void **value); +extern int drmSLInsert(void *l, unsigned long key, void *value); +extern int drmSLDelete(void *l, unsigned long key); +extern int drmSLNext(void *l, unsigned long *key, void **value); +extern int drmSLFirst(void *l, unsigned long *key, void **value); +extern void drmSLDump(void *l); +extern int drmSLLookupNeighbors(void *l, unsigned long key, + unsigned long *prev_key, void **prev_value, + unsigned long *next_key, void **next_value); + +extern int drmOpenOnce(void *unused, const char *BusID, int *newlyopened); +extern int drmOpenOnceWithType(const char *BusID, int *newlyopened, int type); +extern void drmCloseOnce(int fd); +extern void drmMsg(const char *format, ...) DRM_PRINTFLIKE(1, 2); + +extern int drmSetMaster(int fd); +extern int drmDropMaster(int fd); +extern int drmIsMaster(int fd); + +#define DRM_EVENT_CONTEXT_VERSION 4 + +typedef struct _drmEventContext { + + /* This struct is versioned so we can add more pointers if we + * add more events. */ + int version; + + void (*vblank_handler)(int fd, + unsigned int sequence, + unsigned int tv_sec, + unsigned int tv_usec, + void *user_data); + + void (*page_flip_handler)(int fd, + unsigned int sequence, + unsigned int tv_sec, + unsigned int tv_usec, + void *user_data); + + void (*page_flip_handler2)(int fd, + unsigned int sequence, + unsigned int tv_sec, + unsigned int tv_usec, + unsigned int crtc_id, + void *user_data); + + void (*sequence_handler)(int fd, + uint64_t sequence, + uint64_t ns, + uint64_t user_data); +} drmEventContext, *drmEventContextPtr; + +extern int drmHandleEvent(int fd, drmEventContextPtr evctx); + +extern char *drmGetDeviceNameFromFd(int fd); + +/* Improved version of drmGetDeviceNameFromFd which attributes for any type of + * device/node - card, control or renderD. + */ +extern char *drmGetDeviceNameFromFd2(int fd); +extern int drmGetNodeTypeFromFd(int fd); + +/* Convert between GEM handles and DMA-BUF file descriptors. + * + * Warning: since GEM handles are not reference-counted and are unique per + * DRM file description, the caller is expected to perform its own reference + * counting. drmPrimeFDToHandle is guaranteed to return the same handle for + * different FDs if they reference the same underlying buffer object. This + * could even be a buffer object originally created on the same DRM FD. + * + * When sharing a DRM FD with an API such as EGL or GBM, the caller must not + * use drmPrimeHandleToFD nor drmPrimeFDToHandle. A single user-space + * reference-counting implementation is necessary to avoid double-closing GEM + * handles. + * + * Two processes can't share the same DRM FD and both use it to create or + * import GEM handles, even when using a single user-space reference-counting + * implementation like GBM, because GBM doesn't share its state between + * processes. + */ +extern int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, int *prime_fd); +extern int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle); + +extern int drmCloseBufferHandle(int fd, uint32_t handle); + +extern char *drmGetPrimaryDeviceNameFromFd(int fd); +extern char *drmGetRenderDeviceNameFromFd(int fd); + +#define DRM_BUS_PCI 0 +#define DRM_BUS_USB 1 +#define DRM_BUS_PLATFORM 2 +#define DRM_BUS_HOST1X 3 + +typedef struct _drmPciBusInfo { + uint16_t domain; + uint8_t bus; + uint8_t dev; + uint8_t func; +} drmPciBusInfo, *drmPciBusInfoPtr; + +typedef struct _drmPciDeviceInfo { + uint16_t vendor_id; + uint16_t device_id; + uint16_t subvendor_id; + uint16_t subdevice_id; + uint8_t revision_id; +} drmPciDeviceInfo, *drmPciDeviceInfoPtr; + +typedef struct _drmUsbBusInfo { + uint8_t bus; + uint8_t dev; +} drmUsbBusInfo, *drmUsbBusInfoPtr; + +typedef struct _drmUsbDeviceInfo { + uint16_t vendor; + uint16_t product; +} drmUsbDeviceInfo, *drmUsbDeviceInfoPtr; + +#define DRM_PLATFORM_DEVICE_NAME_LEN 512 + +typedef struct _drmPlatformBusInfo { + char fullname[DRM_PLATFORM_DEVICE_NAME_LEN]; +} drmPlatformBusInfo, *drmPlatformBusInfoPtr; + +typedef struct _drmPlatformDeviceInfo { + char **compatible; /* NULL terminated list of compatible strings */ +} drmPlatformDeviceInfo, *drmPlatformDeviceInfoPtr; + +#define DRM_HOST1X_DEVICE_NAME_LEN 512 + +typedef struct _drmHost1xBusInfo { + char fullname[DRM_HOST1X_DEVICE_NAME_LEN]; +} drmHost1xBusInfo, *drmHost1xBusInfoPtr; + +typedef struct _drmHost1xDeviceInfo { + char **compatible; /* NULL terminated list of compatible strings */ +} drmHost1xDeviceInfo, *drmHost1xDeviceInfoPtr; + +typedef struct _drmDevice { + char **nodes; /* DRM_NODE_MAX sized array */ + int available_nodes; /* DRM_NODE_* bitmask */ + int bustype; + union { + drmPciBusInfoPtr pci; + drmUsbBusInfoPtr usb; + drmPlatformBusInfoPtr platform; + drmHost1xBusInfoPtr host1x; + } businfo; + union { + drmPciDeviceInfoPtr pci; + drmUsbDeviceInfoPtr usb; + drmPlatformDeviceInfoPtr platform; + drmHost1xDeviceInfoPtr host1x; + } deviceinfo; +} drmDevice, *drmDevicePtr; + +extern int drmGetDevice(int fd, drmDevicePtr *device); +extern void drmFreeDevice(drmDevicePtr *device); + +extern int drmGetDevices(drmDevicePtr devices[], int max_devices); +extern void drmFreeDevices(drmDevicePtr devices[], int count); + +#define DRM_DEVICE_GET_PCI_REVISION (1 << 0) +extern int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device); +extern int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], int max_devices); + +extern int drmGetDeviceFromDevId(dev_t dev_id, uint32_t flags, drmDevicePtr *device); + +extern int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b); + +extern int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle); +extern int drmSyncobjDestroy(int fd, uint32_t handle); +extern int drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd); +extern int drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle); + +extern int drmSyncobjImportSyncFile(int fd, uint32_t handle, int sync_file_fd); +extern int drmSyncobjExportSyncFile(int fd, uint32_t handle, int *sync_file_fd); +extern int drmSyncobjWait(int fd, uint32_t *handles, unsigned num_handles, + int64_t timeout_nsec, unsigned flags, + uint32_t *first_signaled); +extern int drmSyncobjReset(int fd, const uint32_t *handles, uint32_t handle_count); +extern int drmSyncobjSignal(int fd, const uint32_t *handles, uint32_t handle_count); +extern int drmSyncobjTimelineSignal(int fd, const uint32_t *handles, + uint64_t *points, uint32_t handle_count); +extern int drmSyncobjTimelineWait(int fd, uint32_t *handles, uint64_t *points, + unsigned num_handles, + int64_t timeout_nsec, unsigned flags, + uint32_t *first_signaled); +extern int drmSyncobjQuery(int fd, uint32_t *handles, uint64_t *points, + uint32_t handle_count); +extern int drmSyncobjQuery2(int fd, uint32_t *handles, uint64_t *points, + uint32_t handle_count, uint32_t flags); +extern int drmSyncobjTransfer(int fd, + uint32_t dst_handle, uint64_t dst_point, + uint32_t src_handle, uint64_t src_point, + uint32_t flags); + +extern char * +drmGetFormatModifierVendor(uint64_t modifier); + +extern char * +drmGetFormatModifierName(uint64_t modifier); + +extern char * +drmGetFormatName(uint32_t format); + +#ifndef fourcc_mod_get_vendor +#define fourcc_mod_get_vendor(modifier) \ + (((modifier) >> 56) & 0xff) +#endif + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/xf86drmHash.c b/xf86drmHash.c new file mode 100644 index 0000000..2cf2b80 --- /dev/null +++ b/xf86drmHash.c @@ -0,0 +1,242 @@ +/* xf86drmHash.c -- Small hash table support for integer -> integer mapping + * Created: Sun Apr 18 09:35:45 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * 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, 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT 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. + * + * Authors: Rickard E. (Rik) Faith + * + * DESCRIPTION + * + * This file contains a straightforward implementation of a fixed-sized + * hash table using self-organizing linked lists [Knuth73, pp. 398-399] for + * collision resolution. There are two potentially interesting things + * about this implementation: + * + * 1) The table is power-of-two sized. Prime sized tables are more + * traditional, but do not have a significant advantage over power-of-two + * sized table, especially when double hashing is not used for collision + * resolution. + * + * 2) The hash computation uses a table of random integers [Hanson97, + * pp. 39-41]. + * + * FUTURE ENHANCEMENTS + * + * With a table size of 512, the current implementation is sufficient for a + * few hundred keys. Since this is well above the expected size of the + * tables for which this implementation was designed, the implementation of + * dynamic hash tables was postponed until the need arises. A common (and + * naive) approach to dynamic hash table implementation simply creates a + * new hash table when necessary, rehashes all the data into the new table, + * and destroys the old table. The approach in [Larson88] is superior in + * two ways: 1) only a portion of the table is expanded when needed, + * distributing the expansion cost over several insertions, and 2) portions + * of the table can be locked, enabling a scalable thread-safe + * implementation. + * + * REFERENCES + * + * [Hanson97] David R. Hanson. C Interfaces and Implementations: + * Techniques for Creating Reusable Software. Reading, Massachusetts: + * Addison-Wesley, 1997. + * + * [Knuth73] Donald E. Knuth. The Art of Computer Programming. Volume 3: + * Sorting and Searching. Reading, Massachusetts: Addison-Wesley, 1973. + * + * [Larson88] Per-Ake Larson. "Dynamic Hash Tables". CACM 31(4), April + * 1988, pp. 446-457. + * + */ + +#include +#include + +#include "libdrm_macros.h" +#include "xf86drm.h" +#include "xf86drmHash.h" + +#define HASH_MAGIC 0xdeadbeef + +static unsigned long HashHash(unsigned long key) +{ + unsigned long hash = 0; + unsigned long tmp = key; + static int init = 0; + static unsigned long scatter[256]; + int i; + + if (!init) { + void *state; + state = drmRandomCreate(37); + for (i = 0; i < 256; i++) scatter[i] = drmRandom(state); + drmRandomDestroy(state); + ++init; + } + + while (tmp) { + hash = (hash << 1) + scatter[tmp & 0xff]; + tmp >>= 8; + } + + hash %= HASH_SIZE; + return hash; +} + +drm_public void *drmHashCreate(void) +{ + HashTablePtr table; + + table = drmMalloc(sizeof(*table)); + if (!table) return NULL; + table->magic = HASH_MAGIC; + + return table; +} + +drm_public int drmHashDestroy(void *t) +{ + HashTablePtr table = (HashTablePtr)t; + HashBucketPtr bucket; + HashBucketPtr next; + int i; + + if (table->magic != HASH_MAGIC) return -1; /* Bad magic */ + + for (i = 0; i < HASH_SIZE; i++) { + for (bucket = table->buckets[i]; bucket;) { + next = bucket->next; + drmFree(bucket); + bucket = next; + } + } + drmFree(table); + return 0; +} + +/* Find the bucket and organize the list so that this bucket is at the + top. */ + +static HashBucketPtr HashFind(HashTablePtr table, + unsigned long key, unsigned long *h) +{ + unsigned long hash = HashHash(key); + HashBucketPtr prev = NULL; + HashBucketPtr bucket; + + if (h) *h = hash; + + for (bucket = table->buckets[hash]; bucket; bucket = bucket->next) { + if (bucket->key == key) { + if (prev) { + /* Organize */ + prev->next = bucket->next; + bucket->next = table->buckets[hash]; + table->buckets[hash] = bucket; + ++table->partials; + } else { + ++table->hits; + } + return bucket; + } + prev = bucket; + } + ++table->misses; + return NULL; +} + +drm_public int drmHashLookup(void *t, unsigned long key, void **value) +{ + HashTablePtr table = (HashTablePtr)t; + HashBucketPtr bucket; + + if (!table || table->magic != HASH_MAGIC) return -1; /* Bad magic */ + + bucket = HashFind(table, key, NULL); + if (!bucket) return 1; /* Not found */ + *value = bucket->value; + return 0; /* Found */ +} + +drm_public int drmHashInsert(void *t, unsigned long key, void *value) +{ + HashTablePtr table = (HashTablePtr)t; + HashBucketPtr bucket; + unsigned long hash; + + if (table->magic != HASH_MAGIC) return -1; /* Bad magic */ + + if (HashFind(table, key, &hash)) return 1; /* Already in table */ + + bucket = drmMalloc(sizeof(*bucket)); + if (!bucket) return -1; /* Error */ + bucket->key = key; + bucket->value = value; + bucket->next = table->buckets[hash]; + table->buckets[hash] = bucket; + return 0; /* Added to table */ +} + +drm_public int drmHashDelete(void *t, unsigned long key) +{ + HashTablePtr table = (HashTablePtr)t; + unsigned long hash; + HashBucketPtr bucket; + + if (table->magic != HASH_MAGIC) return -1; /* Bad magic */ + + bucket = HashFind(table, key, &hash); + + if (!bucket) return 1; /* Not found */ + + table->buckets[hash] = bucket->next; + drmFree(bucket); + return 0; +} + +drm_public int drmHashNext(void *t, unsigned long *key, void **value) +{ + HashTablePtr table = (HashTablePtr)t; + + while (table->p0 < HASH_SIZE) { + if (table->p1) { + *key = table->p1->key; + *value = table->p1->value; + table->p1 = table->p1->next; + return 1; + } + table->p1 = table->buckets[table->p0]; + ++table->p0; + } + return 0; +} + +drm_public int drmHashFirst(void *t, unsigned long *key, void **value) +{ + HashTablePtr table = (HashTablePtr)t; + + if (table->magic != HASH_MAGIC) return -1; /* Bad magic */ + + table->p0 = 0; + table->p1 = table->buckets[0]; + return drmHashNext(table, key, value); +} diff --git a/xf86drmHash.h b/xf86drmHash.h new file mode 100644 index 0000000..38fd84b --- /dev/null +++ b/xf86drmHash.h @@ -0,0 +1,47 @@ +/* + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * 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, 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT 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. + * + * Authors: Rickard E. (Rik) Faith + */ + +#define HASH_SIZE 512 /* Good for about 100 entries */ + /* If you change this value, you probably + have to change the HashHash hashing + function! */ + +typedef struct HashBucket { + unsigned long key; + void *value; + struct HashBucket *next; +} HashBucket, *HashBucketPtr; + +typedef struct HashTable { + unsigned long magic; + unsigned long entries; + unsigned long hits; /* At top of linked list */ + unsigned long partials; /* Not at top of linked list */ + unsigned long misses; /* Not in table */ + HashBucketPtr buckets[HASH_SIZE]; + int p0; + HashBucketPtr p1; +} HashTable, *HashTablePtr; diff --git a/xf86drmMode.c b/xf86drmMode.c new file mode 100644 index 0000000..22a8a7c --- /dev/null +++ b/xf86drmMode.c @@ -0,0 +1,1874 @@ +/* + * \file xf86drmMode.c + * Header for DRM modesetting interface. + * + * \author Jakob Bornecrantz + * + * \par Acknowledgements: + * Feb 2007, Dave Airlie + */ + +/* + * Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright (c) 2007-2008 Dave Airlie + * Copyright (c) 2007-2008 Jakob Bornecrantz + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#if HAVE_SYS_SYSCTL_H +#ifdef __FreeBSD__ +#include +#endif +#include +#endif +#include +#include + +#include "libdrm_macros.h" +#include "xf86drmMode.h" +#include "xf86drm.h" +#include +#include +#include +#include +#include +#include + +#define memclear(s) memset(&s, 0, sizeof(s)) + +#define U642VOID(x) ((void *)(unsigned long)(x)) +#define VOID2U64(x) ((uint64_t)(unsigned long)(x)) + +static inline int DRM_IOCTL(int fd, unsigned long cmd, void *arg) +{ + int ret = drmIoctl(fd, cmd, arg); + return ret < 0 ? -errno : ret; +} + +/* + * Util functions + */ + +static void* drmAllocCpy(char *array, int count, int entry_size) +{ + char *r; + int i; + + if (!count || !array || !entry_size) + return 0; + + if (!(r = drmMalloc(count*entry_size))) + return 0; + + for (i = 0; i < count; i++) + memcpy(r+(entry_size*i), array+(entry_size*i), entry_size); + + return r; +} + +/* + * A couple of free functions. + */ + +drm_public void drmModeFreeModeInfo(drmModeModeInfoPtr ptr) +{ + if (!ptr) + return; + + drmFree(ptr); +} + +drm_public void drmModeFreeResources(drmModeResPtr ptr) +{ + if (!ptr) + return; + + drmFree(ptr->fbs); + drmFree(ptr->crtcs); + drmFree(ptr->connectors); + drmFree(ptr->encoders); + drmFree(ptr); +} + +drm_public void drmModeFreeFB(drmModeFBPtr ptr) +{ + if (!ptr) + return; + + /* we might add more frees later. */ + drmFree(ptr); +} + +drm_public void drmModeFreeCrtc(drmModeCrtcPtr ptr) +{ + if (!ptr) + return; + + drmFree(ptr); +} + +drm_public void drmModeFreeConnector(drmModeConnectorPtr ptr) +{ + if (!ptr) + return; + + drmFree(ptr->encoders); + drmFree(ptr->prop_values); + drmFree(ptr->props); + drmFree(ptr->modes); + drmFree(ptr); +} + +drm_public void drmModeFreeEncoder(drmModeEncoderPtr ptr) +{ + drmFree(ptr); +} + +/* + * ModeSetting functions. + */ + +drm_public int drmIsKMS(int fd) +{ + struct drm_mode_card_res res = {0}; + + if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res) != 0) + return 0; + + return res.count_crtcs > 0 && res.count_connectors > 0 && res.count_encoders > 0; +} + +drm_public drmModeResPtr drmModeGetResources(int fd) +{ + struct drm_mode_card_res res, counts; + drmModeResPtr r = 0; + +retry: + memclear(res); + if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) + return 0; + + counts = res; + + if (res.count_fbs) { + res.fb_id_ptr = VOID2U64(drmMalloc(res.count_fbs*sizeof(uint32_t))); + if (!res.fb_id_ptr) + goto err_allocs; + } + if (res.count_crtcs) { + res.crtc_id_ptr = VOID2U64(drmMalloc(res.count_crtcs*sizeof(uint32_t))); + if (!res.crtc_id_ptr) + goto err_allocs; + } + if (res.count_connectors) { + res.connector_id_ptr = VOID2U64(drmMalloc(res.count_connectors*sizeof(uint32_t))); + if (!res.connector_id_ptr) + goto err_allocs; + } + if (res.count_encoders) { + res.encoder_id_ptr = VOID2U64(drmMalloc(res.count_encoders*sizeof(uint32_t))); + if (!res.encoder_id_ptr) + goto err_allocs; + } + + if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) + goto err_allocs; + + /* The number of available connectors and etc may have changed with a + * hotplug event in between the ioctls, in which case the field is + * silently ignored by the kernel. + */ + if (counts.count_fbs < res.count_fbs || + counts.count_crtcs < res.count_crtcs || + counts.count_connectors < res.count_connectors || + counts.count_encoders < res.count_encoders) + { + drmFree(U642VOID(res.fb_id_ptr)); + drmFree(U642VOID(res.crtc_id_ptr)); + drmFree(U642VOID(res.connector_id_ptr)); + drmFree(U642VOID(res.encoder_id_ptr)); + + goto retry; + } + + /* + * return + */ + if (!(r = drmMalloc(sizeof(*r)))) + goto err_allocs; + + r->min_width = res.min_width; + r->max_width = res.max_width; + r->min_height = res.min_height; + r->max_height = res.max_height; + r->count_fbs = res.count_fbs; + r->count_crtcs = res.count_crtcs; + r->count_connectors = res.count_connectors; + r->count_encoders = res.count_encoders; + + r->fbs = drmAllocCpy(U642VOID(res.fb_id_ptr), res.count_fbs, sizeof(uint32_t)); + r->crtcs = drmAllocCpy(U642VOID(res.crtc_id_ptr), res.count_crtcs, sizeof(uint32_t)); + r->connectors = drmAllocCpy(U642VOID(res.connector_id_ptr), res.count_connectors, sizeof(uint32_t)); + r->encoders = drmAllocCpy(U642VOID(res.encoder_id_ptr), res.count_encoders, sizeof(uint32_t)); + if ((res.count_fbs && !r->fbs) || + (res.count_crtcs && !r->crtcs) || + (res.count_connectors && !r->connectors) || + (res.count_encoders && !r->encoders)) + { + drmFree(r->fbs); + drmFree(r->crtcs); + drmFree(r->connectors); + drmFree(r->encoders); + drmFree(r); + r = 0; + } + +err_allocs: + drmFree(U642VOID(res.fb_id_ptr)); + drmFree(U642VOID(res.crtc_id_ptr)); + drmFree(U642VOID(res.connector_id_ptr)); + drmFree(U642VOID(res.encoder_id_ptr)); + + return r; +} + + +drm_public int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, + uint8_t bpp, uint32_t pitch, uint32_t bo_handle, + uint32_t *buf_id) +{ + struct drm_mode_fb_cmd f; + int ret; + + memclear(f); + f.width = width; + f.height = height; + f.pitch = pitch; + f.bpp = bpp; + f.depth = depth; + f.handle = bo_handle; + + if ((ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ADDFB, &f))) + return ret; + + *buf_id = f.fb_id; + return 0; +} + +drm_public int drmModeAddFB2WithModifiers(int fd, uint32_t width, + uint32_t height, uint32_t pixel_format, const uint32_t bo_handles[4], + const uint32_t pitches[4], const uint32_t offsets[4], + const uint64_t modifier[4], uint32_t *buf_id, uint32_t flags) +{ + struct drm_mode_fb_cmd2 f; + int ret; + + memclear(f); + f.width = width; + f.height = height; + f.pixel_format = pixel_format; + f.flags = flags; + memcpy(f.handles, bo_handles, 4 * sizeof(bo_handles[0])); + memcpy(f.pitches, pitches, 4 * sizeof(pitches[0])); + memcpy(f.offsets, offsets, 4 * sizeof(offsets[0])); + if (modifier) + memcpy(f.modifier, modifier, 4 * sizeof(modifier[0])); + + if ((ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ADDFB2, &f))) + return ret; + + *buf_id = f.fb_id; + return 0; +} + +drm_public int drmModeAddFB2(int fd, uint32_t width, uint32_t height, + uint32_t pixel_format, const uint32_t bo_handles[4], + const uint32_t pitches[4], const uint32_t offsets[4], + uint32_t *buf_id, uint32_t flags) +{ + return drmModeAddFB2WithModifiers(fd, width, height, + pixel_format, bo_handles, + pitches, offsets, NULL, + buf_id, flags); +} + +drm_public int drmModeRmFB(int fd, uint32_t bufferId) +{ + return DRM_IOCTL(fd, DRM_IOCTL_MODE_RMFB, &bufferId); +} + +drm_public drmModeFBPtr drmModeGetFB(int fd, uint32_t buf) +{ + struct drm_mode_fb_cmd info; + drmModeFBPtr r; + + memclear(info); + info.fb_id = buf; + + if (drmIoctl(fd, DRM_IOCTL_MODE_GETFB, &info)) + return NULL; + + if (!(r = drmMalloc(sizeof(*r)))) + return NULL; + + r->fb_id = info.fb_id; + r->width = info.width; + r->height = info.height; + r->pitch = info.pitch; + r->bpp = info.bpp; + r->handle = info.handle; + r->depth = info.depth; + + return r; +} + +drm_public int drmModeDirtyFB(int fd, uint32_t bufferId, + drmModeClipPtr clips, uint32_t num_clips) +{ + struct drm_mode_fb_dirty_cmd dirty; + + memclear(dirty); + dirty.fb_id = bufferId; + dirty.clips_ptr = VOID2U64(clips); + dirty.num_clips = num_clips; + + return DRM_IOCTL(fd, DRM_IOCTL_MODE_DIRTYFB, &dirty); +} + +/* + * Crtc functions + */ + +drm_public drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) +{ + struct drm_mode_crtc crtc; + drmModeCrtcPtr r; + + memclear(crtc); + crtc.crtc_id = crtcId; + + if (drmIoctl(fd, DRM_IOCTL_MODE_GETCRTC, &crtc)) + return 0; + + /* + * return + */ + + if (!(r = drmMalloc(sizeof(*r)))) + return 0; + + r->crtc_id = crtc.crtc_id; + r->x = crtc.x; + r->y = crtc.y; + r->mode_valid = crtc.mode_valid; + if (r->mode_valid) { + memcpy(&r->mode, &crtc.mode, sizeof(struct drm_mode_modeinfo)); + r->width = crtc.mode.hdisplay; + r->height = crtc.mode.vdisplay; + } + r->buffer_id = crtc.fb_id; + r->gamma_size = crtc.gamma_size; + return r; +} + +drm_public int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, + uint32_t x, uint32_t y, uint32_t *connectors, int count, + drmModeModeInfoPtr mode) +{ + struct drm_mode_crtc crtc; + + memclear(crtc); + crtc.x = x; + crtc.y = y; + crtc.crtc_id = crtcId; + crtc.fb_id = bufferId; + crtc.set_connectors_ptr = VOID2U64(connectors); + crtc.count_connectors = count; + if (mode) { + memcpy(&crtc.mode, mode, sizeof(struct drm_mode_modeinfo)); + crtc.mode_valid = 1; + } + + return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETCRTC, &crtc); +} + +/* + * Cursor manipulation + */ + +drm_public int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle, + uint32_t width, uint32_t height) +{ + struct drm_mode_cursor arg; + + memclear(arg); + arg.flags = DRM_MODE_CURSOR_BO; + arg.crtc_id = crtcId; + arg.width = width; + arg.height = height; + arg.handle = bo_handle; + + return DRM_IOCTL(fd, DRM_IOCTL_MODE_CURSOR, &arg); +} + +drm_public int drmModeSetCursor2(int fd, uint32_t crtcId, uint32_t bo_handle, + uint32_t width, uint32_t height, int32_t hot_x, + int32_t hot_y) +{ + struct drm_mode_cursor2 arg; + + memclear(arg); + arg.flags = DRM_MODE_CURSOR_BO; + arg.crtc_id = crtcId; + arg.width = width; + arg.height = height; + arg.handle = bo_handle; + arg.hot_x = hot_x; + arg.hot_y = hot_y; + + return DRM_IOCTL(fd, DRM_IOCTL_MODE_CURSOR2, &arg); +} + +drm_public int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y) +{ + struct drm_mode_cursor arg; + + memclear(arg); + arg.flags = DRM_MODE_CURSOR_MOVE; + arg.crtc_id = crtcId; + arg.x = x; + arg.y = y; + + return DRM_IOCTL(fd, DRM_IOCTL_MODE_CURSOR, &arg); +} + +/* + * Encoder get + */ +drm_public drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id) +{ + struct drm_mode_get_encoder enc; + drmModeEncoderPtr r = NULL; + + memclear(enc); + enc.encoder_id = encoder_id; + + if (drmIoctl(fd, DRM_IOCTL_MODE_GETENCODER, &enc)) + return 0; + + if (!(r = drmMalloc(sizeof(*r)))) + return 0; + + r->encoder_id = enc.encoder_id; + r->crtc_id = enc.crtc_id; + r->encoder_type = enc.encoder_type; + r->possible_crtcs = enc.possible_crtcs; + r->possible_clones = enc.possible_clones; + + return r; +} + +/* + * Connector manipulation + */ +static drmModeConnectorPtr +_drmModeGetConnector(int fd, uint32_t connector_id, int probe) +{ + struct drm_mode_get_connector conn, counts; + drmModeConnectorPtr r = NULL; + struct drm_mode_modeinfo stack_mode; + + memclear(conn); + conn.connector_id = connector_id; + if (!probe) { + conn.count_modes = 1; + conn.modes_ptr = VOID2U64(&stack_mode); + } + + if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn)) + return 0; + +retry: + counts = conn; + + if (conn.count_props) { + conn.props_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint32_t))); + if (!conn.props_ptr) + goto err_allocs; + conn.prop_values_ptr = VOID2U64(drmMalloc(conn.count_props*sizeof(uint64_t))); + if (!conn.prop_values_ptr) + goto err_allocs; + } + + if (conn.count_modes) { + conn.modes_ptr = VOID2U64(drmMalloc(conn.count_modes*sizeof(struct drm_mode_modeinfo))); + if (!conn.modes_ptr) + goto err_allocs; + } else { + conn.count_modes = 1; + conn.modes_ptr = VOID2U64(&stack_mode); + } + + if (conn.count_encoders) { + conn.encoders_ptr = VOID2U64(drmMalloc(conn.count_encoders*sizeof(uint32_t))); + if (!conn.encoders_ptr) + goto err_allocs; + } + + if (drmIoctl(fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn)) + goto err_allocs; + + /* The number of available connectors and etc may have changed with a + * hotplug event in between the ioctls, in which case the field is + * silently ignored by the kernel. + */ + if (counts.count_props < conn.count_props || + counts.count_modes < conn.count_modes || + counts.count_encoders < conn.count_encoders) { + drmFree(U642VOID(conn.props_ptr)); + drmFree(U642VOID(conn.prop_values_ptr)); + if (U642VOID(conn.modes_ptr) != &stack_mode) + drmFree(U642VOID(conn.modes_ptr)); + drmFree(U642VOID(conn.encoders_ptr)); + + goto retry; + } + + if(!(r = drmMalloc(sizeof(*r)))) { + goto err_allocs; + } + + r->connector_id = conn.connector_id; + r->encoder_id = conn.encoder_id; + r->connection = conn.connection; + r->mmWidth = conn.mm_width; + r->mmHeight = conn.mm_height; + /* convert subpixel from kernel to userspace */ + r->subpixel = conn.subpixel + 1; + r->count_modes = conn.count_modes; + r->count_props = conn.count_props; + r->props = drmAllocCpy(U642VOID(conn.props_ptr), conn.count_props, sizeof(uint32_t)); + r->prop_values = drmAllocCpy(U642VOID(conn.prop_values_ptr), conn.count_props, sizeof(uint64_t)); + r->modes = drmAllocCpy(U642VOID(conn.modes_ptr), conn.count_modes, sizeof(struct drm_mode_modeinfo)); + r->count_encoders = conn.count_encoders; + r->encoders = drmAllocCpy(U642VOID(conn.encoders_ptr), conn.count_encoders, sizeof(uint32_t)); + r->connector_type = conn.connector_type; + r->connector_type_id = conn.connector_type_id; + + if ((r->count_props && !r->props) || + (r->count_props && !r->prop_values) || + (r->count_modes && !r->modes) || + (r->count_encoders && !r->encoders)) { + drmFree(r->props); + drmFree(r->prop_values); + drmFree(r->modes); + drmFree(r->encoders); + drmFree(r); + r = 0; + } + +err_allocs: + drmFree(U642VOID(conn.prop_values_ptr)); + drmFree(U642VOID(conn.props_ptr)); + if (U642VOID(conn.modes_ptr) != &stack_mode) + drmFree(U642VOID(conn.modes_ptr)); + drmFree(U642VOID(conn.encoders_ptr)); + + return r; +} + +drm_public drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id) +{ + return _drmModeGetConnector(fd, connector_id, 1); +} + +drm_public drmModeConnectorPtr drmModeGetConnectorCurrent(int fd, uint32_t connector_id) +{ + return _drmModeGetConnector(fd, connector_id, 0); +} + +drm_public uint32_t drmModeConnectorGetPossibleCrtcs(int fd, + const drmModeConnector *connector) +{ + drmModeEncoder *encoder; + int i; + uint32_t possible_crtcs; + + possible_crtcs = 0; + for (i = 0; i < connector->count_encoders; i++) { + encoder = drmModeGetEncoder(fd, connector->encoders[i]); + if (!encoder) { + return 0; + } + + possible_crtcs |= encoder->possible_crtcs; + drmModeFreeEncoder(encoder); + } + + if (possible_crtcs == 0) + errno = ENOENT; + return possible_crtcs; +} + +drm_public int drmModeAttachMode(int fd, uint32_t connector_id, drmModeModeInfoPtr mode_info) +{ + struct drm_mode_mode_cmd res; + + memclear(res); + memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo)); + res.connector_id = connector_id; + + return DRM_IOCTL(fd, DRM_IOCTL_MODE_ATTACHMODE, &res); +} + +drm_public int drmModeDetachMode(int fd, uint32_t connector_id, drmModeModeInfoPtr mode_info) +{ + struct drm_mode_mode_cmd res; + + memclear(res); + memcpy(&res.mode, mode_info, sizeof(struct drm_mode_modeinfo)); + res.connector_id = connector_id; + + return DRM_IOCTL(fd, DRM_IOCTL_MODE_DETACHMODE, &res); +} + +drm_public drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id) +{ + struct drm_mode_get_property prop; + drmModePropertyPtr r; + + memclear(prop); + prop.prop_id = property_id; + + if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) + return 0; + + if (prop.count_values) + prop.values_ptr = VOID2U64(drmMalloc(prop.count_values * sizeof(uint64_t))); + + if (prop.count_enum_blobs && (prop.flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK))) + prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(struct drm_mode_property_enum))); + + if (prop.count_enum_blobs && (prop.flags & DRM_MODE_PROP_BLOB)) { + prop.values_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t))); + prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(uint32_t))); + } + + if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) { + r = NULL; + goto err_allocs; + } + + if (!(r = drmMalloc(sizeof(*r)))) + goto err_allocs; + + r->prop_id = prop.prop_id; + r->count_values = prop.count_values; + + r->flags = prop.flags; + if (prop.count_values) + r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_values, sizeof(uint64_t)); + if (prop.flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) { + r->count_enums = prop.count_enum_blobs; + r->enums = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(struct drm_mode_property_enum)); + } else if (prop.flags & DRM_MODE_PROP_BLOB) { + r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_enum_blobs, sizeof(uint32_t)); + r->blob_ids = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(uint32_t)); + r->count_blobs = prop.count_enum_blobs; + } + strncpy(r->name, prop.name, DRM_PROP_NAME_LEN); + r->name[DRM_PROP_NAME_LEN-1] = 0; + +err_allocs: + drmFree(U642VOID(prop.values_ptr)); + drmFree(U642VOID(prop.enum_blob_ptr)); + + return r; +} + +drm_public void drmModeFreeProperty(drmModePropertyPtr ptr) +{ + if (!ptr) + return; + + drmFree(ptr->values); + drmFree(ptr->enums); + drmFree(ptr->blob_ids); + drmFree(ptr); +} + +drm_public drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, + uint32_t blob_id) +{ + struct drm_mode_get_blob blob; + drmModePropertyBlobPtr r; + + memclear(blob); + blob.blob_id = blob_id; + + if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) + return NULL; + + if (blob.length) + blob.data = VOID2U64(drmMalloc(blob.length)); + + if (drmIoctl(fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) { + r = NULL; + goto err_allocs; + } + + if (!(r = drmMalloc(sizeof(*r)))) + goto err_allocs; + + r->id = blob.blob_id; + r->length = blob.length; + r->data = drmAllocCpy(U642VOID(blob.data), 1, blob.length); + +err_allocs: + drmFree(U642VOID(blob.data)); + return r; +} + +static inline const uint32_t * +get_formats_ptr(const struct drm_format_modifier_blob *blob) +{ + return (const uint32_t *)(((uint8_t *)blob) + blob->formats_offset); +} + +static inline const struct drm_format_modifier * +get_modifiers_ptr(const struct drm_format_modifier_blob *blob) +{ + return (const struct drm_format_modifier *)(((uint8_t *)blob) + + blob->modifiers_offset); +} + +static bool _drmModeFormatModifierGetNext(const drmModePropertyBlobRes *blob, + drmModeFormatModifierIterator *iter) +{ + const struct drm_format_modifier *blob_modifiers, *mod; + const struct drm_format_modifier_blob *fmt_mod_blob; + const uint32_t *blob_formats; + + assert(blob && iter); + + fmt_mod_blob = blob->data; + blob_modifiers = get_modifiers_ptr(fmt_mod_blob); + blob_formats = get_formats_ptr(fmt_mod_blob); + + /* fmt_idx and mod_idx designate the number of processed formats + * and modifiers. + */ + if (iter->fmt_idx >= fmt_mod_blob->count_formats || + iter->mod_idx >= fmt_mod_blob->count_modifiers) + return false; + + iter->fmt = blob_formats[iter->fmt_idx]; + iter->mod = DRM_FORMAT_MOD_INVALID; + + /* From the latest valid found, get the next valid modifier */ + while (iter->mod_idx < fmt_mod_blob->count_modifiers) { + mod = &blob_modifiers[iter->mod_idx++]; + + /* Check if the format that fmt_idx designates, belongs to + * this modifier 64-bit window selected via mod->offset. + */ + if (iter->fmt_idx < mod->offset || + iter->fmt_idx >= mod->offset + 64) + continue; + if (!(mod->formats & (1 << (iter->fmt_idx - mod->offset)))) + continue; + + iter->mod = mod->modifier; + break; + } + + if (iter->mod_idx == fmt_mod_blob->count_modifiers) { + iter->mod_idx = 0; + iter->fmt_idx++; + } + + /* Since mod_idx reset, in order for the caller to iterate over + * the last modifier of the last format, always return true here + * and early return from the next call. + */ + return true; +} + +/** + * Iterate over formats first and then over modifiers. On each call, iter->fmt + * is retained until all associated modifiers are returned. Then, either update + * iter->fmt with the next format, or exit if there aren't any left. + * + * NOTE: clients should not make any assumption on mod_idx and fmt_idx values + * + * @blob: valid kernel blob holding formats and modifiers + * @iter: input and output iterator data. Iter data must be initialised to zero + * @return: false, on error or there aren't any further formats or modifiers left. + * true, on success and there are more formats or modifiers. + */ +drm_public bool drmModeFormatModifierBlobIterNext(const drmModePropertyBlobRes *blob, + drmModeFormatModifierIterator *iter) +{ + drmModeFormatModifierIterator tmp; + bool has_fmt; + + if (!blob || !iter) + return false; + + tmp.fmt_idx = iter->fmt_idx; + tmp.mod_idx = iter->mod_idx; + + /* With the current state of things, DRM/KMS drivers are allowed to + * construct blobs having formats and no modifiers. Userspace can't + * legitimately abort in such cases. + * + * While waiting for the kernel to perhaps disallow formats with no + * modifiers in IN_FORMATS blobs, skip the format altogether. + */ + do { + has_fmt = _drmModeFormatModifierGetNext(blob, &tmp); + if (has_fmt && tmp.mod != DRM_FORMAT_MOD_INVALID) + *iter = tmp; + + } while (has_fmt && tmp.mod == DRM_FORMAT_MOD_INVALID); + + return has_fmt; +} + +drm_public void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr) +{ + if (!ptr) + return; + + drmFree(ptr->data); + drmFree(ptr); +} + +drm_public int drmModeConnectorSetProperty(int fd, uint32_t connector_id, + uint32_t property_id, + uint64_t value) +{ + struct drm_mode_connector_set_property osp; + + memclear(osp); + osp.connector_id = connector_id; + osp.prop_id = property_id; + osp.value = value; + + return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETPROPERTY, &osp); +} + +/* + * checks if a modesetting capable driver has attached to the pci id + * returns 0 if modesetting supported. + * -EINVAL or invalid bus id + * -ENOSYS if no modesetting support +*/ +drm_public int drmCheckModesettingSupported(const char *busid) +{ +#if defined (__linux__) + char pci_dev_dir[1024]; + int domain, bus, dev, func; + DIR *sysdir; + struct dirent *dent; + int found = 0, ret; + + ret = sscanf(busid, "pci:%04x:%02x:%02x.%d", &domain, &bus, &dev, &func); + if (ret != 4) + return -EINVAL; + + sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/drm", + domain, bus, dev, func); + + sysdir = opendir(pci_dev_dir); + if (sysdir) { + dent = readdir(sysdir); + while (dent) { + if (!strncmp(dent->d_name, "controlD", 8)) { + found = 1; + break; + } + + dent = readdir(sysdir); + } + closedir(sysdir); + if (found) + return 0; + } + + sprintf(pci_dev_dir, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/", + domain, bus, dev, func); + + sysdir = opendir(pci_dev_dir); + if (!sysdir) + return -EINVAL; + + dent = readdir(sysdir); + while (dent) { + if (!strncmp(dent->d_name, "drm:controlD", 12)) { + found = 1; + break; + } + + dent = readdir(sysdir); + } + + closedir(sysdir); + if (found) + return 0; +#elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__) + char sbusid[1024]; + char oid[128]; + int i, modesetting, ret; + size_t len; + + /* How many GPUs do we expect in the machine ? */ + for (i = 0; i < 10; i++) { + snprintf(oid, sizeof(oid), "hw.dri.%d.busid", i); + len = sizeof(sbusid); + ret = sysctlbyname(oid, sbusid, &len, NULL, 0); + if (ret == -1) { + if (errno == ENOENT) + continue; + return -EINVAL; + } + if (strcmp(sbusid, busid) != 0) + continue; + snprintf(oid, sizeof(oid), "hw.dri.%d.modesetting", i); + len = sizeof(modesetting); + ret = sysctlbyname(oid, &modesetting, &len, NULL, 0); + if (ret == -1 || len != sizeof(modesetting)) + return -EINVAL; + return (modesetting ? 0 : -ENOSYS); + } +#elif defined(__DragonFly__) + return 0; +#elif defined(__OpenBSD__) + int fd; + struct drm_mode_card_res res; + drmModeResPtr r = 0; + + if ((fd = drmOpen(NULL, busid)) < 0) + return -EINVAL; + + memset(&res, 0, sizeof(struct drm_mode_card_res)); + + if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) { + drmClose(fd); + return -errno; + } + + drmClose(fd); + return 0; +#endif + return -ENOSYS; +} + +drm_public int drmModeCrtcGetGamma(int fd, uint32_t crtc_id, uint32_t size, + uint16_t *red, uint16_t *green, + uint16_t *blue) +{ + struct drm_mode_crtc_lut l; + + memclear(l); + l.crtc_id = crtc_id; + l.gamma_size = size; + l.red = VOID2U64(red); + l.green = VOID2U64(green); + l.blue = VOID2U64(blue); + + return DRM_IOCTL(fd, DRM_IOCTL_MODE_GETGAMMA, &l); +} + +drm_public int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size, + uint16_t *red, uint16_t *green, + uint16_t *blue) +{ + struct drm_mode_crtc_lut l; + + memclear(l); + l.crtc_id = crtc_id; + l.gamma_size = size; + l.red = VOID2U64(red); + l.green = VOID2U64(green); + l.blue = VOID2U64(blue); + + return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETGAMMA, &l); +} + +drm_public int drmHandleEvent(int fd, drmEventContextPtr evctx) +{ + char buffer[1024]; + int len, i; + struct drm_event *e; + struct drm_event_vblank *vblank; + struct drm_event_crtc_sequence *seq; + void *user_data; + + /* The DRM read semantics guarantees that we always get only + * complete events. */ + + len = read(fd, buffer, sizeof buffer); + if (len == 0) + return 0; + if (len < (int)sizeof *e) + return -1; + + i = 0; + while (i < len) { + e = (struct drm_event *)(buffer + i); + switch (e->type) { + case DRM_EVENT_VBLANK: + if (evctx->version < 1 || + evctx->vblank_handler == NULL) + break; + vblank = (struct drm_event_vblank *) e; + evctx->vblank_handler(fd, + vblank->sequence, + vblank->tv_sec, + vblank->tv_usec, + U642VOID (vblank->user_data)); + break; + case DRM_EVENT_FLIP_COMPLETE: + vblank = (struct drm_event_vblank *) e; + user_data = U642VOID (vblank->user_data); + + if (evctx->version >= 3 && evctx->page_flip_handler2) + evctx->page_flip_handler2(fd, + vblank->sequence, + vblank->tv_sec, + vblank->tv_usec, + vblank->crtc_id, + user_data); + else if (evctx->version >= 2 && evctx->page_flip_handler) + evctx->page_flip_handler(fd, + vblank->sequence, + vblank->tv_sec, + vblank->tv_usec, + user_data); + break; + case DRM_EVENT_CRTC_SEQUENCE: + seq = (struct drm_event_crtc_sequence *) e; + if (evctx->version >= 4 && evctx->sequence_handler) + evctx->sequence_handler(fd, + seq->sequence, + seq->time_ns, + seq->user_data); + break; + default: + break; + } + i += e->length; + } + + return 0; +} + +drm_public int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id, + uint32_t flags, void *user_data) +{ + struct drm_mode_crtc_page_flip flip; + + memclear(flip); + flip.fb_id = fb_id; + flip.crtc_id = crtc_id; + flip.user_data = VOID2U64(user_data); + flip.flags = flags; + + return DRM_IOCTL(fd, DRM_IOCTL_MODE_PAGE_FLIP, &flip); +} + +drm_public int drmModePageFlipTarget(int fd, uint32_t crtc_id, uint32_t fb_id, + uint32_t flags, void *user_data, + uint32_t target_vblank) +{ + struct drm_mode_crtc_page_flip_target flip_target; + + memclear(flip_target); + flip_target.fb_id = fb_id; + flip_target.crtc_id = crtc_id; + flip_target.user_data = VOID2U64(user_data); + flip_target.flags = flags; + flip_target.sequence = target_vblank; + + return DRM_IOCTL(fd, DRM_IOCTL_MODE_PAGE_FLIP, &flip_target); +} + +drm_public int drmModeSetPlane(int fd, uint32_t plane_id, uint32_t crtc_id, + uint32_t fb_id, uint32_t flags, + int32_t crtc_x, int32_t crtc_y, + uint32_t crtc_w, uint32_t crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h) +{ + struct drm_mode_set_plane s; + + memclear(s); + s.plane_id = plane_id; + s.crtc_id = crtc_id; + s.fb_id = fb_id; + s.flags = flags; + s.crtc_x = crtc_x; + s.crtc_y = crtc_y; + s.crtc_w = crtc_w; + s.crtc_h = crtc_h; + s.src_x = src_x; + s.src_y = src_y; + s.src_w = src_w; + s.src_h = src_h; + + return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETPLANE, &s); +} + +drm_public drmModePlanePtr drmModeGetPlane(int fd, uint32_t plane_id) +{ + struct drm_mode_get_plane ovr, counts; + drmModePlanePtr r = 0; + +retry: + memclear(ovr); + ovr.plane_id = plane_id; + if (drmIoctl(fd, DRM_IOCTL_MODE_GETPLANE, &ovr)) + return 0; + + counts = ovr; + + if (ovr.count_format_types) { + ovr.format_type_ptr = VOID2U64(drmMalloc(ovr.count_format_types * + sizeof(uint32_t))); + if (!ovr.format_type_ptr) + goto err_allocs; + } + + if (drmIoctl(fd, DRM_IOCTL_MODE_GETPLANE, &ovr)) + goto err_allocs; + + if (counts.count_format_types < ovr.count_format_types) { + drmFree(U642VOID(ovr.format_type_ptr)); + goto retry; + } + + if (!(r = drmMalloc(sizeof(*r)))) + goto err_allocs; + + r->count_formats = ovr.count_format_types; + r->plane_id = ovr.plane_id; + r->crtc_id = ovr.crtc_id; + r->fb_id = ovr.fb_id; + r->possible_crtcs = ovr.possible_crtcs; + r->gamma_size = ovr.gamma_size; + r->formats = drmAllocCpy(U642VOID(ovr.format_type_ptr), + ovr.count_format_types, sizeof(uint32_t)); + if (ovr.count_format_types && !r->formats) { + drmFree(r->formats); + drmFree(r); + r = 0; + } + +err_allocs: + drmFree(U642VOID(ovr.format_type_ptr)); + + return r; +} + +drm_public void drmModeFreePlane(drmModePlanePtr ptr) +{ + if (!ptr) + return; + + drmFree(ptr->formats); + drmFree(ptr); +} + +drm_public drmModePlaneResPtr drmModeGetPlaneResources(int fd) +{ + struct drm_mode_get_plane_res res, counts; + drmModePlaneResPtr r = 0; + +retry: + memclear(res); + if (drmIoctl(fd, DRM_IOCTL_MODE_GETPLANERESOURCES, &res)) + return 0; + + counts = res; + + if (res.count_planes) { + res.plane_id_ptr = VOID2U64(drmMalloc(res.count_planes * + sizeof(uint32_t))); + if (!res.plane_id_ptr) + goto err_allocs; + } + + if (drmIoctl(fd, DRM_IOCTL_MODE_GETPLANERESOURCES, &res)) + goto err_allocs; + + if (counts.count_planes < res.count_planes) { + drmFree(U642VOID(res.plane_id_ptr)); + goto retry; + } + + if (!(r = drmMalloc(sizeof(*r)))) + goto err_allocs; + + r->count_planes = res.count_planes; + r->planes = drmAllocCpy(U642VOID(res.plane_id_ptr), + res.count_planes, sizeof(uint32_t)); + if (res.count_planes && !r->planes) { + drmFree(r->planes); + drmFree(r); + r = 0; + } + +err_allocs: + drmFree(U642VOID(res.plane_id_ptr)); + + return r; +} + +drm_public void drmModeFreePlaneResources(drmModePlaneResPtr ptr) +{ + if (!ptr) + return; + + drmFree(ptr->planes); + drmFree(ptr); +} + +drm_public drmModeObjectPropertiesPtr drmModeObjectGetProperties(int fd, + uint32_t object_id, + uint32_t object_type) +{ + struct drm_mode_obj_get_properties properties; + drmModeObjectPropertiesPtr ret = NULL; + uint32_t count; + +retry: + memclear(properties); + properties.obj_id = object_id; + properties.obj_type = object_type; + + if (drmIoctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &properties)) + return 0; + + count = properties.count_props; + + if (count) { + properties.props_ptr = VOID2U64(drmMalloc(count * + sizeof(uint32_t))); + if (!properties.props_ptr) + goto err_allocs; + properties.prop_values_ptr = VOID2U64(drmMalloc(count * + sizeof(uint64_t))); + if (!properties.prop_values_ptr) + goto err_allocs; + } + + if (drmIoctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &properties)) + goto err_allocs; + + if (count < properties.count_props) { + drmFree(U642VOID(properties.props_ptr)); + drmFree(U642VOID(properties.prop_values_ptr)); + goto retry; + } + count = properties.count_props; + + ret = drmMalloc(sizeof(*ret)); + if (!ret) + goto err_allocs; + + ret->count_props = count; + ret->props = drmAllocCpy(U642VOID(properties.props_ptr), + count, sizeof(uint32_t)); + ret->prop_values = drmAllocCpy(U642VOID(properties.prop_values_ptr), + count, sizeof(uint64_t)); + if (ret->count_props && (!ret->props || !ret->prop_values)) { + drmFree(ret->props); + drmFree(ret->prop_values); + drmFree(ret); + ret = NULL; + } + +err_allocs: + drmFree(U642VOID(properties.props_ptr)); + drmFree(U642VOID(properties.prop_values_ptr)); + return ret; +} + +drm_public void drmModeFreeObjectProperties(drmModeObjectPropertiesPtr ptr) +{ + if (!ptr) + return; + drmFree(ptr->props); + drmFree(ptr->prop_values); + drmFree(ptr); +} + +drm_public int drmModeObjectSetProperty(int fd, uint32_t object_id, uint32_t object_type, + uint32_t property_id, uint64_t value) +{ + struct drm_mode_obj_set_property prop; + + memclear(prop); + prop.value = value; + prop.prop_id = property_id; + prop.obj_id = object_id; + prop.obj_type = object_type; + + return DRM_IOCTL(fd, DRM_IOCTL_MODE_OBJ_SETPROPERTY, &prop); +} + +typedef struct _drmModeAtomicReqItem drmModeAtomicReqItem, *drmModeAtomicReqItemPtr; + +struct _drmModeAtomicReqItem { + uint32_t object_id; + uint32_t property_id; + uint64_t value; + uint32_t cursor; +}; + +struct _drmModeAtomicReq { + uint32_t cursor; + uint32_t size_items; + drmModeAtomicReqItemPtr items; +}; + +drm_public drmModeAtomicReqPtr drmModeAtomicAlloc(void) +{ + drmModeAtomicReqPtr req; + + req = drmMalloc(sizeof *req); + if (!req) + return NULL; + + req->items = NULL; + req->cursor = 0; + req->size_items = 0; + + return req; +} + +drm_public drmModeAtomicReqPtr drmModeAtomicDuplicate(const drmModeAtomicReqPtr old) +{ + drmModeAtomicReqPtr new; + + if (!old) + return NULL; + + new = drmMalloc(sizeof *new); + if (!new) + return NULL; + + new->cursor = old->cursor; + new->size_items = old->size_items; + + if (old->size_items) { + new->items = drmMalloc(old->size_items * sizeof(*new->items)); + if (!new->items) { + free(new); + return NULL; + } + memcpy(new->items, old->items, + old->cursor * sizeof(*new->items)); + } else { + new->items = NULL; + } + + return new; +} + +drm_public int drmModeAtomicMerge(drmModeAtomicReqPtr base, + const drmModeAtomicReqPtr augment) +{ + uint32_t i; + + if (!base) + return -EINVAL; + + if (!augment || augment->cursor == 0) + return 0; + + if (base->cursor + augment->cursor >= base->size_items) { + drmModeAtomicReqItemPtr new; + int saved_size = base->size_items; + + base->size_items = base->cursor + augment->cursor; + new = realloc(base->items, + base->size_items * sizeof(*base->items)); + if (!new) { + base->size_items = saved_size; + return -ENOMEM; + } + base->items = new; + } + + memcpy(&base->items[base->cursor], augment->items, + augment->cursor * sizeof(*augment->items)); + for (i = base->cursor; i < base->cursor + augment->cursor; i++) + base->items[i].cursor = i; + base->cursor += augment->cursor; + + return 0; +} + +drm_public int drmModeAtomicGetCursor(const drmModeAtomicReqPtr req) +{ + if (!req) + return -EINVAL; + return req->cursor; +} + +drm_public void drmModeAtomicSetCursor(drmModeAtomicReqPtr req, int cursor) +{ + if (req) + req->cursor = cursor; +} + +drm_public int drmModeAtomicAddProperty(drmModeAtomicReqPtr req, + uint32_t object_id, + uint32_t property_id, + uint64_t value) +{ + if (!req) + return -EINVAL; + + if (object_id == 0 || property_id == 0) + return -EINVAL; + + if (req->cursor >= req->size_items) { + const uint32_t item_size_inc = getpagesize() / sizeof(*req->items); + drmModeAtomicReqItemPtr new; + + req->size_items += item_size_inc; + new = realloc(req->items, req->size_items * sizeof(*req->items)); + if (!new) { + req->size_items -= item_size_inc; + return -ENOMEM; + } + req->items = new; + } + + req->items[req->cursor].object_id = object_id; + req->items[req->cursor].property_id = property_id; + req->items[req->cursor].value = value; + req->items[req->cursor].cursor = req->cursor; + req->cursor++; + + return req->cursor; +} + +drm_public void drmModeAtomicFree(drmModeAtomicReqPtr req) +{ + if (!req) + return; + + if (req->items) + drmFree(req->items); + drmFree(req); +} + +static int sort_req_list(const void *misc, const void *other) +{ + const drmModeAtomicReqItem *first = misc; + const drmModeAtomicReqItem *second = other; + + if (first->object_id != second->object_id) + return first->object_id - second->object_id; + else if (first->property_id != second->property_id) + return first->property_id - second->property_id; + else + return first->cursor - second->cursor; +} + +drm_public int drmModeAtomicCommit(int fd, const drmModeAtomicReqPtr req, + uint32_t flags, void *user_data) +{ + drmModeAtomicReqPtr sorted; + struct drm_mode_atomic atomic; + uint32_t *objs_ptr = NULL; + uint32_t *count_props_ptr = NULL; + uint32_t *props_ptr = NULL; + uint64_t *prop_values_ptr = NULL; + uint32_t last_obj_id = 0; + uint32_t i; + int obj_idx = -1; + int ret = -1; + + if (!req) + return -EINVAL; + + if (req->cursor == 0) + return 0; + + sorted = drmModeAtomicDuplicate(req); + if (sorted == NULL) + return -ENOMEM; + + memclear(atomic); + + /* Sort the list by object ID, then by property ID. */ + qsort(sorted->items, sorted->cursor, sizeof(*sorted->items), + sort_req_list); + + /* Now the list is sorted, eliminate duplicate property sets. */ + for (i = 0; i < sorted->cursor; i++) { + if (sorted->items[i].object_id != last_obj_id) { + atomic.count_objs++; + last_obj_id = sorted->items[i].object_id; + } + + if (i == sorted->cursor - 1) + continue; + + if (sorted->items[i].object_id != sorted->items[i + 1].object_id || + sorted->items[i].property_id != sorted->items[i + 1].property_id) + continue; + + memmove(&sorted->items[i], &sorted->items[i + 1], + (sorted->cursor - i - 1) * sizeof(*sorted->items)); + sorted->cursor--; + } + + for (i = 0; i < sorted->cursor; i++) + sorted->items[i].cursor = i; + + objs_ptr = drmMalloc(atomic.count_objs * sizeof objs_ptr[0]); + if (!objs_ptr) { + errno = ENOMEM; + goto out; + } + + count_props_ptr = drmMalloc(atomic.count_objs * sizeof count_props_ptr[0]); + if (!count_props_ptr) { + errno = ENOMEM; + goto out; + } + + props_ptr = drmMalloc(sorted->cursor * sizeof props_ptr[0]); + if (!props_ptr) { + errno = ENOMEM; + goto out; + } + + prop_values_ptr = drmMalloc(sorted->cursor * sizeof prop_values_ptr[0]); + if (!prop_values_ptr) { + errno = ENOMEM; + goto out; + } + + for (i = 0, last_obj_id = 0; i < sorted->cursor; i++) { + if (sorted->items[i].object_id != last_obj_id) { + obj_idx++; + objs_ptr[obj_idx] = sorted->items[i].object_id; + last_obj_id = objs_ptr[obj_idx]; + } + + count_props_ptr[obj_idx]++; + props_ptr[i] = sorted->items[i].property_id; + prop_values_ptr[i] = sorted->items[i].value; + + } + + atomic.flags = flags; + atomic.objs_ptr = VOID2U64(objs_ptr); + atomic.count_props_ptr = VOID2U64(count_props_ptr); + atomic.props_ptr = VOID2U64(props_ptr); + atomic.prop_values_ptr = VOID2U64(prop_values_ptr); + atomic.user_data = VOID2U64(user_data); + + ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ATOMIC, &atomic); + +out: + drmFree(objs_ptr); + drmFree(count_props_ptr); + drmFree(props_ptr); + drmFree(prop_values_ptr); + drmModeAtomicFree(sorted); + + return ret; +} + +drm_public int +drmModeCreatePropertyBlob(int fd, const void *data, size_t length, + uint32_t *id) +{ + struct drm_mode_create_blob create; + int ret; + + if (length >= 0xffffffff) + return -ERANGE; + + memclear(create); + + create.length = length; + create.data = (uintptr_t) data; + create.blob_id = 0; + *id = 0; + + ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_CREATEPROPBLOB, &create); + if (ret != 0) + return ret; + + *id = create.blob_id; + return 0; +} + +drm_public int +drmModeDestroyPropertyBlob(int fd, uint32_t id) +{ + struct drm_mode_destroy_blob destroy; + + memclear(destroy); + destroy.blob_id = id; + return DRM_IOCTL(fd, DRM_IOCTL_MODE_DESTROYPROPBLOB, &destroy); +} + +drm_public int +drmModeCreateLease(int fd, const uint32_t *objects, int num_objects, int flags, + uint32_t *lessee_id) +{ + struct drm_mode_create_lease create; + int ret; + + memclear(create); + create.object_ids = (uintptr_t) objects; + create.object_count = num_objects; + create.flags = flags; + + ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_CREATE_LEASE, &create); + if (ret == 0) { + *lessee_id = create.lessee_id; + return create.fd; + } + return -errno; +} + +drm_public drmModeLesseeListPtr +drmModeListLessees(int fd) +{ + struct drm_mode_list_lessees list; + uint32_t count; + drmModeLesseeListPtr ret; + + memclear(list); + + if (DRM_IOCTL(fd, DRM_IOCTL_MODE_LIST_LESSEES, &list)) + return NULL; + + count = list.count_lessees; + ret = drmMalloc(sizeof (drmModeLesseeListRes) + count * sizeof (ret->lessees[0])); + if (!ret) + return NULL; + + list.lessees_ptr = VOID2U64(&ret->lessees[0]); + if (DRM_IOCTL(fd, DRM_IOCTL_MODE_LIST_LESSEES, &list)) { + drmFree(ret); + return NULL; + } + + ret->count = count; + return ret; +} + +drm_public drmModeObjectListPtr +drmModeGetLease(int fd) +{ + struct drm_mode_get_lease get; + uint32_t count; + drmModeObjectListPtr ret; + + memclear(get); + + if (DRM_IOCTL(fd, DRM_IOCTL_MODE_GET_LEASE, &get)) + return NULL; + + count = get.count_objects; + ret = drmMalloc(sizeof (drmModeObjectListRes) + count * sizeof (ret->objects[0])); + if (!ret) + return NULL; + + get.objects_ptr = VOID2U64(&ret->objects[0]); + if (DRM_IOCTL(fd, DRM_IOCTL_MODE_GET_LEASE, &get)) { + drmFree(ret); + return NULL; + } + + ret->count = count; + return ret; +} + +drm_public int +drmModeRevokeLease(int fd, uint32_t lessee_id) +{ + struct drm_mode_revoke_lease revoke; + int ret; + + memclear(revoke); + + revoke.lessee_id = lessee_id; + + ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_REVOKE_LEASE, &revoke); + if (ret == 0) + return 0; + return -errno; +} + +drm_public drmModeFB2Ptr +drmModeGetFB2(int fd, uint32_t fb_id) +{ + struct drm_mode_fb_cmd2 get = { + .fb_id = fb_id, + }; + drmModeFB2Ptr ret; + int err; + + err = DRM_IOCTL(fd, DRM_IOCTL_MODE_GETFB2, &get); + if (err != 0) + return NULL; + + ret = drmMalloc(sizeof(drmModeFB2)); + if (!ret) + return NULL; + + ret->fb_id = fb_id; + ret->width = get.width; + ret->height = get.height; + ret->pixel_format = get.pixel_format; + ret->flags = get.flags; + ret->modifier = get.modifier[0]; + memcpy(ret->handles, get.handles, sizeof(uint32_t) * 4); + memcpy(ret->pitches, get.pitches, sizeof(uint32_t) * 4); + memcpy(ret->offsets, get.offsets, sizeof(uint32_t) * 4); + + return ret; +} + +drm_public void drmModeFreeFB2(drmModeFB2Ptr ptr) +{ + drmFree(ptr); +} + +drm_public const char * +drmModeGetConnectorTypeName(uint32_t connector_type) +{ + /* Keep the strings in sync with the kernel's drm_connector_enum_list in + * drm_connector.c. */ + switch (connector_type) { + case DRM_MODE_CONNECTOR_Unknown: + return "Unknown"; + case DRM_MODE_CONNECTOR_VGA: + return "VGA"; + case DRM_MODE_CONNECTOR_DVII: + return "DVI-I"; + case DRM_MODE_CONNECTOR_DVID: + return "DVI-D"; + case DRM_MODE_CONNECTOR_DVIA: + return "DVI-A"; + case DRM_MODE_CONNECTOR_Composite: + return "Composite"; + case DRM_MODE_CONNECTOR_SVIDEO: + return "SVIDEO"; + case DRM_MODE_CONNECTOR_LVDS: + return "LVDS"; + case DRM_MODE_CONNECTOR_Component: + return "Component"; + case DRM_MODE_CONNECTOR_9PinDIN: + return "DIN"; + case DRM_MODE_CONNECTOR_DisplayPort: + return "DP"; + case DRM_MODE_CONNECTOR_HDMIA: + return "HDMI-A"; + case DRM_MODE_CONNECTOR_HDMIB: + return "HDMI-B"; + case DRM_MODE_CONNECTOR_TV: + return "TV"; + case DRM_MODE_CONNECTOR_eDP: + return "eDP"; + case DRM_MODE_CONNECTOR_VIRTUAL: + return "Virtual"; + case DRM_MODE_CONNECTOR_DSI: + return "DSI"; + case DRM_MODE_CONNECTOR_DPI: + return "DPI"; + case DRM_MODE_CONNECTOR_WRITEBACK: + return "Writeback"; + case DRM_MODE_CONNECTOR_SPI: + return "SPI"; + case DRM_MODE_CONNECTOR_USB: + return "USB"; + default: + return NULL; + } +} + +drm_public int +drmModeCreateDumbBuffer(int fd, uint32_t width, uint32_t height, uint32_t bpp, + uint32_t flags, uint32_t *handle, uint32_t *pitch, + uint64_t *size) +{ + int ret; + struct drm_mode_create_dumb create = { + .width = width, + .height = height, + .bpp = bpp, + .flags = flags, + }; + + ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create); + if (ret != 0) + return ret; + + *handle = create.handle; + *pitch = create.pitch; + *size = create.size; + return 0; +} + +drm_public int +drmModeDestroyDumbBuffer(int fd, uint32_t handle) +{ + struct drm_mode_destroy_dumb destroy = { + .handle = handle, + }; + + return DRM_IOCTL(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy); +} + +drm_public int +drmModeMapDumbBuffer(int fd, uint32_t handle, uint64_t *offset) +{ + int ret; + struct drm_mode_map_dumb map = { + .handle = handle, + }; + + ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_MAP_DUMB, &map); + if (ret != 0) + return ret; + + *offset = map.offset; + return 0; +} diff --git a/xf86drmMode.h b/xf86drmMode.h new file mode 100644 index 0000000..d911c9a --- /dev/null +++ b/xf86drmMode.h @@ -0,0 +1,536 @@ +/* + * \file xf86drmMode.h + * Header for DRM modesetting interface. + * + * \author Jakob Bornecrantz + * + * \par Acknowledgements: + * Feb 2007, Dave Airlie + */ + +/* + * Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas. + * Copyright (c) 2007-2008 Dave Airlie + * Copyright (c) 2007-2008 Jakob Bornecrantz + * + * 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. + * + */ + +#ifndef _XF86DRMMODE_H_ +#define _XF86DRMMODE_H_ + +#if defined(__cplusplus) +extern "C" { +#endif + +#include +#include +#include +#include +#include + +/* + * This is the interface for modesetting for drm. + * + * It aims to provide a randr1.2 compatible interface for modesettings in the + * kernel, the interface is also meant to be used by libraries like EGL. + * + * More information can be found in randrproto.txt which can be found here: + * http://gitweb.freedesktop.org/?p=xorg/proto/randrproto.git + * + * There are some major differences to be noted. Unlike the randr1.2 proto you + * need to create the memory object of the framebuffer yourself with the ttm + * buffer object interface. This object needs to be pinned. + */ + +/* + * Feature defines + * + * Just because these are defined doesn't mean that the kernel + * can do that feature, its just for new code vs old libdrm. + */ +#define DRM_MODE_FEATURE_KMS 1 +#define DRM_MODE_FEATURE_DIRTYFB 1 + + +typedef struct _drmModeRes { + + int count_fbs; + uint32_t *fbs; + + int count_crtcs; + uint32_t *crtcs; + + int count_connectors; + uint32_t *connectors; + + int count_encoders; + uint32_t *encoders; + + uint32_t min_width, max_width; + uint32_t min_height, max_height; +} drmModeRes, *drmModeResPtr; + +typedef struct _drmModeModeInfo { + uint32_t clock; + uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew; + uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan; + + uint32_t vrefresh; + + uint32_t flags; + uint32_t type; + char name[DRM_DISPLAY_MODE_LEN]; +} drmModeModeInfo, *drmModeModeInfoPtr; + +typedef struct _drmModeFB { + uint32_t fb_id; + uint32_t width, height; + uint32_t pitch; + uint32_t bpp; + uint32_t depth; + /* driver specific handle */ + uint32_t handle; +} drmModeFB, *drmModeFBPtr; + +typedef struct _drmModeFB2 { + uint32_t fb_id; + uint32_t width, height; + uint32_t pixel_format; /* fourcc code from drm_fourcc.h */ + uint64_t modifier; /* applies to all buffers */ + uint32_t flags; + + /* per-plane GEM handle; may be duplicate entries for multiple planes */ + uint32_t handles[4]; + uint32_t pitches[4]; /* bytes */ + uint32_t offsets[4]; /* bytes */ +} drmModeFB2, *drmModeFB2Ptr; + +typedef struct drm_clip_rect drmModeClip, *drmModeClipPtr; + +typedef struct _drmModePropertyBlob { + uint32_t id; + uint32_t length; + void *data; +} drmModePropertyBlobRes, *drmModePropertyBlobPtr; + +typedef struct _drmModeProperty { + uint32_t prop_id; + uint32_t flags; + char name[DRM_PROP_NAME_LEN]; + int count_values; + uint64_t *values; /* store the blob lengths */ + int count_enums; + struct drm_mode_property_enum *enums; + int count_blobs; + uint32_t *blob_ids; /* store the blob IDs */ +} drmModePropertyRes, *drmModePropertyPtr; + +static inline uint32_t drmModeGetPropertyType(const drmModePropertyRes *prop) +{ + return prop->flags & (DRM_MODE_PROP_LEGACY_TYPE | DRM_MODE_PROP_EXTENDED_TYPE); +} + +static inline int drm_property_type_is(const drmModePropertyPtr property, + uint32_t type) +{ + return drmModeGetPropertyType(property) == type; +} + +typedef struct _drmModeCrtc { + uint32_t crtc_id; + uint32_t buffer_id; /**< FB id to connect to 0 = disconnect */ + + uint32_t x, y; /**< Position on the framebuffer */ + uint32_t width, height; + int mode_valid; + drmModeModeInfo mode; + + int gamma_size; /**< Number of gamma stops */ + +} drmModeCrtc, *drmModeCrtcPtr; + +typedef struct _drmModeEncoder { + uint32_t encoder_id; + uint32_t encoder_type; + uint32_t crtc_id; + uint32_t possible_crtcs; + uint32_t possible_clones; +} drmModeEncoder, *drmModeEncoderPtr; + +/** + * Describes the connector status. + * + * DRM_MODE_CONNECTED means that the connector has a sink plugged in. + * DRM_MODE_DISCONNECTED means the contrary. DRM_MODE_UNKNOWNCONNECTION is used + * when it could be either. + * + * User-space should first try to enable DRM_MODE_CONNECTED connectors and + * ignore other connectors. If there are no DRM_MODE_CONNECTED connectors, + * user-space should then try to probe and enable DRM_MODE_UNKNOWNCONNECTION + * connectors. + */ +typedef enum { + DRM_MODE_CONNECTED = 1, + DRM_MODE_DISCONNECTED = 2, + DRM_MODE_UNKNOWNCONNECTION = 3 +} drmModeConnection; + +typedef enum { + DRM_MODE_SUBPIXEL_UNKNOWN = 1, + DRM_MODE_SUBPIXEL_HORIZONTAL_RGB = 2, + DRM_MODE_SUBPIXEL_HORIZONTAL_BGR = 3, + DRM_MODE_SUBPIXEL_VERTICAL_RGB = 4, + DRM_MODE_SUBPIXEL_VERTICAL_BGR = 5, + DRM_MODE_SUBPIXEL_NONE = 6 +} drmModeSubPixel; + +typedef struct _drmModeConnector { + uint32_t connector_id; + uint32_t encoder_id; /**< Encoder currently connected to */ + uint32_t connector_type; + uint32_t connector_type_id; + drmModeConnection connection; + uint32_t mmWidth, mmHeight; /**< HxW in millimeters */ + drmModeSubPixel subpixel; + + int count_modes; + drmModeModeInfoPtr modes; + + int count_props; + uint32_t *props; /**< List of property ids */ + uint64_t *prop_values; /**< List of property values */ + + int count_encoders; + uint32_t *encoders; /**< List of encoder ids */ +} drmModeConnector, *drmModeConnectorPtr; + +#define DRM_PLANE_TYPE_OVERLAY 0 +#define DRM_PLANE_TYPE_PRIMARY 1 +#define DRM_PLANE_TYPE_CURSOR 2 + +typedef struct _drmModeObjectProperties { + uint32_t count_props; + uint32_t *props; + uint64_t *prop_values; +} drmModeObjectProperties, *drmModeObjectPropertiesPtr; + +typedef struct _drmModeFormatModifierIterator { + uint32_t fmt_idx, mod_idx; + uint32_t fmt; + uint64_t mod; +} drmModeFormatModifierIterator; + +typedef struct _drmModePlane { + uint32_t count_formats; + uint32_t *formats; + uint32_t plane_id; + + uint32_t crtc_id; + uint32_t fb_id; + + uint32_t crtc_x, crtc_y; + uint32_t x, y; + + uint32_t possible_crtcs; + uint32_t gamma_size; +} drmModePlane, *drmModePlanePtr; + +typedef struct _drmModePlaneRes { + uint32_t count_planes; + uint32_t *planes; +} drmModePlaneRes, *drmModePlaneResPtr; + +extern void drmModeFreeModeInfo( drmModeModeInfoPtr ptr ); +extern void drmModeFreeResources( drmModeResPtr ptr ); +extern void drmModeFreeFB( drmModeFBPtr ptr ); +extern void drmModeFreeFB2( drmModeFB2Ptr ptr ); +extern void drmModeFreeCrtc( drmModeCrtcPtr ptr ); +extern void drmModeFreeConnector( drmModeConnectorPtr ptr ); +extern void drmModeFreeEncoder( drmModeEncoderPtr ptr ); +extern void drmModeFreePlane( drmModePlanePtr ptr ); +extern void drmModeFreePlaneResources(drmModePlaneResPtr ptr); + +/** + * Check whether the DRM node supports Kernel Mode-Setting. + * + * Returns 1 if suitable for KMS, 0 otherwise. + */ +extern int drmIsKMS(int fd); + +/** + * Retrieves all of the resources associated with a card. + */ +extern drmModeResPtr drmModeGetResources(int fd); + +/* + * FrameBuffer manipulation. + */ + +/** + * Retrieve information about framebuffer bufferId + */ +extern drmModeFBPtr drmModeGetFB(int fd, uint32_t bufferId); +extern drmModeFB2Ptr drmModeGetFB2(int fd, uint32_t bufferId); + +/** + * Creates a new framebuffer with an buffer object as its scanout buffer. + */ +extern int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, + uint8_t bpp, uint32_t pitch, uint32_t bo_handle, + uint32_t *buf_id); +/* ...with a specific pixel format */ +extern int drmModeAddFB2(int fd, uint32_t width, uint32_t height, + uint32_t pixel_format, const uint32_t bo_handles[4], + const uint32_t pitches[4], const uint32_t offsets[4], + uint32_t *buf_id, uint32_t flags); + +/* ...with format modifiers */ +int drmModeAddFB2WithModifiers(int fd, uint32_t width, uint32_t height, + uint32_t pixel_format, const uint32_t bo_handles[4], + const uint32_t pitches[4], const uint32_t offsets[4], + const uint64_t modifier[4], uint32_t *buf_id, + uint32_t flags); + +/** + * Destroies the given framebuffer. + */ +extern int drmModeRmFB(int fd, uint32_t bufferId); + +/** + * Mark a region of a framebuffer as dirty. + */ +extern int drmModeDirtyFB(int fd, uint32_t bufferId, + drmModeClipPtr clips, uint32_t num_clips); + + +/* + * Crtc functions + */ + +/** + * Retrieve information about the ctrt crtcId + */ +extern drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId); + +/** + * Set the mode on a crtc crtcId with the given mode modeId. + */ +int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, + uint32_t x, uint32_t y, uint32_t *connectors, int count, + drmModeModeInfoPtr mode); + +/* + * Cursor functions + */ + +/** + * Set the cursor on crtc + */ +int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width, uint32_t height); + +int drmModeSetCursor2(int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width, uint32_t height, int32_t hot_x, int32_t hot_y); +/** + * Move the cursor on crtc + */ +int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y); + +/** + * Encoder functions + */ +drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id); + +/* + * Connector manipulation + */ + +/** + * Retrieve all information about the connector connectorId. This will do a + * forced probe on the connector to retrieve remote information such as EDIDs + * from the display device. + */ +extern drmModeConnectorPtr drmModeGetConnector(int fd, + uint32_t connectorId); + +/** + * Retrieve current information, i.e the currently active mode and encoder, + * about the connector connectorId. This will not do any probing on the + * connector or remote device, and only reports what is currently known. + * For the complete set of modes and encoders associated with the connector + * use drmModeGetConnector() which will do a probe to determine any display + * link changes first. + */ +extern drmModeConnectorPtr drmModeGetConnectorCurrent(int fd, + uint32_t connector_id); + +/** + * Get a bitmask of CRTCs a connector is compatible with. + * + * The bits reference CRTC indices. If the n-th CRTC is compatible with the + * connector, the n-th bit will be set. The indices are taken from the array + * returned by drmModeGetResources(). The indices are different from the object + * IDs. + * + * Zero is returned on error. + */ +extern uint32_t drmModeConnectorGetPossibleCrtcs(int fd, + const drmModeConnector *connector); + +/** + * Attaches the given mode to an connector. + */ +extern int drmModeAttachMode(int fd, uint32_t connectorId, drmModeModeInfoPtr mode_info); + +/** + * Detaches a mode from the connector + * must be unused, by the given mode. + */ +extern int drmModeDetachMode(int fd, uint32_t connectorId, drmModeModeInfoPtr mode_info); + +extern drmModePropertyPtr drmModeGetProperty(int fd, uint32_t propertyId); +extern void drmModeFreeProperty(drmModePropertyPtr ptr); + +extern drmModePropertyBlobPtr drmModeGetPropertyBlob(int fd, uint32_t blob_id); +extern bool drmModeFormatModifierBlobIterNext(const drmModePropertyBlobRes *blob, + drmModeFormatModifierIterator *iter); +extern void drmModeFreePropertyBlob(drmModePropertyBlobPtr ptr); +extern int drmModeConnectorSetProperty(int fd, uint32_t connector_id, uint32_t property_id, + uint64_t value); +extern int drmCheckModesettingSupported(const char *busid); + +extern int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size, + uint16_t *red, uint16_t *green, uint16_t *blue); +extern int drmModeCrtcGetGamma(int fd, uint32_t crtc_id, uint32_t size, + uint16_t *red, uint16_t *green, uint16_t *blue); +extern int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id, + uint32_t flags, void *user_data); +extern int drmModePageFlipTarget(int fd, uint32_t crtc_id, uint32_t fb_id, + uint32_t flags, void *user_data, + uint32_t target_vblank); + +extern drmModePlaneResPtr drmModeGetPlaneResources(int fd); +extern drmModePlanePtr drmModeGetPlane(int fd, uint32_t plane_id); +extern int drmModeSetPlane(int fd, uint32_t plane_id, uint32_t crtc_id, + uint32_t fb_id, uint32_t flags, + int32_t crtc_x, int32_t crtc_y, + uint32_t crtc_w, uint32_t crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h); + +extern drmModeObjectPropertiesPtr drmModeObjectGetProperties(int fd, + uint32_t object_id, + uint32_t object_type); +extern void drmModeFreeObjectProperties(drmModeObjectPropertiesPtr ptr); +extern int drmModeObjectSetProperty(int fd, uint32_t object_id, + uint32_t object_type, uint32_t property_id, + uint64_t value); + + +typedef struct _drmModeAtomicReq drmModeAtomicReq, *drmModeAtomicReqPtr; + +extern drmModeAtomicReqPtr drmModeAtomicAlloc(void); +extern drmModeAtomicReqPtr drmModeAtomicDuplicate(const drmModeAtomicReqPtr req); +extern int drmModeAtomicMerge(drmModeAtomicReqPtr base, + const drmModeAtomicReqPtr augment); +extern void drmModeAtomicFree(drmModeAtomicReqPtr req); +extern int drmModeAtomicGetCursor(const drmModeAtomicReqPtr req); +extern void drmModeAtomicSetCursor(drmModeAtomicReqPtr req, int cursor); +extern int drmModeAtomicAddProperty(drmModeAtomicReqPtr req, + uint32_t object_id, + uint32_t property_id, + uint64_t value); +extern int drmModeAtomicCommit(int fd, + const drmModeAtomicReqPtr req, + uint32_t flags, + void *user_data); + +extern int drmModeCreatePropertyBlob(int fd, const void *data, size_t size, + uint32_t *id); +extern int drmModeDestroyPropertyBlob(int fd, uint32_t id); + +/* + * DRM mode lease APIs. These create and manage new drm_masters with + * access to a subset of the available DRM resources + */ + +extern int drmModeCreateLease(int fd, const uint32_t *objects, int num_objects, int flags, uint32_t *lessee_id); + +typedef struct drmModeLesseeList { + uint32_t count; + uint32_t lessees[]; +} drmModeLesseeListRes, *drmModeLesseeListPtr; + +extern drmModeLesseeListPtr drmModeListLessees(int fd); + +typedef struct drmModeObjectList { + uint32_t count; + uint32_t objects[]; +} drmModeObjectListRes, *drmModeObjectListPtr; + +extern drmModeObjectListPtr drmModeGetLease(int fd); + +extern int drmModeRevokeLease(int fd, uint32_t lessee_id); + +/** + * Get a string describing a connector type. + * + * NULL is returned if the connector type is unsupported. Callers should handle + * this gracefully, e.g. by falling back to "Unknown" or printing the raw value. + */ +extern const char * +drmModeGetConnectorTypeName(uint32_t connector_type); + +/** + * Create a dumb buffer. + * + * Given a width, height and bits-per-pixel, the kernel will return a buffer + * handle, pitch and size. The flags must be zero. + * + * Returns 0 on success, negative errno on error. + */ +extern int +drmModeCreateDumbBuffer(int fd, uint32_t width, uint32_t height, uint32_t bpp, + uint32_t flags, uint32_t *handle, uint32_t *pitch, + uint64_t *size); + +/** + * Destroy a dumb buffer. + * + * Returns 0 on success, negative errno on error. + */ +extern int +drmModeDestroyDumbBuffer(int fd, uint32_t handle); + +/** + * Prepare a dumb buffer for mapping. + * + * The kernel returns an offset which can be used as an argument to mmap(2) on + * the DRM FD. + * + * Returns 0 on success, negative errno on error. + */ +extern int +drmModeMapDumbBuffer(int fd, uint32_t handle, uint64_t *offset); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/xf86drmRandom.c b/xf86drmRandom.c new file mode 100644 index 0000000..51e9676 --- /dev/null +++ b/xf86drmRandom.c @@ -0,0 +1,138 @@ +/* xf86drmRandom.c -- "Minimal Standard" PRNG Implementation + * Created: Mon Apr 19 08:28:13 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * 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, 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT 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. + * + * Authors: Rickard E. (Rik) Faith + * + * DESCRIPTION + * + * This file contains a simple, straightforward implementation of the Park + * & Miller "Minimal Standard" PRNG [PM88, PMS93], which is a Lehmer + * multiplicative linear congruential generator (MLCG) with a period of + * 2^31-1. + * + * This implementation is intended to provide a reliable, portable PRNG + * that is suitable for testing a hash table implementation and for + * implementing skip lists. + * + * FUTURE ENHANCEMENTS + * + * If initial seeds are not selected randomly, two instances of the PRNG + * can be correlated. [Knuth81, pp. 32-33] describes a shuffling technique + * that can eliminate this problem. + * + * If PRNGs are used for simulation, the period of the current + * implementation may be too short. [LE88] discusses methods of combining + * MLCGs to produce much longer periods, and suggests some alternative + * values for A and M. [LE90 and Sch92] also provide information on + * long-period PRNGs. + * + * REFERENCES + * + * [Knuth81] Donald E. Knuth. The Art of Computer Programming. Volume 2: + * Seminumerical Algorithms. Reading, Massachusetts: Addison-Wesley, 1981. + * + * [LE88] Pierre L'Ecuyer. "Efficient and Portable Combined Random Number + * Generators". CACM 31(6), June 1988, pp. 742-774. + * + * [LE90] Pierre L'Ecuyer. "Random Numbers for Simulation". CACM 33(10, + * October 1990, pp. 85-97. + * + * [PM88] Stephen K. Park and Keith W. Miller. "Random Number Generators: + * Good Ones are Hard to Find". CACM 31(10), October 1988, pp. 1192-1201. + * + * [Sch92] Bruce Schneier. "Pseudo-Ransom Sequence Generator for 32-Bit + * CPUs". Dr. Dobb's Journal 17(2), February 1992, pp. 34, 37-38, 40. + * + * [PMS93] Stephen K. Park, Keith W. Miller, and Paul K. Stockmeyer. In + * "Technical Correspondence: Remarks on Choosing and Implementing Random + * Number Generators". CACM 36(7), July 1993, pp. 105-110. + * + */ + +#include +#include + +#include "libdrm_macros.h" +#include "xf86drm.h" +#include "xf86drmRandom.h" + +#define RANDOM_MAGIC 0xfeedbeef + +drm_public void *drmRandomCreate(unsigned long seed) +{ + RandomState *state; + + state = drmMalloc(sizeof(*state)); + if (!state) return NULL; + state->magic = RANDOM_MAGIC; +#if 0 + /* Park & Miller, October 1988 */ + state->a = 16807; + state->m = 2147483647; + state->check = 1043618065; /* After 10000 iterations */ +#else + /* Park, Miller, and Stockmeyer, July 1993 */ + state->a = 48271; + state->m = 2147483647; + state->check = 399268537; /* After 10000 iterations */ +#endif + state->q = state->m / state->a; + state->r = state->m % state->a; + + state->seed = seed; + /* Check for illegal boundary conditions, + and choose closest legal value. */ + if (state->seed <= 0) state->seed = 1; + if (state->seed >= state->m) state->seed = state->m - 1; + + return state; +} + +drm_public int drmRandomDestroy(void *state) +{ + drmFree(state); + return 0; +} + +drm_public unsigned long drmRandom(void *state) +{ + RandomState *s = (RandomState *)state; + unsigned long hi; + unsigned long lo; + + hi = s->seed / s->q; + lo = s->seed % s->q; + s->seed = s->a * lo - s->r * hi; + if ((s->a * lo) <= (s->r * hi)) s->seed += s->m; + + return s->seed; +} + +drm_public double drmRandomDouble(void *state) +{ + RandomState *s = (RandomState *)state; + + return (double)drmRandom(state)/(double)s->m; +} diff --git a/xf86drmRandom.h b/xf86drmRandom.h new file mode 100644 index 0000000..43b730c --- /dev/null +++ b/xf86drmRandom.h @@ -0,0 +1,35 @@ +/* + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * 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, 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT 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. + * + * Authors: Rickard E. (Rik) Faith + */ + +typedef struct RandomState { + unsigned long magic; + unsigned long a; + unsigned long m; + unsigned long q; /* m div a */ + unsigned long r; /* m mod a */ + unsigned long check; + unsigned long seed; +} RandomState; diff --git a/xf86drmSL.c b/xf86drmSL.c new file mode 100644 index 0000000..3826df9 --- /dev/null +++ b/xf86drmSL.c @@ -0,0 +1,319 @@ +/* xf86drmSL.c -- Skip list support + * Created: Mon May 10 09:28:13 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * 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, 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 (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 NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT 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. + * + * Authors: Rickard E. (Rik) Faith + * + * DESCRIPTION + * + * This file contains a straightforward skip list implementation.n + * + * FUTURE ENHANCEMENTS + * + * REFERENCES + * + * [Pugh90] William Pugh. Skip Lists: A Probabilistic Alternative to + * Balanced Trees. CACM 33(6), June 1990, pp. 668-676. + * + */ + +#include +#include + +#include "libdrm_macros.h" +#include "xf86drm.h" + +#define SL_LIST_MAGIC 0xfacade00LU +#define SL_ENTRY_MAGIC 0x00fab1edLU +#define SL_FREED_MAGIC 0xdecea5edLU +#define SL_MAX_LEVEL 16 +#define SL_RANDOM_SEED 0xc01055a1LU + +#define SL_RANDOM_DECL static void *state = NULL +#define SL_RANDOM_INIT(seed) if (!state) state = drmRandomCreate(seed) +#define SL_RANDOM drmRandom(state) + +typedef struct SLEntry { + unsigned long magic; /* SL_ENTRY_MAGIC */ + unsigned long key; + void *value; + int levels; + struct SLEntry *forward[1]; /* variable sized array */ +} SLEntry, *SLEntryPtr; + +typedef struct SkipList { + unsigned long magic; /* SL_LIST_MAGIC */ + int level; + int count; + SLEntryPtr head; + SLEntryPtr p0; /* Position for iteration */ +} SkipList, *SkipListPtr; + +static SLEntryPtr SLCreateEntry(int max_level, unsigned long key, void *value) +{ + SLEntryPtr entry; + + if (max_level < 0 || max_level > SL_MAX_LEVEL) max_level = SL_MAX_LEVEL; + + entry = drmMalloc(sizeof(*entry) + + (max_level + 1) * sizeof(entry->forward[0])); + if (!entry) return NULL; + entry->magic = SL_ENTRY_MAGIC; + entry->key = key; + entry->value = value; + entry->levels = max_level + 1; + + return entry; +} + +static int SLRandomLevel(void) +{ + int level = 1; + SL_RANDOM_DECL; + + SL_RANDOM_INIT(SL_RANDOM_SEED); + + while ((SL_RANDOM & 0x01) && level < SL_MAX_LEVEL) ++level; + return level; +} + +drm_public void *drmSLCreate(void) +{ + SkipListPtr list; + int i; + + list = drmMalloc(sizeof(*list)); + if (!list) return NULL; + list->magic = SL_LIST_MAGIC; + list->level = 0; + list->head = SLCreateEntry(SL_MAX_LEVEL, 0, NULL); + list->count = 0; + + for (i = 0; i <= SL_MAX_LEVEL; i++) list->head->forward[i] = NULL; + + return list; +} + +drm_public int drmSLDestroy(void *l) +{ + SkipListPtr list = (SkipListPtr)l; + SLEntryPtr entry; + SLEntryPtr next; + + if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */ + + for (entry = list->head; entry; entry = next) { + if (entry->magic != SL_ENTRY_MAGIC) return -1; /* Bad magic */ + next = entry->forward[0]; + entry->magic = SL_FREED_MAGIC; + drmFree(entry); + } + + list->magic = SL_FREED_MAGIC; + drmFree(list); + return 0; +} + +static SLEntryPtr SLLocate(void *l, unsigned long key, SLEntryPtr *update) +{ + SkipListPtr list = (SkipListPtr)l; + SLEntryPtr entry; + int i; + + if (list->magic != SL_LIST_MAGIC) return NULL; + + for (i = list->level, entry = list->head; i >= 0; i--) { + while (entry->forward[i] && entry->forward[i]->key < key) + entry = entry->forward[i]; + update[i] = entry; + } + + return entry->forward[0]; +} + +drm_public int drmSLInsert(void *l, unsigned long key, void *value) +{ + SkipListPtr list = (SkipListPtr)l; + SLEntryPtr entry; + SLEntryPtr update[SL_MAX_LEVEL + 1]; + int level; + int i; + + if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */ + + entry = SLLocate(list, key, update); + + if (entry && entry->key == key) return 1; /* Already in list */ + + + level = SLRandomLevel(); + if (level > list->level) { + level = ++list->level; + update[level] = list->head; + } + + entry = SLCreateEntry(level, key, value); + + /* Fix up forward pointers */ + for (i = 0; i <= level; i++) { + entry->forward[i] = update[i]->forward[i]; + update[i]->forward[i] = entry; + } + + ++list->count; + return 0; /* Added to table */ +} + +drm_public int drmSLDelete(void *l, unsigned long key) +{ + SkipListPtr list = (SkipListPtr)l; + SLEntryPtr update[SL_MAX_LEVEL + 1]; + SLEntryPtr entry; + int i; + + if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */ + + entry = SLLocate(list, key, update); + + if (!entry || entry->key != key) return 1; /* Not found */ + + /* Fix up forward pointers */ + for (i = 0; i <= list->level; i++) { + if (update[i]->forward[i] == entry) + update[i]->forward[i] = entry->forward[i]; + } + + entry->magic = SL_FREED_MAGIC; + drmFree(entry); + + while (list->level && !list->head->forward[list->level]) --list->level; + --list->count; + return 0; +} + +drm_public int drmSLLookup(void *l, unsigned long key, void **value) +{ + SkipListPtr list = (SkipListPtr)l; + SLEntryPtr update[SL_MAX_LEVEL + 1]; + SLEntryPtr entry; + + entry = SLLocate(list, key, update); + + if (entry && entry->key == key) { + *value = entry; + return 0; + } + *value = NULL; + return -1; +} + +drm_public int drmSLLookupNeighbors(void *l, unsigned long key, + unsigned long *prev_key, void **prev_value, + unsigned long *next_key, void **next_value) +{ + SkipListPtr list = (SkipListPtr)l; + SLEntryPtr update[SL_MAX_LEVEL + 1] = {0}; + int retcode = 0; + + SLLocate(list, key, update); + + *prev_key = *next_key = key; + *prev_value = *next_value = NULL; + + if (update[0]) { + *prev_key = update[0]->key; + *prev_value = update[0]->value; + ++retcode; + if (update[0]->forward[0]) { + *next_key = update[0]->forward[0]->key; + *next_value = update[0]->forward[0]->value; + ++retcode; + } + } + return retcode; +} + +drm_public int drmSLNext(void *l, unsigned long *key, void **value) +{ + SkipListPtr list = (SkipListPtr)l; + SLEntryPtr entry; + + if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */ + + entry = list->p0; + + if (entry) { + list->p0 = entry->forward[0]; + *key = entry->key; + *value = entry->value; + return 1; + } + list->p0 = NULL; + return 0; +} + +drm_public int drmSLFirst(void *l, unsigned long *key, void **value) +{ + SkipListPtr list = (SkipListPtr)l; + + if (list->magic != SL_LIST_MAGIC) return -1; /* Bad magic */ + + list->p0 = list->head->forward[0]; + return drmSLNext(list, key, value); +} + +/* Dump internal data structures for debugging. */ +drm_public void drmSLDump(void *l) +{ + SkipListPtr list = (SkipListPtr)l; + SLEntryPtr entry; + int i; + + if (list->magic != SL_LIST_MAGIC) { + printf("Bad magic: 0x%08lx (expected 0x%08lx)\n", + list->magic, SL_LIST_MAGIC); + return; + } + + printf("Level = %d, count = %d\n", list->level, list->count); + for (entry = list->head; entry; entry = entry->forward[0]) { + if (entry->magic != SL_ENTRY_MAGIC) { + printf("Bad magic: 0x%08lx (expected 0x%08lx)\n", + list->magic, SL_ENTRY_MAGIC); + } + printf("\nEntry %p <0x%08lx, %p> has %2d levels\n", + entry, entry->key, entry->value, entry->levels); + for (i = 0; i < entry->levels; i++) { + if (entry->forward[i]) { + printf(" %2d: %p <0x%08lx, %p>\n", + i, + entry->forward[i], + entry->forward[i]->key, + entry->forward[i]->value); + } else { + printf(" %2d: %p\n", i, entry->forward[i]); + } + } + } +} -- cgit v1.2.3