From 9e7496921284ad023fad994d4944f886649306f9 Mon Sep 17 00:00:00 2001 From: zhusiyuan Date: Wed, 12 Apr 2023 16:34:13 +0800 Subject: [PATCH] upgrade version 2.4.111 Signed-off-by: zhusiyuan --- OAT.xml | 2 +- README.OpenSource | 6 +- README.rst | 18 + RELEASING | 4 +- amdgpu/amdgpu-symbols.txt | 3 + amdgpu/amdgpu.h | 46 + amdgpu/amdgpu_bo.c | 24 +- amdgpu/amdgpu_cs.c | 22 + amdgpu/amdgpu_device.c | 5 + amdgpu/amdgpu_gpu_info.c | 15 + amdgpu/amdgpu_vamgr.c | 133 +- amdgpu/meson.build | 12 +- bundle.json | 2 +- core-symbols.txt | 6 + data/amdgpu.ids | 347 ++++-- etnaviv/etnaviv_bo.c | 13 +- etnaviv/etnaviv_drm.h | 13 +- etnaviv/meson.build | 11 +- exynos/exynos_drm.c | 6 +- exynos/meson.build | 10 +- freedreno/freedreno_bo.c | 10 +- freedreno/meson.build | 10 +- gen_table_fourcc.py | 84 ++ generated_static_table_fourcc.h | 49 + include/drm/amdgpu_drm.h | 116 +- include/drm/drm.h | 250 +++- include/drm/drm_fourcc.h | 638 +++++++++- include/drm/drm_mode.h | 283 ++++- include/drm/tegra_drm.h | 429 ++++++- intel/i915_pciids.h | 235 ++-- intel/intel_bufmgr_gem.c | 286 ++--- intel/intel_chipset.c | 8 + intel/intel_decode.c | 39 +- intel/meson.build | 11 +- intel/tests/gen4-3d.batch.sh | 21 +- intel/tests/gen5-3d.batch.sh | 21 +- intel/tests/gen6-3d.batch.sh | 21 +- intel/tests/gen7-2d-copy.batch.sh | 21 +- intel/tests/gen7-3d.batch.sh | 21 +- intel/tests/gm45-3d.batch.sh | 21 +- intel/tests/test-batch.sh | 0 libdrm_lists.h | 22 +- libkms/Android.mk | 51 - libkms/Makefile.sources | 23 - libkms/api.c | 139 --- libkms/dumb.c | 216 ---- libkms/exynos.c | 220 ---- libkms/intel.c | 236 ---- libkms/internal.h | 80 -- libkms/kms-symbols.txt | 8 - libkms/libkms.h | 82 -- libkms/libkms.pc.in | 11 - libkms/linux.c | 147 --- libkms/meson.build | 78 -- libkms/nouveau.c | 218 ---- libkms/radeon.c | 239 ---- libkms/vmwgfx.c | 204 ---- man/drm-kms.7.rst | 229 ++++ man/drm-kms.xml | 342 ------ man/drm-memory.7.rst | 313 +++++ man/drm-memory.xml | 430 ------- man/drm.7.rst | 91 ++ man/drm.xml | 137 --- man/drmAvailable.3.rst | 41 + man/drmAvailable.xml | 75 -- man/drmHandleEvent.3.rst | 62 + man/drmHandleEvent.xml | 102 -- man/drmModeGetResources.3.rst | 92 ++ man/drmModeGetResources.xml | 139 --- man/meson.build | 57 +- meson.build | 142 +-- meson_options.txt | 7 - nouveau/meson.build | 11 +- nouveau/nouveau-symbols.txt | 1 + nouveau/nouveau.c | 35 +- nouveau/nouveau.h | 4 + nouveau/private.h | 17 +- nouveau/pushbuf.c | 31 +- omap/meson.build | 10 +- omap/omap_drm.c | 10 +- radeon/meson.build | 11 +- radeon/radeon_bo.h | 1 - radeon/radeon_bo_gem.c | 7 +- tegra/channel.c | 195 +++ tegra/job.c | 187 +++ tegra/meson.build | 18 +- tegra/private.h | 85 +- tegra/pushbuf.c | 184 +++ tegra/syncpt.c | 101 ++ tegra/tegra-symbols.txt | 27 +- tegra/tegra.c | 390 +++--- tegra/tegra.h | 95 +- tests/amdgpu/.editorconfig | 14 +- tests/amdgpu/amdgpu_stress.c | 418 +++++++ tests/amdgpu/amdgpu_test.c | 154 ++- tests/amdgpu/amdgpu_test.h | 130 +- tests/amdgpu/basic_tests.c | 1066 +++++++++++++---- tests/amdgpu/bo_tests.c | 4 +- tests/amdgpu/cp_dma_tests.c | 533 +++++++++ tests/amdgpu/cs_tests.c | 5 +- tests/amdgpu/deadlock_tests.c | 54 +- tests/amdgpu/decode_messages.h | 31 +- tests/amdgpu/hotunplug_tests.c | 443 +++++++ tests/amdgpu/jpeg_tests.c | 579 +++++++++ tests/amdgpu/meson.build | 14 +- tests/amdgpu/security_tests.c | 486 ++++++++ tests/amdgpu/syncobj_tests.c | 22 +- tests/amdgpu/vce_tests.c | 6 +- tests/amdgpu/vcn_tests.c | 85 +- tests/amdgpu/vm_tests.c | 19 +- tests/etnaviv/etnaviv_2d_test.c | 70 +- tests/exynos/exynos_fimg2d_test.c | 1 - tests/exynos/meson.build | 21 +- tests/kms/kms-steal-crtc.c | 161 --- tests/kms/kms-universal-planes.c | 357 ------ tests/kms/libkms-test-device.c | 217 ---- tests/kms/libkms-test-framebuffer.c | 153 --- tests/kms/libkms-test-plane.c | 137 --- tests/kms/libkms-test.h | 120 -- tests/kms/meson.build | 49 - tests/kmstest/main.c | 109 -- tests/kmstest/meson.build | 30 - tests/meson.build | 4 - tests/modeprint/modeprint.c | 2 +- tests/modetest/modetest.c | 125 +- tests/nouveau/threaded.c | 2 +- tests/proptest/proptest.c | 4 +- tests/tegra/.gitignore | 3 +- tests/tegra/drm-test-tegra.c | 147 +++ tests/tegra/drm-test-tegra.h | 55 + tests/tegra/drm-test.c | 248 ++++ .../libkms-test-screen.c => tegra/drm-test.h} | 130 +- tests/tegra/gr2d-fill.c | 146 +++ .../libkms-test-crtc.c => tegra/host1x.h} | 39 +- tests/tegra/meson.build | 88 +- tests/tegra/openclose.c | 52 +- 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/reconf | 0 tests/util/kms.c | 3 + tests/util/pattern.c | 5 +- util_double_list.h | 2 +- xf86drm.c | 634 +++++++++- xf86drm.h | 33 + xf86drmMode.c | 145 ++- xf86drmMode.h | 163 +-- 159 files changed, 14861 insertions(+), 6273 deletions(-) create mode 100644 gen_table_fourcc.py create mode 100644 generated_static_table_fourcc.h mode change 120000 => 100644 intel/tests/gen4-3d.batch.sh mode change 120000 => 100644 intel/tests/gen5-3d.batch.sh mode change 120000 => 100644 intel/tests/gen6-3d.batch.sh mode change 120000 => 100644 intel/tests/gen7-2d-copy.batch.sh mode change 120000 => 100644 intel/tests/gen7-3d.batch.sh mode change 120000 => 100644 intel/tests/gm45-3d.batch.sh mode change 100755 => 100644 intel/tests/test-batch.sh delete mode 100644 libkms/Android.mk delete mode 100644 libkms/Makefile.sources delete mode 100644 libkms/api.c delete mode 100644 libkms/dumb.c delete mode 100644 libkms/exynos.c delete mode 100644 libkms/intel.c delete mode 100644 libkms/internal.h delete mode 100644 libkms/kms-symbols.txt delete mode 100644 libkms/libkms.h delete mode 100644 libkms/libkms.pc.in delete mode 100644 libkms/linux.c delete mode 100644 libkms/meson.build delete mode 100644 libkms/nouveau.c delete mode 100644 libkms/radeon.c delete mode 100644 libkms/vmwgfx.c create mode 100644 man/drm-kms.7.rst delete mode 100644 man/drm-kms.xml create mode 100644 man/drm-memory.7.rst delete mode 100644 man/drm-memory.xml create mode 100644 man/drm.7.rst delete mode 100644 man/drm.xml create mode 100644 man/drmAvailable.3.rst delete mode 100644 man/drmAvailable.xml create mode 100644 man/drmHandleEvent.3.rst delete mode 100644 man/drmHandleEvent.xml create mode 100644 man/drmModeGetResources.3.rst delete mode 100644 man/drmModeGetResources.xml create mode 100644 tegra/channel.c create mode 100644 tegra/job.c create mode 100644 tegra/pushbuf.c create mode 100644 tegra/syncpt.c mode change 120000 => 100644 tests/amdgpu/.editorconfig create mode 100644 tests/amdgpu/amdgpu_stress.c create mode 100644 tests/amdgpu/cp_dma_tests.c create mode 100644 tests/amdgpu/hotunplug_tests.c create mode 100644 tests/amdgpu/jpeg_tests.c create mode 100644 tests/amdgpu/security_tests.c delete mode 100644 tests/kms/kms-steal-crtc.c delete mode 100644 tests/kms/kms-universal-planes.c delete mode 100644 tests/kms/libkms-test-device.c delete mode 100644 tests/kms/libkms-test-framebuffer.c delete mode 100644 tests/kms/libkms-test-plane.c delete mode 100644 tests/kms/libkms-test.h delete mode 100644 tests/kms/meson.build delete mode 100644 tests/kmstest/main.c delete mode 100644 tests/kmstest/meson.build 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 rename tests/{kms/libkms-test-screen.c => tegra/drm-test.h} (30%) create mode 100644 tests/tegra/gr2d-fill.c rename tests/{kms/libkms-test-crtc.c => tegra/host1x.h} (47%) 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 mode change 100755 => 100644 tests/ttmtest/reconf diff --git a/OAT.xml b/OAT.xml index a767839..b59b1a7 100644 --- a/OAT.xml +++ b/OAT.xml @@ -1,5 +1,5 @@ - - - - - - - - Direct Rendering Manager - libdrm - September 2012 - - - Developer - David - Herrmann - dh.herrmann@googlemail.com - - - - - - drm-kms - 7 - - - - drm-kms - Kernel Mode-Setting - - - - - #include <xf86drm.h> - #include <xf86drmMode.h> - - - - - 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 - drmModeSettingSupported3 - 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 - drmModeCrtcSet3 - 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-memory7 - API. - - - - - - - Mode-Setting - Before mode-setting can be performed, an application needs to call - drmSetMaster3 - to become DRM-Master. It then has exclusive - access to the KMS API. A call to - drmModeGetResources3 - 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 - drmModeGetConnector3 - 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-depedent and described in - drm-memory7. - 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 - drmModeAddFB3 - and - drmModeAddFB23. - - As a last step, you want to program your CRTC to drive your selected - connector. You can do this with a call to - drmModeSetCrtc3. - - - - Page-Flipping - A call to - drmModeSetCrtc3 - 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 - drmModeSetCrtc3 - on the next buffer to flip. If you want to synchronize your flips - with vertical-blanks, you can use - drmModePageFlip3 - which schedules your page-flip for the next - vblank. - - - - Planes - Planes are controlled independently from CRTCs. That is, a call to - drmModeSetCrtc3 - does not affect planes. Instead, you need to call - drmModeSetPlane3 - 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 - drmModeGetPlaneResources3 - 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 - drmModeSetCursor3 - and move it on the screen with - drmModeMoveCursor3. - 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 - drmModeGetResources3 - as drmModeRes *res, - selected a connector from the list in - res->connectors - and retrieved the connector-information as - drmModeConnector *conn - via - drmModeGetConnector3 - 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 - drmOpen3) - 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://bugs.freedesktop.org/enter_bug.cgi?product=DRI&component=libdrm - under the "DRI" product, component "libdrm" - - - - See Also - - drm7, - drm-memory7, - drmModeGetResources3, - drmModeGetConnector3, - drmModeGetEncoder3, - drmModeGetCrtc3, - drmModeSetCrtc3, - drmModeGetFB3, - drmModeAddFB3, - drmModeAddFB23, - drmModeRmFB3, - drmModePageFlip3, - drmModeGetPlaneResources3, - drmModeGetPlane3, - drmModeSetPlane3, - drmModeSetCursor3, - drmModeMoveCursor3, - drmSetMaster3, - drmAvailable3, - drmCheckModesettingSupported3, - drmOpen3 - - - 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-memory.xml b/man/drm-memory.xml deleted file mode 100644 index 3aa7cf2..0000000 --- a/man/drm-memory.xml +++ /dev/null @@ -1,430 +0,0 @@ - - - - - - - - Direct Rendering Manager - libdrm - September 2012 - - - Developer - David - Herrmann - dh.herrmann@googlemail.com - - - - - - drm-memory - 7 - - - - drm-memory - drm-mm - drm-gem - drm-ttm - DRM Memory Management - - - - - #include <xf86drm.h> - - - - - 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 - mmap2 - 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 32bit handle - that can be used to manage the buffer with the DRM API. You can - create framebuffers with - drmModeAddFB3 - 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 - mmap2. - - 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 32bit 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 32bit or 64bit - 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 - mmap2 - 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 - mmap2 - 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 manpages 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 - ioctl2 - on the DRM file descriptor. An application must be authorized via - drmAuthMagic3 - 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-prime7 - 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-intel7 - or - drm-radeon7). - - Gem-buffers can be closed with the - DRM_IOCTL_GEM_CLOSE ioctl. It takes as argument - a structure of type struct drm_gem_close: - - -struct drm_gem_close { - __u32 handle; - __u32 pad; -}; - - - The handle field is the gem-handle to be - closed. The pad field is unused padding. - It must be zeroed. 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 32bit - 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 - drmAuthMagic3 - 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-prime7 - 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 manpages, 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-intel7, - drm-radeon7 - and - drm-nouveau7. - However, the - drm-prime7 - 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-kms7). - - -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://bugs.freedesktop.org/enter_bug.cgi?product=DRI&component=libdrm - under the "DRI" product, component "libdrm" - - - - See Also - - drm7, - drm-kms7, - drm-prime7, - drmAvailable3, - drmOpen3, - drm-intel7, - drm-radeon7, - drm-nouveau7 - - - 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/drm.xml b/man/drm.xml deleted file mode 100644 index dbb67ad..0000000 --- a/man/drm.xml +++ /dev/null @@ -1,137 +0,0 @@ - - - - - - - - Direct Rendering Manager - libdrm - September 2012 - - - Developer - David - Herrmann - dh.herrmann@googlemail.com - - - - - - drm - 7 - - - - drm - Direct Rendering Manager - - - - - #include <xf86drm.h> - - - - - 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 - ioctl2 - 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 - open2 - and - close2. - 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 - drmSetMaster3 - for information on how to become DRM-Master and what the limitations - are. Other DRM users can be authenticated to the DRM-Master via - drmAuthMagic3 - 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-kms7 - 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-depedent 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-memory7. - - - - - Reporting Bugs - Bugs in this manual should be reported to - https://bugs.freedesktop.org/enter_bug.cgi?product=DRI&component=libdrm - under the "DRI" product, component "libdrm" - - - - See Also - - drm-kms7, - drm-memory7, - drmSetMaster3, - drmAuthMagic3, - drmAvailable3, - drmOpen3 - - - 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/drmAvailable.xml b/man/drmAvailable.xml deleted file mode 100644 index 1e5d787..0000000 --- a/man/drmAvailable.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - - - Direct Rendering Manager - libdrm - September 2012 - - - Developer - David - Herrmann - dh.herrmann@googlemail.com - - - - - - drmAvailable - 3 - - - - drmAvailable - determine whether a DRM kernel driver has been - loaded - - - - - - #include <xf86drm.h> - - - 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://bugs.freedesktop.org/enter_bug.cgi?product=DRI&component=libdrm - under the "DRI" product, component "libdrm" - - - - See Also - - drm7, - drmOpen3 - - - 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/drmHandleEvent.xml b/man/drmHandleEvent.xml deleted file mode 100644 index 8330442..0000000 --- a/man/drmHandleEvent.xml +++ /dev/null @@ -1,102 +0,0 @@ - - - - - - - - Direct Rendering Manager - libdrm - September 2012 - - - Developer - David - Herrmann - dh.herrmann@googlemail.com - - - - - - drmHandleEvent - 3 - - - - drmHandleEvent - read and process pending DRM events - - - - - - #include <xf86drm.h> - - - 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://bugs.freedesktop.org/enter_bug.cgi?product=DRI&component=libdrm - under the "DRI" product, component "libdrm" - - - - See Also - - drm7, - drm-kms7, - drmModePageFlip3, - drmWaitVBlank3 - - - 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/drmModeGetResources.xml b/man/drmModeGetResources.xml deleted file mode 100644 index 0ab6a68..0000000 --- a/man/drmModeGetResources.xml +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - - Direct Rendering Manager - libdrm - September 2012 - - - Developer - David - Herrmann - dh.herrmann@googlemail.com - - - - - - drmModeGetResources - 3 - - - - drmModeGetResources - retrieve current display configuration information - - - - - - #include <xf86drm.h> - #include <xf86drmMode.h> - - - 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 - drmModeFreeResources3. - - - - Reporting Bugs - Bugs in this function should be reported to - https://bugs.freedesktop.org/enter_bug.cgi?product=DRI&component=libdrm - under the "DRI" product, component "libdrm" - - - - See Also - - drm7, - drm-kms7, - drmModeGetFB3, - drmModeAddFB3, - drmModeAddFB23, - drmModeRmFB3, - drmModeDirtyFB3, - drmModeGetCrtc3, - drmModeSetCrtc3, - drmModeGetEncoder3, - drmModeGetConnector3 - - - diff --git a/man/meson.build b/man/meson.build index 45eaeda..92a4c37 100644 --- a/man/meson.build +++ b/man/meson.build @@ -18,50 +18,23 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -xsltproc_args = [ - '--stringparam', 'man.authors.section.enabled', '0', - '--stringparam', 'man.copyright.section.enabled', '0', - '--stringparam', 'funcsynopsis.style', 'ansi', - '--stringparam', 'man.output.quietly', '1', - '--nonet', manpage_style, +rst_pages = [ + ['drm', '7'], + ['drm-kms', '7'], + ['drm-memory', '7'], + ['drmAvailable', '3'], + ['drmHandleEvent', '3'], + ['drmModeGetResources', '3'], ] - -xmls = [ - ['drm', '7'], ['drm-kms', '7'], ['drm-memory', '7'], ['drmAvailable', '3'], - ['drmHandleEvent', '3'], ['drmModeGetResources', '3'] -] -foreach x : xmls - m = x[0] - s = x[1] - custom_target( - m, - input : files('@0@.xml'.format(m)), - output : '@0@.@1@'.format(m, s), - command : [prog_xslt, '-o', '@OUTPUT@', xsltproc_args, '@INPUT0@'], - install : true, - install_dir : join_paths(get_option('mandir'), 'man@0@'.format(s)), - build_by_default : true, - ) -endforeach - -foreach x : ['drm-mm', 'drm-gem', 'drm-ttm'] - gen = custom_target( - 'gen-@0@'.format(x), - input : 'drm-memory.xml', - output : '@0@.xml'.format(x), - command : [ - prog_sed, '-e', 's@^\.so \([a-z_]\+\)\.\([0-9]\)$$@\.so man\2\/\1\.\2@', - '@INPUT@', - ], - capture : true, - ) +foreach page : rst_pages + name = page[0] + '.' + page[1] + rst = files(name + '.rst') custom_target( - '@0@.7'.format(x), - input : gen, - output : '@0@.7'.format(x, '7'), - command : [prog_xslt, '-o', '@OUTPUT@', xsltproc_args, '@INPUT@'], + name, + input : rst, + output : name, + command : [prog_rst2man, '@INPUT@', '@OUTPUT@'], install : true, - install_dir : join_paths(get_option('mandir'), 'man7'), - build_by_default : true, + install_dir : join_paths(get_option('mandir'), 'man' + page[1]), ) endforeach diff --git a/meson.build b/meson.build index 831c883..06f48dd 100644 --- a/meson.build +++ b/meson.build @@ -21,10 +21,10 @@ project( 'libdrm', ['c'], - version : '2.4.102', + version : '2.4.111', license : 'MIT', - meson_version : '>= 0.43', - default_options : ['buildtype=debugoptimized', 'c_std=gnu99'], + meson_version : '>= 0.53', + default_options : ['buildtype=debugoptimized', 'c_std=c99'], ) pkg = import('pkgconfig') @@ -44,6 +44,8 @@ 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') @@ -51,6 +53,13 @@ prog_nm = find_program('nm') 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); } @@ -82,6 +91,7 @@ if _intel != 'false' with_intel = _intel == 'true' or host_machine.cpu_family().startswith('x86') endif endif +summary('Intel', with_intel) with_radeon = false _radeon = get_option('radeon') @@ -91,6 +101,7 @@ if _radeon != 'false' endif with_radeon = true endif +summary('Radeon', with_radeon) with_amdgpu = false _amdgpu = get_option('amdgpu') @@ -100,6 +111,7 @@ if _amdgpu != 'false' endif with_amdgpu = true endif +summary('AMDGPU', with_amdgpu) with_nouveau = false _nouveau = get_option('nouveau') @@ -109,12 +121,14 @@ if _nouveau != 'false' endif with_nouveau = true endif +summary('Nouveau', with_nouveau) with_vmwgfx = false _vmwgfx = get_option('vmwgfx') if _vmwgfx != 'false' with_vmwgfx = true endif +summary('vmwgfx', with_vmwgfx) with_omap = false _omap = get_option('omap') @@ -124,6 +138,7 @@ if _omap == 'true' endif with_omap = true endif +summary('OMAP', with_omap) with_freedreno = false _freedreno = get_option('freedreno') @@ -134,6 +149,8 @@ if _freedreno != 'false' with_freedreno = _freedreno == 'true' or ['arm', 'aarch64'].contains(host_machine.cpu_family()) endif endif +summary('Freedreno', with_freedreno) +summary('Freedreon-kgsl', with_freedreno_kgsl) with_tegra = false _tegra = get_option('tegra') @@ -143,6 +160,7 @@ if _tegra == 'true' endif with_tegra = true endif +summary('Tegra', with_tegra) with_etnaviv = false _etnaviv = get_option('etnaviv') @@ -152,22 +170,17 @@ if _etnaviv == 'true' endif with_etnaviv = true endif +summary('Etnaviv', with_etnaviv) with_exynos = get_option('exynos') == 'true' +summary('EXYNOS', with_exynos) with_vc4 = false _vc4 = get_option('vc4') if _vc4 != 'false' with_vc4 = _vc4 == 'true' or ['arm', 'aarch64'].contains(host_machine.cpu_family()) endif - -# XXX: Apparently only freebsd and dragonfly bsd actually need this (and -# gnu/kfreebsd), not openbsd and netbsd -with_libkms = false -_libkms = get_option('libkms') -if _libkms != 'false' - with_libkms = _libkms == 'true' or ['linux', 'freebsd', 'dragonfly'].contains(host_machine.system()) -endif +summary('VC4', with_vc4) # Among others FreeBSD does not have a separate dl library. if not cc.has_function('dlsym') @@ -196,8 +209,7 @@ else endif foreach header : ['sys/select.h', 'alloca.h'] - config.set10('HAVE_' + header.underscorify().to_upper(), - cc.compiles('#include <@0@>'.format(header), name : '@0@ works'.format(header))) + config.set10('HAVE_' + header.underscorify().to_upper(), cc.check_header(header)) endforeach if (cc.has_header_symbol('sys/sysmacros.h', 'major') and @@ -212,30 +224,15 @@ if (cc.has_header_symbol('sys/mkdev.h', 'major') and endif config.set10('HAVE_OPEN_MEMSTREAM', cc.has_function('open_memstream')) -warn_c_args = [] -foreach a : ['-Wall', '-Wextra', '-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'] - if cc.has_argument(a) - warn_c_args += a - endif -endforeach -# GCC will never error for -Wno-*, so check for -W* then add -Wno-* to the list -# of options -foreach a : ['unused-parameter', 'attributes', 'long-long', - 'missing-field-initializers'] - if cc.has_argument('-W@0@'.format(a)) - warn_c_args += '-Wno-@0@'.format(a) - endif -endforeach - -# all c args: -libdrm_c_args = warn_c_args + ['-fvisibility=hidden'] - +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_pciaccess = dependency('pciaccess', version : '>= 0.10', required : with_intel) dep_cunit = dependency('cunit', version : '>= 2.1', required : false) @@ -261,22 +258,10 @@ else endif with_man_pages = get_option('man-pages') -prog_xslt = find_program('xsltproc', required : with_man_pages == 'true') -prog_sed = find_program('sed', required : with_man_pages == 'true') -manpage_style = 'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl' -if prog_xslt.found() - if run_command(prog_xslt, '--nonet', manpage_style).returncode() != 0 - if with_man_pages == 'true' - error('Manpage style sheet cannot be found') - endif - with_man_pages = 'false' - endif -endif -with_man_pages = with_man_pages != 'false' and prog_xslt.found() and prog_sed.found() +prog_rst2man = find_program('rst2man', 'rst2man.py', required: with_man_pages == 'true') +with_man_pages = with_man_pages != 'false' and prog_rst2man.found() -config.set10('HAVE_VISIBILITY', - cc.compiles('''int foo_hidden(void) __attribute__((visibility(("hidden"))));''', - name : 'compiler supports __attribute__(("hidden"))')) +config.set10('HAVE_VISIBILITY', cc.has_function_attribute('visibility:hidden')) foreach t : [ [with_exynos, 'EXYNOS'], @@ -304,19 +289,29 @@ add_project_arguments('-include', '@0@'.format(config_file), language : 'c') inc_root = include_directories('.') inc_drm = include_directories('include/drm') -libdrm = shared_library( +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', - [files( - 'xf86drm.c', 'xf86drmHash.c', 'xf86drmRandom.c', 'xf86drmSL.c', - 'xf86drmMode.c' - ), - config_file, - ], + libdrm_files, c_args : libdrm_c_args, dependencies : [dep_valgrind, dep_rt, dep_m], include_directories : inc_drm, - version : '2.4.0', install : true, + kwargs : libdrm_kw, + gnu_symbol_visibility : 'hidden', ) test( @@ -334,6 +329,10 @@ ext_libdrm = declare_dependency( 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', @@ -352,16 +351,12 @@ if with_vmwgfx endif pkg.generate( + libdrm, name : 'libdrm', - libraries : libdrm, subdirs : ['.', 'libdrm'], - version : meson.project_version(), description : 'Userspace interface to kernel DRM services', ) -if with_libkms - subdir('libkms') -endif if with_intel subdir('intel') endif @@ -397,20 +392,3 @@ if with_man_pages endif subdir('data') subdir('tests') - -message('') -message('@0@ will be compiled with:'.format(meson.project_name())) -message('') -message(' libkms @0@'.format(with_libkms)) -message(' Intel API @0@'.format(with_intel)) -message(' vmwgfx API @0@'.format(with_vmwgfx)) -message(' Radeon API @0@'.format(with_radeon)) -message(' AMDGPU API @0@'.format(with_amdgpu)) -message(' Nouveau API @0@'.format(with_nouveau)) -message(' OMAP API @0@'.format(with_omap)) -message(' EXYNOS API @0@'.format(with_exynos)) -message(' Freedreno API @0@ (kgsl: @1@)'.format(with_freedreno, with_freedreno_kgsl)) -message(' Tegra API @0@'.format(with_tegra)) -message(' VC4 API @0@'.format(with_vc4)) -message(' Etnaviv API @0@'.format(with_etnaviv)) -message('') diff --git a/meson_options.txt b/meson_options.txt index 8af33f1..f5d066f 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -18,13 +18,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -option( - 'libkms', - type : 'combo', - value : 'auto', - choices : ['true', 'false', 'auto'], - description : 'Build libkms mm abstraction library.', -) option( 'intel', type : 'combo', diff --git a/nouveau/meson.build b/nouveau/meson.build index 9bd58fc..350f34c 100644 --- a/nouveau/meson.build +++ b/nouveau/meson.build @@ -19,10 +19,11 @@ # SOFTWARE. -libdrm_nouveau = shared_library( +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], @@ -35,6 +36,10 @@ ext_libdrm_nouveau = declare_dependency( 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', @@ -43,11 +48,9 @@ install_headers( ) pkg.generate( + libdrm_nouveau, name : 'libdrm_nouveau', - libraries : libdrm_nouveau, subdirs : ['.', 'libdrm', 'libdrm/nouveau'], - version : meson.project_version(), - requires_private : 'libdrm', description : 'Userspace interface to nouveau kernel DRM services', ) diff --git a/nouveau/nouveau-symbols.txt b/nouveau/nouveau-symbols.txt index ef8032f..598465f 100644 --- a/nouveau/nouveau-symbols.txt +++ b/nouveau/nouveau-symbols.txt @@ -12,6 +12,7 @@ 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 diff --git a/nouveau/nouveau.c b/nouveau/nouveau.c index f18d142..7b4efde 100644 --- a/nouveau/nouveau.c +++ b/nouveau/nouveau.c @@ -46,19 +46,35 @@ #include "nvif/ioctl.h" #include "nvif/unpack.h" -#ifdef DEBUG +drm_private FILE *nouveau_out = NULL; drm_private uint32_t nouveau_debug = 0; static void -debug_init(char *args) +debug_init(void) { - if (args) { - int n = strtol(args, NULL, 0); + 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; } } -#endif static int nouveau_object_ioctl(struct nouveau_object *obj, void *data, uint32_t size) @@ -327,9 +343,7 @@ nouveau_drm_new(int fd, struct nouveau_drm **pdrm) struct nouveau_drm *drm; drmVersionPtr ver; -#ifdef DEBUG - debug_init(getenv("NOUVEAU_LIBDRM_DEBUG")); -#endif + debug_init(); if (!(drm = calloc(1, sizeof(*drm)))) return -ENOMEM; @@ -593,7 +607,6 @@ 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); - struct drm_gem_close req = { .handle = bo->handle }; if (nvbo->head.next) { pthread_mutex_lock(&nvdev->lock); @@ -607,11 +620,11 @@ nouveau_bo_del(struct nouveau_bo *bo) * might cause the bo to be closed accidentally while * re-importing. */ - drmIoctl(drm->fd, DRM_IOCTL_GEM_CLOSE, &req); + drmCloseBufferHandle(drm->fd, bo->handle); } pthread_mutex_unlock(&nvdev->lock); } else { - drmIoctl(drm->fd, DRM_IOCTL_GEM_CLOSE, &req); + drmCloseBufferHandle(drm->fd, bo->handle); } if (bo->map) drm_munmap(bo->map, bo->size); diff --git a/nouveau/nouveau.h b/nouveau/nouveau.h index 335ce77..0c632fe 100644 --- a/nouveau/nouveau.h +++ b/nouveau/nouveau.h @@ -273,4 +273,8 @@ struct nv04_notify { uint32_t offset; uint32_t length; }; + +bool +nouveau_check_dead_channel(struct nouveau_drm *, struct nouveau_object *chan); + #endif diff --git a/nouveau/private.h b/nouveau/private.h index 034a958..b81d4b1 100644 --- a/nouveau/private.h +++ b/nouveau/private.h @@ -1,6 +1,8 @@ #ifndef __NOUVEAU_LIBDRM_PRIVATE_H__ #define __NOUVEAU_LIBDRM_PRIVATE_H__ +#include + #include #include #include @@ -9,18 +11,19 @@ #include "nouveau.h" -#ifdef DEBUG +/* + * 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(stderr, "nouveau: "fmt, ##args); \ + fprintf(nouveau_out, "nouveau: "fmt, ##args); \ } while(0) -#else -#define dbg_on(lvl) (0) -#define dbg(lvl, fmt, args...) -#endif -#define err(fmt, args...) fprintf(stderr, "nouveau: "fmt, ##args) +#define err(fmt, args...) fprintf(nouveau_out, "nouveau: "fmt, ##args) struct nouveau_client_kref { struct drm_nouveau_gem_pushbuf_bo *kref; diff --git a/nouveau/pushbuf.c b/nouveau/pushbuf.c index e5f73f0..5d54f21 100644 --- a/nouveau/pushbuf.c +++ b/nouveau/pushbuf.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -274,9 +275,10 @@ pushbuf_dump(struct nouveau_pushbuf_krec *krec, int krec_id, int chid) kref = krec->buffer; for (i = 0; i < krec->nr_buffer; i++, kref++) { - err("ch%d: buf %08x %08x %08x %08x %08x\n", chid, i, + 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); + kref->read_domains, kref->write_domains, bo->map, bo->offset, bo->size); } krel = krec->reloc; @@ -292,11 +294,14 @@ pushbuf_dump(struct nouveau_pushbuf_krec *krec, int krec_id, int chid) 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 /4); + end = bgn + ((kpsh->length & 0x7fffff) /4); - err("ch%d: psh %08x %010llx %010llx\n", chid, kpsh->bo_index, + 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++); } @@ -336,6 +341,8 @@ pushbuf_submit(struct nouveau_pushbuf *push, struct nouveau_object *chan) 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)) @@ -775,3 +782,19 @@ nouveau_pushbuf_kick(struct nouveau_pushbuf *push, struct nouveau_object *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/meson.build b/omap/meson.build index 53330b6..2215918 100644 --- a/omap/meson.build +++ b/omap/meson.build @@ -18,11 +18,12 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -libdrm_omap = shared_library( +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', @@ -34,15 +35,18 @@ ext_libdrm_omap = declare_dependency( 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', - libraries : libdrm_omap, subdirs : ['.', 'libdrm', 'omap'], version : '0.6', - requires_private : 'libdrm', description : 'Userspace interface to omap kernel DRM services', ) diff --git a/omap/omap_drm.c b/omap/omap_drm.c index ffacea6..aa27366 100644 --- a/omap/omap_drm.c +++ b/omap/omap_drm.c @@ -174,10 +174,7 @@ static struct omap_bo * bo_from_handle(struct omap_device *dev, { struct omap_bo *bo = calloc(sizeof(*bo), 1); if (!bo) { - struct drm_gem_close req = { - .handle = handle, - }; - drmIoctl(dev->fd, DRM_IOCTL_GEM_CLOSE, &req); + drmCloseBufferHandle(dev->fd, handle); return NULL; } bo->dev = omap_device_ref(dev); @@ -365,12 +362,9 @@ drm_public void omap_bo_del(struct omap_bo *bo) } if (bo->handle) { - struct drm_gem_close req = { - .handle = bo->handle, - }; pthread_mutex_lock(&table_lock); drmHashDelete(bo->dev->handle_table, bo->handle); - drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req); + drmCloseBufferHandle(bo->dev->fd, bo->handle); pthread_mutex_unlock(&table_lock); } diff --git a/radeon/meson.build b/radeon/meson.build index ca12832..4c1c71e 100644 --- a/radeon/meson.build +++ b/radeon/meson.build @@ -19,7 +19,7 @@ # SOFTWARE. -libdrm_radeon = shared_library( +libdrm_radeon = library( 'drm_radeon', [ files( @@ -29,6 +29,7 @@ libdrm_radeon = shared_library( 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], @@ -41,6 +42,10 @@ ext_libdrm_radeon = declare_dependency( 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', @@ -48,11 +53,9 @@ install_headers( ) pkg.generate( + libdrm_radeon, name : 'libdrm_radeon', - libraries : libdrm_radeon, subdirs : ['.', 'libdrm'], - version : meson.project_version(), - requires_private : 'libdrm', description : 'Userspace interface to kernel DRM services for radeon', ) diff --git a/radeon/radeon_bo.h b/radeon/radeon_bo.h index 37478a0..6e20c6c 100644 --- a/radeon/radeon_bo.h +++ b/radeon/radeon_bo.h @@ -48,7 +48,6 @@ struct radeon_bo { uint32_t size; }; -struct radeon_bo_manager; void radeon_bo_debug(struct radeon_bo *bo, const char *op); diff --git a/radeon/radeon_bo_gem.c b/radeon/radeon_bo_gem.c index 86f7c00..bbe72ce 100644 --- a/radeon/radeon_bo_gem.c +++ b/radeon/radeon_bo_gem.c @@ -125,7 +125,6 @@ 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; - struct drm_gem_close args; if (boi->cref) { return (struct radeon_bo *)boi; @@ -134,12 +133,8 @@ static struct radeon_bo *bo_unref(struct radeon_bo_int *boi) drm_munmap(bo_gem->priv_ptr, boi->size); } - /* Zero out args to make valgrind happy */ - memset(&args, 0, sizeof(args)); - /* close object */ - args.handle = boi->handle; - drmIoctl(boi->bom->fd, DRM_IOCTL_GEM_CLOSE, &args); + drmCloseBufferHandle(boi->bom->fd, boi->handle); memset(bo_gem, 0, sizeof(struct radeon_bo_gem)); free(bo_gem); return NULL; 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/meson.build b/tegra/meson.build index 88613b9..0b63d78 100644 --- a/tegra/meson.build +++ b/tegra/meson.build @@ -18,13 +18,19 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -libdrm_tegra = shared_library( +libdrm_tegra = library( 'drm_tegra', - [files('tegra.c'), config_file], + [ + 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, ) @@ -34,14 +40,16 @@ ext_libdrm_tegra = declare_dependency( 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', - libraries : libdrm_tegra, subdirs : ['.', 'libdrm'], - version : meson.project_version(), - requires_private : 'libdrm', description : 'Userspace interface to Tegra kernel DRM services', ) diff --git a/tegra/private.h b/tegra/private.h index bb6c1a5..fc204e8 100644 --- a/tegra/private.h +++ b/tegra/private.h @@ -26,26 +26,93 @@ #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; + bool close; + int fd; }; struct drm_tegra_bo { - struct drm_tegra *drm; - uint32_t handle; - uint32_t offset; - uint32_t flags; - uint32_t size; - atomic_t ref; - void *map; + 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 index 5e3e955..1a75c3d 100644 --- a/tegra/tegra-symbols.txt +++ b/tegra/tegra-symbols.txt @@ -1,13 +1,32 @@ -drm_tegra_bo_get_flags +drm_tegra_bo_export drm_tegra_bo_get_handle -drm_tegra_bo_get_tiling +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_set_flags -drm_tegra_bo_set_tiling 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 index cf00a3c..6a51c43 100644 --- a/tegra/tegra.c +++ b/tegra/tegra.c @@ -37,292 +37,318 @@ static void drm_tegra_bo_free(struct drm_tegra_bo *bo) { - struct drm_tegra *drm = bo->drm; - struct drm_gem_close args; + struct drm_tegra *drm = bo->drm; - if (bo->map) - munmap(bo->map, bo->size); + if (bo->map) + munmap(bo->map, bo->size); - memset(&args, 0, sizeof(args)); - args.handle = bo->handle; + drmCloseBufferHandle(drm->fd, bo->handle); - drmIoctl(drm->fd, DRM_IOCTL_GEM_CLOSE, &args); - - free(bo); + free(bo); } static int drm_tegra_wrap(struct drm_tegra **drmp, int fd, bool close) { - struct drm_tegra *drm; + struct drm_tegra *drm; - if (fd < 0 || !drmp) - return -EINVAL; + if (fd < 0 || !drmp) + return -EINVAL; - drm = calloc(1, sizeof(*drm)); - if (!drm) - return -ENOMEM; + drm = calloc(1, sizeof(*drm)); + if (!drm) + return -ENOMEM; - drm->close = close; - drm->fd = fd; + drm->close = close; + drm->fd = fd; - *drmp = drm; + *drmp = drm; - return 0; + return 0; } -drm_public int drm_tegra_new(struct drm_tegra **drmp, int fd) +drm_public int drm_tegra_new(int fd, struct drm_tegra **drmp) { - bool supported = false; - drmVersionPtr version; + bool supported = false; + drmVersionPtr version; - version = drmGetVersion(fd); - if (!version) - return -ENOMEM; + version = drmGetVersion(fd); + if (!version) + return -ENOMEM; - if (!strncmp(version->name, "tegra", version->name_len)) - supported = true; + if (!strncmp(version->name, "tegra", version->name_len)) + supported = true; - drmFreeVersion(version); + drmFreeVersion(version); - if (!supported) - return -ENOTSUP; + if (!supported) + return -ENOTSUP; - return drm_tegra_wrap(drmp, fd, false); + return drm_tegra_wrap(drmp, fd, false); } drm_public void drm_tegra_close(struct drm_tegra *drm) { - if (!drm) - return; + if (!drm) + return; - if (drm->close) - close(drm->fd); + if (drm->close) + close(drm->fd); - free(drm); + free(drm); } -drm_public int drm_tegra_bo_new(struct drm_tegra_bo **bop, struct drm_tegra *drm, - uint32_t flags, uint32_t size) +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_gem_create args; - struct drm_tegra_bo *bo; - int err; + struct drm_tegra_bo *bo; + + bo = calloc(1, sizeof(*bo)); + if (!bo) + return NULL; - if (!drm || size == 0 || !bop) - return -EINVAL; + atomic_set(&bo->ref, 1); + bo->handle = handle; + bo->flags = flags; + bo->size = size; + bo->drm = drm; - bo = calloc(1, sizeof(*bo)); - if (!bo) - return -ENOMEM; + 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; - atomic_set(&bo->ref, 1); - bo->flags = flags; - bo->size = size; - bo->drm = drm; + if (!drm || size == 0 || !bop) + return -EINVAL; - memset(&args, 0, sizeof(args)); - args.flags = flags; - args.size = size; + bo = drm_tegra_bo_alloc(drm, 0, flags, size); + if (!bo) + return -ENOMEM; - err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_CREATE, &args, - sizeof(args)); - if (err < 0) { - err = -errno; - free(bo); - return err; - } + memset(&args, 0, sizeof(args)); + args.flags = flags; + args.size = size; - bo->handle = args.handle; + err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_CREATE, &args, + sizeof(args)); + if (err < 0) { + err = -errno; + free(bo); + return err; + } - *bop = bo; + bo->handle = args.handle; - return 0; + *bop = bo; + + return 0; } -drm_public int drm_tegra_bo_wrap(struct drm_tegra_bo **bop, struct drm_tegra *drm, - uint32_t handle, uint32_t flags, uint32_t size) +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; + struct drm_tegra_bo *bo; - bo = calloc(1, sizeof(*bo)); - if (!bo) - return -ENOMEM; + if (!drm || !bop) + return -EINVAL; - atomic_set(&bo->ref, 1); - bo->handle = handle; - bo->flags = flags; - bo->size = size; - bo->drm = drm; + bo = drm_tegra_bo_alloc(drm, handle, flags, size); + if (!bo) + return -ENOMEM; - *bop = bo; + *bop = bo; - return 0; + return 0; } drm_public struct drm_tegra_bo *drm_tegra_bo_ref(struct drm_tegra_bo *bo) { - if (bo) - atomic_inc(&bo->ref); + if (bo) + atomic_inc(&bo->ref); - return bo; + 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); + 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) +drm_public int +drm_tegra_bo_get_handle(struct drm_tegra_bo *bo, uint32_t *handle) { - if (!bo || !handle) - return -EINVAL; + if (!bo || !handle) + return -EINVAL; - *handle = bo->handle; + *handle = bo->handle; - return 0; + return 0; } drm_public int drm_tegra_bo_map(struct drm_tegra_bo *bo, void **ptr) { - struct drm_tegra *drm = bo->drm; + struct drm_tegra *drm = bo->drm; - if (!bo->map) { - struct drm_tegra_gem_mmap args; - int err; + if (!bo->map) { + struct drm_tegra_gem_mmap args; + int err; - memset(&args, 0, sizeof(args)); - args.handle = bo->handle; + 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; + err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_MMAP, &args, + sizeof(args)); + if (err < 0) + return -errno; - bo->offset = args.offset; + bo->offset = args.offset; - bo->map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, - drm->fd, bo->offset); - if (bo->map == MAP_FAILED) { - bo->map = NULL; - return -errno; - } - } + 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; + if (ptr) + *ptr = bo->map; - return 0; + return 0; } drm_public int drm_tegra_bo_unmap(struct drm_tegra_bo *bo) { - if (!bo) - return -EINVAL; + if (!bo) + return -EINVAL; - if (!bo->map) - return 0; + if (!bo->map) + return 0; - if (munmap(bo->map, bo->size)) - return -errno; + if (munmap(bo->map, bo->size)) + return -errno; - bo->map = NULL; + bo->map = NULL; - return 0; + return 0; } -drm_public int drm_tegra_bo_get_flags(struct drm_tegra_bo *bo, uint32_t *flags) +drm_public int drm_tegra_bo_get_name(struct drm_tegra_bo *bo, uint32_t *name) { - struct drm_tegra_gem_get_flags args; - struct drm_tegra *drm = bo->drm; - int err; + struct drm_tegra *drm = bo->drm; + struct drm_gem_flink args; + int err; - if (!bo) - return -EINVAL; + memset(&args, 0, sizeof(args)); + args.handle = bo->handle; - memset(&args, 0, sizeof(args)); - args.handle = bo->handle; + err = drmIoctl(drm->fd, DRM_IOCTL_GEM_FLINK, &args); + if (err < 0) + return err; - err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_GET_FLAGS, &args, - sizeof(args)); - if (err < 0) - return -errno; + if (name) + *name = args.name; - if (flags) - *flags = args.flags; - - return 0; + return 0; } -drm_public int drm_tegra_bo_set_flags(struct drm_tegra_bo *bo, uint32_t flags) +drm_public int +drm_tegra_bo_open(struct drm_tegra *drm, uint32_t name, uint32_t flags, + struct drm_tegra_bo **bop) { - struct drm_tegra_gem_get_flags args; - struct drm_tegra *drm = bo->drm; - int err; + 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; - if (!bo) - return -EINVAL; + memset(&args, 0, sizeof(args)); + args.name = name; - memset(&args, 0, sizeof(args)); - args.handle = bo->handle; - args.flags = flags; + err = drmIoctl(drm->fd, DRM_IOCTL_GEM_OPEN, &args); + if (err < 0) + goto free; - err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_SET_FLAGS, &args, - sizeof(args)); - if (err < 0) - return -errno; + bo->handle = args.handle; + bo->size = args.size; - return 0; + *bop = bo; + + return 0; + +free: + free(bo); + return err; } -drm_public int drm_tegra_bo_get_tiling(struct drm_tegra_bo *bo, - struct drm_tegra_bo_tiling *tiling) +drm_public int drm_tegra_bo_export(struct drm_tegra_bo *bo, uint32_t flags) { - struct drm_tegra_gem_get_tiling args; - struct drm_tegra *drm = bo->drm; - int err; + int fd, err; - if (!bo) - return -EINVAL; + flags |= DRM_CLOEXEC; - memset(&args, 0, sizeof(args)); - args.handle = bo->handle; + err = drmPrimeHandleToFD(bo->drm->fd, bo->handle, flags, &fd); + if (err < 0) + return err; - err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_GET_TILING, &args, - sizeof(args)); - if (err < 0) - return -errno; + return fd; +} + +static ssize_t fd_get_size(int fd) +{ + ssize_t size, offset; + int err; - if (tiling) { - tiling->mode = args.mode; - tiling->value = args.value; - } + offset = lseek(fd, 0, SEEK_CUR); + if (offset < 0) + return -errno; - return 0; + 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_set_tiling(struct drm_tegra_bo *bo, - const struct drm_tegra_bo_tiling *tiling) +drm_public int +drm_tegra_bo_import(struct drm_tegra *drm, int fd, struct drm_tegra_bo **bop) { - struct drm_tegra_gem_set_tiling args; - struct drm_tegra *drm = bo->drm; - int err; + 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; - if (!bo) - return -EINVAL; + err = drmPrimeFDToHandle(drm->fd, fd, &bo->handle); + if (err < 0) + goto free; - memset(&args, 0, sizeof(args)); - args.handle = bo->handle; - args.mode = tiling->mode; - args.value = tiling->value; + *bop = bo; - err = drmCommandWriteRead(drm->fd, DRM_TEGRA_GEM_SET_TILING, &args, - sizeof(args)); - if (err < 0) - return -errno; + return 0; - return 0; +free: + free(bo); + return err; } diff --git a/tegra/tegra.h b/tegra/tegra.h index 31b0995..8f3c055 100644 --- a/tegra/tegra.h +++ b/tegra/tegra.h @@ -28,33 +28,100 @@ #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(struct drm_tegra **drmp, int fd); +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_bo **bop, struct drm_tegra *drm, - uint32_t flags, uint32_t size); -int drm_tegra_bo_wrap(struct drm_tegra_bo **bop, struct drm_tegra *drm, - uint32_t handle, uint32_t flags, uint32_t size); +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_flags(struct drm_tegra_bo *bo, uint32_t *flags); -int drm_tegra_bo_set_flags(struct drm_tegra_bo *bo, uint32_t flags); +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; -struct drm_tegra_bo_tiling { - uint32_t mode; - uint32_t value; +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_bo_get_tiling(struct drm_tegra_bo *bo, - struct drm_tegra_bo_tiling *tiling); -int drm_tegra_bo_set_tiling(struct drm_tegra_bo *bo, - const struct drm_tegra_bo_tiling *tiling); +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/amdgpu/.editorconfig b/tests/amdgpu/.editorconfig deleted file mode 120000 index 70734e4..0000000 --- a/tests/amdgpu/.editorconfig +++ /dev/null @@ -1 +0,0 @@ -../../amdgpu/.editorconfig \ No newline at end of file diff --git a/tests/amdgpu/.editorconfig b/tests/amdgpu/.editorconfig new file mode 100644 index 0000000..426273f --- /dev/null +++ b/tests/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/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 index 47e1676..7f3aee4 100644 --- a/tests/amdgpu/amdgpu_test.c +++ b/tests/amdgpu/amdgpu_test.c @@ -37,6 +37,18 @@ #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" @@ -53,11 +65,15 @@ #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 @@ -100,6 +116,12 @@ static CU_SuiteInfo suites[] = { .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, @@ -130,6 +152,24 @@ static CU_SuiteInfo suites[] = { .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, }; @@ -149,7 +189,7 @@ static CU_BOOL always_active() static Suites_Active_Status suites_active_stat[] = { { .pName = BASIC_TESTS_STR, - .pActive = always_active, + .pActive = suite_basic_tests_enable, }, { .pName = BO_TESTS_STR, @@ -167,6 +207,10 @@ static Suites_Active_Status suites_active_stat[] = { .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, @@ -187,6 +231,18 @@ static Suites_Active_Status suites_active_stat[] = { .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, + }, }; @@ -266,6 +322,10 @@ static int amdgpu_open_devices(int open_render_node) 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) { @@ -328,12 +388,13 @@ static int amdgpu_open_devices(int open_render_node) /* Close AMD devices. */ -static void amdgpu_close_devices() +void amdgpu_close_devices() { int i; for (i = 0; i < MAX_CARDS_SUPPORTED; i++) - if (drm_amdgpu[i] >=0) + if (drm_amdgpu[i] >=0) { close(drm_amdgpu[i]); + } } /* Print AMD devices information */ @@ -419,7 +480,8 @@ static void amdgpu_disable_suites() { amdgpu_device_handle device_handle; uint32_t major_version, minor_version, family_id; - int i; + 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, @@ -431,6 +493,8 @@ static void amdgpu_disable_suites() 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, @@ -485,9 +549,6 @@ static void amdgpu_disable_suites() "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(BO_TESTS_STR, "Metadata", 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()); @@ -513,6 +574,84 @@ static void amdgpu_disable_suites() //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. @@ -530,7 +669,6 @@ int main(int argc, char **argv) int display_devices = 0;/* By default not to display devices' info */ CU_pSuite pSuite = NULL; CU_pTest pTest = NULL; - int test_device_index; int display_list = 0; int force_run = 0; diff --git a/tests/amdgpu/amdgpu_test.h b/tests/amdgpu/amdgpu_test.h index f549225..9f4453d 100644 --- a/tests/amdgpu/amdgpu_test.h +++ b/tests/amdgpu/amdgpu_test.h @@ -54,6 +54,11 @@ int suite_basic_tests_init(); */ 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 */ @@ -134,6 +139,26 @@ CU_BOOL suite_vcn_tests_enable(void); + */ 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 */ @@ -236,11 +261,81 @@ CU_BOOL suite_syncobj_timeline_tests_enable(void); */ 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[]; + void amdgpu_dispatch_hang_helper(amdgpu_device_handle device_handle, uint32_t ip_type); void amdgpu_dispatch_hang_slow_helper(amdgpu_device_handle device_handle, uint32_t ip_type); void amdgpu_memcpy_draw_test(amdgpu_device_handle device_handle, uint32_t ring, - int hang); -void amdgpu_memcpy_draw_hang_slow_test(amdgpu_device_handle device_handle, uint32_t ring); + int version, int hang); +void amdgpu_memcpy_draw_hang_slow_test(amdgpu_device_handle device_handle, uint32_t ring, int version); + +/** + * 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); + + + +/** + * 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 @@ -418,4 +513,35 @@ static inline CU_ErrorCode amdgpu_set_test_active(const char *suite_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 index 57496c8..688260d 100644 --- a/tests/amdgpu/basic_tests.c +++ b/tests/amdgpu/basic_tests.c @@ -39,12 +39,15 @@ #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); @@ -59,6 +62,7 @@ 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); @@ -69,7 +73,7 @@ static void amdgpu_test_exec_cs_helper(amdgpu_context_handle context_handle, 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 }, @@ -84,6 +88,7 @@ CU_TestInfo basic_tests[] = { { "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())) @@ -106,6 +111,20 @@ CU_TestInfo basic_tests[] = { #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 @@ -157,6 +176,20 @@ CU_TestInfo basic_tests[] = { * 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 @@ -259,6 +292,8 @@ CU_TestInfo basic_tests[] = { #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 @@ -312,9 +347,16 @@ enum cs_type { }; static const uint32_t bufferclear_cs_shader_gfx9[] = { - 0xD1FD0000, 0x04010C08, 0x7E020204, 0x7E040205, - 0x7E060206, 0x7E080207, 0xE01C2000, 0x80000100, - 0xBF810000 + 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] = { @@ -328,8 +370,14 @@ static const uint32_t bufferclear_cs_shader_registers_gfx9[][2] = { static const uint32_t bufferclear_cs_shader_registers_num_gfx9 = 5; static const uint32_t buffercopy_cs_shader_gfx9[] = { - 0xD1FD0000, 0x04010C08, 0xE00C2000, 0x80000100, - 0xBF8C0F70, 0xE01C2000, 0x80010100, 0xBF810000 + 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[] = { @@ -355,6 +403,32 @@ static const uint32_t preamblecache_gfx9[] = { 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, @@ -407,6 +481,39 @@ static const uint32_t ps_const_context_reg_gfx9[][2] = { {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, @@ -450,6 +557,34 @@ static const uint32_t ps_tex_context_reg_gfx9[][2] = { {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, @@ -461,6 +596,17 @@ static const uint32_t vs_RectPosTexFast_shader_gfx9[] = { 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, @@ -472,6 +618,17 @@ static const uint32_t cached_cmd_gfx9[] = { 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, @@ -511,6 +668,18 @@ struct amdgpu_test_shader memcpy_cs_hang_slow_rv = { 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, @@ -586,6 +755,45 @@ int amdgpu_bo_alloc_and_map_raw(amdgpu_device_handle dev, unsigned size, +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}; @@ -1000,6 +1208,14 @@ static void amdgpu_semaphore_test(void) 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); @@ -1042,14 +1258,14 @@ static void amdgpu_semaphore_test(void) 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], AMDGPU_HW_IP_GFX, 0, 0, sem); + 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 = AMDGPU_HW_IP_GFX; + 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]; @@ -1059,7 +1275,7 @@ static void amdgpu_semaphore_test(void) CU_ASSERT_EQUAL(r, 0); fence_status.context = context_handle[0]; - fence_status.ip_type = AMDGPU_HW_IP_GFX; + 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, @@ -1073,24 +1289,24 @@ static void amdgpu_semaphore_test(void) ib_info[0].ib_mc_address = ib_result_mc_address[0]; ib_info[0].size = 1; - ibs_request[0].ip_type = AMDGPU_HW_IP_GFX; + 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], AMDGPU_HW_IP_GFX, 0, 0, sem); + 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], AMDGPU_HW_IP_GFX, 0, 0, sem); + 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 = AMDGPU_HW_IP_GFX; + 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]; @@ -1100,7 +1316,7 @@ static void amdgpu_semaphore_test(void) CU_ASSERT_EQUAL(r, 0); fence_status.context = context_handle[1]; - fence_status.ip_type = AMDGPU_HW_IP_GFX; + 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, @@ -1232,12 +1448,15 @@ static void amdgpu_command_submission_compute(void) * pm4_src, resources, ib_info, and ibs_request * submit command stream described in ibs_request and wait for this IB accomplished */ -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) +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; @@ -1269,6 +1488,8 @@ static void amdgpu_test_exec_cs_helper(amdgpu_context_handle context_handle, 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; @@ -1310,7 +1531,24 @@ static void amdgpu_test_exec_cs_helper(amdgpu_context_handle context_handle, CU_ASSERT_EQUAL(r, 0); } -static void amdgpu_command_submission_write_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) +{ + 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; @@ -1322,6 +1560,7 @@ static void amdgpu_command_submission_write_linear_helper(unsigned ip_type) 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; @@ -1336,10 +1575,14 @@ static void amdgpu_command_submission_write_linear_helper(unsigned ip_type) 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); + r = amdgpu_query_hw_ip_info(device, ip_type, 0, &hw_ip_info); CU_ASSERT_EQUAL(r, 0); - r = amdgpu_cs_ctx_create(device_handle, &context_handle); + 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 */ @@ -1350,7 +1593,7 @@ static void amdgpu_command_submission_write_linear_helper(unsigned ip_type) loop = 0; while(loop < 2) { /* allocate UC bo for sDMA use */ - r = amdgpu_bo_alloc_and_map(device_handle, + 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, @@ -1370,8 +1613,9 @@ static void amdgpu_command_submission_write_linear_helper(unsigned ip_type) sdma_write_length); else pm4[i++] = SDMA_PACKET(SDMA_OPCODE_WRITE, - SDMA_WRITE_SUB_OPCODE_LINEAR, 0); - pm4[i++] = 0xffffffff & bo_mc; + 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; @@ -1389,16 +1633,99 @@ static void amdgpu_command_submission_write_linear_helper(unsigned ip_type) pm4[i++] = 0xdeadbeaf; } - amdgpu_test_exec_cs_helper(context_handle, - ip_type, ring_id, - i, pm4, - 1, resources, - ib_info, ibs_request); + 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; - while(i < sdma_write_length) { - CU_ASSERT_EQUAL(bo_cpu[i++], 0xdeadbeaf); + 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, @@ -1418,6 +1745,13 @@ static void amdgpu_command_submission_write_linear_helper(unsigned ip_type) 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); @@ -2135,6 +2469,9 @@ static int amdgpu_dispatch_load_cs_shader_hang_slow(uint32_t *ptr, int family) case AMDGPU_FAMILY_RV: shader = &memcpy_cs_hang_slow_rv; break; + case AMDGPU_FAMILY_NV: + shader = &memcpy_cs_hang_slow_nv; + break; default: return -1; break; @@ -2155,19 +2492,30 @@ static int amdgpu_dispatch_load_cs_shader_hang_slow(uint32_t *ptr, int family) } static int amdgpu_dispatch_load_cs_shader(uint8_t *ptr, - int cs_type) + int cs_type, + uint32_t version) { uint32_t shader_size; const uint32_t *shader; switch (cs_type) { case CS_BUFFERCLEAR: - shader = bufferclear_cs_shader_gfx9; - shader_size = sizeof(bufferclear_cs_shader_gfx9); + if (version == 9) { + shader = bufferclear_cs_shader_gfx9; + shader_size = sizeof(bufferclear_cs_shader_gfx9); + } else if (version == 10) { + shader = bufferclear_cs_shader_gfx10; + shader_size = sizeof(bufferclear_cs_shader_gfx10); + } break; case CS_BUFFERCOPY: - shader = buffercopy_cs_shader_gfx9; - shader_size = sizeof(buffercopy_cs_shader_gfx9); + if (version == 9) { + shader = buffercopy_cs_shader_gfx9; + shader_size = sizeof(buffercopy_cs_shader_gfx9); + } else if (version == 10) { + shader = buffercopy_cs_shader_gfx10; + shader_size = sizeof(buffercopy_cs_shader_gfx10); + } break; case CS_HANG: shader = memcpy_ps_hang; @@ -2182,7 +2530,7 @@ static int amdgpu_dispatch_load_cs_shader(uint8_t *ptr, return 0; } -static int amdgpu_dispatch_init(uint32_t *ptr, uint32_t ip_type) +static int amdgpu_dispatch_init(uint32_t *ptr, uint32_t ip_type, uint32_t version) { int i = 0; @@ -2204,29 +2552,57 @@ static int amdgpu_dispatch_init(uint32_t *ptr, uint32_t ip_type) ptr[i++] = 0x218; ptr[i++] = 0; + /* Set new sh registers in GFX10 to 0 */ + if (version == 10) { + /* mmCOMPUTE_SHADER_CHKSUM */ + ptr[i++] = PACKET3_COMPUTE(PKT3_SET_SH_REG, 1); + ptr[i++] = 0x22a; + ptr[i++] = 0; + /* mmCOMPUTE_REQ_CTRL */ + ptr[i++] = PACKET3_COMPUTE(PKT3_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; + } return i; } -static int amdgpu_dispatch_write_cumask(uint32_t *ptr) +static int amdgpu_dispatch_write_cumask(uint32_t *ptr, uint32_t version) { int i = 0; /* Issue commands to set cu mask used in current dispatch */ - /* set mmCOMPUTE_STATIC_THREAD_MGMT_SE1 - mmCOMPUTE_STATIC_THREAD_MGMT_SE0 */ - ptr[i++] = PACKET3_COMPUTE(PKT3_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(PKT3_SET_SH_REG, 2); - ptr[i++] = 0x219; - ptr[i++] = 0xffffffff; - ptr[i++] = 0xffffffff; + if (version == 9) { + /* set mmCOMPUTE_STATIC_THREAD_MGMT_SE1 - mmCOMPUTE_STATIC_THREAD_MGMT_SE0 */ + ptr[i++] = PACKET3_COMPUTE(PKT3_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(PKT3_SET_SH_REG, 2); + ptr[i++] = 0x219; + ptr[i++] = 0xffffffff; + ptr[i++] = 0xffffffff; + } else if (version == 10) { + /* set mmCOMPUTE_STATIC_THREAD_MGMT_SE1 - mmCOMPUTE_STATIC_THREAD_MGMT_SE0 */ + ptr[i++] = PACKET3_COMPUTE(PKT3_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(PKT3_SET_SH_REG_INDEX, 2); + ptr[i++] = 0x30000219; + ptr[i++] = 0xffffffff; + ptr[i++] = 0xffffffff; + } return i; } -static int amdgpu_dispatch_write2hw(uint32_t *ptr, uint64_t shader_addr) +static int amdgpu_dispatch_write2hw(uint32_t *ptr, uint64_t shader_addr, uint32_t version) { int i, j; @@ -2246,12 +2622,20 @@ static int amdgpu_dispatch_write2hw(uint32_t *ptr, uint64_t shader_addr) ptr[i++] = bufferclear_cs_shader_registers_gfx9[j][1]; } + if (version == 10) { + /* mmCOMPUTE_PGM_RSRC3 */ + ptr[i++] = PACKET3_COMPUTE(PKT3_SET_SH_REG, 1); + ptr[i++] = 0x228; + ptr[i++] = 0; + } + return i; } static void amdgpu_memset_dispatch_test(amdgpu_device_handle device_handle, uint32_t ip_type, - uint32_t ring) + uint32_t ring, + uint32_t version) { amdgpu_context_handle context_handle; amdgpu_bo_handle bo_dst, bo_shader, bo_cmd, resources[3]; @@ -2287,7 +2671,7 @@ static void amdgpu_memset_dispatch_test(amdgpu_device_handle device_handle, CU_ASSERT_EQUAL(r, 0); memset(ptr_shader, 0, bo_shader_size); - r = amdgpu_dispatch_load_cs_shader(ptr_shader, CS_BUFFERCLEAR); + r = amdgpu_dispatch_load_cs_shader(ptr_shader, CS_BUFFERCLEAR, version); CU_ASSERT_EQUAL(r, 0); r = amdgpu_bo_alloc_and_map(device_handle, bo_dst_size, 4096, @@ -2297,13 +2681,13 @@ static void amdgpu_memset_dispatch_test(amdgpu_device_handle device_handle, CU_ASSERT_EQUAL(r, 0); i = 0; - i += amdgpu_dispatch_init(ptr_cmd + i, ip_type); + i += amdgpu_dispatch_init(ptr_cmd + i, ip_type, version); /* Issue commands to set cu mask used in current dispatch */ - i += amdgpu_dispatch_write_cumask(ptr_cmd + i); + i += amdgpu_dispatch_write_cumask(ptr_cmd + i, version); /* Writes shader state to HW */ - i += amdgpu_dispatch_write2hw(ptr_cmd + i, mc_address_shader); + i += amdgpu_dispatch_write2hw(ptr_cmd + i, mc_address_shader, version); /* Write constant data */ /* Writes the UAV constant data to the SGPRs. */ @@ -2312,7 +2696,10 @@ static void amdgpu_memset_dispatch_test(amdgpu_device_handle device_handle, ptr_cmd[i++] = mc_address_dst; ptr_cmd[i++] = (mc_address_dst >> 32) | 0x100000; ptr_cmd[i++] = 0x400; - ptr_cmd[i++] = 0x74fac; + if (version == 9) + ptr_cmd[i++] = 0x74fac; + else if (version == 10) + ptr_cmd[i++] = 0x1104bfac; /* Sets a range of pixel shader constants */ ptr_cmd[i++] = PACKET3_COMPUTE(PKT3_SET_SH_REG, 4); @@ -2394,6 +2781,7 @@ static void amdgpu_memset_dispatch_test(amdgpu_device_handle device_handle, static void amdgpu_memcpy_dispatch_test(amdgpu_device_handle device_handle, uint32_t ip_type, uint32_t ring, + uint32_t version, int hang) { amdgpu_context_handle context_handle; @@ -2433,7 +2821,7 @@ static void amdgpu_memcpy_dispatch_test(amdgpu_device_handle device_handle, memset(ptr_shader, 0, bo_shader_size); cs_type = hang ? CS_HANG : CS_BUFFERCOPY; - r = amdgpu_dispatch_load_cs_shader(ptr_shader, cs_type); + r = amdgpu_dispatch_load_cs_shader(ptr_shader, cs_type, version); CU_ASSERT_EQUAL(r, 0); r = amdgpu_bo_alloc_and_map(device_handle, bo_dst_size, 4096, @@ -2451,13 +2839,13 @@ static void amdgpu_memcpy_dispatch_test(amdgpu_device_handle device_handle, memset(ptr_src, 0x55, bo_dst_size); i = 0; - i += amdgpu_dispatch_init(ptr_cmd + i, ip_type); + i += amdgpu_dispatch_init(ptr_cmd + i, ip_type, version); /* Issue commands to set cu mask used in current dispatch */ - i += amdgpu_dispatch_write_cumask(ptr_cmd + i); + i += amdgpu_dispatch_write_cumask(ptr_cmd + i, version); /* Writes shader state to HW */ - i += amdgpu_dispatch_write2hw(ptr_cmd + i, mc_address_shader); + i += amdgpu_dispatch_write2hw(ptr_cmd + i, mc_address_shader, version); /* Write constant data */ /* Writes the texture resource constants data to the SGPRs */ @@ -2466,7 +2854,10 @@ static void amdgpu_memcpy_dispatch_test(amdgpu_device_handle device_handle, ptr_cmd[i++] = mc_address_src; ptr_cmd[i++] = (mc_address_src >> 32) | 0x100000; ptr_cmd[i++] = 0x400; - ptr_cmd[i++] = 0x74fac; + if (version == 9) + ptr_cmd[i++] = 0x74fac; + else if (version == 10) + ptr_cmd[i++] = 0x1104bfac; /* Writes the UAV constant data to the SGPRs. */ ptr_cmd[i++] = PACKET3_COMPUTE(PKT3_SET_SH_REG, 4); @@ -2474,7 +2865,10 @@ static void amdgpu_memcpy_dispatch_test(amdgpu_device_handle device_handle, ptr_cmd[i++] = mc_address_dst; ptr_cmd[i++] = (mc_address_dst >> 32) | 0x100000; ptr_cmd[i++] = 0x400; - ptr_cmd[i++] = 0x74fac; + if (version == 9) + ptr_cmd[i++] = 0x74fac; + else if (version == 10) + ptr_cmd[i++] = 0x1104bfac; /* clear mmCOMPUTE_RESOURCE_LIMITS */ ptr_cmd[i++] = PACKET3_COMPUTE(PKT3_SET_SH_REG, 1); @@ -2558,16 +2952,22 @@ static void amdgpu_compute_dispatch_test(void) { int r; struct drm_amdgpu_info_hw_ip info; - uint32_t ring_id; + uint32_t ring_id, version; r = amdgpu_query_hw_ip_info(device_handle, AMDGPU_HW_IP_COMPUTE, 0, &info); CU_ASSERT_EQUAL(r, 0); if (!info.available_rings) printf("SKIP ... as there's no compute ring\n"); + version = info.hw_ip_version_major; + if (version != 9 && version != 10) { + printf("SKIP ... unsupported gfx version %d\n", version); + return; + } + for (ring_id = 0; (1 << ring_id) & info.available_rings; ring_id++) { - amdgpu_memset_dispatch_test(device_handle, AMDGPU_HW_IP_COMPUTE, ring_id); - amdgpu_memcpy_dispatch_test(device_handle, AMDGPU_HW_IP_COMPUTE, ring_id, 0); + amdgpu_memset_dispatch_test(device_handle, AMDGPU_HW_IP_COMPUTE, ring_id, version); + amdgpu_memcpy_dispatch_test(device_handle, AMDGPU_HW_IP_COMPUTE, ring_id, version, 0); } } @@ -2575,16 +2975,22 @@ static void amdgpu_gfx_dispatch_test(void) { int r; struct drm_amdgpu_info_hw_ip info; - uint32_t ring_id; + uint32_t ring_id, version; r = amdgpu_query_hw_ip_info(device_handle, AMDGPU_HW_IP_GFX, 0, &info); CU_ASSERT_EQUAL(r, 0); if (!info.available_rings) printf("SKIP ... as there's no graphics ring\n"); + version = info.hw_ip_version_major; + if (version != 9 && version != 10) { + printf("SKIP ... unsupported gfx version %d\n", version); + return; + } + for (ring_id = 0; (1 << ring_id) & info.available_rings; ring_id++) { - amdgpu_memset_dispatch_test(device_handle, AMDGPU_HW_IP_GFX, ring_id); - amdgpu_memcpy_dispatch_test(device_handle, AMDGPU_HW_IP_GFX, ring_id, 0); + amdgpu_memset_dispatch_test(device_handle, AMDGPU_HW_IP_GFX, ring_id, version); + amdgpu_memcpy_dispatch_test(device_handle, AMDGPU_HW_IP_GFX, ring_id, version, 0); } } @@ -2592,22 +2998,28 @@ void amdgpu_dispatch_hang_helper(amdgpu_device_handle device_handle, uint32_t ip { int r; struct drm_amdgpu_info_hw_ip info; - uint32_t ring_id; + uint32_t ring_id, version; r = amdgpu_query_hw_ip_info(device_handle, ip_type, 0, &info); CU_ASSERT_EQUAL(r, 0); if (!info.available_rings) printf("SKIP ... as there's no ring for ip %d\n", ip_type); + version = info.hw_ip_version_major; + if (version != 9 && version != 10) { + printf("SKIP ... unsupported gfx version %d\n", version); + return; + } + for (ring_id = 0; (1 << ring_id) & info.available_rings; ring_id++) { - amdgpu_memcpy_dispatch_test(device_handle, ip_type, ring_id, 0); - amdgpu_memcpy_dispatch_test(device_handle, ip_type, ring_id, 1); - amdgpu_memcpy_dispatch_test(device_handle, ip_type, ring_id, 0); + amdgpu_memcpy_dispatch_test(device_handle, ip_type, ring_id, version, 0); + amdgpu_memcpy_dispatch_test(device_handle, ip_type, ring_id, version, 1); + amdgpu_memcpy_dispatch_test(device_handle, ip_type, ring_id, version, 0); } } static void amdgpu_memcpy_dispatch_hang_slow_test(amdgpu_device_handle device_handle, - uint32_t ip_type, uint32_t ring) + uint32_t ip_type, uint32_t ring, int version) { amdgpu_context_handle context_handle; amdgpu_bo_handle bo_src, bo_dst, bo_shader, bo_cmd, resources[4]; @@ -2666,13 +3078,13 @@ static void amdgpu_memcpy_dispatch_hang_slow_test(amdgpu_device_handle device_ha memset(ptr_src, 0x55, bo_dst_size); i = 0; - i += amdgpu_dispatch_init(ptr_cmd + i, ip_type); + i += amdgpu_dispatch_init(ptr_cmd + i, ip_type, version); /* Issue commands to set cu mask used in current dispatch */ - i += amdgpu_dispatch_write_cumask(ptr_cmd + i); + i += amdgpu_dispatch_write_cumask(ptr_cmd + i, version); /* Writes shader state to HW */ - i += amdgpu_dispatch_write2hw(ptr_cmd + i, mc_address_shader); + i += amdgpu_dispatch_write2hw(ptr_cmd + i, mc_address_shader, version); /* Write constant data */ /* Writes the texture resource constants data to the SGPRs */ @@ -2681,7 +3093,10 @@ static void amdgpu_memcpy_dispatch_hang_slow_test(amdgpu_device_handle device_ha ptr_cmd[i++] = mc_address_src; ptr_cmd[i++] = (mc_address_src >> 32) | 0x100000; ptr_cmd[i++] = 0x400000; - ptr_cmd[i++] = 0x74fac; + if (version == 9) + ptr_cmd[i++] = 0x74fac; + else if (version == 10) + ptr_cmd[i++] = 0x1104bfac; /* Writes the UAV constant data to the SGPRs. */ ptr_cmd[i++] = PACKET3_COMPUTE(PKT3_SET_SH_REG, 4); @@ -2689,7 +3104,10 @@ static void amdgpu_memcpy_dispatch_hang_slow_test(amdgpu_device_handle device_ha ptr_cmd[i++] = mc_address_dst; ptr_cmd[i++] = (mc_address_dst >> 32) | 0x100000; ptr_cmd[i++] = 0x400000; - ptr_cmd[i++] = 0x74fac; + if (version == 9) + ptr_cmd[i++] = 0x74fac; + else if (version == 10) + ptr_cmd[i++] = 0x1104bfac; /* clear mmCOMPUTE_RESOURCE_LIMITS */ ptr_cmd[i++] = PACKET3_COMPUTE(PKT3_SET_SH_REG, 1); @@ -2761,17 +3179,23 @@ void amdgpu_dispatch_hang_slow_helper(amdgpu_device_handle device_handle, uint32 { int r; struct drm_amdgpu_info_hw_ip info; - uint32_t ring_id; + uint32_t ring_id, version; r = amdgpu_query_hw_ip_info(device_handle, ip_type, 0, &info); CU_ASSERT_EQUAL(r, 0); if (!info.available_rings) printf("SKIP ... as there's no ring for ip %d\n", ip_type); + version = info.hw_ip_version_major; + if (version != 9 && version != 10) { + printf("SKIP ... unsupported gfx version %d\n", version); + return; + } + for (ring_id = 0; (1 << ring_id) & info.available_rings; ring_id++) { - amdgpu_memcpy_dispatch_test(device_handle, ip_type, ring_id, 0); - amdgpu_memcpy_dispatch_hang_slow_test(device_handle, ip_type, ring_id); - amdgpu_memcpy_dispatch_test(device_handle, ip_type, ring_id, 0); + amdgpu_memcpy_dispatch_test(device_handle, ip_type, ring_id, version, 0); + amdgpu_memcpy_dispatch_hang_slow_test(device_handle, ip_type, ring_id, version); + amdgpu_memcpy_dispatch_test(device_handle, ip_type, ring_id, version, 0); } } @@ -2804,7 +3228,7 @@ static int amdgpu_draw_load_ps_shader_hang_slow(uint32_t *ptr, int family) return 0; } -static int amdgpu_draw_load_ps_shader(uint8_t *ptr, int ps_type) +static int amdgpu_draw_load_ps_shader(uint8_t *ptr, int ps_type, uint32_t version) { int i; uint32_t shader_offset= 256; @@ -2816,18 +3240,34 @@ static int amdgpu_draw_load_ps_shader(uint8_t *ptr, int ps_type) switch (ps_type) { case PS_CONST: - shader = ps_const_shader_gfx9; - shader_size = sizeof(ps_const_shader_gfx9); - patchinfo_code = (const uint32_t *)ps_const_shader_patchinfo_code_gfx9; - patchinfo_code_size = ps_const_shader_patchinfo_code_size_gfx9; - patchcode_offset = ps_const_shader_patchinfo_offset_gfx9; + if (version == 9) { + shader = ps_const_shader_gfx9; + shader_size = sizeof(ps_const_shader_gfx9); + patchinfo_code = (const uint32_t *)ps_const_shader_patchinfo_code_gfx9; + patchinfo_code_size = ps_const_shader_patchinfo_code_size_gfx9; + patchcode_offset = ps_const_shader_patchinfo_offset_gfx9; + } else if (version == 10){ + shader = ps_const_shader_gfx10; + shader_size = sizeof(ps_const_shader_gfx10); + patchinfo_code = (const uint32_t *)ps_const_shader_patchinfo_code_gfx10; + patchinfo_code_size = ps_const_shader_patchinfo_code_size_gfx10; + patchcode_offset = ps_const_shader_patchinfo_offset_gfx10; + } break; case PS_TEX: - shader = ps_tex_shader_gfx9; - shader_size = sizeof(ps_tex_shader_gfx9); - patchinfo_code = (const uint32_t *)ps_tex_shader_patchinfo_code_gfx9; - patchinfo_code_size = ps_tex_shader_patchinfo_code_size_gfx9; - patchcode_offset = ps_tex_shader_patchinfo_offset_gfx9; + if (version == 9) { + shader = ps_tex_shader_gfx9; + shader_size = sizeof(ps_tex_shader_gfx9); + patchinfo_code = (const uint32_t *)ps_tex_shader_patchinfo_code_gfx9; + patchinfo_code_size = ps_tex_shader_patchinfo_code_size_gfx9; + patchcode_offset = ps_tex_shader_patchinfo_offset_gfx9; + } else if (version == 10) { + shader = ps_tex_shader_gfx10; + shader_size = sizeof(ps_tex_shader_gfx10); + patchinfo_code = (const uint32_t *)ps_tex_shader_patchinfo_code_gfx10; + patchinfo_code_size = ps_tex_shader_patchinfo_code_size_gfx10; + patchcode_offset = ps_tex_shader_patchinfo_offset_gfx10; + } break; case PS_HANG: shader = memcpy_ps_hang; @@ -2859,20 +3299,25 @@ static int amdgpu_draw_load_ps_shader(uint8_t *ptr, int ps_type) } /* load RectPosTexFast_VS */ -static int amdgpu_draw_load_vs_shader(uint8_t *ptr) +static int amdgpu_draw_load_vs_shader(uint8_t *ptr, uint32_t version) { const uint32_t *shader; uint32_t shader_size; - shader = vs_RectPosTexFast_shader_gfx9; - shader_size = sizeof(vs_RectPosTexFast_shader_gfx9); + if (version == 9) { + shader = vs_RectPosTexFast_shader_gfx9; + shader_size = sizeof(vs_RectPosTexFast_shader_gfx9); + } else if (version == 10) { + shader = vs_RectPosTexFast_shader_gfx10; + shader_size = sizeof(vs_RectPosTexFast_shader_gfx10); + } memcpy(ptr, shader, shader_size); return 0; } -static int amdgpu_draw_init(uint32_t *ptr) +static int amdgpu_draw_init(uint32_t *ptr, uint32_t version) { int i = 0; const uint32_t *preamblecache_ptr; @@ -2883,8 +3328,13 @@ static int amdgpu_draw_init(uint32_t *ptr) ptr[i++] = 0x80000000; ptr[i++] = 0x80000000; - preamblecache_ptr = preamblecache_gfx9; - preamblecache_size = sizeof(preamblecache_gfx9); + if (version == 9) { + preamblecache_ptr = preamblecache_gfx9; + preamblecache_size = sizeof(preamblecache_gfx9); + } else if (version == 10) { + preamblecache_ptr = preamblecache_gfx10; + preamblecache_size = sizeof(preamblecache_gfx10); + } memcpy(ptr + i, preamblecache_ptr, preamblecache_size); return i + preamblecache_size/sizeof(uint32_t); @@ -2892,41 +3342,95 @@ static int amdgpu_draw_init(uint32_t *ptr) static int amdgpu_draw_setup_and_write_drawblt_surf_info(uint32_t *ptr, uint64_t dst_addr, + uint32_t version, int hang_slow) { int i = 0; /* 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++] = dst_addr >> 8; - ptr[i++] = dst_addr >> 40; - ptr[i++] = hang_slow ? 0x1ffc7ff : 0x7c01f; - ptr[i++] = 0; - ptr[i++] = 0x50438; - ptr[i++] = 0x10140000; - i += 9; + if (version == 9) { + /* 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++] = dst_addr >> 8; + ptr[i++] = dst_addr >> 40; + ptr[i++] = 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++] = hang_slow ? 0xfff : 0x1f; + } else if (version == 10) { + /* 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++] = dst_addr >> 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++] = dst_addr >> 40; + + /* 0xA398 CB_COLOR0_CMASK_BASE_EXT */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); + ptr[i++] = 0x398; + ptr[i++] = 0; - /* mmCB_MRT0_EPITCH */ - ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); - ptr[i++] = 0x1e8; - ptr[i++] = hang_slow ? 0x7ff : 0x1f; + /* 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++] = 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); @@ -2944,15 +3448,24 @@ static int amdgpu_draw_setup_and_write_drawblt_surf_info(uint32_t *ptr, ptr[i++] = 9; /* Setup depth buffer */ - /* mmDB_Z_INFO */ - ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 2); - ptr[i++] = 0xe; - i += 2; + if (version == 9) { + /* mmDB_Z_INFO */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 2); + ptr[i++] = 0xe; + i += 2; + } else if (version == 10) { + /* mmDB_Z_INFO */ + ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 2); + ptr[i++] = 0x10; + i += 2; + } return i; } -static int amdgpu_draw_setup_and_write_drawblt_state(uint32_t *ptr, int hang_slow) +static int amdgpu_draw_setup_and_write_drawblt_state(uint32_t *ptr, + uint32_t version, + int hang_slow) { int i = 0; const uint32_t *cached_cmd_ptr; @@ -2968,7 +3481,10 @@ static int amdgpu_draw_setup_and_write_drawblt_state(uint32_t *ptr, int hang_slo ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 1); ptr[i++] = 0xd7; - ptr[i++] = 1; + if (version == 9) + ptr[i++] = 1; + else if (version == 10) + ptr[i++] = 0; /* mmPA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0 */ ptr[i++] = PACKET3(PACKET3_SET_CONTEXT_REG, 16); @@ -2980,20 +3496,37 @@ static int amdgpu_draw_setup_and_write_drawblt_state(uint32_t *ptr, int hang_slo ptr[i++] = 0x2f5; i += 2; - cached_cmd_ptr = cached_cmd_gfx9; - cached_cmd_size = sizeof(cached_cmd_gfx9); + if (version == 9) { + cached_cmd_ptr = cached_cmd_gfx9; + cached_cmd_size = sizeof(cached_cmd_gfx9); + } else if (version == 10) { + cached_cmd_ptr = cached_cmd_gfx10; + cached_cmd_size = sizeof(cached_cmd_gfx10); + } memcpy(ptr + i, cached_cmd_ptr, cached_cmd_size); if (hang_slow) *(ptr + i + 12) = 0x8000800; i += cached_cmd_size/sizeof(uint32_t); + if (version == 10) { + /* 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; + } + return i; } static int amdgpu_draw_vs_RectPosTexFast_write2hw(uint32_t *ptr, int ps_type, uint64_t shader_addr, + uint32_t version, int hang_slow) { int i = 0; @@ -3003,10 +3536,21 @@ static int amdgpu_draw_vs_RectPosTexFast_write2hw(uint32_t *ptr, ptr[i++] = 0x207; ptr[i++] = 0; - /* mmSPI_SHADER_PGM_RSRC3_VS */ - ptr[i++] = PACKET3(PKT3_SET_SH_REG, 1); - ptr[i++] = 0x46; - ptr[i++] = 0xffff; + if (version == 9) { + /* mmSPI_SHADER_PGM_RSRC3_VS */ + ptr[i++] = PACKET3(PKT3_SET_SH_REG, 1); + ptr[i++] = 0x46; + ptr[i++] = 0xffff; + } else if (version == 10) { + /* mmSPI_SHADER_PGM_RSRC3_VS */ + ptr[i++] = PACKET3(PKT3_SET_SH_REG_INDEX, 1); + ptr[i++] = 0x30000046; + ptr[i++] = 0xffff; + /* mmSPI_SHADER_PGM_RSRC4_VS */ + ptr[i++] = PACKET3(PKT3_SET_SH_REG_INDEX, 1); + ptr[i++] = 0x30000041; + ptr[i++] = 0xffff; + } /* mmSPI_SHADER_PGM_LO_VS...mmSPI_SHADER_PGM_HI_VS */ ptr[i++] = PACKET3(PKT3_SET_SH_REG, 2); @@ -3017,7 +3561,10 @@ static int amdgpu_draw_vs_RectPosTexFast_write2hw(uint32_t *ptr, /* mmSPI_SHADER_PGM_RSRC1_VS */ ptr[i++] = PACKET3(PKT3_SET_SH_REG, 1); ptr[i++] = 0x4a; - ptr[i++] = 0xc0081; + if (version == 9) + ptr[i++] = 0xc0081; + else if (version == 10) + ptr[i++] = 0xc0041; /* mmSPI_SHADER_PGM_RSRC2_VS */ ptr[i++] = PACKET3(PKT3_SET_SH_REG, 1); ptr[i++] = 0x4b; @@ -3058,7 +3605,8 @@ static int amdgpu_draw_vs_RectPosTexFast_write2hw(uint32_t *ptr, static int amdgpu_draw_ps_write2hw(uint32_t *ptr, int ps_type, - uint64_t shader_addr) + uint64_t shader_addr, + uint32_t version) { int i, j; const uint32_t *sh_registers; @@ -3066,9 +3614,14 @@ static int amdgpu_draw_ps_write2hw(uint32_t *ptr, uint32_t num_sh_reg, num_context_reg; if (ps_type == PS_CONST) { - sh_registers = (const uint32_t *)ps_const_sh_registers_gfx9; + if (version == 9) { + sh_registers = (const uint32_t *)ps_const_sh_registers_gfx9; + num_sh_reg = ps_num_sh_registers_gfx9; + } else if (version == 10) { + sh_registers = (const uint32_t *)ps_const_sh_registers_gfx10; + num_sh_reg = ps_num_sh_registers_gfx10; + } context_registers = (const uint32_t *)ps_const_context_reg_gfx9; - num_sh_reg = ps_num_sh_registers_gfx9; num_context_reg = ps_num_context_registers_gfx9; } else if (ps_type == PS_TEX) { sh_registers = (const uint32_t *)ps_tex_sh_registers_gfx9; @@ -3079,15 +3632,35 @@ static int amdgpu_draw_ps_write2hw(uint32_t *ptr, i = 0; - /* 0x2c07 SPI_SHADER_PGM_RSRC3_PS - 0x2c08 SPI_SHADER_PGM_LO_PS - 0x2c09 SPI_SHADER_PGM_HI_PS */ - shader_addr += 256 * 9; - ptr[i++] = PACKET3(PKT3_SET_SH_REG, 3); - ptr[i++] = 0x7; - ptr[i++] = 0xffff; - ptr[i++] = shader_addr >> 8; - ptr[i++] = shader_addr >> 40; + if (version == 9) { + /* 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 */ + shader_addr += 256 * 9; + ptr[i++] = PACKET3(PKT3_SET_SH_REG, 3); + ptr[i++] = 0x7; + ptr[i++] = 0xffff; + ptr[i++] = shader_addr >> 8; + ptr[i++] = shader_addr >> 40; + } else if (version == 10) { + shader_addr += 256 * 9; + /* 0x2c08 SPI_SHADER_PGM_LO_PS + 0x2c09 SPI_SHADER_PGM_HI_PS */ + ptr[i++] = PACKET3(PKT3_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(PKT3_SET_SH_REG_INDEX, 1); + ptr[i++] = 0x30000007; + ptr[i++] = 0xffff; + /* mmSPI_SHADER_PGM_RSRC4_PS */ + ptr[i++] = PACKET3(PKT3_SET_SH_REG_INDEX, 1); + ptr[i++] = 0x30000001; + ptr[i++] = 0xffff; + } for (j = 0; j < num_sh_reg; j++) { ptr[i++] = PACKET3(PKT3_SET_SH_REG, 1); @@ -3112,19 +3685,29 @@ static int amdgpu_draw_ps_write2hw(uint32_t *ptr, return i; } -static int amdgpu_draw_draw(uint32_t *ptr) +static int amdgpu_draw_draw(uint32_t *ptr, uint32_t version) { int i = 0; - /* 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; + if (version == 9) { + /* 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; + } else if (version == 10) { + /* 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; + } ptr[i++] = PACKET3(PACKET3_DRAW_INDEX_AUTO, 1); ptr[i++] = 3; @@ -3138,7 +3721,7 @@ void amdgpu_memset_draw(amdgpu_device_handle device_handle, amdgpu_bo_handle bo_shader_vs, uint64_t mc_address_shader_ps, uint64_t mc_address_shader_vs, - uint32_t ring_id) + uint32_t ring_id, uint32_t version) { amdgpu_context_handle context_handle; amdgpu_bo_handle bo_dst, bo_cmd, resources[4]; @@ -3172,15 +3755,16 @@ void amdgpu_memset_draw(amdgpu_device_handle device_handle, CU_ASSERT_EQUAL(r, 0); i = 0; - i += amdgpu_draw_init(ptr_cmd + i); + i += amdgpu_draw_init(ptr_cmd + i, version); - i += amdgpu_draw_setup_and_write_drawblt_surf_info(ptr_cmd + i, mc_address_dst, 0); + i += amdgpu_draw_setup_and_write_drawblt_surf_info(ptr_cmd + i, mc_address_dst, version, 0); - i += amdgpu_draw_setup_and_write_drawblt_state(ptr_cmd + i, 0); + i += amdgpu_draw_setup_and_write_drawblt_state(ptr_cmd + i, version, 0); - i += amdgpu_draw_vs_RectPosTexFast_write2hw(ptr_cmd + i, PS_CONST, mc_address_shader_vs, 0); + i += amdgpu_draw_vs_RectPosTexFast_write2hw(ptr_cmd + i, PS_CONST, mc_address_shader_vs, + version, 0); - i += amdgpu_draw_ps_write2hw(ptr_cmd + i, PS_CONST, mc_address_shader_ps); + i += amdgpu_draw_ps_write2hw(ptr_cmd + i, PS_CONST, mc_address_shader_ps, version); ptr_cmd[i++] = PACKET3(PKT3_SET_SH_REG, 4); ptr_cmd[i++] = 0xc; @@ -3189,7 +3773,7 @@ void amdgpu_memset_draw(amdgpu_device_handle device_handle, ptr_cmd[i++] = 0x33333333; ptr_cmd[i++] = 0x33333333; - i += amdgpu_draw_draw(ptr_cmd + i); + i += amdgpu_draw_draw(ptr_cmd + i, version); while (i & 7) ptr_cmd[i++] = 0xffff1000; /* type3 nop packet */ @@ -3247,7 +3831,7 @@ void amdgpu_memset_draw(amdgpu_device_handle device_handle, } static void amdgpu_memset_draw_test(amdgpu_device_handle device_handle, - uint32_t ring) + uint32_t ring, int version) { amdgpu_bo_handle bo_shader_ps, bo_shader_vs; void *ptr_shader_ps; @@ -3271,14 +3855,15 @@ static void amdgpu_memset_draw_test(amdgpu_device_handle device_handle, CU_ASSERT_EQUAL(r, 0); memset(ptr_shader_vs, 0, bo_shader_size); - r = amdgpu_draw_load_ps_shader(ptr_shader_ps, PS_CONST); + r = amdgpu_draw_load_ps_shader(ptr_shader_ps, PS_CONST, version); CU_ASSERT_EQUAL(r, 0); - r = amdgpu_draw_load_vs_shader(ptr_shader_vs); + r = amdgpu_draw_load_vs_shader(ptr_shader_vs, version); CU_ASSERT_EQUAL(r, 0); amdgpu_memset_draw(device_handle, bo_shader_ps, bo_shader_vs, - mc_address_shader_ps, mc_address_shader_vs, ring); + mc_address_shader_ps, mc_address_shader_vs, + ring, version); r = amdgpu_bo_unmap_and_free(bo_shader_ps, va_shader_ps, mc_address_shader_ps, bo_shader_size); CU_ASSERT_EQUAL(r, 0); @@ -3292,7 +3877,7 @@ static void amdgpu_memcpy_draw(amdgpu_device_handle device_handle, amdgpu_bo_handle bo_shader_vs, uint64_t mc_address_shader_ps, uint64_t mc_address_shader_vs, - uint32_t ring, int hang) + uint32_t ring, int version, int hang) { amdgpu_context_handle context_handle; amdgpu_bo_handle bo_dst, bo_src, bo_cmd, resources[5]; @@ -3336,24 +3921,36 @@ static void amdgpu_memcpy_draw(amdgpu_device_handle device_handle, memset(ptr_src, 0x55, bo_size); i = 0; - i += amdgpu_draw_init(ptr_cmd + i); + i += amdgpu_draw_init(ptr_cmd + i, version); - i += amdgpu_draw_setup_and_write_drawblt_surf_info(ptr_cmd + i, mc_address_dst, 0); + i += amdgpu_draw_setup_and_write_drawblt_surf_info(ptr_cmd + i, mc_address_dst, version, 0); - i += amdgpu_draw_setup_and_write_drawblt_state(ptr_cmd + i, 0); + i += amdgpu_draw_setup_and_write_drawblt_state(ptr_cmd + i, version, 0); - i += amdgpu_draw_vs_RectPosTexFast_write2hw(ptr_cmd + i, PS_TEX, mc_address_shader_vs, 0); + i += amdgpu_draw_vs_RectPosTexFast_write2hw(ptr_cmd + i, PS_TEX, mc_address_shader_vs, + version, 0); - i += amdgpu_draw_ps_write2hw(ptr_cmd + i, PS_TEX, mc_address_shader_ps); + i += amdgpu_draw_ps_write2hw(ptr_cmd + i, PS_TEX, mc_address_shader_ps, version); ptr_cmd[i++] = PACKET3(PKT3_SET_SH_REG, 8); - ptr_cmd[i++] = 0xc; - ptr_cmd[i++] = mc_address_src >> 8; - ptr_cmd[i++] = mc_address_src >> 40 | 0x10e00000; - ptr_cmd[i++] = 0x7c01f; - ptr_cmd[i++] = 0x90500fac; - ptr_cmd[i++] = 0x3e000; - i += 3; + if (version == 9) { + ptr_cmd[i++] = 0xc; + ptr_cmd[i++] = mc_address_src >> 8; + ptr_cmd[i++] = mc_address_src >> 40 | 0x10e00000; + ptr_cmd[i++] = 0x7c01f; + ptr_cmd[i++] = 0x90500fac; + ptr_cmd[i++] = 0x3e000; + i += 3; + } else if (version == 10) { + ptr_cmd[i++] = 0xc; + ptr_cmd[i++] = mc_address_src >> 8; + ptr_cmd[i++] = mc_address_src >> 40 | 0xc4b00000; + ptr_cmd[i++] = 0x8007c007; + ptr_cmd[i++] = 0x90500fac; + i += 2; + ptr_cmd[i++] = 0x400; + i++; + } ptr_cmd[i++] = PACKET3(PKT3_SET_SH_REG, 4); ptr_cmd[i++] = 0x14; @@ -3364,7 +3961,7 @@ static void amdgpu_memcpy_draw(amdgpu_device_handle device_handle, ptr_cmd[i++] = 0x191; ptr_cmd[i++] = 0; - i += amdgpu_draw_draw(ptr_cmd + i); + i += amdgpu_draw_draw(ptr_cmd + i, version); while (i & 7) ptr_cmd[i++] = 0xffff1000; /* type3 nop packet */ @@ -3430,7 +4027,7 @@ static void amdgpu_memcpy_draw(amdgpu_device_handle device_handle, } void amdgpu_memcpy_draw_test(amdgpu_device_handle device_handle, uint32_t ring, - int hang) + int version, int hang) { amdgpu_bo_handle bo_shader_ps, bo_shader_vs; void *ptr_shader_ps; @@ -3455,14 +4052,15 @@ void amdgpu_memcpy_draw_test(amdgpu_device_handle device_handle, uint32_t ring, CU_ASSERT_EQUAL(r, 0); memset(ptr_shader_vs, 0, bo_shader_size); - r = amdgpu_draw_load_ps_shader(ptr_shader_ps, ps_type); + r = amdgpu_draw_load_ps_shader(ptr_shader_ps, ps_type, version); CU_ASSERT_EQUAL(r, 0); - r = amdgpu_draw_load_vs_shader(ptr_shader_vs); + r = amdgpu_draw_load_vs_shader(ptr_shader_vs, version); CU_ASSERT_EQUAL(r, 0); amdgpu_memcpy_draw(device_handle, bo_shader_ps, bo_shader_vs, - mc_address_shader_ps, mc_address_shader_vs, ring, hang); + mc_address_shader_ps, mc_address_shader_vs, + ring, version, hang); r = amdgpu_bo_unmap_and_free(bo_shader_ps, va_shader_ps, mc_address_shader_ps, bo_shader_size); CU_ASSERT_EQUAL(r, 0); @@ -3475,20 +4073,26 @@ static void amdgpu_draw_test(void) { int r; struct drm_amdgpu_info_hw_ip info; - uint32_t ring_id; + uint32_t ring_id, version; r = amdgpu_query_hw_ip_info(device_handle, AMDGPU_HW_IP_GFX, 0, &info); CU_ASSERT_EQUAL(r, 0); if (!info.available_rings) printf("SKIP ... as there's no graphics ring\n"); + version = info.hw_ip_version_major; + if (version != 9 && version != 10) { + printf("SKIP ... unsupported gfx version %d\n", version); + return; + } + for (ring_id = 0; (1 << ring_id) & info.available_rings; ring_id++) { - amdgpu_memset_draw_test(device_handle, ring_id); - amdgpu_memcpy_draw_test(device_handle, ring_id, 0); + amdgpu_memset_draw_test(device_handle, ring_id, version); + amdgpu_memcpy_draw_test(device_handle, ring_id, version, 0); } } -void amdgpu_memcpy_draw_hang_slow_test(amdgpu_device_handle device_handle, uint32_t ring) +void amdgpu_memcpy_draw_hang_slow_test(amdgpu_device_handle device_handle, uint32_t ring, int version) { amdgpu_context_handle context_handle; amdgpu_bo_handle bo_shader_ps, bo_shader_vs; @@ -3544,7 +4148,7 @@ void amdgpu_memcpy_draw_hang_slow_test(amdgpu_device_handle device_handle, uint3 r = amdgpu_draw_load_ps_shader_hang_slow(ptr_shader_ps, gpu_info.family_id); CU_ASSERT_EQUAL(r, 0); - r = amdgpu_draw_load_vs_shader(ptr_shader_vs); + r = amdgpu_draw_load_vs_shader(ptr_shader_vs, version); CU_ASSERT_EQUAL(r, 0); r = amdgpu_bo_alloc_and_map(device_handle, bo_size, 4096, @@ -3562,25 +4166,35 @@ void amdgpu_memcpy_draw_hang_slow_test(amdgpu_device_handle device_handle, uint3 memset(ptr_src, 0x55, bo_size); i = 0; - i += amdgpu_draw_init(ptr_cmd + i); + i += amdgpu_draw_init(ptr_cmd + i, version); - i += amdgpu_draw_setup_and_write_drawblt_surf_info(ptr_cmd + i, mc_address_dst, 1); + i += amdgpu_draw_setup_and_write_drawblt_surf_info(ptr_cmd + i, mc_address_dst, version, 1); - i += amdgpu_draw_setup_and_write_drawblt_state(ptr_cmd + i, 1); + i += amdgpu_draw_setup_and_write_drawblt_state(ptr_cmd + i, version, 1); i += amdgpu_draw_vs_RectPosTexFast_write2hw(ptr_cmd + i, PS_TEX, - mc_address_shader_vs, 1); + mc_address_shader_vs, version, 1); - i += amdgpu_draw_ps_write2hw(ptr_cmd + i, PS_TEX, mc_address_shader_ps); + i += amdgpu_draw_ps_write2hw(ptr_cmd + i, PS_TEX, mc_address_shader_ps, version); ptr_cmd[i++] = PACKET3(PKT3_SET_SH_REG, 8); - ptr_cmd[i++] = 0xc; - ptr_cmd[i++] = mc_address_src >> 8; - ptr_cmd[i++] = mc_address_src >> 40 | 0x10e00000; - ptr_cmd[i++] = 0x1ffc7ff; - ptr_cmd[i++] = 0x90500fac; - ptr_cmd[i++] = 0xffe000; - i += 3; + + if (version == 9) { + ptr_cmd[i++] = 0xc; + ptr_cmd[i++] = mc_address_src >> 8; + ptr_cmd[i++] = mc_address_src >> 40 | 0x10e00000; + ptr_cmd[i++] = 0x1ffcfff; + ptr_cmd[i++] = 0x90500fac; + ptr_cmd[i++] = 0x1ffe000; + i += 3; + } else if (version == 10) { + ptr_cmd[i++] = 0xc; + ptr_cmd[i++] = mc_address_src >> 8; + ptr_cmd[i++] = mc_address_src >> 40 | 0xc4b00000; + ptr_cmd[i++] = 0x81ffc1ff; + ptr_cmd[i++] = 0x90500fac; + i += 4; + } ptr_cmd[i++] = PACKET3(PKT3_SET_SH_REG, 4); ptr_cmd[i++] = 0x14; @@ -3591,7 +4205,7 @@ void amdgpu_memcpy_draw_hang_slow_test(amdgpu_device_handle device_handle, uint3 ptr_cmd[i++] = 0x191; ptr_cmd[i++] = 0; - i += amdgpu_draw_draw(ptr_cmd + i); + i += amdgpu_draw_draw(ptr_cmd + i, version); while (i & 7) ptr_cmd[i++] = 0xffff1000; /* type3 nop packet */ @@ -3683,3 +4297,33 @@ static void amdgpu_gpu_reset_test(void) 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 index 4c11665..8fc7fe2 100644 --- a/tests/amdgpu/bo_tests.c +++ b/tests/amdgpu/bo_tests.c @@ -168,7 +168,7 @@ static void amdgpu_bo_metadata(void) struct amdgpu_bo_info info = {0}; int r; - meta.size_metadata = 1; + meta.size_metadata = 4; meta.umd_metadata[0] = 0xdeadbeef; r = amdgpu_bo_set_metadata(buffer_handle, &meta); @@ -177,7 +177,7 @@ static void amdgpu_bo_metadata(void) r = amdgpu_bo_query_info(buffer_handle, &info); CU_ASSERT_EQUAL(r, 0); - CU_ASSERT_EQUAL(info.metadata.size_metadata, 1); + CU_ASSERT_EQUAL(info.metadata.size_metadata, 4); CU_ASSERT_EQUAL(info.metadata.umd_metadata[0], 0xdeadbeef); } 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 index ae4f65f..f509678 100644 --- a/tests/amdgpu/cs_tests.c +++ b/tests/amdgpu/cs_tests.c @@ -69,12 +69,15 @@ CU_BOOL suite_cs_tests_enable(void) 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) { + 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; } diff --git a/tests/amdgpu/deadlock_tests.c b/tests/amdgpu/deadlock_tests.c index a18d578..f29a83a 100644 --- a/tests/amdgpu/deadlock_tests.c +++ b/tests/amdgpu/deadlock_tests.c @@ -106,6 +106,10 @@ 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); @@ -129,17 +133,31 @@ CU_BOOL suite_deadlock_tests_enable(void) &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/9 dGPUS) + * by default (currently GFX8+ dGPUS and gfx9+ APUs). Note that Raven1 + * did not support GPU reset, but newer variants do. */ - if (device_handle->info.family_id != AMDGPU_FAMILY_VI && - device_handle->info.family_id != AMDGPU_FAMILY_AI && - device_handle->info.family_id != AMDGPU_FAMILY_CI) { + 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; @@ -515,32 +533,44 @@ static void amdgpu_draw_hang_gfx(void) { int r; struct drm_amdgpu_info_hw_ip info; - uint32_t ring_id; + uint32_t ring_id, version; r = amdgpu_query_hw_ip_info(device_handle, AMDGPU_HW_IP_GFX, 0, &info); CU_ASSERT_EQUAL(r, 0); if (!info.available_rings) printf("SKIP ... as there's no graphic ring\n"); + version = info.hw_ip_version_major; + if (version != 9 && version != 10) { + printf("SKIP ... unsupported gfx version %d\n", version); + return; + } + for (ring_id = 0; (1 << ring_id) & info.available_rings; ring_id++) { - amdgpu_memcpy_draw_test(device_handle, ring_id, 0); - amdgpu_memcpy_draw_test(device_handle, ring_id, 1); - amdgpu_memcpy_draw_test(device_handle, ring_id, 0); + amdgpu_memcpy_draw_test(device_handle, ring_id, version, 0); + amdgpu_memcpy_draw_test(device_handle, ring_id, version, 1); + amdgpu_memcpy_draw_test(device_handle, ring_id, version, 0); } } static void amdgpu_draw_hang_slow_gfx(void) { struct drm_amdgpu_info_hw_ip info; - uint32_t ring_id; + uint32_t ring_id, version; int r; r = amdgpu_query_hw_ip_info(device_handle, AMDGPU_HW_IP_GFX, 0, &info); CU_ASSERT_EQUAL(r, 0); + version = info.hw_ip_version_major; + if (version != 9 && version != 10) { + printf("SKIP ... unsupported gfx version %d\n", version); + return; + } + for (ring_id = 0; (1 << ring_id) & info.available_rings; ring_id++) { - amdgpu_memcpy_draw_test(device_handle, ring_id, 0); - amdgpu_memcpy_draw_hang_slow_test(device_handle, ring_id); - amdgpu_memcpy_draw_test(device_handle, ring_id, 0); + amdgpu_memcpy_draw_test(device_handle, ring_id, version, 0); + amdgpu_memcpy_draw_hang_slow_test(device_handle, ring_id, version); + amdgpu_memcpy_draw_test(device_handle, ring_id, version, 0); } } diff --git a/tests/amdgpu/decode_messages.h b/tests/amdgpu/decode_messages.h index 52c1cbb..218cd77 100644 --- a/tests/amdgpu/decode_messages.h +++ b/tests/amdgpu/decode_messages.h @@ -361,7 +361,7 @@ static const uint8_t uvd_decode_msg[] = { }; static const uint8_t avc_decode_msg[] = { - 0x02,0x00,0x00,0x00,0x1e,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x88,0x00,0x00,0x00, + 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, @@ -826,7 +826,7 @@ 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,0x01,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, @@ -851,4 +851,31 @@ static const uint8_t feedback_msg[] = { 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/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 index 4dfa5c8..53f2010 100644 --- a/tests/amdgpu/meson.build +++ b/tests/amdgpu/meson.build @@ -24,7 +24,8 @@ if dep_cunit.found() 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', + 'vm_tests.c', 'ras_tests.c', 'syncobj_tests.c', 'security_tests.c', + 'hotunplug_tests.c', 'jpeg_tests.c', 'cp_dma_tests.c' ), dependencies : [dep_cunit, dep_threads, dep_atomic_ops], include_directories : [inc_root, inc_drm, include_directories('../../amdgpu')], @@ -32,3 +33,14 @@ if dep_cunit.found() 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/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/syncobj_tests.c b/tests/amdgpu/syncobj_tests.c index 3a7b38e..690bea0 100644 --- a/tests/amdgpu/syncobj_tests.c +++ b/tests/amdgpu/syncobj_tests.c @@ -33,6 +33,10 @@ 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) @@ -100,6 +104,18 @@ static int syncobj_command_submission_helper(uint32_t syncobj_handle, bool 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); @@ -125,11 +141,11 @@ static int syncobj_command_submission_helper(uint32_t syncobj_handle, bool 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 ? AMDGPU_HW_IP_GFX : + 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 = 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 : @@ -151,7 +167,7 @@ static int syncobj_command_submission_helper(uint32_t syncobj_handle, bool memset(&fence_status, 0, sizeof(struct amdgpu_cs_fence)); fence_status.context = context_handle; - fence_status.ip_type = wait_or_signal ? AMDGPU_HW_IP_GFX: + fence_status.ip_type = wait_or_signal ? gc_ip_type : AMDGPU_HW_IP_DMA; fence_status.ip_instance = 0; fence_status.ring = 0; diff --git a/tests/amdgpu/vce_tests.c b/tests/amdgpu/vce_tests.c index 0026826..4e925ca 100644 --- a/tests/amdgpu/vce_tests.c +++ b/tests/amdgpu/vce_tests.c @@ -96,7 +96,7 @@ CU_TestInfo vce_tests[] = { CU_BOOL suite_vce_tests_enable(void) { - uint32_t version, feature; + uint32_t version, feature, asic_id; CU_BOOL ret_mv = CU_FALSE; if (amdgpu_device_initialize(drm_amdgpu[0], &major_version, @@ -107,6 +107,7 @@ CU_BOOL suite_vce_tests_enable(void) chip_rev = device_handle->info.chip_rev; chip_id = device_handle->info.chip_external_rev; ids_flags = device_handle->info.ids_flags; + asic_id = device_handle->info.asic_id; amdgpu_query_firmware_version(device_handle, AMDGPU_INFO_FW_VCE, 0, 0, &version, &feature); @@ -114,7 +115,8 @@ CU_BOOL suite_vce_tests_enable(void) if (amdgpu_device_deinitialize(device_handle)) return CU_FALSE; - if (family_id >= AMDGPU_FAMILY_RV || family_id == AMDGPU_FAMILY_SI) { + 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; } diff --git a/tests/amdgpu/vcn_tests.c b/tests/amdgpu/vcn_tests.c index 77ceeb1..ff97f34 100644 --- a/tests/amdgpu/vcn_tests.c +++ b/tests/amdgpu/vcn_tests.c @@ -56,7 +56,11 @@ 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; @@ -66,7 +70,13 @@ static uint32_t *ib_cpu; static amdgpu_bo_handle resources[MAX_RESOURCES]; static unsigned num_resources; -static struct amdgpu_vcn_reg reg; + +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}, +}; static void amdgpu_cs_vcn_dec_create(void); static void amdgpu_cs_vcn_dec_decode(void); @@ -90,6 +100,8 @@ CU_TestInfo vcn_tests[] = { CU_BOOL suite_vcn_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)) @@ -97,37 +109,36 @@ CU_BOOL suite_vcn_tests_enable(void) 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_DEC, 0, &info); if (amdgpu_device_deinitialize(device_handle)) return CU_FALSE; - - if (family_id < AMDGPU_FAMILY_RV) { + 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 VCN, suite disabled\n"); return CU_FALSE; } - if (family_id == AMDGPU_FAMILY_RV) { - if (asic_id == 0x1636) { - reg.data0 = 0x504; - reg.data1 = 0x505; - reg.cmd = 0x503; - reg.nop = 0x53f; - reg.cntl = 0x506; - } else { - reg.data0 = 0x81c4; - reg.data1 = 0x81c5; - reg.cmd = 0x81c3; - reg.nop = 0x81ff; - reg.cntl = 0x81c6; - } - } else if (family_id == AMDGPU_FAMILY_NV) { - reg.data0 = 0x504; - reg.data1 = 0x505; - reg.cmd = 0x503; - reg.nop = 0x53f; - reg.cntl = 0x506; - } else + if (family_id == AMDGPU_FAMILY_AI) { + amdgpu_set_test_active("VCN Tests", "VCN ENC create", CU_FALSE); + amdgpu_set_test_active("VCN Tests", "VCN ENC decode", CU_FALSE); + amdgpu_set_test_active("VCN Tests", "VCN ENC destroy", CU_FALSE); + } + + if (info.hw_ip_version_major == 1) + vcn_reg_index = 0; + else if (info.hw_ip_version_major == 2) + vcn_reg_index = 1; + else if ((info.hw_ip_version_major == 2 && info.hw_ip_version_minor >= 5) || + info.hw_ip_version_major == 3) + vcn_reg_index = 2; + else return CU_FALSE; return CU_TRUE; @@ -271,11 +282,11 @@ static void free_resource(struct amdgpu_vcn_bo *vcn_bo) static void vcn_dec_cmd(uint64_t addr, unsigned cmd, int *idx) { - ib_cpu[(*idx)++] = reg.data0; + ib_cpu[(*idx)++] = reg[vcn_reg_index].data0; ib_cpu[(*idx)++] = addr; - ib_cpu[(*idx)++] = reg.data1; + ib_cpu[(*idx)++] = reg[vcn_reg_index].data1; ib_cpu[(*idx)++] = addr >> 32; - ib_cpu[(*idx)++] = reg.cmd; + ib_cpu[(*idx)++] = reg[vcn_reg_index].cmd; ib_cpu[(*idx)++] = cmd << 1; } @@ -296,14 +307,14 @@ static void amdgpu_cs_vcn_dec_create(void) memcpy(msg_buf.ptr, vcn_dec_create_msg, sizeof(vcn_dec_create_msg)); len = 0; - ib_cpu[len++] = reg.data0; + ib_cpu[len++] = reg[vcn_reg_index].data0; ib_cpu[len++] = msg_buf.addr; - ib_cpu[len++] = reg.data1; + ib_cpu[len++] = reg[vcn_reg_index].data1; ib_cpu[len++] = msg_buf.addr >> 32; - ib_cpu[len++] = reg.cmd; + ib_cpu[len++] = reg[vcn_reg_index].cmd; ib_cpu[len++] = 0; for (; len % 16; ) { - ib_cpu[len++] = reg.nop; + ib_cpu[len++] = reg[vcn_reg_index].nop; ib_cpu[len++] = 0; } @@ -371,10 +382,10 @@ static void amdgpu_cs_vcn_dec_decode(void) vcn_dec_cmd(it_addr, 0x204, &len); vcn_dec_cmd(ctx_addr, 0x206, &len); - ib_cpu[len++] = reg.cntl; + ib_cpu[len++] = reg[vcn_reg_index].cntl; ib_cpu[len++] = 0x1; for (; len % 16; ) { - ib_cpu[len++] = reg.nop; + ib_cpu[len++] = reg[vcn_reg_index].nop; ib_cpu[len++] = 0; } @@ -406,14 +417,14 @@ static void amdgpu_cs_vcn_dec_destroy(void) memcpy(msg_buf.ptr, vcn_dec_destroy_msg, sizeof(vcn_dec_destroy_msg)); len = 0; - ib_cpu[len++] = reg.data0; + ib_cpu[len++] = reg[vcn_reg_index].data0; ib_cpu[len++] = msg_buf.addr; - ib_cpu[len++] = reg.data1; + ib_cpu[len++] = reg[vcn_reg_index].data1; ib_cpu[len++] = msg_buf.addr >> 32; - ib_cpu[len++] = reg.cmd; + ib_cpu[len++] = reg[vcn_reg_index].cmd; ib_cpu[len++] = 0; for (; len % 16; ) { - ib_cpu[len++] = reg.nop; + ib_cpu[len++] = reg[vcn_reg_index].nop; ib_cpu[len++] = 0; } diff --git a/tests/amdgpu/vm_tests.c b/tests/amdgpu/vm_tests.c index 69bc468..b94999c 100644 --- a/tests/amdgpu/vm_tests.c +++ b/tests/amdgpu/vm_tests.c @@ -30,6 +30,9 @@ 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); @@ -104,6 +107,18 @@ static void amdgpu_vmid_reserve_test(void) 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); @@ -133,7 +148,7 @@ static void amdgpu_vmid_reserve_test(void) ib_info.size = 16; memset(&ibs_request, 0, sizeof(struct amdgpu_cs_request)); - ibs_request.ip_type = AMDGPU_HW_IP_GFX; + ibs_request.ip_type = gc_ip_type; ibs_request.ring = 0; ibs_request.number_of_ibs = 1; ibs_request.ibs = &ib_info; @@ -146,7 +161,7 @@ static void amdgpu_vmid_reserve_test(void) 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_type = gc_ip_type; fence_status.ip_instance = 0; fence_status.ring = 0; fence_status.fence = ibs_request.seq_no; diff --git a/tests/etnaviv/etnaviv_2d_test.c b/tests/etnaviv/etnaviv_2d_test.c index 8dd77b6..9fcdae1 100644 --- a/tests/etnaviv/etnaviv_2d_test.c +++ b/tests/etnaviv/etnaviv_2d_test.c @@ -147,6 +147,27 @@ static void gen_cmd_stream(struct etna_cmd_stream *stream, struct etna_bo *bmp, 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; @@ -161,10 +182,19 @@ int main(int argc, char *argv[]) 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) + if (fd < 0) { + perror(argv[1]); return 1; + } version = drmGetVersion(fd); if (version) { @@ -178,25 +208,44 @@ int main(int argc, char *argv[]) dev = etna_device_new(fd); if (!dev) { + perror("etna_device_new"); ret = 2; goto out; } - /* TODO: we assume that core 0 is a 2D capable one */ - gpu = etna_gpu_new(dev, 0); - if (!gpu) { - ret = 3; - goto out_device; - } + 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; } @@ -204,6 +253,7 @@ int main(int argc, char *argv[]) stream = etna_cmd_stream_new(pipe, 0x300, NULL, NULL); if (!stream) { + perror("etna_cmd_stream_new"); ret = 6; goto out_bo; } @@ -213,7 +263,11 @@ int main(int argc, char *argv[]) etna_cmd_stream_finish(stream); - bmp_dump32(etna_bo_map(bmp), width, height, false, "/tmp/etna.bmp"); + 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); diff --git a/tests/exynos/exynos_fimg2d_test.c b/tests/exynos/exynos_fimg2d_test.c index 99bb923..d85e2f6 100644 --- a/tests/exynos/exynos_fimg2d_test.c +++ b/tests/exynos/exynos_fimg2d_test.c @@ -35,7 +35,6 @@ #include #include -#include #include #include "exynos_drm.h" diff --git a/tests/exynos/meson.build b/tests/exynos/meson.build index 3a048e8..12259c3 100644 --- a/tests/exynos/meson.build +++ b/tests/exynos/meson.build @@ -20,18 +20,15 @@ inc_exynos = include_directories('../../exynos') -if with_libkms - 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, - include_directories('../../libkms')], - link_with : [libdrm, libkms, libdrm_exynos], - dependencies : dep_threads, - install : with_install_tests, - ) -endif +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', diff --git a/tests/kms/kms-steal-crtc.c b/tests/kms/kms-steal-crtc.c deleted file mode 100644 index 4d884c0..0000000 --- a/tests/kms/kms-steal-crtc.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * 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 (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 -#if HAVE_SYS_SELECT_H -#include -#endif - -#include - -#include "util/pattern.h" -#include "libkms-test.h" - -static void signal_handler(int signum) -{ -} - -int main(int argc, char *argv[]) -{ - struct kms_framebuffer *fb; - struct kms_screen *screen; - struct kms_device *device; - unsigned int index = 0; - struct sigaction sa; - int fd, err; - void *ptr; - - if (argc < 2) { - fprintf(stderr, "usage: %s DEVICE\n", argv[0]); - return 1; - } - - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = signal_handler; - - err = sigaction(SIGINT, &sa, NULL); - if (err < 0) { - fprintf(stderr, "sigaction() failed: %m\n"); - return 1; - } - - fd = open(argv[1], O_RDWR); - if (fd < 0) { - fprintf(stderr, "open() failed: %m\n"); - return 1; - } - - device = kms_device_open(fd); - if (!device) { - fprintf(stderr, "kms_device_open() failed: %m\n"); - return 1; - } - - if (device->num_screens < 1) { - fprintf(stderr, "no screens found\n"); - kms_device_close(device); - close(fd); - return 1; - } - - /* TODO: allow command-line to override */ - screen = device->screens[0]; - - printf("Using screen %s, resolution %ux%u\n", screen->name, - screen->width, screen->height); - - fb = kms_framebuffer_create(device, screen->width, screen->height, - DRM_FORMAT_XRGB8888); - if (!fb) { - fprintf(stderr, "kms_framebuffer_create() failed\n"); - return 1; - } - - err = kms_framebuffer_map(fb, &ptr); - if (err < 0) { - fprintf(stderr, "kms_framebuffer_map() failed: %d\n", err); - return 1; - } - - util_fill_pattern(fb->format, UTIL_PATTERN_SMPTE, &ptr, fb->width, - fb->height, fb->pitch); - - kms_framebuffer_unmap(fb); - - err = kms_screen_set(screen, device->crtcs[index++], fb); - if (err < 0) { - fprintf(stderr, "kms_screen_set() failed: %d\n", err); - return 1; - } - - while (true) { - int nfds = STDIN_FILENO + 1; - struct timeval timeout; - fd_set fds; - - memset(&timeout, 0, sizeof(timeout)); - timeout.tv_sec = 5; - timeout.tv_usec = 0; - - FD_ZERO(&fds); - FD_SET(STDIN_FILENO, &fds); - - err = select(nfds, &fds, NULL, NULL, &timeout); - if (err < 0) { - if (errno == EINTR) - break; - - fprintf(stderr, "select() failed: %d\n", errno); - break; - } - - if (err > 0) { - if (FD_ISSET(STDIN_FILENO, &fds)) - break; - } - - /* switch CRTC */ - if (index >= device->num_crtcs) - index = 0; - - err = kms_screen_set(screen, device->crtcs[index], fb); - if (err < 0) { - fprintf(stderr, "kms_screen_set() failed: %d\n", err); - break; - } - - index++; - } - - kms_framebuffer_free(fb); - kms_device_close(device); - close(fd); - - return 0; -} diff --git a/tests/kms/kms-universal-planes.c b/tests/kms/kms-universal-planes.c deleted file mode 100644 index 1d79388..0000000 --- a/tests/kms/kms-universal-planes.c +++ /dev/null @@ -1,357 +0,0 @@ -/* - * 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 (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 -#if HAVE_SYS_SELECT_H -#include -#endif - -#include -#include "xf86drm.h" - -#include "util/common.h" -#include "libkms-test.h" - -static const uint32_t formats[] = { - DRM_FORMAT_XRGB8888, - DRM_FORMAT_XBGR8888, - DRM_FORMAT_RGBA8888, -}; - -static uint32_t choose_format(struct kms_plane *plane) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(formats); i++) - if (kms_plane_supports_format(plane, formats[i])) - return formats[i]; - - return 0; -} - -static void prepare_framebuffer(struct kms_framebuffer *fb, bool invert) -{ - const unsigned int block_size = 16; - uint32_t colors[2]; - unsigned int i, j; - uint32_t *buf; - void *ptr; - int err; - - switch (fb->format) { - case DRM_FORMAT_XRGB8888: - printf("using XRGB8888 format\n"); - /* XXRRGGBB */ - colors[0] = 0xffff0000; - colors[1] = 0xff0000ff; - break; - - case DRM_FORMAT_XBGR8888: - printf("using XBGR8888 format\n"); - /* XXBBGGRR */ - colors[0] = 0xff0000ff; - colors[1] = 0xffff0000; - break; - - case DRM_FORMAT_RGBA8888: - printf("using RGBA8888 format\n"); - /* RRGGBBAA */ - colors[0] = 0xff0000ff; - colors[1] = 0x0000ffff; - break; - - default: - colors[0] = 0xffffffff; - colors[1] = 0xffffffff; - break; - } - - err = kms_framebuffer_map(fb, &ptr); - if (err < 0) { - fprintf(stderr, "kms_framebuffer_map() failed: %s\n", - strerror(-err)); - return; - } - - buf = ptr; - - for (j = 0; j < fb->height; j++) { - for (i = 0; i < fb->width; i++) { - unsigned int color = (j / block_size) ^ - (i / block_size); - - if (invert) - color ^= color; - - *buf++ = colors[color & 1]; - } - } - - kms_framebuffer_unmap(fb); -} - -int main(int argc, char *argv[]) -{ - static const char opts[] = "chopv"; - static struct option options[] = { - { "cursor", 0, 0, 'c' }, - { "help", 0, 0, 'h' }, - { "overlay", 0, 0, 'o' }, - { "primary", 0, 0, 'p' }, - { "verbose", 0, 0, 'v' }, - { 0, 0, 0, 0 }, - }; - struct kms_framebuffer *cursor = NULL; - struct kms_framebuffer *root = NULL; - struct kms_framebuffer *fb = NULL; - struct kms_device *device; - bool use_overlay = false; - bool use_primary = false; - struct kms_plane *plane; - bool use_cursor = false; - bool verbose = false; - unsigned int i; - int opt, idx; - int fd, err; - - while ((opt = getopt_long(argc, argv, opts, options, &idx)) != -1) { - switch (opt) { - case 'c': - use_cursor = true; - break; - - case 'h': - break; - - case 'o': - use_overlay = true; - break; - - case 'p': - use_primary = true; - break; - - case 'v': - verbose = true; - break; - - default: - printf("unknown option \"%c\"\n", opt); - return 1; - } - } - - if (optind >= argc) { - fprintf(stderr, "usage: %s [options] DEVICE\n", argv[0]); - return 1; - } - - fd = open(argv[optind], O_RDWR); - if (fd < 0) { - fprintf(stderr, "open() failed: %m\n"); - return 1; - } - - err = drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); - if (err < 0) { - fprintf(stderr, "drmSetClientCap() failed: %d\n", err); - return 1; - } - - device = kms_device_open(fd); - if (!device) - return 1; - - if (verbose) { - printf("Screens: %u\n", device->num_screens); - - for (i = 0; i < device->num_screens; i++) { - struct kms_screen *screen = device->screens[i]; - const char *status = "disconnected"; - - if (screen->connected) - status = "connected"; - - printf(" %u: %x\n", i, screen->id); - printf(" Status: %s\n", status); - printf(" Name: %s\n", screen->name); - printf(" Resolution: %ux%u\n", screen->width, - screen->height); - } - - printf("Planes: %u\n", device->num_planes); - - for (i = 0; i < device->num_planes; i++) { - const char *type = NULL; - - plane = device->planes[i]; - switch (plane->type) { - case DRM_PLANE_TYPE_OVERLAY: - type = "overlay"; - break; - - case DRM_PLANE_TYPE_PRIMARY: - type = "primary"; - break; - - case DRM_PLANE_TYPE_CURSOR: - type = "cursor"; - break; - } - - printf(" %u: %p\n", i, plane); - printf(" ID: %x\n", plane->id); - printf(" CRTC: %x\n", plane->crtc->id); - printf(" Type: %x (%s)\n", plane->type, type); - } - } - - if (use_cursor) { - unsigned int x, y; - uint32_t format; - - plane = kms_device_find_plane_by_type(device, - DRM_PLANE_TYPE_CURSOR, - 0); - if (!plane) { - fprintf(stderr, "no cursor plane found\n"); - return 1; - } - - format = choose_format(plane); - if (!format) { - fprintf(stderr, "no matching format found\n"); - return 1; - } - - cursor = kms_framebuffer_create(device, 32, 32, format); - if (!cursor) { - fprintf(stderr, "failed to create cursor buffer\n"); - return 1; - } - - prepare_framebuffer(cursor, false); - - x = (device->screens[0]->width - cursor->width) / 2; - y = (device->screens[0]->height - cursor->height) / 2; - - kms_plane_set(plane, cursor, x, y); - } - - if (use_overlay) { - uint32_t format; - - plane = kms_device_find_plane_by_type(device, - DRM_PLANE_TYPE_OVERLAY, - 0); - if (!plane) { - fprintf(stderr, "no overlay plane found\n"); - return 1; - } - - format = choose_format(plane); - if (!format) { - fprintf(stderr, "no matching format found\n"); - return 1; - } - - fb = kms_framebuffer_create(device, 320, 240, format); - if (!fb) - return 1; - - prepare_framebuffer(fb, false); - - kms_plane_set(plane, fb, 0, 0); - } - - if (use_primary) { - unsigned int x, y; - uint32_t format; - - plane = kms_device_find_plane_by_type(device, - DRM_PLANE_TYPE_PRIMARY, - 0); - if (!plane) { - fprintf(stderr, "no primary plane found\n"); - return 1; - } - - format = choose_format(plane); - if (!format) { - fprintf(stderr, "no matching format found\n"); - return 1; - } - - root = kms_framebuffer_create(device, 640, 480, format); - if (!root) - return 1; - - prepare_framebuffer(root, true); - - x = (device->screens[0]->width - root->width) / 2; - y = (device->screens[0]->height - root->height) / 2; - - kms_plane_set(plane, root, x, y); - } - - while (1) { - struct timeval timeout = { 1, 0 }; - fd_set fds; - - FD_ZERO(&fds); - FD_SET(STDIN_FILENO, &fds); - - err = select(STDIN_FILENO + 1, &fds, NULL, NULL, &timeout); - if (err < 0) { - fprintf(stderr, "select() failed: %m\n"); - break; - } - - /* timeout */ - if (err == 0) - continue; - - if (FD_ISSET(STDIN_FILENO, &fds)) - break; - } - - if (cursor) - kms_framebuffer_free(cursor); - - if (root) - kms_framebuffer_free(root); - - if (fb) - kms_framebuffer_free(fb); - - kms_device_close(device); - close(fd); - - return 0; -} diff --git a/tests/kms/libkms-test-device.c b/tests/kms/libkms-test-device.c deleted file mode 100644 index d3bb11c..0000000 --- a/tests/kms/libkms-test-device.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * 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 (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 "util/common.h" -#include "libkms-test.h" - -static const char *const connector_names[] = { - "Unknown", - "VGA", - "DVI-I", - "DVI-D", - "DVI-A", - "Composite", - "SVIDEO", - "LVDS", - "Component", - "9PinDIN", - "DisplayPort", - "HDMI-A", - "HDMI-B", - "TV", - "eDP", - "Virtual", - "DSI", -}; - -static void kms_device_probe_screens(struct kms_device *device) -{ - unsigned int counts[ARRAY_SIZE(connector_names)]; - struct kms_screen *screen; - drmModeRes *res; - int i; - - memset(counts, 0, sizeof(counts)); - - res = drmModeGetResources(device->fd); - if (!res) - return; - - device->screens = calloc(res->count_connectors, sizeof(screen)); - if (!device->screens) - goto err_free_resources; - - for (i = 0; i < res->count_connectors; i++) { - unsigned int *count; - const char *type; - int len; - - screen = kms_screen_create(device, res->connectors[i]); - if (!screen) - continue; - - /* assign a unique name to this screen */ - type = connector_names[screen->type]; - count = &counts[screen->type]; - - len = snprintf(NULL, 0, "%s-%u", type, *count); - - screen->name = malloc(len + 1); - if (!screen->name) { - free(screen); - continue; - } - - snprintf(screen->name, len + 1, "%s-%u", type, *count); - (*count)++; - - device->screens[i] = screen; - device->num_screens++; - } - -err_free_resources: - drmModeFreeResources(res); -} - -static void kms_device_probe_crtcs(struct kms_device *device) -{ - struct kms_crtc *crtc; - drmModeRes *res; - int i; - - res = drmModeGetResources(device->fd); - if (!res) - return; - - device->crtcs = calloc(res->count_crtcs, sizeof(crtc)); - if (!device->crtcs) - goto err_free_resources; - - for (i = 0; i < res->count_crtcs; i++) { - crtc = kms_crtc_create(device, res->crtcs[i]); - if (!crtc) - continue; - - device->crtcs[i] = crtc; - device->num_crtcs++; - } - -err_free_resources: - drmModeFreeResources(res); -} - -static void kms_device_probe_planes(struct kms_device *device) -{ - struct kms_plane *plane; - drmModePlaneRes *res; - unsigned int i; - - res = drmModeGetPlaneResources(device->fd); - if (!res) - return; - - device->planes = calloc(res->count_planes, sizeof(plane)); - if (!device->planes) - goto err_free_resources; - - for (i = 0; i < res->count_planes; i++) { - plane = kms_plane_create(device, res->planes[i]); - if (!plane) - continue; - - device->planes[i] = plane; - device->num_planes++; - } - -err_free_resources: - drmModeFreePlaneResources(res); -} - -static void kms_device_probe(struct kms_device *device) -{ - kms_device_probe_screens(device); - kms_device_probe_crtcs(device); - kms_device_probe_planes(device); -} - -struct kms_device *kms_device_open(int fd) -{ - struct kms_device *device; - - device = calloc(1, sizeof(*device)); - if (!device) - return NULL; - - device->fd = fd; - - kms_device_probe(device); - - return device; -} - -void kms_device_close(struct kms_device *device) -{ - unsigned int i; - - for (i = 0; i < device->num_planes; i++) - kms_plane_free(device->planes[i]); - - free(device->planes); - - for (i = 0; i < device->num_crtcs; i++) - kms_crtc_free(device->crtcs[i]); - - free(device->crtcs); - - for (i = 0; i < device->num_screens; i++) - kms_screen_free(device->screens[i]); - - free(device->screens); - - if (device->fd >= 0) - close(device->fd); - - free(device); -} - -struct kms_plane *kms_device_find_plane_by_type(struct kms_device *device, - uint32_t type, - unsigned int index) -{ - unsigned int i; - - for (i = 0; i < device->num_planes; i++) { - if (device->planes[i]->type == type) { - if (index == 0) - return device->planes[i]; - - index--; - } - } - - return NULL; -} diff --git a/tests/kms/libkms-test-framebuffer.c b/tests/kms/libkms-test-framebuffer.c deleted file mode 100644 index 9bb2d95..0000000 --- a/tests/kms/libkms-test-framebuffer.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * 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 (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 "xf86drm.h" - -#include "libkms-test.h" - -struct kms_framebuffer *kms_framebuffer_create(struct kms_device *device, - unsigned int width, - unsigned int height, - uint32_t format) -{ - uint32_t handles[4], pitches[4], offsets[4]; - struct drm_mode_create_dumb args; - struct kms_framebuffer *fb; - int err; - - fb = calloc(1, sizeof(*fb)); - if (!fb) - return NULL; - - fb->device = device; - fb->width = width; - fb->height = height; - fb->format = format; - - memset(&args, 0, sizeof(args)); - args.width = width; - args.height = height; - - switch (format) { - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_RGBA8888: - args.bpp = 32; - break; - - default: - free(fb); - return NULL; - } - - err = drmIoctl(device->fd, DRM_IOCTL_MODE_CREATE_DUMB, &args); - if (err < 0) { - free(fb); - return NULL; - } - - fb->handle = args.handle; - fb->pitch = args.pitch; - fb->size = args.size; - - handles[0] = fb->handle; - pitches[0] = fb->pitch; - offsets[0] = 0; - - err = drmModeAddFB2(device->fd, width, height, format, handles, - pitches, offsets, &fb->id, 0); - if (err < 0) { - kms_framebuffer_free(fb); - return NULL; - } - - return fb; -} - -void kms_framebuffer_free(struct kms_framebuffer *fb) -{ - struct kms_device *device = fb->device; - struct drm_mode_destroy_dumb args; - int err; - - if (fb->id) { - err = drmModeRmFB(device->fd, fb->id); - if (err < 0) { - /* not much we can do now */ - } - } - - memset(&args, 0, sizeof(args)); - args.handle = fb->handle; - - err = drmIoctl(device->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &args); - if (err < 0) { - /* not much we can do now */ - } - - free(fb); -} - -int kms_framebuffer_map(struct kms_framebuffer *fb, void **ptrp) -{ - struct kms_device *device = fb->device; - struct drm_mode_map_dumb args; - void *ptr; - int err; - - if (fb->ptr) { - *ptrp = fb->ptr; - return 0; - } - - memset(&args, 0, sizeof(args)); - args.handle = fb->handle; - - err = drmIoctl(device->fd, DRM_IOCTL_MODE_MAP_DUMB, &args); - if (err < 0) - return -errno; - - ptr = mmap(0, fb->size, PROT_READ | PROT_WRITE, MAP_SHARED, - device->fd, args.offset); - if (ptr == MAP_FAILED) - return -errno; - - *ptrp = fb->ptr = ptr; - - return 0; -} - -void kms_framebuffer_unmap(struct kms_framebuffer *fb) -{ - if (fb->ptr) { - munmap(fb->ptr, fb->size); - fb->ptr = NULL; - } -} diff --git a/tests/kms/libkms-test-plane.c b/tests/kms/libkms-test-plane.c deleted file mode 100644 index 4cb2737..0000000 --- a/tests/kms/libkms-test-plane.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * 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 (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 "libkms-test.h" - -static int kms_plane_probe(struct kms_plane *plane) -{ - struct kms_device *device = plane->device; - drmModeObjectPropertiesPtr props; - drmModePlane *p; - unsigned int i; - - p = drmModeGetPlane(device->fd, plane->id); - if (!p) - return -ENODEV; - - /* TODO: allow dynamic assignment to CRTCs */ - if (p->crtc_id == 0) { - for (i = 0; i < device->num_crtcs; i++) { - if (p->possible_crtcs & (1 << i)) { - p->crtc_id = device->crtcs[i]->id; - break; - } - } - } - - for (i = 0; i < device->num_crtcs; i++) { - if (device->crtcs[i]->id == p->crtc_id) { - plane->crtc = device->crtcs[i]; - break; - } - } - - plane->formats = calloc(p->count_formats, sizeof(uint32_t)); - if (!plane->formats) { - drmModeFreePlane(p); - return -ENOMEM; - } - - for (i = 0; i < p->count_formats; i++) - plane->formats[i] = p->formats[i]; - - plane->num_formats = p->count_formats; - - drmModeFreePlane(p); - - props = drmModeObjectGetProperties(device->fd, plane->id, - DRM_MODE_OBJECT_PLANE); - if (!props) - return -ENODEV; - - for (i = 0; i < props->count_props; i++) { - drmModePropertyPtr prop; - - prop = drmModeGetProperty(device->fd, props->props[i]); - if (prop) { - if (strcmp(prop->name, "type") == 0) - plane->type = props->prop_values[i]; - - drmModeFreeProperty(prop); - } - } - - drmModeFreeObjectProperties(props); - - return 0; -} - -struct kms_plane *kms_plane_create(struct kms_device *device, uint32_t id) -{ - struct kms_plane *plane; - - plane = calloc(1, sizeof(*plane)); - if (!plane) - return NULL; - - plane->device = device; - plane->id = id; - - kms_plane_probe(plane); - - return plane; -} - -void kms_plane_free(struct kms_plane *plane) -{ - free(plane); -} - -int kms_plane_set(struct kms_plane *plane, struct kms_framebuffer *fb, - unsigned int x, unsigned int y) -{ - struct kms_device *device = plane->device; - int err; - - err = drmModeSetPlane(device->fd, plane->id, plane->crtc->id, fb->id, - 0, x, y, fb->width, fb->height, 0 << 16, - 0 << 16, fb->width << 16, fb->height << 16); - if (err < 0) - return -errno; - - return 0; -} - -bool kms_plane_supports_format(struct kms_plane *plane, uint32_t format) -{ - unsigned int i; - - for (i = 0; i < plane->num_formats; i++) - if (plane->formats[i] == format) - return true; - - return false; -} diff --git a/tests/kms/libkms-test.h b/tests/kms/libkms-test.h deleted file mode 100644 index 7b1d02e..0000000 --- a/tests/kms/libkms-test.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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 (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 LIBKMS_TEST_H -#define LIBKMS_TEST_H - -#include -#include -#include - -#include - -struct kms_device { - int fd; - - struct kms_screen **screens; - unsigned int num_screens; - - struct kms_crtc **crtcs; - unsigned int num_crtcs; - - struct kms_plane **planes; - unsigned int num_planes; -}; - -struct kms_device *kms_device_open(int fd); -void kms_device_close(struct kms_device *device); - -struct kms_plane *kms_device_find_plane_by_type(struct kms_device *device, - uint32_t type, - unsigned int index); - -struct kms_crtc { - struct kms_device *device; - uint32_t id; -}; - -struct kms_crtc *kms_crtc_create(struct kms_device *device, uint32_t id); -void kms_crtc_free(struct kms_crtc *crtc); - -struct kms_framebuffer { - struct kms_device *device; - - unsigned int width; - unsigned int height; - unsigned int pitch; - uint32_t format; - size_t size; - - uint32_t handle; - uint32_t id; - - void *ptr; -}; - -struct kms_framebuffer *kms_framebuffer_create(struct kms_device *device, - unsigned int width, - unsigned int height, - uint32_t format); -void kms_framebuffer_free(struct kms_framebuffer *fb); -int kms_framebuffer_map(struct kms_framebuffer *fb, void **ptrp); -void kms_framebuffer_unmap(struct kms_framebuffer *fb); - -struct kms_screen { - struct kms_device *device; - bool connected; - uint32_t type; - uint32_t id; - - unsigned int width; - unsigned int height; - char *name; - - drmModeModeInfo mode; -}; - -struct kms_screen *kms_screen_create(struct kms_device *device, uint32_t id); -void kms_screen_free(struct kms_screen *screen); - -int kms_screen_set(struct kms_screen *screen, struct kms_crtc *crtc, - struct kms_framebuffer *fb); - -struct kms_plane { - struct kms_device *device; - struct kms_crtc *crtc; - unsigned int type; - uint32_t id; - - uint32_t *formats; - unsigned int num_formats; -}; - -struct kms_plane *kms_plane_create(struct kms_device *device, uint32_t id); -void kms_plane_free(struct kms_plane *plane); - -int kms_plane_set(struct kms_plane *plane, struct kms_framebuffer *fb, - unsigned int x, unsigned int y); -bool kms_plane_supports_format(struct kms_plane *plane, uint32_t format); - -#endif diff --git a/tests/kms/meson.build b/tests/kms/meson.build deleted file mode 100644 index 91371aa..0000000 --- a/tests/kms/meson.build +++ /dev/null @@ -1,49 +0,0 @@ -# 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. - - -libkms_test = static_library( - 'kms-test', - files( - 'libkms-test-crtc.c', 'libkms-test-device.c', 'libkms-test-framebuffer.c', - 'libkms-test-plane.c', 'libkms-test-screen.c', - ), - include_directories : [inc_root, inc_tests, inc_drm], - link_with : libdrm, - c_args : libdrm_c_args, -) - -kms_steal_crtc = executable( - 'kms-steal-crtc', - files('kms-steal-crtc.c'), - dependencies : dep_cairo, - include_directories : [inc_root, inc_tests, inc_drm], - link_with : [libkms_test, libutil], - install : with_install_tests, -) - -kms_universal_planes = executable( - 'kms-universal-planes', - files('kms-universal-planes.c'), - dependencies : dep_cairo, - include_directories : [inc_root, inc_tests, inc_drm], - link_with : [libkms_test], - install : with_install_tests, -) diff --git a/tests/kmstest/main.c b/tests/kmstest/main.c deleted file mode 100644 index a0e4ebb..0000000 --- a/tests/kmstest/main.c +++ /dev/null @@ -1,109 +0,0 @@ -/************************************************************************** - * - * Copyright © 2009 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. - * - **************************************************************************/ - -#include -#include -#include -#include "xf86drm.h" -#include "libkms.h" - -#include "util/kms.h" - -#define CHECK_RET_RETURN(ret, str) \ - if (ret < 0) { \ - printf("%s: %s (%s)\n", __func__, str, strerror(-ret)); \ - return ret; \ - } - -static int test_bo(struct kms_driver *kms) -{ - struct kms_bo *bo; - int ret; - unsigned attrs[7] = { - KMS_WIDTH, 1024, - KMS_HEIGHT, 768, - KMS_BO_TYPE, KMS_BO_TYPE_SCANOUT_X8R8G8B8, - KMS_TERMINATE_PROP_LIST, - }; - - ret = kms_bo_create(kms, attrs, &bo); - CHECK_RET_RETURN(ret, "Could not create bo"); - - kms_bo_destroy(&bo); - - return 0; -} - -static void usage(const char *program) -{ - fprintf(stderr, "Usage: %s [options]\n", program); - fprintf(stderr, "\n"); - fprintf(stderr, " -D DEVICE open the given device\n"); - fprintf(stderr, " -M MODULE open the given module\n"); -} - -int main(int argc, char** argv) -{ - static const char optstr[] = "D:M:"; - struct kms_driver *kms; - int c, fd, ret; - 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]); - return 0; - } - } - - fd = util_open(device, module); - CHECK_RET_RETURN(fd, "Could not open device"); - - ret = kms_create(fd, &kms); - CHECK_RET_RETURN(ret, "Failed to create kms driver"); - - ret = test_bo(kms); - if (ret) - goto err; - - printf("%s: All ok!\n", __func__); - - kms_destroy(&kms); - return 0; - -err: - kms_destroy(&kms); - return ret; -} diff --git a/tests/kmstest/meson.build b/tests/kmstest/meson.build deleted file mode 100644 index 4fb870f..0000000 --- a/tests/kmstest/meson.build +++ /dev/null @@ -1,30 +0,0 @@ -# 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. - -kmstest = executable( - 'kmstest', - files('main.c'), - c_args : libdrm_c_args, - include_directories : [ - inc_root, inc_tests, include_directories('../../libkms'), inc_drm, - ], - link_with : [libutil, libkms, libdrm], - install : with_install_tests, -) diff --git a/tests/meson.build b/tests/meson.build index 196edbf..ac9e66b 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -21,14 +21,10 @@ inc_tests = include_directories('.') subdir('util') -subdir('kms') subdir('modeprint') subdir('proptest') subdir('modetest') subdir('vbltest') -if with_libkms - subdir('kmstest') -endif if with_radeon subdir('radeon') endif diff --git a/tests/modeprint/modeprint.c b/tests/modeprint/modeprint.c index ad727e1..9372ad9 100644 --- a/tests/modeprint/modeprint.c +++ b/tests/modeprint/modeprint.c @@ -113,7 +113,7 @@ static int printProperty(int fd, drmModeResPtr res, drmModePropertyPtr props, ui } else { for (j = 0; j < props->count_enums; j++) { - printf("\t\t%lld = %s\n", props->enums[j].value, props->enums[j].name); + 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; } diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c index 3371eee..d6ab9dc 100644 --- a/tests/modetest/modetest.c +++ b/tests/modetest/modetest.c @@ -265,61 +265,44 @@ static void dump_blob(struct device *dev, uint32_t blob_id) static const char *modifier_to_string(uint64_t modifier) { - switch (modifier) { - case DRM_FORMAT_MOD_INVALID: - return "INVALID"; - case DRM_FORMAT_MOD_LINEAR: - return "LINEAR"; - case I915_FORMAT_MOD_X_TILED: - return "X_TILED"; - case I915_FORMAT_MOD_Y_TILED: - return "Y_TILED"; - case I915_FORMAT_MOD_Yf_TILED: - return "Yf_TILED"; - case I915_FORMAT_MOD_Y_TILED_CCS: - return "Y_TILED_CCS"; - case I915_FORMAT_MOD_Yf_TILED_CCS: - return "Yf_TILED_CCS"; - case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE: - return "SAMSUNG_64_32_TILE"; - case DRM_FORMAT_MOD_VIVANTE_TILED: - return "VIVANTE_TILED"; - case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED: - return "VIVANTE_SUPER_TILED"; - case DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED: - return "VIVANTE_SPLIT_TILED"; - case DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED: - return "VIVANTE_SPLIT_SUPER_TILED"; - case DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED: - return "NVIDIA_TEGRA_TILED"; - case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0): - return "NVIDIA_16BX2_BLOCK(0)"; - case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1): - return "NVIDIA_16BX2_BLOCK(1)"; - case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2): - return "NVIDIA_16BX2_BLOCK(2)"; - case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3): - return "NVIDIA_16BX2_BLOCK(3)"; - case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4): - return "NVIDIA_16BX2_BLOCK(4)"; - case DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5): - return "NVIDIA_16BX2_BLOCK(5)"; - case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: - return "MOD_BROADCOM_VC4_T_TILED"; - case DRM_FORMAT_MOD_QCOM_COMPRESSED: - return "QCOM_COMPRESSED"; - default: - return "(UNKNOWN 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) { - uint32_t i, j; + drmModeFormatModifierIterator iter = {0}; drmModePropertyBlobPtr blob; - struct drm_format_modifier_blob *header; - uint32_t *formats; - struct drm_format_modifier *modifiers; + uint32_t fmt = 0; printf("\t\tin_formats blob decoded:\n"); blob = drmModeGetPropertyBlob(dev->fd, blob_id); @@ -328,23 +311,19 @@ static void dump_in_formats(struct device *dev, uint32_t blob_id) return; } - header = blob->data; - formats = (uint32_t *) ((char *) header + header->formats_offset); - modifiers = (struct drm_format_modifier *) - ((char *) header + header->modifiers_offset); - - for (i = 0; i < header->count_formats; i++) { - printf("\t\t\t"); - dump_fourcc(formats[i]); - printf(": "); - for (j = 0; j < header->count_modifiers; j++) { - uint64_t mask = 1ULL << i; - if (modifiers[j].formats & mask) - printf(" %s", modifier_to_string(modifiers[j].modifier)); + while (drmModeFormatModifierBlobIterNext(blob, &iter)) { + if (!fmt || fmt != iter.fmt) { + printf("%s\t\t\t", !fmt ? "" : "\n"); + fmt = iter.fmt; + dump_fourcc(fmt); + printf(": "); } - printf("\n"); + + printf(" %s", modifier_to_string(iter.mod)); } + printf("\n"); + drmModeFreePropertyBlob(blob); } @@ -396,8 +375,8 @@ static void dump_prop(struct device *dev, drmModePropertyPtr prop, if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM)) { printf("\t\tenums:"); for (i = 0; i < prop->count_enums; i++) - printf(" %s=%llu", prop->enums[i].name, - prop->enums[i].value); + 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:"); @@ -457,7 +436,7 @@ static void dump_connectors(struct device *dev) if (connector->count_modes) { printf(" modes:\n"); printf("\tindex name refresh (Hz) hdisp hss hse htot vdisp " - "vss vse vtot)\n"); + "vss vse vtot\n"); for (j = 0; j < connector->count_modes; j++) dump_mode(&connector->modes[j], j); } @@ -1725,13 +1704,21 @@ static void set_planes(struct device *dev, struct plane_arg *p, unsigned int cou 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; - /* maybe make cursor width/height configurable some day */ - uint32_t cw = 64; - uint32_t ch = 64; + 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 diff --git a/tests/nouveau/threaded.c b/tests/nouveau/threaded.c index ddbac74..eaa469e 100644 --- a/tests/nouveau/threaded.c +++ b/tests/nouveau/threaded.c @@ -31,7 +31,7 @@ #include "xf86drm.h" #include "nouveau.h" -static typeof(ioctl) *old_ioctl; +static __typeof__(ioctl) *old_ioctl; static int failed; static int import_fd; diff --git a/tests/proptest/proptest.c b/tests/proptest/proptest.c index 5abbf02..88bed10 100644 --- a/tests/proptest/proptest.c +++ b/tests/proptest/proptest.c @@ -126,8 +126,8 @@ dump_prop(uint32_t prop_id, uint64_t value) if (drm_property_type_is(prop, DRM_MODE_PROP_ENUM)) { printf("\t\tenums:"); for (i = 0; i < prop->count_enums; i++) - printf(" %s=%llu", prop->enums[i].name, - prop->enums[i].value); + 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:"); diff --git a/tests/tegra/.gitignore b/tests/tegra/.gitignore index 5c5216c..0db9e54 100644 --- a/tests/tegra/.gitignore +++ b/tests/tegra/.gitignore @@ -1 +1,2 @@ -openclose +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/kms/libkms-test-screen.c b/tests/tegra/drm-test.h similarity index 30% rename from tests/kms/libkms-test-screen.c rename to tests/tegra/drm-test.h index d00ae54..f11aed4 100644 --- a/tests/kms/libkms-test-screen.c +++ b/tests/tegra/drm-test.h @@ -8,83 +8,65 @@ * 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 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. + * 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 "libkms-test.h" - -static void kms_screen_probe(struct kms_screen *screen) -{ - struct kms_device *device = screen->device; - drmModeConnector *con; - - con = drmModeGetConnector(device->fd, screen->id); - if (!con) - return; - - screen->type = con->connector_type; - - if (con->connection == DRM_MODE_CONNECTED) - screen->connected = true; - else - screen->connected = false; - - if (con->modes) - memcpy(&screen->mode, &con->modes[0], sizeof(drmModeModeInfo)); - - screen->width = screen->mode.hdisplay; - screen->height = screen->mode.vdisplay; - - drmModeFreeConnector(con); -} - -struct kms_screen *kms_screen_create(struct kms_device *device, uint32_t id) -{ - struct kms_screen *screen; - - screen = calloc(1, sizeof(*screen)); - if (!screen) - return NULL; - - screen->device = device; - screen->id = id; - - kms_screen_probe(screen); - - return screen; -} - -void kms_screen_free(struct kms_screen *screen) -{ - if (screen) - free(screen->name); - - free(screen); -} - -int kms_screen_set(struct kms_screen *screen, struct kms_crtc *crtc, - struct kms_framebuffer *fb) -{ - struct kms_device *device = screen->device; - int err; - - err = drmModeSetCrtc(device->fd, crtc->id, fb->id, 0, 0, &screen->id, - 1, &screen->mode); - if (err < 0) - return -errno; - - return 0; -} +#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/kms/libkms-test-crtc.c b/tests/tegra/host1x.h similarity index 47% rename from tests/kms/libkms-test-crtc.c rename to tests/tegra/host1x.h index 2c28fac..902b0c1 100644 --- a/tests/kms/libkms-test-crtc.c +++ b/tests/tegra/host1x.h @@ -1,5 +1,5 @@ /* - * Copyright © 2014 NVIDIA Corporation + * 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"), @@ -8,36 +8,27 @@ * 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 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. + * 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 "libkms-test.h" +#ifndef HOST1X_H +#define HOST1X_H -struct kms_crtc *kms_crtc_create(struct kms_device *device, uint32_t id) -{ - struct kms_crtc *crtc; +#define HOST1X_OPCODE_SETCL(offset, classid, mask) \ + ((0x0 << 28) | (((offset) & 0xfff) << 16) | (((classid) & 0x3ff) << 6) | ((mask) & 0x3f)) - crtc = calloc(1, sizeof(*crtc)); - if (!crtc) - return NULL; +#define HOST1X_OPCODE_INCR(offset, count) \ + ((0x1 << 28) | (((offset) & 0xfff) << 16) | ((count) & 0xffff)) - crtc->device = device; - crtc->id = id; +#define HOST1X_CLASS_VIC 0x5d - return crtc; -} - -void kms_crtc_free(struct kms_crtc *crtc) -{ - free(crtc); -} +#endif diff --git a/tests/tegra/meson.build b/tests/tegra/meson.build index 4f8c54f..26a32e8 100644 --- a/tests/tegra/meson.build +++ b/tests/tegra/meson.build @@ -18,10 +18,94 @@ # 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( - 'openclose', + 'tegra-openclose', files('openclose.c'), - include_directories : [inc_root, inc_drm, include_directories('../../tegra')], + 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 index f80f52d..61dbc2b 100644 --- a/tests/tegra/openclose.c +++ b/tests/tegra/openclose.c @@ -31,37 +31,37 @@ 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; + struct drm_tegra *tegra; + drmVersionPtr version; + const char *device; + int err, fd; - if (argc < 2) - device = default_device; - else - device = argv[1]; + if (argc < 2) + device = default_device; + else + device = argv[1]; - fd = open(device, O_RDWR); - if (fd < 0) - return 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); + 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); - } + drmFreeVersion(version); + } - err = drm_tegra_new(&tegra, fd); - if (err < 0) - return 1; + err = drm_tegra_new(fd, &tegra); + if (err < 0) + return 1; - drm_tegra_close(tegra); - close(fd); + drm_tegra_close(tegra); + close(fd); - return 0; + 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/reconf b/tests/ttmtest/reconf old mode 100755 new mode 100644 diff --git a/tests/util/kms.c b/tests/util/kms.c index dd1bbee..39a9386 100644 --- a/tests/util/kms.c +++ b/tests/util/kms.c @@ -147,6 +147,9 @@ static const char * const modules[] = { "stm", "sun4i-drm", "armada-drm", + "komeda", + "imx-dcss", + "mxsfb-drm", }; int util_open(const char *device, const char *module) diff --git a/tests/util/pattern.c b/tests/util/pattern.c index bf1797d..158c0b1 100644 --- a/tests/util/pattern.c +++ b/tests/util/pattern.c @@ -985,7 +985,6 @@ static void fill_tiles_rgb16fp(const struct util_format_info *info, void *mem, unsigned int stride) { const struct util_rgb_info *rgb = &info->rgb; - void *mem_base = mem; unsigned int x, y; /* TODO: Give this actual fp16 precision */ @@ -1113,7 +1112,7 @@ static void fill_gradient_rgb32(const struct util_rgb_info *rgb, unsigned int width, unsigned int height, unsigned int stride) { - int i, j; + unsigned int i, j; for (i = 0; i < height / 2; i++) { uint32_t *row = mem; @@ -1141,7 +1140,7 @@ static void fill_gradient_rgb16fp(const struct util_rgb_info *rgb, unsigned int width, unsigned int height, unsigned int stride) { - int i, j; + unsigned int i, j; for (i = 0; i < height / 2; i++) { uint64_t *row = mem; diff --git a/util_double_list.h b/util_double_list.h index 7e48b26..9bdca13 100644 --- a/util_double_list.h +++ b/util_double_list.h @@ -110,7 +110,7 @@ static inline void list_delinit(struct list_head *item) #ifndef container_of #define container_of(ptr, sample, member) \ (void *)((char *)(ptr) \ - - ((char *)&((typeof(sample))0)->member)) + - ((char *)&((__typeof__(sample))0)->member)) #endif #define LIST_FOR_EACH_ENTRY(pos, head, member) \ diff --git a/xf86drm.c b/xf86drm.c index b49d42f..76fdfaa 100644 --- a/xf86drm.c +++ b/xf86drm.c @@ -61,6 +61,7 @@ #include #endif #include +#include #if defined(__FreeBSD__) #include @@ -76,6 +77,7 @@ #include "xf86drm.h" #include "libdrm_macros.h" +#include "drm_fourcc.h" #include "util_math.h" @@ -124,6 +126,443 @@ 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; @@ -696,7 +1135,7 @@ static int drmOpenByName(const char *name, int type) int retcode; sprintf(proc_name, "/proc/dri/%d/name", i); - if ((fd = open(proc_name, 0, 0)) >= 0) { + if ((fd = open(proc_name, O_RDONLY, 0)) >= 0) { retcode = read(fd, buf, sizeof(buf)-1); close(fd); if (retcode) { @@ -1121,8 +1560,8 @@ drm_public int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType t memclear(map); map.offset = offset; map.size = size; - map.type = type; - map.flags = flags; + 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) @@ -1166,7 +1605,7 @@ drm_public int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags, memclear(request); request.count = count; request.size = size; - request.flags = flags; + request.flags = (int)flags; request.agp_start = agp_offset; if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request)) @@ -1335,7 +1774,12 @@ drm_public drmBufInfoPtr drmGetBufInfo(int fd) retval = drmMalloc(sizeof(*retval)); retval->count = info.count; - retval->list = drmMalloc(info.count * sizeof(*retval->list)); + 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; @@ -1445,7 +1889,7 @@ drm_public int drmDMA(int fd, drmDMAReqPtr request) dma.send_count = request->send_count; dma.send_indices = request->send_list; dma.send_sizes = request->send_sizes; - dma.flags = request->flags; + 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; @@ -2382,8 +2826,8 @@ drm_public int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size, return -errno; *offset = map.offset; *size = map.size; - *type = map.type; - *flags = map.flags; + *type = (drmMapType)map.type; + *flags = (drmMapFlags)map.flags; *handle = (unsigned long)map.handle; *mtrr = map.mtrr; return 0; @@ -2822,7 +3266,7 @@ static bool drmNodeIsDRM(int maj, int min) snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/drm", maj, min); return stat(path, &sbuf) == 0; -#elif __FreeBSD__ +#elif defined(__FreeBSD__) char name[SPECNAMELEN]; if (!devname_r(makedev(maj, min), S_IFCHR, name, sizeof(name))) @@ -2892,6 +3336,15 @@ drm_public int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *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__ @@ -2925,8 +3378,9 @@ static char *drmGetMinorNameForFD(int fd, int type) while ((ent = readdir(sysdir))) { if (strncmp(ent->d_name, name, len) == 0) { - snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s", - ent->d_name); + if (snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s", + ent->d_name) < 0) + return NULL; closedir(sysdir); return strdup(dev_name); @@ -2935,7 +3389,7 @@ static char *drmGetMinorNameForFD(int fd, int type) closedir(sysdir); return NULL; -#elif __FreeBSD__ +#elif defined(__FreeBSD__) struct stat sbuf; char dname[SPECNAMELEN]; const char *mname; @@ -3255,7 +3709,7 @@ static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info) info->func = pinfo.func; return 0; -#elif __FreeBSD__ +#elif defined(__FreeBSD__) return get_sysctl_pci_bus_info(maj, min, info); #else #warning "Missing implementation of drmParsePciBusInfo" @@ -3337,7 +3791,9 @@ static int parse_separate_sysfs_files(int maj, int min, get_pci_path(maj, min, pci_path); for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) { - snprintf(path, PATH_MAX, "%s/%s", pci_path, attrs[i]); + if (snprintf(path, PATH_MAX, "%s/%s", pci_path, attrs[i]) < 0) + return -errno; + fp = fopen(path, "r"); if (!fp) return -errno; @@ -3367,7 +3823,9 @@ static int parse_config_sysfs_file(int maj, int min, get_pci_path(maj, min, pci_path); - snprintf(path, PATH_MAX, "%s/config", pci_path); + if (snprintf(path, PATH_MAX, "%s/config", pci_path) < 0) + return -errno; + fd = open(path, O_RDONLY); if (fd < 0) return -errno; @@ -3424,7 +3882,7 @@ static int drmParsePciDeviceInfo(int maj, int min, device->subdevice_id = pinfo.subdevice_id; return 0; -#elif __FreeBSD__ +#elif defined(__FreeBSD__) drmPciBusInfo info; struct pci_conf_io pc; struct pci_match_conf patterns[1]; @@ -3619,6 +4077,7 @@ free_device: 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); @@ -3626,9 +4085,13 @@ static int drm_usb_dev_path(int maj, int min, char *path, size_t len) if (!value) return -ENOENT; - if (strcmp(value, "usb_device") == 0) + usb_device = strcmp(value, "usb_device") == 0; + usb_interface = strcmp(value, "usb_interface") == 0; + free(value); + + if (usb_device) return 0; - if (strcmp(value, "usb_interface") != 0) + if (!usb_interface) return -ENOTSUP; /* The parent of a usb_interface is a usb_device */ @@ -4001,7 +4464,7 @@ static void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count) 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(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]); @@ -4040,19 +4503,16 @@ drm_device_has_rdev(drmDevicePtr device, dev_t find_rdev) #define MAX_DRM_NODES 256 /** - * Get information about the opened drm device + * Get information about a device from its dev_t identifier * - * \param fd file descriptor of the drm device + * \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. - * - * \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) +drm_public int drmGetDeviceFromDevId(dev_t find_rdev, uint32_t flags, drmDevicePtr *device) { #ifdef __OpenBSD__ /* @@ -4061,22 +4521,18 @@ drm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device) * Avoid stat'ing all of /dev needlessly by implementing this custom path. */ drmDevicePtr d; - struct stat sbuf; char node[PATH_MAX + 1]; const char *dev_name; int node_type, subsystem_type; int maj, min, n, ret; - if (fd == -1 || device == NULL) + if (device == NULL) return -EINVAL; - if (fstat(fd, &sbuf)) - return -errno; - - maj = major(sbuf.st_rdev); - min = minor(sbuf.st_rdev); + maj = major(find_rdev); + min = minor(find_rdev); - if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) + if (!drmNodeIsDRM(maj, min)) return -EINVAL; node_type = drmGetMinorType(maj, min); @@ -4109,26 +4565,20 @@ drm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device) drmDevicePtr d; DIR *sysdir; struct dirent *dent; - struct stat sbuf; int subsystem_type; int maj, min; int ret, i, node_count; - dev_t find_rdev; if (drm_device_validate_flags(flags)) return -EINVAL; - if (fd == -1 || device == NULL) + if (device == NULL) return -EINVAL; - if (fstat(fd, &sbuf)) - return -errno; + maj = major(find_rdev); + min = minor(find_rdev); - find_rdev = sbuf.st_rdev; - maj = major(sbuf.st_rdev); - min = minor(sbuf.st_rdev); - - if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) + if (!drmNodeIsDRM(maj, min)) return -EINVAL; subsystem_type = drmParseSubsystemType(maj, min); @@ -4177,6 +4627,35 @@ drm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device) #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 * @@ -4256,6 +4735,10 @@ drm_public int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], } closedir(sysdir); + + if (devices != NULL) + return MIN2(device_count, max_devices); + return device_count; } @@ -4302,7 +4785,7 @@ drm_public char *drmGetDeviceNameFromFd2(int fd) free(value); return strdup(path); -#elif __FreeBSD__ +#elif defined(__FreeBSD__) return drmGetDeviceNameFromFd(fd); #else struct stat sbuf; @@ -4560,3 +5043,66 @@ drm_public int drmSyncobjTransfer(int fd, 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; +} diff --git a/xf86drm.h b/xf86drm.h index 7b85079..1631396 100644 --- a/xf86drm.h +++ b/xf86drm.h @@ -813,9 +813,29 @@ extern char *drmGetDeviceNameFromFd(int fd); 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); @@ -897,6 +917,8 @@ extern void drmFreeDevices(drmDevicePtr devices[], int count); 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); @@ -926,6 +948,17 @@ extern int drmSyncobjTransfer(int fd, uint32_t src_handle, uint64_t src_point, uint32_t flags); +extern char * +drmGetFormatModifierVendor(uint64_t modifier); + +extern char * +drmGetFormatModifierName(uint64_t modifier); + +#ifndef fourcc_mod_get_vendor +#define fourcc_mod_get_vendor(modifier) \ + (((modifier) >> 56) & 0xff) +#endif + #if defined(__cplusplus) } #endif diff --git a/xf86drmMode.c b/xf86drmMode.c index 5af27c4..87e9660 100644 --- a/xf86drmMode.c +++ b/xf86drmMode.c @@ -33,16 +33,15 @@ * */ -/* - * TODO the types we are after are defined in different headers on different - * platforms find which headers to include to get uint32_t - */ - +#include #include #include #include #include #if HAVE_SYS_SYSCTL_H +#ifdef __FreeBSD__ +#include +#endif #include #endif #include @@ -52,6 +51,7 @@ #include "xf86drmMode.h" #include "xf86drm.h" #include +#include #include #include #include @@ -151,6 +151,16 @@ drm_public void drmModeFreeEncoder(drmModeEncoderPtr 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; @@ -719,6 +729,112 @@ err_allocs: 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) @@ -1208,6 +1324,7 @@ struct _drmModeAtomicReqItem { uint32_t object_id; uint32_t property_id; uint64_t value; + uint32_t cursor; }; struct _drmModeAtomicReq { @@ -1263,6 +1380,8 @@ drm_public drmModeAtomicReqPtr drmModeAtomicDuplicate(drmModeAtomicReqPtr old) drm_public int drmModeAtomicMerge(drmModeAtomicReqPtr base, drmModeAtomicReqPtr augment) { + uint32_t i; + if (!base) return -EINVAL; @@ -1285,6 +1404,8 @@ drm_public int drmModeAtomicMerge(drmModeAtomicReqPtr base, 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; @@ -1330,6 +1451,7 @@ drm_public int drmModeAtomicAddProperty(drmModeAtomicReqPtr req, 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; @@ -1350,12 +1472,12 @@ 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 -1; - else if (first->object_id > second->object_id) - return 1; + 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 second->property_id - first->property_id; + return first->cursor - second->cursor; } drm_public int drmModeAtomicCommit(int fd, drmModeAtomicReqPtr req, @@ -1407,6 +1529,9 @@ drm_public int drmModeAtomicCommit(int fd, drmModeAtomicReqPtr req, 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; diff --git a/xf86drmMode.h b/xf86drmMode.h index 5449320..19bf91d 100644 --- a/xf86drmMode.h +++ b/xf86drmMode.h @@ -41,15 +41,14 @@ extern "C" { #endif #include +#include +#include #include #include /* * This is the interface for modesetting for drm. * - * In order to use this interface you must include either or another - * header defining uint32_t, int32_t and uint16_t. - * * 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. * @@ -61,121 +60,6 @@ extern "C" { * buffer object interface. This object needs to be pinned. */ -/* - * If we pickup an old version of drm.h which doesn't include drm_mode.h - * we should redefine defines. This is so that builds doesn't breaks with - * new libdrm on old kernels. - */ -#ifndef _DRM_MODE_H - -#define DRM_DISPLAY_INFO_LEN 32 -#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) -#define DRM_MODE_TYPE_CLOCK_C ((1<<1) | DRM_MODE_TYPE_BUILTIN) -#define DRM_MODE_TYPE_CRTC_C ((1<<2) | DRM_MODE_TYPE_BUILTIN) -#define DRM_MODE_TYPE_PREFERRED (1<<3) -#define DRM_MODE_TYPE_DEFAULT (1<<4) -#define DRM_MODE_TYPE_USERDEF (1<<5) -#define DRM_MODE_TYPE_DRIVER (1<<6) - -/* Video mode flags */ -/* bit compatible with the xorg definitions. */ -#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) -#define DRM_MODE_FLAG_PIXMUX (1<<11) -#define DRM_MODE_FLAG_DBLCLK (1<<12) -#define DRM_MODE_FLAG_CLKDIV2 (1<<13) -#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) - -/* 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_NON_GPU 0 -#define DRM_MODE_SCALE_FULLSCREEN 1 -#define DRM_MODE_SCALE_NO_SCALE 2 -#define DRM_MODE_SCALE_ASPECT 3 - -/* Dithering mode options */ -#define DRM_MODE_DITHERING_OFF 0 -#define DRM_MODE_DITHERING_ON 1 - -#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 - -#define DRM_MODE_SUBCONNECTOR_Automatic 0 -#define DRM_MODE_SUBCONNECTOR_Unknown 0 -#define DRM_MODE_SUBCONNECTOR_DVID 3 -#define DRM_MODE_SUBCONNECTOR_DVIA 4 -#define DRM_MODE_SUBCONNECTOR_Composite 5 -#define DRM_MODE_SUBCONNECTOR_SVIDEO 6 -#define DRM_MODE_SUBCONNECTOR_Component 8 -#define DRM_MODE_SUBCONNECTOR_SCART 9 - -#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_PROP_PENDING (1<<0) -#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_CURSOR_BO (1<<0) -#define DRM_MODE_CURSOR_MOVE (1<<1) - -#endif /* _DRM_MODE_H */ - - /* * Feature defines * @@ -259,13 +143,15 @@ typedef struct _drmModeProperty { uint32_t *blob_ids; /* store the blob IDs */ } drmModePropertyRes, *drmModePropertyPtr; -static __inline int drm_property_type_is(drmModePropertyPtr property, +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) { - /* instanceof for props.. handles extended type vs original types: */ - if (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) - return (property->flags & DRM_MODE_PROP_EXTENDED_TYPE) == type; - return property->flags & type; + return drmModeGetPropertyType(property) == type; } typedef struct _drmModeCrtc { @@ -289,6 +175,18 @@ typedef struct _drmModeEncoder { 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, @@ -334,6 +232,12 @@ typedef struct _drmModeObjectProperties { 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; @@ -364,6 +268,13 @@ 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. */ @@ -484,6 +395,8 @@ 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); @@ -548,14 +461,14 @@ extern int drmModeCreateLease(int fd, const uint32_t *objects, int num_objects, typedef struct drmModeLesseeList { uint32_t count; - uint32_t lessees[0]; + uint32_t lessees[]; } drmModeLesseeListRes, *drmModeLesseeListPtr; extern drmModeLesseeListPtr drmModeListLessees(int fd); typedef struct drmModeObjectList { uint32_t count; - uint32_t objects[0]; + uint32_t objects[]; } drmModeObjectListRes, *drmModeObjectListPtr; extern drmModeObjectListPtr drmModeGetLease(int fd); -- Gitee