Compare commits

..
10 Commits
15 changed files with 2354 additions and 1763 deletions
+3 -3
View File
@@ -1,7 +1,7 @@
#define MY_VER_MAJOR 26
#define MY_VER_MINOR 1
#define MY_VER_MINOR 2
#define MY_VER_BUILD 0
#define MY_VERSION_NUMBERS "26.01"
#define MY_VERSION_NUMBERS "26.02"
#define MY_VERSION MY_VERSION_NUMBERS
#ifdef MY_CPU_NAME
@@ -10,7 +10,7 @@
#define MY_VERSION_CPU MY_VERSION
#endif
#define MY_DATE "2026-04-27"
#define MY_DATE "2026-06-25"
#undef MY_COPYRIGHT
#undef MY_VERSION_COPYRIGHT_DATE
#define MY_AUTHOR_NAME "Igor Pavlov"
+5
View File
@@ -76,6 +76,11 @@
#pragma GCC diagnostic ignored "-Wreserved-identifier"
#endif
#if __clang_major__ >= 22
// for "StdAfx.h" and "Precomp.h"
#pragma GCC diagnostic ignored "-Wshadow-header"
#endif
#endif // __clang__
#if defined(__clang__) && __clang_major__ >= 16
+680
View File
@@ -0,0 +1,680 @@
ISTORY of the LZMA SDK
-----------------------
26.02 2026-06-25
-------------------------
- Some bugs and vulnerabilities were fixed.
26.01 2026-04-27
-------------------------
- linux version of 7-Zip can use huge pages (2 MB pages). It can increase compression
speed for 10% for 7z/xz/LZMA/LZMA2 compression.
- new -spo[d|c|r] switch specifies the path generation mode for the output directory
for archive extraction. The output directory path is generated from the path specified
in the -o{dir_path} switch and the name of the archive being unpacked.
-spod : for Linux/Posix/macOS: -o{dir_path} specifies the direct path to the output directory.
The asterisk (*) character in {dir_path} will not be replaced by the archive name.
-spoc : 7-Zip will concatenate the path specified in -o{dir_path} with the archive name
to form the final path to the output directory.
-spor : 7-Zip will replace asterisk (*) character in the path specified in the -o{dir_path}
with the archive name. This is the default option.
- The 7zdec.exe program (a lightweight 7z archive decoder) has been modified for security purposes.
Now 7zdec.exe extracts files only to the current folder and its subfolders.
- some bugs were fixed.
26.00 2026-02-12
-------------------------
- some bugs were fixed.
25.01 2025-08-03
-------------------------
- The code for handling symbolic links has been changed
to provide greater security when extracting files from archives.
Command line switch -snld20 can be used to bypass default security
checks when creating symbolic links.
25.00 2025-07-05
-------------------------
- 7-Zip for Windows can now use more than 64 CPU threads for compression
to zip/7z/xz archives and for the 7-Zip benchmark.
If there are more than one processor group in Windows (on systems with more than
64 cpu threads), 7-Zip distributes running CPU threads across different processor groups.
- fixed some bugs and vulnerabilities.
24.09 2024-11-29
-------------------------
- The default dictionary size values for LZMA/LZMA2 compression methods were increased:
dictionary size compression level
v24.08 v24.09 v24.09
32-bit 64-bit
8 MB 16 MB 16 MB -mx4
16 MB 32 MB 32 MB -mx5 : Normal
32 MB 64 MB 64 MB -mx6
32 MB 64 MB 128 MB -mx7 : Maximum
64 MB 64 MB 256 MB -mx8
64 MB 64 MB 256 MB -mx9 : Ultra
The default dictionary size values for 32-bit versions of LZMA/LZMA2 don't exceed 64 MB.
- If an archive update operation uses a temporary archive folder and
the archive is moved to the destination folder, 7-Zip shows the progress of moving
the archive file, as this operation can take a long time if the archive is large.
- Some bugs were fixed.
24.07 2024-06-19
-------------------------
- Changes in files:
Asm/x86/Sha256Opt.asm
Now it uses "READONLY" flag for constant array segment.
It fixes an issue where ".rodata" section in 7-Zip for x86/x64 Linux had a "WRITE" attribute.
24.05 2024-05-14
-------------------------
- New switch -myv={MMNN} to set decoder compatibility version for 7z archive creating.
{MMNN} is 4-digit number that represents the version of 7-Zip without a dot.
If -myv={MMNN} switch is specified, 7-Zip will only use compression methods that can
be decoded by the specified version {MMNN} of 7-Zip and newer versions.
If -myv={MMNN} switch is not specified, -myv=2300 is used, and 7-Zip will only
use compression methods that can be decoded by 7-Zip 23.00 and newer versions.
- New switch -myfa={FilterID} to allow 7-Zip to use the specified filter method for 7z archive creating.
- New switch -myfd={FilterID} to disallow 7-Zip to use the specified filter method for 7z archive creating.
24.03 2024-03-23
-------------------------
- 7-Zip now can use new RISCV filter for compression to 7z and xz archives.
RISCV filter can increase compression ratio for data containing executable
files compiled for RISC-V architecture.
- The speed for LZMA and LZMA2 decompression in ARM64 version for Windows
was increased by 20%-60%.
It uses arm64 assembler code, and clang-cl is required for arm64 assembler code compiling.
- -slmu switch : to show timestamps as UTC instead of LOCAL TIME.
- -slsl switch : in console 7-Zip for Windows : to show file paths with
linux path separator slash '/' instead of backslash separator '\'.
- 7-Zip supports .sha256 files that use backslash path separator '\'.
- Some bugs were fixed.
24.01 2024-01-31
-------------------------
- 7-Zip uses file C/Precomp.h that is included to all c and c++ files.
CPP/Common/Common.h also includes C/Precomp.h.
C/Precomp.h defines the following macros (if _WIN32 is defined):
Z7_LARGE_PAGES 1
Z7_LONG_PATH 1
Z7_WIN32_WINNT_MIN 0x0500 (or higher)
_WIN32_WINNT 0x0500 (or higher)
WINVER _WIN32_WINNT
UNICODE 1
_UNICODE 1
if _WIN32_WINNT is defined already, C/Precomp.h doesn't redefine it.
- Speed optimizations for hash caclulation: CRC-32, CRC-64.
- The bug was fixed: 7-Zip for Linux could fail for multivolume creation in some cases.
- 7zr.exe for arm64 is included to LZMA SDK package.
- Some bugs were fixed.
23.01 2023-06-20
-------------------------
- 7-Zip now can use new ARM64 filter for compression to 7z and xz archives.
ARM64 filter can increase compression ratio for data containing executable
files compiled for ARM64 (AArch64) architecture.
Also 7-Zip now parses executable files (that have exe and dll filename extensions)
before compressing, and it selects appropriate filter for each parsed file:
- BCJ or BCJ2 filter for x86 executable files,
- ARM64 filter for ARM64 executable files.
Previous versions by default used x86 filter BCJ or BCJ2 for all exe/dll files.
- Default section size for BCJ2 filter was changed from 64 MiB to 240 MiB.
It can increase compression ratio for executable files larger than 64 MiB.
- Some optimizations in filters code: BCJ, BCJ2, Swap* and opthers.
- If 7-Zip uses BCJ2 filter for big datasets compressing, it can use additional temp
files in system's TEMP folder. 7-Zip uses temp file for additional compressed
data stream, if size of such compressed stream is larger than predefined limit:
16 MiB in 32-bit version, 4 GiB in 64-bit version.
- When new 7-Zip creates multivolume archive, 7-Zip keeps in open state
only volumes that still can be changed. Previous versions kept all volumes
in open state until the end of the archive creation.
- 7-Zip for Linux and macOS now can reduce the number of simultaneously open files,
when 7-Zip opens, extracts or creates multivolume archive. It allows to avoid
the failures for cases with big number of volumes, bacause there is a limitation
for number of open files allowed for a single program in Linux and macOS.
- Some bugs were fixed.
- Source code changes:
- All external macros for compiling C/C++ code of 7-Zip now have Z7_ prefix.
- 7-Zip COM interfaces now use new macros that allow to declare and implement COM interface.
- The code has been modified to compile with the maximum diagnostic warning level:
-Wall in MSVC and -Weverything in CLANG.
And some warning types are disabled in 2 files:
- C/Compiler.h for C/C++ code warnings.
- CPP/Common/Common.h for C++ code warnings.
- Linux/macOS versions of 7-Zip: IUnknown interface in new code doesn't use
virtual destructor that was used in previous 7-Zip and p7zip:
// virtual ~IUnknown() {}
So 7-Zip's dynamically linked shared libraries (codecs) are not compatible
between new 7-Zip for Linux/macOS and old 7-Zip (and p7zip).
21.07 2021-12-26
-------------------------
- New switches: -spm and -im!{file_path} to exclude directories from processing
for specified paths that don't contain path separator character at the end of path.
- The sorting order of files in archives was slightly changed to be more consistent
for cases where the name of some directory is the same as the prefix part of the name
of another directory or file.
21.06 2021-11-24
-------------------------
- Bug in LZMA encoder in file LzmaEnc.c was fixed:
LzmaEnc_MemEncode(), LzmaEncode() and LzmaCompress() could work incorrectly,
if size value for output buffer is smaller than size required for all compressed data.
LzmaEnc_Encode() could work incorrectly,
if callback ISeqOutStream::Write() doesn't write all compressed data.
NCompress::NLzma::CEncoder::Code() could work incorrectly,
if callback ISequentialOutStream::Write() returns error code.
- Bug in versions 21.00-21.05 was fixed:
7-Zip didn't set attributes of directories during archive extracting.
21.04 beta 2021-11-02
-------------------------
- 7-Zip now reduces the number of working CPU threads for compression,
if RAM size is not enough for compression with big LZMA2 dictionary.
- 7-Zip now can create and check "file.sha256" text files that contain the list
of file names and SHA-256 checksums in format compatible with sha256sum program.
21.03 beta 2021-07-20
-------------------------
- The maximum dictionary size for LZMA/LZMA2 compressing was increased to 4 GB (3840 MiB).
- Minor speed optimizations in LZMA/LZMA2 compressing.
21.02 alpha 2021-05-06
-------------------------
- The command line version of 7-Zip for macOS was released.
- The speed for LZMA and LZMA2 decompression in arm64 versions for macOS and Linux
was increased by 20%-60%.
21.01 alpha 2021-03-09
-------------------------
- The command line version of 7-Zip for Linux was released.
- The improvements for speed of ARM64 version using hardware CPU instructions
for AES, CRC-32, SHA-1 and SHA-256.
- Some bugs were fixed.
20.02 alpha 2020-08-08
-------------------------
- The default number of LZMA2 chunks per solid block in 7z archive was increased to 64.
It allows to increase the compression speed for big 7z archives, if there is a big number
of CPU cores and threads.
- The speed of PPMd compressing/decompressing was increased for 7z archives.
- The new -ssp switch. If the switch -ssp is specified, 7-Zip doesn't allow the system
to modify "Last Access Time" property of source files for archiving and hashing operations.
- Some bugs were fixed.
20.00 alpha 2020-02-06
-------------------------
- 7-Zip now supports new optional match finders for LZMA/LZMA2 compression: bt5 and hc5,
that can work faster than bt4 and hc4 match finders for the data with big redundancy.
- The compression ratio was improved for Fast and Fastest compression levels with the
following default settings:
- Fastest level (-mx1) : hc5 match finder with 256 KB dictionary.
- Fast level (-mx3) : hc5 match finder with 4 MB dictionary.
- Minor speed optimizations in multithreaded LZMA/LZMA2 compression for Normal/Maximum/Ultra
compression levels.
19.00 2019-02-21
-------------------------
- Encryption strength for 7z archives was increased:
the size of random initialization vector was increased from 64-bit to 128-bit,
and the pseudo-random number generator was improved.
- The bug in 7zIn.c code was fixed.
18.06 2018-12-30
-------------------------
- The speed for LZMA/LZMA2 compressing was increased by 3-10%,
and there are minor changes in compression ratio.
- Some bugs were fixed.
- The bug in 7-Zip 18.02-18.05 was fixed:
There was memory leak in multithreading xz decoder - XzDecMt_Decode(),
if xz stream contains only one block.
- The changes for MSVS compiler makefiles:
- the makefiles now use "PLATFORM" macroname with values (x64, x86, arm64)
instead of "CPU" macroname with values (AMD64, ARM64).
- the makefiles by default now use static version of the run-time library.
18.05 2018-04-30
-------------------------
- The speed for LZMA/LZMA2 compressing was increased
by 8% for fastest/fast compression levels and
by 3% for normal/maximum compression levels.
- Previous versions of 7-Zip could work incorrectly in "Large memory pages" mode in
Windows 10 because of some BUG with "Large Pages" in Windows 10.
Now 7-Zip doesn't use "Large Pages" on Windows 10 up to revision 1709 (16299).
- The BUG was fixed in Lzma2Enc.c
Lzma2Enc_Encode2() function worked incorretly,
if (inStream == NULL) and the number of block threads is more than 1.
18.03 beta 2018-03-04
-------------------------
- Asm\x86\LzmaDecOpt.asm: new optimized LZMA decoder written in asm
for x64 with about 30% higher speed than main version of LZMA decoder written in C.
- The speed for single-thread LZMA/LZMA2 decoder written in C was increased by 3%.
- 7-Zip now can use multi-threading for 7z/LZMA2 decoding,
if there are multiple independent data chunks in LZMA2 stream.
- 7-Zip now can use multi-threading for xz decoding,
if there are multiple blocks in xz stream.
18.01 2019-01-28
-------------------------
- The BUG in 17.01 - 18.00 beta was fixed:
XzDec.c : random block unpacking and XzUnpacker_IsBlockFinished()
didn't work correctly for xz archives without checksum (CRC).
18.00 beta 2019-01-10
-------------------------
- The BUG in xz encoder was fixed:
There was memory leak of 16 KB for each file compressed with
xz compression method, if additional filter was used.
17.01 beta 2017-08-28
-------------------------
- Minor speed optimization for LZMA2 (xz and 7z) multi-threading compression.
7-Zip now uses additional memory buffers for multi-block LZMA2 compression.
CPU utilization was slightly improved.
- 7-zip now creates multi-block xz archives by default. Block size can be
specified with -ms[Size]{m|g} switch.
- xz decoder now can unpack random block from multi-block xz archives.
- 7-Zip command line: @listfile now doesn't work after -- switch.
Use -i@listfile before -- switch instead.
- The BUGs were fixed:
7-Zip 17.00 beta crashed for commands that write anti-item to 7z archive.
17.00 beta 2017-04-29
-------------------------
- NewHandler.h / NewHandler.cpp:
now it redefines operator new() only for old MSVC compilers (_MSC_VER < 1900).
- C/7zTypes.h : the names of variables in interface structures were changed (vt).
- Some bugs were fixed. 7-Zip could crash in some cases.
- Some internal changes in code.
16.04 2016-10-04
-------------------------
- The bug was fixed in DllSecur.c.
16.03 2016-09-28
-------------------------
- SFX modules now use some protection against DLL preloading attack.
- Some bugs in 7z code were fixed.
16.02 2016-05-21
-------------------------
- The BUG in 16.00 - 16.01 was fixed:
Split Handler (SplitHandler.cpp) returned incorrect
total size value (kpidSize) for split archives.
16.01 2016-05-19
-------------------------
- Some internal changes to reduce the number of compiler warnings.
16.00 2016-05-10
-------------------------
- Some bugs were fixed.
15.12 2015-11-19
-------------------------
- The BUG in C version of 7z decoder was fixed:
7zDec.c : SzDecodeLzma2()
7z decoder could mistakenly report about decoding error for some 7z archives
that use LZMA2 compression method.
The probability to get that mistaken decoding error report was about
one error per 16384 solid blocks for solid blocks larger than 16 KB (compressed size).
- The BUG (in 9.26-15.11) in C version of 7z decoder was fixed:
7zArcIn.c : SzReadHeader2()
7z decoder worked incorrectly for 7z archives that contain
empty solid blocks, that can be placed to 7z archive, if some file is
unavailable for reading during archive creation.
15.09 beta 2015-10-16
-------------------------
- The BUG in LZMA / LZMA2 encoding code was fixed.
The BUG in LzFind.c::MatchFinder_ReadBlock() function.
If input data size is larger than (4 GiB - dictionary_size),
the following code worked incorrectly:
- LZMA : LzmaEnc_MemEncode(), LzmaEncode() : LZMA encoding functions
for compressing from memory to memory.
That BUG is not related to LZMA encoder version that works via streams.
- LZMA2 : multi-threaded version of LZMA2 encoder worked incorrectly, if
default value of chunk size (CLzma2EncProps::blockSize) is changed
to value larger than (4 GiB - dictionary_size).
9.38 beta 2015-01-03
-------------------------
- The BUG in 9.31-9.37 was fixed:
IArchiveGetRawProps interface was disabled for 7z archives.
- The BUG in 9.26-9.36 was fixed:
Some code in CPP\7zip\Archive\7z\ worked correctly only under Windows.
9.36 beta 2014-12-26
-------------------------
- The BUG in command line version was fixed:
7-Zip created temporary archive in current folder during update archive
operation, if -w{Path} switch was not specified.
The fixed 7-Zip creates temporary archive in folder that contains updated archive.
- The BUG in 9.33-9.35 was fixed:
7-Zip silently ignored file reading errors during 7z or gz archive creation,
and the created archive contained only part of file that was read before error.
The fixed 7-Zip stops archive creation and it reports about error.
9.35 beta 2014-12-07
-------------------------
- 7zr.exe now support AES encryption.
- SFX mudules were added to LZMA SDK
- Some bugs were fixed.
9.21 beta 2011-04-11
-------------------------
- New class FString for file names at file systems.
- Speed optimization in CRC code for big-endian CPUs.
- The BUG in Lzma2Dec.c was fixed:
Lzma2Decode function didn't work.
9.18 beta 2010-11-02
-------------------------
- New small SFX module for installers (SfxSetup).
9.12 beta 2010-03-24
-------------------------
- The BUG in LZMA SDK 9.* was fixed: LZMA2 codec didn't work,
if more than 10 threads were used (or more than 20 threads in some modes).
9.11 beta 2010-03-15
-------------------------
- PPMd compression method support
9.09 2009-12-12
-------------------------
- The bug was fixed:
Utf16_To_Utf8 funstions in UTFConvert.cpp and 7zMain.c
incorrectly converted surrogate characters (the code >= 0x10000) to UTF-8.
- Some bugs were fixed
9.06 2009-08-17
-------------------------
- Some changes in ANSI-C 7z Decoder interfaces.
9.04 2009-05-30
-------------------------
- LZMA2 compression method support
- xz format support
4.65 2009-02-03
-------------------------
- Some minor fixes
4.63 2008-12-31
-------------------------
- Some minor fixes
4.61 beta 2008-11-23
-------------------------
- The bug in ANSI-C LZMA Decoder was fixed:
If encoded stream was corrupted, decoder could access memory
outside of allocated range.
- Some changes in ANSI-C 7z Decoder interfaces.
- LZMA SDK is placed in the public domain.
4.60 beta 2008-08-19
-------------------------
- Some minor fixes.
4.59 beta 2008-08-13
-------------------------
- The bug was fixed:
LZMA Encoder in fast compression mode could access memory outside of
allocated range in some rare cases.
4.58 beta 2008-05-05
-------------------------
- ANSI-C LZMA Decoder was rewritten for speed optimizations.
- ANSI-C LZMA Encoder was included to LZMA SDK.
- C++ LZMA code now is just wrapper over ANSI-C code.
4.57 2007-12-12
-------------------------
- Speed optimizations in Ñ++ LZMA Decoder.
- Small changes for more compatibility with some C/C++ compilers.
4.49 beta 2007-07-05
-------------------------
- .7z ANSI-C Decoder:
- now it supports BCJ and BCJ2 filters
- now it supports files larger than 4 GB.
- now it supports "Last Write Time" field for files.
- C++ code for .7z archives compressing/decompressing from 7-zip
was included to LZMA SDK.
4.43 2006-06-04
-------------------------
- Small changes for more compatibility with some C/C++ compilers.
4.42 2006-05-15
-------------------------
- Small changes in .h files in ANSI-C version.
4.39 beta 2006-04-14
-------------------------
- The bug in versions 4.33b:4.38b was fixed:
C++ version of LZMA encoder could not correctly compress
files larger than 2 GB with HC4 match finder (-mfhc4).
4.37 beta 2005-04-06
-------------------------
- Fixes in C++ code: code could no be compiled if _NO_EXCEPTIONS was defined.
4.35 beta 2005-03-02
-------------------------
- The bug was fixed in C++ version of LZMA Decoder:
If encoded stream was corrupted, decoder could access memory
outside of allocated range.
4.34 beta 2006-02-27
-------------------------
- Compressing speed and memory requirements for compressing were increased
- LZMA now can use only these match finders: HC4, BT2, BT3, BT4
4.32 2005-12-09
-------------------------
- Java version of LZMA SDK was included
4.30 2005-11-20
-------------------------
- Compression ratio was improved in -a2 mode
- Speed optimizations for compressing in -a2 mode
- -fb switch now supports values up to 273
- The bug in 7z_C (7zIn.c) was fixed:
It used Alloc/Free functions from different memory pools.
So if program used two memory pools, it worked incorrectly.
- 7z_C: .7z format supporting was improved
- LZMA# SDK (C#.NET version) was included
4.27 (Updated) 2005-09-21
-------------------------
- Some GUIDs/interfaces in C++ were changed.
IStream.h:
ISequentialInStream::Read now works as old ReadPart
ISequentialOutStream::Write now works as old WritePart
4.27 2005-08-07
-------------------------
- The bug in LzmaDecodeSize.c was fixed:
if _LZMA_IN_CB and _LZMA_OUT_READ were defined,
decompressing worked incorrectly.
4.26 2005-08-05
-------------------------
- Fixes in 7z_C code and LzmaTest.c:
previous versions could work incorrectly,
if malloc(0) returns 0
4.23 2005-06-29
-------------------------
- Small fixes in C++ code
4.22 2005-06-10
-------------------------
- Small fixes
4.21 2005-06-08
-------------------------
- Interfaces for ANSI-C LZMA Decoder (LzmaDecode.c) were changed
- New additional version of ANSI-C LZMA Decoder with zlib-like interface:
- LzmaStateDecode.h
- LzmaStateDecode.c
- LzmaStateTest.c
- ANSI-C LZMA Decoder now can decompress files larger than 4 GB
4.17 2005-04-18
-------------------------
- New example for RAM->RAM compressing/decompressing:
LZMA + BCJ (filter for x86 code):
- LzmaRam.h
- LzmaRam.cpp
- LzmaRamDecode.h
- LzmaRamDecode.c
- -f86 switch for lzma.exe
4.16 2005-03-29
-------------------------
- The bug was fixed in LzmaDecode.c (ANSI-C LZMA Decoder):
If _LZMA_OUT_READ was defined, and if encoded stream was corrupted,
decoder could access memory outside of allocated range.
- Speed optimization of ANSI-C LZMA Decoder (now it's about 20% faster).
Old version of LZMA Decoder now is in file LzmaDecodeSize.c.
LzmaDecodeSize.c can provide slightly smaller code than LzmaDecode.c
- Small speed optimization in LZMA C++ code
- filter for SPARC's code was added
- Simplified version of .7z ANSI-C Decoder was included
4.06 2004-09-05
-------------------------
- The bug in v4.05 was fixed:
LZMA-Encoder didn't release output stream in some cases.
4.05 2004-08-25
-------------------------
- Source code of filters for x86, IA-64, ARM, ARM-Thumb
and PowerPC code was included to SDK
- Some internal minor changes
4.04 2004-07-28
-------------------------
- More compatibility with some C++ compilers
4.03 2004-06-18
-------------------------
- "Benchmark" command was added. It measures compressing
and decompressing speed and shows rating values.
Also it checks hardware errors.
4.02 2004-06-10
-------------------------
- C++ LZMA Encoder/Decoder code now is more portable
and it can be compiled by GCC on Linux.
4.01 2004-02-15
-------------------------
- Some detection of data corruption was enabled.
LzmaDecode.c / RangeDecoderReadByte
.....
{
rd->ExtraBytes = 1;
return 0xFF;
}
4.00 2004-02-13
-------------------------
- Original version of LZMA SDK
HISTORY of the LZMA
-------------------
2001-2008: Improvements to LZMA compressing/decompressing code,
keeping compatibility with original LZMA format
1996-2001: Development of LZMA compression format
Some milestones:
2001-08-30: LZMA compression was added to 7-Zip
1999-01-02: First version of 7-Zip was released
End of document
+287 -366
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -1,5 +1,5 @@
/* DllSecur.c -- DLL loading security
2023-12-03 : Igor Pavlov : Public domain */
: Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -67,7 +67,7 @@ void LoadSecurityDlls(void)
// at Vista (ver 6.0) : CoCreateInstance(CLSID_ShellLink, ...) doesn't work after SetDefaultDllDirectories() : Check it ???
IF_NON_VISTA_SET_DLL_DIRS_AND_RETURN
{
wchar_t buf[MAX_PATH + 100];
WCHAR buf[MAX_PATH + 100];
const char *dll;
unsigned pos = GetSystemDirectoryW(buf, MAX_PATH + 2);
if (pos == 0 || pos > MAX_PATH)
@@ -76,7 +76,7 @@ void LoadSecurityDlls(void)
buf[pos++] = '\\';
for (dll = g_Dlls; *dll != 0;)
{
wchar_t *dest = &buf[pos];
WCHAR *dest = &buf[pos];
for (;;)
{
const char c = *dll++;
+2 -2
View File
@@ -1,5 +1,5 @@
/* MtDec.c -- Multi-thread Decoder
2024-02-20 : Igor Pavlov : Public domain */
: Igor Pavlov : Public domain */
#include "Precomp.h"
@@ -22,7 +22,7 @@
#define PRF(x)
#endif
#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d))
#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d);)
void MtProgress_Init(CMtProgress *p, ICompressProgressPtr progress)
{
+17 -30
View File
@@ -25,8 +25,8 @@
#define PRF(x)
#endif
#define PRF_STR(s) PRF(printf("\n" s "\n"))
#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d))
#define PRF_STR(s) PRF(printf("\n" s "\n");)
#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d);)
#include <stdlib.h>
#include <string.h>
@@ -574,7 +574,7 @@ static SRes MixCoder_ResetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 m
output (status) can be :
CODER_STATUS_NOT_FINISHED
CODER_STATUS_FINISHED_WITH_MARK
CODER_STATUS_NEEDS_MORE_INPUT - not implemented still
CODER_STATUS_NEEDS_MORE_INPUT
*/
static SRes MixCoder_Code(CMixCoder *p,
@@ -582,8 +582,8 @@ static SRes MixCoder_Code(CMixCoder *p,
const Byte *src, SizeT *srcLen, int srcWasFinished,
ECoderFinishMode finishMode)
{
SizeT destLenOrig = *destLen;
SizeT srcLenOrig = *srcLen;
const SizeT destLenOrig = *destLen;
const SizeT srcLenOrig = *srcLen;
*destLen = 0;
*srcLen = 0;
@@ -597,39 +597,26 @@ static SRes MixCoder_Code(CMixCoder *p,
if (p->outBuf)
{
SRes res;
SizeT destLen2, srcLen2;
SizeT destLen2;
int wasFinished;
PRF_STR("------- MixCoder Single ----------")
srcLen2 = srcLenOrig;
destLen2 = destLenOrig;
if (p->numCoders != 1)
{
if (destLen2 < p->outWritten)
return SZ_ERROR_FAIL;
destLen2 -= p->outWritten;
}
*srcLen = srcLenOrig;
{
IStateCoder *coder = &p->coders[0];
res = coder->Code2(coder->p, NULL, &destLen2, src, &srcLen2, srcWasFinished, finishMode,
// &wasFinished,
&p->status);
wasFinished = (p->status == CODER_STATUS_FINISHED_WITH_MARK);
res = coder->Code2(coder->p, NULL, &destLen2, src, srcLen, srcWasFinished, finishMode, &p->status);
}
p->res = res;
/*
if (wasFinished)
p->status = CODER_STATUS_FINISHED_WITH_MARK;
else
{
if (res == SZ_OK)
if (destLen2 != destLenOrig)
p->status = CODER_STATUS_NEEDS_MORE_INPUT;
}
*/
*srcLen = srcLen2;
src += srcLen2;
p->outWritten += destLen2;
wasFinished = (p->status == CODER_STATUS_FINISHED_WITH_MARK);
if (res != SZ_OK || srcWasFinished || wasFinished)
p->wasFinished = True;
@@ -1016,8 +1003,8 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
const Byte *src, SizeT *srcLen, int srcFinished,
ECoderFinishMode finishMode, ECoderStatus *status)
{
SizeT destLenOrig = *destLen;
SizeT srcLenOrig = *srcLen;
const SizeT destLenOrig = *destLen;
const SizeT srcLenOrig = *srcLen;
*destLen = 0;
*srcLen = 0;
*status = CODER_STATUS_NOT_SPECIFIED;
+1
View File
@@ -1901,6 +1901,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
060000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000005e040000130b000022050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
060000005e040000120b000011050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000005e040000130b000023050000,Xbox Series X Controller,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,misc1:b15,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Linux,
03000000450c00002043000010010000,XEOX SL6556 BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
05000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux,
03000000c0160000e105000001010000,XinMo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux,
File diff suppressed because it is too large Load Diff
+238 -264
View File
@@ -289,55 +289,58 @@ void GSState::ResetDrawBufferIdx()
{
int entry_ptr = 0;
for (int i = 0; i < m_used_buffers_idx; i++)
if (GSConfig.UserHacks_DrawBuffering && m_used_buffers_idx > 1)
{
// There can be situations like VSync where it won't purge the draws, this is bad for us!
if (m_index_buffers[i].tail > 0 || i == m_current_buffer_idx)
for (int i = 0; i < m_used_buffers_idx; i++)
{
if (m_index_buffers[i].tail == 0)
m_env_buffers[i].draw_rect = GSVector4i::zero();
if (entry_ptr == i && (m_index_buffers[i].tail > 0 || i == m_current_buffer_idx))
// There can be situations like VSync where it won't purge the draws, this is bad for us!
if (m_index_buffers[i].tail > 0 || i == m_current_buffer_idx)
{
if (m_index_buffers[i].tail == 0)
m_env_buffers[i].draw_rect = GSVector4i::zero();
if (entry_ptr == i && (m_index_buffers[i].tail > 0 || i == m_current_buffer_idx))
{
entry_ptr++;
continue;
}
memcpy(m_vertex_buffers[entry_ptr].buff, m_vertex_buffers[i].buff, sizeof(GSVertex) * m_vertex_buffers[i].tail);
m_vertex_buffers[entry_ptr].head = m_vertex_buffers[i].head;
m_vertex_buffers[entry_ptr].tail = m_vertex_buffers[i].tail;
m_vertex_buffers[entry_ptr].next = m_vertex_buffers[i].next;
memcpy(m_index_buffers[entry_ptr].buff, m_index_buffers[i].buff, sizeof(u16) * m_index_buffers[i].tail);
m_index_buffers[entry_ptr].tail = m_index_buffers[i].tail;
if (m_vertex_buffers[entry_ptr].tail != 0)
{
memcpy(m_vertex_buffers[entry_ptr].xy, m_vertex_buffers[i].xy, sizeof(m_vertex_buffers[i].xy));
m_vertex_buffers[entry_ptr].xyhead = m_vertex_buffers[i].xyhead;
m_vertex_buffers[entry_ptr].xy_tail = m_vertex_buffers[i].xy_tail;
}
else
{
m_vertex_buffers[entry_ptr].xy_tail = 0;
}
memcpy(&m_env_buffers[entry_ptr], &m_env_buffers[i], sizeof(m_env_buffers[i]));
if (i == m_current_buffer_idx)
m_current_buffer_idx = entry_ptr;
entry_ptr++;
continue;
}
memcpy(m_vertex_buffers[entry_ptr].buff, m_vertex_buffers[i].buff, sizeof(GSVertex) * m_vertex_buffers[i].tail);
m_vertex_buffers[entry_ptr].head = m_vertex_buffers[i].head;
m_vertex_buffers[entry_ptr].tail = m_vertex_buffers[i].tail;
m_vertex_buffers[entry_ptr].next = m_vertex_buffers[i].next;
memcpy(m_index_buffers[entry_ptr].buff, m_index_buffers[i].buff, sizeof(u16) * m_index_buffers[i].tail);
m_index_buffers[entry_ptr].tail = m_index_buffers[i].tail;
if (m_vertex_buffers[entry_ptr].tail != 0)
if (i != (entry_ptr - 1))
{
memcpy(m_vertex_buffers[entry_ptr].xy, m_vertex_buffers[i].xy, sizeof(m_vertex_buffers[i].xy));
m_vertex_buffers[entry_ptr].xyhead = m_vertex_buffers[i].xyhead;
m_vertex_buffers[entry_ptr].xy_tail = m_vertex_buffers[i].xy_tail;
m_index_buffers[i].tail = 0;
memset(&m_env_buffers[i], 0, sizeof(GSDrawBufferEnv));
m_vertex_buffers[i].head = m_vertex_buffers[i].tail = m_vertex_buffers[i].next = 0;
m_vertex_buffers[i].xy_tail = 0;
}
else
{
m_vertex_buffers[entry_ptr].xy_tail = 0;
}
memcpy(&m_env_buffers[entry_ptr], &m_env_buffers[i], sizeof(m_env_buffers[i]));
if (i == m_current_buffer_idx)
m_current_buffer_idx = entry_ptr;
entry_ptr++;
}
if (i != (entry_ptr - 1))
{
m_index_buffers[i].tail = 0;
memset(&m_env_buffers[i], 0, sizeof(GSDrawBufferEnv));
m_vertex_buffers[i].head = m_vertex_buffers[i].tail = m_vertex_buffers[i].next = 0;
m_vertex_buffers[i].xy_tail = 0;
}
}
@@ -389,18 +392,11 @@ void GSState::ResetDrawBuffers()
// exclude_current is used if there is a flush for a reason other than the normal context change.
void GSState::FlushBuffers(bool flush_base_only, bool use_flush_reason, GSFlushReason flush_reason)
{
const int current_idx = m_current_buffer_idx;
bool restore_env = false;
if (m_used_buffers_idx > 0)
if (m_used_buffers_idx > 1)
{
if (m_used_buffers_idx > 1)
{
restore_env = true;
memcpy(&m_temp_env, &m_env, sizeof(m_env));
}
else if (m_index_buffers[0].tail == 0)
return;
const int current_idx = m_current_buffer_idx;
bool restore_env = true;
memcpy(&m_temp_env, &m_env, sizeof(m_env));
const int max_flushes = flush_base_only ? 1 : m_used_buffers_idx;
for (int i = 0; i < max_flushes; i++)
@@ -440,19 +436,26 @@ void GSState::FlushBuffers(bool flush_base_only, bool use_flush_reason, GSFlushR
else
FlushDraw(GSFlushReason::CONTEXTCHANGE);
}
// Restore the environment
m_current_buffer_idx = current_idx;
m_index = &m_index_buffers[m_current_buffer_idx];
m_vertex = &m_vertex_buffers[m_current_buffer_idx];
const int ctx = m_env_buffers[m_current_buffer_idx].m_backed_up_ctx;
std::memcpy(&m_prev_env, &m_env_buffers[m_current_buffer_idx].m_env, 88);
std::memcpy(&m_prev_env.CTXT[0], &m_env_buffers[m_current_buffer_idx].m_env.CTXT[0], 96);
std::memcpy(&m_prev_env.CTXT[1], &m_env_buffers[m_current_buffer_idx].m_env.CTXT[1], 96);
std::memcpy(&m_prev_env.CTXT[ctx].offset, &m_env_buffers[m_current_buffer_idx].m_env.CTXT[ctx].offset, sizeof(m_env_buffers[m_current_buffer_idx].m_env.CTXT[ctx].offset));
std::memcpy(&m_prev_env.CTXT[ctx].scissor, &m_env_buffers[m_current_buffer_idx].m_env.CTXT[ctx].scissor, sizeof(m_env_buffers[m_current_buffer_idx].m_env.CTXT[ctx].scissor));
}
else
{
if (use_flush_reason || flush_reason == VSYNC)
FlushDraw(flush_reason);
else
FlushDraw(GSFlushReason::CONTEXTCHANGE);
}
// Restore the environment
m_current_buffer_idx = current_idx;
m_index = &m_index_buffers[m_current_buffer_idx];
m_vertex = &m_vertex_buffers[m_current_buffer_idx];
const int ctx = m_env_buffers[m_current_buffer_idx].m_backed_up_ctx;
std::memcpy(&m_prev_env, &m_env_buffers[m_current_buffer_idx].m_env, 88);
std::memcpy(&m_prev_env.CTXT[0], &m_env_buffers[m_current_buffer_idx].m_env.CTXT[0], 96);
std::memcpy(&m_prev_env.CTXT[1], &m_env_buffers[m_current_buffer_idx].m_env.CTXT[1], 96);
std::memcpy(&m_prev_env.CTXT[ctx].offset, &m_env_buffers[m_current_buffer_idx].m_env.CTXT[ctx].offset, sizeof(m_env_buffers[m_current_buffer_idx].m_env.CTXT[ctx].offset));
std::memcpy(&m_prev_env.CTXT[ctx].scissor, &m_env_buffers[m_current_buffer_idx].m_env.CTXT[ctx].scissor, sizeof(m_env_buffers[m_current_buffer_idx].m_env.CTXT[ctx].scissor));
}
void GSState::PushBuffer()
@@ -469,6 +472,8 @@ void GSState::PushBuffer()
{
m_index = &m_index_buffers[m_used_buffers_idx];
m_vertex = &m_vertex_buffers[m_used_buffers_idx];
GSVertexBuff& vtx_buff = *m_vertex;
GSIndexBuff& idx_buff = *m_index;
const u32 base = m_vertex_buffers[m_current_buffer_idx].head;
const u32 copy_amt = m_vertex_buffers[m_current_buffer_idx].tail - base;
@@ -476,25 +481,25 @@ void GSState::PushBuffer()
m_vertex->tail = 0;
if (copy_amt)
memcpy(m_vertex->buff, &m_vertex_buffers[m_current_buffer_idx].buff[base], sizeof(GSVertex) * copy_amt);
memcpy(vtx_buff.buff, &m_vertex_buffers[m_current_buffer_idx].buff[base], sizeof(GSVertex) * copy_amt);
m_vertex->head = 0;
m_vertex->next = 0;
m_vertex->tail += copy_amt;
vtx_buff.head = 0;
vtx_buff.next = 0;
vtx_buff.tail += copy_amt;
if (copy_amt)
{
for (u32 i = 0; i < copy_amt; i++)
{
m_vertex->xy[i & 3] = m_vertex_buffers[m_current_buffer_idx].xy[((m_vertex_buffers[m_current_buffer_idx].xy_tail - copy_amt) + i) & 3];
m_vertex->xy_tail++;
vtx_buff.xy[i & 3] = m_vertex_buffers[m_current_buffer_idx].xy[((m_vertex_buffers[m_current_buffer_idx].xy_tail - copy_amt) + i) & 3];
vtx_buff.xy_tail++;
if (i == 0)
m_vertex->xyhead = m_vertex_buffers[m_current_buffer_idx].xyhead;
vtx_buff.xyhead = m_vertex_buffers[m_current_buffer_idx].xyhead;
}
}
else
m_vertex->xy_tail = 0;
vtx_buff.xy_tail = 0;
m_current_buffer_idx = m_used_buffers_idx;
temp_draw_rect = GSVector4i::zero();
@@ -504,6 +509,18 @@ void GSState::PushBuffer()
}
}
void GSState::SetDrawBufferEnv()
{
memcpy(&m_env_buffers[m_current_buffer_idx].m_env, &m_env, sizeof(GSDrawingEnvironment));
m_env_buffers[m_current_buffer_idx].m_backed_up_ctx = m_backed_up_ctx;
}
void GSState::SetDrawBuffDirty()
{
m_env_buffers[m_current_buffer_idx].m_dirty_regs = m_dirty_gs_regs;
m_env_buffers[m_current_buffer_idx].draw_rect = temp_draw_rect;
}
bool GSState::CanBufferNewDraw()
{
if (!GSConfig.UserHacks_DrawBuffering)
@@ -618,21 +635,23 @@ bool GSState::CanBufferNewDraw()
// We found a matching draw
m_index = &m_index_buffers[i];
m_vertex = &m_vertex_buffers[i];
GSVertexBuff& vtx_buff = *m_vertex;
GSIndexBuff& idx_buff = *m_index;
const u32 copy_amt = m_vertex_buffers[m_current_buffer_idx].tail - m_vertex_buffers[m_current_buffer_idx].head;
m_recent_buffer_switch = m_vertex->tail == m_vertex->head;
if (m_index->tail)
m_vertex->tail = m_index->buff[m_index->tail - 1] + 1;
m_recent_buffer_switch = vtx_buff.tail == vtx_buff.head;
if (idx_buff.tail)
vtx_buff.tail = idx_buff.buff[idx_buff.tail - 1] + 1;
else
m_vertex->tail = 0;
vtx_buff.tail = 0;
if (copy_amt)
memcpy(&m_vertex->buff[m_vertex->tail], &m_vertex_buffers[m_current_buffer_idx].buff[m_vertex_buffers[m_current_buffer_idx].head], sizeof(GSVertex) * copy_amt);
memcpy(&vtx_buff.buff[vtx_buff.tail], &m_vertex_buffers[m_current_buffer_idx].buff[m_vertex_buffers[m_current_buffer_idx].head], sizeof(GSVertex) * copy_amt);
m_vertex->head = m_vertex->tail;
m_vertex->next = m_vertex->head;
m_vertex->tail += copy_amt;
vtx_buff.head = vtx_buff.tail;
vtx_buff.next = vtx_buff.head;
vtx_buff.tail += copy_amt;
m_backed_up_ctx = m_env_buffers[i].m_backed_up_ctx;
temp_draw_rect = m_env_buffers[i].draw_rect;
m_env_buffers[i].m_dirty_regs = 0;
@@ -648,15 +667,15 @@ bool GSState::CanBufferNewDraw()
{
for (u32 i = 0; i < copy_amt; i++)
{
m_vertex->xy[m_vertex->xy_tail & 3] = m_vertex_buffers[m_current_buffer_idx].xy[((m_vertex_buffers[m_current_buffer_idx].xy_tail - copy_amt) + i) & 3];
m_vertex->xy_tail++;
vtx_buff.xy[vtx_buff.xy_tail & 3] = m_vertex_buffers[m_current_buffer_idx].xy[((m_vertex_buffers[m_current_buffer_idx].xy_tail - copy_amt) + i) & 3];
vtx_buff.xy_tail++;
if (i == 0)
m_vertex->xyhead = m_vertex_buffers[m_current_buffer_idx].xyhead;
vtx_buff.xyhead = m_vertex_buffers[m_current_buffer_idx].xyhead;
}
}
else
m_vertex->xy_tail = 0;
vtx_buff.xy_tail = 0;
m_current_buffer_idx = i;
@@ -692,18 +711,6 @@ bool GSState::CanBufferNewDraw()
return true;
}
void GSState::SetDrawBufferEnv()
{
memcpy(&m_env_buffers[m_current_buffer_idx].m_env, &m_env, sizeof(GSDrawingEnvironment));
m_env_buffers[m_current_buffer_idx].m_backed_up_ctx = m_backed_up_ctx;
}
void GSState::SetDrawBuffDirty()
{
m_env_buffers[m_current_buffer_idx].m_dirty_regs = m_dirty_gs_regs;
m_env_buffers[m_current_buffer_idx].draw_rect = temp_draw_rect;
}
void GSState::ResetHandlers()
{
std::fill(std::begin(m_fpGIFPackedRegHandlers), std::end(m_fpGIFPackedRegHandlers), &GSState::GIFPackedRegHandlerNull);
@@ -1673,7 +1680,7 @@ void GSState::ApplyTEX0(GIFRegTEX0& TEX0)
{
for (int b = 0; b < m_used_buffers_idx; b++)
{
GSDrawingEnvironment& buffered_env = m_env_buffers[b].m_env;
GSDrawingEnvironment& buffered_env = (m_current_buffer_idx == b) ? m_prev_env : m_env_buffers[b].m_env;
if ((buffered_env.PRIM.TME && (buffered_env.CTXT[buffered_env.PRIM.CTXT].TEX0.PSM & 0x7) >= 3) || (m_mem.m_clut.IsInvalid() & 2))
Flush(GSFlushReason::CLUTCHANGE);
}
@@ -2509,11 +2516,13 @@ void GSState::FlushPrim()
}
GSVertex buff[2];
GSVertexBuff& vtx_buff = *m_vertex;
GSIndexBuff& idx_buff = *m_index;
s_n++;
const u32 head = m_vertex->head;
const u32 tail = m_vertex->tail;
const u32 next = m_vertex->next;
const u32 head = vtx_buff.head;
const u32 tail = vtx_buff.tail;
const u32 next = vtx_buff.next;
u32 unused = 0;
if (tail > head)
@@ -2527,19 +2536,19 @@ void GSState::FlushPrim()
case GS_LINESTRIP:
case GS_SPRITE:
unused = 1;
buff[0] = m_vertex->buff[tail - 1];
buff[0] = vtx_buff.buff[tail - 1];
break;
case GS_TRIANGLELIST:
case GS_TRIANGLESTRIP:
unused = std::min<u32>(tail - head, 2);
memcpy(buff, &m_vertex->buff[tail - unused], sizeof(GSVertex) * 2);
memcpy(buff, &vtx_buff.buff[tail - unused], sizeof(GSVertex) * 2);
break;
case GS_TRIANGLEFAN:
buff[0] = m_vertex->buff[head];
buff[0] = vtx_buff.buff[head];
unused = 1;
if (tail - 1 > head)
{
buff[1] = m_vertex->buff[tail - 1];
buff[1] = vtx_buff.buff[tail - 1];
unused = 2;
}
break;
@@ -2563,7 +2572,7 @@ void GSState::FlushPrim()
#endif
// Update scissor, it may have been modified by a previous draw
m_env.CTXT[PRIM->CTXT].UpdateScissor();
m_vt.Update(m_vertex->buff, m_index->buff, m_vertex->tail, m_index->tail, GSUtil::GetPrimClass(PRIM->PRIM));
m_vt.Update(vtx_buff.buff, idx_buff.buff, vtx_buff.tail, idx_buff.tail, GSUtil::GetPrimClass(PRIM->PRIM));
// Texel coordinate rounding
// Helps Manhunt (lights shining through objects).
@@ -2575,13 +2584,13 @@ void GSState::FlushPrim()
{
const bool is_sprite = GSUtil::GetPrimClass(PRIM->PRIM) == GS_PRIM_CLASS::GS_SPRITE_CLASS;
// ST's have the lowest 9 bits (or greater depending on exponent difference) rounding down (from hardware tests).
for (int i = m_index->tail - 1; i >= 0; i--)
for (int i = idx_buff.tail - 1; i >= 0; i--)
{
GSVertex* v = &m_vertex->buff[m_index->buff[i]];
GSVertex* v = &vtx_buff.buff[idx_buff.buff[i]];
// Only Q on the second vertex is valid
if (!(i & 1) && is_sprite)
v->RGBAQ.Q = m_vertex->buff[m_index->buff[i + 1]].RGBAQ.Q;
v->RGBAQ.Q = vtx_buff.buff[idx_buff.buff[i + 1]].RGBAQ.Q;
int T = std::bit_cast<int>(v->ST.T);
int Q = std::bit_cast<int>(v->RGBAQ.Q);
@@ -2634,7 +2643,7 @@ void GSState::FlushPrim()
Draw();
g_perfmon.Put(GSPerfMon::Draw, 1);
g_perfmon.Put(GSPerfMon::Prim, m_index->tail / GSUtil::GetVertexCount(PRIM->PRIM));
g_perfmon.Put(GSPerfMon::Prim, idx_buff.tail / GSUtil::GetVertexCount(PRIM->PRIM));
if (GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()))
{
@@ -2646,15 +2655,15 @@ void GSState::FlushPrim()
}
}
m_index->tail = 0;
m_vertex->head = 0;
idx_buff.tail = 0;
vtx_buff.head = 0;
if (unused > 0)
{
memcpy(m_vertex->buff, buff, sizeof(GSVertex) * unused);
memcpy(vtx_buff.buff, buff, sizeof(GSVertex) * unused);
m_vertex->tail = unused;
m_vertex->next = next > head ? next - head : 0;
vtx_buff.tail = unused;
vtx_buff.next = next > head ? next - head : 0;
// If it's a Triangle fan the XY buffer needs to be updated to point to the correct head vert
// Jak 3 shadows get spikey (with autoflush) if you don't.
@@ -2662,22 +2671,22 @@ void GSState::FlushPrim()
{
for (u32 i = 0; i < unused; i++)
{
GSVector4i* RESTRICT vert_ptr = (GSVector4i*)&m_vertex->buff[i];
GSVector4i* RESTRICT vert_ptr = (GSVector4i*)&vtx_buff.buff[i];
GSVector4i v = vert_ptr[1];
v = v.xxxx().u16to32().sub32(m_xyof);
m_vertex->xy[i & 3] = v;
m_vertex->xy_tail = unused;
vtx_buff.xy[i & 3] = v;
vtx_buff.xy_tail = unused;
}
}
}
else
{
m_vertex->tail = 0;
m_vertex->next = 0;
vtx_buff.tail = 0;
vtx_buff.next = 0;
}
}
}
GSVector4i GSState::GetTEX0Rect(GSDrawingContext prev_ctx)
GSVector4i GSState::GetTEX0Rect(const GSDrawingContext& prev_ctx)
{
GSVector4i ret = GSVector4i::zero();
@@ -2723,27 +2732,19 @@ void GSState::CheckWriteOverlap(bool req_write, bool req_read)
const GIFRegBITBLTBUF& blit = m_env.BITBLTBUF;
const GSVector4i write_rect = GSVector4i(m_env.TRXPOS.DSAX, m_env.TRXPOS.DSAY, m_env.TRXPOS.DSAX + w, m_env.TRXPOS.DSAY + h);
const u32 write_start_bp = GSLocalMemory::GetStartBlockAddress(blit.DBP, blit.DBW, blit.DPSM, write_rect);
const u32 write_end_bp = ((GSLocalMemory::GetEndBlockAddress(blit.DBP, blit.DBW, blit.DPSM, write_rect) + 1) + (GS_BLOCKS_PER_PAGE - 1)) & ~(GS_BLOCKS_PER_PAGE - 1);
for (int i = 0; i < m_used_buffers_idx; i++)
{
GSIndexBuff* cur_index_buff = &m_index_buffers[i];
GSVertexBuff* cur_vertex_buff = &m_vertex_buffers[i];
const GSDrawingContext& prev_ctx = m_env_buffers[i].m_env.CTXT[m_env_buffers[i].m_backed_up_ctx];
const GSDrawingEnvironment& prev_env = m_env_buffers[i].m_env;
GSVector4i tex_rect = prev_env.PRIM.TME ? GetTEX0Rect(prev_ctx) : GSVector4i::zero();
const GSDrawingContext& prev_ctx = m_current_buffer_idx == i ? m_prev_env.CTXT[m_backed_up_ctx] :m_env_buffers[i].m_env.CTXT[m_env_buffers[i].m_backed_up_ctx];
const GSDrawingEnvironment& prev_env = m_current_buffer_idx == i ? m_prev_env : m_env_buffers[i].m_env;
if (cur_index_buff->tail > 0)
{
// Only flush on a NEW transfer if a pending one is using the same address or overlap.
// Check Fast & Furious (Hardare mode) and Assault Suits Valken (either renderer) and Tomb Raider - Angel of Darkness menu (TBP != DBP but overlaps).
// Cartoon Network overwrites its own Z buffer in the middle of a draw.
// Alias wraps its transfers, so be careful
const GSVector4i read_rect = GSVector4i(m_env.TRXPOS.SSAX, m_env.TRXPOS.SSAY, m_env.TRXPOS.SSAX + w, m_env.TRXPOS.SSAY + h);
if (req_write && prev_env.PRIM.TME)
{
GSVector4i tex_rect = prev_env.PRIM.TME ? GetTEX0Rect(prev_ctx) : GSVector4i::zero();
// Tex rect could be invalid showing 1024x1024 when it isn't. If the frame is only 1 page wide, it's either a big strip or a single page draw.
// This large texture causes misdetection of overlapping writes, causing our heuristics in the hardware renderer for future draws to be missing.
// Either way if we check the queued up coordinates, it should give us a fair idea. (Cabela's Trophy Bucks)
@@ -2842,6 +2843,11 @@ void GSState::CheckWriteOverlap(bool req_write, bool req_read)
}
}
// Only flush on a NEW transfer if a pending one is using the same address or overlap.
// Check Fast & Furious (Hardare mode) and Assault Suits Valken (either renderer) and Tomb Raider - Angel of Darkness menu (TBP != DBP but overlaps).
// Cartoon Network overwrites its own Z buffer in the middle of a draw.
// Alias wraps its transfers, so be careful
const GSVector4i read_rect = GSVector4i(m_env.TRXPOS.SSAX, m_env.TRXPOS.SSAY, m_env.TRXPOS.SSAX + w, m_env.TRXPOS.SSAY + h);
const u32 frame_mask = GSLocalMemory::m_psm[prev_ctx.FRAME.PSM].fmsk;
const bool frame_required = (!(prev_ctx.TEST.ATE && prev_ctx.TEST.ATST == 0 && (prev_ctx.TEST.AFAIL == 2 || prev_ctx.TEST.AFAIL == 0)) && ((prev_ctx.FRAME.FBMSK & frame_mask) != frame_mask)) || prev_ctx.TEST.DATE;
const GSVector4i draw_rect = (m_current_buffer_idx == i) ? temp_draw_rect : m_env_buffers[i].draw_rect;
@@ -2874,6 +2880,9 @@ void GSState::CheckWriteOverlap(bool req_write, bool req_read)
if (req_write)
{
const u32 write_start_bp = GSLocalMemory::GetStartBlockAddress(blit.DBP, blit.DBW, blit.DPSM, write_rect);
const u32 write_end_bp = ((GSLocalMemory::GetEndBlockAddress(blit.DBP, blit.DBW, blit.DPSM, write_rect) + 1) + (GS_BLOCKS_PER_PAGE - 1)) & ~(GS_BLOCKS_PER_PAGE - 1);
// Invalid the CLUT if it crosses paths.
m_mem.m_clut.InvalidateRange(write_start_bp, write_end_bp);
}
@@ -4771,12 +4780,12 @@ bool GSState::SpriteDrawWithoutGaps()
const GSVertex* v = &m_vertex->buff[0];
const int first_dpY = v[1].XYZ.Y - v[0].XYZ.Y;
const int first_dpX = v[1].XYZ.X - v[0].XYZ.X;
const u32 next_count = m_vertex->next;
// Horizontal Match.
if (((first_dpX + 8) >> 4) == m_r_no_scissor.z)
{
// Borrowed from MergeSprite() modified to calculate heights.
for (u32 i = 2; i < m_vertex->next; i += 2)
for (u32 i = 2; i < next_count; i += 2)
{
const int last_pY = v[i - 1].XYZ.Y;
const int dpY = v[i + 1].XYZ.Y - v[i].XYZ.Y;
@@ -4793,7 +4802,7 @@ bool GSState::SpriteDrawWithoutGaps()
{
// Borrowed from MergeSprite().
const int offset_X = m_context->XYOFFSET.OFX;
for (u32 i = 2; i < m_vertex->next; i += 2)
for (u32 i = 2; i < next_count; i += 2)
{
const int last_pX = v[i - 1].XYZ.X;
const int this_start_X = v[i].XYZ.X;
@@ -4810,7 +4819,7 @@ bool GSState::SpriteDrawWithoutGaps()
else
{
const int dpY = v[i + 1].XYZ.Y - v[i].XYZ.Y;
if ((std::abs(dpY - first_dpY) >= 16 && (i + 2) < m_vertex->next) || std::abs(this_start_X - last_pX) >= 16)
if ((std::abs(dpY - first_dpY) >= 16 && (i + 2) < next_count) || std::abs(this_start_X - last_pX) >= 16)
return false;
}
}
@@ -4823,7 +4832,7 @@ bool GSState::SpriteDrawWithoutGaps()
{
int lastXEdge = std::max(v[1].XYZ.X, v[0].XYZ.X);
int lastYEdge = std::max(v[1].XYZ.Y, v[0].XYZ.Y);
for (u32 i = 2; i < m_vertex->next; i += 2)
for (u32 i = 2; i < next_count; i += 2)
{
const int dpY = v[i + 1].XYZ.Y - v[i].XYZ.Y;
@@ -5405,7 +5414,7 @@ __forceinline void GSState::CheckCLUTValidity(u32 prim)
for (int i = 0; i < m_used_buffers_idx; i++)
{
GSDrawingEnvironment& buffered_env = m_env_buffers[i].m_env;
GSDrawingEnvironment& buffered_env = (m_current_buffer_idx == i) ? m_prev_env : m_env_buffers[i].m_env;
const GSDrawingContext& ctx = buffered_env.CTXT[buffered_env.PRIM.CTXT];
if ((m_index_buffers[i].tail > 0 || (m_vertex_buffers[i].tail == n - 1)) && (GSLocalMemory::m_psm[ctx.TEX0.PSM].pal == 0 || !buffered_env.PRIM.TME))
{
@@ -5421,7 +5430,8 @@ __forceinline void GSState::CheckCLUTValidity(u32 prim)
if (prim != GS_POINTLIST || (m_index_buffers[i].tail > 1))
endbp = fpsm.info.bn(temp_draw_rect.z - 1, temp_draw_rect.w - 1, ctx.FRAME.Block(), ctx.FRAME.FBW);
m_mem.m_clut.InvalidateRange(startbp, endbp, true);
if (m_mem.m_clut.InvalidateRange(startbp, endbp, true))
break;
}
}
}
@@ -5434,6 +5444,8 @@ __forceinline void GSState::HandleAutoFlush()
if ((m_index->tail & 1) && (prim == GS_TRIANGLESTRIP || prim == GS_TRIANGLEFAN) && !m_texflush_flag)
return;
GSVertexBuff& vtx_buff = *m_vertex;
GSIndexBuff& idx_buff = *m_index;
// To briefly explain what's going on here, what we are checking for is draws over a texture when the source and destination are themselves.
// Because one page of the texture gets buffered in the Texture Cache (the PS2's one) if any of those pixels are overwritten, you still read the old data.
// So we need to calculate if a page boundary is being crossed for the format it is in and if the same part of the texture being written and read inside the draw.
@@ -5442,8 +5454,8 @@ __forceinline void GSState::HandleAutoFlush()
{
int n = 1;
u32 buff[3];
const u32 head = m_vertex->head;
const u32 tail = m_vertex->tail;
const u32 head = vtx_buff.head;
const u32 tail = vtx_buff.tail;
switch (prim)
{
@@ -5510,7 +5522,7 @@ __forceinline void GSState::HandleAutoFlush()
// Get the rest of the rect.
for (int i = 0; i < (n - 1); i++)
{
const GSVertex* v = &m_vertex->buff[buff[i]];
const GSVertex* v = &vtx_buff.buff[buff[i]];
xy_coord.x = (static_cast<int>(v->XYZ.X) - static_cast<int>(m_context->XYOFFSET.OFX)) >> 4;
xy_coord.y = (static_cast<int>(v->XYZ.Y) - static_cast<int>(m_context->XYOFFSET.OFY)) >> 4;
@@ -5562,7 +5574,7 @@ __forceinline void GSState::HandleAutoFlush()
return;
// Get the last texture position from the last draw.
const GSVertex* v = &m_vertex->buff[m_index->buff[m_index->tail - 1]];
const GSVertex* v = &vtx_buff.buff[idx_buff.buff[idx_buff.tail - 1]];
if (PRIM->FST)
{
@@ -5652,13 +5664,13 @@ __forceinline void GSState::HandleAutoFlush()
const GSVector2i offset = GSVector2i(m_context->XYOFFSET.OFX, m_context->XYOFFSET.OFY);
const GSVector4i scissor = m_context->scissor.in;
GSVector4i old_draw_rect = GSVector4i::zero();
int current_draw_end = m_index->tail;
int current_draw_end = idx_buff.tail;
while (current_draw_end >= n)
{
for (int i = current_draw_end - 1; i >= current_draw_end - n; i--)
{
const GSVertex* v = &m_vertex->buff[m_index->buff[i]];
const GSVertex* v = &vtx_buff.buff[idx_buff.buff[i]];
if (prim == GS_SPRITE && (i & 1))
{
@@ -5740,32 +5752,33 @@ __forceinline void GSState::HandleAutoFlush()
}
}
bool GSState::CheckOverlapVerts(u32 n)
__inline bool GSState::CheckOverlapVerts(u32 n)
{
if (!GSConfig.UserHacks_DrawBuffering)
return false;
GSVertexBuff& vtx_buff = *m_vertex;
GSIndexBuff& idx_buff = *m_index;
if (m_recent_buffer_switch && ((m_vertex->tail + 1) - m_vertex->head) == n)
if (m_recent_buffer_switch && ((vtx_buff.tail + 1) - vtx_buff.head) == n)
{
m_recent_buffer_switch = false;
if (m_used_buffers_idx > 1)
{
const GSVertex* v = &m_vertex->buff[0];
const GSVertex* RESTRICT v = &vtx_buff.buff[0];
const GSVector2i off_xy = GSVector2i(m_context->XYOFFSET.OFX, m_context->XYOFFSET.OFY);
GSVector2i cur_verts[3];
GSVector4i new_area = GSVector4i(m_v.XYZ.X - m_context->XYOFFSET.OFX, m_v.XYZ.Y - m_context->XYOFFSET.OFY).xyxy();
GSVector4i new_area = GSVector4i(m_v.XYZ.X - off_xy.x, m_v.XYZ.Y - off_xy.y).xyxy();
cur_verts[0] = GSVector2i(new_area.x, new_area.y);
for (u32 i = 0; i < (n - 1); i++)
{
const int pos = (m_vertex->tail - 1) - i;
const int pos = (vtx_buff.tail - 1) - i;
GSVector2i prev_vert;
if (m_env.PRIM.PRIM == GS_TRIANGLEFAN && i == (n - 2))
prev_vert = GSVector2i(v[m_vertex->head].XYZ.X - m_context->XYOFFSET.OFX, v[m_vertex->head].XYZ.X - m_context->XYOFFSET.OFY);
prev_vert = GSVector2i(v[vtx_buff.head].XYZ.X - off_xy.y, v[vtx_buff.head].XYZ.X - off_xy.y);
else
prev_vert = GSVector2i(v[pos].XYZ.X - m_context->XYOFFSET.OFX, v[pos].XYZ.Y - m_context->XYOFFSET.OFY);
prev_vert = GSVector2i(v[pos].XYZ.X - off_xy.x, v[pos].XYZ.Y - off_xy.y);
cur_verts[i + 1] = prev_vert;
@@ -5775,13 +5788,13 @@ bool GSState::CheckOverlapVerts(u32 n)
new_area.w = std::max(new_area.w, prev_vert.y);
}
if (m_index->tail > 0)
if (idx_buff.tail > 0)
{
u32 matching_verts = 0;
for (u32 i = 0; i < n; i++)
{
const u32 pos = m_index->buff[(m_index->tail - n) + i];
const GSVector2i prev_vert = GSVector2i(v[pos].XYZ.X - m_context->XYOFFSET.OFX, v[pos].XYZ.Y - m_context->XYOFFSET.OFY);
const u32 pos = idx_buff.buff[(idx_buff.tail - n) + i];
const GSVector2i prev_vert = GSVector2i(v[pos].XYZ.X - off_xy.x, v[pos].XYZ.Y - off_xy.y);
for (u32 j = 0; j < n; j++)
{
@@ -5810,48 +5823,6 @@ bool GSState::CheckOverlapVerts(u32 n)
return true;
}
}
/*const GSVertex* v = &m_vertex->buff[0];
GSVector4i new_area = GSVector4i(m_v.XYZ.X - m_context->XYOFFSET.OFX, m_v.XYZ.Y - m_context->XYOFFSET.OFY).xyxy();
for (u32 i = 0; i < (n - 1); i++)
{
const int pos = m_index->buff[(m_index->tail - 1) - i];
GSVector2i pre_vert = GSVector2i(v[pos].XYZ.X - m_context->XYOFFSET.OFX, v[pos].XYZ.Y - m_context->XYOFFSET.OFY);
new_area.x = std::min(new_area.x, pre_vert.x);
new_area.z = std::max(new_area.z, pre_vert.x);
new_area.y = std::min(new_area.y, pre_vert.y);
new_area.w = std::max(new_area.w, pre_vert.y);
}
new_area = new_area.sra32<4>();
if (new_area.rintersect(temp_draw_rect).eq(new_area))
{
const int end_pos = m_index->tail - (n - 1);
//Need to check if it's already drawn at this vector with this setup, if it has, it means one of the other draws might be drawing over it, which is a bad time for us, so best check.
for (int j = 0; j < end_pos; j+=n)
{
if (v[m_index->buff[j]].XYZ.X == m_v.XYZ.X && v[m_index->buff[j]].XYZ.Y == m_v.XYZ.Y)
{
int min_point = std::max(j - 2, 0);
int match = 0;
for (int k = min_point; k < (min_point + 5); k++)
{
if (k == j)
continue;
if (v[m_index->buff[k]].XYZ.X == v[m_vertex->tail - 2].XYZ.X && v[m_index->buff[k]].XYZ.Y == v[m_vertex->tail - 2].XYZ.Y)
match |= 1;
if (v[m_index->buff[k]].XYZ.X == v[m_vertex->tail - 1].XYZ.X && v[m_index->buff[k]].XYZ.Y == v[m_vertex->tail - 1].XYZ.Y)
match |= 2;
}
if (match)
return true;
}
}
}*/
}
return false;
}
@@ -5861,28 +5832,30 @@ __forceinline void GSState::VertexKick(u32 skip)
{
constexpr u32 n = NumIndicesForPrim(prim);
constexpr int primclass = GSUtil::GetPrimClass(prim);
GSVertexBuff& vtx_buff = *m_vertex;
GSIndexBuff& idx_buff = *m_index;
static_assert(n > 0);
pxAssert(m_vertex->tail < m_vertex->maxcount + 3);
pxAssert(vtx_buff.tail < vtx_buff. maxcount + 3);
if constexpr (prim == GS_INVALID)
{
m_vertex->tail = m_vertex->head;
vtx_buff.tail = vtx_buff.head;
return;
}
if (CheckOverlapVerts(n))
Flush(CONTEXTCHANGE);
if (GSConfig.UserHacks_DrawBuffering)
if (CheckOverlapVerts(n))
Flush(CONTEXTCHANGE);
if (auto_flush && skip == 0 && m_index->tail > 0 && ((m_vertex->tail + 1) - m_vertex->head) >= n)
if (auto_flush && skip == 0 && idx_buff.tail > 0 && ((vtx_buff.tail + 1) - vtx_buff.head) >= n)
{
HandleAutoFlush<prim>();
}
u32 head = m_vertex->head;
u32 tail = m_vertex->tail;
u32 next = m_vertex->next;
u32 xy_tail = m_vertex->xy_tail;
u32 head = vtx_buff.head;
u32 tail = vtx_buff.tail;
u32 next = vtx_buff.next;
u32 xy_tail = vtx_buff.xy_tail;
if (GSIsHardwareRenderer() && GSLocalMemory::m_psm[m_context->ZBUF.PSM].bpp == 32)
{
@@ -5897,7 +5870,7 @@ __forceinline void GSState::VertexKick(u32 skip)
const GSVector4i new_v0(m_v.m[0]);
const GSVector4i new_v1(m_v.m[1]);
GSVector4i* RESTRICT tailptr = (GSVector4i*)&m_vertex->buff[tail];
GSVector4i* RESTRICT tailptr = (GSVector4i*)&vtx_buff.buff[tail];
tailptr[0] = new_v0;
tailptr[1] = new_v1;
@@ -5905,41 +5878,29 @@ __forceinline void GSState::VertexKick(u32 skip)
// We maintain the X/Y coordinates for the last 4 vertices, as well as the head for triangle fans, so we can compute
// the min/max, and cull degenerate triangles, which saves draws in some cases. Why 4? Mod 4 is cheaper than Mod 3.
const GSVector4i xy = new_v1.xxxx().u16to32().sub32(m_xyof);
m_vertex->xy[xy_tail & 3] = xy;
vtx_buff.xy[xy_tail & 3] = xy;
// Backup head for triangle fans so we can read it later, otherwise it'll get lost after the 4th vertex.
if (prim == GS_TRIANGLEFAN && tail == head)
m_vertex->xyhead = xy;
vtx_buff.xyhead = xy;
m_vertex->tail = ++tail;
m_vertex->xy_tail = ++xy_tail;
vtx_buff.tail = ++tail;
vtx_buff.xy_tail = ++xy_tail;
const u32 m = tail - head;
if (m < n)
return;
if (m_index->tail == 0/* && ((m_backed_up_ctx != m_env.PRIM.CTXT) || m_dirty_gs_regs)*/)
{
const int ctx = m_env.PRIM.CTXT;
std::memcpy(&m_prev_env, &m_env, 88);
std::memcpy(&m_prev_env.CTXT[ctx], &m_env.CTXT[ctx], 96);
std::memcpy(&m_prev_env.CTXT[ctx].offset, &m_env.CTXT[ctx].offset, sizeof(m_env.CTXT[ctx].offset));
std::memcpy(&m_prev_env.CTXT[ctx].scissor, &m_env.CTXT[ctx].scissor, sizeof(m_env.CTXT[ctx].scissor));
m_dirty_gs_regs = 0;
m_backed_up_ctx = m_env.PRIM.CTXT;
SetDrawBufferEnv();
}
// Skip draws when scissor is out of range (i.e. bottom-right is less than top-left), since everything will get clipped.
skip |= static_cast<u32>(m_scissor_invalid);
GSVector4i bbox;
if (skip == 0)
{
const GSVector4i v0 = m_vertex->xy[(xy_tail - 1) & 3];
const GSVector4i v1 = m_vertex->xy[(xy_tail - 2) & 3];
const GSVector4i v2 = (prim == GS_TRIANGLEFAN) ? m_vertex->xyhead : m_vertex->xy[(xy_tail - 3) & 3];
const GSVector4i v0 = vtx_buff.xy[(xy_tail - 1) & 3];
const GSVector4i v1 = vtx_buff.xy[(xy_tail - 2) & 3];
const GSVector4i v2 = (prim == GS_TRIANGLEFAN) ? vtx_buff.xyhead : vtx_buff.xy[(xy_tail - 3) & 3];
if constexpr (n == 1)
{
@@ -6004,14 +5965,14 @@ __forceinline void GSState::VertexKick(u32 skip)
case GS_LINELIST:
case GS_TRIANGLELIST:
case GS_SPRITE:
m_vertex->tail = head; // no need to check or grow the buffer length
vtx_buff.tail = head; // no need to check or grow the buffer length
break;
case GS_LINESTRIP:
case GS_TRIANGLESTRIP:
m_vertex->head = head + 1;
vtx_buff.head = head + 1;
[[fallthrough]];
case GS_TRIANGLEFAN:
if (tail >= m_vertex->maxcount)
if (tail >= vtx_buff.maxcount)
GrowVertexBuffer(); // in case too many vertices were skipped
break;
default:
@@ -6021,71 +5982,85 @@ __forceinline void GSState::VertexKick(u32 skip)
return;
}
if (tail >= m_vertex->maxcount)
if (idx_buff.tail == 0 /* && ((m_backed_up_ctx != m_env.PRIM.CTXT) || m_dirty_gs_regs)*/)
{
const int ctx = m_env.PRIM.CTXT;
std::memcpy(&m_prev_env, &m_env, 88);
std::memcpy(&m_prev_env.CTXT[ctx], &m_env.CTXT[ctx], 96);
std::memcpy(&m_prev_env.CTXT[ctx].offset, &m_env.CTXT[ctx].offset, sizeof(m_env.CTXT[ctx].offset));
std::memcpy(&m_prev_env.CTXT[ctx].scissor, &m_env.CTXT[ctx].scissor, sizeof(m_env.CTXT[ctx].scissor));
m_dirty_gs_regs = 0;
m_backed_up_ctx = m_env.PRIM.CTXT;
if (GSConfig.UserHacks_DrawBuffering)
SetDrawBufferEnv();
}
if (tail >= vtx_buff.maxcount)
GrowVertexBuffer();
u16* RESTRICT buff = &m_index->buff[m_index->tail];
u16* RESTRICT buff = &idx_buff.buff[idx_buff.tail];
switch (prim)
{
case GS_POINTLIST:
buff[0] = static_cast<u16>(head + 0);
m_vertex->head = head + 1;
m_vertex->next = head + 1;
m_index->tail += 1;
vtx_buff.head = head + 1;
vtx_buff.next = head + 1;
idx_buff.tail += 1;
break;
case GS_LINELIST:
buff[0] = static_cast<u16>(head + 0);
buff[1] = static_cast<u16>(head + 1);
m_vertex->head = head + 2;
m_vertex->next = head + 2;
m_index->tail += 2;
vtx_buff.head = head + 2;
vtx_buff.next = head + 2;
idx_buff.tail += 2;
break;
case GS_LINESTRIP:
if (next < head)
{
m_vertex->buff[next + 0] = m_vertex->buff[head + 0];
m_vertex->buff[next + 1] = m_vertex->buff[head + 1];
vtx_buff.buff[next + 0] = vtx_buff.buff[head + 0];
vtx_buff.buff[next + 1] = vtx_buff.buff[head + 1];
head = next;
m_vertex->tail = next + 2;
vtx_buff.tail = next + 2;
}
buff[0] = static_cast<u16>(head + 0);
buff[1] = static_cast<u16>(head + 1);
m_vertex->head = head + 1;
m_vertex->next = head + 2;
m_index->tail += 2;
vtx_buff.head = head + 1;
vtx_buff.next = head + 2;
idx_buff.tail += 2;
break;
case GS_TRIANGLELIST:
buff[0] = static_cast<u16>(head + 0);
buff[1] = static_cast<u16>(head + 1);
buff[2] = static_cast<u16>(head + 2);
m_vertex->head = head + 3;
m_vertex->next = head + 3;
m_index->tail += 3;
vtx_buff.head = head + 3;
vtx_buff.next = head + 3;
idx_buff.tail += 3;
break;
case GS_TRIANGLESTRIP:
if (next < head)
{
m_vertex->buff[next + 0] = m_vertex->buff[head + 0];
m_vertex->buff[next + 1] = m_vertex->buff[head + 1];
m_vertex->buff[next + 2] = m_vertex->buff[head + 2];
vtx_buff.buff[next + 0] = vtx_buff.buff[head + 0];
vtx_buff.buff[next + 1] = vtx_buff.buff[head + 1];
vtx_buff.buff[next + 2] = vtx_buff.buff[head + 2];
head = next;
m_vertex->tail = next + 3;
vtx_buff.tail = next + 3;
}
buff[0] = static_cast<u16>(head + 0);
buff[1] = static_cast<u16>(head + 1);
buff[2] = static_cast<u16>(head + 2);
m_vertex->head = head + 1;
m_vertex->next = head + 3;
m_index->tail += 3;
vtx_buff.head = head + 1;
vtx_buff.next = head + 3;
idx_buff.tail += 3;
break;
case GS_TRIANGLEFAN:
// TODO: remove gaps, next == head && head < tail - 3 || next > head && next < tail - 2 (very rare)
buff[0] = static_cast<u16>(head + 0);
buff[1] = static_cast<u16>(tail - 2);
buff[2] = static_cast<u16>(tail - 1);
m_vertex->next = tail;
m_index->tail += 3;
vtx_buff.next = tail;
idx_buff.tail += 3;
break;
case GS_SPRITE:
buff[0] = static_cast<u16>(head + 0);
@@ -6093,11 +6068,11 @@ __forceinline void GSState::VertexKick(u32 skip)
// Update the first vert's Q for ease of doing Autoflush
if (!m_env.PRIM.FST)
m_vertex->buff[buff[0]].RGBAQ.Q = m_vertex->buff[buff[1]].RGBAQ.Q;
vtx_buff.buff[buff[0]].RGBAQ.Q = vtx_buff.buff[buff[1]].RGBAQ.Q;
m_vertex->head = head + 2;
m_vertex->next = head + 2;
m_index->tail += 2;
vtx_buff.head = head + 2;
vtx_buff.next = head + 2;
idx_buff.tail += 2;
break;
default:
ASSUME(0);
@@ -6105,14 +6080,14 @@ __forceinline void GSState::VertexKick(u32 skip)
// Update rectangle for the current draw. Needs exclusive endpoints.
const GSVector4i draw_rect = bbox.sra32<4>() + GSVector4i(0, 0, 1, 1);
if (m_index->tail != n)
if (idx_buff.tail != n)
temp_draw_rect = temp_draw_rect.runion(draw_rect);
else
temp_draw_rect = draw_rect;
temp_draw_rect = temp_draw_rect.rintersect(m_context->scissor.in);
constexpr u32 max_vertices = MaxVerticesForPrim(prim);
if (max_vertices != 0 && m_vertex->tail >= max_vertices)
if (max_vertices != 0 && vtx_buff.tail >= max_vertices)
Flush(VERTEXCOUNT);
}
@@ -6274,7 +6249,6 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL
const GSVector4i scissored_rc(int_rc.rintersect(m_context->scissor.in));
if (!int_rc.eq(scissored_rc))
{
const GSVertex* vert_first = &m_vertex->buff[m_index->buff[0]];
const GSVertex* vert_second = &m_vertex->buff[m_index->buff[1]];
const GSVertex* vert_third = &m_vertex->buff[m_index->buff[2]];
+1 -1
View File
@@ -506,7 +506,7 @@ public:
virtual void Move();
GSVector4i GetTEX0Rect(GSDrawingContext prev_ctx);
GSVector4i GetTEX0Rect(const GSDrawingContext& prev_ctx);
void CheckWriteOverlap(bool req_write, bool req_read);
void Write(const u8* mem, int len);
void Read(u8* mem, int len);
+85 -66
View File
@@ -222,7 +222,9 @@ void GSRendererHW::Lines2Sprites()
// each sprite converted to quad needs twice the space
while (m_vertex->tail * 2 > m_vertex->maxcount)
const int tail = m_vertex->tail * 2;
const int max_count = m_vertex->maxcount;
while (tail > max_count)
{
GrowVertexBuffer();
}
@@ -298,12 +300,13 @@ void GSRendererHW::Lines2Sprites()
void GSRendererHW::ExpandLineIndices()
{
const u32 process_count = (m_index->tail + 7) / 8 * 8;
GSIndexBuff& idx_buff = *m_index;
const u32 process_count = (idx_buff.tail + 7) / 8 * 8;
constexpr u32 expansion_factor = 3;
m_index->tail *= expansion_factor;
GSVector4i* end = reinterpret_cast<GSVector4i*>(m_index->buff);
GSVector4i* read = reinterpret_cast<GSVector4i*>(m_index->buff + process_count);
GSVector4i* write = reinterpret_cast<GSVector4i*>(m_index->buff + process_count * expansion_factor);
idx_buff.tail *= expansion_factor;
GSVector4i* end = reinterpret_cast<GSVector4i*>(idx_buff.buff);
GSVector4i* read = reinterpret_cast<GSVector4i*>(idx_buff.buff + process_count);
GSVector4i* write = reinterpret_cast<GSVector4i*>(idx_buff.buff + process_count * expansion_factor);
constexpr GSVector4i mask0 = GSVector4i::cxpr8(0, 1, 0, 1, 2, 3, 0, 1, 2, 3, 2, 3, 4, 5, 4, 5);
constexpr GSVector4i mask1 = GSVector4i::cxpr8(6, 7, 4, 5, 6, 7, 6, 7, 8, 9, 8, 9, 10, 11, 8, 9);
@@ -1428,7 +1431,8 @@ void GSRendererHW::MergeSprite(GSTextureCache::Source* tex)
}
else
{
for (u32 i = 2; i < (m_vertex->tail & ~1); i++)
const u32 tail = m_vertex->tail & ~1;
for (u32 i = 2; i < tail; i++)
{
bool unique_found = false;
@@ -1469,7 +1473,8 @@ void GSRendererHW::MergeSprite(GSTextureCache::Source* tex)
}
else
{
for (u32 i = 2; i < (m_vertex->tail & ~1); i++)
const u32 tail = m_vertex->tail & ~1;
for (u32 i = 2; i < tail; i++)
{
bool unique_found = false;
@@ -2235,16 +2240,16 @@ void GSRendererHW::HandleManualDeswizzle()
// Check if it's doing manual deswizzling first (draws are 32x16), if they are, check if the Z is flat, if not,
// we're gonna have to get creative and swap around the quandrants, but that's a TODO.
GSVertex* v = &m_vertex->buff[0];
GSIndexBuff& idx_buff = *m_index;
// Check for page quadrant and compare it to the quadrant from the verts, if it does match then we need to do correction.
const GSVector2i page_quadrant = GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].pgs / 2;
if (PRIM->FST)
{
for (u32 i = 0; i < m_index->tail; i += 2)
for (u32 i = 0; i < idx_buff.tail; i += 2)
{
const u32 index_first = m_index->buff[i];
const u32 index_last = m_index->buff[i + 1];
const u32 index_first = idx_buff.buff[i];
const u32 index_last = idx_buff.buff[i + 1];
if ((abs((v[index_last].U) - (v[index_first].U)) >> 4) != page_quadrant.x || (abs((v[index_last].V) - (v[index_first].V)) >> 4) != page_quadrant.y)
return;
@@ -2252,10 +2257,10 @@ void GSRendererHW::HandleManualDeswizzle()
}
else
{
for (u32 i = 0; i < m_index->tail; i += 2)
for (u32 i = 0; i < idx_buff.tail; i += 2)
{
const u32 index_first = m_index->buff[i];
const u32 index_last = m_index->buff[i + 1];
const u32 index_first = idx_buff.buff[i];
const u32 index_last = idx_buff.buff[i + 1];
const u32 x = abs(((v[index_last].ST.S / v[index_last].RGBAQ.Q) * (1 << m_context->TEX0.TW)) - ((v[index_first].ST.S / v[index_first].RGBAQ.Q) * (1 << m_context->TEX0.TW)));
const u32 y = abs(((v[index_last].ST.T / v[index_last].RGBAQ.Q) * (1 << m_context->TEX0.TH)) - ((v[index_first].ST.T / v[index_first].RGBAQ.Q) * (1 << m_context->TEX0.TH)));
@@ -2756,7 +2761,8 @@ void GSRendererHW::RoundSpriteOffset()
void GSRendererHW::Draw()
{
static u32 num_skipped_channel_shuffle_draws = 0;
GSVertexBuff& vtx_buff = *m_vertex;
GSIndexBuff& idx_buff = *m_index;
// We mess with this state as an optimization, so take a copy and use that instead.
const GSDrawingContext* context = m_context;
m_cached_ctx.TEX0 = context->TEX0;
@@ -3183,7 +3189,7 @@ void GSRendererHW::Draw()
}
const u32 vert_index = (m_vt.m_primclass == GS_TRIANGLE_CLASS) ? 2 : 1;
u32 const_color = m_vertex->buff[m_index->buff[vert_index]].RGBAQ.U32[0];
u32 const_color = vtx_buff.buff[idx_buff.buff[vert_index]].RGBAQ.U32[0];
u32 fb_mask = m_cached_ctx.FRAME.FBMSK;
// If we could just check the colour, it would be great, but Echo Night decided it's going to set the alpha and green to 128, for some reason, and actually be 32bit, so it ruined my day.
@@ -3219,7 +3225,7 @@ void GSRendererHW::Draw()
m_cached_ctx.TEXA.TA0 = 0;
m_cached_ctx.TEXA.TA1 = 128;
m_cached_ctx.FRAME.PSM = (m_cached_ctx.FRAME.PSM & 2) ? m_cached_ctx.FRAME.PSM : PSMCT16;
m_vertex->buff[m_index->buff[1]].RGBAQ.U32[0] = const_color;
vtx_buff.buff[idx_buff.buff[1]].RGBAQ.U32[0] = const_color;
ReplaceVerticesWithSprite(m_r, GSVector2i(m_r.width(), m_r.height()));
}
@@ -3444,13 +3450,13 @@ void GSRendererHW::Draw()
const u32 page_alignment = GSLocalMemory::IsPageAlignedMasked(m_cached_ctx.TEX0.PSM, m_r);
const bool page_aligned = (page_alignment & 0xF0F0) != 0; // Make sure Y is page aligned.
if (!no_rt && page_aligned && m_cached_ctx.ZBUF.ZMSK && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16 && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].trbpp <= 16 &&
(m_vt.m_primclass == GS_SPRITE_CLASS || (m_vt.m_primclass == GS_TRIANGLE_CLASS && (m_index->tail % 6) == 0 && TrianglesAreQuads(true) && m_index->tail > 6)))
(m_vt.m_primclass == GS_SPRITE_CLASS || (m_vt.m_primclass == GS_TRIANGLE_CLASS && (idx_buff.tail % 6) == 0 && TrianglesAreQuads(true) && idx_buff.tail > 6)))
{
// Tail check is to make sure we have enough strips to go all the way across the page, or if it's using a region clamp could be used to draw strips.
if (GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp == 16 &&
(m_index->tail >= (m_cached_ctx.TEX0.TBW * 2) || m_cached_ctx.TEX0.TBP0 == m_cached_ctx.FRAME.Block() || m_cached_ctx.CLAMP.WMS > CLAMP_CLAMP || m_cached_ctx.CLAMP.WMT > CLAMP_CLAMP))
(idx_buff.tail >= (m_cached_ctx.TEX0.TBW * 2) || m_cached_ctx.TEX0.TBP0 == m_cached_ctx.FRAME.Block() || m_cached_ctx.CLAMP.WMS > CLAMP_CLAMP || m_cached_ctx.CLAMP.WMT > CLAMP_CLAMP))
{
const GSVertex* v = &m_vertex->buff[0];
const GSVertex* v = &vtx_buff.buff[0];
const int first_x = std::clamp((static_cast<int>(((v[0].XYZ.X - m_context->XYOFFSET.OFX) + 8))) >> 4, 0, 2048);
const bool offset_last = PRIM->FST ? (v[1].U > v[0].U) : ((v[1].ST.S / v[1].RGBAQ.Q) > (v[0].ST.S / v[1].RGBAQ.Q));
@@ -3476,11 +3482,11 @@ void GSRendererHW::Draw()
{
bool shuffle_channel_reads = !m_cached_ctx.FRAME.FBMSK;
const u32 increment = (m_vt.m_primclass == GS_TRIANGLE_CLASS) ? 3 : 2;
const GSVertex* v = &m_vertex->buff[0];
const GSVertex* v = &vtx_buff.buff[0];
if (shuffle_channel_reads)
{
for (u32 i = 0; i < m_index->tail; i += increment)
for (u32 i = 0; i < idx_buff.tail; i += increment)
{
const int first_u = (PRIM->FST ? v[i].U : static_cast<int>(v[i].ST.S / v[(increment == 2) ? i + 1 : i].RGBAQ.Q)) >> 4;
const int second_u = (PRIM->FST ? v[i + 1].U : static_cast<int>(v[i + 1].ST.S / v[i + 1].RGBAQ.Q)) >> 4;
@@ -3829,9 +3835,10 @@ void GSRendererHW::Draw()
if (vertical_offset || horizontal_offset)
{
GSVertex* v = &m_vertex->buff[0];
GSVertex* v = &vtx_buff.buff[0];
const u32 tail = vtx_buff.tail;
for (u32 i = 0; i < m_vertex->tail; i++)
for (u32 i = 0; i < tail; i++)
{
v[i].XYZ.X += horizontal_offset << 4;
v[i].XYZ.Y += vertical_offset << 4;
@@ -4126,9 +4133,10 @@ void GSRendererHW::Draw()
if (vertical_offset || horizontal_offset)
{
GSVertex* v = &m_vertex->buff[0];
GSVertex* v = &vtx_buff.buff[0];
const u32 tail = vtx_buff.tail;
for (u32 i = 0; i < m_vertex->tail; i++)
for (u32 i = 0; i < tail; i++)
{
v[i].XYZ.X += horizontal_offset << 4;
v[i].XYZ.Y += vertical_offset << 4;
@@ -4587,13 +4595,13 @@ void GSRendererHW::Draw()
if (!m_texture_shuffle && !m_channel_shuffle)
{
// Try to turn blits in to single sprites, saves upscaling problems when striped clears/blits.
if (m_vt.m_primclass == GS_SPRITE_CLASS && m_primitive_covers_without_gaps == NoGapsType::FullCover && m_index->tail > 2 && (!PRIM->TME || TextureCoversWithoutGapsNotEqual()) && m_vt.m_eq.rgba == 0xFFFF)
if (m_vt.m_primclass == GS_SPRITE_CLASS && m_primitive_covers_without_gaps == NoGapsType::FullCover && idx_buff.tail > 2 && (!PRIM->TME || TextureCoversWithoutGapsNotEqual()) && m_vt.m_eq.rgba == 0xFFFF)
{
// Full final framebuffer only.
const GSVector2i fb_size = PCRTCDisplays.GetFramebufferSize(-1);
if (std::abs(fb_size.x - m_r.width()) <= 1 && std::abs(fb_size.y - m_r.height()) <= 1)
{
GSVertex* v = m_vertex->buff;
GSVertex* v = vtx_buff.buff;
v[0].XYZ.Z = v[1].XYZ.Z;
v[0].RGBAQ = v[1].RGBAQ;
@@ -4602,23 +4610,23 @@ void GSRendererHW::Draw()
m_vt.m_eq.z = true;
m_vt.m_eq.f = true;
v[1].XYZ.X = v[m_index->tail - 1].XYZ.X;
v[1].XYZ.Y = v[m_index->tail - 1].XYZ.Y;
v[1].XYZ.X = v[idx_buff.tail - 1].XYZ.X;
v[1].XYZ.Y = v[idx_buff.tail - 1].XYZ.Y;
if (PRIM->FST)
{
v[1].U = v[m_index->tail - 1].U;
v[1].V = v[m_index->tail - 1].V;
v[1].U = v[idx_buff.tail - 1].U;
v[1].V = v[idx_buff.tail - 1].V;
}
else
{
v[1].ST.S = v[m_index->tail - 1].ST.S;
v[1].ST.T = v[m_index->tail - 1].ST.T;
v[1].RGBAQ.Q = v[m_index->tail - 1].RGBAQ.Q;
v[1].ST.S = v[idx_buff.tail - 1].ST.S;
v[1].ST.T = v[idx_buff.tail - 1].ST.T;
v[1].RGBAQ.Q = v[idx_buff.tail - 1].RGBAQ.Q;
}
m_vertex->head = m_vertex->tail = m_vertex->next = 2;
m_index->tail = 2;
vtx_buff.head = vtx_buff.tail = vtx_buff.next = 2;
idx_buff.tail = 2;
}
}
@@ -5076,8 +5084,8 @@ void GSRendererHW::Draw()
// but it still needs to adjust native stuff from memory as it's not been compensated for upscaling (Dragon Quest 8 font for example).
if (CanUpscale() && (m_vt.m_primclass == GS_SPRITE_CLASS) && rt && rt->GetScale() > 1.0f)
{
const u32 count = m_vertex->next;
GSVertex* v = &m_vertex->buff[0];
const u32 count = vtx_buff.next;
GSVertex* v = &vtx_buff.buff[0];
// Hack to avoid vertical black line in various games (ace combat/tekken)
if (GSConfig.UserHacks_AlignSpriteX)
@@ -5304,33 +5312,35 @@ void GSRendererHW::Draw()
/// Verifies assumptions we expect to hold about indices
bool GSRendererHW::VerifyIndices()
{
GSIndexBuff& idx_buff = *m_index;
switch (m_vt.m_primclass)
{
case GS_SPRITE_CLASS:
if (m_index->tail % 2 != 0)
if (idx_buff.tail % 2 != 0)
return false;
[[fallthrough]];
case GS_POINT_CLASS:
// Expect indices to be flat increasing
for (u32 i = 0; i < m_index->tail; i++)
for (u32 i = 0; i < idx_buff.tail; i++)
{
if (m_index->buff[i] != i)
if (idx_buff.buff[i] != i)
return false;
}
break;
case GS_LINE_CLASS:
if (m_index->tail % 2 != 0)
if (idx_buff.tail % 2 != 0)
return false;
// Expect each line to be a pair next to each other
// VS expand relies on this!
for (u32 i = 0; i < m_index->tail; i += 2)
for (u32 i = 0; i < idx_buff.tail; i += 2)
{
if (m_index->buff[i] + 1 != m_index->buff[i + 1])
if (idx_buff.buff[i] + 1 != idx_buff.buff[i + 1])
return false;
}
break;
case GS_TRIANGLE_CLASS:
if (m_index->tail % 3 != 0)
if (idx_buff.tail % 3 != 0)
return false;
break;
case GS_INVALID_CLASS:
@@ -5351,15 +5361,17 @@ void GSRendererHW::HandleFlatShadedVertices()
if (!maybe_fix_vertices || dont_fix_vertices)
return;
const int n = GSUtil::GetClassVertexCount(m_vt.m_primclass);
const u32 n = GSUtil::GetClassVertexCount(m_vt.m_primclass);
GSVertexBuff& vtx_buff = *m_vertex;
GSIndexBuff& idx_buff = *m_index;
// If all vertices of each prim have the same color there is nothing to do.
bool prims_flat = true;
for (u32 i = 0; i < m_index->tail; i += n)
for (u32 i = 0; i < idx_buff.tail; i += n)
{
for (u32 j = 0; j < n - 1; j++)
{
if (m_vertex->buff[m_index->buff[i + j]].RGBAQ.U32[0] != m_vertex->buff[m_index->buff[i + n - 1]].RGBAQ.U32[0])
if (vtx_buff.buff[idx_buff.buff[i + j]].RGBAQ.U32[0] != vtx_buff.buff[idx_buff.buff[i + n - 1]].RGBAQ.U32[0])
{
prims_flat = false;
break;
@@ -5372,21 +5384,22 @@ void GSRendererHW::HandleFlatShadedVertices()
return;
// De-index the vertices using the copy buffer
while (m_vertex->maxcount < m_index->tail)
while (vtx_buff.maxcount < idx_buff.tail)
GrowVertexBuffer();
for (int i = static_cast<int>(m_index->tail) - 1; i >= 0; i--)
for (int i = static_cast<int>(idx_buff.tail) - 1; i >= 0; i--)
{
m_vertex->buff_copy[i] = m_vertex->buff[m_index->buff[i]];
m_index->buff[i] = static_cast<u16>(i);
vtx_buff.buff_copy[i] = vtx_buff.buff[idx_buff.buff[i]];
idx_buff.buff[i] = static_cast<u16>(i);
}
std::swap(m_vertex->buff, m_vertex->buff_copy);
m_vertex->head = m_vertex->next = m_vertex->tail = m_index->tail;
std::swap(vtx_buff.buff, vtx_buff.buff_copy);
vtx_buff.head = vtx_buff.next = vtx_buff.tail = idx_buff.tail;
// Make all vertices the same color to simplify handling in expand shaders.
for (u32 i = 0; i < m_index->tail; i += n)
for (u32 i = 0; i < idx_buff.tail; i += n)
{
for (u32 j = 0; j < n - 1; j++)
m_vertex->buff[i + j].RGBAQ.U32[0] = m_vertex->buff[i + n - 1].RGBAQ.U32[0];
vtx_buff.buff[i + j].RGBAQ.U32[0] = vtx_buff.buff[i + n - 1].RGBAQ.U32[0];
}
}
@@ -9869,11 +9882,13 @@ bool GSRendererHW::DetectStripedDoubleClear(bool& no_rt, bool& no_ds)
// and I could cheat and stop when we get a size that matches, but that might be a lucky misdetection, I don't wanna risk it.
int vertex_offset = 0;
int last_vertex = m_vertex->buff[0].XYZ.X;
const u32 tail = m_vertex->tail;
GSVertexBuff& vtx_buff = *m_vertex;
for (u32 i = 1; i < m_vertex->tail; i++)
for (u32 i = 1; i < tail; i++)
{
vertex_offset = std::max(static_cast<int>((m_vertex->buff[i].XYZ.X - last_vertex) >> 4), vertex_offset);
last_vertex = m_vertex->buff[i].XYZ.X;
vertex_offset = std::max(static_cast<int>((vtx_buff.buff[i].XYZ.X - last_vertex) >> 4), vertex_offset);
last_vertex = vtx_buff.buff[i].XYZ.X;
// Found a gap which is much bigger, no point continuing to scan.
if (vertex_offset > strip_size)
@@ -10609,12 +10624,13 @@ bool GSRendererHW::TextureCoversWithoutGapsNotEqual()
const int first_dpX = v[1].XYZ.X - v[0].XYZ.X;
const int first_dtV = v[1].V - v[0].V;
const int first_dtU = v[1].U - v[0].U;
const u32 next_count = m_vertex->next;
// Horizontal Match.
if ((first_dpX >> 4) == m_r.z)
{
// Borrowed from MergeSprite() modified to calculate heights.
for (u32 i = 2; i < m_vertex->next; i += 2)
for (u32 i = 2; i < next_count; i += 2)
{
const int last_tV = v[i - 1].V;
const int dtV = v[i + 1].V - v[i].V;
@@ -10632,7 +10648,7 @@ bool GSRendererHW::TextureCoversWithoutGapsNotEqual()
if ((first_dpY >> 4) == m_r.w)
{
// Borrowed from MergeSprite().
for (u32 i = 2; i < m_vertex->next; i += 2)
for (u32 i = 2; i < next_count; i += 2)
{
const int last_tU = v[i - 1].U;
const int this_start_U = v[i].U;
@@ -10888,10 +10904,13 @@ void GSRendererHW::OffsetDraw(s32 fbp_offset, s32 zbp_offset, s32 xoffset, s32 y
const s32 fp_xoffset = xoffset << 4;
const s32 fp_yoffset = yoffset << 4;
for (u32 i = 0; i < m_vertex->next; i++)
GSVertexBuff& vtx_buff = *m_vertex;
for (u32 i = 0; i < vtx_buff.next; i++)
{
m_vertex->buff[i].XYZ.X += fp_xoffset;
m_vertex->buff[i].XYZ.Y += fp_yoffset;
vtx_buff.buff[i].XYZ.X += fp_xoffset;
vtx_buff.buff[i].XYZ.Y += fp_yoffset;
}
m_vt.m_min.p.x += static_cast<float>(xoffset);
+2 -2
View File
@@ -205,7 +205,7 @@ bool CubebAudioStream::Initialize(const char* driver_name, const char* device_na
}
cubeb_devid selected_device = nullptr;
cubeb_device_collection devices;
cubeb_device_collection devices = {};
bool devices_valid = false;
if (device_name && *device_name)
{
@@ -350,7 +350,7 @@ std::vector<AudioStream::DeviceInfo> AudioStream::GetCubebOutputDevices(const ch
ScopedGuard context_cleanup([context]() { cubeb_destroy(context); });
cubeb_device_collection devices;
cubeb_device_collection devices = {};
rv = cubeb_enumerate_devices(context, CUBEB_DEVICE_TYPE_OUTPUT, &devices);
if (rv != CUBEB_OK)
{
+10 -6
View File
@@ -441,12 +441,16 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
// GPU
const char* gpu_suffix = "";
if (GSConfig.UseDebugDevice && GSConfig.HWROV)
gpu_suffix = " (Debug & ROV)";
else if (GSConfig.UseDebugDevice)
gpu_suffix = " (Debug)";
else if (GSConfig.HWROV)
gpu_suffix = " (ROV)";
if (GSConfig.Renderer != GSRendererType::SW)
{
if (GSConfig.UseDebugDevice && GSConfig.HWROV)
gpu_suffix = " (Debug & ROV)";
else if (GSConfig.UseDebugDevice)
gpu_suffix = " (Debug)";
else if (GSConfig.HWROV)
gpu_suffix = " (ROV)";
}
s_hardware_info_gpu_line.format(
"GPU: {}{}",
+1 -1
View File
@@ -247,7 +247,7 @@ static void doBranch(s32 tar) {
}
// Override the memory size argument to IOPBOOT
if(tar == 0xbfc4a000) {
if(static_cast<u32>(tar) == 0xbfc4a000) {
psxRegs.GPR.n.a0 = Ps2MemSize::ExposedIopRam >> 20;
}