mirror of
https://github.com/mirkobrombin/raven.git
synced 2026-10-26 21:17:40 +00:00
feat: test the DirectX June 2010 runtimes installed and used in both widths
This commit is contained in:
1 parent
93927378aa
commit
deee36d7a5
3 files changed
+180
No files matched your search
@@ -1937,6 +1937,25 @@ if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|AMD64)$")
|
||||
PASS_REGULAR_EXPRESSION "PASS: ")
|
||||
endforeach()
|
||||
endif()
|
||||
# The DirectX End-User Runtimes of June 2010 (directx_Jun2010_redist.exe in the same directory), unpacked and installed as a
|
||||
# game's setup does (scripts/native-directx-redist.py); a program of each width then uses what they installed.
|
||||
if(TARGET raven_wayland AND RAVEN_LABWC AND RAVEN_GRIM AND RAVEN_PIL_PYTHON AND RAVEN_REDIST_DIRECTORY AND RAVEN_MINGW32
|
||||
AND EXISTS ${RAVEN_REDIST_DIRECTORY}/directx_Jun2010_redist.exe)
|
||||
set(directx_fixtures ${CMAKE_CURRENT_BINARY_DIR}/directx-fixtures)
|
||||
add_custom_command(OUTPUT ${directx_fixtures}/directx-check64.exe ${directx_fixtures}/directx-check32.exe
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${directx_fixtures}
|
||||
COMMAND ${RAVEN_MINGW64} -O1 -nostdlib -fno-stack-protector -fno-builtin -mno-stack-arg-probe -Wl,--entry,raven_entry
|
||||
-o ${directx_fixtures}/directx-check64.exe ${LOADER_SOURCES}/directx_check.c -lkernel32
|
||||
COMMAND ${RAVEN_MINGW32} -O1 -nostdlib -fno-stack-protector -fno-builtin -Wl,--entry,_raven_entry
|
||||
-o ${directx_fixtures}/directx-check32.exe ${LOADER_SOURCES}/directx_check.c -lkernel32
|
||||
DEPENDS ${LOADER_SOURCES}/directx_check.c VERBATIM)
|
||||
add_custom_target(directx_check_fixtures ALL DEPENDS ${directx_fixtures}/directx-check64.exe ${directx_fixtures}/directx-check32.exe)
|
||||
add_test(NAME native_redist_directx_jun2010 COMMAND ${RAVEN_PIL_PYTHON} ${PROJECT_SOURCE_DIR}/scripts/native-directx-redist.py
|
||||
$<TARGET_FILE:raven> ${RAVEN_REDIST_DIRECTORY}/directx_Jun2010_redist.exe ${directx_fixtures}/directx-check64.exe
|
||||
${directx_fixtures}/directx-check32.exe ${CMAKE_CURRENT_BINARY_DIR}/directx-redist-evidence)
|
||||
set_tests_properties(native_redist_directx_jun2010 PROPERTIES TIMEOUT 3600 RESOURCE_LOCK raven_compositor
|
||||
PASS_REGULAR_EXPRESSION "PASS: ")
|
||||
endif()
|
||||
add_test(NAME native_x86_process COMMAND ${Python3_EXECUTABLE}
|
||||
${PROJECT_SOURCE_DIR}/scripts/native-x86-process.py $<TARGET_FILE:raven> ${CMAKE_CURRENT_BINARY_DIR}/x86-client.exe)
|
||||
set_tests_properties(native_x86_process PROPERTIES TIMEOUT 30)
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Install the DirectX End-User Runtimes of June 2010 through Raven, as a game's setup does, and use what they install.
|
||||
|
||||
The package Microsoft publishes unpacks itself into a folder, then DXSETUP.exe runs silent from there. Before it runs, a program of each
|
||||
width that needs the libraries finds none; after it, the shader compiler, D3DX, X3DAudio, XAudio2 and XInput load from the system
|
||||
directories and work, every library is where Windows puts it, and DirectX's own log says the installation succeeded. A second run over
|
||||
the installed runtimes succeeds as well, and the programs still work.
|
||||
|
||||
usage: native-directx-redist.py RAVEN PACKAGE CHECK64 CHECK32 EVIDENCE_DIR
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
import importlib.util
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
# The compositor and the runs are the ones of the Visual C++ workflow, loaded without leaving compiled files in the tree.
|
||||
sys.dont_write_bytecode = True
|
||||
_spec = importlib.util.spec_from_file_location("native_redist", Path(__file__).with_name("native-redist.py"))
|
||||
native_redist = importlib.util.module_from_spec(_spec)
|
||||
_spec.loader.exec_module(native_redist)
|
||||
|
||||
# The libraries the runtimes install for Windows 10 in both system directories, by family and version.
|
||||
LIBRARIES = ([f"d3dx9_{version}.dll" for version in range(24, 44)] + [f"d3dx10_{version}.dll" for version in range(33, 44)] +
|
||||
["d3dx11_42.dll", "d3dx11_43.dll", "d3dcsx_42.dll", "d3dcsx_43.dll"] + [f"d3dcompiler_{version}.dll" for version in range(33, 44)] +
|
||||
[f"xinput1_{version}.dll" for version in range(1, 4)] + [f"xaudio2_{version}.dll" for version in range(0, 8)] +
|
||||
[f"x3daudio1_{version}.dll" for version in range(0, 8)] + [f"xapofx1_{version}.dll" for version in range(0, 6)] +
|
||||
[f"xactengine2_{version}.dll" for version in range(0, 11)] + [f"xactengine3_{version}.dll" for version in range(0, 8)])
|
||||
|
||||
|
||||
def check(raven, prefix, program, evidence, step, expected):
|
||||
"""Runs a check program from the prefix's drive, as an installed game runs; it returns the number of the first check that failed."""
|
||||
target = prefix / "drive_c" / program.name
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copy(program, target)
|
||||
log = evidence / f"{step}-{program.stem}.log"
|
||||
native_redist.run(raven, prefix, target, [], log, timeout=120)
|
||||
if f"Native entry returned {expected} ".encode() not in log.read_bytes():
|
||||
raise RuntimeError(f"{step}: {program.name} did not return {expected}, see {log.name}")
|
||||
|
||||
|
||||
def setup(raven, prefix, evidence, step):
|
||||
code = native_redist.run(raven, prefix, prefix / "drive_c" / "dx" / "DXSETUP.exe", ["/silent"], evidence / f"{step}.log", timeout=900)
|
||||
logs = prefix / "drive_c" / "windows" / "Logs"
|
||||
text = (logs / "DirectX.log").read_text(encoding="utf-8", errors="replace")
|
||||
shutil.copy(logs / "DirectX.log", evidence / f"{step}-DirectX.log")
|
||||
if (logs / "DXError.log").exists():
|
||||
shutil.copy(logs / "DXError.log", evidence / f"{step}-DXError.log")
|
||||
last = [line for line in text.splitlines() if "Installation ended with value" in line]
|
||||
if code != 0 or not last or "value 0 " not in last[-1]:
|
||||
raise RuntimeError(f"{step}: DXSETUP ended with status {code}: {last[-1] if last else 'no result in DirectX.log'}")
|
||||
|
||||
|
||||
def main():
|
||||
raven, package, check64, check32, evidence = map(Path, sys.argv[1:6])
|
||||
evidence.mkdir(parents=True, exist_ok=True)
|
||||
prefix = evidence / "prefix"
|
||||
shutil.rmtree(prefix, ignore_errors=True)
|
||||
log = (evidence / "compositor.log").open("wb")
|
||||
compositor = native_redist.start_compositor(log)
|
||||
try:
|
||||
# Without the runtimes the programs find no shader compiler.
|
||||
check(raven, prefix, check64, evidence, "before", 1)
|
||||
check(raven, prefix, check32, evidence, "before", 1)
|
||||
code = native_redist.run(raven, prefix, package, ["/Q", "/T:C:\\dx"], evidence / "unpack.log", timeout=300)
|
||||
if code != 0 or not (prefix / "drive_c" / "dx" / "DXSETUP.exe").exists():
|
||||
raise RuntimeError(f"the package did not unpack (status {code})")
|
||||
setup(raven, prefix, evidence, "install")
|
||||
for folder in ("system32", "syswow64"):
|
||||
present = {path.name.lower() for path in (prefix / "drive_c" / "windows" / folder).iterdir()}
|
||||
missing = [name for name in LIBRARIES if name not in present]
|
||||
if missing:
|
||||
raise RuntimeError(f"{folder} lacks {', '.join(missing)}")
|
||||
check(raven, prefix, check64, evidence, "installed", 0)
|
||||
check(raven, prefix, check32, evidence, "installed", 0)
|
||||
setup(raven, prefix, evidence, "reinstall")
|
||||
check(raven, prefix, check64, evidence, "reinstalled", 0)
|
||||
check(raven, prefix, check32, evidence, "reinstalled", 0)
|
||||
print(f"PASS: DirectX June 2010 installed {len(LIBRARIES)} libraries in each system directory, both widths use them, installed again")
|
||||
finally:
|
||||
if compositor:
|
||||
compositor.terminate()
|
||||
compositor.wait(timeout=10)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/* What a game finds after the DirectX redistributable of June 2010 has installed: its libraries load from the system directory and work.
|
||||
* The shader compiler compiles a pixel shader, D3DX multiplies two matrices, X3DAudio initializes for stereo, and the XAudio2 and
|
||||
* XInput libraries load. Built for both widths; the entry returns the number of the first check that failed. */
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
typedef struct Blob Blob;
|
||||
typedef struct {
|
||||
HRESULT (WINAPI *QueryInterface)(Blob *, const GUID *, void **);
|
||||
ULONG (WINAPI *AddRef)(Blob *);
|
||||
ULONG (WINAPI *Release)(Blob *);
|
||||
void *(WINAPI *GetBufferPointer)(Blob *);
|
||||
SIZE_T (WINAPI *GetBufferSize)(Blob *);
|
||||
} BlobMethods;
|
||||
struct Blob {
|
||||
const BlobMethods *methods;
|
||||
};
|
||||
|
||||
typedef HRESULT (WINAPI *Compile)(const void *, SIZE_T, const char *, const void *, void *, const char *, const char *, UINT, UINT, Blob **,
|
||||
Blob **);
|
||||
typedef float *(WINAPI *Multiply)(float *, const float *, const float *);
|
||||
/* Version 1.7 of X3DAudio returns nothing; it fills the handle in. */
|
||||
typedef void (__cdecl *Initialize)(UINT32, float, BYTE *);
|
||||
|
||||
static const char shader[] = "float4 main() : SV_Target { return float4(1, 0.5, 0.25, 1); }";
|
||||
|
||||
int raven_entry(void)
|
||||
{
|
||||
HMODULE compiler = LoadLibraryA("d3dcompiler_43.dll");
|
||||
if (!compiler)
|
||||
return 1;
|
||||
const Compile compile = (Compile)GetProcAddress(compiler, "D3DCompile");
|
||||
if (!compile)
|
||||
return 2;
|
||||
Blob *code = NULL, *errors = NULL;
|
||||
if (compile(shader, sizeof shader - 1, "check", NULL, NULL, "main", "ps_4_0", 0, 0, &code, &errors) != S_OK || !code)
|
||||
return 3;
|
||||
/* The bytecode is a DXBC container. */
|
||||
const unsigned char *bytes = code->methods->GetBufferPointer(code);
|
||||
if (code->methods->GetBufferSize(code) < 32 || bytes[0] != 'D' || bytes[1] != 'X' || bytes[2] != 'B' || bytes[3] != 'C')
|
||||
return 4;
|
||||
code->methods->Release(code);
|
||||
|
||||
HMODULE d3dx = LoadLibraryA("d3dx9_43.dll");
|
||||
if (!d3dx)
|
||||
return 5;
|
||||
const Multiply multiply = (Multiply)GetProcAddress(d3dx, "D3DXMatrixMultiply");
|
||||
if (!multiply)
|
||||
return 6;
|
||||
/* A scale by two followed by a translation of (3, 4, 5), in D3DX's row-vector order. */
|
||||
float scale[16] = {2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1}, move[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 3, 4, 5, 1}, result[16];
|
||||
if (multiply(result, scale, move) != result || result[0] != 2 || result[5] != 2 || result[10] != 2 || result[12] != 3 || result[13] != 4 ||
|
||||
result[14] != 5 || result[15] != 1)
|
||||
return 7;
|
||||
|
||||
HMODULE audio = LoadLibraryA("X3DAudio1_7.dll");
|
||||
if (!audio)
|
||||
return 8;
|
||||
const Initialize initialize = (Initialize)GetProcAddress(audio, "X3DAudioInitialize");
|
||||
BYTE handle[20] = {0};
|
||||
if (!initialize)
|
||||
return 9;
|
||||
initialize(3, 343.5f, handle);
|
||||
BOOL filled = FALSE;
|
||||
for (int index = 0; index < 20; ++index)
|
||||
filled |= handle[index] != 0;
|
||||
if (!filled)
|
||||
return 12;
|
||||
if (!LoadLibraryA("XAudio2_7.dll"))
|
||||
return 10;
|
||||
if (!LoadLibraryA("xinput1_3.dll"))
|
||||
return 11;
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user