From bdea21923622a7828dc1a4a0eda57abc7b51d3c6 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 27 Mar 2025 15:53:38 -0700 Subject: [PATCH 01/80] ci: Pin actions to commit hash --- .../workflows/build-xemu-win64-toolchain.yml | 10 ++--- .github/workflows/build.yml | 42 +++++++++---------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/.github/workflows/build-xemu-win64-toolchain.yml b/.github/workflows/build-xemu-win64-toolchain.yml index deefd9c070..972382d5d7 100644 --- a/.github/workflows/build-xemu-win64-toolchain.yml +++ b/.github/workflows/build-xemu-win64-toolchain.yml @@ -21,10 +21,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Clone tree - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Extract image metadata (tags, labels) id: meta - uses: docker/metadata-action@v5 + uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} labels: | @@ -35,16 +35,16 @@ jobs: type=ref,event=branch type=sha - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3 - name: Login to GitHub Container Registry - uses: docker/login-action@v3 + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3 if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5 with: context: ubuntu-win64-cross push: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0ef3537790..79876dd479 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Clone tree - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: fetch-depth: 0 - name: Install dependencies @@ -50,7 +50,7 @@ jobs: ./scripts/archive-source.sh src.tar gzip -1 src.tar - name: Upload source package artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: src.tar.gz path: src.tar.gz @@ -83,14 +83,14 @@ jobs: steps: - name: Download source package - uses: actions/download-artifact@v4 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 with: name: src.tar.gz - name: Extract source package run: tar xf src.tar.gz - name: Initialize compiler cache id: cache - uses: actions/cache@v4 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4 with: path: /tmp/xemu-ccache key: cache-wincross-${{ runner.os }}-${{ matrix.arch }}-${{ matrix.configuration }}-${{ github.sha }} @@ -111,7 +111,7 @@ jobs: $DOCKER_IMAGE_NAME \ bash -c "ccache -z; ./build.sh -p win64-cross ${{ matrix.build_param }} && ccache -s" - name: Upload build artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: ${{ matrix.artifact_name }} path: dist @@ -140,7 +140,7 @@ jobs: arch: aarch64 steps: - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 with: name: ${{ matrix.artifact_name }} path: ${{ matrix.artifact_name }} @@ -157,7 +157,7 @@ jobs: 7z a -tzip ../dist/${{ matrix.artifact_name }}.zip * "-xr!*.pdb" 7z a -tzip ../dist/${{ matrix.artifact_name }}-pdb.zip "-ir!*.pdb" - name: Upload build artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: ${{ matrix.artifact_name }}-pdb path: dist @@ -196,13 +196,13 @@ jobs: steps: - name: Initialize compiler cache id: cache - uses: actions/cache@v4 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4 with: path: /tmp/xemu-ccache key: cache-${{ runner.os }}-${{ matrix.arch }}-${{ matrix.configuration }}-${{ github.sha }} restore-keys: cache-${{ runner.os }}-${{ matrix.arch }}-${{ matrix.configuration }}- - name: Download source package - uses: actions/download-artifact@v4 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 with: name: src.tar.gz - name: Extract source package @@ -266,7 +266,7 @@ jobs: run: | tar -czvf ${{ matrix.artifact_filename }} --transform "s#^dist#xemu#" dist - name: Upload build artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: ${{ matrix.artifact_name }} path: ${{ matrix.artifact_filename }} @@ -300,7 +300,7 @@ jobs: artifact_filename: xemu-macos-arm64-release.zip steps: - name: Download source package - uses: actions/download-artifact@v4 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 with: name: src.tar.gz - name: Extract source package @@ -319,7 +319,7 @@ jobs: pip install pyyaml requests - name: Initialize compiler, library cache id: cache - uses: actions/cache@v4 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4 with: path: | xemu-ccache @@ -339,7 +339,7 @@ jobs: zip -r ../${{ matrix.artifact_filename }} * popd - name: Upload build artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: ${{ matrix.artifact_name }} path: ${{ matrix.artifact_filename }} @@ -353,12 +353,12 @@ jobs: configuration: ["debug", "release"] steps: - name: Download x86_64 build - uses: actions/download-artifact@v4 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 with: name: xemu-macos-x86_64-${{ matrix.configuration }} path: xemu-macos-x86_64-${{ matrix.configuration }} - name: Download arm64 build - uses: actions/download-artifact@v4 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 with: name: xemu-macos-arm64-${{ matrix.configuration }} path: xemu-macos-arm64-${{ matrix.configuration }} @@ -382,7 +382,7 @@ jobs: zip -r ../xemu-macos-universal-${{ matrix.configuration }}.zip * popd - name: Upload build artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: xemu-macos-universal-${{ matrix.configuration }} path: xemu-macos-universal-${{ matrix.configuration }}.zip @@ -393,7 +393,7 @@ jobs: needs: [Ubuntu, macOSUniversal, Windows, WindowsPdb] steps: - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 with: path: dist - name: Extract source package @@ -415,7 +415,7 @@ jobs: run: | cp dist/xemu-win-x86_64-release-pdb/xemu-win-x86_64-release.zip dist/xemu-win-x86_64-release-pdb/xemu-win-release.zip - name: Publish release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1 with: tag_name: v${{ env.XEMU_VERSION }} name: v${{ env.XEMU_VERSION }} @@ -439,7 +439,7 @@ jobs: dist/xemu-ubuntu-aarch64-debug/xemu/xemu-v${{ env.XEMU_VERSION }}-dbg-aarch64.AppImage dist/xemu-ubuntu-aarch64-release/xemu/xemu-v${{ env.XEMU_VERSION }}-aarch64.AppImage - name: Trigger website update - uses: benc-uk/workflow-dispatch@v1.2.2 + uses: benc-uk/workflow-dispatch@798e70c97009500150087d30d9f11c5444830385 # v1.2.2 with: workflow: build.yml repo: xemu-project/xemu-website @@ -457,7 +457,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download source package - uses: actions/download-artifact@v4 + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 with: name: src.tar.gz - name: Extract source package @@ -476,7 +476,7 @@ jobs: -- Matt Borgerson $(date -R)" > debian/changelog popd - name: Deploy source archive to branch - uses: peaceiris/actions-gh-pages@v3 + uses: peaceiris/actions-gh-pages@373f7f263a76c20808c831209c920827a82a2847 # v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./src From 9cf1483cd3c0c7b158d926c25935cf8c9b99f8f0 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 27 Mar 2025 15:54:21 -0700 Subject: [PATCH 02/80] ci: Add dependabot config for GH actions update --- .github/dependabot.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..5ace4600a1 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" From 8a2bd21bcb6d55493ba5ccd8a75fc16529d5db67 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 17:02:14 -0700 Subject: [PATCH 03/80] ci: bump benc-uk/workflow-dispatch from 1.2.2 to 1.2.4 Bumps [benc-uk/workflow-dispatch](https://github.com/benc-uk/workflow-dispatch) from 1.2.2 to 1.2.4. - [Release notes](https://github.com/benc-uk/workflow-dispatch/releases) - [Commits](https://github.com/benc-uk/workflow-dispatch/compare/798e70c97009500150087d30d9f11c5444830385...e2e5e9a103e331dad343f381a29e654aea3cf8fc) --- updated-dependencies: - dependency-name: benc-uk/workflow-dispatch dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 79876dd479..57ac4664be 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -439,7 +439,7 @@ jobs: dist/xemu-ubuntu-aarch64-debug/xemu/xemu-v${{ env.XEMU_VERSION }}-dbg-aarch64.AppImage dist/xemu-ubuntu-aarch64-release/xemu/xemu-v${{ env.XEMU_VERSION }}-aarch64.AppImage - name: Trigger website update - uses: benc-uk/workflow-dispatch@798e70c97009500150087d30d9f11c5444830385 # v1.2.2 + uses: benc-uk/workflow-dispatch@e2e5e9a103e331dad343f381a29e654aea3cf8fc # v1.2.4 with: workflow: build.yml repo: xemu-project/xemu-website From ce7e228afa598653af4e038335730ac2a33aecfa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 17:02:50 -0700 Subject: [PATCH 04/80] ci: bump actions/setup-python from 5.1.0 to 5.5.0 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5.1.0 to 5.5.0. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v5.1.0...v5.5.0) --- updated-dependencies: - dependency-name: actions/setup-python dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 57ac4664be..e844798886 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -305,7 +305,7 @@ jobs: name: src.tar.gz - name: Extract source package run: tar xf src.tar.gz - - uses: actions/setup-python@v5.1.0 + - uses: actions/setup-python@v5.5.0 with: python-version: '3.12' - name: Install dependencies From 56d643ff2660c2568d87ef0bfaeb773ae51c7f1f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 17:23:09 -0700 Subject: [PATCH 05/80] ci: bump softprops/action-gh-release from 1 to 2 Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 1 to 2. - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/de2c0eb89ae2a093876385947365aca7b0e5f844...c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e844798886..7c14ad126d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -415,7 +415,7 @@ jobs: run: | cp dist/xemu-win-x86_64-release-pdb/xemu-win-x86_64-release.zip dist/xemu-win-x86_64-release-pdb/xemu-win-release.zip - name: Publish release - uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1 + uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda # v2.2.1 with: tag_name: v${{ env.XEMU_VERSION }} name: v${{ env.XEMU_VERSION }} From 5eeee7cd5c85e9fa412d33c9bac1c458e189a079 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 17:23:35 -0700 Subject: [PATCH 06/80] ci: bump docker/build-push-action from 5.4.0 to 6.15.0 Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5.4.0 to 6.15.0. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/ca052bb54ab0790a636c9b5f226502c73d547a25...471d1dc4e07e5cdedd4c2171150001c434f0b7a4) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-xemu-win64-toolchain.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-xemu-win64-toolchain.yml b/.github/workflows/build-xemu-win64-toolchain.yml index 972382d5d7..7a521389a5 100644 --- a/.github/workflows/build-xemu-win64-toolchain.yml +++ b/.github/workflows/build-xemu-win64-toolchain.yml @@ -44,7 +44,7 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push image - uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5 + uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v5 with: context: ubuntu-win64-cross push: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} From a6fbb4957b6fe4f8636c70a5892a87db1a450cb2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 17:25:32 -0700 Subject: [PATCH 07/80] ci: bump peaceiris/actions-gh-pages from 3.9.3 to 4.0.0 Bumps [peaceiris/actions-gh-pages](https://github.com/peaceiris/actions-gh-pages) from 3.9.3 to 4.0.0. - [Release notes](https://github.com/peaceiris/actions-gh-pages/releases) - [Changelog](https://github.com/peaceiris/actions-gh-pages/blob/main/CHANGELOG.md) - [Commits](https://github.com/peaceiris/actions-gh-pages/compare/373f7f263a76c20808c831209c920827a82a2847...4f9cc6602d3f66b9c108549d475ec49e8ef4d45e) --- updated-dependencies: - dependency-name: peaceiris/actions-gh-pages dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7c14ad126d..71a2d9a500 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -476,7 +476,7 @@ jobs: -- Matt Borgerson $(date -R)" > debian/changelog popd - name: Deploy source archive to branch - uses: peaceiris/actions-gh-pages@373f7f263a76c20808c831209c920827a82a2847 # v3 + uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./src From 48c454e1b620ee53a393a5aef311cf9130ab4bc5 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 27 Mar 2025 16:38:17 -0700 Subject: [PATCH 08/80] ci: Add 'ci: ' prefix for dependabot updates --- .github/dependabot.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 5ace4600a1..4c39a334be 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,3 +4,5 @@ updates: directory: "/" schedule: interval: "weekly" + commit-message: + prefix: "ci" From ee5c556ae9306b0e59b26e62be8cbe0a0375645d Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 27 Mar 2025 16:28:20 -0700 Subject: [PATCH 09/80] ubuntu-win64-cross: Bump Vulkan headers --- ubuntu-win64-cross/vulkan-headers.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ubuntu-win64-cross/vulkan-headers.mk b/ubuntu-win64-cross/vulkan-headers.mk index 01594d6c3a..3ea0f9d679 100644 --- a/ubuntu-win64-cross/vulkan-headers.mk +++ b/ubuntu-win64-cross/vulkan-headers.mk @@ -2,10 +2,10 @@ PKG := vulkan-headers $(PKG)_WEBSITE := https://github.com/KhronosGroup/Vulkan-Headers $(PKG)_DESCR := Vulkan-Headers $(PKG)_IGNORE := -$(PKG)_VERSION := vulkan-sdk-1.4.304.0 +$(PKG)_VERSION := vulkan-sdk-1.4.309.0 $(PKG)_SUBDIR := Vulkan-Headers-$($(PKG)_VERSION) $(PKG)_FILE := vulkan-headers-$($(PKG)_VERSION).tar.gz -$(PKG)_CHECKSUM := 46f8f5b6384a36c688e0c40d28d534df41d22de406493dfb5c9b7bcc29672613 +$(PKG)_CHECKSUM := 2bc1b4127950badc80212abf1edfa5c3b5032f3425edf37255863ba7592c1969 $(PKG)_URL := https://github.com/KhronosGroup/Vulkan-Headers/archive/refs/tags/$($(PKG)_VERSION).tar.gz $(PKG)_DEPS := cc From 9764c90b21967b8c195ba554a9ea44769768e82a Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 27 Mar 2025 16:31:48 -0700 Subject: [PATCH 10/80] ubuntu-win64-cross: Bump mxe/build-win64-mxe --- ubuntu-win64-cross/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ubuntu-win64-cross/Dockerfile b/ubuntu-win64-cross/Dockerfile index 8741b629de..a3aeb78329 100644 --- a/ubuntu-win64-cross/Dockerfile +++ b/ubuntu-win64-cross/Dockerfile @@ -6,10 +6,10 @@ FROM ubuntu:24.04 ENV MXE_PATH=/opt/mxe ENV MXE_REPO=https://github.com/mxe/mxe.git -ENV MXE_VERSION=866492387740cc6580ef516c8a746402be645453 +ENV MXE_VERSION=db7f5247eaab700f28bb9b9433d279e5958f5f01 ENV MXE_LLVM_MINGW_REPO=https://github.com/libvips/build-win64-mxe -ENV MXE_LLVM_MINGW_VERSION=32a2d0ecdfd3ea16bb4a99e333a8d5a3d63be491 +ENV MXE_LLVM_MINGW_VERSION=51fc5884d0c4a3be43a2f09fa36a464885918d3d ENV MXE_LLVM_MINGW_PATH=/opt/build-win64-mxe ARG PLUGIN_DIRS="${MXE_LLVM_MINGW_PATH} ${MXE_LLVM_MINGW_PATH}/build/plugins/llvm-mingw" From cc857adb6cebc8e4a04ba0fe3ac7b4659b71b4d1 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 27 Mar 2025 16:32:05 -0700 Subject: [PATCH 11/80] meson: Bump SPIRV-Reflect --- subprojects/SPIRV-Reflect.wrap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/SPIRV-Reflect.wrap b/subprojects/SPIRV-Reflect.wrap index dded924d1d..bdc1486c5c 100644 --- a/subprojects/SPIRV-Reflect.wrap +++ b/subprojects/SPIRV-Reflect.wrap @@ -1,4 +1,4 @@ [wrap-git] url=https://github.com/KhronosGroup/SPIRV-Reflect -revision=vulkan-sdk-1.4.304.0 +revision=vulkan-sdk-1.4.309.0 depth=1 From 0d06ce860379dfacfdf796d9e011427ded7e8302 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 27 Mar 2025 16:32:13 -0700 Subject: [PATCH 12/80] meson: Bump glslang --- subprojects/glslang.wrap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/glslang.wrap b/subprojects/glslang.wrap index 29b74d8249..9aa182135a 100644 --- a/subprojects/glslang.wrap +++ b/subprojects/glslang.wrap @@ -1,4 +1,4 @@ [wrap-git] url=https://github.com/KhronosGroup/glslang -revision=vulkan-sdk-1.4.304.0 +revision=vulkan-sdk-1.4.309.0 depth=1 From 68b3683f77a109f7e561c8577dc8421758d8ab2a Mon Sep 17 00:00:00 2001 From: antangelo Date: Thu, 27 Mar 2025 21:35:52 -0400 Subject: [PATCH 13/80] ci: Add clang-format lint check Co-authored-by: Matt Borgerson --- .github/workflows/lint.yml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000000..20757708b5 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,36 @@ +name: Lint + +on: + pull_request: + paths-ignore: + - '.github/**' + - '!.github/workflows/lint.yml' + - 'README.md' + - 'ubuntu-win64-cross/**' + +jobs: + Check: + name: Check formatting and lints + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + steps: + - name: Clone tree + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + with: + fetch-depth: 0 + - name: Check formatting/lints + uses: cpp-linter/cpp-linter-action@832a609fe16e1c98ea764641f07dec5d39db5a56 # v2.13.4 + id: linter + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + version: '16' + style: file + lines-changed-only: true + format-review: true + - name: Report result + if: steps.linter.outputs.checks-failed > 0 + run: exit 1 + From d6a285e173215d4141c238a17ceaa6ed0b28da14 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 27 Mar 2025 19:07:31 -0700 Subject: [PATCH 14/80] ci: Migrate lint to build.yml --- .github/workflows/build.yml | 13 +++++++++++++ .github/workflows/lint.yml | 36 ------------------------------------ 2 files changed, 13 insertions(+), 36 deletions(-) delete mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 71a2d9a500..ec0d7f1c5c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -270,6 +270,19 @@ jobs: with: name: ${{ matrix.artifact_name }} path: ${{ matrix.artifact_filename }} + - name: Lint + if: matrix.configuration == 'Debug' && matrix.arch == 'x86_64' + uses: cpp-linter/cpp-linter-action@8ae6cfaea8cc035c6155b5fe79d7991a9bf638af # v2.14.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + version: '18' # clang-format version + repo-root: ${{ github.workspace }}/src + style: file:${{ github.workspace }}/src/.clang-format + database: ${{ github.workspace }}/src/build/compile_commands.json + lines-changed-only: true + format-review: true + passive-reviews: true macOS: name: Build for macOS (${{ matrix.arch }}, ${{ matrix.configuration }}) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index 20757708b5..0000000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: Lint - -on: - pull_request: - paths-ignore: - - '.github/**' - - '!.github/workflows/lint.yml' - - 'README.md' - - 'ubuntu-win64-cross/**' - -jobs: - Check: - name: Check formatting and lints - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: write - steps: - - name: Clone tree - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - with: - fetch-depth: 0 - - name: Check formatting/lints - uses: cpp-linter/cpp-linter-action@832a609fe16e1c98ea764641f07dec5d39db5a56 # v2.13.4 - id: linter - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - version: '16' - style: file - lines-changed-only: true - format-review: true - - name: Report result - if: steps.linter.outputs.checks-failed > 0 - run: exit 1 - From 0fe76b531f3394ab857ce7d656ca65caba194b49 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 27 Mar 2025 22:01:25 -0700 Subject: [PATCH 15/80] .gitignore: Unignore .clang-format --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index bfac196fad..e1927ae154 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,6 @@ .sdk .stgit-* .git-submodule-status -.clang-format .gdb_history cscope.* tags From a830cc45261a936a6dcd84e4cb408d03337758ac Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 27 Mar 2025 20:27:33 -0700 Subject: [PATCH 16/80] xbox: Disable clang-format for deliberately aligned reg defs --- hw/xbox/mcpx/apu_regs.h | 4 ++++ hw/xbox/nv2a/nv2a_regs.h | 4 ++++ hw/xbox/nvnet_regs.h | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/hw/xbox/mcpx/apu_regs.h b/hw/xbox/mcpx/apu_regs.h index 7488c2e267..2fa71593ae 100644 --- a/hw/xbox/mcpx/apu_regs.h +++ b/hw/xbox/mcpx/apu_regs.h @@ -22,6 +22,8 @@ #ifndef MCPX_APU_REGS_H #define MCPX_APU_REGS_H +// clang-format off + #define NV_PAPU_ISTS 0x00001000 # define NV_PAPU_ISTS_GINTSTS (1 << 0) # define NV_PAPU_ISTS_FETINTSTS (1 << 4) @@ -343,4 +345,6 @@ enum MCPX_HW_NOTIFIER { #define NV1BA0_NOTIFICATION_STATUS_DONE_SUCCESS 0x01 #define NV1BA0_NOTIFICATION_STATUS_IN_PROGRESS 0x80 +// clang-format on + #endif diff --git a/hw/xbox/nv2a/nv2a_regs.h b/hw/xbox/nv2a/nv2a_regs.h index 78a9091eb5..fa657bf271 100644 --- a/hw/xbox/nv2a/nv2a_regs.h +++ b/hw/xbox/nv2a/nv2a_regs.h @@ -32,6 +32,8 @@ (v) |= ((__val) << ctz32(__mask)) & (__mask); \ }) +// clang-format off + #define NV_NUM_BLOCKS 21 #define NV_PMC 0 /* card master control */ #define NV_PBUS 1 /* bus control */ @@ -1463,4 +1465,6 @@ #define NV2A_CUBEMAP_FACE_ALIGNMENT 128 +// clang-format on + #endif diff --git a/hw/xbox/nvnet_regs.h b/hw/xbox/nvnet_regs.h index 992f609937..7a1744f7bc 100644 --- a/hw/xbox/nvnet_regs.h +++ b/hw/xbox/nvnet_regs.h @@ -68,6 +68,8 @@ #ifndef HW_NVNET_REGS_H #define HW_NVNET_REGS_H +// clang-format on + #define DEV_NEED_LASTPACKET1 0x0001 #define DEV_IRQMASK_1 0x0002 #define DEV_IRQMASK_2 0x0004 @@ -291,4 +293,6 @@ enum { #define LPA_LPACK 0x4000 /* Link partner acked us */ #define LPA_NPAGE 0x8000 /* Next page bit */ +// clang-format off + #endif /* HW_NVNET_REGS_H */ From 0e18d11d90d01b78cd6211daffc2abbe264b61b7 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 27 Mar 2025 19:48:08 -0700 Subject: [PATCH 17/80] nv2a: Rename methods.h -> methods.h.inc --- hw/xbox/nv2a/pgraph/{methods.h => methods.h.inc} | 0 hw/xbox/nv2a/pgraph/pgraph.c | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) rename hw/xbox/nv2a/pgraph/{methods.h => methods.h.inc} (100%) diff --git a/hw/xbox/nv2a/pgraph/methods.h b/hw/xbox/nv2a/pgraph/methods.h.inc similarity index 100% rename from hw/xbox/nv2a/pgraph/methods.h rename to hw/xbox/nv2a/pgraph/methods.h.inc diff --git a/hw/xbox/nv2a/pgraph/pgraph.c b/hw/xbox/nv2a/pgraph/pgraph.c index 9db475796e..9d133db139 100644 --- a/hw/xbox/nv2a/pgraph/pgraph.c +++ b/hw/xbox/nv2a/pgraph/pgraph.c @@ -431,7 +431,7 @@ unsigned int nv2a_get_surface_scale_factor(void) #define DEF_METHOD_CASE_4_OFFSET(gclass, name, offset, stride) /* Drop */ #define DEF_METHOD_CASE_4(gclass, name, stride) \ DEF_METHOD_PROTO(gclass, name); -#include "methods.h" +#include "methods.h.inc" #undef DEF_METHOD #undef DEF_METHOD_RANGE #undef DEF_METHOD_CASE_4_OFFSET @@ -485,7 +485,7 @@ static const struct { }, #define DEF_METHOD_CASE_4(gclass, name, stride) \ DEF_METHOD_CASE_4_OFFSET(gclass, name, 0, stride) -#include "methods.h" +#include "methods.h.inc" #undef DEF_METHOD #undef DEF_METHOD_RANGE #undef DEF_METHOD_CASE_4_OFFSET @@ -504,7 +504,7 @@ static const struct { #define DEF_METHOD_CASE_4(gclass, name, stride) \ static const size_t METHOD_RANGE_END_NAME(gclass, name) = \ METHOD_ADDR(gclass, name) + 4*stride; -#include "methods.h" +#include "methods.h.inc" #undef DEF_METHOD #undef DEF_METHOD_RANGE #undef DEF_METHOD_CASE_4_OFFSET From 2d73e8aafe838782649d7f59d6107b9087a6fa78 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 27 Mar 2025 20:33:33 -0700 Subject: [PATCH 18/80] nv2a: Use root-relative paths to reference parent dir headers --- hw/xbox/nv2a/pgraph/pgraph.c | 2 +- hw/xbox/nv2a/pgraph/profile.c | 2 +- hw/xbox/nv2a/pgraph/rdi.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/xbox/nv2a/pgraph/pgraph.c b/hw/xbox/nv2a/pgraph/pgraph.c index 9d133db139..5b0bc982d1 100644 --- a/hw/xbox/nv2a/pgraph/pgraph.c +++ b/hw/xbox/nv2a/pgraph/pgraph.c @@ -19,7 +19,7 @@ * License along with this library; if not, see . */ -#include "../nv2a_int.h" +#include "hw/xbox/nv2a/nv2a_int.h" #include "ui/xemu-notifications.h" #include "ui/xemu-settings.h" #include "util.h" diff --git a/hw/xbox/nv2a/pgraph/profile.c b/hw/xbox/nv2a/pgraph/profile.c index 69a1b5bfbd..295042010d 100644 --- a/hw/xbox/nv2a/pgraph/profile.c +++ b/hw/xbox/nv2a/pgraph/profile.c @@ -17,7 +17,7 @@ * License along with this library; if not, see . */ -#include "../nv2a_int.h" +#include "hw/xbox/nv2a/nv2a_int.h" NV2AStats g_nv2a_stats; diff --git a/hw/xbox/nv2a/pgraph/rdi.c b/hw/xbox/nv2a/pgraph/rdi.c index 297c7a67c0..f540b240c6 100644 --- a/hw/xbox/nv2a/pgraph/rdi.c +++ b/hw/xbox/nv2a/pgraph/rdi.c @@ -19,7 +19,7 @@ * License along with this library; if not, see . */ -#include "../nv2a_int.h" +#include "hw/xbox/nv2a/nv2a_int.h" uint32_t pgraph_rdi_read(PGRAPHState *pg, unsigned int select, unsigned int address) From 312bd9457301a12204ce341649bec44bf74dc140 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 27 Mar 2025 22:47:27 -0700 Subject: [PATCH 19/80] mcpx: Move voice_list_regs to apu.c --- hw/xbox/mcpx/apu.c | 8 ++++++++ hw/xbox/mcpx/apu_regs.h | 9 --------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/hw/xbox/mcpx/apu.c b/hw/xbox/mcpx/apu.c index ecace96ce3..d5eec18f40 100644 --- a/hw/xbox/mcpx/apu.c +++ b/hw/xbox/mcpx/apu.c @@ -154,6 +154,14 @@ typedef struct MCPXAPUState { int16_t apu_fifo_output[256][2]; // 1 EP frame (0x400 bytes), 8 buffered } MCPXAPUState; +static const struct { + hwaddr top, current, next; +} voice_list_regs[] = { + { NV_PAPU_TVL2D, NV_PAPU_CVL2D, NV_PAPU_NVL2D }, // 2D + { NV_PAPU_TVL3D, NV_PAPU_CVL3D, NV_PAPU_NVL3D }, // 3D + { NV_PAPU_TVLMP, NV_PAPU_CVLMP, NV_PAPU_NVLMP }, // MP +}; + static MCPXAPUState *g_state; // Used via debug handlers static struct McpxApuDebug g_dbg, g_dbg_cache; static int g_dbg_voice_monitor = -1; diff --git a/hw/xbox/mcpx/apu_regs.h b/hw/xbox/mcpx/apu_regs.h index 2fa71593ae..d745a69354 100644 --- a/hw/xbox/mcpx/apu_regs.h +++ b/hw/xbox/mcpx/apu_regs.h @@ -124,15 +124,6 @@ #define NV_PAPU_EPPMEM 0x0000A000 #define NV_PAPU_EPRST 0x0000FFFC -static const struct { - hwaddr top, current, next; -} voice_list_regs[] = { - {NV_PAPU_TVL2D, NV_PAPU_CVL2D, NV_PAPU_NVL2D}, //2D - {NV_PAPU_TVL3D, NV_PAPU_CVL3D, NV_PAPU_NVL3D}, //3D - {NV_PAPU_TVLMP, NV_PAPU_CVLMP, NV_PAPU_NVLMP}, //MP -}; - - /* audio processor object / front-end messages */ #define NV1BA0_PIO_FREE 0x00000010 #define NV1BA0_PIO_SET_ANTECEDENT_VOICE 0x00000120 From 1586b40b11c8bf5ee561d8fc4dba20f49112b0c4 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Thu, 27 Mar 2025 23:35:21 -0700 Subject: [PATCH 20/80] ci: Bump Windows build container --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ec0d7f1c5c..bbe0335c33 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -79,7 +79,7 @@ jobs: artifact_name: xemu-win-aarch64-release arch: aarch64 env: - DOCKER_IMAGE_NAME: ghcr.io/xemu-project/xemu-win64-toolchain:sha-3bdb9e7 + DOCKER_IMAGE_NAME: ghcr.io/xemu-project/xemu-win64-toolchain:sha-0d06ce8 steps: - name: Download source package From 48d1195c27e09f83f5fb7098ef9dfdb3369f8dac Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Fri, 28 Mar 2025 02:15:00 -0700 Subject: [PATCH 21/80] ci: Drop lint action for now --- .github/workflows/build.yml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bbe0335c33..576d3adf89 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -270,19 +270,6 @@ jobs: with: name: ${{ matrix.artifact_name }} path: ${{ matrix.artifact_filename }} - - name: Lint - if: matrix.configuration == 'Debug' && matrix.arch == 'x86_64' - uses: cpp-linter/cpp-linter-action@8ae6cfaea8cc035c6155b5fe79d7991a9bf638af # v2.14.0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - version: '18' # clang-format version - repo-root: ${{ github.workspace }}/src - style: file:${{ github.workspace }}/src/.clang-format - database: ${{ github.workspace }}/src/build/compile_commands.json - lines-changed-only: true - format-review: true - passive-reviews: true macOS: name: Build for macOS (${{ matrix.arch }}, ${{ matrix.configuration }}) From 672e9cd553df9fa4629ecdc49efacf310d9994b0 Mon Sep 17 00:00:00 2001 From: Erik Abair Date: Mon, 10 Mar 2025 19:15:03 -0700 Subject: [PATCH 22/80] nv2a: Handle SET_SPECULAR_ENABLE --- hw/xbox/nv2a/nv2a_regs.h | 2 ++ hw/xbox/nv2a/pgraph/glsl/vsh-ff.c | 5 +++++ hw/xbox/nv2a/pgraph/glsl/vsh.c | 15 ++++++++++++--- hw/xbox/nv2a/pgraph/methods.h.inc | 1 + hw/xbox/nv2a/pgraph/pgraph.c | 6 +++++- hw/xbox/nv2a/pgraph/shaders.c | 2 ++ hw/xbox/nv2a/pgraph/shaders.h | 1 + 7 files changed, 28 insertions(+), 4 deletions(-) diff --git a/hw/xbox/nv2a/nv2a_regs.h b/hw/xbox/nv2a/nv2a_regs.h index fa657bf271..fa62536181 100644 --- a/hw/xbox/nv2a/nv2a_regs.h +++ b/hw/xbox/nv2a/nv2a_regs.h @@ -314,6 +314,7 @@ # define NV_PGRAPH_CSV0_D_SKIN_4 6 #define NV_PGRAPH_CSV0_C 0x00000FB8 # define NV_PGRAPH_CSV0_C_CHEOPS_PROGRAM_START 0x0000FF00 +# define NV_PGRAPH_CSV0_C_SPECULAR_ENABLE (1 << 16) # define NV_PGRAPH_CSV0_C_SPECULAR (3 << 19) # define NV_PGRAPH_CSV0_C_DIFFUSE (3 << 21) # define NV_PGRAPH_CSV0_C_AMBIENT (3 << 23) @@ -1015,6 +1016,7 @@ # define NV097_SET_NORMALIZATION_ENABLE 0x000003A4 # define NV097_SET_MATERIAL_EMISSION 0x000003A8 # define NV097_SET_MATERIAL_ALPHA 0x000003B4 +# define NV097_SET_SPECULAR_ENABLE 0x000003B8 # define NV097_SET_LIGHT_ENABLE_MASK 0x000003BC # define NV097_SET_LIGHT_ENABLE_MASK_LIGHT0_OFF 0 # define NV097_SET_LIGHT_ENABLE_MASK_LIGHT0_INFINITE 1 diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c index 2412826647..445ce73066 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c @@ -383,6 +383,11 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz mstring_append(body, " oD0 = diffuse;\n"); mstring_append(body, " oD1 = specular;\n"); } + + if (!state->specular_enable) { + mstring_append(body, " oD1 = vec4(0.0, 0.0, 0.0, 1.0);\n"); + } + mstring_append(body, " oB0 = backDiffuse;\n"); mstring_append(body, " oB1 = backSpecular;\n"); diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh.c b/hw/xbox/nv2a/pgraph/glsl/vsh.c index d92c8b2fb3..5fff5cf410 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh.c @@ -34,7 +34,6 @@ MString *pgraph_gen_vsh_glsl(const ShaderState *state, bool prefix_outputs) mstring_append_fmt(output, "#version %d\n\n", state->vulkan ? 450 : 400); MString *header = mstring_from_str(""); - MString *uniforms = mstring_from_str(""); const char *u = state->vulkan ? "" : "uniform "; // FIXME: Remove @@ -243,9 +242,7 @@ MString *pgraph_gen_vsh_glsl(const ShaderState *state, bool prefix_outputs) /* Set outputs */ mstring_append(body, "\n" " vtxD0 = clamp(oD0, 0.0, 1.0);\n" - " vtxD1 = clamp(oD1, 0.0, 1.0);\n" " vtxB0 = clamp(oB0, 0.0, 1.0);\n" - " vtxB1 = clamp(oB1, 0.0, 1.0);\n" " vtxFog = oFog.x;\n" " vtxT0 = oT0;\n" " vtxT1 = oT1;\n" @@ -254,6 +251,18 @@ MString *pgraph_gen_vsh_glsl(const ShaderState *state, bool prefix_outputs) " gl_PointSize = oPts.x;\n" ); + if (state->specular_enable) { + mstring_append(body, + " vtxD1 = clamp(oD1, 0.0, 1.0);\n" + " vtxB1 = clamp(oB1, 0.0, 1.0);\n" + ); + } else { + mstring_append(body, + " vtxD1 = vec4(0.0, 0.0, 0.0, 1.0);\n" + " vtxB1 = vec4(0.0, 0.0, 0.0, 1.0);\n" + ); + } + if (state->vulkan) { mstring_append(body, " gl_Position = oPos;\n" diff --git a/hw/xbox/nv2a/pgraph/methods.h.inc b/hw/xbox/nv2a/pgraph/methods.h.inc index 380df07ea5..fd6184426e 100644 --- a/hw/xbox/nv2a/pgraph/methods.h.inc +++ b/hw/xbox/nv2a/pgraph/methods.h.inc @@ -78,6 +78,7 @@ DEF_METHOD(NV097, SET_FRONT_FACE) DEF_METHOD(NV097, SET_NORMALIZATION_ENABLE) DEF_METHOD_RANGE(NV097, SET_MATERIAL_EMISSION, 3) DEF_METHOD(NV097, SET_MATERIAL_ALPHA) +DEF_METHOD(NV097, SET_SPECULAR_ENABLE) DEF_METHOD(NV097, SET_LIGHT_ENABLE_MASK) DEF_METHOD_CASE_4(NV097, SET_TEXGEN_S, 16) DEF_METHOD_CASE_4(NV097, SET_TEXGEN_T, 16) diff --git a/hw/xbox/nv2a/pgraph/pgraph.c b/hw/xbox/nv2a/pgraph/pgraph.c index 5b0bc982d1..0f17fde184 100644 --- a/hw/xbox/nv2a/pgraph/pgraph.c +++ b/hw/xbox/nv2a/pgraph/pgraph.c @@ -1619,6 +1619,11 @@ DEF_METHOD(NV097, SET_MATERIAL_ALPHA) pg->material_alpha = *(float*)¶meter; } +DEF_METHOD(NV097, SET_SPECULAR_ENABLE) +{ + PG_SET_MASK(NV_PGRAPH_CSV0_C, NV_PGRAPH_CSV0_C_SPECULAR_ENABLE, parameter); +} + DEF_METHOD(NV097, SET_LIGHT_ENABLE_MASK) { PG_SET_MASK(NV_PGRAPH_CSV0_D, NV_PGRAPH_CSV0_D_LIGHTS, parameter); @@ -3022,4 +3027,3 @@ void pgraph_pre_shutdown_wait(NV2AState *d) PGRAPHState *pg = &d->pgraph; pg->renderer->ops.pre_shutdown_wait(d); } - diff --git a/hw/xbox/nv2a/pgraph/shaders.c b/hw/xbox/nv2a/pgraph/shaders.c index 6e13f2084c..dce6d05bb3 100644 --- a/hw/xbox/nv2a/pgraph/shaders.c +++ b/hw/xbox/nv2a/pgraph/shaders.c @@ -69,6 +69,8 @@ ShaderState pgraph_get_shader_state(PGRAPHState *pg) pgraph_reg_r(pg, NV_PGRAPH_SHADOWCTL), NV_PGRAPH_SHADOWCTL_SHADOW_ZFUNC); state.fixed_function = fixed_function; + state.specular_enable = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), + NV_PGRAPH_CSV0_C_SPECULAR_ENABLE); /* fixed function stuff */ if (fixed_function) { diff --git a/hw/xbox/nv2a/pgraph/shaders.h b/hw/xbox/nv2a/pgraph/shaders.h index 71febe2e2f..7ff93a6302 100644 --- a/hw/xbox/nv2a/pgraph/shaders.h +++ b/hw/xbox/nv2a/pgraph/shaders.h @@ -83,6 +83,7 @@ typedef struct ShaderState { enum VshLight light[NV2A_MAX_LIGHTS]; bool fixed_function; + bool specular_enable; /* vertex program */ bool vertex_program; From bf51af891d5976b4ad3814d9f54d2733cbe9d121 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Mon, 17 Feb 2025 01:49:28 -0700 Subject: [PATCH 23/80] mcpx/dsp: Move to a library --- hw/xbox/mcpx/dsp/meson.build | 2 ++ hw/xbox/mcpx/meson.build | 7 +++---- 2 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 hw/xbox/mcpx/dsp/meson.build diff --git a/hw/xbox/mcpx/dsp/meson.build b/hw/xbox/mcpx/dsp/meson.build new file mode 100644 index 0000000000..b94537f97c --- /dev/null +++ b/hw/xbox/mcpx/dsp/meson.build @@ -0,0 +1,2 @@ +libdsp = static_library('dsp', files(['dsp.c', 'dsp_cpu.c', 'dsp_dma.c']) + genh) +dsp = declare_dependency(objects: libdsp.extract_all_objects(recursive: false)) diff --git a/hw/xbox/mcpx/meson.build b/hw/xbox/mcpx/meson.build index fd87ef118e..5f6807337d 100644 --- a/hw/xbox/mcpx/meson.build +++ b/hw/xbox/mcpx/meson.build @@ -1,10 +1,9 @@ +subdir('dsp') + mcpx_ss = ss.source_set() -mcpx_ss.add(sdl, libsamplerate, files( +mcpx_ss.add(sdl, libsamplerate, dsp, files( 'apu.c', 'aci.c', - 'dsp/dsp.c', - 'dsp/dsp_cpu.c', - 'dsp/dsp_dma.c', )) specific_ss.add_all(mcpx_ss) \ No newline at end of file From d6a4b4e36a95333d83e0aefcdb0336a3cfa5ab1f Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Mon, 17 Feb 2025 01:49:28 -0700 Subject: [PATCH 24/80] tests/mcpx/dsp: Add basic test --- tests/meson.build | 1 + tests/xbox/dsp/data/Makefile | 4 ++ tests/xbox/dsp/data/basic | 12 +++++ tests/xbox/dsp/data/basic.a56 | 12 +++++ tests/xbox/dsp/meson.build | 13 ++++++ tests/xbox/dsp/test-dsp.c | 84 +++++++++++++++++++++++++++++++++++ tests/xbox/meson.build | 1 + 7 files changed, 127 insertions(+) create mode 100644 tests/xbox/dsp/data/Makefile create mode 100644 tests/xbox/dsp/data/basic create mode 100644 tests/xbox/dsp/data/basic.a56 create mode 100644 tests/xbox/dsp/meson.build create mode 100644 tests/xbox/dsp/test-dsp.c create mode 100644 tests/xbox/meson.build diff --git a/tests/meson.build b/tests/meson.build index 907a4c1c98..febbe02806 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -86,3 +86,4 @@ subdir('qapi-schema') subdir('qtest') subdir('migration') subdir('functional') +subdir('xbox') diff --git a/tests/xbox/dsp/data/Makefile b/tests/xbox/dsp/data/Makefile new file mode 100644 index 0000000000..8bd271a422 --- /dev/null +++ b/tests/xbox/dsp/data/Makefile @@ -0,0 +1,4 @@ +all: basic + +%: %.a56 + a56 -o $@ $< diff --git a/tests/xbox/dsp/data/basic b/tests/xbox/dsp/data/basic new file mode 100644 index 0000000000..7b11e507ea --- /dev/null +++ b/tests/xbox/dsp/data/basic @@ -0,0 +1,12 @@ +P 0000 0C0040 +P 0040 0AF080 +P 0041 000042 +P 0042 56F400 +P 0043 123456 +P 0044 567000 +P 0045 000003 +P 0046 08F484 +P 0047 000001 +P 0048 0C0042 +I 000040 start +I 000042 mainloop diff --git a/tests/xbox/dsp/data/basic.a56 b/tests/xbox/dsp/data/basic.a56 new file mode 100644 index 0000000000..0be7483dba --- /dev/null +++ b/tests/xbox/dsp/data/basic.a56 @@ -0,0 +1,12 @@ + org p:$0000 + jmp . + */ + +#include "qemu/osdep.h" +#include "hw/xbox/mcpx/dsp/dsp.h" + +static void scratch_rw(void *opaque, uint8_t *ptr, uint32_t addr, size_t len, bool dir) +{ + assert(!"Not implemented"); +} + +static void fifo_rw(void *opaque, uint8_t *ptr, unsigned int index, size_t len, bool dir) +{ + assert(!"Not implemented"); +} + +static void load_prog(DSPState *s, const char *path) +{ + FILE *file = fopen(path, "r"); + assert(file && "Error opening file"); + + char type, line[100], arg1[20], arg2[20]; + int addr, value; + + while (fgets(line, sizeof(line), file)) { + if (sscanf(line, "%c %s %s", &type, arg1, arg2) >= 2) { + switch (type) { + case 'P': + case 'X': + case 'Y': { + assert(sscanf(arg1, "%x", &addr) == 1); + assert(sscanf(arg2, "%x", &value) == 1); + dsp_write_memory(s, type, addr, value); + break; + } + } + } else { + printf("Invalid line: %s\n", line); + assert(0); + } + } + + fclose(file); +} + +static void test_dsp_basic(void) +{ + g_autofree gchar *path = g_test_build_filename(G_TEST_DIST, "data", "basic", NULL); + + DSPState *s = dsp_init(NULL, scratch_rw, fifo_rw); + + load_prog(s, path); + dsp_run(s, 1000); + + uint32_t v = dsp_read_memory(s, 'X', 3); + g_assert_cmphex(v, ==, 0x123456); + + dsp_destroy(s); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + g_test_add_func("/basic", test_dsp_basic); + + return g_test_run(); +} diff --git a/tests/xbox/meson.build b/tests/xbox/meson.build new file mode 100644 index 0000000000..e836218210 --- /dev/null +++ b/tests/xbox/meson.build @@ -0,0 +1 @@ +subdir('dsp') From 9af3c1a0057cfc0507374a3434ae8cf6e5373d9d Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Mon, 17 Feb 2025 01:49:28 -0700 Subject: [PATCH 25/80] mcpx/dsp: Add missing copyright --- hw/xbox/mcpx/dsp/dsp.c | 1 + hw/xbox/mcpx/dsp/dsp_cpu.c | 1 + 2 files changed, 2 insertions(+) diff --git a/hw/xbox/mcpx/dsp/dsp.c b/hw/xbox/mcpx/dsp/dsp.c index d1e3b2a9b3..a86d9f314b 100644 --- a/hw/xbox/mcpx/dsp/dsp.c +++ b/hw/xbox/mcpx/dsp/dsp.c @@ -2,6 +2,7 @@ * MCPX DSP emulator * * Copyright (c) 2015 espes + * Copyright (c) 2020-2025 Matt Borgerson * * Adapted from Hatari DSP M56001 emulation * (C) 2001-2008 ARAnyM developer team diff --git a/hw/xbox/mcpx/dsp/dsp_cpu.c b/hw/xbox/mcpx/dsp/dsp_cpu.c index 874dd494ce..b31172fd60 100644 --- a/hw/xbox/mcpx/dsp/dsp_cpu.c +++ b/hw/xbox/mcpx/dsp/dsp_cpu.c @@ -2,6 +2,7 @@ * DSP56300 emulator * * Copyright (c) 2015 espes + * Copyright (c) 2020-2025 Matt Borgerson * * Adapted from Hatari DSP M56001 emulation * (C) 2003-2008 ARAnyM developer team From 89f98947f62cdc476cf1a48197013959e316f090 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Mon, 17 Feb 2025 01:49:28 -0700 Subject: [PATCH 26/80] mcpx/dsp: Fix dprintf use --- hw/xbox/mcpx/dsp/dsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/xbox/mcpx/dsp/dsp.c b/hw/xbox/mcpx/dsp/dsp.c index a86d9f314b..09d39e2a14 100644 --- a/hw/xbox/mcpx/dsp/dsp.c +++ b/hw/xbox/mcpx/dsp/dsp.c @@ -202,7 +202,7 @@ void dsp_bootstrap(DSPState* dsp) (uint8_t*)dsp->core.pram, 0, 0x800*4, false); for (int i = 0; i < 0x800; i++) { if (dsp->core.pram[i] & 0xff000000) { - DPRINTF(stderr, "Bootstrap %04x: %08x\n", i, dsp->core.pram[i]); + DPRINTF("Bootstrap %04x: %08x\n", i, dsp->core.pram[i]); dsp->core.pram[i] &= 0x00ffffff; } } From 115456f2557d964213e3953e8d3b5d378b4bc37e Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Mon, 17 Feb 2025 01:49:28 -0700 Subject: [PATCH 27/80] mcpx/dsp: Bring back disassembly --- hw/xbox/mcpx/dsp/dsp_cpu.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/hw/xbox/mcpx/dsp/dsp_cpu.c b/hw/xbox/mcpx/dsp/dsp_cpu.c index b31172fd60..89a3555899 100644 --- a/hw/xbox/mcpx/dsp/dsp_cpu.c +++ b/hw/xbox/mcpx/dsp/dsp_cpu.c @@ -595,25 +595,16 @@ static void disasm_reg_compare(dsp_core_t* dsp) static const char* disasm_get_instruction_text(dsp_core_t* dsp) { - // const int len = sizeof(dsp->disasm_str_instr); - // uint64_t count, cycles; - // uint16_t cycle_diff; - // float percentage; - // int offset; + const int len = sizeof(dsp->disasm_str_instr); if (dsp->disasm_is_looping) { dsp->disasm_str_instr2[0] = 0; } - // if (dsp->disasm_cur_inst_len == 1) { - // offset = sprintf(dsp->disasm_str_instr2, "p:%04x %06x (%02d cyc) %-*s\n", dsp->disasm_prev_inst_pc, dsp->disasm_cur_inst, dsp->instr_cycle, len, dsp->disasm_str_instr); - // } else { - // offset = sprintf(dsp->disasm_str_instr2, "p:%04x %06x %06x (%02d cyc) %-*s\n", dsp->disasm_prev_inst_pc, dsp->disasm_cur_inst, read_memory_p(dsp, dsp->disasm_prev_inst_pc + 1), dsp->instr_cycle, len, dsp->disasm_str_instr); - // } - // if (offset > 2 && Profile_DspAddressData(dsp->disasm_prev_inst_pc, &percentage, &count, &cycles, &cycle_diff)) { - // offset -= 2; - // sprintf(str_instr2+offset, "%5.2f%% (%"PRId64", %"PRId64", %d)\n", - // percentage, count, cycles, cycle_diff); - // } + if (dsp->disasm_cur_inst_len == 1) { + snprintf(dsp->disasm_str_instr2, sizeof(dsp->disasm_str_instr2), "p:%04x %06x (%02d cyc) %-*s\n", dsp->disasm_prev_inst_pc, dsp->disasm_cur_inst, dsp->instr_cycle, len, dsp->disasm_str_instr); + } else { + snprintf(dsp->disasm_str_instr2, sizeof(dsp->disasm_str_instr2), "p:%04x %06x %06x (%02d cyc) %-*s\n", dsp->disasm_prev_inst_pc, dsp->disasm_cur_inst, read_memory_p(dsp, dsp->disasm_prev_inst_pc + 1), dsp->instr_cycle, len, dsp->disasm_str_instr); + } return dsp->disasm_str_instr2; } From 148f04e1c789dfc19695faa04ef93b03a3cf6b70 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Mon, 17 Feb 2025 01:49:29 -0700 Subject: [PATCH 28/80] mcpx/dsp: Replace printf -> DPRINTF --- hw/xbox/mcpx/dsp/dsp.c | 6 ++++-- hw/xbox/mcpx/dsp/dsp_cpu.c | 43 ++++++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/hw/xbox/mcpx/dsp/dsp.c b/hw/xbox/mcpx/dsp/dsp.c index 09d39e2a14..d304c0ebe0 100644 --- a/hw/xbox/mcpx/dsp/dsp.c +++ b/hw/xbox/mcpx/dsp/dsp.c @@ -43,9 +43,11 @@ #define INTERRUPT_START_FRAME (1 << 1) #define INTERRUPT_DMA_EOL (1 << 7) -// #define DEBUG_DSP +#ifndef DEBUG_DSP +#define DEBUG_DSP 0 +#endif -#ifdef DEBUG_DSP +#if DEBUG_DSP #define DPRINTF(fmt, ...) \ do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) #else diff --git a/hw/xbox/mcpx/dsp/dsp_cpu.c b/hw/xbox/mcpx/dsp/dsp_cpu.c index 89a3555899..d40d2eafe4 100644 --- a/hw/xbox/mcpx/dsp/dsp_cpu.c +++ b/hw/xbox/mcpx/dsp/dsp_cpu.c @@ -33,11 +33,18 @@ #include "dsp_cpu.h" +#ifndef DEBUG_DSP +#define DEBUG_DSP 0 +#endif + #define TRACE_DSP_DISASM 0 #define TRACE_DSP_DISASM_REG 0 #define TRACE_DSP_DISASM_MEM 0 -#define DPRINTF(s, ...) printf(s, ## __VA_ARGS__) +#define DPRINTF(fmt, ...) \ + do { \ + if (DEBUG_DSP) fprintf(stderr, fmt, ## __VA_ARGS__); \ + } while (0) #define BITMASK(x) ((1<<(x))-1) @@ -463,7 +470,7 @@ static uint16_t disasm_instruction(dsp_core_t* dsp, dsp_trace_disasm_t mode) if (mode == DSP_TRACE_MODE) { if (dsp->disasm_prev_inst_pc == dsp->pc) { if (!dsp->disasm_is_looping) { - printf( "Looping on DSP instruction at PC = $%04x\n", dsp->disasm_prev_inst_pc); + DPRINTF("Looping on DSP instruction at PC = $%04x\n", dsp->disasm_prev_inst_pc); dsp->disasm_is_looping = true; } return 0; @@ -521,7 +528,7 @@ static void disasm_reg_compare(dsp_core_t* dsp) case DSP_REG_X1: case DSP_REG_Y0: case DSP_REG_Y1: - printf("\tReg: %s $%06x -> $%06x\n", + DPRINTF("\tReg: %s $%06x -> $%06x\n", registers_name[i], dsp->disasm_registers_save[i], dsp->registers[i]); break; case DSP_REG_R0: @@ -551,21 +558,21 @@ static void disasm_reg_compare(dsp_core_t* dsp) case DSP_REG_SR: case DSP_REG_LA: case DSP_REG_LC: - printf("\tReg: %s $%04x -> $%04x\n", + DPRINTF("\tReg: %s $%04x -> $%04x\n", registers_name[i], dsp->disasm_registers_save[i], dsp->registers[i]); break; case DSP_REG_OMR: case DSP_REG_SP: case DSP_REG_SSH: case DSP_REG_SSL: - printf("\tReg: %s $%02x -> $%02x\n", + DPRINTF("\tReg: %s $%02x -> $%02x\n", registers_name[i], dsp->disasm_registers_save[i], dsp->registers[i]); break; case DSP_REG_A0: case DSP_REG_A1: case DSP_REG_A2: if (bRegA == false) { - printf("\tReg: a $%02x:%06x:%06x -> $%02x:%06x:%06x\n", + DPRINTF("\tReg: a $%02x:%06x:%06x -> $%02x:%06x:%06x\n", dsp->disasm_registers_save[DSP_REG_A2], dsp->disasm_registers_save[DSP_REG_A1], dsp->disasm_registers_save[DSP_REG_A0], dsp->registers[DSP_REG_A2], dsp->registers[DSP_REG_A1], dsp->registers[DSP_REG_A0] ); @@ -576,7 +583,7 @@ static void disasm_reg_compare(dsp_core_t* dsp) case DSP_REG_B1: case DSP_REG_B2: if (bRegB == false) { - printf("\tReg: b $%02x:%06x:%06x -> $%02x:%06x:%06x\n", + DPRINTF("\tReg: b $%02x:%06x:%06x -> $%02x:%06x:%06x\n", dsp->disasm_registers_save[DSP_REG_B2], dsp->disasm_registers_save[DSP_REG_B1], dsp->disasm_registers_save[DSP_REG_B0], dsp->registers[DSP_REG_B2], dsp->registers[DSP_REG_B1], dsp->registers[DSP_REG_B0] ); @@ -588,7 +595,7 @@ static void disasm_reg_compare(dsp_core_t* dsp) #ifdef DSP_DISASM_REG_PC if (pc_save != dsp->pc) { - printf("\tReg: pc $%04x -> $%04x\n", pc_save, dsp->pc); + DPRINTF("\tReg: pc $%04x -> $%04x\n", pc_save, dsp->pc); } #endif } @@ -660,7 +667,7 @@ void dsp56k_execute_instruction(dsp_core_t* dsp) disasm_return = disasm_instruction(dsp, DSP_TRACE_MODE); if (disasm_return) { - printf( "%s", disasm_get_instruction_text(dsp)); + DPRINTF("%s", disasm_get_instruction_text(dsp)); } if (disasm_return != 0 && TRACE_DSP_DISASM_REG) { /* DSP regs trace enabled only if DSP DISASM is enabled */ @@ -678,7 +685,7 @@ void dsp56k_execute_instruction(dsp_core_t* dsp) if (op->emu_func) { op->emu_func(dsp); } else { - printf("%x - %s\n", dsp->cur_inst, op->name); + DPRINTF("%x - %s\n", dsp->cur_inst, op->name); emu_undefined(dsp); } } else { @@ -691,7 +698,7 @@ void dsp56k_execute_instruction(dsp_core_t* dsp) /* Display only when DSP is called in trace mode */ if (!dsp->executing_for_disasm) { if (disasm_return != 0) { - // printf( "%s", disasm_get_instruction_text(dsp)); + // DPRINTF("%s", disasm_get_instruction_text(dsp)); /* DSP regs trace enabled only if DSP DISASM is enabled */ if (TRACE_DSP_DISASM_REG) @@ -700,11 +707,11 @@ void dsp56k_execute_instruction(dsp_core_t* dsp) if (TRACE_DSP_DISASM_MEM) { /* 1 memory change to display ? */ if (dsp->disasm_memory_ptr == 1) - printf( "\t%s\n", dsp->str_disasm_memory[0]); + DPRINTF("\t%s\n", dsp->str_disasm_memory[0]); /* 2 memory changes to display ? */ else if (dsp->disasm_memory_ptr == 2) { - printf( "\t%s\n", dsp->str_disasm_memory[0]); - printf( "\t%s\n", dsp->str_disasm_memory[1]); + DPRINTF("\t%s\n", dsp->str_disasm_memory[0]); + DPRINTF("\t%s\n", dsp->str_disasm_memory[1]); } } } @@ -726,7 +733,7 @@ void dsp56k_execute_instruction(dsp_core_t* dsp) /* Evaluate time after instructions have been executed to avoid asking too frequently */ uint32_t cur_time = SDL_GetTicks(); if (cur_time-start_time>1000) { - printf( "Dsp: %d i/s\n", (dsp->num_inst*1000)/(cur_time-start_time)); + DPRINTF("Dsp: %d i/s\n", (dsp->num_inst*1000)/(cur_time-start_time)); start_time=cur_time; dsp->num_inst=0; } @@ -1115,7 +1122,7 @@ static void dsp_write_reg(dsp_core_t* dsp, uint32_t numreg, uint32_t value) dsp56k_add_interrupt(dsp, DSP_INTER_STACK_ERROR); dsp->registers[DSP_REG_SP] = value & (3<executing_for_disasm) { - printf( "Dsp: Stack Overflow or Underflow\n"); + DPRINTF("Dsp: Stack Overflow or Underflow\n"); } if (dsp->exception_debugging) { assert(false); @@ -1160,7 +1167,7 @@ static void dsp_stack_push(dsp_core_t* dsp, uint32_t curpc, uint32_t cursr, uint /* Stack full, raise interrupt */ dsp56k_add_interrupt(dsp, DSP_INTER_STACK_ERROR); if (!dsp->executing_for_disasm) - printf("Dsp: Stack Overflow\n"); + DPRINTF("Dsp: Stack Overflow\n"); if (dsp->exception_debugging) assert(false); } @@ -1197,7 +1204,7 @@ static void dsp_stack_pop(dsp_core_t* dsp, uint32_t *newpc, uint32_t *newsr) /* Stack empty*/ dsp56k_add_interrupt(dsp, DSP_INTER_STACK_ERROR); if (!dsp->executing_for_disasm) - printf("Dsp: Stack underflow\n"); + DPRINTF("Dsp: Stack underflow\n"); if (dsp->exception_debugging) assert(false); } From 5ba2ef790c5f5e7803d1738f681d886229b13e29 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Mon, 17 Feb 2025 01:49:29 -0700 Subject: [PATCH 29/80] mcpx/dsp: Factor out debug bits to a header --- hw/xbox/mcpx/dsp/debug.h | 37 +++++++++++++++++++++++++++++++++++++ hw/xbox/mcpx/dsp/dsp.c | 13 +------------ hw/xbox/mcpx/dsp/dsp_cpu.c | 14 +------------- 3 files changed, 39 insertions(+), 25 deletions(-) create mode 100644 hw/xbox/mcpx/dsp/debug.h diff --git a/hw/xbox/mcpx/dsp/debug.h b/hw/xbox/mcpx/dsp/debug.h new file mode 100644 index 0000000000..befef229b1 --- /dev/null +++ b/hw/xbox/mcpx/dsp/debug.h @@ -0,0 +1,37 @@ +/* + * MCPX DSP emulator + + * Copyright (c) 2025 Matt Borgerson + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef HW_XBOX_MCPX_DSP_DEBUG_H +#define HW_XBOX_MCPX_DSP_DEBUG_H + +#ifndef DEBUG_DSP +#define DEBUG_DSP 0 +#endif + +#define TRACE_DSP_DISASM 0 +#define TRACE_DSP_DISASM_REG 0 +#define TRACE_DSP_DISASM_MEM 0 + +#define DPRINTF(fmt, ...) \ + do { \ + if (DEBUG_DSP) fprintf(stderr, fmt, ## __VA_ARGS__); \ + } while (0) + +#endif diff --git a/hw/xbox/mcpx/dsp/dsp.c b/hw/xbox/mcpx/dsp/dsp.c index d304c0ebe0..29d8d67ea3 100644 --- a/hw/xbox/mcpx/dsp/dsp.c +++ b/hw/xbox/mcpx/dsp/dsp.c @@ -35,6 +35,7 @@ #include "dsp_state.h" #include "dsp.h" +#include "debug.h" /* Defines */ #define BITMASK(x) ((1<<(x))-1) @@ -43,18 +44,6 @@ #define INTERRUPT_START_FRAME (1 << 1) #define INTERRUPT_DMA_EOL (1 << 7) -#ifndef DEBUG_DSP -#define DEBUG_DSP 0 -#endif - -#if DEBUG_DSP -#define DPRINTF(fmt, ...) \ - do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) \ - do { } while (0) -#endif - static uint32_t read_peripheral(dsp_core_t* core, uint32_t address); static void write_peripheral(dsp_core_t* core, uint32_t address, uint32_t value); diff --git a/hw/xbox/mcpx/dsp/dsp_cpu.c b/hw/xbox/mcpx/dsp/dsp_cpu.c index d40d2eafe4..f89a8ea1b8 100644 --- a/hw/xbox/mcpx/dsp/dsp_cpu.c +++ b/hw/xbox/mcpx/dsp/dsp_cpu.c @@ -32,19 +32,7 @@ #include "qemu/bswap.h" #include "dsp_cpu.h" - -#ifndef DEBUG_DSP -#define DEBUG_DSP 0 -#endif - -#define TRACE_DSP_DISASM 0 -#define TRACE_DSP_DISASM_REG 0 -#define TRACE_DSP_DISASM_MEM 0 - -#define DPRINTF(fmt, ...) \ - do { \ - if (DEBUG_DSP) fprintf(stderr, fmt, ## __VA_ARGS__); \ - } while (0) +#include "debug.h" #define BITMASK(x) ((1<<(x))-1) From 31c491a7026ee3a8ae2739b1ffe8937908e0d82f Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Mon, 17 Feb 2025 01:49:29 -0700 Subject: [PATCH 30/80] mcpx/dsp: Move cpu reg defs to a header --- hw/xbox/mcpx/dsp/dsp_cpu.h | 110 +------------------------ hw/xbox/mcpx/dsp/dsp_cpu_regs.h | 138 ++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+), 109 deletions(-) create mode 100644 hw/xbox/mcpx/dsp/dsp_cpu_regs.h diff --git a/hw/xbox/mcpx/dsp/dsp_cpu.h b/hw/xbox/mcpx/dsp/dsp_cpu.h index 6876b4d20a..4a87868139 100644 --- a/hw/xbox/mcpx/dsp/dsp_cpu.h +++ b/hw/xbox/mcpx/dsp/dsp_cpu.h @@ -29,115 +29,7 @@ #include #include -#define DSP_OMR_MA 0x00 -#define DSP_OMR_MB 0x01 -#define DSP_OMR_DE 0x02 -#define DSP_OMR_SD 0x06 -#define DSP_OMR_EA 0x07 - -#define DSP_SR_C 0x00 -#define DSP_SR_V 0x01 -#define DSP_SR_Z 0x02 -#define DSP_SR_N 0x03 -#define DSP_SR_U 0x04 -#define DSP_SR_E 0x05 -#define DSP_SR_L 0x06 - -#define DSP_SR_I0 0x08 -#define DSP_SR_I1 0x09 -#define DSP_SR_S0 0x0a -#define DSP_SR_S1 0x0b -#define DSP_SR_T 0x0d -#define DSP_SR_LF 0x0f - -#define DSP_SP_SE 0x04 -#define DSP_SP_UF 0x05 - -/* Registers numbers in dsp.registers[] */ -#define DSP_REG_X0 0x04 -#define DSP_REG_X1 0x05 -#define DSP_REG_Y0 0x06 -#define DSP_REG_Y1 0x07 -#define DSP_REG_A0 0x08 -#define DSP_REG_B0 0x09 -#define DSP_REG_A2 0x0a -#define DSP_REG_B2 0x0b -#define DSP_REG_A1 0x0c -#define DSP_REG_B1 0x0d -#define DSP_REG_A 0x0e -#define DSP_REG_B 0x0f - -#define DSP_REG_R0 0x10 -#define DSP_REG_R1 0x11 -#define DSP_REG_R2 0x12 -#define DSP_REG_R3 0x13 -#define DSP_REG_R4 0x14 -#define DSP_REG_R5 0x15 -#define DSP_REG_R6 0x16 -#define DSP_REG_R7 0x17 - -#define DSP_REG_N0 0x18 -#define DSP_REG_N1 0x19 -#define DSP_REG_N2 0x1a -#define DSP_REG_N3 0x1b -#define DSP_REG_N4 0x1c -#define DSP_REG_N5 0x1d -#define DSP_REG_N6 0x1e -#define DSP_REG_N7 0x1f - -#define DSP_REG_M0 0x20 -#define DSP_REG_M1 0x21 -#define DSP_REG_M2 0x22 -#define DSP_REG_M3 0x23 -#define DSP_REG_M4 0x24 -#define DSP_REG_M5 0x25 -#define DSP_REG_M6 0x26 -#define DSP_REG_M7 0x27 - -#define DSP_REG_SR 0x39 -#define DSP_REG_OMR 0x3a -#define DSP_REG_SP 0x3b -#define DSP_REG_SSH 0x3c -#define DSP_REG_SSL 0x3d -#define DSP_REG_LA 0x3e -#define DSP_REG_LC 0x3f - -#define DSP_REG_NULL 0x00 -#define DSP_REG_LCSAVE 0x30 - -#define DSP_REG_MAX 0x40 - -/* Memory spaces for dsp.ram[], dsp.rom[] */ -#define DSP_SPACE_X 0x00 -#define DSP_SPACE_Y 0x01 -#define DSP_SPACE_P 0x02 - -#define DSP_XRAM_SIZE 4096 -#define DSP_YRAM_SIZE 2048 -#define DSP_PRAM_SIZE 4096 - -#define DSP_MIXBUFFER_BASE 0x001400 -#define DSP_MIXBUFFER_SIZE 1024 - -#define DSP_PERIPH_BASE 0xFFFF80 -#define DSP_PERIPH_SIZE 128 - -#define DSP_INTERRUPT_NONE 0x0 -#define DSP_INTERRUPT_DISABLED 0x1 -#define DSP_INTERRUPT_LONG 0x2 - -#define DSP_INTER_RESET 0x0 -#define DSP_INTER_ILLEGAL 0x1 -#define DSP_INTER_STACK_ERROR 0x2 -#define DSP_INTER_TRACE 0x3 -#define DSP_INTER_SWI 0x4 -#define DSP_INTER_HOST_COMMAND 0x5 -#define DSP_INTER_HOST_RCV_DATA 0x6 -#define DSP_INTER_HOST_TRX_DATA 0x7 -#define DSP_INTER_SSI_RCV_DATA_E 0x8 -#define DSP_INTER_SSI_RCV_DATA 0x9 -#define DSP_INTER_SSI_TRX_DATA_E 0xa -#define DSP_INTER_SSI_TRX_DATA 0xb +#include "dsp_cpu_regs.h" typedef enum { DSP_TRACE_MODE, diff --git a/hw/xbox/mcpx/dsp/dsp_cpu_regs.h b/hw/xbox/mcpx/dsp/dsp_cpu_regs.h new file mode 100644 index 0000000000..75b2009b2f --- /dev/null +++ b/hw/xbox/mcpx/dsp/dsp_cpu_regs.h @@ -0,0 +1,138 @@ +/* + * DSP56300 emulator + * + * Copyright (c) 2015 espes + * + * Adapted from Hatari DSP M56001 emulation + * (C) 2003-2008 ARAnyM developer team + * Adaption to Hatari (C) 2008 by Thomas Huth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef HW_XBOX_MCPX_DSP_DSP_CPU_REGS_H +#define HW_XBOX_MCPX_DSP_DSP_CPU_REGS_H + +#define DSP_OMR_MA 0x00 +#define DSP_OMR_MB 0x01 +#define DSP_OMR_DE 0x02 +#define DSP_OMR_SD 0x06 +#define DSP_OMR_EA 0x07 + +#define DSP_SR_C 0x00 +#define DSP_SR_V 0x01 +#define DSP_SR_Z 0x02 +#define DSP_SR_N 0x03 +#define DSP_SR_U 0x04 +#define DSP_SR_E 0x05 +#define DSP_SR_L 0x06 + +#define DSP_SR_I0 0x08 +#define DSP_SR_I1 0x09 +#define DSP_SR_S0 0x0a +#define DSP_SR_S1 0x0b +#define DSP_SR_T 0x0d +#define DSP_SR_LF 0x0f + +#define DSP_SP_SE 0x04 +#define DSP_SP_UF 0x05 + +/* Registers numbers in dsp.registers[] */ +#define DSP_REG_X0 0x04 +#define DSP_REG_X1 0x05 +#define DSP_REG_Y0 0x06 +#define DSP_REG_Y1 0x07 +#define DSP_REG_A0 0x08 +#define DSP_REG_B0 0x09 +#define DSP_REG_A2 0x0a +#define DSP_REG_B2 0x0b +#define DSP_REG_A1 0x0c +#define DSP_REG_B1 0x0d +#define DSP_REG_A 0x0e +#define DSP_REG_B 0x0f + +#define DSP_REG_R0 0x10 +#define DSP_REG_R1 0x11 +#define DSP_REG_R2 0x12 +#define DSP_REG_R3 0x13 +#define DSP_REG_R4 0x14 +#define DSP_REG_R5 0x15 +#define DSP_REG_R6 0x16 +#define DSP_REG_R7 0x17 + +#define DSP_REG_N0 0x18 +#define DSP_REG_N1 0x19 +#define DSP_REG_N2 0x1a +#define DSP_REG_N3 0x1b +#define DSP_REG_N4 0x1c +#define DSP_REG_N5 0x1d +#define DSP_REG_N6 0x1e +#define DSP_REG_N7 0x1f + +#define DSP_REG_M0 0x20 +#define DSP_REG_M1 0x21 +#define DSP_REG_M2 0x22 +#define DSP_REG_M3 0x23 +#define DSP_REG_M4 0x24 +#define DSP_REG_M5 0x25 +#define DSP_REG_M6 0x26 +#define DSP_REG_M7 0x27 + +#define DSP_REG_SR 0x39 +#define DSP_REG_OMR 0x3a +#define DSP_REG_SP 0x3b +#define DSP_REG_SSH 0x3c +#define DSP_REG_SSL 0x3d +#define DSP_REG_LA 0x3e +#define DSP_REG_LC 0x3f + +#define DSP_REG_NULL 0x00 +#define DSP_REG_LCSAVE 0x30 + +#define DSP_REG_MAX 0x40 + +/* Memory spaces for dsp.ram[], dsp.rom[] */ +#define DSP_SPACE_X 0x00 +#define DSP_SPACE_Y 0x01 +#define DSP_SPACE_P 0x02 + +#define DSP_XRAM_SIZE 4096 +#define DSP_YRAM_SIZE 2048 +#define DSP_PRAM_SIZE 4096 + +#define DSP_MIXBUFFER_BASE 0x001400 +#define DSP_MIXBUFFER_SIZE 1024 + +#define DSP_PERIPH_BASE 0xFFFF80 +#define DSP_PERIPH_SIZE 128 + +#define DSP_INTERRUPT_NONE 0x0 +#define DSP_INTERRUPT_DISABLED 0x1 +#define DSP_INTERRUPT_LONG 0x2 + +#define DSP_INTER_RESET 0x0 +#define DSP_INTER_ILLEGAL 0x1 +#define DSP_INTER_STACK_ERROR 0x2 +#define DSP_INTER_TRACE 0x3 +#define DSP_INTER_SWI 0x4 +#define DSP_INTER_HOST_COMMAND 0x5 +#define DSP_INTER_HOST_RCV_DATA 0x6 +#define DSP_INTER_HOST_TRX_DATA 0x7 +#define DSP_INTER_SSI_RCV_DATA_E 0x8 +#define DSP_INTER_SSI_RCV_DATA 0x9 +#define DSP_INTER_SSI_TRX_DATA_E 0xa +#define DSP_INTER_SSI_TRX_DATA 0xb + +#endif From c68cdd9479c38bede20028e8c046ebba69d018c8 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Mon, 17 Feb 2025 01:49:29 -0700 Subject: [PATCH 31/80] mcpx/dsp: Fix minor header issues --- hw/xbox/mcpx/dsp/dsp.c | 7 ------- hw/xbox/mcpx/dsp/dsp_cpu.c | 6 ------ hw/xbox/mcpx/dsp/dsp_dma.c | 9 +-------- 3 files changed, 1 insertion(+), 21 deletions(-) diff --git a/hw/xbox/mcpx/dsp/dsp.c b/hw/xbox/mcpx/dsp/dsp.c index 29d8d67ea3..c2327a73be 100644 --- a/hw/xbox/mcpx/dsp/dsp.c +++ b/hw/xbox/mcpx/dsp/dsp.c @@ -24,16 +24,9 @@ */ #include "qemu/osdep.h" - -#include -#include -#include -#include - #include "dsp_cpu.h" #include "dsp_dma.h" #include "dsp_state.h" - #include "dsp.h" #include "debug.h" diff --git a/hw/xbox/mcpx/dsp/dsp_cpu.c b/hw/xbox/mcpx/dsp/dsp_cpu.c index f89a8ea1b8..8d786bcd69 100644 --- a/hw/xbox/mcpx/dsp/dsp_cpu.c +++ b/hw/xbox/mcpx/dsp/dsp_cpu.c @@ -24,13 +24,7 @@ */ #include "qemu/osdep.h" - -#include -#include -#include - #include "qemu/bswap.h" - #include "dsp_cpu.h" #include "debug.h" diff --git a/hw/xbox/mcpx/dsp/dsp_dma.c b/hw/xbox/mcpx/dsp/dsp_dma.c index 377475fb76..50a7a9f01d 100644 --- a/hw/xbox/mcpx/dsp/dsp_dma.c +++ b/hw/xbox/mcpx/dsp/dsp_dma.c @@ -18,12 +18,7 @@ * License along with this library; if not, see . */ -#include -#include -#include -#include - -#include +#include "qemu/osdep.h" #include "qemu/compiler.h" #include "dsp_dma.h" #include "dsp_state.h" @@ -98,8 +93,6 @@ const char *space_names[] = { #endif -#define MIN(a,b) (((a)<(b))?(a):(b)) - static void scratch_circular_copy( DSPDMAState *s, uint32_t scratch_base, From f8cbcbadaa07adf243b0e967ce58f93142624c45 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Mon, 17 Feb 2025 01:49:29 -0700 Subject: [PATCH 32/80] mcpx/dsp: Move dma reg defs to a header --- hw/xbox/mcpx/dsp/dsp_dma.c | 25 +----------------- hw/xbox/mcpx/dsp/dsp_dma_regs.h | 46 +++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 24 deletions(-) create mode 100644 hw/xbox/mcpx/dsp/dsp_dma_regs.h diff --git a/hw/xbox/mcpx/dsp/dsp_dma.c b/hw/xbox/mcpx/dsp/dsp_dma.c index 50a7a9f01d..80cf5a9747 100644 --- a/hw/xbox/mcpx/dsp/dsp_dma.c +++ b/hw/xbox/mcpx/dsp/dsp_dma.c @@ -21,32 +21,9 @@ #include "qemu/osdep.h" #include "qemu/compiler.h" #include "dsp_dma.h" +#include "dsp_dma_regs.h" #include "dsp_state.h" - -#define DMA_CONFIGURATION_AUTOSTART (1 << 0) -#define DMA_CONFIGURATION_AUTOREADY (1 << 1) -#define DMA_CONFIGURATION_IOC_CLEAR (1 << 2) -#define DMA_CONFIGURATION_EOL_CLEAR (1 << 3) -#define DMA_CONFIGURATION_ERR_CLEAR (1 << 4) - -#define DMA_CONTROL_ACTION 0x7 -#define DMA_CONTROL_ACTION_NOP 0 -#define DMA_CONTROL_ACTION_START 1 -#define DMA_CONTROL_ACTION_STOP 2 -#define DMA_CONTROL_ACTION_FREEZE 3 -#define DMA_CONTROL_ACTION_UNFREEZE 4 -#define DMA_CONTROL_ACTION_ABORT 5 -#define DMA_CONTROL_FROZEN (1 << 3) -#define DMA_CONTROL_RUNNING (1 << 4) -#define DMA_CONTROL_STOPPED (1 << 5) - -#define NODE_POINTER_VAL 0x3fff -#define NODE_POINTER_EOL (1 << 14) - -#define NODE_CONTROL_DIRECTION (1 << 1) - - // #define DEBUG #ifdef DEBUG # define DPRINTF(s, ...) printf(s, ## __VA_ARGS__) diff --git a/hw/xbox/mcpx/dsp/dsp_dma_regs.h b/hw/xbox/mcpx/dsp/dsp_dma_regs.h new file mode 100644 index 0000000000..a373cb7c14 --- /dev/null +++ b/hw/xbox/mcpx/dsp/dsp_dma_regs.h @@ -0,0 +1,46 @@ +/* + * MCPX DSP DMA + * + * Copyright (c) 2015 espes + * Copyright (c) 2020-2025 Matt Borgerson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#ifndef HW_XBOX_MCPX_DSP_DSP_DMA_REGS_H +#define HW_XBOX_MCPX_DSP_DSP_DMA_REGS_H + +#define DMA_CONFIGURATION_AUTOSTART (1 << 0) +#define DMA_CONFIGURATION_AUTOREADY (1 << 1) +#define DMA_CONFIGURATION_IOC_CLEAR (1 << 2) +#define DMA_CONFIGURATION_EOL_CLEAR (1 << 3) +#define DMA_CONFIGURATION_ERR_CLEAR (1 << 4) + +#define DMA_CONTROL_ACTION 0x7 +#define DMA_CONTROL_ACTION_NOP 0 +#define DMA_CONTROL_ACTION_START 1 +#define DMA_CONTROL_ACTION_STOP 2 +#define DMA_CONTROL_ACTION_FREEZE 3 +#define DMA_CONTROL_ACTION_UNFREEZE 4 +#define DMA_CONTROL_ACTION_ABORT 5 +#define DMA_CONTROL_FROZEN (1 << 3) +#define DMA_CONTROL_RUNNING (1 << 4) +#define DMA_CONTROL_STOPPED (1 << 5) + +#define NODE_POINTER_VAL 0x3fff +#define NODE_POINTER_EOL (1 << 14) + +#define NODE_CONTROL_DIRECTION (1 << 1) + +#endif From d18125994c3d1c20cf78173b5f45fb2cada29924 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Mon, 17 Feb 2025 01:49:29 -0700 Subject: [PATCH 33/80] mcpx/dsp: Drop some dead code --- hw/xbox/mcpx/dsp/dsp_dma.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/hw/xbox/mcpx/dsp/dsp_dma.c b/hw/xbox/mcpx/dsp/dsp_dma.c index 80cf5a9747..98f7bc3cb7 100644 --- a/hw/xbox/mcpx/dsp/dsp_dma.c +++ b/hw/xbox/mcpx/dsp/dsp_dma.c @@ -24,14 +24,8 @@ #include "dsp_dma_regs.h" #include "dsp_state.h" -// #define DEBUG #ifdef DEBUG -# define DPRINTF(s, ...) printf(s, ## __VA_ARGS__) -#else -# define DPRINTF(s, ...) do { } while (0) -#endif -#ifdef DEBUG const char *buffer_names[] = { "fifo0", /* 0x0 */ "fifo1", /* 0x1 */ @@ -112,8 +106,6 @@ static void dsp_dma_run(DSPDMAState *s) return; } - // DSPState *dsp = container_of(s, DSPState, dma); - while (!(s->next_block & NODE_POINTER_EOL)) { uint32_t addr = s->next_block & NODE_POINTER_VAL; uint32_t block_addr = 0; From 8dafd513b90fe711cbe4be6857430022165bef77 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Mon, 17 Feb 2025 01:49:29 -0700 Subject: [PATCH 34/80] mcpx/dsp: Move some debug functions out to debug.c --- hw/xbox/mcpx/dsp/debug.c | 312 +++++++++++++++++++++++++++++++++++ hw/xbox/mcpx/dsp/dsp.c | 269 ------------------------------ hw/xbox/mcpx/dsp/dsp.h | 9 +- hw/xbox/mcpx/dsp/dsp_cpu.c | 2 - hw/xbox/mcpx/dsp/meson.build | 2 +- 5 files changed, 316 insertions(+), 278 deletions(-) create mode 100644 hw/xbox/mcpx/dsp/debug.c diff --git a/hw/xbox/mcpx/dsp/debug.c b/hw/xbox/mcpx/dsp/debug.c new file mode 100644 index 0000000000..e678acb3d3 --- /dev/null +++ b/hw/xbox/mcpx/dsp/debug.c @@ -0,0 +1,312 @@ +/* + * MCPX DSP emulator + * + * Copyright (c) 2015 espes + * Copyright (c) 2020-2025 Matt Borgerson + * + * Adapted from Hatari DSP M56001 emulation + * (C) 2001-2008 ARAnyM developer team + * Adaption to Hatari (C) 2008 by Thomas Huth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "qemu/osdep.h" + +#include +#include +#include +#include + +#include "dsp_cpu.h" +#include "dsp_dma.h" +#include "dsp_state.h" + +#include "dsp.h" +#include "debug.h" + +#if DEBUG_DSP +#define BITMASK(x) ((1<<(x))-1) + +/** + * Disassemble DSP code between given addresses, return next PC address + */ +uint32_t dsp_disasm_address(DSPState* dsp, FILE *out, uint32_t lowerAdr, uint32_t UpperAdr) +{ + uint32_t dsp_pc; + + for (dsp_pc=lowerAdr; dsp_pc<=UpperAdr; dsp_pc++) { + dsp_pc += dsp56k_execute_one_disasm_instruction(&dsp->core, out, dsp_pc); + } + return dsp_pc; +} + +/** + * Output memory values between given addresses in given DSP address space. + * Return next DSP address value. + */ +uint32_t dsp_disasm_memory(DSPState* dsp, uint32_t dsp_memdump_addr, uint32_t dsp_memdump_upper, char space) +{ + uint32_t mem, value; + + for (mem = dsp_memdump_addr; mem <= dsp_memdump_upper; mem++) { + value = dsp_read_memory(dsp, space, mem); + printf("%04x %06x\n", mem, value); + } + return dsp_memdump_upper+1; +} + +/** + * Show information on DSP core state which isn't + * shown by any of the other commands (dd, dm, dr). + */ +void dsp_info(DSPState* dsp) +{ + int i, j; + const char *stackname[] = { "SSH", "SSL" }; + + printf("DSP core information:\n"); + + for (i = 0; i < ARRAY_SIZE(stackname); i++) { + printf("- %s stack:", stackname[i]); + for (j = 0; j < ARRAY_SIZE(dsp->core.stack[0]); j++) { + printf(" %04x", dsp->core.stack[i][j]); + } + printf("\n"); + } + + printf("- Interrupt IPL:"); + for (i = 0; i < ARRAY_SIZE(dsp->core.interrupt_ipl); i++) { + printf(" %04x", dsp->core.interrupt_ipl[i]); + } + printf("\n"); + + printf("- Pending ints: "); + for (i = 0; i < ARRAY_SIZE(dsp->core.interrupt_is_pending); i++) { + printf(" %04hx", dsp->core.interrupt_is_pending[i]); + } + printf("\n"); +} + +/** + * Show DSP register contents + */ +void dsp_print_registers(DSPState* dsp) +{ + uint32_t i; + + printf("A: A2: %02x A1: %06x A0: %06x\n", + dsp->core.registers[DSP_REG_A2], dsp->core.registers[DSP_REG_A1], dsp->core.registers[DSP_REG_A0]); + printf("B: B2: %02x B1: %06x B0: %06x\n", + dsp->core.registers[DSP_REG_B2], dsp->core.registers[DSP_REG_B1], dsp->core.registers[DSP_REG_B0]); + + printf("X: X1: %06x X0: %06x\n", dsp->core.registers[DSP_REG_X1], dsp->core.registers[DSP_REG_X0]); + printf("Y: Y1: %06x Y0: %06x\n", dsp->core.registers[DSP_REG_Y1], dsp->core.registers[DSP_REG_Y0]); + + for (i=0; i<8; i++) { + printf("R%01x: %04x N%01x: %04x M%01x: %04x\n", + i, dsp->core.registers[DSP_REG_R0+i], + i, dsp->core.registers[DSP_REG_N0+i], + i, dsp->core.registers[DSP_REG_M0+i]); + } + + printf("LA: %04x LC: %04x PC: %04x\n", dsp->core.registers[DSP_REG_LA], dsp->core.registers[DSP_REG_LC], dsp->core.pc); + printf("SR: %04x OMR: %02x\n", dsp->core.registers[DSP_REG_SR], dsp->core.registers[DSP_REG_OMR]); + printf("SP: %02x SSH: %04x SSL: %04x\n", + dsp->core.registers[DSP_REG_SP], dsp->core.registers[DSP_REG_SSH], dsp->core.registers[DSP_REG_SSL]); +} + + +/** + * Get given DSP register address and required bit mask. + * Works for A0-2, B0-2, LA, LC, M0-7, N0-7, R0-7, X0-1, Y0-1, PC, SR, SP, + * OMR, SSH & SSL registers, but note that the SP, SSH & SSL registers + * need special handling (in DSP*SetRegister()) when they are set. + * Return the register width in bits or zero for an error. + */ +int dsp_get_register_address(DSPState* dsp, const char *regname, uint32_t **addr, uint32_t *mask) +{ +#define MAX_REGNAME_LEN 4 + typedef struct { + const char name[MAX_REGNAME_LEN]; + uint32_t *addr; + size_t bits; + uint32_t mask; + } reg_addr_t; + + /* sorted by name so that this can be bisected */ + const reg_addr_t registers[] = { + + /* 56-bit A register */ + { "A0", &dsp->core.registers[DSP_REG_A0], 32, BITMASK(24) }, + { "A1", &dsp->core.registers[DSP_REG_A1], 32, BITMASK(24) }, + { "A2", &dsp->core.registers[DSP_REG_A2], 32, BITMASK(8) }, + + /* 56-bit B register */ + { "B0", &dsp->core.registers[DSP_REG_B0], 32, BITMASK(24) }, + { "B1", &dsp->core.registers[DSP_REG_B1], 32, BITMASK(24) }, + { "B2", &dsp->core.registers[DSP_REG_B2], 32, BITMASK(8) }, + + /* 16-bit LA & LC registers */ + { "LA", &dsp->core.registers[DSP_REG_LA], 32, BITMASK(16) }, + { "LC", &dsp->core.registers[DSP_REG_LC], 32, BITMASK(16) }, + + /* 16-bit M registers */ + { "M0", &dsp->core.registers[DSP_REG_M0], 32, BITMASK(16) }, + { "M1", &dsp->core.registers[DSP_REG_M1], 32, BITMASK(16) }, + { "M2", &dsp->core.registers[DSP_REG_M2], 32, BITMASK(16) }, + { "M3", &dsp->core.registers[DSP_REG_M3], 32, BITMASK(16) }, + { "M4", &dsp->core.registers[DSP_REG_M4], 32, BITMASK(16) }, + { "M5", &dsp->core.registers[DSP_REG_M5], 32, BITMASK(16) }, + { "M6", &dsp->core.registers[DSP_REG_M6], 32, BITMASK(16) }, + { "M7", &dsp->core.registers[DSP_REG_M7], 32, BITMASK(16) }, + + /* 16-bit N registers */ + { "N0", &dsp->core.registers[DSP_REG_N0], 32, BITMASK(16) }, + { "N1", &dsp->core.registers[DSP_REG_N1], 32, BITMASK(16) }, + { "N2", &dsp->core.registers[DSP_REG_N2], 32, BITMASK(16) }, + { "N3", &dsp->core.registers[DSP_REG_N3], 32, BITMASK(16) }, + { "N4", &dsp->core.registers[DSP_REG_N4], 32, BITMASK(16) }, + { "N5", &dsp->core.registers[DSP_REG_N5], 32, BITMASK(16) }, + { "N6", &dsp->core.registers[DSP_REG_N6], 32, BITMASK(16) }, + { "N7", &dsp->core.registers[DSP_REG_N7], 32, BITMASK(16) }, + + { "OMR", &dsp->core.registers[DSP_REG_OMR], 32, 0x5f }, + + /* 16-bit program counter */ + { "PC", (uint32_t*)(&dsp->core.pc), 24, BITMASK(24) }, + + /* 16-bit DSP R (address) registers */ + { "R0", &dsp->core.registers[DSP_REG_R0], 32, BITMASK(16) }, + { "R1", &dsp->core.registers[DSP_REG_R1], 32, BITMASK(16) }, + { "R2", &dsp->core.registers[DSP_REG_R2], 32, BITMASK(16) }, + { "R3", &dsp->core.registers[DSP_REG_R3], 32, BITMASK(16) }, + { "R4", &dsp->core.registers[DSP_REG_R4], 32, BITMASK(16) }, + { "R5", &dsp->core.registers[DSP_REG_R5], 32, BITMASK(16) }, + { "R6", &dsp->core.registers[DSP_REG_R6], 32, BITMASK(16) }, + { "R7", &dsp->core.registers[DSP_REG_R7], 32, BITMASK(16) }, + + { "SSH", &dsp->core.registers[DSP_REG_SSH], 32, BITMASK(16) }, + { "SSL", &dsp->core.registers[DSP_REG_SSL], 32, BITMASK(16) }, + { "SP", &dsp->core.registers[DSP_REG_SP], 32, BITMASK(6) }, + + /* 16-bit status register */ + { "SR", &dsp->core.registers[DSP_REG_SR], 32, 0xefff }, + + /* 48-bit X register */ + { "X0", &dsp->core.registers[DSP_REG_X0], 32, BITMASK(24) }, + { "X1", &dsp->core.registers[DSP_REG_X1], 32, BITMASK(24) }, + + /* 48-bit Y register */ + { "Y0", &dsp->core.registers[DSP_REG_Y0], 32, BITMASK(24) }, + { "Y1", &dsp->core.registers[DSP_REG_Y1], 32, BITMASK(24) } + }; + /* left, right, middle, direction */ + int l, r, m, dir = 0; + unsigned int i, len; + char reg[MAX_REGNAME_LEN]; + + for (i = 0; i < sizeof(reg) && regname[i]; i++) { + reg[i] = toupper(regname[i]); + } + if (i < 2 || regname[i]) { + /* too short or longer than any of the names */ + return 0; + } + len = i; + + /* bisect */ + l = 0; + r = ARRAY_SIZE(registers) - 1; + do { + m = (l+r) >> 1; + for (i = 0; i < len; i++) { + dir = (int)reg[i] - registers[m].name[i]; + if (dir) { + break; + } + } + if (dir == 0) { + *addr = registers[m].addr; + *mask = registers[m].mask; + return registers[m].bits; + } + if (dir < 0) { + r = m-1; + } else { + l = m+1; + } + } while (l <= r); +#undef MAX_REGNAME_LEN + return 0; +} + + +/** + * Set given DSP register value, return false if unknown register given + */ +bool dsp_disasm_set_register(DSPState* dsp, const char *arg, uint32_t value) +{ + uint32_t *addr, mask, sp_value; + int bits; + + /* first check registers needing special handling... */ + if (arg[0]=='S' || arg[0]=='s') { + if (arg[1]=='P' || arg[1]=='p') { + dsp->core.registers[DSP_REG_SP] = value & BITMASK(6); + value &= BITMASK(4); + dsp->core.registers[DSP_REG_SSH] = dsp->core.stack[0][value]; + dsp->core.registers[DSP_REG_SSL] = dsp->core.stack[1][value]; + return true; + } + if (arg[1]=='S' || arg[1]=='s') { + sp_value = dsp->core.registers[DSP_REG_SP] & BITMASK(4); + if (arg[2]=='H' || arg[2]=='h') { + if (sp_value == 0) { + dsp->core.registers[DSP_REG_SSH] = 0; + dsp->core.stack[0][sp_value] = 0; + } else { + dsp->core.registers[DSP_REG_SSH] = value & BITMASK(16); + dsp->core.stack[0][sp_value] = value & BITMASK(16); + } + return true; + } + if (arg[2]=='L' || arg[2]=='l') { + if (sp_value == 0) { + dsp->core.registers[DSP_REG_SSL] = 0; + dsp->core.stack[1][sp_value] = 0; + } else { + dsp->core.registers[DSP_REG_SSL] = value & BITMASK(16); + dsp->core.stack[1][sp_value] = value & BITMASK(16); + } + return true; + } + } + } + + /* ...then registers where address & mask are enough */ + bits = dsp_get_register_address(dsp, arg, &addr, &mask); + switch (bits) { + case 32: + *addr = value & mask; + return true; + case 16: + *(uint16_t*)addr = value & mask; + return true; + } + return false; +} + +#endif diff --git a/hw/xbox/mcpx/dsp/dsp.c b/hw/xbox/mcpx/dsp/dsp.c index c2327a73be..dda5f829e1 100644 --- a/hw/xbox/mcpx/dsp/dsp.c +++ b/hw/xbox/mcpx/dsp/dsp.c @@ -198,19 +198,6 @@ void dsp_start_frame(DSPState* dsp) dsp->interrupts |= INTERRUPT_START_FRAME; } -/** - * Disassemble DSP code between given addresses, return next PC address - */ -uint32_t dsp_disasm_address(DSPState* dsp, FILE *out, uint32_t lowerAdr, uint32_t UpperAdr) -{ - uint32_t dsp_pc; - - for (dsp_pc=lowerAdr; dsp_pc<=UpperAdr; dsp_pc++) { - dsp_pc += dsp56k_execute_one_disasm_instruction(&dsp->core, out, dsp_pc); - } - return dsp_pc; -} - uint32_t dsp_read_memory(DSPState* dsp, char space, uint32_t address) { int space_id; @@ -254,259 +241,3 @@ void dsp_write_memory(DSPState* dsp, char space, uint32_t address, uint32_t valu dsp56k_write_memory(&dsp->core, space_id, address, value); } - -/** - * Output memory values between given addresses in given DSP address space. - * Return next DSP address value. - */ -uint32_t dsp_disasm_memory(DSPState* dsp, uint32_t dsp_memdump_addr, uint32_t dsp_memdump_upper, char space) -{ - uint32_t mem, value; - - for (mem = dsp_memdump_addr; mem <= dsp_memdump_upper; mem++) { - value = dsp_read_memory(dsp, space, mem); - printf("%04x %06x\n", mem, value); - } - return dsp_memdump_upper+1; -} - -/** - * Show information on DSP core state which isn't - * shown by any of the other commands (dd, dm, dr). - */ -void dsp_info(DSPState* dsp) -{ - int i, j; - const char *stackname[] = { "SSH", "SSL" }; - - printf("DSP core information:\n"); - - for (i = 0; i < ARRAY_SIZE(stackname); i++) { - printf("- %s stack:", stackname[i]); - for (j = 0; j < ARRAY_SIZE(dsp->core.stack[0]); j++) { - printf(" %04x", dsp->core.stack[i][j]); - } - printf("\n"); - } - - printf("- Interrupt IPL:"); - for (i = 0; i < ARRAY_SIZE(dsp->core.interrupt_ipl); i++) { - printf(" %04x", dsp->core.interrupt_ipl[i]); - } - printf("\n"); - - printf("- Pending ints: "); - for (i = 0; i < ARRAY_SIZE(dsp->core.interrupt_is_pending); i++) { - printf(" %04hx", dsp->core.interrupt_is_pending[i]); - } - printf("\n"); -} - -/** - * Show DSP register contents - */ -void dsp_print_registers(DSPState* dsp) -{ - uint32_t i; - - printf("A: A2: %02x A1: %06x A0: %06x\n", - dsp->core.registers[DSP_REG_A2], dsp->core.registers[DSP_REG_A1], dsp->core.registers[DSP_REG_A0]); - printf("B: B2: %02x B1: %06x B0: %06x\n", - dsp->core.registers[DSP_REG_B2], dsp->core.registers[DSP_REG_B1], dsp->core.registers[DSP_REG_B0]); - - printf("X: X1: %06x X0: %06x\n", dsp->core.registers[DSP_REG_X1], dsp->core.registers[DSP_REG_X0]); - printf("Y: Y1: %06x Y0: %06x\n", dsp->core.registers[DSP_REG_Y1], dsp->core.registers[DSP_REG_Y0]); - - for (i=0; i<8; i++) { - printf("R%01x: %04x N%01x: %04x M%01x: %04x\n", - i, dsp->core.registers[DSP_REG_R0+i], - i, dsp->core.registers[DSP_REG_N0+i], - i, dsp->core.registers[DSP_REG_M0+i]); - } - - printf("LA: %04x LC: %04x PC: %04x\n", dsp->core.registers[DSP_REG_LA], dsp->core.registers[DSP_REG_LC], dsp->core.pc); - printf("SR: %04x OMR: %02x\n", dsp->core.registers[DSP_REG_SR], dsp->core.registers[DSP_REG_OMR]); - printf("SP: %02x SSH: %04x SSL: %04x\n", - dsp->core.registers[DSP_REG_SP], dsp->core.registers[DSP_REG_SSH], dsp->core.registers[DSP_REG_SSL]); -} - - -/** - * Get given DSP register address and required bit mask. - * Works for A0-2, B0-2, LA, LC, M0-7, N0-7, R0-7, X0-1, Y0-1, PC, SR, SP, - * OMR, SSH & SSL registers, but note that the SP, SSH & SSL registers - * need special handling (in DSP*SetRegister()) when they are set. - * Return the register width in bits or zero for an error. - */ -int dsp_get_register_address(DSPState* dsp, const char *regname, uint32_t **addr, uint32_t *mask) -{ -#define MAX_REGNAME_LEN 4 - typedef struct { - const char name[MAX_REGNAME_LEN]; - uint32_t *addr; - size_t bits; - uint32_t mask; - } reg_addr_t; - - /* sorted by name so that this can be bisected */ - const reg_addr_t registers[] = { - - /* 56-bit A register */ - { "A0", &dsp->core.registers[DSP_REG_A0], 32, BITMASK(24) }, - { "A1", &dsp->core.registers[DSP_REG_A1], 32, BITMASK(24) }, - { "A2", &dsp->core.registers[DSP_REG_A2], 32, BITMASK(8) }, - - /* 56-bit B register */ - { "B0", &dsp->core.registers[DSP_REG_B0], 32, BITMASK(24) }, - { "B1", &dsp->core.registers[DSP_REG_B1], 32, BITMASK(24) }, - { "B2", &dsp->core.registers[DSP_REG_B2], 32, BITMASK(8) }, - - /* 16-bit LA & LC registers */ - { "LA", &dsp->core.registers[DSP_REG_LA], 32, BITMASK(16) }, - { "LC", &dsp->core.registers[DSP_REG_LC], 32, BITMASK(16) }, - - /* 16-bit M registers */ - { "M0", &dsp->core.registers[DSP_REG_M0], 32, BITMASK(16) }, - { "M1", &dsp->core.registers[DSP_REG_M1], 32, BITMASK(16) }, - { "M2", &dsp->core.registers[DSP_REG_M2], 32, BITMASK(16) }, - { "M3", &dsp->core.registers[DSP_REG_M3], 32, BITMASK(16) }, - { "M4", &dsp->core.registers[DSP_REG_M4], 32, BITMASK(16) }, - { "M5", &dsp->core.registers[DSP_REG_M5], 32, BITMASK(16) }, - { "M6", &dsp->core.registers[DSP_REG_M6], 32, BITMASK(16) }, - { "M7", &dsp->core.registers[DSP_REG_M7], 32, BITMASK(16) }, - - /* 16-bit N registers */ - { "N0", &dsp->core.registers[DSP_REG_N0], 32, BITMASK(16) }, - { "N1", &dsp->core.registers[DSP_REG_N1], 32, BITMASK(16) }, - { "N2", &dsp->core.registers[DSP_REG_N2], 32, BITMASK(16) }, - { "N3", &dsp->core.registers[DSP_REG_N3], 32, BITMASK(16) }, - { "N4", &dsp->core.registers[DSP_REG_N4], 32, BITMASK(16) }, - { "N5", &dsp->core.registers[DSP_REG_N5], 32, BITMASK(16) }, - { "N6", &dsp->core.registers[DSP_REG_N6], 32, BITMASK(16) }, - { "N7", &dsp->core.registers[DSP_REG_N7], 32, BITMASK(16) }, - - { "OMR", &dsp->core.registers[DSP_REG_OMR], 32, 0x5f }, - - /* 16-bit program counter */ - { "PC", (uint32_t*)(&dsp->core.pc), 24, BITMASK(24) }, - - /* 16-bit DSP R (address) registers */ - { "R0", &dsp->core.registers[DSP_REG_R0], 32, BITMASK(16) }, - { "R1", &dsp->core.registers[DSP_REG_R1], 32, BITMASK(16) }, - { "R2", &dsp->core.registers[DSP_REG_R2], 32, BITMASK(16) }, - { "R3", &dsp->core.registers[DSP_REG_R3], 32, BITMASK(16) }, - { "R4", &dsp->core.registers[DSP_REG_R4], 32, BITMASK(16) }, - { "R5", &dsp->core.registers[DSP_REG_R5], 32, BITMASK(16) }, - { "R6", &dsp->core.registers[DSP_REG_R6], 32, BITMASK(16) }, - { "R7", &dsp->core.registers[DSP_REG_R7], 32, BITMASK(16) }, - - { "SSH", &dsp->core.registers[DSP_REG_SSH], 32, BITMASK(16) }, - { "SSL", &dsp->core.registers[DSP_REG_SSL], 32, BITMASK(16) }, - { "SP", &dsp->core.registers[DSP_REG_SP], 32, BITMASK(6) }, - - /* 16-bit status register */ - { "SR", &dsp->core.registers[DSP_REG_SR], 32, 0xefff }, - - /* 48-bit X register */ - { "X0", &dsp->core.registers[DSP_REG_X0], 32, BITMASK(24) }, - { "X1", &dsp->core.registers[DSP_REG_X1], 32, BITMASK(24) }, - - /* 48-bit Y register */ - { "Y0", &dsp->core.registers[DSP_REG_Y0], 32, BITMASK(24) }, - { "Y1", &dsp->core.registers[DSP_REG_Y1], 32, BITMASK(24) } - }; - /* left, right, middle, direction */ - int l, r, m, dir = 0; - unsigned int i, len; - char reg[MAX_REGNAME_LEN]; - - for (i = 0; i < sizeof(reg) && regname[i]; i++) { - reg[i] = toupper(regname[i]); - } - if (i < 2 || regname[i]) { - /* too short or longer than any of the names */ - return 0; - } - len = i; - - /* bisect */ - l = 0; - r = ARRAY_SIZE(registers) - 1; - do { - m = (l+r) >> 1; - for (i = 0; i < len; i++) { - dir = (int)reg[i] - registers[m].name[i]; - if (dir) { - break; - } - } - if (dir == 0) { - *addr = registers[m].addr; - *mask = registers[m].mask; - return registers[m].bits; - } - if (dir < 0) { - r = m-1; - } else { - l = m+1; - } - } while (l <= r); -#undef MAX_REGNAME_LEN - return 0; -} - - -/** - * Set given DSP register value, return false if unknown register given - */ -bool dsp_disasm_set_register(DSPState* dsp, const char *arg, uint32_t value) -{ - uint32_t *addr, mask, sp_value; - int bits; - - /* first check registers needing special handling... */ - if (arg[0]=='S' || arg[0]=='s') { - if (arg[1]=='P' || arg[1]=='p') { - dsp->core.registers[DSP_REG_SP] = value & BITMASK(6); - value &= BITMASK(4); - dsp->core.registers[DSP_REG_SSH] = dsp->core.stack[0][value]; - dsp->core.registers[DSP_REG_SSL] = dsp->core.stack[1][value]; - return true; - } - if (arg[1]=='S' || arg[1]=='s') { - sp_value = dsp->core.registers[DSP_REG_SP] & BITMASK(4); - if (arg[2]=='H' || arg[2]=='h') { - if (sp_value == 0) { - dsp->core.registers[DSP_REG_SSH] = 0; - dsp->core.stack[0][sp_value] = 0; - } else { - dsp->core.registers[DSP_REG_SSH] = value & BITMASK(16); - dsp->core.stack[0][sp_value] = value & BITMASK(16); - } - return true; - } - if (arg[2]=='L' || arg[2]=='l') { - if (sp_value == 0) { - dsp->core.registers[DSP_REG_SSL] = 0; - dsp->core.stack[1][sp_value] = 0; - } else { - dsp->core.registers[DSP_REG_SSL] = value & BITMASK(16); - dsp->core.stack[1][sp_value] = value & BITMASK(16); - } - return true; - } - } - } - - /* ...then registers where address & mask are enough */ - bits = dsp_get_register_address(dsp, arg, &addr, &mask); - switch (bits) { - case 32: - *addr = value & mask; - return true; - case 16: - *(uint16_t*)addr = value & mask; - return true; - } - return false; -} diff --git a/hw/xbox/mcpx/dsp/dsp.h b/hw/xbox/mcpx/dsp/dsp.h index 0b18fa0c45..d85e03d55e 100644 --- a/hw/xbox/mcpx/dsp/dsp.h +++ b/hw/xbox/mcpx/dsp/dsp.h @@ -36,7 +36,6 @@ typedef void (*dsp_scratch_rw_func)( typedef void (*dsp_fifo_rw_func)( void *opaque, uint8_t *ptr, unsigned int index, size_t len, bool dir); -/* Dsp commands */ DSPState *dsp_init(void *rw_opaque, dsp_scratch_rw_func scratch_rw, dsp_fifo_rw_func fifo_rw); @@ -49,16 +48,14 @@ void dsp_run(DSPState* dsp, int cycles); void dsp_bootstrap(DSPState* dsp); void dsp_start_frame(DSPState* dsp); - -/* Dsp Debugger commands */ uint32_t dsp_read_memory(DSPState* dsp, char space, uint32_t addr); void dsp_write_memory(DSPState* dsp, char space, uint32_t address, uint32_t value); -uint32_t dsp_disasm_memory(DSPState* dsp, uint32_t dsp_memdump_addr, uint32_t dsp_memdump_upper, char space); -uint32_t dsp_disasm_address(DSPState* dsp, FILE *out, uint32_t lowerAdr, uint32_t UpperAdr); + void dsp_info(DSPState* dsp); void dsp_print_registers(DSPState* dsp); int dsp_get_register_address(DSPState* dsp, const char *arg, uint32_t **addr, uint32_t *mask); +uint32_t dsp_disasm_memory(DSPState* dsp, uint32_t dsp_memdump_addr, uint32_t dsp_memdump_upper, char space); +uint32_t dsp_disasm_address(DSPState* dsp, FILE *out, uint32_t lowerAdr, uint32_t UpperAdr); bool dsp_disasm_set_register(DSPState* dsp, const char *arg, uint32_t value); - #endif /* DSP_H */ diff --git a/hw/xbox/mcpx/dsp/dsp_cpu.c b/hw/xbox/mcpx/dsp/dsp_cpu.c index 8d786bcd69..ba6fd7e057 100644 --- a/hw/xbox/mcpx/dsp/dsp_cpu.c +++ b/hw/xbox/mcpx/dsp/dsp_cpu.c @@ -1439,5 +1439,3 @@ static uint32_t dsp_signextend(int bits, uint32_t v) { assert(shift > 0); return (uint32_t)(((int32_t)v << shift) >> shift); } - - diff --git a/hw/xbox/mcpx/dsp/meson.build b/hw/xbox/mcpx/dsp/meson.build index b94537f97c..4e06c59496 100644 --- a/hw/xbox/mcpx/dsp/meson.build +++ b/hw/xbox/mcpx/dsp/meson.build @@ -1,2 +1,2 @@ -libdsp = static_library('dsp', files(['dsp.c', 'dsp_cpu.c', 'dsp_dma.c']) + genh) +libdsp = static_library('dsp', files(['debug.c', 'dsp.c', 'dsp_cpu.c', 'dsp_dma.c']) + genh) dsp = declare_dependency(objects: libdsp.extract_all_objects(recursive: false)) From 31d8237ee3c1ed4d6cc98bf0acc40992627eec54 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Mon, 17 Feb 2025 01:49:29 -0700 Subject: [PATCH 35/80] mcpx/dsp: Remove dsp56k_execute_one_disasm_instruction --- hw/xbox/mcpx/apu.c | 2 +- hw/xbox/mcpx/dsp/debug.c | 13 ------ hw/xbox/mcpx/dsp/dsp_cpu.c | 89 ++++++++---------------------------- hw/xbox/mcpx/dsp/dsp_cpu.h | 5 -- hw/xbox/mcpx/dsp/dsp_emu.inl | 13 ++---- 5 files changed, 24 insertions(+), 98 deletions(-) diff --git a/hw/xbox/mcpx/apu.c b/hw/xbox/mcpx/apu.c index d5eec18f40..338e132956 100644 --- a/hw/xbox/mcpx/apu.c +++ b/hw/xbox/mcpx/apu.c @@ -2579,7 +2579,7 @@ const VMStateDescription vmstate_vp_dsp_core_state = { VMSTATE_UINT32(num_inst, dsp_core_t), VMSTATE_UINT32(cur_inst_len, dsp_core_t), VMSTATE_UINT32(cur_inst, dsp_core_t), - VMSTATE_BOOL(executing_for_disasm, dsp_core_t), + VMSTATE_UNUSED(1), VMSTATE_UINT32(disasm_memory_ptr, dsp_core_t), VMSTATE_BOOL(exception_debugging, dsp_core_t), VMSTATE_UINT32(disasm_prev_inst_pc, dsp_core_t), diff --git a/hw/xbox/mcpx/dsp/debug.c b/hw/xbox/mcpx/dsp/debug.c index e678acb3d3..e41a222bf9 100644 --- a/hw/xbox/mcpx/dsp/debug.c +++ b/hw/xbox/mcpx/dsp/debug.c @@ -40,19 +40,6 @@ #if DEBUG_DSP #define BITMASK(x) ((1<<(x))-1) -/** - * Disassemble DSP code between given addresses, return next PC address - */ -uint32_t dsp_disasm_address(DSPState* dsp, FILE *out, uint32_t lowerAdr, uint32_t UpperAdr) -{ - uint32_t dsp_pc; - - for (dsp_pc=lowerAdr; dsp_pc<=UpperAdr; dsp_pc++) { - dsp_pc += dsp56k_execute_one_disasm_instruction(&dsp->core, out, dsp_pc); - } - return dsp_pc; -} - /** * Output memory values between given addresses in given DSP address space. * Return next DSP address value. diff --git a/hw/xbox/mcpx/dsp/dsp_cpu.c b/hw/xbox/mcpx/dsp/dsp_cpu.c index ba6fd7e057..06d4b82ab2 100644 --- a/hw/xbox/mcpx/dsp/dsp_cpu.c +++ b/hw/xbox/mcpx/dsp/dsp_cpu.c @@ -405,7 +405,6 @@ void dsp56k_reset_cpu(dsp_core_t* dsp) /* runtime shit */ - dsp->executing_for_disasm = false; // start_time = SDL_GetTicks(); dsp->num_inst = 0; @@ -597,39 +596,6 @@ static const char* disasm_get_instruction_text(dsp_core_t* dsp) return dsp->disasm_str_instr2; } -/** - * Execute one instruction in trace mode at a given PC address. - * */ -uint16_t dsp56k_execute_one_disasm_instruction(dsp_core_t* dsp, FILE *out, uint32_t pc) -{ - dsp_core_t dsp_core_save; - - /* Set DSP in disasm mode */ - dsp->executing_for_disasm = true; - - /* Save DSP context before executing instruction */ - memcpy(&dsp_core_save, dsp, sizeof(dsp_core_t)); - - /* execute and disasm instruction */ - dsp->pc = pc; - - /* Disasm instruction */ - uint16_t instruction_length = disasm_instruction(dsp, DSP_DISASM_MODE) - 1; - - /* Execute instruction at address given in parameter to get the number of cycles it takes */ - dsp56k_execute_instruction(dsp); - - fprintf(out, "%s", disasm_get_instruction_text(dsp)); - - /* Restore DSP context after executing instruction */ - memcpy(dsp, &dsp_core_save, sizeof(dsp_core_t)); - - /* Unset DSP in disasm mode */ - dsp->executing_for_disasm = false; - - return instruction_length; -} - void dsp56k_execute_instruction(dsp_core_t* dsp) { uint32_t disasm_return = 0; @@ -644,15 +610,10 @@ void dsp56k_execute_instruction(dsp_core_t* dsp) /* Disasm current instruction ? (trace mode only) */ if (TRACE_DSP_DISASM) { - /* Call disasm_instruction only when DSP is called in trace mode */ - if (!dsp->executing_for_disasm) { - disasm_return = disasm_instruction(dsp, DSP_TRACE_MODE); - - if (disasm_return) { - DPRINTF("%s", disasm_get_instruction_text(dsp)); - } - if (disasm_return != 0 && TRACE_DSP_DISASM_REG) { - /* DSP regs trace enabled only if DSP DISASM is enabled */ + disasm_return = disasm_instruction(dsp, DSP_TRACE_MODE); + if (disasm_return) { + DPRINTF("%s", disasm_get_instruction_text(dsp)); + if (TRACE_DSP_DISASM_REG) { disasm_reg_save(dsp); } } @@ -676,26 +637,18 @@ void dsp56k_execute_instruction(dsp_core_t* dsp) } /* Disasm current instruction ? (trace mode only) */ - if (TRACE_DSP_DISASM) { - /* Display only when DSP is called in trace mode */ - if (!dsp->executing_for_disasm) { - if (disasm_return != 0) { - // DPRINTF("%s", disasm_get_instruction_text(dsp)); - - /* DSP regs trace enabled only if DSP DISASM is enabled */ - if (TRACE_DSP_DISASM_REG) - disasm_reg_compare(dsp); - - if (TRACE_DSP_DISASM_MEM) { - /* 1 memory change to display ? */ - if (dsp->disasm_memory_ptr == 1) - DPRINTF("\t%s\n", dsp->str_disasm_memory[0]); - /* 2 memory changes to display ? */ - else if (dsp->disasm_memory_ptr == 2) { - DPRINTF("\t%s\n", dsp->str_disasm_memory[0]); - DPRINTF("\t%s\n", dsp->str_disasm_memory[1]); - } - } + if (TRACE_DSP_DISASM && disasm_return) { + if (TRACE_DSP_DISASM_REG) { + disasm_reg_compare(dsp); + } + if (TRACE_DSP_DISASM_MEM) { + /* 1 memory change to display ? */ + if (dsp->disasm_memory_ptr == 1) + DPRINTF("\t%s\n", dsp->str_disasm_memory[0]); + /* 2 memory changes to display ? */ + else if (dsp->disasm_memory_ptr == 2) { + DPRINTF("\t%s\n", dsp->str_disasm_memory[0]); + DPRINTF("\t%s\n", dsp->str_disasm_memory[1]); } } } @@ -1103,9 +1056,7 @@ static void dsp_write_reg(dsp_core_t* dsp, uint32_t numreg, uint32_t value) /* Stack underflow or overflow detected, raise interrupt */ dsp56k_add_interrupt(dsp, DSP_INTER_STACK_ERROR); dsp->registers[DSP_REG_SP] = value & (3<executing_for_disasm) { - DPRINTF("Dsp: Stack Overflow or Underflow\n"); - } + DPRINTF("Dsp: Stack Overflow or Underflow\n"); if (dsp->exception_debugging) { assert(false); } @@ -1148,8 +1099,7 @@ static void dsp_stack_push(dsp_core_t* dsp, uint32_t curpc, uint32_t cursr, uint if ((stack_error==0) && (stack & (1<executing_for_disasm) - DPRINTF("Dsp: Stack Overflow\n"); + DPRINTF("Dsp: Stack Overflow\n"); if (dsp->exception_debugging) assert(false); } @@ -1185,8 +1135,7 @@ static void dsp_stack_pop(dsp_core_t* dsp, uint32_t *newpc, uint32_t *newsr) if ((stack_error==0) && (stack & (1<executing_for_disasm) - DPRINTF("Dsp: Stack underflow\n"); + DPRINTF("Dsp: Stack underflow\n"); if (dsp->exception_debugging) assert(false); } diff --git a/hw/xbox/mcpx/dsp/dsp_cpu.h b/hw/xbox/mcpx/dsp/dsp_cpu.h index 4a87868139..4cffd2631d 100644 --- a/hw/xbox/mcpx/dsp/dsp_cpu.h +++ b/hw/xbox/mcpx/dsp/dsp_cpu.h @@ -101,10 +101,6 @@ struct dsp_core_s { /* Current instruction */ uint32_t cur_inst; - /* DSP is in disasm mode ? */ - /* If yes, stack overflow, underflow and illegal instructions messages are not displayed */ - bool executing_for_disasm; - char str_disasm_memory[2][50]; /* Buffer for memory change text in disasm mode */ uint32_t disasm_memory_ptr; /* Pointer for memory change in disasm mode */ @@ -142,7 +138,6 @@ struct dsp_core_s { /* Functions */ void dsp56k_reset_cpu(dsp_core_t* dsp); /* Set dsp_core to use */ void dsp56k_execute_instruction(dsp_core_t* dsp); /* Execute 1 instruction */ -uint16_t dsp56k_execute_one_disasm_instruction(dsp_core_t* dsp, FILE *out, uint32_t pc); /* Execute 1 instruction in disasm mode */ uint32_t dsp56k_read_memory(dsp_core_t* dsp, int space, uint32_t address); void dsp56k_write_memory(dsp_core_t* dsp, int space, uint32_t address, uint32_t value); diff --git a/hw/xbox/mcpx/dsp/dsp_emu.inl b/hw/xbox/mcpx/dsp/dsp_emu.inl index e509baa2d7..b67ea13398 100644 --- a/hw/xbox/mcpx/dsp/dsp_emu.inl +++ b/hw/xbox/mcpx/dsp/dsp_emu.inl @@ -27,15 +27,10 @@ typedef void (*emu_func_t)(dsp_core_t* dsp); static void emu_undefined(dsp_core_t* dsp) { - if (!dsp->executing_for_disasm) { - dsp->cur_inst_len = 0; - printf("Dsp: 0x%04x: 0x%06x Illegal instruction\n",dsp->pc, dsp->cur_inst); - /* Add some artificial CPU cycles to avoid being stuck in an infinite loop */ - dsp->instr_cycle += 100; - } else { - dsp->cur_inst_len = 1; - dsp->instr_cycle = 0; - } + dsp->cur_inst_len = 0; + printf("Dsp: 0x%04x: 0x%06x Illegal instruction\n",dsp->pc, dsp->cur_inst); + /* Add some artificial CPU cycles to avoid being stuck in an infinite loop */ + dsp->instr_cycle += 100; if (dsp->exception_debugging) { assert(false); } From 4b81c289011d2e085573bc3351cb9425a80856de Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Mon, 17 Feb 2025 01:49:29 -0700 Subject: [PATCH 36/80] mcpx/dsp: Migrate some DPRINTFs to trace events --- hw/xbox/mcpx/dsp/dsp.c | 9 ++++----- hw/xbox/mcpx/dsp/dsp_cpu.c | 21 ++++++++++++++------- hw/xbox/mcpx/dsp/trace-events | 9 +++++++++ hw/xbox/mcpx/dsp/trace.h | 1 + meson.build | 1 + 5 files changed, 29 insertions(+), 12 deletions(-) create mode 100644 hw/xbox/mcpx/dsp/trace-events create mode 100644 hw/xbox/mcpx/dsp/trace.h diff --git a/hw/xbox/mcpx/dsp/dsp.c b/hw/xbox/mcpx/dsp/dsp.c index dda5f829e1..32b9c12d40 100644 --- a/hw/xbox/mcpx/dsp/dsp.c +++ b/hw/xbox/mcpx/dsp/dsp.c @@ -29,6 +29,7 @@ #include "dsp_state.h" #include "dsp.h" #include "debug.h" +#include "trace.h" /* Defines */ #define BITMASK(x) ((1<<(x))-1) @@ -76,8 +77,6 @@ void dsp_destroy(DSPState* dsp) static uint32_t read_peripheral(dsp_core_t* core, uint32_t address) { DSPState* dsp = container_of(core, DSPState, core); - DPRINTF("read_peripheral 0x%06x", address); - uint32_t v = 0xababa; switch(address) { case 0xFFFFB3: @@ -103,15 +102,13 @@ static uint32_t read_peripheral(dsp_core_t* core, uint32_t address) { break; } - DPRINTF(" -> 0x%06x\n", v); + trace_dsp_read_peripheral(address, v); return v; } static void write_peripheral(dsp_core_t* core, uint32_t address, uint32_t value) { DSPState* dsp = container_of(core, DSPState, core); - DPRINTF("write_peripheral [0x%06x] = 0x%06x\n", address, value); - switch(address) { case 0xFFFFC4: if (value & 1) { @@ -137,6 +134,8 @@ static void write_peripheral(dsp_core_t* core, uint32_t address, uint32_t value) dsp_dma_write(&dsp->dma, DMA_CONFIGURATION, value); break; } + + trace_dsp_write_peripheral(address, value); } diff --git a/hw/xbox/mcpx/dsp/dsp_cpu.c b/hw/xbox/mcpx/dsp/dsp_cpu.c index 06d4b82ab2..61cce8cf41 100644 --- a/hw/xbox/mcpx/dsp/dsp_cpu.c +++ b/hw/xbox/mcpx/dsp/dsp_cpu.c @@ -27,6 +27,7 @@ #include "qemu/bswap.h" #include "dsp_cpu.h" #include "debug.h" +#include "trace.h" #define BITMASK(x) ((1<<(x))-1) @@ -583,21 +584,21 @@ static void disasm_reg_compare(dsp_core_t* dsp) static const char* disasm_get_instruction_text(dsp_core_t* dsp) { - const int len = sizeof(dsp->disasm_str_instr); - if (dsp->disasm_is_looping) { dsp->disasm_str_instr2[0] = 0; } if (dsp->disasm_cur_inst_len == 1) { - snprintf(dsp->disasm_str_instr2, sizeof(dsp->disasm_str_instr2), "p:%04x %06x (%02d cyc) %-*s\n", dsp->disasm_prev_inst_pc, dsp->disasm_cur_inst, dsp->instr_cycle, len, dsp->disasm_str_instr); + snprintf(dsp->disasm_str_instr2, sizeof(dsp->disasm_str_instr2), "p:%04x %06x (%02d cyc) %s", dsp->disasm_prev_inst_pc, dsp->disasm_cur_inst, dsp->instr_cycle, dsp->disasm_str_instr); } else { - snprintf(dsp->disasm_str_instr2, sizeof(dsp->disasm_str_instr2), "p:%04x %06x %06x (%02d cyc) %-*s\n", dsp->disasm_prev_inst_pc, dsp->disasm_cur_inst, read_memory_p(dsp, dsp->disasm_prev_inst_pc + 1), dsp->instr_cycle, len, dsp->disasm_str_instr); + snprintf(dsp->disasm_str_instr2, sizeof(dsp->disasm_str_instr2), "p:%04x %06x %06x (%02d cyc) %s", dsp->disasm_prev_inst_pc, dsp->disasm_cur_inst, read_memory_p(dsp, dsp->disasm_prev_inst_pc + 1), dsp->instr_cycle, dsp->disasm_str_instr); } return dsp->disasm_str_instr2; } void dsp56k_execute_instruction(dsp_core_t* dsp) { + trace_dsp56k_execute_instruction(dsp->is_gp, dsp->pc); + uint32_t disasm_return = 0; dsp->disasm_memory_ptr = 0; @@ -608,11 +609,17 @@ void dsp56k_execute_instruction(dsp_core_t* dsp) dsp->cur_inst_len = 1; dsp->instr_cycle = 2; + bool tracing = TRACE_DSP_DISASM || trace_event_get_state(TRACE_DSP56K_EXECUTE_INSTRUCTION_DISASM); + /* Disasm current instruction ? (trace mode only) */ - if (TRACE_DSP_DISASM) { + if (tracing) { disasm_return = disasm_instruction(dsp, DSP_TRACE_MODE); if (disasm_return) { - DPRINTF("%s", disasm_get_instruction_text(dsp)); + const char *text = disasm_get_instruction_text(dsp); + trace_dsp56k_execute_instruction_disasm(text); + if (TRACE_DSP_DISASM) { + DPRINTF("%s\n", text); + } if (TRACE_DSP_DISASM_REG) { disasm_reg_save(dsp); } @@ -637,7 +644,7 @@ void dsp56k_execute_instruction(dsp_core_t* dsp) } /* Disasm current instruction ? (trace mode only) */ - if (TRACE_DSP_DISASM && disasm_return) { + if (tracing && disasm_return) { if (TRACE_DSP_DISASM_REG) { disasm_reg_compare(dsp); } diff --git a/hw/xbox/mcpx/dsp/trace-events b/hw/xbox/mcpx/dsp/trace-events new file mode 100644 index 0000000000..82f10a3f92 --- /dev/null +++ b/hw/xbox/mcpx/dsp/trace-events @@ -0,0 +1,9 @@ +# See docs/devel/tracing.rst for syntax documentation. + +# dsp.c +dsp_read_peripheral(uint32_t addr, uint32_t val) "addr 0x%"PRIx32" val 0x%"PRIx32 +dsp_write_peripheral(uint32_t addr, uint32_t val) "addr 0x%"PRIx32" val 0x%"PRIx32 + +# dsp_cpu.c +dsp56k_execute_instruction(uint32_t id, uint32_t pc) "[gp=%d]: pc=0x%"PRIx32 +dsp56k_execute_instruction_disasm(const char *disasm) "%s" diff --git a/hw/xbox/mcpx/dsp/trace.h b/hw/xbox/mcpx/dsp/trace.h new file mode 100644 index 0000000000..6ab110fe5b --- /dev/null +++ b/hw/xbox/mcpx/dsp/trace.h @@ -0,0 +1 @@ +#include "trace/trace-hw_xbox_mcpx_dsp.h" diff --git a/meson.build b/meson.build index 72e7049e02..c1e9612bbf 100644 --- a/meson.build +++ b/meson.build @@ -3772,6 +3772,7 @@ if have_system 'hw/remote', 'hw/xbox/nv2a', 'hw/xbox/mcpx', + 'hw/xbox/mcpx/dsp', 'hw/xbox', ] endif From 4a5c91397f7fb00bfa9647204543a14778f74d9b Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Sat, 29 Mar 2025 16:03:14 -0700 Subject: [PATCH 37/80] ci: Run xbox tests --- .github/workflows/build.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 576d3adf89..fb2a6cc123 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -245,6 +245,11 @@ jobs: echo -e "\n\nCompiler Cache Stats:" ccache -s + - name: Test + run: | + pushd src/build + ./pyvenv/bin/meson test --suite xbox + popd - name: Generate AppImage run: | wget --no-verbose https://github.com/linuxdeploy/linuxdeploy/releases/latest/download/linuxdeploy-${{ matrix.arch }}.AppImage From e08011b77201920fabd95df9ad2241d1b8883ad5 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Sat, 29 Mar 2025 16:10:41 -0700 Subject: [PATCH 38/80] mcpx/dsp: Rename *.inl -> *.c.inc --- hw/xbox/mcpx/dsp/dsp_cpu.c | 5 ++--- hw/xbox/mcpx/dsp/{dsp_dis.inl => dsp_dis.c.inc} | 0 hw/xbox/mcpx/dsp/{dsp_emu.inl => dsp_emu.c.inc} | 0 3 files changed, 2 insertions(+), 3 deletions(-) rename hw/xbox/mcpx/dsp/{dsp_dis.inl => dsp_dis.c.inc} (100%) rename hw/xbox/mcpx/dsp/{dsp_emu.inl => dsp_emu.c.inc} (100%) diff --git a/hw/xbox/mcpx/dsp/dsp_cpu.c b/hw/xbox/mcpx/dsp/dsp_cpu.c index 61cce8cf41..a5b2d64630 100644 --- a/hw/xbox/mcpx/dsp/dsp_cpu.c +++ b/hw/xbox/mcpx/dsp/dsp_cpu.c @@ -129,9 +129,8 @@ static const int registers_mask[64] = { 16, 16, 16, 16 }; -#include "dsp_emu.inl" - -#include "dsp_dis.inl" +#include "dsp_emu.c.inc" +#include "dsp_dis.c.inc" typedef bool (*match_func_t)(uint32_t op); diff --git a/hw/xbox/mcpx/dsp/dsp_dis.inl b/hw/xbox/mcpx/dsp/dsp_dis.c.inc similarity index 100% rename from hw/xbox/mcpx/dsp/dsp_dis.inl rename to hw/xbox/mcpx/dsp/dsp_dis.c.inc diff --git a/hw/xbox/mcpx/dsp/dsp_emu.inl b/hw/xbox/mcpx/dsp/dsp_emu.c.inc similarity index 100% rename from hw/xbox/mcpx/dsp/dsp_emu.inl rename to hw/xbox/mcpx/dsp/dsp_emu.c.inc From 9439f605a89e1af0b34a4123a1f79571f105c285 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Sat, 29 Mar 2025 17:07:50 -0700 Subject: [PATCH 39/80] mcpx/dsp: Drop redundant value/address assertions --- hw/xbox/mcpx/dsp/dsp_cpu.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/hw/xbox/mcpx/dsp/dsp_cpu.c b/hw/xbox/mcpx/dsp/dsp_cpu.c index a5b2d64630..09cbb7c180 100644 --- a/hw/xbox/mcpx/dsp/dsp_cpu.c +++ b/hw/xbox/mcpx/dsp/dsp_cpu.c @@ -961,9 +961,6 @@ uint32_t dsp56k_read_memory(dsp_core_t* dsp, int space, uint32_t address) void dsp56k_write_memory(dsp_core_t* dsp, int space, uint32_t address, uint32_t value) { - assert((value & 0xFF000000) == 0); - assert((address & 0xFF000000) == 0); - if (TRACE_DSP_DISASM_MEM) write_memory_disasm(dsp, space, address, value); else From 57cdee770e228409f1755b636d7075135e046f12 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Sat, 29 Mar 2025 17:23:55 -0700 Subject: [PATCH 40/80] mcpx/dsp: Fix some formatting/spelling nits --- hw/xbox/mcpx/dsp/dsp_cpu.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/hw/xbox/mcpx/dsp/dsp_cpu.c b/hw/xbox/mcpx/dsp/dsp_cpu.c index 09cbb7c180..380c07e1bb 100644 --- a/hw/xbox/mcpx/dsp/dsp_cpu.c +++ b/hw/xbox/mcpx/dsp/dsp_cpu.c @@ -71,18 +71,18 @@ static void dsp_rnd56(dsp_core_t* dsp, uint32_t *dest); static uint32_t dsp_signextend(int bits, uint32_t v); static const dsp_interrupt_t dsp_interrupt[12] = { - {DSP_INTER_RESET , 0x00, 0, "Reset"}, - {DSP_INTER_ILLEGAL , 0x3e, 0, "Illegal"}, - {DSP_INTER_STACK_ERROR , 0x02, 0, "Stack Error"}, - {DSP_INTER_TRACE , 0x04, 0, "Trace"}, - {DSP_INTER_SWI , 0x06, 0, "Swi"}, - {DSP_INTER_HOST_COMMAND , 0xff, 1, "Host Command"}, - {DSP_INTER_HOST_RCV_DATA, 0x20, 1, "Host receive"}, - {DSP_INTER_HOST_TRX_DATA, 0x22, 1, "Host transmit"}, - {DSP_INTER_SSI_RCV_DATA_E, 0x0e, 2, "SSI receive with exception"}, - {DSP_INTER_SSI_RCV_DATA , 0x0c, 2, "SSI receive"}, - {DSP_INTER_SSI_TRX_DATA_E, 0x12, 2, "SSI transmit with exception"}, - {DSP_INTER_SSI_TRX_DATA , 0x10, 2, "SSI tramsmit"} + { DSP_INTER_RESET, 0x00, 0, "Reset" }, + { DSP_INTER_ILLEGAL, 0x3e, 0, "Illegal" }, + { DSP_INTER_STACK_ERROR, 0x02, 0, "Stack Error" }, + { DSP_INTER_TRACE, 0x04, 0, "Trace" }, + { DSP_INTER_SWI, 0x06, 0, "Swi" }, + { DSP_INTER_HOST_COMMAND, 0xff, 1, "Host Command" }, + { DSP_INTER_HOST_RCV_DATA, 0x20, 1, "Host receive" }, + { DSP_INTER_HOST_TRX_DATA, 0x22, 1, "Host transmit" }, + { DSP_INTER_SSI_RCV_DATA_E, 0x0e, 2, "SSI receive with exception" }, + { DSP_INTER_SSI_RCV_DATA, 0x0c, 2, "SSI receive" }, + { DSP_INTER_SSI_TRX_DATA_E, 0x12, 2, "SSI transmit with exception" }, + { DSP_INTER_SSI_TRX_DATA, 0x10, 2, "SSI transmit" } }; static const int registers_tcc[16][2] = { From f82c6865fc27a07f52470e0a1da30151b130b4a2 Mon Sep 17 00:00:00 2001 From: Mason Thompson <72317541+MasonT8198@users.noreply.github.com> Date: Mon, 31 Mar 2025 18:03:28 -0400 Subject: [PATCH 41/80] control: Add python3-tomli/python3-pip --- debian/control | 2 ++ 1 file changed, 2 insertions(+) diff --git a/debian/control b/debian/control index eb495ec081..7f5871bbd7 100644 --- a/debian/control +++ b/debian/control @@ -6,6 +6,8 @@ Build-Depends: debhelper (>= 11), cmake, git, python3:any, + python3-pip, + python3-tomli, python3-yaml, python3-venv, ninja-build, From ebec5e30284a6ef2c55fe4f1d1c123eb88c19a74 Mon Sep 17 00:00:00 2001 From: Erik Abair Date: Tue, 8 Apr 2025 11:03:00 -0700 Subject: [PATCH 42/80] nv2a: Fix assert when setting fog gen mode to fog_x --- hw/xbox/nv2a/pgraph/glsl/vsh-ff.c | 2 +- hw/xbox/nv2a/pgraph/vsh.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c index 445ce73066..19ebf12f3b 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c @@ -414,7 +414,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz mstring_append(body, " float fogDistance = fogCoord;\n"); break; default: - assert(false); + assert(!"Invalid foggen mode"); break; } diff --git a/hw/xbox/nv2a/pgraph/vsh.h b/hw/xbox/nv2a/pgraph/vsh.h index 405b6c9aa6..36cac16edf 100644 --- a/hw/xbox/nv2a/pgraph/vsh.h +++ b/hw/xbox/nv2a/pgraph/vsh.h @@ -55,8 +55,6 @@ enum VshFoggen { FOGGEN_RADIAL, FOGGEN_PLANAR, FOGGEN_ABS_PLANAR, - FOGGEN_ERROR4, - FOGGEN_ERROR5, FOGGEN_FOG_X }; From 2cc926588b9fea2aa5bd5b4882cb7440c6553991 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Fri, 11 Apr 2025 03:52:24 -0700 Subject: [PATCH 43/80] nv2a/gl: Fix COLOR_LE_G8B8 GL surface format type --- hw/xbox/nv2a/pgraph/gl/constants.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/xbox/nv2a/pgraph/gl/constants.h b/hw/xbox/nv2a/pgraph/gl/constants.h index d78b0054e3..e3e78df8d1 100644 --- a/hw/xbox/nv2a/pgraph/gl/constants.h +++ b/hw/xbox/nv2a/pgraph/gl/constants.h @@ -298,7 +298,7 @@ static const SurfaceFormatInfo kelvin_surface_color_format_gl_map[] = { [NV097_SET_SURFACE_FORMAT_COLOR_LE_B8] = {1, GL_R8, GL_RED, GL_UNSIGNED_BYTE, GL_COLOR_ATTACHMENT0}, [NV097_SET_SURFACE_FORMAT_COLOR_LE_G8B8] = - {2, GL_RG8, GL_RG, GL_UNSIGNED_SHORT, GL_COLOR_ATTACHMENT0}, + {2, GL_RG8, GL_RG, GL_UNSIGNED_BYTE, GL_COLOR_ATTACHMENT0}, }; static const SurfaceFormatInfo kelvin_surface_zeta_float_format_gl_map[] = { From 1f876ce0da6e1b6b2396db494e10b8c0b5db8bb0 Mon Sep 17 00:00:00 2001 From: Erik Abair Date: Wed, 16 Apr 2025 09:22:56 -0700 Subject: [PATCH 44/80] build.sh: Add xemu_version fallback to macOS builds --- build.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/build.sh b/build.sh index d84b67ee4b..81fca2fb59 100755 --- a/build.sh +++ b/build.sh @@ -66,8 +66,14 @@ package_macos() { cp Info.plist dist/xemu.app/Contents/ - plutil -replace CFBundleShortVersionString -string $(cat ${project_source_dir}/XEMU_VERSION | cut -f1 -d-) dist/xemu.app/Contents/Info.plist - plutil -replace CFBundleVersion -string $(cat ${project_source_dir}/XEMU_VERSION | cut -f1 -d-) dist/xemu.app/Contents/Info.plist + if [[ -e "${project_source_dir}/XEMU_VERSION" ]]; then + xemu_version="$(cat ${project_source_dir}/XEMU_VERSION | cut -f1 -d-)" + else + xemu_version="0.0.0" + fi + + plutil -replace CFBundleShortVersionString -string "${xemu_version}" dist/xemu.app/Contents/Info.plist + plutil -replace CFBundleVersion -string "${xemu_version}" dist/xemu.app/Contents/Info.plist codesign --force --deep --preserve-metadata=entitlements,requirements,flags,runtime --sign - "${exe_path}" python3 ./scripts/gen-license.py --version-file=macos-libs/$target_arch/INSTALLED > dist/LICENSE.txt From 86c85023e6f970a20c559f717a21dc263ed69dd6 Mon Sep 17 00:00:00 2001 From: Erik Abair Date: Wed, 16 Apr 2025 08:15:07 -0700 Subject: [PATCH 45/80] nv2a: Handle SET_FOG_COORD and SET_WEIGHT* commands --- hw/xbox/nv2a/nv2a_regs.h | 5 ++++ hw/xbox/nv2a/pgraph/methods.h.inc | 5 ++++ hw/xbox/nv2a/pgraph/pgraph.c | 47 ++++++++++++++++++++++++++++++- 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/hw/xbox/nv2a/nv2a_regs.h b/hw/xbox/nv2a/nv2a_regs.h index fa62536181..99fd3ee526 100644 --- a/hw/xbox/nv2a/nv2a_regs.h +++ b/hw/xbox/nv2a/nv2a_regs.h @@ -1099,6 +1099,11 @@ # define NV097_SET_TEXCOORD3_4F 0x00001620 # define NV097_SET_TEXCOORD3_2S 0x00001610 # define NV097_SET_TEXCOORD3_4S 0x00001630 +# define NV097_SET_FOG_COORD 0x00001698 +# define NV097_SET_WEIGHT1F 0x0000169C +# define NV097_SET_WEIGHT2F 0x000016A0 +# define NV097_SET_WEIGHT3F 0x000016B0 +# define NV097_SET_WEIGHT4F 0x000016C0 # define NV097_SET_VERTEX_DATA_ARRAY_OFFSET 0x00001720 # define NV097_SET_VERTEX_DATA_ARRAY_FORMAT 0x00001760 # define NV097_SET_VERTEX_DATA_ARRAY_FORMAT_TYPE 0x0000000F diff --git a/hw/xbox/nv2a/pgraph/methods.h.inc b/hw/xbox/nv2a/pgraph/methods.h.inc index fd6184426e..d2892c5501 100644 --- a/hw/xbox/nv2a/pgraph/methods.h.inc +++ b/hw/xbox/nv2a/pgraph/methods.h.inc @@ -134,6 +134,11 @@ DEF_METHOD_RANGE(NV097, SET_TEXCOORD3_2F, 2) DEF_METHOD_RANGE(NV097, SET_TEXCOORD3_4F, 4) DEF_METHOD_RANGE(NV097, SET_TEXCOORD3_2S, 1) DEF_METHOD_RANGE(NV097, SET_TEXCOORD3_4S, 2) +DEF_METHOD(NV097, SET_FOG_COORD) +DEF_METHOD(NV097, SET_WEIGHT1F) +DEF_METHOD_RANGE(NV097, SET_WEIGHT2F, 2) +DEF_METHOD_RANGE(NV097, SET_WEIGHT3F, 3) +DEF_METHOD_RANGE(NV097, SET_WEIGHT4F, 4) DEF_METHOD_RANGE(NV097, SET_VERTEX_DATA_ARRAY_FORMAT, 16) DEF_METHOD_RANGE(NV097, SET_VERTEX_DATA_ARRAY_OFFSET, 16) DEF_METHOD(NV097, SET_LOGIC_OP_ENABLE) diff --git a/hw/xbox/nv2a/pgraph/pgraph.c b/hw/xbox/nv2a/pgraph/pgraph.c index 0f17fde184..14de8a78ff 100644 --- a/hw/xbox/nv2a/pgraph/pgraph.c +++ b/hw/xbox/nv2a/pgraph/pgraph.c @@ -2010,6 +2010,26 @@ DEF_METHOD_INC(NV097, SET_VERTEX4F) } } +DEF_METHOD(NV097, SET_FOG_COORD) +{ + VertexAttribute *attribute = &pg->vertex_attributes[NV2A_VERTEX_ATTR_FOG]; + pgraph_allocate_inline_buffer_vertices(pg, NV2A_VERTEX_ATTR_FOG); + attribute->inline_value[0] = *(float*)¶meter; + attribute->inline_value[1] = attribute->inline_value[0]; + attribute->inline_value[2] = attribute->inline_value[0]; + attribute->inline_value[3] = attribute->inline_value[0]; +} + +DEF_METHOD(NV097, SET_WEIGHT1F) +{ + VertexAttribute *attribute = &pg->vertex_attributes[NV2A_VERTEX_ATTR_WEIGHT]; + pgraph_allocate_inline_buffer_vertices(pg, NV2A_VERTEX_ATTR_WEIGHT); + attribute->inline_value[0] = *(float*)¶meter; + attribute->inline_value[1] = 0.f; + attribute->inline_value[2] = 0.f; + attribute->inline_value[3] = 1.f; +} + DEF_METHOD_INC(NV097, SET_NORMAL3S) { int slot = (method - NV097_SET_NORMAL3S) / 4; @@ -2144,7 +2164,6 @@ DEF_METHOD_INC(NV097, SET_TEXCOORD1_4F) SET_VERTEX_ATTRIBUTE_F(NV097_SET_TEXCOORD1_4F, NV2A_VERTEX_ATTR_TEXTURE1); } - DEF_METHOD_INC(NV097, SET_TEXCOORD2_4F) { SET_VERTEX_ATTRIBUTE_F(NV097_SET_TEXCOORD2_4F, NV2A_VERTEX_ATTR_TEXTURE2); @@ -2155,8 +2174,34 @@ DEF_METHOD_INC(NV097, SET_TEXCOORD3_4F) SET_VERTEX_ATTRIBUTE_F(NV097_SET_TEXCOORD3_4F, NV2A_VERTEX_ATTR_TEXTURE3); } +DEF_METHOD_INC(NV097, SET_WEIGHT4F) +{ + SET_VERTEX_ATTRIBUTE_F(NV097_SET_WEIGHT4F, NV2A_VERTEX_ATTR_WEIGHT); +} + #undef SET_VERTEX_ATTRIBUTE_F +DEF_METHOD_INC(NV097, SET_WEIGHT2F) +{ + int slot = (method - NV097_SET_WEIGHT2F) / 4; + VertexAttribute *attribute = + &pg->vertex_attributes[NV2A_VERTEX_ATTR_WEIGHT]; + pgraph_allocate_inline_buffer_vertices(pg, NV2A_VERTEX_ATTR_WEIGHT); + attribute->inline_value[slot] = *(float*)¶meter; + attribute->inline_value[2] = 0.0f; + attribute->inline_value[3] = 1.0f; +} + +DEF_METHOD_INC(NV097, SET_WEIGHT3F) +{ + int slot = (method - NV097_SET_WEIGHT3F) / 4; + VertexAttribute *attribute = + &pg->vertex_attributes[NV2A_VERTEX_ATTR_WEIGHT]; + pgraph_allocate_inline_buffer_vertices(pg, NV2A_VERTEX_ATTR_WEIGHT); + attribute->inline_value[slot] = *(float*)¶meter; + attribute->inline_value[3] = 1.0f; +} + #define SET_VERTEX_ATRIBUTE_TEX_2F(command, attr_index) \ do { \ int slot = (method - (command)) / 4; \ From 7a34eedd6fe699dc7d55686e005d1d4205e8ad8c Mon Sep 17 00:00:00 2001 From: Erik Abair Date: Wed, 26 Mar 2025 14:10:06 -0700 Subject: [PATCH 46/80] nv2a: Partially handle SET_LIGHT_CONTROL --- hw/xbox/nv2a/nv2a_regs.h | 7 +++++++ hw/xbox/nv2a/pgraph/glsl/vsh-ff.c | 20 ++++++++++++++++---- hw/xbox/nv2a/pgraph/glsl/vsh.c | 7 +++++++ hw/xbox/nv2a/pgraph/methods.h.inc | 1 + hw/xbox/nv2a/pgraph/pgraph.c | 12 ++++++++++++ hw/xbox/nv2a/pgraph/shaders.c | 5 +++++ hw/xbox/nv2a/pgraph/shaders.h | 3 +++ 7 files changed, 51 insertions(+), 4 deletions(-) diff --git a/hw/xbox/nv2a/nv2a_regs.h b/hw/xbox/nv2a/nv2a_regs.h index 99fd3ee526..0990d635fe 100644 --- a/hw/xbox/nv2a/nv2a_regs.h +++ b/hw/xbox/nv2a/nv2a_regs.h @@ -315,11 +315,14 @@ #define NV_PGRAPH_CSV0_C 0x00000FB8 # define NV_PGRAPH_CSV0_C_CHEOPS_PROGRAM_START 0x0000FF00 # define NV_PGRAPH_CSV0_C_SPECULAR_ENABLE (1 << 16) +# define NV_PGRAPH_CSV0_C_ALPHA_FROM_MATERIAL_SPECULAR (1 << 17) +# define NV_PGRAPH_CSV0_C_SEPARATE_SPECULAR (1 << 18) # define NV_PGRAPH_CSV0_C_SPECULAR (3 << 19) # define NV_PGRAPH_CSV0_C_DIFFUSE (3 << 21) # define NV_PGRAPH_CSV0_C_AMBIENT (3 << 23) # define NV_PGRAPH_CSV0_C_EMISSION (3 << 25) # define NV_PGRAPH_CSV0_C_NORMALIZATION_ENABLE (1 << 27) +# define NV_PGRAPH_CSV0_C_LOCALEYE (1 << 30) # define NV_PGRAPH_CSV0_C_LIGHTING (1 << 31) #define NV_PGRAPH_CSV1_B 0x00000FBC #define NV_PGRAPH_CSV1_A 0x00000FC0 @@ -882,6 +885,10 @@ # define NV097_SET_CONTROL0_STENCIL_WRITE_ENABLE (1 << 0) # define NV097_SET_CONTROL0_Z_FORMAT (1 << 12) # define NV097_SET_CONTROL0_Z_PERSPECTIVE_ENABLE (1 << 16) +# define NV097_SET_LIGHT_CONTROL 0x00000294 +# define NV097_SET_LIGHT_CONTROL_SEPARATE_SPECULAR 1 +# define NV097_SET_LIGHT_CONTROL_LOCALEYE (1 << 16) +# define NV097_SET_LIGHT_CONTROL_ALPHA_FROM_MATERIAL_SPECULAR (1 << 17) # define NV097_SET_COLOR_MATERIAL 0x00000298 # define NV097_SET_FOG_MODE 0x0000029C # define NV097_SET_FOG_MODE_V_LINEAR 0x2601 diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c index 19ebf12f3b..52e6296791 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c @@ -384,13 +384,25 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz mstring_append(body, " oD1 = specular;\n"); } - if (!state->specular_enable) { - mstring_append(body, " oD1 = vec4(0.0, 0.0, 0.0, 1.0);\n"); - } - mstring_append(body, " oB0 = backDiffuse;\n"); mstring_append(body, " oB1 = backSpecular;\n"); + if (!state->specular_enable) { + mstring_append(body, " oD1 = vec4(0.0, 0.0, 0.0, 1.0);\n"); + mstring_append(body, " oB1 = vec4(0.0, 0.0, 0.0, 1.0);\n"); + } else { + if (!state->separate_specular) { + mstring_append(body, " oD1 = specular;\n"); + mstring_append(body, " oB1 = backSpecular;\n"); + } + if (state->ignore_specular_alpha) { + mstring_append(body, + " oD1.w = 1.0;\n" + " oB1.a = 1.0;\n" + ); + } + } + /* Fog */ if (state->fog_enable) { diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh.c b/hw/xbox/nv2a/pgraph/glsl/vsh.c index 5fff5cf410..25c846bbde 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh.c @@ -256,6 +256,13 @@ MString *pgraph_gen_vsh_glsl(const ShaderState *state, bool prefix_outputs) " vtxD1 = clamp(oD1, 0.0, 1.0);\n" " vtxB1 = clamp(oB1, 0.0, 1.0);\n" ); + + if (state->ignore_specular_alpha) { + mstring_append(body, + " vtxD1.w = 1.0;\n" + " vtxB1.w = 1.0;\n" + ); + } } else { mstring_append(body, " vtxD1 = vec4(0.0, 0.0, 0.0, 1.0);\n" diff --git a/hw/xbox/nv2a/pgraph/methods.h.inc b/hw/xbox/nv2a/pgraph/methods.h.inc index d2892c5501..0b3c014e7d 100644 --- a/hw/xbox/nv2a/pgraph/methods.h.inc +++ b/hw/xbox/nv2a/pgraph/methods.h.inc @@ -27,6 +27,7 @@ DEF_METHOD(NV097, SET_COMBINER_SPECULAR_FOG_CW0) DEF_METHOD(NV097, SET_COMBINER_SPECULAR_FOG_CW1) DEF_METHOD_CASE_4(NV097, SET_TEXTURE_ADDRESS, 64) DEF_METHOD(NV097, SET_CONTROL0) +DEF_METHOD(NV097, SET_LIGHT_CONTROL) DEF_METHOD(NV097, SET_COLOR_MATERIAL) DEF_METHOD(NV097, SET_FOG_MODE) DEF_METHOD(NV097, SET_FOG_GEN_MODE) diff --git a/hw/xbox/nv2a/pgraph/pgraph.c b/hw/xbox/nv2a/pgraph/pgraph.c index 14de8a78ff..fa6d734405 100644 --- a/hw/xbox/nv2a/pgraph/pgraph.c +++ b/hw/xbox/nv2a/pgraph/pgraph.c @@ -1075,6 +1075,18 @@ DEF_METHOD(NV097, SET_CONTROL0) z_perspective); } +DEF_METHOD(NV097, SET_LIGHT_CONTROL) +{ + PG_SET_MASK(NV_PGRAPH_CSV0_C, NV_PGRAPH_CSV0_C_SEPARATE_SPECULAR, + (parameter & NV097_SET_LIGHT_CONTROL_SEPARATE_SPECULAR) != 0); + + PG_SET_MASK(NV_PGRAPH_CSV0_C, NV_PGRAPH_CSV0_C_LOCALEYE, + (parameter & NV097_SET_LIGHT_CONTROL_LOCALEYE) != 0); + + PG_SET_MASK(NV_PGRAPH_CSV0_C, NV_PGRAPH_CSV0_C_ALPHA_FROM_MATERIAL_SPECULAR, + (parameter & NV097_SET_LIGHT_CONTROL_ALPHA_FROM_MATERIAL_SPECULAR) != 0); +} + DEF_METHOD(NV097, SET_COLOR_MATERIAL) { PG_SET_MASK(NV_PGRAPH_CSV0_C, NV_PGRAPH_CSV0_C_EMISSION, diff --git a/hw/xbox/nv2a/pgraph/shaders.c b/hw/xbox/nv2a/pgraph/shaders.c index dce6d05bb3..ce80dc127a 100644 --- a/hw/xbox/nv2a/pgraph/shaders.c +++ b/hw/xbox/nv2a/pgraph/shaders.c @@ -92,6 +92,11 @@ ShaderState pgraph_get_shader_state(PGRAPHState *pg) pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_SPECULAR); } + state.separate_specular = GET_MASK( + pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_SEPARATE_SPECULAR); + state.ignore_specular_alpha = !GET_MASK( + pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_ALPHA_FROM_MATERIAL_SPECULAR); + /* vertex program stuff */ state.vertex_program = vertex_program, state.z_perspective = pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0) & diff --git a/hw/xbox/nv2a/pgraph/shaders.h b/hw/xbox/nv2a/pgraph/shaders.h index 7ff93a6302..9496cbbea2 100644 --- a/hw/xbox/nv2a/pgraph/shaders.h +++ b/hw/xbox/nv2a/pgraph/shaders.h @@ -79,6 +79,9 @@ typedef struct ShaderState { enum MaterialColorSource diffuse_src; enum MaterialColorSource specular_src; + bool separate_specular; + bool ignore_specular_alpha; + bool lighting; enum VshLight light[NV2A_MAX_LIGHTS]; From 69c8df2a3e3e342e3ef99c817638b6c7793bd6fb Mon Sep 17 00:00:00 2001 From: Erik Abair Date: Sat, 29 Mar 2025 11:40:57 -0700 Subject: [PATCH 47/80] nv2a: Partial implementation of SET_SPECULAR_PARAMS --- hw/xbox/nv2a/nv2a_regs.h | 2 + hw/xbox/nv2a/pgraph/gl/renderer.h | 1 + hw/xbox/nv2a/pgraph/gl/shaders.c | 7 ++ hw/xbox/nv2a/pgraph/glsl/vsh-ff.c | 66 ++++++++++------- hw/xbox/nv2a/pgraph/methods.h.inc | 2 + hw/xbox/nv2a/pgraph/pgraph.c | 118 ++++++++++++++++++++++++++++++ hw/xbox/nv2a/pgraph/pgraph.h | 5 ++ hw/xbox/nv2a/pgraph/shaders.c | 3 + hw/xbox/nv2a/pgraph/shaders.h | 2 + hw/xbox/nv2a/pgraph/vk/renderer.h | 1 + 10 files changed, 181 insertions(+), 26 deletions(-) diff --git a/hw/xbox/nv2a/nv2a_regs.h b/hw/xbox/nv2a/nv2a_regs.h index 0990d635fe..0c0fb70eef 100644 --- a/hw/xbox/nv2a/nv2a_regs.h +++ b/hw/xbox/nv2a/nv2a_regs.h @@ -1056,6 +1056,7 @@ # define NV097_SET_TEXGEN_VIEW_MODEL_LOCAL_VIEWER 0 # define NV097_SET_TEXGEN_VIEW_MODEL_INFINITE_VIEWER 1 # define NV097_SET_FOG_PLANE 0x000009D0 +# define NV097_SET_SPECULAR_PARAMS 0x000009E0 # define NV097_SET_SCENE_AMBIENT_COLOR 0x00000A10 # define NV097_SET_VIEWPORT_OFFSET 0x00000A20 # define NV097_SET_POINT_PARAMS 0x00000A30 @@ -1264,6 +1265,7 @@ # define NV097_SET_CLEAR_RECT_HORIZONTAL 0x00001D98 # define NV097_SET_CLEAR_RECT_VERTICAL 0x00001D9C # define NV097_SET_SPECULAR_FOG_FACTOR 0x00001E20 +# define NV097_SET_SPECULAR_PARAMS_BACK 0x00001E28 # define NV097_SET_COMBINER_COLOR_OCW 0x00001E40 # define NV097_SET_COMBINER_CONTROL 0x00001E60 # define NV097_SET_SHADOW_ZSLOPE_THRESHOLD 0x00001E68 diff --git a/hw/xbox/nv2a/pgraph/gl/renderer.h b/hw/xbox/nv2a/pgraph/gl/renderer.h index 3529006898..89ed6ecfd3 100644 --- a/hw/xbox/nv2a/pgraph/gl/renderer.h +++ b/hw/xbox/nv2a/pgraph/gl/renderer.h @@ -122,6 +122,7 @@ typedef struct ShaderBinding { GLint light_infinite_direction_loc[NV2A_MAX_LIGHTS]; GLint light_local_position_loc[NV2A_MAX_LIGHTS]; GLint light_local_attenuation_loc[NV2A_MAX_LIGHTS]; + int specular_power_loc; GLint clip_region_loc[8]; diff --git a/hw/xbox/nv2a/pgraph/gl/shaders.c b/hw/xbox/nv2a/pgraph/gl/shaders.c index ad1c21f4a2..ad2f3e1b9b 100644 --- a/hw/xbox/nv2a/pgraph/gl/shaders.c +++ b/hw/xbox/nv2a/pgraph/gl/shaders.c @@ -193,8 +193,11 @@ static void update_shader_constant_locations(ShaderBinding *binding) if (binding->state.fixed_function) { binding->material_alpha_loc = glGetUniformLocation(binding->gl_program, "material_alpha"); + binding->specular_power_loc = + glGetUniformLocation(binding->gl_program, "specularPower"); } else { binding->material_alpha_loc = -1; + binding->specular_power_loc = -1; } } @@ -836,6 +839,10 @@ static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding, } } + if (binding->specular_power_loc != -1) { + glUniform1f(binding->specular_power_loc, pg->specular_power); + } + /* estimate the viewport by assuming it matches the surface ... */ unsigned int aa_width = 1, aa_height = 1; pgraph_apply_anti_aliasing_factor(pg, &aa_width, &aa_height); diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c index 52e6296791..a26c1fa17f 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c @@ -230,10 +230,16 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz } /* Lighting */ - if (state->lighting) { - + if (!state->lighting) { + mstring_append(body, " oD0 = diffuse;\n"); + mstring_append(body, " oD1 = specular;\n"); + mstring_append(body, " oB0 = backDiffuse;\n"); + mstring_append(body, " oB1 = backSpecular;\n"); + } else { //FIXME: Do 2 passes if we want 2 sided-lighting? + mstring_append_fmt(uniforms, "%sfloat specularPower;\n", u); + static char alpha_source_diffuse[] = "diffuse.a"; static char alpha_source_specular[] = "specular.a"; static char alpha_source_material[] = "material_alpha"; @@ -269,12 +275,6 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz continue; } - /* FIXME: It seems that we only have to handle the surface colors if - * they are not part of the material [= vertex colors]. - * If they are material the cpu will premultiply light - * colors - */ - mstring_append_fmt(body, "/* Light %d */ {\n", i); if (state->light[i] == LIGHT_LOCAL @@ -310,14 +310,10 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz u, i, u, i); mstring_append_fmt(body, " float attenuation = 1.0;\n" - " float nDotVP = max(0.0, dot(tNormal, normalize(vec3(lightInfiniteDirection%d))));\n" - " float nDotHV = max(0.0, dot(tNormal, vec3(lightInfiniteHalfVector%d)));\n", + " float nDotVP = max(0.0, dot(tNormal, normalize(lightInfiniteDirection%d)));\n" + " float nDotHV = max(0.0, dot(tNormal, lightInfiniteHalfVector%d));\n", i, i); - /* FIXME: Do specular */ - - /* FIXME: tBackDiffuse */ - break; case LIGHT_LOCAL: /* Everything done already */ @@ -349,11 +345,11 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz " if (nDotVP == 0.0) {\n" " pf = 0.0;\n" " } else {\n" - " pf = pow(nDotHV, /* specular(l, m, n, l1, m1, n1) */ 0.001);\n" + " pf = pow(nDotHV, specularPower);\n" " }\n" " vec3 lightAmbient = lightAmbientColor(%d) * attenuation;\n" " vec3 lightDiffuse = lightDiffuseColor(%d) * attenuation * nDotVP;\n" - " vec3 lightSpecular = lightSpecularColor(%d) * pf;\n", + " vec3 lightSpecular = lightSpecularColor(%d) * attenuation * pf;\n", i, i, i); mstring_append(body, @@ -374,26 +370,44 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz break; } - mstring_append(body, - " oD1.xyz += specular.xyz * lightSpecular;\n"); + switch (state->specular_src) { + case MATERIAL_COLOR_SRC_MATERIAL: + mstring_append(body, + " oD1.xyz += lightSpecular;\n"); + break; + case MATERIAL_COLOR_SRC_DIFFUSE: + mstring_append(body, + " oD1.xyz += diffuse.xyz * lightSpecular;\n"); + break; + case MATERIAL_COLOR_SRC_SPECULAR: + mstring_append(body, + " oD1.xyz += specular.xyz * lightSpecular;\n"); + break; + } mstring_append(body, "}\n"); } - } else { - mstring_append(body, " oD0 = diffuse;\n"); - mstring_append(body, " oD1 = specular;\n"); - } - mstring_append(body, " oB0 = backDiffuse;\n"); - mstring_append(body, " oB1 = backSpecular;\n"); + /* TODO: Implement two-sided lighting */ + mstring_append(body, " oB0 = backDiffuse;\n"); + mstring_append(body, " oB1 = backSpecular;\n"); + } if (!state->specular_enable) { mstring_append(body, " oD1 = vec4(0.0, 0.0, 0.0, 1.0);\n"); mstring_append(body, " oB1 = vec4(0.0, 0.0, 0.0, 1.0);\n"); } else { if (!state->separate_specular) { - mstring_append(body, " oD1 = specular;\n"); - mstring_append(body, " oB1 = backSpecular;\n"); + if (state->lighting) { + mstring_append(body, + " oD0.xyz += oD1.xyz;\n" + " oB0.xyz += oB1.xyz;\n" + ); + } + mstring_append(body, + " oD1 = specular;\n" + " oB1 = backSpecular;\n" + ); } if (state->ignore_specular_alpha) { mstring_append(body, diff --git a/hw/xbox/nv2a/pgraph/methods.h.inc b/hw/xbox/nv2a/pgraph/methods.h.inc index 0b3c014e7d..2f7b7b4198 100644 --- a/hw/xbox/nv2a/pgraph/methods.h.inc +++ b/hw/xbox/nv2a/pgraph/methods.h.inc @@ -96,6 +96,7 @@ DEF_METHOD_RANGE(NV097, SET_FOG_PARAMS, 3) DEF_METHOD_RANGE(NV097, SET_TEXGEN_PLANE_S, 4*4*4) DEF_METHOD(NV097, SET_TEXGEN_VIEW_MODEL) DEF_METHOD_RANGE(NV097, SET_FOG_PLANE, 4) +DEF_METHOD_RANGE(NV097, SET_SPECULAR_PARAMS, 6) DEF_METHOD_RANGE(NV097, SET_SCENE_AMBIENT_COLOR, 3) DEF_METHOD_RANGE(NV097, SET_VIEWPORT_OFFSET, 4) DEF_METHOD_RANGE(NV097, SET_POINT_PARAMS, 8) @@ -183,6 +184,7 @@ DEF_METHOD(NV097, CLEAR_SURFACE) DEF_METHOD(NV097, SET_CLEAR_RECT_HORIZONTAL) DEF_METHOD(NV097, SET_CLEAR_RECT_VERTICAL) DEF_METHOD_RANGE(NV097, SET_SPECULAR_FOG_FACTOR, 2) +DEF_METHOD_RANGE(NV097, SET_SPECULAR_PARAMS_BACK, 6) DEF_METHOD(NV097, SET_SHADER_CLIP_PLANE_MODE) DEF_METHOD_RANGE(NV097, SET_COMBINER_COLOR_OCW, 8) DEF_METHOD(NV097, SET_COMBINER_CONTROL) diff --git a/hw/xbox/nv2a/pgraph/pgraph.c b/hw/xbox/nv2a/pgraph/pgraph.c index fa6d734405..feb5f858ca 100644 --- a/hw/xbox/nv2a/pgraph/pgraph.c +++ b/hw/xbox/nv2a/pgraph/pgraph.c @@ -19,6 +19,8 @@ * License along with this library; if not, see . */ +#include + #include "hw/xbox/nv2a/nv2a_int.h" #include "ui/xemu-notifications.h" #include "ui/xemu-settings.h" @@ -1803,6 +1805,113 @@ DEF_METHOD_INC(NV097, SET_FOG_PLANE) pg->vsh_constants_dirty[NV_IGRAPH_XF_XFCTX_FOG] = true; } +struct CurveCoefficients { + float a; + float b; + float c; +}; + +static const struct CurveCoefficients curve_coefficients[] = { + {1.000108475163, -9.838607076280, 54.829089549713}, + {1.199164441703, -3.292603784852, 7.799987995214}, + {8.653441252033, 29.189473787191, 43.586027561823}, + {-531.307758450301, 117.398468683934, 113.155490738338}, + {-4.662713151292, 1.221108944572, 1.217360986939}, + {-124.435242105211, 35.401219563514, 35.408114377045}, + {10672560.259502287954, 21565843.555823743343, 10894794.336297152564}, + {-51973801.463933646679, -104199997.554352939129, -52225454.356278456748}, + {972270.324080004124, 2025882.096547174733, 1054898.052467488218}, +}; + +static const float kCoefficient0StepPoints[] = { + -0.022553957999, // power = 1.25 + -0.421539008617, // power = 4.00 + -0.678715527058, // power = 9.00 + -0.838916420937, // power = 20.00 + -0.961754500866, // power = 90.00 + -0.990773200989, // power = 375.00 + -0.994858562946, // power = 650.00 + -0.996561050415, // power = 1000.00 + -0.999547004700, // power = 1250.00 +}; + +static float reconstruct_quadratic(float c0, const struct CurveCoefficients *coefficients) { + return coefficients->a + coefficients->b * c0 + coefficients->c * c0 * c0; +} + +static float reconstruct_saturation_growth_rate(float c0, const struct CurveCoefficients *coefficients) { + return (coefficients->a * c0) / (coefficients->b + coefficients->c * c0); +} + +static float (* const reconstruct_func_map[])(float, const struct CurveCoefficients *) = { + reconstruct_quadratic, // 1.0..1.25 max error 0.01 % + reconstruct_quadratic, // 1.25..4.0 max error 2.2 % + reconstruct_quadratic, // 4.0..9.0 max error 2.3 % + reconstruct_saturation_growth_rate, // 9.0..20.0 max error 1.4 % + reconstruct_saturation_growth_rate, // 20.0..90.0 max error 2.1 % + reconstruct_saturation_growth_rate, // 90.0..375.0 max error 2.8% + reconstruct_quadratic, // 375..650 max error 1.0 % + reconstruct_quadratic, // 650..1000 max error 1.7% + reconstruct_quadratic, // 1000..1250 max error 1.0% +}; + +static float reconstruct_specular_power(const float *params) { + // See https://github.com/dracc/xgu/blob/db3172d8c983629f0dc971092981846da22438ae/xgux.h#L279 + + // Values < 1.0 will result in a positive c1 and (c2 - c0 * 2) will be very + // close to the original value. + if (params[1] > 0.0f && params[2] < 1.0f) { + return params[2] - (params[0] * 2.0f); + } + + float c0 = params[0]; + float c3 = params[3]; + // FIXME: This handling is not correct, but is distinct without crashing. + // It does not appear possible for a DirectX-generated value to be positive, + // so while this differs from hardware behavior, it may be irrelevant in + // practice. + if (c0 > 0.0f || c3 > 0.0f) { + return 0.0001f; + } + + float reconstructed_power = 0.f; + for (uint32_t i = 0; i < sizeof(kCoefficient0StepPoints) / sizeof(kCoefficient0StepPoints[0]); ++i) { + if (c0 > kCoefficient0StepPoints[i]) { + reconstructed_power = reconstruct_func_map[i](c0, &curve_coefficients[i]); + break; + } + } + + float reconstructed_half_power = 0.f; + for (uint32_t i = 0; i < sizeof(kCoefficient0StepPoints) / sizeof(kCoefficient0StepPoints[0]); ++i) { + if (c3 > kCoefficient0StepPoints[i]) { + reconstructed_half_power = reconstruct_func_map[i](c3, &curve_coefficients[i]); + break; + } + } + + // The range can be extended beyond 1250 by using the half power params. This + // will only work for DirectX generated values, arbitrary params could + // erroneously trigger this. + // + // There are some very low power (~1) values that have inverted powers, but + // they are easily identified by comparatively high c0 parameters. + if (reconstructed_power == 0.f || (reconstructed_half_power > reconstructed_power && c0 < -0.1f)) { + return reconstructed_half_power * 2.f; + } + + return reconstructed_power; +} + +DEF_METHOD_INC(NV097, SET_SPECULAR_PARAMS) +{ + int slot = (method - NV097_SET_SPECULAR_PARAMS) / 4; + pg->specular_params[slot] = *(float *)¶meter; + if (slot == 5) { + pg->specular_power = reconstruct_specular_power(pg->specular_params); + } +} + DEF_METHOD_INC(NV097, SET_SCENE_AMBIENT_COLOR) { int slot = (method - NV097_SET_SCENE_AMBIENT_COLOR) / 4; @@ -2785,6 +2894,15 @@ DEF_METHOD_INC(NV097, SET_SPECULAR_FOG_FACTOR) pgraph_reg_w(pg, NV_PGRAPH_SPECFOGFACTOR0 + slot*4, parameter); } +DEF_METHOD_INC(NV097, SET_SPECULAR_PARAMS_BACK) +{ + int slot = (method - NV097_SET_SPECULAR_PARAMS_BACK) / 4; + pg->specular_params_back[slot] = *(float *)¶meter; + if (slot == 5) { + pg->specular_power_back = reconstruct_specular_power(pg->specular_params_back); + } +} + DEF_METHOD(NV097, SET_SHADER_CLIP_PLANE_MODE) { pgraph_reg_w(pg, NV_PGRAPH_SHADERCLIPMODE, parameter); diff --git a/hw/xbox/nv2a/pgraph/pgraph.h b/hw/xbox/nv2a/pgraph/pgraph.h index 64b671e71d..c74e370bba 100644 --- a/hw/xbox/nv2a/pgraph/pgraph.h +++ b/hw/xbox/nv2a/pgraph/pgraph.h @@ -197,6 +197,11 @@ typedef struct PGRAPHState { float light_local_position[NV2A_MAX_LIGHTS][3]; float light_local_attenuation[NV2A_MAX_LIGHTS][3]; + float specular_params[6]; + float specular_power; + float specular_params_back[6]; + float specular_power_back; + float point_params[8]; VertexAttribute vertex_attributes[NV2A_VERTEXSHADER_ATTRIBUTES]; diff --git a/hw/xbox/nv2a/pgraph/shaders.c b/hw/xbox/nv2a/pgraph/shaders.c index ce80dc127a..79f66026d9 100644 --- a/hw/xbox/nv2a/pgraph/shaders.c +++ b/hw/xbox/nv2a/pgraph/shaders.c @@ -97,6 +97,9 @@ ShaderState pgraph_get_shader_state(PGRAPHState *pg) state.ignore_specular_alpha = !GET_MASK( pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_ALPHA_FROM_MATERIAL_SPECULAR); + state.specular_power = pg->specular_power; + state.specular_power_back = pg->specular_power_back; + /* vertex program stuff */ state.vertex_program = vertex_program, state.z_perspective = pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0) & diff --git a/hw/xbox/nv2a/pgraph/shaders.h b/hw/xbox/nv2a/pgraph/shaders.h index 9496cbbea2..b384b679bf 100644 --- a/hw/xbox/nv2a/pgraph/shaders.h +++ b/hw/xbox/nv2a/pgraph/shaders.h @@ -81,6 +81,8 @@ typedef struct ShaderState { bool separate_specular; bool ignore_specular_alpha; + float specular_power; + float specular_power_back; bool lighting; enum VshLight light[NV2A_MAX_LIGHTS]; diff --git a/hw/xbox/nv2a/pgraph/vk/renderer.h b/hw/xbox/nv2a/pgraph/vk/renderer.h index eb0726ac2f..d728805475 100644 --- a/hw/xbox/nv2a/pgraph/vk/renderer.h +++ b/hw/xbox/nv2a/pgraph/vk/renderer.h @@ -190,6 +190,7 @@ typedef struct ShaderBinding { int light_infinite_direction_loc[NV2A_MAX_LIGHTS]; int light_local_position_loc[NV2A_MAX_LIGHTS]; int light_local_attenuation_loc[NV2A_MAX_LIGHTS]; + int specular_power_loc; int clip_region_loc; From 34ed0f75dea71a4479bacb4ae73207dee5d41e83 Mon Sep 17 00:00:00 2001 From: Erik Abair Date: Sun, 30 Mar 2025 18:08:02 -0700 Subject: [PATCH 48/80] nv2a: Handle LOCAL_RANGE --- hw/xbox/nv2a/pgraph/glsl/vsh-ff.c | 84 ++++++++++++++++--------------- 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c index a26c1fa17f..74ee67c4ad 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c @@ -287,15 +287,15 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz mstring_append_fmt(body, " vec3 VP = lightLocalPosition%d - tPosition.xyz/tPosition.w;\n" " float d = length(VP);\n" -//FIXME: if (d > lightLocalRange) { .. don't process this light .. } /* inclusive?! */ - what about directional lights? - " VP = normalize(VP);\n" - " float attenuation = 1.0 / (lightLocalAttenuation%d.x\n" - " + lightLocalAttenuation%d.y * d\n" - " + lightLocalAttenuation%d.z * d * d);\n" - " vec3 halfVector = normalize(VP + eyePosition.xyz / eyePosition.w);\n" /* FIXME: Not sure if eyePosition is correct */ - " float nDotVP = max(0.0, dot(tNormal, VP));\n" - " float nDotHV = max(0.0, dot(tNormal, halfVector));\n", - i, i, i, i); + " if (d <= lightLocalRange(%d)) {\n" /* FIXME: Double check that range is inclusive */ + " VP = normalize(VP);\n" + " float attenuation = 1.0 / (lightLocalAttenuation%d.x\n" + " + lightLocalAttenuation%d.y * d\n" + " + lightLocalAttenuation%d.z * d * d);\n" + " vec3 halfVector = normalize(VP + eyePosition.xyz / eyePosition.w);\n" /* FIXME: Not sure if eyePosition is correct */ + " float nDotVP = max(0.0, dot(tNormal, VP));\n" + " float nDotHV = max(0.0, dot(tNormal, halfVector));\n", + i, i, i, i, i); } @@ -309,9 +309,10 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz "%svec3 lightInfiniteDirection%d;\n", u, i, u, i); mstring_append_fmt(body, - " float attenuation = 1.0;\n" - " float nDotVP = max(0.0, dot(tNormal, normalize(lightInfiniteDirection%d)));\n" - " float nDotHV = max(0.0, dot(tNormal, lightInfiniteHalfVector%d));\n", + " {\n" + " float attenuation = 1.0;\n" + " float nDotVP = max(0.0, dot(tNormal, normalize(lightInfiniteDirection%d)));\n" + " float nDotHV = max(0.0, dot(tNormal, lightInfiniteHalfVector%d));\n", i, i); break; @@ -321,18 +322,18 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz case LIGHT_SPOT: /* https://docs.microsoft.com/en-us/windows/win32/direct3d9/attenuation-and-spotlight-factor#spotlight-factor */ mstring_append_fmt(body, - " vec4 spotDir = lightSpotDirection(%d);\n" - " float invScale = 1/length(spotDir.xyz);\n" - " float cosHalfPhi = -invScale*spotDir.w;\n" - " float cosHalfTheta = invScale + cosHalfPhi;\n" - " float spotDirDotVP = dot(spotDir.xyz, VP);\n" - " float rho = invScale*spotDirDotVP;\n" - " if (rho > cosHalfTheta) {\n" - " } else if (rho <= cosHalfPhi) {\n" - " attenuation = 0.0;\n" - " } else {\n" - " attenuation *= spotDirDotVP + spotDir.w;\n" /* FIXME: lightSpotFalloff */ - " }\n", + " vec4 spotDir = lightSpotDirection(%d);\n" + " float invScale = 1/length(spotDir.xyz);\n" + " float cosHalfPhi = -invScale*spotDir.w;\n" + " float cosHalfTheta = invScale + cosHalfPhi;\n" + " float spotDirDotVP = dot(spotDir.xyz, VP);\n" + " float rho = invScale*spotDirDotVP;\n" + " if (rho > cosHalfTheta) {\n" + " } else if (rho <= cosHalfPhi) {\n" + " attenuation = 0.0;\n" + " } else {\n" + " attenuation *= spotDirDotVP + spotDir.w;\n" /* FIXME: lightSpotFalloff */ + " }\n", i); break; default: @@ -341,51 +342,52 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz } mstring_append_fmt(body, - " float pf;\n" - " if (nDotVP == 0.0) {\n" - " pf = 0.0;\n" - " } else {\n" - " pf = pow(nDotHV, specularPower);\n" - " }\n" - " vec3 lightAmbient = lightAmbientColor(%d) * attenuation;\n" - " vec3 lightDiffuse = lightDiffuseColor(%d) * attenuation * nDotVP;\n" - " vec3 lightSpecular = lightSpecularColor(%d) * attenuation * pf;\n", + " float pf;\n" + " if (nDotVP == 0.0) {\n" + " pf = 0.0;\n" + " } else {\n" + " pf = pow(nDotHV, specularPower);\n" + " }\n" + " vec3 lightAmbient = lightAmbientColor(%d) * attenuation;\n" + " vec3 lightDiffuse = lightDiffuseColor(%d) * attenuation * nDotVP;\n" + " vec3 lightSpecular = lightSpecularColor(%d) * attenuation * pf;\n", i, i, i); mstring_append(body, - " oD0.xyz += lightAmbient;\n"); + " oD0.xyz += lightAmbient;\n"); switch (state->diffuse_src) { case MATERIAL_COLOR_SRC_MATERIAL: mstring_append(body, - " oD0.xyz += lightDiffuse;\n"); + " oD0.xyz += lightDiffuse;\n"); break; case MATERIAL_COLOR_SRC_DIFFUSE: mstring_append(body, - " oD0.xyz += diffuse.xyz * lightDiffuse;\n"); + " oD0.xyz += diffuse.xyz * lightDiffuse;\n"); break; case MATERIAL_COLOR_SRC_SPECULAR: mstring_append(body, - " oD0.xyz += specular.xyz * lightDiffuse;\n"); + " oD0.xyz += specular.xyz * lightDiffuse;\n"); break; } switch (state->specular_src) { case MATERIAL_COLOR_SRC_MATERIAL: mstring_append(body, - " oD1.xyz += lightSpecular;\n"); + " oD1.xyz += lightSpecular;\n"); break; case MATERIAL_COLOR_SRC_DIFFUSE: mstring_append(body, - " oD1.xyz += diffuse.xyz * lightSpecular;\n"); + " oD1.xyz += diffuse.xyz * lightSpecular;\n"); break; case MATERIAL_COLOR_SRC_SPECULAR: mstring_append(body, - " oD1.xyz += specular.xyz * lightSpecular;\n"); + " oD1.xyz += specular.xyz * lightSpecular;\n"); break; } - mstring_append(body, "}\n"); + mstring_append(body, " }\n" + "}\n"); } /* TODO: Implement two-sided lighting */ From 679f6d06bd61ef8cb5c09c663c63bab36e76b899 Mon Sep 17 00:00:00 2001 From: Erik Abair Date: Sun, 30 Mar 2025 21:20:18 -0700 Subject: [PATCH 49/80] nv2a: Handle LOCALEYE light control --- hw/xbox/nv2a/pgraph/glsl/vsh-ff.c | 35 +++++++++++++++++++++++-------- hw/xbox/nv2a/pgraph/shaders.c | 2 ++ hw/xbox/nv2a/pgraph/shaders.h | 1 + 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c index 74ee67c4ad..f1a2956ca0 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c @@ -270,6 +270,12 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz mstring_append(body, "oD1 = vec4(0.0, 0.0, 0.0, specular.a);\n"); + if (state->local_eye) { + mstring_append(body, + "vec3 VPeye = normalize(eyePosition.xyz / eyePosition.w - tPosition.xyz / tPosition.w);\n" + ); + } + for (i = 0; i < NV2A_MAX_LIGHTS; i++) { if (state->light[i] == LIGHT_OFF) { continue; @@ -285,18 +291,20 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz "%svec3 lightLocalAttenuation%d;\n", u, i, u, i); mstring_append_fmt(body, - " vec3 VP = lightLocalPosition%d - tPosition.xyz/tPosition.w;\n" + " vec3 tPos = tPosition.xyz/tPosition.w;\n" + " vec3 VP = lightLocalPosition%d - tPos;\n" " float d = length(VP);\n" " if (d <= lightLocalRange(%d)) {\n" /* FIXME: Double check that range is inclusive */ " VP = normalize(VP);\n" " float attenuation = 1.0 / (lightLocalAttenuation%d.x\n" " + lightLocalAttenuation%d.y * d\n" " + lightLocalAttenuation%d.z * d * d);\n" - " vec3 halfVector = normalize(VP + eyePosition.xyz / eyePosition.w);\n" /* FIXME: Not sure if eyePosition is correct */ + " vec3 halfVector = normalize(VP + %s);\n" " float nDotVP = max(0.0, dot(tNormal, VP));\n" " float nDotHV = max(0.0, dot(tNormal, halfVector));\n", - i, i, i, i, i); - + i, i, i, i, i, + state->local_eye ? "VPeye" : "vec3(0.0, 0.0, 0.0)" + ); } switch(state->light[i]) { @@ -311,10 +319,19 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz mstring_append_fmt(body, " {\n" " float attenuation = 1.0;\n" - " float nDotVP = max(0.0, dot(tNormal, normalize(lightInfiniteDirection%d)));\n" - " float nDotHV = max(0.0, dot(tNormal, lightInfiniteHalfVector%d));\n", - i, i); - + " vec3 lightDirection = normalize(lightInfiniteDirection%d);\n" + " float nDotVP = max(0.0, dot(tNormal, lightDirection));\n", + i); + if (state->local_eye) { + mstring_append(body, + " float nDotHV = max(0.0, dot(tNormal, normalize(lightDirection + VPeye)));\n" + ); + } else { + mstring_append_fmt(body, + " float nDotHV = max(0.0, dot(tNormal, lightInfiniteHalfVector%d));\n", + i + ); + } break; case LIGHT_LOCAL: /* Everything done already */ @@ -413,7 +430,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz } if (state->ignore_specular_alpha) { mstring_append(body, - " oD1.w = 1.0;\n" + " oD1.a = 1.0;\n" " oB1.a = 1.0;\n" ); } diff --git a/hw/xbox/nv2a/pgraph/shaders.c b/hw/xbox/nv2a/pgraph/shaders.c index 79f66026d9..cddbf450f0 100644 --- a/hw/xbox/nv2a/pgraph/shaders.c +++ b/hw/xbox/nv2a/pgraph/shaders.c @@ -96,6 +96,8 @@ ShaderState pgraph_get_shader_state(PGRAPHState *pg) pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_SEPARATE_SPECULAR); state.ignore_specular_alpha = !GET_MASK( pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_ALPHA_FROM_MATERIAL_SPECULAR); + state.local_eye = GET_MASK( + pgraph_reg_r(pg, NV_PGRAPH_CSV0_C), NV_PGRAPH_CSV0_C_LOCALEYE); state.specular_power = pg->specular_power; state.specular_power_back = pg->specular_power_back; diff --git a/hw/xbox/nv2a/pgraph/shaders.h b/hw/xbox/nv2a/pgraph/shaders.h index b384b679bf..4cc07e3a9d 100644 --- a/hw/xbox/nv2a/pgraph/shaders.h +++ b/hw/xbox/nv2a/pgraph/shaders.h @@ -81,6 +81,7 @@ typedef struct ShaderState { bool separate_specular; bool ignore_specular_alpha; + bool local_eye; float specular_power; float specular_power_back; From 5685a6290cfbf7b022ec5e58a8ffb09f664c04e8 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Wed, 16 Apr 2025 20:15:16 -0700 Subject: [PATCH 50/80] nv2a/vk: Set specular power uniform --- hw/xbox/nv2a/pgraph/vk/shaders.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/xbox/nv2a/pgraph/vk/shaders.c b/hw/xbox/nv2a/pgraph/vk/shaders.c index 421a81ba60..5d6e345ffb 100644 --- a/hw/xbox/nv2a/pgraph/vk/shaders.c +++ b/hw/xbox/nv2a/pgraph/vk/shaders.c @@ -313,6 +313,9 @@ static void update_shader_constant_locations(ShaderBinding *binding) binding->uniform_attrs_loc = uniform_index(&binding->vertex->uniforms, "inlineValue"); + + binding->specular_power_loc = + uniform_index(&binding->vertex->uniforms, "specularPower"); } static void shader_cache_entry_init(Lru *lru, LruNode *node, void *state) @@ -607,6 +610,11 @@ static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding, } } + if (binding->specular_power_loc != -1) { + uniform1f(&binding->vertex->uniforms, binding->specular_power_loc, + pg->specular_power); + } + /* estimate the viewport by assuming it matches the surface ... */ unsigned int aa_width = 1, aa_height = 1; pgraph_apply_anti_aliasing_factor(pg, &aa_width, &aa_height); From 270dbe01ea6b36c38f8cf2bc6a66449caa719a01 Mon Sep 17 00:00:00 2001 From: Erik Abair Date: Thu, 17 Apr 2025 22:22:19 -0700 Subject: [PATCH 51/80] nv2a: Increase MAX_BATCH_LENGTH beyond highest known retail use --- hw/xbox/nv2a/nv2a_regs.h | 13 ++++++++++++- hw/xbox/nv2a/pgraph/pgraph.c | 6 +++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/hw/xbox/nv2a/nv2a_regs.h b/hw/xbox/nv2a/nv2a_regs.h index 0c0fb70eef..2bdac1d93f 100644 --- a/hw/xbox/nv2a/nv2a_regs.h +++ b/hw/xbox/nv2a/nv2a_regs.h @@ -1467,7 +1467,18 @@ #define NV2A_NUM_SUBCHANNELS 8 #define NV2A_CACHE1_SIZE 128 -#define NV2A_MAX_BATCH_LENGTH 0x1FFFF +/* This is a multi-use limit. Testing on an Xbox 1.0, it is possible to send + * arrays of at least 0x0FFFFF elements without issue, however sending + * NV097_DRAW_ARRAYS with a start value > 0xFFFF raises an exception implying + * that there may be a vertex limit. Since xemu uses batch length for vertex + * elements in NV097_INLINE_ARRAY the size should ideally be high enough to + * accommodate 0xFFFF vertices with maximum attributes specified. + * + * Retail games are known to send at least 0x410FA elements in a single draw, so + * a somewhat larger value is selected to balance memory use with real-world + * limits. + */ +#define NV2A_MAX_BATCH_LENGTH 0x07FFFF #define NV2A_VERTEXSHADER_ATTRIBUTES 16 #define NV2A_MAX_TEXTURES 4 diff --git a/hw/xbox/nv2a/pgraph/pgraph.c b/hw/xbox/nv2a/pgraph/pgraph.c index feb5f858ca..fc6420fff0 100644 --- a/hw/xbox/nv2a/pgraph/pgraph.c +++ b/hw/xbox/nv2a/pgraph/pgraph.c @@ -2692,7 +2692,11 @@ DEF_METHOD(NV097, DRAW_ARRAYS) int32_t count = GET_MASK(parameter, NV097_DRAW_ARRAYS_COUNT) + 1; if (pg->inline_elements_length) { - /* FIXME: Determine HW behavior for overflow case. */ + /* FIXME: HW throws an exception if the start index is > 0xFFFF. This + * would prevent this assert from firing for any reasonable choice of + * NV2A_MAX_BATCH_LENGTH (which must be larger to accommodate + * NV097_INLINE_ARRAY anyway) + */ assert((pg->inline_elements_length + count) < NV2A_MAX_BATCH_LENGTH); assert(!pg->draw_arrays_prevent_connect); From fee1e58204949b91800772590e6cbb191442f32f Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Fri, 18 Apr 2025 11:21:27 -0700 Subject: [PATCH 52/80] vmstate: Add VMSTATE_UINT32_SUB_ARRAY_V --- include/migration/vmstate.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index f313f2f408..eee7359f2d 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -1085,6 +1085,9 @@ extern const VMStateInfo vmstate_info_qlist; #define VMSTATE_UINT32_SUB_ARRAY(_f, _s, _start, _num) \ VMSTATE_SUB_ARRAY(_f, _s, _start, _num, 0, vmstate_info_uint32, uint32_t) +#define VMSTATE_UINT32_SUB_ARRAY_V(_f, _s, _start, _num, _v) \ + VMSTATE_SUB_ARRAY(_f, _s, _start, _num, _v, vmstate_info_uint32, uint32_t) + #define VMSTATE_UINT32_2DARRAY(_f, _s, _n1, _n2) \ VMSTATE_UINT32_2DARRAY_V(_f, _s, _n1, _n2, 0) From 0c2a6178192043db8b30c4d61a96129b442102f5 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Fri, 18 Apr 2025 11:22:25 -0700 Subject: [PATCH 53/80] nv2a: Bump vmstate version for new NV2A_MAX_BATCH_LENGTH --- hw/xbox/nv2a/nv2a.c | 8 +++++--- hw/xbox/nv2a/nv2a_regs.h | 4 ++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/hw/xbox/nv2a/nv2a.c b/hw/xbox/nv2a/nv2a.c index 0124a0d451..02cfbca3e9 100644 --- a/hw/xbox/nv2a/nv2a.c +++ b/hw/xbox/nv2a/nv2a.c @@ -423,7 +423,7 @@ const VMStateDescription vmstate_nv2a_pgraph_vertex_attributes = { static const VMStateDescription vmstate_nv2a = { .name = "nv2a", - .version_id = 2, + .version_id = 3, .minimum_version_id = 1, .post_save = nv2a_post_save, .post_load = nv2a_post_load, @@ -507,9 +507,11 @@ static const VMStateDescription vmstate_nv2a = { VMSTATE_BOOL_ARRAY(pgraph.ltc1_dirty, NV2AState, NV2A_LTC1_COUNT), VMSTATE_STRUCT_ARRAY(pgraph.vertex_attributes, NV2AState, NV2A_VERTEXSHADER_ATTRIBUTES, 1, vmstate_nv2a_pgraph_vertex_attributes, VertexAttribute), VMSTATE_UINT32(pgraph.inline_array_length, NV2AState), - VMSTATE_UINT32_ARRAY(pgraph.inline_array, NV2AState, NV2A_MAX_BATCH_LENGTH), + VMSTATE_UINT32_SUB_ARRAY(pgraph.inline_array, NV2AState, 0, NV2A_MAX_BATCH_LENGTH_V2), + VMSTATE_UINT32_SUB_ARRAY_V(pgraph.inline_array, NV2AState, NV2A_MAX_BATCH_LENGTH_V2, NV2A_MAX_BATCH_LENGTH - NV2A_MAX_BATCH_LENGTH_V2, 3), VMSTATE_UINT32(pgraph.inline_elements_length, NV2AState), // fixme - VMSTATE_UINT32_ARRAY(pgraph.inline_elements, NV2AState, NV2A_MAX_BATCH_LENGTH), + VMSTATE_UINT32_SUB_ARRAY(pgraph.inline_elements, NV2AState, 0, NV2A_MAX_BATCH_LENGTH_V2), + VMSTATE_UINT32_SUB_ARRAY_V(pgraph.inline_elements, NV2AState, NV2A_MAX_BATCH_LENGTH_V2, NV2A_MAX_BATCH_LENGTH - NV2A_MAX_BATCH_LENGTH_V2, 3), VMSTATE_UINT32(pgraph.inline_buffer_length, NV2AState), // fixme VMSTATE_UINT32(pgraph.draw_arrays_length, NV2AState), VMSTATE_UINT32(pgraph.draw_arrays_max_count, NV2AState), diff --git a/hw/xbox/nv2a/nv2a_regs.h b/hw/xbox/nv2a/nv2a_regs.h index 2bdac1d93f..c1804a2cef 100644 --- a/hw/xbox/nv2a/nv2a_regs.h +++ b/hw/xbox/nv2a/nv2a_regs.h @@ -1477,8 +1477,12 @@ * Retail games are known to send at least 0x410FA elements in a single draw, so * a somewhat larger value is selected to balance memory use with real-world * limits. + * + * NV2A_MAX_BATCH_LENGTH_V2 is the previous limit, for migration. + * FIXME: Remove NV2A_MAX_BATCH_LENGTH_V2 at some point in the future. */ #define NV2A_MAX_BATCH_LENGTH 0x07FFFF +#define NV2A_MAX_BATCH_LENGTH_V2 0x1FFFF #define NV2A_VERTEXSHADER_ATTRIBUTES 16 #define NV2A_MAX_TEXTURES 4 From 1a6b858fe83e6817ed8fa931ad591bf4922b65f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Apr 2025 04:31:22 +0000 Subject: [PATCH 54/80] ci: bump softprops/action-gh-release from 2.2.1 to 2.2.2 Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.2.1 to 2.2.2. - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda...da05d552573ad5aba039eaac05058a918a7bf631) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-version: 2.2.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fb2a6cc123..fb9f70df1f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -420,7 +420,7 @@ jobs: run: | cp dist/xemu-win-x86_64-release-pdb/xemu-win-x86_64-release.zip dist/xemu-win-x86_64-release-pdb/xemu-win-release.zip - name: Publish release - uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda # v2.2.1 + uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2 with: tag_name: v${{ env.XEMU_VERSION }} name: v${{ env.XEMU_VERSION }} From 89185e6937c7d597ba353bc4d4800dde0015ea39 Mon Sep 17 00:00:00 2001 From: Erik Abair Date: Tue, 22 Apr 2025 14:28:31 -0700 Subject: [PATCH 55/80] nv2a/psh: Fix default alpha for unbound texture samplers --- hw/xbox/nv2a/pgraph/glsl/psh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/xbox/nv2a/pgraph/glsl/psh.c b/hw/xbox/nv2a/pgraph/glsl/psh.c index e3a566a347..448281f46c 100644 --- a/hw/xbox/nv2a/pgraph/glsl/psh.c +++ b/hw/xbox/nv2a/pgraph/glsl/psh.c @@ -949,7 +949,7 @@ static MString* psh_convert(struct PixelShader *ps) switch (ps->tex_modes[i]) { case PS_TEXTUREMODES_NONE: - mstring_append_fmt(vars, "vec4 t%d = vec4(0.0); /* PS_TEXTUREMODES_NONE */\n", + mstring_append_fmt(vars, "vec4 t%d = vec4(0.0, 0.0, 0.0, 1.0); /* PS_TEXTUREMODES_NONE */\n", i); break; case PS_TEXTUREMODES_PROJECT2D: { From 362c27b23525f700ee65c2d06538bed53abeb5ba Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Sat, 26 Apr 2025 15:53:02 -0700 Subject: [PATCH 56/80] ci: Auto-update subproject wraps periodically --- .github/workflows/bump-subproject-wraps.yml | 74 ++++++++ scripts/bump-subproject-wraps.py | 197 ++++++++++++++++++++ 2 files changed, 271 insertions(+) create mode 100644 .github/workflows/bump-subproject-wraps.yml create mode 100644 scripts/bump-subproject-wraps.py diff --git a/.github/workflows/bump-subproject-wraps.yml b/.github/workflows/bump-subproject-wraps.yml new file mode 100644 index 0000000000..8eb239d107 --- /dev/null +++ b/.github/workflows/bump-subproject-wraps.yml @@ -0,0 +1,74 @@ +name: Bump Meson subprojects + +on: + workflow_dispatch: + schedule: + - cron: '0 6 * * 1' + +permissions: + contents: write + pull-requests: write + +jobs: + bump_wraps: + name: "Bump Meson subprojects" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + + - name: Install the latest version of uv + uses: astral-sh/setup-uv@c7f87aa956e4c323abf06d5dec078e358f6b4d04 # v6 + with: + enable-cache: false + + - name: Check for updates + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + uv run -s scripts/bump-subproject-wraps.py -m \ + subprojects/curl.wrap \ + subprojects/genconfig.wrap \ + subprojects/glslang.wrap \ + subprojects/imgui.wrap \ + subprojects/implot.wrap \ + subprojects/json.wrap \ + subprojects/nv2a_vsh_cpu.wrap \ + subprojects/SPIRV-Reflect.wrap \ + subprojects/tomlplusplus.wrap \ + subprojects/volk.wrap \ + subprojects/VulkanMemoryAllocator.wrap \ + subprojects/xxhash.wrap \ + > updated.json + + - name: Create PRs for updates + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -euo pipefail + git config user.name "xemu-robot" + git config user.email "robot@xemu.app" + + jq -c '.[]' updated.json | while read -r item; do + path=$(echo "$item" | jq -r '.path') + file_basename=$(basename "$path") + name="${file_basename%%.*}" + + owner=$(echo "$item" | jq -r '.owner') + repo=$(echo "$item" | jq -r '.repo') + old_rev=$(echo "$item" | jq -r '.old_rev') + new_rev=$(echo "$item" | jq -r '.new_rev') + new_tag=$(echo "$item" | jq -r '.new_tag') + + echo "➤ Processing $name" + branch="sync/bump-${name//\//-}-${GITHUB_RUN_ID}" + + git switch --quiet -c "$branch" origin/master + git add "$path" + git commit -m "meson: Bump ${name} to ${new_tag}" + git push -u origin "$branch" + + gh pr create \ + --title "meson: Bump ${name} to ${new_tag}" \ + --body "Automatic bump of \`${name}\` to [${new_tag}](https://github.com/${owner}/${repo}/compare/${old_rev}..${new_rev})." \ + --base master + done diff --git a/scripts/bump-subproject-wraps.py b/scripts/bump-subproject-wraps.py new file mode 100644 index 0000000000..f9768b366a --- /dev/null +++ b/scripts/bump-subproject-wraps.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python +# /// script +# dependencies = ["requests"] +# /// +""" +Update Meson wrap file `revision` fields to point to latest release. +""" +from __future__ import annotations +import argparse +import configparser +import json +import logging +import os +import re +import sys +from pathlib import Path +from dataclasses import dataclass, asdict + +import requests + + +log = logging.getLogger(__name__) + + +SEMVER_RE = re.compile( + r""" + ^v? + (?P0|[1-9]\d*)\. + (?P0|[1-9]\d*)\. + (?P0|[1-9]\d*) + $""", + re.VERBOSE, +) + +ROOT = Path(__file__).resolve().parents[1] +WRAP_DIR = ROOT / "subprojects" +SESSION = requests.Session() +GH_TOKEN = os.getenv("GH_TOKEN", "") +if GH_TOKEN: + SESSION.headers["Authorization"] = f"Bearer {GH_TOKEN}" +SESSION.headers["Accept"] = "application/vnd.github+json" + + +def gh_sha_for_tag(owner: str, repo: str, tag: str) -> str: + data = SESSION.get( + f"https://api.github.com/repos/{owner}/{repo}/git/ref/tags/{tag}", timeout=30 + ).json() + + # First level: get the object it points to + obj_type = data["object"]["type"] + obj_sha = data["object"]["sha"] + + if obj_type == "commit": + # Lightweight tag + return obj_sha + elif obj_type == "tag": + # Annotated tag: need to dereference + tag_obj_url = data["object"]["url"] + tag_data = requests.get(tag_obj_url).json() + return tag_data["object"]["sha"] + else: + raise Exception(f"Unknown object type: {obj_type}") + + +def gh_latest_release( + owner: str, repo: str, pattern: re.Pattern +) -> None | tuple[str, str]: + """ + Return (tag_name, commit_sha) for the most recent matching release. + """ + releases = SESSION.get( + f"https://api.github.com/repos/{owner}/{repo}/releases", timeout=30 + ).json() + viable = [t for t in releases if pattern.match(t["tag_name"])] + + if not viable: + return None + + tag_name = viable[0]["tag_name"] + sha = gh_sha_for_tag(owner, repo, tag_name) + + return tag_name, sha + + +def gh_latest_tag(owner: str, repo: str, pattern: re.Pattern) -> tuple[str, str]: + """ + Return (tag_name, commit_sha) for the most recent matching tag. + """ + tags = SESSION.get( + f"https://api.github.com/repos/{owner}/{repo}/tags", timeout=30 + ).json() + viable = [t for t in tags if pattern.match(t["name"])] + + if not viable: + return None + + return viable[0]["name"], viable[0]["commit"]["sha"] + + +@dataclass +class UpdatedWrap: + path: str + owner: str + repo: str + old_rev: str + new_rev: str + new_tag: str + + +def update_wrap(path: Path) -> None | UpdatedWrap: + """ + Return (tag_name, commit_sha) if updated, otherwise None. + """ + cp = configparser.ConfigParser(interpolation=None) + cp.read(path, encoding="utf-8") + + if "wrap-git" not in cp: + # FIXME: Support wrap-file from wrapdb + return None + + w = cp["wrap-git"] + url = w.get("url", "") + rev = w.get("revision", "").strip() + m = re.match(r".*github\.com[:/](?P[^/]+)/(?P[^/.]+)(?:\.git)?", url) + if not (m and rev): + return None + + owner, repo = m.group("owner"), m.group("repo") + try: + pattern = cp.get("update", "tag_regex", fallback=None) + pattern = re.compile(pattern) if pattern else SEMVER_RE + + latest = gh_latest_release(owner, repo, pattern) + if latest is None: + log.info("Couldn't find latest release for %s/%s", owner, repo) + log.info("Searching for tags directly...") + latest = gh_latest_tag(owner, repo, pattern) + if latest is None: + log.info("Couldn't find latest tag for %s/%s", owner, repo) + return None + tag, sha = latest + except Exception as e: + log.exception(e) + return None + + if sha.startswith(rev): + log.info("%s already at %s (%s)", path.name, tag, sha) + return None + + log.info("%s updated to %s (%s)", path.name, tag, sha) + + w["revision"] = sha + + with open(path, "w", encoding="utf-8") as file: + cp.write(file) + + # XXX: ConfigParser writes two extra newlines. Trim the last one. + file.seek(file.tell() - 1, 0) + file.truncate() + + return UpdatedWrap(str(path), owner, repo, rev, sha, tag) + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument( + "--manifest", + "-m", + action="store_true", + default=False, + help="Print JSON-formatted updated manifest", + ) + ap.add_argument( + "wraps", nargs="*", help="Which wraps to update, or all if unspecified" + ) + args = ap.parse_args() + + wraps = args.wraps + if wraps: + wraps = [Path(p) for p in wraps] + else: + wraps = WRAP_DIR.glob("*.wrap") + + logging.basicConfig(level=logging.INFO) + + updated = [] + for wrap in wraps: + info = update_wrap(wrap) + if info: + updated.append(asdict(info)) + + if args.manifest: + json.dump(updated, sys.stdout, indent=2) + + +if __name__ == "__main__": + main() From c035ff9f5d5a74e35fe9d76640910432a3943bc2 Mon Sep 17 00:00:00 2001 From: xemu-robot Date: Sat, 26 Apr 2025 23:03:30 +0000 Subject: [PATCH 57/80] meson: Bump VulkanMemoryAllocator to v3.2.1 --- subprojects/VulkanMemoryAllocator.wrap | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subprojects/VulkanMemoryAllocator.wrap b/subprojects/VulkanMemoryAllocator.wrap index b5f1c7f217..56550f5c96 100644 --- a/subprojects/VulkanMemoryAllocator.wrap +++ b/subprojects/VulkanMemoryAllocator.wrap @@ -1,4 +1,4 @@ [wrap-git] -url=https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator -revision=v3.2.1 -depth=1 +url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator +revision = c788c52156f3ef7bc7ab769cb03c110a53ac8fcb +depth = 1 From 1e1ef6fbb9492c5e9b8d43bd2bc07b5bd6ff8df1 Mon Sep 17 00:00:00 2001 From: xemu-robot Date: Sat, 26 Apr 2025 23:03:29 +0000 Subject: [PATCH 58/80] meson: Bump volk to 1.4.304 --- subprojects/volk.wrap | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subprojects/volk.wrap b/subprojects/volk.wrap index 46578b64ce..1cb25819be 100644 --- a/subprojects/volk.wrap +++ b/subprojects/volk.wrap @@ -1,4 +1,4 @@ [wrap-git] -url=https://github.com/zeux/volk -revision=1.4.304 -depth=1 +url = https://github.com/zeux/volk +revision = 0b17a763ba5643e32da1b2152f8140461b3b7345 +depth = 1 From c4b554fd80f218155efeb42b44a5a3e4ab031d24 Mon Sep 17 00:00:00 2001 From: mborgerson Date: Sat, 26 Apr 2025 16:13:13 -0700 Subject: [PATCH 59/80] meson: Add tag regex for subproject wrap auto-updater --- subprojects/SPIRV-Reflect.wrap | 9 ++++++--- subprojects/glslang.wrap | 3 +++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/subprojects/SPIRV-Reflect.wrap b/subprojects/SPIRV-Reflect.wrap index bdc1486c5c..784ee56af5 100644 --- a/subprojects/SPIRV-Reflect.wrap +++ b/subprojects/SPIRV-Reflect.wrap @@ -1,4 +1,7 @@ [wrap-git] -url=https://github.com/KhronosGroup/SPIRV-Reflect -revision=vulkan-sdk-1.4.309.0 -depth=1 +url = https://github.com/KhronosGroup/SPIRV-Reflect +revision = vulkan-sdk-1.4.309.0 +depth = 1 + +[update] +tag_regex = ^(vulkan-sdk-)?[\d\.]+$ diff --git a/subprojects/glslang.wrap b/subprojects/glslang.wrap index 9aa182135a..96edb2d7ba 100644 --- a/subprojects/glslang.wrap +++ b/subprojects/glslang.wrap @@ -2,3 +2,6 @@ url=https://github.com/KhronosGroup/glslang revision=vulkan-sdk-1.4.309.0 depth=1 + +[update] +tag_regex = ^(vulkan-sdk-)?[\d\.]+$ From 668017518a6da4e335b82bc08d4b3aa9971744c8 Mon Sep 17 00:00:00 2001 From: xemu-robot Date: Sat, 26 Apr 2025 23:03:27 +0000 Subject: [PATCH 60/80] meson: Bump tomlplusplus to v3.4.0 --- subprojects/tomlplusplus.wrap | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subprojects/tomlplusplus.wrap b/subprojects/tomlplusplus.wrap index 4f2d59c52f..7f678ce951 100644 --- a/subprojects/tomlplusplus.wrap +++ b/subprojects/tomlplusplus.wrap @@ -1,4 +1,4 @@ [wrap-git] -url=https://github.com/marzer/tomlplusplus -revision=c635f218c0aefc801d9748841930365e54fe3089 -depth=1 +url = https://github.com/marzer/tomlplusplus +revision = 30172438cee64926dc41fdd9c11fb3ba5b2ba9de +depth = 1 From a3dc07970648b9254bf17192542ded77ffa8a993 Mon Sep 17 00:00:00 2001 From: xemu-robot Date: Sat, 26 Apr 2025 23:21:39 +0000 Subject: [PATCH 61/80] meson: Bump glslang to 15.3.0 --- subprojects/glslang.wrap | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subprojects/glslang.wrap b/subprojects/glslang.wrap index 96edb2d7ba..5eb28687e5 100644 --- a/subprojects/glslang.wrap +++ b/subprojects/glslang.wrap @@ -1,7 +1,7 @@ [wrap-git] -url=https://github.com/KhronosGroup/glslang -revision=vulkan-sdk-1.4.309.0 -depth=1 +url = https://github.com/KhronosGroup/glslang +revision = fc9889c889561c5882e83819dcaffef5ed45529b +depth = 1 [update] tag_regex = ^(vulkan-sdk-)?[\d\.]+$ From 4dfbe29cbd5f45ce0b89467a3e273b963ecf2556 Mon Sep 17 00:00:00 2001 From: xemu-robot Date: Sat, 26 Apr 2025 23:21:42 +0000 Subject: [PATCH 62/80] meson: Bump SPIRV-Reflect to vulkan-sdk-1.4.309.0 --- subprojects/SPIRV-Reflect.wrap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/SPIRV-Reflect.wrap b/subprojects/SPIRV-Reflect.wrap index 784ee56af5..8107b8b7a7 100644 --- a/subprojects/SPIRV-Reflect.wrap +++ b/subprojects/SPIRV-Reflect.wrap @@ -1,6 +1,6 @@ [wrap-git] url = https://github.com/KhronosGroup/SPIRV-Reflect -revision = vulkan-sdk-1.4.309.0 +revision = c637858562fbce1b6f5dc7ca48d4e8a5bd117b70 depth = 1 [update] From 8f89ef14d7c2ea5fd2d6ebf2139add792b612803 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Sat, 26 Apr 2025 16:44:20 -0700 Subject: [PATCH 63/80] ci: Use XEMU_ROBOT_TOKEN for PR creation to trigger build workflow --- .github/workflows/bump-subproject-wraps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bump-subproject-wraps.yml b/.github/workflows/bump-subproject-wraps.yml index 8eb239d107..163d55e259 100644 --- a/.github/workflows/bump-subproject-wraps.yml +++ b/.github/workflows/bump-subproject-wraps.yml @@ -42,7 +42,7 @@ jobs: - name: Create PRs for updates env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ secrets.XEMU_ROBOT_TOKEN }} run: | set -euo pipefail git config user.name "xemu-robot" From 5af43523abf55ce3586014f1d06631ba62351951 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Apr 2025 04:03:11 +0000 Subject: [PATCH 64/80] ci: bump actions/download-artifact from 4.2.1 to 4.3.0 Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4.2.1 to 4.3.0. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/95815c38cf2ff2164869cbab79da8d1f422bc89e...d3f86a106a0bac45b974a628896c90dbdf5c8093) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: 4.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/build.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fb9f70df1f..d55279e8fa 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -83,7 +83,7 @@ jobs: steps: - name: Download source package - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: name: src.tar.gz - name: Extract source package @@ -140,7 +140,7 @@ jobs: arch: aarch64 steps: - name: Download artifacts - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: name: ${{ matrix.artifact_name }} path: ${{ matrix.artifact_name }} @@ -202,7 +202,7 @@ jobs: key: cache-${{ runner.os }}-${{ matrix.arch }}-${{ matrix.configuration }}-${{ github.sha }} restore-keys: cache-${{ runner.os }}-${{ matrix.arch }}-${{ matrix.configuration }}- - name: Download source package - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: name: src.tar.gz - name: Extract source package @@ -305,7 +305,7 @@ jobs: artifact_filename: xemu-macos-arm64-release.zip steps: - name: Download source package - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: name: src.tar.gz - name: Extract source package @@ -358,12 +358,12 @@ jobs: configuration: ["debug", "release"] steps: - name: Download x86_64 build - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: name: xemu-macos-x86_64-${{ matrix.configuration }} path: xemu-macos-x86_64-${{ matrix.configuration }} - name: Download arm64 build - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: name: xemu-macos-arm64-${{ matrix.configuration }} path: xemu-macos-arm64-${{ matrix.configuration }} @@ -398,7 +398,7 @@ jobs: needs: [Ubuntu, macOSUniversal, Windows, WindowsPdb] steps: - name: Download artifacts - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: path: dist - name: Extract source package @@ -462,7 +462,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Download source package - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: name: src.tar.gz - name: Extract source package From 7108c7a37c6b167704ae9f863244a45a43618918 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Apr 2025 04:03:14 +0000 Subject: [PATCH 65/80] ci: bump actions/setup-python from 5.5.0 to 5.6.0 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5.5.0 to 5.6.0. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/v5.5.0...v5.6.0) --- updated-dependencies: - dependency-name: actions/setup-python dependency-version: 5.6.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d55279e8fa..7b57efd6be 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -310,7 +310,7 @@ jobs: name: src.tar.gz - name: Extract source package run: tar xf src.tar.gz - - uses: actions/setup-python@v5.5.0 + - uses: actions/setup-python@v5.6.0 with: python-version: '3.12' - name: Install dependencies From b48f84af792d332be7d48befc03b9e21f2c87b6c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Apr 2025 04:03:17 +0000 Subject: [PATCH 66/80] ci: bump docker/build-push-action from 6.15.0 to 6.16.0 Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.15.0 to 6.16.0. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/471d1dc4e07e5cdedd4c2171150001c434f0b7a4...14487ce63c7a62a4a324b0bfb37086795e31c6c1) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-version: 6.16.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/build-xemu-win64-toolchain.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-xemu-win64-toolchain.yml b/.github/workflows/build-xemu-win64-toolchain.yml index 7a521389a5..346e8fad8d 100644 --- a/.github/workflows/build-xemu-win64-toolchain.yml +++ b/.github/workflows/build-xemu-win64-toolchain.yml @@ -44,7 +44,7 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push image - uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v5 + uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v5 with: context: ubuntu-win64-cross push: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} From 6e513ed94812246cba3b17954f8da049bb41fbcb Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Tue, 29 Apr 2025 23:22:07 -0700 Subject: [PATCH 67/80] nv2a/psh: Fix 2D texture addressing in DOT_STR_3D mode --- hw/xbox/nv2a/pgraph/glsl/psh.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/xbox/nv2a/pgraph/glsl/psh.c b/hw/xbox/nv2a/pgraph/glsl/psh.c index 448281f46c..893a8fbc9d 100644 --- a/hw/xbox/nv2a/pgraph/glsl/psh.c +++ b/hw/xbox/nv2a/pgraph/glsl/psh.c @@ -1123,8 +1123,8 @@ static MString* psh_convert(struct PixelShader *ps) i, i-2, i-1, i); apply_border_adjustment(ps, vars, i, "dotSTR%d"); - mstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, dotSTR%d);\n", - i, i, i); + mstring_append_fmt(vars, "vec4 t%d = texture(texSamp%d, %s(dotSTR%d%s));\n", + i, i, tex_remap, i, ps->state.dim_tex[i] == 2 ? ".xy" : ""); break; case PS_TEXTUREMODES_DOT_STR_CUBE: assert(i == 3); From d59386942947eb7ae3087548bd7e273974af20c4 Mon Sep 17 00:00:00 2001 From: Erik Abair Date: Wed, 30 Apr 2025 23:43:38 -0700 Subject: [PATCH 68/80] nv2a: Move point params to uniforms Co-authored-by: Matt Borgerson --- hw/xbox/nv2a/pgraph/gl/renderer.h | 1 + hw/xbox/nv2a/pgraph/gl/shaders.c | 12 ++++++++++++ hw/xbox/nv2a/pgraph/glsl/vsh-ff.c | 10 ++++------ hw/xbox/nv2a/pgraph/vk/renderer.h | 2 +- hw/xbox/nv2a/pgraph/vk/shaders.c | 8 ++++++++ 5 files changed, 26 insertions(+), 7 deletions(-) diff --git a/hw/xbox/nv2a/pgraph/gl/renderer.h b/hw/xbox/nv2a/pgraph/gl/renderer.h index 89ed6ecfd3..d1a64bb024 100644 --- a/hw/xbox/nv2a/pgraph/gl/renderer.h +++ b/hw/xbox/nv2a/pgraph/gl/renderer.h @@ -126,6 +126,7 @@ typedef struct ShaderBinding { GLint clip_region_loc[8]; + GLint point_params_loc[8]; GLint material_alpha_loc; } ShaderBinding; diff --git a/hw/xbox/nv2a/pgraph/gl/shaders.c b/hw/xbox/nv2a/pgraph/gl/shaders.c index ad2f3e1b9b..af3cfd2f40 100644 --- a/hw/xbox/nv2a/pgraph/gl/shaders.c +++ b/hw/xbox/nv2a/pgraph/gl/shaders.c @@ -190,6 +190,11 @@ static void update_shader_constant_locations(ShaderBinding *binding) binding->clip_region_loc[i] = glGetUniformLocation(binding->gl_program, tmp); } + for (int i = 0; i < 8; ++i) { + snprintf(tmp, sizeof(tmp), "pointParams[%d]", i); + binding->point_params_loc[i] = glGetUniformLocation(binding->gl_program, tmp); + } + if (binding->state.fixed_function) { binding->material_alpha_loc = glGetUniformLocation(binding->gl_program, "material_alpha"); @@ -950,6 +955,13 @@ static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding, x_min, y_min_xlat, x_max, y_max_xlat); } + for (i = 0; i < 8; ++i) { + GLint loc = binding->point_params_loc[i]; + if (loc != -1) { + glUniform1f(loc, pg->point_params[i]); + } + } + if (binding->material_alpha_loc != -1) { glUniform1f(binding->material_alpha_loc, pg->material_alpha); } diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c index f1a2956ca0..6bc637d582 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c @@ -482,14 +482,12 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz /* FIXME: Testing */ if (state->point_params_enable) { - mstring_append_fmt( + mstring_append_fmt(uniforms, "%sfloat pointParams[8];\n", u); + mstring_append( body, " float d_e = length(position * modelViewMat0);\n" - " oPts.x = 1/sqrt(%f + %f*d_e + %f*d_e*d_e) + %f;\n", - state->point_params[0], state->point_params[1], state->point_params[2], - state->point_params[6]); - mstring_append_fmt(body, " oPts.x = min(oPts.x*%f + %f, 64.0) * %d;\n", - state->point_params[3], state->point_params[7], + " oPts.x = 1/sqrt(pointParams[0] + pointParams[1] * d_e + pointParams[2] * d_e * d_e) + pointParams[6];\n"); + mstring_append_fmt(body, " oPts.x = min(oPts.x * pointParams[3] + pointParams[7], 64.0) * %d;\n", state->surface_scale_factor); } else { mstring_append_fmt(body, " oPts.x = %f * %d;\n", state->point_size, diff --git a/hw/xbox/nv2a/pgraph/vk/renderer.h b/hw/xbox/nv2a/pgraph/vk/renderer.h index d728805475..4112517e58 100644 --- a/hw/xbox/nv2a/pgraph/vk/renderer.h +++ b/hw/xbox/nv2a/pgraph/vk/renderer.h @@ -191,9 +191,9 @@ typedef struct ShaderBinding { int light_local_position_loc[NV2A_MAX_LIGHTS]; int light_local_attenuation_loc[NV2A_MAX_LIGHTS]; int specular_power_loc; + int point_params_loc; int clip_region_loc; - int material_alpha_loc; int uniform_attrs_loc; diff --git a/hw/xbox/nv2a/pgraph/vk/shaders.c b/hw/xbox/nv2a/pgraph/vk/shaders.c index 5d6e345ffb..78122c701d 100644 --- a/hw/xbox/nv2a/pgraph/vk/shaders.c +++ b/hw/xbox/nv2a/pgraph/vk/shaders.c @@ -308,6 +308,9 @@ static void update_shader_constant_locations(ShaderBinding *binding) binding->clip_region_loc = uniform_index(&binding->fragment->uniforms, "clipRegion"); + binding->point_params_loc = + uniform_index(&binding->vertex->uniforms, "pointParams"); + binding->material_alpha_loc = uniform_index(&binding->vertex->uniforms, "material_alpha"); @@ -720,6 +723,11 @@ static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding, uniform1iv(&binding->fragment->uniforms, binding->clip_region_loc, 8 * 4, (void *)clip_regions); + if (binding->point_params_loc != -1) { + uniform1iv(&binding->vertex->uniforms, binding->point_params_loc, + ARRAY_SIZE(pg->point_params), (void *)pg->point_params); + } + if (binding->material_alpha_loc != -1) { uniform1f(&binding->vertex->uniforms, binding->material_alpha_loc, pg->material_alpha); From 687bf629720a84d68b489043ad1e63f4ebc954fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 May 2025 03:31:37 +0000 Subject: [PATCH 69/80] ci: bump astral-sh/setup-uv from 6.0.0 to 6.0.1 Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 6.0.0 to 6.0.1. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/c7f87aa956e4c323abf06d5dec078e358f6b4d04...6b9c6063abd6010835644d4c2e1bef4cf5cd0fca) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 6.0.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/bump-subproject-wraps.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/bump-subproject-wraps.yml b/.github/workflows/bump-subproject-wraps.yml index 163d55e259..ff7740d78f 100644 --- a/.github/workflows/bump-subproject-wraps.yml +++ b/.github/workflows/bump-subproject-wraps.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Install the latest version of uv - uses: astral-sh/setup-uv@c7f87aa956e4c323abf06d5dec078e358f6b4d04 # v6 + uses: astral-sh/setup-uv@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # v6 with: enable-cache: false From f7e40b2b80ad08745d6ecbdd3ffca0b655d6d6fb Mon Sep 17 00:00:00 2001 From: xemu-robot Date: Mon, 12 May 2025 06:03:35 +0000 Subject: [PATCH 70/80] meson: Bump SPIRV-Reflect to vulkan-sdk-1.4.313.0 --- subprojects/SPIRV-Reflect.wrap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/SPIRV-Reflect.wrap b/subprojects/SPIRV-Reflect.wrap index 8107b8b7a7..43ec680c93 100644 --- a/subprojects/SPIRV-Reflect.wrap +++ b/subprojects/SPIRV-Reflect.wrap @@ -1,6 +1,6 @@ [wrap-git] url = https://github.com/KhronosGroup/SPIRV-Reflect -revision = c637858562fbce1b6f5dc7ca48d4e8a5bd117b70 +revision = c6c0f5c9796bdef40c55065d82e0df67c38a29a4 depth = 1 [update] From 428c975f098cf3c8914e07219be02bed56a0b8d1 Mon Sep 17 00:00:00 2001 From: Erik Abair Date: Fri, 4 Apr 2025 10:32:49 -0700 Subject: [PATCH 71/80] nv2a: Allow multiframe RenderDoc captures with nv2a traces Allows multiple frames to be captured at once by holding shift while pressing F10. Temporarily toggles nv2a trace messages if control is held while pressing F10. --- hw/xbox/nv2a/debug.h | 3 ++- hw/xbox/nv2a/pgraph/debug_renderdoc.c | 4 +++- hw/xbox/nv2a/pgraph/gl/debug.c | 26 +++++++++++++++++++------- hw/xbox/nv2a/pgraph/vk/debug.c | 16 ++++++++++++++-- ui/xui/main.cc | 4 ++-- ui/xui/menubar.cc | 4 +++- 6 files changed, 43 insertions(+), 14 deletions(-) diff --git a/hw/xbox/nv2a/debug.h b/hw/xbox/nv2a/debug.h index 3873f94239..2dc4bece96 100644 --- a/hw/xbox/nv2a/debug.h +++ b/hw/xbox/nv2a/debug.h @@ -155,8 +155,9 @@ static inline void nv2a_profile_inc_counter(enum NV2A_PROF_COUNTERS_ENUM cnt) void nv2a_dbg_renderdoc_init(void); void *nv2a_dbg_renderdoc_get_api(void); bool nv2a_dbg_renderdoc_available(void); -void nv2a_dbg_renderdoc_capture_frames(int num_frames); +void nv2a_dbg_renderdoc_capture_frames(int num_frames, bool trace); extern int renderdoc_capture_frames; +extern bool renderdoc_trace_frames; #endif #ifdef __cplusplus diff --git a/hw/xbox/nv2a/pgraph/debug_renderdoc.c b/hw/xbox/nv2a/pgraph/debug_renderdoc.c index 273e307973..667f01a0c9 100644 --- a/hw/xbox/nv2a/pgraph/debug_renderdoc.c +++ b/hw/xbox/nv2a/pgraph/debug_renderdoc.c @@ -36,6 +36,7 @@ static RENDERDOC_API_1_6_0 *rdoc_api = NULL; int renderdoc_capture_frames = 0; +bool renderdoc_trace_frames = false; void nv2a_dbg_renderdoc_init(void) { @@ -89,7 +90,8 @@ bool nv2a_dbg_renderdoc_available(void) return rdoc_api != NULL; } -void nv2a_dbg_renderdoc_capture_frames(int num_frames) +void nv2a_dbg_renderdoc_capture_frames(int num_frames, bool trace) { renderdoc_capture_frames += num_frames; + renderdoc_trace_frames = trace; } diff --git a/hw/xbox/nv2a/pgraph/gl/debug.c b/hw/xbox/nv2a/pgraph/gl/debug.c index 968941dc7e..97803bc301 100644 --- a/hw/xbox/nv2a/pgraph/gl/debug.c +++ b/hw/xbox/nv2a/pgraph/gl/debug.c @@ -29,6 +29,8 @@ #include #ifdef CONFIG_RENDERDOC +#include "trace/control.h" + #pragma GCC diagnostic ignored "-Wstrict-prototypes" #include "thirdparty/renderdoc_app.h" #endif @@ -154,7 +156,8 @@ void gl_debug_frame_terminator(void) RENDERDOC_API_1_6_0 *rdoc_api = nv2a_dbg_renderdoc_get_api(); if (rdoc_api->IsTargetControlConnected()) { - if (rdoc_api->IsFrameCapturing()) { + bool capturing = rdoc_api->IsFrameCapturing(); + if (capturing && renderdoc_capture_frames == 0) { rdoc_api->EndFrameCapture(NULL, NULL); GLenum error = glGetError(); if (error != GL_NO_ERROR) { @@ -162,14 +165,23 @@ void gl_debug_frame_terminator(void) "Renderdoc EndFrameCapture triggered GL error 0x%X - ignoring\n", error); } + if (renderdoc_trace_frames) { + trace_enable_events("-nv2a_pgraph_*"); + renderdoc_trace_frames = false; + } } if (renderdoc_capture_frames > 0) { - rdoc_api->StartFrameCapture(NULL, NULL); - GLenum error = glGetError(); - if (error != GL_NO_ERROR) { - fprintf(stderr, - "Renderdoc StartFrameCapture triggered GL error 0x%X - ignoring\n", - error); + if (!capturing) { + if (renderdoc_trace_frames) { + trace_enable_events("nv2a_pgraph_*"); + } + rdoc_api->StartFrameCapture(NULL, NULL); + GLenum error = glGetError(); + if (error != GL_NO_ERROR) { + fprintf(stderr, + "Renderdoc StartFrameCapture triggered GL error 0x%X - ignoring\n", + error); + } } --renderdoc_capture_frames; } diff --git a/hw/xbox/nv2a/pgraph/vk/debug.c b/hw/xbox/nv2a/pgraph/vk/debug.c index 5c31c9f119..88327b0cca 100644 --- a/hw/xbox/nv2a/pgraph/vk/debug.c +++ b/hw/xbox/nv2a/pgraph/vk/debug.c @@ -25,6 +25,8 @@ #endif #ifdef CONFIG_RENDERDOC +#include "trace/control.h" + #pragma GCC diagnostic ignored "-Wstrict-prototypes" #include "thirdparty/renderdoc_app.h" #endif @@ -46,11 +48,21 @@ void pgraph_vk_debug_frame_terminator(void) PGRAPHVkState *r = g_nv2a->pgraph.vk_renderer_state; if (rdoc_api->IsTargetControlConnected()) { - if (rdoc_api->IsFrameCapturing()) { + bool capturing = rdoc_api->IsFrameCapturing(); + if (capturing && renderdoc_capture_frames == 0) { rdoc_api->EndFrameCapture(RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(r->instance), 0); + if (renderdoc_trace_frames) { + trace_enable_events("-nv2a_pgraph_*"); + renderdoc_trace_frames = false; + } } if (renderdoc_capture_frames > 0) { - rdoc_api->StartFrameCapture(RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(r->instance), 0); + if (!capturing) { + if (renderdoc_trace_frames) { + trace_enable_events("nv2a_pgraph_*"); + } + rdoc_api->StartFrameCapture(RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(r->instance), 0); + } --renderdoc_capture_frames; } } diff --git a/ui/xui/main.cc b/ui/xui/main.cc index 699805f113..a0e57820e1 100644 --- a/ui/xui/main.cc +++ b/ui/xui/main.cc @@ -218,7 +218,7 @@ void xemu_hud_render(void) #if defined(CONFIG_RENDERDOC) if (g_capture_renderdoc_frame) { - nv2a_dbg_renderdoc_capture_frames(1); + nv2a_dbg_renderdoc_capture_frames(1, false); g_capture_renderdoc_frame = false; } #endif @@ -291,7 +291,7 @@ void xemu_hud_render(void) !ImGui::IsAnyItemFocused() && !ImGui::IsAnyItemHovered())) { g_scene_mgr.PushScene(g_popup_menu); } - + bool mod_key_down = ImGui::IsKeyDown(ImGuiKey_ModShift); for (int f_key = 0; f_key < 4; ++f_key) { if (ImGui::IsKeyPressed((enum ImGuiKey)(ImGuiKey_F5 + f_key))) { diff --git a/ui/xui/menubar.cc b/ui/xui/menubar.cc index f0b6c1d5c2..83a0b08ae2 100644 --- a/ui/xui/menubar.cc +++ b/ui/xui/menubar.cc @@ -73,7 +73,9 @@ void ProcessKeyboardShortcuts(void) #ifdef CONFIG_RENDERDOC if (ImGui::IsKeyPressed(ImGuiKey_F10) && nv2a_dbg_renderdoc_available()) { - nv2a_dbg_renderdoc_capture_frames(1); + ImGuiIO& io = ImGui::GetIO(); + int num_frames = io.KeyShift ? 5 : 1; + nv2a_dbg_renderdoc_capture_frames(num_frames, io.KeyCtrl); } #endif } From bd3cd78ae47498e03dae947a8c35a8dde66143db Mon Sep 17 00:00:00 2001 From: Erik Abair Date: Tue, 22 Apr 2025 21:30:21 -0700 Subject: [PATCH 72/80] ui: Toggle fullscreen on mouse double click --- ui/xui/main.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/xui/main.cc b/ui/xui/main.cc index a0e57820e1..07441f3a64 100644 --- a/ui/xui/main.cc +++ b/ui/xui/main.cc @@ -290,6 +290,8 @@ void xemu_hud_render(void) (ImGui::IsMouseClicked(ImGuiMouseButton_Right) && !ImGui::IsAnyItemFocused() && !ImGui::IsAnyItemHovered())) { g_scene_mgr.PushScene(g_popup_menu); + } else if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) { + xemu_toggle_fullscreen(); } bool mod_key_down = ImGui::IsKeyDown(ImGuiKey_ModShift); From c720af00bb9db153fc26e982ae379006fa7dbbc2 Mon Sep 17 00:00:00 2001 From: Erik Abair Date: Thu, 15 May 2025 12:54:56 -0700 Subject: [PATCH 73/80] nv2a/vsh: Replace NaN with 1.0 for Bx, Dx, Fog outputs and MUL zero-check --- hw/xbox/nv2a/pgraph/glsl/vsh-prog.c | 2 +- hw/xbox/nv2a/pgraph/glsl/vsh.c | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c b/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c index 0530e7ea7b..3e0ab5fbba 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c @@ -639,7 +639,7 @@ static const char* vsh_header = // Unfortunately mix() falls victim to the same handling of exceptional // (inf/NaN) handling as a multiply, so per-component comparisons are used // to guarantee HW behavior (anything * 0 must == 0). - " vec4 zero_components = sign(src0) * sign(src1);\n" + " vec4 zero_components = sign(NaNToOne(src0)) * sign(NaNToOne(src1));\n" " vec4 ret = src0 * src1;\n" " if (zero_components.x == 0.0) { ret.x = 0.0; }\n" " if (zero_components.y == 0.0) { ret.y = 0.0; }\n" diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh.c b/hw/xbox/nv2a/pgraph/glsl/vsh.c index 25c846bbde..f3c5dd5a43 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh.c @@ -81,6 +81,10 @@ MString *pgraph_gen_vsh_glsl(const ShaderState *state, bool prefix_outputs) " t = clamp(t, uintBitsToFloat(0xDF800000), uintBitsToFloat(0x9F800000));\n" " }\n" " return t;\n" + "}\n" + "\n" + "vec4 NaNToOne(vec4 src) {\n" + " return mix(src, vec4(1.0), isnan(src));\n" "}\n"); pgraph_get_glsl_vtx_header(header, state->vulkan, state->smooth_shading, @@ -128,6 +132,7 @@ MString *pgraph_gen_vsh_glsl(const ShaderState *state, bool prefix_outputs) } } } + mstring_append(header, "\n"); MString *body = mstring_from_str("void main() {\n"); @@ -232,17 +237,17 @@ MString *pgraph_gen_vsh_glsl(const ShaderState *state, bool prefix_outputs) break; } - mstring_append(body, " oFog.xyzw = vec4(fogFactor);\n"); + mstring_append(body, " oFog = NaNToOne(vec4(fogFactor));\n"); } else { /* FIXME: Is the fog still calculated / passed somehow?! */ - mstring_append(body, " oFog.xyzw = vec4(1.0);\n"); + mstring_append(body, " oFog = vec4(1.0);\n"); } /* Set outputs */ mstring_append(body, "\n" - " vtxD0 = clamp(oD0, 0.0, 1.0);\n" - " vtxB0 = clamp(oB0, 0.0, 1.0);\n" + " vtxD0 = clamp(NaNToOne(oD0), 0.0, 1.0);\n" + " vtxB0 = clamp(NaNToOne(oB0), 0.0, 1.0);\n" " vtxFog = oFog.x;\n" " vtxT0 = oT0;\n" " vtxT1 = oT1;\n" @@ -253,8 +258,8 @@ MString *pgraph_gen_vsh_glsl(const ShaderState *state, bool prefix_outputs) if (state->specular_enable) { mstring_append(body, - " vtxD1 = clamp(oD1, 0.0, 1.0);\n" - " vtxB1 = clamp(oB1, 0.0, 1.0);\n" + " vtxD1 = clamp(NaNToOne(oD1), 0.0, 1.0);\n" + " vtxB1 = clamp(NaNToOne(oB1), 0.0, 1.0);\n" ); if (state->ignore_specular_alpha) { From d8b1cae1fd59a28d4106a82d0feaec235288c3c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 May 2025 04:00:39 +0000 Subject: [PATCH 74/80] ci: bump docker/build-push-action from 6.16.0 to 6.17.0 Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.16.0 to 6.17.0. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/14487ce63c7a62a4a324b0bfb37086795e31c6c1...1dc73863535b631f98b2378be8619f83b136f4a0) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-version: 6.17.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/build-xemu-win64-toolchain.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-xemu-win64-toolchain.yml b/.github/workflows/build-xemu-win64-toolchain.yml index 346e8fad8d..4257895759 100644 --- a/.github/workflows/build-xemu-win64-toolchain.yml +++ b/.github/workflows/build-xemu-win64-toolchain.yml @@ -44,7 +44,7 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push image - uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v5 + uses: docker/build-push-action@1dc73863535b631f98b2378be8619f83b136f4a0 # v5 with: context: ubuntu-win64-cross push: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} From c9cdd76102ae6345b4f3df20a8090186034e8bbb Mon Sep 17 00:00:00 2001 From: xemu-robot Date: Mon, 19 May 2025 06:03:58 +0000 Subject: [PATCH 75/80] meson: Bump VulkanMemoryAllocator to v3.3.0 --- subprojects/VulkanMemoryAllocator.wrap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/VulkanMemoryAllocator.wrap b/subprojects/VulkanMemoryAllocator.wrap index 56550f5c96..321b8c7bed 100644 --- a/subprojects/VulkanMemoryAllocator.wrap +++ b/subprojects/VulkanMemoryAllocator.wrap @@ -1,4 +1,4 @@ [wrap-git] url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator -revision = c788c52156f3ef7bc7ab769cb03c110a53ac8fcb +revision = 1d8f600fd424278486eade7ed3e877c99f0846b1 depth = 1 From ef1b08d79dd780bd4b019306996a6b8cdb7e92aa Mon Sep 17 00:00:00 2001 From: Shiralyn <68858896+ShiralynDev@users.noreply.github.com> Date: Tue, 20 May 2025 20:37:29 +0200 Subject: [PATCH 76/80] ui: Add "allow vibration" input setting --- config_spec.yml | 3 +++ ui/xemu-input.c | 2 +- ui/xui/main-menu.cc | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/config_spec.yml b/config_spec.yml index d013c806ac..e95e6bddf7 100644 --- a/config_spec.yml +++ b/config_spec.yml @@ -54,6 +54,9 @@ input: auto_bind: type: bool default: true + allow_vibration: + type: bool + default: true background_input_capture: bool keyboard_controller_scancode_map: # Scancode reference : https://github.com/libsdl-org/SDL/blob/main/include/SDL_scancode.h diff --git a/ui/xemu-input.c b/ui/xemu-input.c index 31a51eda9d..de1db08f21 100644 --- a/ui/xemu-input.c +++ b/ui/xemu-input.c @@ -490,7 +490,7 @@ void xemu_input_update_sdl_controller_state(ControllerState *state) void xemu_input_update_rumble(ControllerState *state) { - if (!state->rumble_enabled) { + if (!state->rumble_enabled || !g_config.input.allow_vibration) { return; } diff --git a/ui/xui/main-menu.cc b/ui/xui/main-menu.cc index 9bb5dcf33f..ef3bb05c89 100644 --- a/ui/xui/main-menu.cc +++ b/ui/xui/main-menu.cc @@ -485,6 +485,8 @@ void MainMenuInputView::Draw() SectionTitle("Options"); Toggle("Auto-bind controllers", &g_config.input.auto_bind, "Bind newly connected controllers to any open port"); + Toggle("Controller vibration", &g_config.input.allow_vibration, + "Allows the controllers to vibrate"); Toggle("Background controller input capture", &g_config.input.background_input_capture, "Capture even if window is unfocused (requires restart)"); From 11dcae01b9c14c49426accbc167b431cff89fc3a Mon Sep 17 00:00:00 2001 From: coldhex Date: Mon, 13 Jan 2025 18:52:25 +0200 Subject: [PATCH 77/80] nv2a: implement screen coordinate rounding to 4 bit fractional precision Xbox triangle rasterization appears to follow the usual top-left rule. However, since Xemu renders to an OpenGL framebuffer object (FBO) instead of directly to the default framebuffer, Xemu actually has what could be called the bottom-left triangle rasterization rule. I'll address that in another commit. Also, note that the ProjAdjacentGeometry_0.5625 test in nxdk_pgraph_tests is very sensitive to floating point rounding errors. For example, the nxdk_pgraph_tests commit 66b32a0b1feba32a0db7a95d6358e84f7a6246ad changed the math library which caused the test result to change also on real Xbox hardware due to floating point rounding error differences in matrix inverse computation. Apart from the bottom-left rasterization issue, the differing result between Xbox and the rounding I am proposing here for Xemu seems to stem from floating point rounding that happens in screen coordinate calculations before the rounding to 4 bit precision takes place. Fixing such rounding issues would require carrying all preceding floating point computations exactly in the same order and with same precision as Xbox. Note that Xbox Direct3D library seems to add 0.03125 (1/32) to screen coordinates by default. Likely the idea there was to make floating point screen coordinates round to the nearest screen coordinates in 4 bit fixed point precision. So the Xbox Direct3D library (and therefore games) already mitigate against precarious rounding when exactly half-integer coordinates are used by games. Actually they would use integer coordinates because it is Direct3D 8, but since nv2a appears to rasterize at half-integer coordinates like OpenGL, Xbox Direct3D also adds 0.5 to screen coordinates in addition to 1/32. --- hw/xbox/nv2a/pgraph/gl/renderer.h | 1 - hw/xbox/nv2a/pgraph/gl/shaders.c | 23 ----------------------- hw/xbox/nv2a/pgraph/glsl/vsh-ff.c | 17 ++++++++++------- hw/xbox/nv2a/pgraph/glsl/vsh-prog.c | 24 ++++++++++-------------- hw/xbox/nv2a/pgraph/vk/renderer.h | 1 - hw/xbox/nv2a/pgraph/vk/shaders.c | 23 ----------------------- 6 files changed, 20 insertions(+), 69 deletions(-) diff --git a/hw/xbox/nv2a/pgraph/gl/renderer.h b/hw/xbox/nv2a/pgraph/gl/renderer.h index d1a64bb024..b9074d9644 100644 --- a/hw/xbox/nv2a/pgraph/gl/renderer.h +++ b/hw/xbox/nv2a/pgraph/gl/renderer.h @@ -111,7 +111,6 @@ typedef struct ShaderBinding { GLint vsh_constant_loc[NV2A_VERTEXSHADER_CONSTANTS]; uint32_t vsh_constants[NV2A_VERTEXSHADER_CONSTANTS][4]; - GLint inv_viewport_loc; GLint ltctxa_loc[NV2A_LTCTXA_COUNT]; GLint ltctxb_loc[NV2A_LTCTXB_COUNT]; GLint ltc1_loc[NV2A_LTC1_COUNT]; diff --git a/hw/xbox/nv2a/pgraph/gl/shaders.c b/hw/xbox/nv2a/pgraph/gl/shaders.c index af3cfd2f40..dbf555a621 100644 --- a/hw/xbox/nv2a/pgraph/gl/shaders.c +++ b/hw/xbox/nv2a/pgraph/gl/shaders.c @@ -158,7 +158,6 @@ static void update_shader_constant_locations(ShaderBinding *binding) binding->fog_color_loc = glGetUniformLocation(binding->gl_program, "fogColor"); binding->fog_param_loc = glGetUniformLocation(binding->gl_program, "fogParam"); - binding->inv_viewport_loc = glGetUniformLocation(binding->gl_program, "invViewport"); for (int i = 0; i < NV2A_LTCTXA_COUNT; i++) { snprintf(tmp, sizeof(tmp), "ltctxa[%d]", i); binding->ltctxa_loc[i] = glGetUniformLocation(binding->gl_program, tmp); @@ -847,28 +846,6 @@ static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding, if (binding->specular_power_loc != -1) { glUniform1f(binding->specular_power_loc, pg->specular_power); } - - /* estimate the viewport by assuming it matches the surface ... */ - unsigned int aa_width = 1, aa_height = 1; - pgraph_apply_anti_aliasing_factor(pg, &aa_width, &aa_height); - - float m11 = 0.5 * (pg->surface_binding_dim.width/aa_width); - float m22 = -0.5 * (pg->surface_binding_dim.height/aa_height); - float m33 = zmax; - float m41 = *(float*)&pg->vsh_constants[NV_IGRAPH_XF_XFCTX_VPOFF][0]; - float m42 = *(float*)&pg->vsh_constants[NV_IGRAPH_XF_XFCTX_VPOFF][1]; - - float invViewport[16] = { - 1.0/m11, 0, 0, 0, - 0, 1.0/m22, 0, 0, - 0, 0, 1.0/m33, 0, - -1.0+m41/m11, 1.0+m42/m22, 0, 1.0 - }; - - if (binding->inv_viewport_loc != -1) { - glUniformMatrix4fv(binding->inv_viewport_loc, - 1, GL_FALSE, &invViewport[0]); - } } /* update vertex program constants */ diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c index 6bc637d582..02b1a8fda8 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c @@ -115,8 +115,6 @@ GLSL_DEFINE(sceneAmbientColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_FR_AMB) ".xyz") GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz") "\n" ); - mstring_append_fmt(uniforms, -"%smat4 invViewport;\n", u); /* Skinning */ unsigned int count; @@ -471,13 +469,18 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz } mstring_append(body, - " oPos = tPosition * compositeMat;\n" - " oPos.w = clampAwayZeroInf(oPos.w);\n" - " oPos = invViewport * oPos;\n" + " oPos = tPosition * compositeMat;\n" + " oPos.z = oPos.z / clipRange.y;\n" + " oPos.w = clampAwayZeroInf(oPos.w);\n" + " oPos.xy /= oPos.w;\n" + " oPos.xy += c[" stringify(NV_IGRAPH_XF_XFCTX_VPOFF) "].xy;\n" + " oPos.xy = floor(oPos.xy * 16.0f) / 16.0f;\n" + " oPos.xy = (2.0f * oPos.xy - surfaceSize) / surfaceSize;\n" + " oPos.xy *= oPos.w;\n" ); - if (state->vulkan) { - mstring_append(body, " oPos.y *= -1;\n"); + if (!state->vulkan) { + mstring_append(body, " oPos.y = -oPos.y;\n"); } /* FIXME: Testing */ diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c b/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c index 3e0ab5fbba..e26d0c0304 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c @@ -821,22 +821,14 @@ void pgraph_gen_vsh_prog_glsl(uint16_t version, assert(has_final); mstring_append(body, - /* the shaders leave the result in screen space, while - * opengl expects it in clip space. - * TODO: the pixel-center co-ordinate differences should handled + /* The shaders leave the result in screen space, while OpenGL expects it + * in clip space. Xbox NV2A rasterizer appears to have 4 bit precision + * fixed point fractional part and to convert floating point coordinates + * by flooring. */ - " oPos.x = 2.0 * (oPos.x - surfaceSize.x * 0.5) / surfaceSize.x;\n" - ); + " oPos.xy = floor(oPos.xy * 16.0f) / 16.0f;\n" + " oPos.xy = (2.0f * oPos.xy - surfaceSize) / surfaceSize;\n" - if (vulkan) { - mstring_append(body, - " oPos.y = 2.0 * oPos.y / surfaceSize.y - 1.0;\n"); - } else { - mstring_append(body, " oPos.y = -2.0 * (oPos.y - surfaceSize.y * 0.5) " - "/ surfaceSize.y;\n"); - } - - mstring_append(body, " oPos.z = oPos.z / clipRange.y;\n" " oPos.w = clampAwayZeroInf(oPos.w);\n" @@ -849,4 +841,8 @@ void pgraph_gen_vsh_prog_glsl(uint16_t version, */ " oPos.xyz *= oPos.w;\n" ); + + if (!vulkan) { + mstring_append(body, " oPos.y = -oPos.y;\n"); + } } diff --git a/hw/xbox/nv2a/pgraph/vk/renderer.h b/hw/xbox/nv2a/pgraph/vk/renderer.h index 4112517e58..91bbf0f31d 100644 --- a/hw/xbox/nv2a/pgraph/vk/renderer.h +++ b/hw/xbox/nv2a/pgraph/vk/renderer.h @@ -179,7 +179,6 @@ typedef struct ShaderBinding { int vsh_constant_loc; uint32_t vsh_constants[NV2A_VERTEXSHADER_CONSTANTS][4]; - int inv_viewport_loc; int ltctxa_loc; int ltctxb_loc; int ltc1_loc; diff --git a/hw/xbox/nv2a/pgraph/vk/shaders.c b/hw/xbox/nv2a/pgraph/vk/shaders.c index 78122c701d..0a6e8a2b5c 100644 --- a/hw/xbox/nv2a/pgraph/vk/shaders.c +++ b/hw/xbox/nv2a/pgraph/vk/shaders.c @@ -283,8 +283,6 @@ static void update_shader_constant_locations(ShaderBinding *binding) binding->fog_param_loc = uniform_index(&binding->vertex->uniforms, "fogParam"); - binding->inv_viewport_loc = - uniform_index(&binding->vertex->uniforms, "invViewport"); binding->ltctxa_loc = uniform_index(&binding->vertex->uniforms, "ltctxa"); binding->ltctxb_loc = uniform_index(&binding->vertex->uniforms, "ltctxb"); binding->ltc1_loc = uniform_index(&binding->vertex->uniforms, "ltc1"); @@ -617,27 +615,6 @@ static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding, uniform1f(&binding->vertex->uniforms, binding->specular_power_loc, pg->specular_power); } - - /* estimate the viewport by assuming it matches the surface ... */ - unsigned int aa_width = 1, aa_height = 1; - pgraph_apply_anti_aliasing_factor(pg, &aa_width, &aa_height); - - float m11 = 0.5 * (pg->surface_binding_dim.width / aa_width); - float m22 = -0.5 * (pg->surface_binding_dim.height / aa_height); - float m33 = zmax; - float m41 = *(float *)&pg->vsh_constants[NV_IGRAPH_XF_XFCTX_VPOFF][0]; - float m42 = *(float *)&pg->vsh_constants[NV_IGRAPH_XF_XFCTX_VPOFF][1]; - - float invViewport[16] = { - 1.0 / m11, 0, 0, 0, 0, 1.0 / m22, 0, - 0, 0, 0, 1.0 / m33, 0, -1.0 + m41 / m11, 1.0 + m42 / m22, - 0, 1.0 - }; - - if (binding->inv_viewport_loc != -1) { - uniformMatrix4fv(&binding->vertex->uniforms, - binding->inv_viewport_loc, &invViewport[0]); - } } /* update vertex program constants */ From a316d7487219e0412360097836c17b65ff877953 Mon Sep 17 00:00:00 2001 From: coldhex Date: Mon, 5 May 2025 21:56:31 +0300 Subject: [PATCH 78/80] nv2a: Use trunc in vertex rounding instead of floor Xbox seems to truncate instead of flooring, which can be inferred from interpolated depth buffer values. --- hw/xbox/nv2a/pgraph/glsl/vsh-ff.c | 2 +- hw/xbox/nv2a/pgraph/glsl/vsh-prog.c | 6 ++---- hw/xbox/nv2a/pgraph/glsl/vsh.c | 7 +++++++ 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c index 02b1a8fda8..8cee360997 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c @@ -474,7 +474,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz " oPos.w = clampAwayZeroInf(oPos.w);\n" " oPos.xy /= oPos.w;\n" " oPos.xy += c[" stringify(NV_IGRAPH_XF_XFCTX_VPOFF) "].xy;\n" - " oPos.xy = floor(oPos.xy * 16.0f) / 16.0f;\n" + " oPos.xy = roundScreenCoords(oPos.xy);\n" " oPos.xy = (2.0f * oPos.xy - surfaceSize) / surfaceSize;\n" " oPos.xy *= oPos.w;\n" ); diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c b/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c index e26d0c0304..3068684d32 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c @@ -822,11 +822,9 @@ void pgraph_gen_vsh_prog_glsl(uint16_t version, mstring_append(body, /* The shaders leave the result in screen space, while OpenGL expects it - * in clip space. Xbox NV2A rasterizer appears to have 4 bit precision - * fixed point fractional part and to convert floating point coordinates - * by flooring. + * in clip space. */ - " oPos.xy = floor(oPos.xy * 16.0f) / 16.0f;\n" + " oPos.xy = roundScreenCoords(oPos.xy);\n" " oPos.xy = (2.0f * oPos.xy - surfaceSize) / surfaceSize;\n" " oPos.z = oPos.z / clipRange.y;\n" diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh.c b/hw/xbox/nv2a/pgraph/glsl/vsh.c index f3c5dd5a43..b6b7045186 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh.c @@ -85,6 +85,13 @@ MString *pgraph_gen_vsh_glsl(const ShaderState *state, bool prefix_outputs) "\n" "vec4 NaNToOne(vec4 src) {\n" " return mix(src, vec4(1.0), isnan(src));\n" + "}\n" + "\n" + // Xbox NV2A rasterizer appears to have 4 bit precision fixed-point + // fractional part and to convert floating-point coordinates by + // by truncating (not flooring). + "vec2 roundScreenCoords(vec2 pos) {\n" + " return trunc(pos * 16.0f) / 16.0f;\n" "}\n"); pgraph_get_glsl_vtx_header(header, state->vulkan, state->smooth_shading, From ce936bccdd70a18c28f35ffada8cb8c934fa0d74 Mon Sep 17 00:00:00 2001 From: coldhex Date: Tue, 20 May 2025 22:19:33 +0300 Subject: [PATCH 79/80] nv2a/gl: y-flipped rendering to framebuffer object Render scenes upside-down to framebuffer objects (FBO). The strange thing about rendering to OpenGL FBO is that it follows the bottom-left triangle rasterization rule with common PC GPUs. At least Intel and AMD. NVIDIA to be tested. My raster-rule-test github gist demonstrates this. This commit flips coordinates in y-direction, which effectively turns the bottom-left rule into top-left rule needed for Xbox compatibility. This (together with the previous commit) fixes Midtown Madness 3 Seine water rectangular seam rendering artifacts (and the remaining seams are present with Xbox hardware too.) May fix similar artifacts in other games. --- hw/xbox/nv2a/pgraph/gl/display.c | 2 +- hw/xbox/nv2a/pgraph/gl/draw.c | 5 ++-- hw/xbox/nv2a/pgraph/gl/shaders.c | 6 +---- hw/xbox/nv2a/pgraph/gl/surface.c | 42 ++++++++++++++++------------- hw/xbox/nv2a/pgraph/glsl/vsh-ff.c | 4 --- hw/xbox/nv2a/pgraph/glsl/vsh-prog.c | 4 --- 6 files changed, 27 insertions(+), 36 deletions(-) diff --git a/hw/xbox/nv2a/pgraph/gl/display.c b/hw/xbox/nv2a/pgraph/gl/display.c index 6d52a5c3b3..47400cbbd0 100644 --- a/hw/xbox/nv2a/pgraph/gl/display.c +++ b/hw/xbox/nv2a/pgraph/gl/display.c @@ -68,7 +68,7 @@ void pgraph_gl_init_display(NV2AState *d) "{\n" " vec2 texCoord = gl_FragCoord.xy/display_size;\n" " float rel = display_size.y/textureSize(tex, 0).y/line_offset;\n" - " texCoord.y = 1 + rel*(texCoord.y - 1);" + " texCoord.y = rel*(1.0f - texCoord.y);" " out_Color.rgba = texture(tex, texCoord);\n" " if (pvideo_enable) {\n" " vec2 screenCoord = gl_FragCoord.xy - 0.5;\n" diff --git a/hw/xbox/nv2a/pgraph/gl/draw.c b/hw/xbox/nv2a/pgraph/gl/draw.c index bfa92662e7..79c18040f9 100644 --- a/hw/xbox/nv2a/pgraph/gl/draw.c +++ b/hw/xbox/nv2a/pgraph/gl/draw.c @@ -92,7 +92,6 @@ void pgraph_gl_clear_surface(NV2AState *d, uint32_t parameter) scissor_height = ymax - ymin + 1; pgraph_apply_anti_aliasing_factor(pg, &xmin, &ymin); pgraph_apply_anti_aliasing_factor(pg, &scissor_width, &scissor_height); - ymin = pg->surface_binding_dim.height - (ymin + scissor_height); NV2A_DPRINTF("Translated clear rect to %d,%d - %d,%d\n", xmin, ymin, xmin + scissor_width - 1, ymin + scissor_height - 1); @@ -204,9 +203,10 @@ void pgraph_gl_draw_begin(NV2AState *d) } /* Front-face select */ + /* Winding is reverse here because clip-space y-coordinates are inverted */ glFrontFace(pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) & NV_PGRAPH_SETUPRASTER_FRONTFACE - ? GL_CCW : GL_CW); + ? GL_CW : GL_CCW); /* Polygon offset */ /* FIXME: GL implementation-specific, maybe do this in VS? */ @@ -340,7 +340,6 @@ void pgraph_gl_draw_begin(NV2AState *d) pgraph_apply_anti_aliasing_factor(pg, &xmin, &ymin); pgraph_apply_anti_aliasing_factor(pg, &scissor_width, &scissor_height); - ymin = pg->surface_binding_dim.height - (ymin + scissor_height); pgraph_apply_scaling_factor(pg, &xmin, &ymin); pgraph_apply_scaling_factor(pg, &scissor_width, &scissor_height); diff --git a/hw/xbox/nv2a/pgraph/gl/shaders.c b/hw/xbox/nv2a/pgraph/gl/shaders.c index dbf555a621..742e3c2881 100644 --- a/hw/xbox/nv2a/pgraph/gl/shaders.c +++ b/hw/xbox/nv2a/pgraph/gl/shaders.c @@ -924,12 +924,8 @@ static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding, pgraph_apply_scaling_factor(pg, &x_min, &y_min); pgraph_apply_scaling_factor(pg, &x_max, &y_max); - /* Translate for the GL viewport origin */ - int y_min_xlat = MAX((int)max_gl_height - (int)y_max, 0); - int y_max_xlat = MIN((int)max_gl_height - (int)y_min, max_gl_height); - glUniform4i(r->shader_binding->clip_region_loc[i], - x_min, y_min_xlat, x_max, y_max_xlat); + x_min, y_min, x_max, y_max); } for (i = 0; i < 8; ++i) { diff --git a/hw/xbox/nv2a/pgraph/gl/surface.c b/hw/xbox/nv2a/pgraph/gl/surface.c index 53df185130..ab63dd4e3b 100644 --- a/hw/xbox/nv2a/pgraph/gl/surface.c +++ b/hw/xbox/nv2a/pgraph/gl/surface.c @@ -137,11 +137,7 @@ static void init_render_to_texture(PGRAPHState *pg) "layout(location = 0) out vec4 out_Color;\n" "void main()\n" "{\n" - " vec2 texCoord;\n" - " texCoord.x = gl_FragCoord.x;\n" - " texCoord.y = (surface_size.y - gl_FragCoord.y)\n" - " + (textureSize(tex,0).y - surface_size.y);\n" - " texCoord /= textureSize(tex,0).xy;\n" + " vec2 texCoord = gl_FragCoord.xy / textureSize(tex, 0).xy;\n" " out_Color.rgba = texture(tex, texCoord);\n" "}\n"; @@ -298,7 +294,7 @@ static void render_surface_to_texture_slow(NV2AState *d, size_t bufsize = width * height * surface->fmt.bytes_per_pixel; uint8_t *buf = g_malloc(bufsize); - surface_download_to_buffer(d, surface, false, true, false, buf); + surface_download_to_buffer(d, surface, false, false, false, buf); width = texture_shape->width; height = texture_shape->height; @@ -738,7 +734,7 @@ static void surface_download(NV2AState *d, SurfaceBinding *surface, bool force) nv2a_profile_inc_counter(NV2A_PROF_SURF_DOWNLOAD); - surface_download_to_buffer(d, surface, true, true, true, + surface_download_to_buffer(d, surface, true, false, true, d->vram_ptr + surface->vram_addr); memory_region_set_client_dirty(d->vram, surface->vram_addr, @@ -875,20 +871,26 @@ void pgraph_gl_upload_surface_data(NV2AState *d, SurfaceBinding *surface, surface->fmt.bytes_per_pixel); } - /* FIXME: Replace this flip/scaling */ + /* FIXME: Replace this scaling */ // This is VRAM so we can't do this inplace! - uint8_t *flipped_buf = (uint8_t *)g_malloc( - surface->height * surface->width * surface->fmt.bytes_per_pixel); - unsigned int irow; - for (irow = 0; irow < surface->height; irow++) { - memcpy(&flipped_buf[surface->width * (surface->height - irow - 1) - * surface->fmt.bytes_per_pixel], - &buf[surface->pitch * irow], - surface->width * surface->fmt.bytes_per_pixel); + uint8_t *optimal_buf = buf; + unsigned int optimal_pitch = surface->width * surface->fmt.bytes_per_pixel; + + if (surface->pitch != optimal_pitch) { + optimal_buf = (uint8_t *)g_malloc(surface->height * optimal_pitch); + + uint8_t *src = buf; + uint8_t *dst = optimal_buf; + unsigned int irow; + for (irow = 0; irow < surface->height; irow++) { + memcpy(dst, src, optimal_pitch); + src += surface->pitch; + dst += optimal_pitch; + } } - uint8_t *gl_read_buf = flipped_buf; + uint8_t *gl_read_buf = optimal_buf; unsigned int width = surface->width, height = surface->height; if (pg->surface_scale_factor > 1) { @@ -896,7 +898,7 @@ void pgraph_gl_upload_surface_data(NV2AState *d, SurfaceBinding *surface, pg->scale_buf = (uint8_t *)g_realloc( pg->scale_buf, width * height * surface->fmt.bytes_per_pixel); gl_read_buf = pg->scale_buf; - uint8_t *out = gl_read_buf, *in = flipped_buf; + uint8_t *out = gl_read_buf, *in = optimal_buf; surface_copy_expand(out, in, surface->width, surface->height, surface->fmt.bytes_per_pixel, d->pgraph.surface_scale_factor); @@ -915,7 +917,9 @@ void pgraph_gl_upload_surface_data(NV2AState *d, SurfaceBinding *surface, height, 0, surface->fmt.gl_format, surface->fmt.gl_type, gl_read_buf); glPixelStorei(GL_UNPACK_ALIGNMENT, prev_unpack_alignment); - g_free(flipped_buf); + if (optimal_buf != buf) { + g_free(optimal_buf); + } if (surface->swizzle) { g_free(buf); } diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c index 8cee360997..fb07a12a4b 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c @@ -479,10 +479,6 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz " oPos.xy *= oPos.w;\n" ); - if (!state->vulkan) { - mstring_append(body, " oPos.y = -oPos.y;\n"); - } - /* FIXME: Testing */ if (state->point_params_enable) { mstring_append_fmt(uniforms, "%sfloat pointParams[8];\n", u); diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c b/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c index 3068684d32..fd48979447 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c @@ -839,8 +839,4 @@ void pgraph_gen_vsh_prog_glsl(uint16_t version, */ " oPos.xyz *= oPos.w;\n" ); - - if (!vulkan) { - mstring_append(body, " oPos.y = -oPos.y;\n"); - } } From 8667193001e4d9f20f9d5237d941f6f0ff3a2672 Mon Sep 17 00:00:00 2001 From: Erik Abair Date: Tue, 20 May 2025 13:02:00 -0700 Subject: [PATCH 80/80] nv2a: Prevent NaN in specular power factor calculation --- hw/xbox/nv2a/pgraph/glsl/vsh-ff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c index fb07a12a4b..daf821f3f1 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-ff.c @@ -358,7 +358,7 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz mstring_append_fmt(body, " float pf;\n" - " if (nDotVP == 0.0) {\n" + " if (nDotVP == 0.0 || nDotHV == 0.0) {\n" " pf = 0.0;\n" " } else {\n" " pf = pow(nDotHV, specularPower);\n"