Merge branch 'master' into ohci_fix

This commit is contained in:
Fred Hallock 2025-05-20 23:06:08 -04:00 committed by GitHub
commit 8b67182891
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 827 additions and 228 deletions

View File

@ -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@1dc73863535b631f98b2378be8619f83b136f4a0 # v5
with:
context: ubuntu-win64-cross
push: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}

View File

@ -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,12 +305,12 @@ 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
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
@ -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
@ -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 }}
@ -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

View File

@ -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@6b9c6063abd6010835644d4c2e1bef4cf5cd0fca # 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.XEMU_ROBOT_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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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),

View File

@ -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
@ -1049,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
@ -1099,6 +1107,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
@ -1252,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
@ -1453,7 +1467,22 @@
#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.
*
* 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

View File

@ -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;
}

View File

@ -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[] = {

View File

@ -29,6 +29,8 @@
#include <assert.h>
#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;
}

View File

@ -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"

View File

@ -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);

View File

@ -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];
@ -122,9 +121,11 @@ 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];
GLint point_params_loc[8];
GLint material_alpha_loc;
} ShaderBinding;

View File

@ -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);
@ -190,11 +189,19 @@ 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");
binding->specular_power_loc =
glGetUniformLocation(binding->gl_program, "specularPower");
} else {
binding->material_alpha_loc = -1;
binding->specular_power_loc = -1;
}
}
@ -836,27 +843,9 @@ static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding,
}
}
/* 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]);
}
if (binding->specular_power_loc != -1) {
glUniform1f(binding->specular_power_loc, pg->specular_power);
}
}
/* update vertex program constants */
@ -935,12 +924,15 @@ 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) {
GLint loc = binding->point_params_loc[i];
if (loc != -1) {
glUniform1f(loc, pg->point_params[i]);
}
}
if (binding->material_alpha_loc != -1) {

View File

@ -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);
}

View File

@ -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: {
@ -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);

View File

@ -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;
@ -230,10 +228,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";
@ -264,17 +268,17 @@ 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;
}
/* 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
@ -285,18 +289,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"
//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 + %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,
state->local_eye ? "VPeye" : "vec3(0.0, 0.0, 0.0)"
);
}
switch(state->light[i]) {
@ -309,15 +315,21 @@ 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(vec3(lightInfiniteDirection%d))));\n"
" float nDotHV = max(0.0, dot(tNormal, vec3(lightInfiniteHalfVector%d)));\n",
i, i);
/* FIXME: Do specular */
/* FIXME: tBackDiffuse */
" {\n"
" float attenuation = 1.0;\n"
" 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 */
@ -325,18 +337,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:
@ -345,52 +357,83 @@ 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, /* specular(l, m, n, l1, m1, n1) */ 0.001);\n"
" }\n"
" vec3 lightAmbient = lightAmbientColor(%d) * attenuation;\n"
" vec3 lightDiffuse = lightDiffuseColor(%d) * attenuation * nDotVP;\n"
" vec3 lightSpecular = lightSpecularColor(%d) * pf;\n",
" float pf;\n"
" if (nDotVP == 0.0 || nDotHV == 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;
}
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");
mstring_append(body, " }\n"
"}\n");
}
} else {
mstring_append(body, " oD0 = diffuse;\n");
mstring_append(body, " oD1 = specular;\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) {
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,
" oD1.a = 1.0;\n"
" oB1.a = 1.0;\n"
);
}
}
mstring_append(body, " oB0 = backDiffuse;\n");
mstring_append(body, " oB1 = backSpecular;\n");
/* Fog */
if (state->fog_enable) {
@ -414,7 +457,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;
}
@ -426,25 +469,24 @@ 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 = roundScreenCoords(oPos.xy);\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");
}
/* 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,

View File

@ -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"
@ -821,22 +821,12 @@ 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.
*/
" oPos.x = 2.0 * (oPos.x - surfaceSize.x * 0.5) / surfaceSize.x;\n"
);
" oPos.xy = roundScreenCoords(oPos.xy);\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"

View File

@ -81,6 +81,17 @@ 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"
"\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,
@ -128,6 +139,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 +244,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,9 +265,16 @@ 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) {
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"

View File

@ -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)
@ -95,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)
@ -134,6 +136,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)
@ -177,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)

View File

@ -19,6 +19,8 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <math.h>
#include "hw/xbox/nv2a/nv2a_int.h"
#include "ui/xemu-notifications.h"
#include "ui/xemu-settings.h"
@ -1075,6 +1077,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,
@ -1791,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 *)&parameter;
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;
@ -2010,6 +2131,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*)&parameter;
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*)&parameter;
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 +2285,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 +2295,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*)&parameter;
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*)&parameter;
attribute->inline_value[3] = 1.0f;
}
#define SET_VERTEX_ATRIBUTE_TEX_2F(command, attr_index) \
do { \
int slot = (method - (command)) / 4; \
@ -2526,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);
@ -2728,6 +2898,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 *)&parameter;
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);

View File

@ -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];

View File

@ -92,6 +92,16 @@ 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);
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;
/* vertex program stuff */
state.vertex_program = vertex_program,
state.z_perspective = pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0) &

View File

@ -79,6 +79,12 @@ typedef struct ShaderState {
enum MaterialColorSource diffuse_src;
enum MaterialColorSource specular_src;
bool separate_specular;
bool ignore_specular_alpha;
bool local_eye;
float specular_power;
float specular_power_back;
bool lighting;
enum VshLight light[NV2A_MAX_LIGHTS];

View File

@ -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;
}
}

View File

@ -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;
@ -190,9 +189,10 @@ 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 point_params_loc;
int clip_region_loc;
int material_alpha_loc;
int uniform_attrs_loc;

View File

@ -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");
@ -308,11 +306,17 @@ 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");
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,25 +611,9 @@ static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding,
}
}
/* 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]);
if (binding->specular_power_loc != -1) {
uniform1f(&binding->vertex->uniforms, binding->specular_power_loc,
pg->specular_power);
}
}
@ -712,6 +700,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);

View File

@ -55,8 +55,6 @@ enum VshFoggen {
FOGGEN_RADIAL,
FOGGEN_PLANAR,
FOGGEN_ABS_PLANAR,
FOGGEN_ERROR4,
FOGGEN_ERROR5,
FOGGEN_FOG_X
};

View File

@ -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)

View File

@ -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?
(?P<major>0|[1-9]\d*)\.
(?P<minor>0|[1-9]\d*)\.
(?P<patch>0|[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<owner>[^/]+)/(?P<repo>[^/.]+)(?:\.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()

View File

@ -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 = c6c0f5c9796bdef40c55065d82e0df67c38a29a4
depth = 1
[update]
tag_regex = ^(vulkan-sdk-)?[\d\.]+$

View File

@ -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 = 1d8f600fd424278486eade7ed3e877c99f0846b1
depth = 1

View File

@ -1,4 +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\.]+$

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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)");

View File

@ -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
@ -290,8 +290,10 @@ 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);
for (int f_key = 0; f_key < 4; ++f_key) {
if (ImGui::IsKeyPressed((enum ImGuiKey)(ImGuiKey_F5 + f_key))) {

View File

@ -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
}