diff --git a/CMakeLists.txt b/CMakeLists.txt index 19310e3cf..de350b96f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,7 +73,7 @@ if(GIT_FOUND AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git") OUTPUT_STRIP_TRAILING_WHITESPACE ) if(WINDOWS_STORE) - string(REPLACE "v" "" MS_VERSION ${GIT_VERSION}) + string(REGEX REPLACE "[Vv]" "" MS_VERSION ${GIT_VERSION}) string(REPLACE "-" "." MS_VERSION ${MS_VERSION}) string(REGEX REPLACE "\.g[0-9a-f]+" "" MS_VERSION ${MS_VERSION}) string(REGEX MATCH "[0-9]+\.[0-9]+\.[0-9]+" VERSION_3PARTS ${MS_VERSION}) @@ -176,10 +176,6 @@ else() target_compile_options(${PROJECT_NAME} PRIVATE $<$:-fno-strict-aliasing> $<$:-Wall>) - if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - target_compile_options(${PROJECT_NAME} PRIVATE - $<$:-Wno-nullability-completeness>) - endif() endif() target_compile_definitions(${PROJECT_NAME} PRIVATE @@ -1184,6 +1180,7 @@ if(USE_VULKAN) endif() add_library(VulkanMemoryAllocator INTERFACE) + target_compile_options(VulkanMemoryAllocator INTERFACE $<$,$>:-Wno-nullability-completeness>) target_include_directories(VulkanMemoryAllocator INTERFACE core/deps/VulkanMemoryAllocator/include) target_link_libraries(${PROJECT_NAME} PRIVATE VulkanMemoryAllocator) diff --git a/README.md b/README.md index c08eebf43..d5f155f7c 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Join us on our [**Discord server**](https://discord.gg/X8YWP8w) for a chat. ## Install -### Flatpak (Linux) +### Flatpak (Linux ![ubuntu logo](https://flyinghead.github.io/flycast-builds/ubuntu.png)) 1. [Set up Flatpak](https://www.flatpak.org/setup/). @@ -27,7 +27,7 @@ Join us on our [**Discord server**](https://discord.gg/X8YWP8w) for a chat. `flatpak run org.flycast.Flycast` -### Homebrew (MacOS) +### Homebrew (MacOS ![apple logo](https://flyinghead.github.io/flycast-builds/apple.png)) 1. [Set up Homebrew](https://brew.sh). @@ -35,7 +35,7 @@ Join us on our [**Discord server**](https://discord.gg/X8YWP8w) for a chat. `brew install --cask flycast` -### Xbox One/Series +### Xbox One/Series ![xbox logo](https://flyinghead.github.io/flycast-builds/xbox.png) #### Retail: Open [**gamr13's github page**](https://gamr13.github.io/) from your Xbox console. @@ -43,7 +43,7 @@ Open [**gamr13's github page**](https://gamr13.github.io/) from your Xbox consol #### Dev Mode: Grab the latest build from [**the builds page**](https://flyinghead.github.io/flycast-builds/), or the [**GitHub Actions**](https://github.com/flyinghead/flycast/actions/workflows/uwp.yml). Then install it using the **Xbox Device Portal**. -### Binaries +### Binaries ![android](https://flyinghead.github.io/flycast-builds/android.jpg) ![windows](https://flyinghead.github.io/flycast-builds/windows.png) ![linux](https://flyinghead.github.io/flycast-builds/ubuntu.png) ![apple](https://flyinghead.github.io/flycast-builds/apple.png) ![switch](https://flyinghead.github.io/flycast-builds/switch.png) ![xbox](https://flyinghead.github.io/flycast-builds/xbox.png) Get fresh builds for your system [**on the builds page**](https://flyinghead.github.io/flycast-builds/). diff --git a/core/cheats.cpp b/core/cheats.cpp index 7951f34b9..b57b1c5ee 100644 --- a/core/cheats.cpp +++ b/core/cheats.cpp @@ -150,7 +150,8 @@ const WidescreenCheat CheatManager::widescreen_cheats[] = { "MK-5102250", "V1.001", { 0x107FDC, 0x11253C }, { 0x3F99999A, 0x3F900000 } }, // Metropolis Street Racer (v1.001) (PAL) { "MK-5102250", "V1.009", { 0x106B5C, 0x1111F4 }, { 0x3F99999A, 0x3F900000 } }, // Metropolis Street Racer (v1.009) (PAL) { "MK-51012", nullptr, { 0x10A01C, 0x1146FC }, { 0x3F99999A, 0x3F900000 } }, // Metropolis Street Racer (USA) - { "T0000M", nullptr, { 0x1CAEAC, 0x1CAEDC }, { 0x43F00000, 0x3F400000 } }, // Millenium Racer Y2K Fighters + { "T0000M", "MILLENNIUM RACER - Y2K FIGHTERS ", + { 0x1CAEAC, 0x1CAEDC }, { 0x43F00000, 0x3F400000 } }, // Millenium Racer Y2K Fighters { "T1221M", nullptr, { 0x426B74 }, { 0x43F00000 } }, // Moero! Justice Gauken (JP) { "T9701D", nullptr, { 0x31290C }, { 0x3F400000 } }, // Mortal Kombat Gold (PAL) { "T-9701N", nullptr, { 0x337B8C }, { 0x3FA66666 } }, // Mortal Kombat Gold (USA) @@ -434,6 +435,21 @@ void CheatManager::reset(const std::string& gameId) cheats.emplace_back(Cheat::Type::setValue, "Skip DIMM version check", true, 16, 0x0007f486, 0xe001); // mov #1, r0 cheats.back().builtIn = true; } + else if (gameId == "Fixed BOOT strapper") // Extreme Hunting 2 + { + setActive(true); + cheats.emplace_back(Cheat::Type::runNextIfEq, "skip netbd check ifeq", true, 32, 0x00067b04, 0); + cheats.back().builtIn = true; + cheats.emplace_back(Cheat::Type::setValue, "skip netbd check", true, 32, 0x00067b04, 1); // 1 skips initNetwork() + cheats.back().builtIn = true; + cheats.emplace_back(Cheat::Type::setValue, "skip netbd check 2", true, 16, 0x0009acc8, 0x0009); // not acceptable by main board + cheats.back().builtIn = true; + // ac010000 should be d202 9302, but is changed to 78c0 8c93 + cheats.emplace_back(Cheat::Type::runNextIfEq, "fix boot ifeq", true, 32, 0x00010000, 0x8c9378c0); + cheats.back().builtIn = true; + cheats.emplace_back(Cheat::Type::setValue, "fix boot", true, 32, 0x00010000, 0x9302d202); + cheats.back().builtIn = true; + } } if (config::WidescreenGameHacks) { diff --git a/core/emulator.cpp b/core/emulator.cpp index 2cf6c3c71..5a6b31f96 100644 --- a/core/emulator.cpp +++ b/core/emulator.cpp @@ -196,16 +196,13 @@ static void loadSpecialSettings() NOTICE_LOG(BOOT, "Game doesn't support RGB. Using TV Composite instead"); config::Cable.override(3); } - if (prod_id == "T9512N" // The Grinch (US) - || prod_id == "T9503D" // The Grinch (EU) - || prod_id == "T-9707N" // San Francisco Rush 2049 (US) - || prod_id == "T-9709D-50" // San Francisco Rush 2049 (EU) - || prod_id == "T7001D 50" // Jimmy White's 2 Cueball + if (prod_id == "T7001D 50" // Jimmy White's 2 Cueball || prod_id == "T40505D 50" // Railroad Tycoon 2 (EU) || prod_id == "T18702M" // Miss Moonlight || prod_id == "T0019M" // KenJu Atomiswave DC Conversion || prod_id == "T0020M" // Force Five Atomiswave DC Conversion - || prod_id == "HDR-0187") // Fushigi no Dungeon - Fuurai no Shiren Gaiden - Onna Kenshi Asuka Kenzan! + || prod_id == "HDR-0187" // Fushigi no Dungeon - Fuurai no Shiren Gaiden - Onna Kenshi Asuka Kenzan! + || prod_id == "T15104D 50") // Slave Zero (PAL) { NOTICE_LOG(BOOT, "Forcing real BIOS"); config::UseReios.override(false); @@ -224,7 +221,8 @@ static void loadSpecialSettings() config::Broadcast.override(1); } if (prod_id == "T1102M" // Densha de Go! 2 - || prod_id == "T00000A") // The Ring of the Nibelungen (demo, hack) + || prod_id == "T00000A" // The Ring of the Nibelungen (demo, hack) + || prod_id == "T15124N 00") // Worms Pinball (prototype) { NOTICE_LOG(BOOT, "Forcing Full Framebuffer Emulation"); config::EmulateFramebuffer.override(true); @@ -286,8 +284,9 @@ static void loadSpecialSettings() else if (prod_id == "NINJA ASSAULT" || prod_id == "Sports Shooting USA" // AW || prod_id == "SEGA CLAY CHALLENGE" // AW - || prod_id == "RANGER MISSION" // AW - || prod_id == "EXTREME HUNTING") // AW + || prod_id == "RANGER MISSION" // AW + || prod_id == "EXTREME HUNTING" // AW + || prod_id == "Fixed BOOT strapper")// Extreme hunting 2 (AW) { INFO_LOG(BOOT, "Enabling lightgun setup for game %s", prod_id.c_str()); settings.input.JammaSetup = JVS::LightGun; diff --git a/core/hw/maple/maple_if.cpp b/core/hw/maple/maple_if.cpp index d19446fb0..f903f3921 100644 --- a/core/hw/maple/maple_if.cpp +++ b/core/hw/maple/maple_if.cpp @@ -261,7 +261,7 @@ static void maple_DoDma() // Maple bus max speed: 2 Mb/s, actual speed: 1 Mb/s //printf("Maple XFER size %d bytes - %.2f ms\n", xfer_count, xfer_count * 1000.0f / (128 * 1024)); if (!occupy) - sh4_sched_request(maple_schid, std::min((u64)xfer_count * (SH4_MAIN_CLOCK / (128 * 1024)), (u64)SH4_MAIN_CLOCK)); + sh4_sched_request(maple_schid, std::min((u64)xfer_count * (SH4_MAIN_CLOCK / (256 * 1024)), (u64)SH4_MAIN_CLOCK)); } static int maple_schd(int tag, int c, int j) diff --git a/core/hw/pvr/ta_util.cpp b/core/hw/pvr/ta_util.cpp index 2d5203946..3b47e5e1c 100644 --- a/core/hw/pvr/ta_util.cpp +++ b/core/hw/pvr/ta_util.cpp @@ -144,7 +144,6 @@ void sortTriangles(rend_context& ctx, RenderPass& pass, const RenderPass& previo //re-assemble them into drawing commands - size_t initialSize = ctx.sortedTriangles.size(); int idx = -1; int idxSize = ctx.idx.size(); @@ -182,7 +181,7 @@ void sortTriangles(rend_context& ctx, RenderPass& pass, const RenderPass& previo // Add a dummy one to signal we're using sorted triangles ctx.sortedTriangles.push_back({ pp_base, 0, 0}); } - pass.sorted_tr_count = ctx.sortedTriangles.size() - initialSize; + pass.sorted_tr_count = ctx.sortedTriangles.size(); #if PRINT_SORT_STATS printf("Reassembled into %d from %d\n", (int)ctx.sortedTriangles.size(), pp_end - pp_base); diff --git a/core/hw/pvr/ta_vtx.cpp b/core/hw/pvr/ta_vtx.cpp index f321ca3a2..6258fa402 100644 --- a/core/hw/pvr/ta_vtx.cpp +++ b/core/hw/pvr/ta_vtx.cpp @@ -1171,6 +1171,7 @@ static void parseRenderPass(RenderPass& pass, const RenderPass& previousPass, re makeIndex(ctx.global_param_op, previousPass.op_count, pass.op_count, true, ctx); makeIndex(ctx.global_param_pt, previousPass.pt_count, pass.pt_count, true, ctx); } + pass.sorted_tr_count = previousPass.sorted_tr_count; if (pass.autosort && !perPixel) { if (config::PerStripSorting) diff --git a/core/imgread/cdi.cpp b/core/imgread/cdi.cpp index 8f07ca48f..f96fb189d 100644 --- a/core/imgread/cdi.cpp +++ b/core/imgread/cdi.cpp @@ -12,7 +12,7 @@ Disc* cdi_parse(const char* file, std::vector *digest) if (fsource == nullptr) { - WARN_LOG(COMMON, "Cannot open file '%s' errno %d", file, errno); + WARN_LOG(GDROM, "Cannot open file '%s' errno %d", file, errno); throw FlycastException(std::string("Cannot open CDI file ") + file); } @@ -101,7 +101,15 @@ Disc* cdi_parse(const char* file, std::vector *digest) t.CTRL=track.mode==0?0:4; t.StartFAD=track.start_lba+track.pregap_length; t.EndFAD=t.StartFAD+track.length-1; - t.file = new RawTrackFile(nowide::fopen(file, "rb"), track.position + track.pregap_length * track.sector_size, t.StartFAD, track.sector_size); + FILE *trackFile = nowide::fopen(file, "rb"); + if (trackFile == nullptr) + { + delete rv; + std::fclose(fsource); + WARN_LOG(GDROM, "Cannot re-open file '%s' errno %d", file, errno); + throw FlycastException("Cannot re-open CDI file"); + } + t.file = new RawTrackFile(trackFile, track.position + track.pregap_length * track.sector_size, t.StartFAD, track.sector_size); rv->tracks.push_back(t); diff --git a/core/oslib/audiobackend_oboe.cpp b/core/oslib/audiobackend_oboe.cpp index 5241b16bd..c7137a6f7 100644 --- a/core/oslib/audiobackend_oboe.cpp +++ b/core/oslib/audiobackend_oboe.cpp @@ -58,12 +58,17 @@ class OboeBackend : AudioBackend public: AudioErrorCallback(OboeBackend *backend) : backend(backend) {} - void onErrorAfterClose(oboe::AudioStream *stream, oboe::Result error) override { - WARN_LOG(AUDIO, "Audio device lost. Attempting to reopen the audio stream"); - // the oboe stream is already closed so make sure we don't close it twice - backend->stream.reset(); - backend->term(); - backend->init(); + void onErrorAfterClose(oboe::AudioStream *stream, oboe::Result error) override + { + // Only attempt to recover if init was successful + if (backend->stream != nullptr) + { + WARN_LOG(AUDIO, "Audio device lost. Attempting to reopen the audio stream"); + // the oboe stream is already closed so make sure we don't close it twice + backend->stream.reset(); + backend->term(); + backend->init(); + } } OboeBackend *backend; diff --git a/core/oslib/oslib.cpp b/core/oslib/oslib.cpp index d5422d9e3..aebe6cb82 100644 --- a/core/oslib/oslib.cpp +++ b/core/oslib/oslib.cpp @@ -20,6 +20,7 @@ #include "stdclass.h" #include "cfg/cfg.h" #include "cfg/option.h" +#include "nowide/fstream.hpp" #ifndef _WIN32 #include #endif @@ -218,9 +219,24 @@ void uploadCrashes(const std::string& directory) if (config::UploadCrashLogs) { NOTICE_LOG(COMMON, "Uploading minidump %s", line); + std::string version = std::string(GIT_VERSION); + if (file_exists(logfile)) + { + nowide::ifstream ifs(logfile); + if (ifs.is_open()) + { + std::string line; + while (std::getline(ifs, line)) + if (line.substr(0, 9) == "Version: ") + { + version = line.substr(9); + break; + } + } + } std::vector fields; fields.emplace_back("upload_file_minidump", dmpfile, "application/octet-stream"); - fields.emplace_back("sentry[release]", std::string(GIT_VERSION)); + fields.emplace_back("sentry[release]", version); if (file_exists(logfile)) fields.emplace_back("flycast_log", logfile, "text/plain"); // TODO config, gpu/driver, ... diff --git a/core/reios/reios.cpp b/core/reios/reios.cpp index 43126196d..dd6452d40 100644 --- a/core/reios/reios.cpp +++ b/core/reios/reios.cpp @@ -373,7 +373,8 @@ static void reios_sys_misc() typedef void hook_fp(); -static void setup_syscall(u32 hook_addr, u32 syscall_addr) { +static void setup_syscall(u32 hook_addr, u32 syscall_addr) +{ WriteMem32(syscall_addr, hook_addr); WriteMem16(hook_addr, REIOS_OPCODE); @@ -383,6 +384,25 @@ static void setup_syscall(u32 hook_addr, u32 syscall_addr) { static void reios_setup_state(u32 boot_addr) { + // San Francisco Rush checksum + short *p = (short *)GetMemPtr(0x8c0010f0, 2); + int chksum = (int)0xFFF937D1; + for (int i = 0; i < 10; i++) + chksum -= *p++; + p += 0xee - 1; + for (int i = 0; i < 3; i++) + chksum += *p++; + p += 0x347 - 1; + for (int i = 0; i < 11; i++) + chksum -= *p++; + p += 0xbf8 - 1; + for (int i = 0; i < 98; i++) + { + short v = chksum < 0 ? std::min(-chksum, 32767) : std::max(-chksum, -32768); + *p = v; + chksum += *p++; + } + // Set up AICA interrupt masks aica::writeAicaReg(SCIEB_addr, (u16)0x48); aica::writeAicaReg(SCILV0_addr, (u8)0x18); @@ -711,6 +731,11 @@ void reios_reset(u8* rom) rom16[0] = REIOS_OPCODE; + // The Grinch game bug + *(u32 *)&rom[0x44c] = 0xe303d463; + // Jeremy McGrath game bug + *(u32 *)&rom[0x1c] = 0x71294118; + u8 *pFont = rom + (FONT_TABLE_ADDR % BIOS_SIZE); // 288 12 × 24 pixels (36 bytes) characters diff --git a/core/rend/dx11/oit/dx11_oitrenderer.cpp b/core/rend/dx11/oit/dx11_oitrenderer.cpp index 1d65e89f9..d56eea0b8 100644 --- a/core/rend/dx11/oit/dx11_oitrenderer.cpp +++ b/core/rend/dx11/oit/dx11_oitrenderer.cpp @@ -1,711 +1,711 @@ -/* - Copyright 2021 flyinghead - - This file is part of Flycast. - - Flycast is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 2 of the License, or - (at your option) any later version. - - Flycast is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Flycast. If not, see . -*/ -#include "types.h" -#include "hw/pvr/Renderer_if.h" -#include -#include "../dx11context.h" -#include "../dx11_renderer.h" -#include "rend/transform_matrix.h" -#include "../dx11_texture.h" -#include "dx11_oitshaders.h" -#include "../dx11_renderstate.h" -#include "dx11_oitbuffers.h" -#include "dx11_oitshaders.h" -#include "rend/tileclip.h" - -const D3D11_INPUT_ELEMENT_DESC MainLayout[] -{ - { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, (UINT)offsetof(Vertex, x), D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "COLOR", 0, DXGI_FORMAT_B8G8R8A8_UNORM, 0, (UINT)offsetof(Vertex, col), D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "COLOR", 1, DXGI_FORMAT_B8G8R8A8_UNORM, 0, (UINT)offsetof(Vertex, spc), D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)offsetof(Vertex, u), D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "COLOR", 2, DXGI_FORMAT_B8G8R8A8_UNORM, 0, (UINT)offsetof(Vertex, col1), D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "COLOR", 3, DXGI_FORMAT_B8G8R8A8_UNORM, 0, (UINT)offsetof(Vertex, spc1), D3D11_INPUT_PER_VERTEX_DATA, 0 }, - { "TEXCOORD", 1, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)offsetof(Vertex, u1), D3D11_INPUT_PER_VERTEX_DATA, 0 }, - // Naomi 2 - { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, (UINT)offsetof(Vertex, nx), D3D11_INPUT_PER_VERTEX_DATA, 0 }, -}; - -struct DX11OITRenderer : public DX11Renderer -{ - struct PixelPolyConstants - { - float clipTest[4]; - int blend_mode0[2]; - int blend_mode1[2]; - float paletteIndex; - float trilinearAlpha; - - // two volume mode - int shading_instr0; - int shading_instr1; - int fog_control0; - int fog_control1; - int use_alpha0; - int use_alpha1; - int ignore_tex_alpha0; - int ignore_tex_alpha1; - }; - - bool Init() override - { - if (!DX11Renderer::Init()) - return false; - pxlPolyConstants.reset(); - D3D11_BUFFER_DESC desc{}; - desc.Usage = D3D11_USAGE_DYNAMIC; - desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - desc.ByteWidth = sizeof(PixelPolyConstants); - desc.ByteWidth = (((desc.ByteWidth - 1) >> 4) + 1) << 4; - bool success = SUCCEEDED(device->CreateBuffer(&desc, nullptr, &pxlPolyConstants.get())); - - shaders.init(device, theDX11Context.getCompiler()); - buffers.init(device, deviceContext); - pixelBufferSize = config::PixelBufferSize; - ComPtr blob = shaders.getVertexShaderBlob(); - mainInputLayout.reset(); +/* + Copyright 2021 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ +#include "types.h" +#include "hw/pvr/Renderer_if.h" +#include +#include "../dx11context.h" +#include "../dx11_renderer.h" +#include "rend/transform_matrix.h" +#include "../dx11_texture.h" +#include "dx11_oitshaders.h" +#include "../dx11_renderstate.h" +#include "dx11_oitbuffers.h" +#include "dx11_oitshaders.h" +#include "rend/tileclip.h" + +const D3D11_INPUT_ELEMENT_DESC MainLayout[] +{ + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, (UINT)offsetof(Vertex, x), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_B8G8R8A8_UNORM, 0, (UINT)offsetof(Vertex, col), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 1, DXGI_FORMAT_B8G8R8A8_UNORM, 0, (UINT)offsetof(Vertex, spc), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)offsetof(Vertex, u), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 2, DXGI_FORMAT_B8G8R8A8_UNORM, 0, (UINT)offsetof(Vertex, col1), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 3, DXGI_FORMAT_B8G8R8A8_UNORM, 0, (UINT)offsetof(Vertex, spc1), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 1, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)offsetof(Vertex, u1), D3D11_INPUT_PER_VERTEX_DATA, 0 }, + // Naomi 2 + { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, (UINT)offsetof(Vertex, nx), D3D11_INPUT_PER_VERTEX_DATA, 0 }, +}; + +struct DX11OITRenderer : public DX11Renderer +{ + struct PixelPolyConstants + { + float clipTest[4]; + int blend_mode0[2]; + int blend_mode1[2]; + float paletteIndex; + float trilinearAlpha; + + // two volume mode + int shading_instr0; + int shading_instr1; + int fog_control0; + int fog_control1; + int use_alpha0; + int use_alpha1; + int ignore_tex_alpha0; + int ignore_tex_alpha1; + }; + + bool Init() override + { + if (!DX11Renderer::Init()) + return false; + pxlPolyConstants.reset(); + D3D11_BUFFER_DESC desc{}; + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + desc.ByteWidth = sizeof(PixelPolyConstants); + desc.ByteWidth = (((desc.ByteWidth - 1) >> 4) + 1) << 4; + bool success = SUCCEEDED(device->CreateBuffer(&desc, nullptr, &pxlPolyConstants.get())); + + shaders.init(device, theDX11Context.getCompiler()); + buffers.init(device, deviceContext); + pixelBufferSize = config::PixelBufferSize; + ComPtr blob = shaders.getVertexShaderBlob(); + mainInputLayout.reset(); success = SUCCEEDED(device->CreateInputLayout(MainLayout, std::size(MainLayout), blob->GetBufferPointer(), blob->GetBufferSize(), &mainInputLayout.get())) && success; - - blob = shaders.getFinalVertexShaderBlob(); - success = SUCCEEDED(device->CreateInputLayout(MainLayout, 0, blob->GetBufferPointer(), blob->GetBufferSize(), &finalInputLayout.get())) && success; - - desc.ByteWidth = sizeof(int); - desc.ByteWidth = (((desc.ByteWidth - 1) >> 4) + 1) << 4; - desc.Usage = D3D11_USAGE_DYNAMIC; - desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - success = SUCCEEDED(device->CreateBuffer(&desc, nullptr, &vtxPolyConstants.get())) && success; - - return success; - } - - void resize(int w, int h) override - { - if (w == (int)width && h == (int)height && opaqueTex != nullptr) - return; - DX11Renderer::resize(w, h); - buffers.resize(w, h); - - createTexAndRenderTarget(opaqueTex, opaqueRenderTarget, width, height); - multipassTex.reset(); - multipassRenderTarget.reset(); - multipassTextureView.reset(); - opaqueTextureView.reset(); - D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc{}; - viewDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - viewDesc.Texture2D.MipLevels = 1; - device->CreateShaderResourceView(opaqueTex, &viewDesc, &opaqueTextureView.get()); - - // For depth pass. Use a 32-bit format for depth to avoid loss of precision - createDepthTexAndView(depthStencilTex2, depthStencilView2, width, height, DXGI_FORMAT_R32G8X24_TYPELESS, D3D11_BIND_SHADER_RESOURCE); - stencilView.reset(); - viewDesc.Format = DXGI_FORMAT_X32_TYPELESS_G8X24_UINT; - device->CreateShaderResourceView(depthStencilTex2, &viewDesc, &stencilView.get()); - - depthView.reset(); - viewDesc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; - device->CreateShaderResourceView(depthStencilTex2, &viewDesc, &depthView.get()); - - createDepthTexAndView(depthTex, depthTexView, width, height, DXGI_FORMAT_R32G8X24_TYPELESS); - } - - void setRTTSize(int width, int height) override { - buffers.resize(width, height); - } - - void Term() override - { - vtxPolyConstants.reset(); - finalInputLayout.reset(); - mainInputLayout.reset(); - multipassTextureView.reset(); - multipassRenderTarget.reset(); - multipassTex.reset(); - opaqueTextureView.reset(); - opaqueRenderTarget.reset(); - opaqueTex.reset(); - shaders.term(); - buffers.term(); - DX11Renderer::Term(); - } - - template - void setRenderState(const PolyParam *gp, int polyNumber) - { - ComPtr vertexShader = shaders.getVertexShader(gp->pcw.Gouraud, gp->isNaomi2(), false, pass != DX11OITShaders::Depth); - deviceContext->VSSetShader(vertexShader, nullptr, 0); - - PixelPolyConstants constants; - if (gp->pcw.Texture && gp->tsp.FilterMode > 1 && Type != ListType_Punch_Through && gp->tcw.MipMapped == 1) - { - constants.trilinearAlpha = 0.25f * (gp->tsp.MipMapD & 0x3); - if (gp->tsp.FilterMode == 2) - // Trilinear pass A - constants.trilinearAlpha = 1.f - constants.trilinearAlpha; - } - else - constants.trilinearAlpha = 1.f; - - int clip_rect[4] = {}; - TileClipping clipmode = GetTileClip(gp->tileclip, matrices.GetViewportMatrix(), clip_rect); - bool gpuPalette = gp->texture != nullptr ? gp->texture->gpuPalette : false; - // Two volumes mode only supported for OP and PT - bool two_volumes_mode = (gp->tsp1.full != (u32)-1) && Type != ListType_Translucent; - bool useTexture; - - ComPtr pixelShader; - if (pass == DX11OITShaders::Depth) - { - useTexture = Type == ListType_Punch_Through ? gp->pcw.Texture : false; - pixelShader = shaders.getShader( - useTexture, - gp->tsp.UseAlpha, - gp->tsp.IgnoreTexA, - 0, - false, - 2, - false, - false, - gpuPalette, - gp->pcw.Gouraud, - useTexture, - clipmode == TileClipping::Inside, - false, - two_volumes_mode, - pass); - } - else - { - bool color_clamp = gp->tsp.ColorClamp && (pvrrc.fog_clamp_min.full != 0 || pvrrc.fog_clamp_max.full != 0xffffffff); - - int fog_ctrl = config::Fog ? gp->tsp.FogCtrl : 2; - useTexture = gp->pcw.Texture; - - pixelShader = shaders.getShader( - useTexture, - gp->tsp.UseAlpha, - gp->tsp.IgnoreTexA, - gp->tsp.ShadInstr, - gp->pcw.Offset, - fog_ctrl, - gp->tcw.PixelFmt == PixelBumpMap, - color_clamp, - gpuPalette, - gp->pcw.Gouraud, - Type == ListType_Punch_Through, - clipmode == TileClipping::Inside, - gp->pcw.Texture && gp->tsp.FilterMode == 0 && !gp->tsp.ClampU && !gp->tsp.ClampV && !gp->tsp.FlipU && !gp->tsp.FlipV, - two_volumes_mode, - pass); - - } - deviceContext->PSSetShader(pixelShader, nullptr, 0); - - if (gpuPalette) - { - if (gp->tcw.PixelFmt == PixelPal4) - constants.paletteIndex = (float)(gp->tcw.PalSelect << 4); - else - constants.paletteIndex = (float)((gp->tcw.PalSelect >> 4) << 8); - } - - if (clipmode == TileClipping::Outside) - { - RECT rect { clip_rect[0], clip_rect[1], clip_rect[0] + clip_rect[2], clip_rect[1] + clip_rect[3] }; - deviceContext->RSSetScissorRects(1, &rect); - } - else - { - deviceContext->RSSetScissorRects(1, &scissorRect); - if (clipmode == TileClipping::Inside) - { - constants.clipTest[0] = (float)clip_rect[0]; - constants.clipTest[1] = (float)clip_rect[1]; - constants.clipTest[2] = (float)(clip_rect[0] + clip_rect[2]); - constants.clipTest[3] = (float)(clip_rect[1] + clip_rect[3]); - } - } - constants.blend_mode0[0] = gp->tsp.SrcInstr; - constants.blend_mode0[1] = gp->tsp.DstInstr; - if (two_volumes_mode) - { - constants.blend_mode1[0] = gp->tsp1.SrcInstr; - constants.blend_mode1[1] = gp->tsp1.DstInstr; - constants.shading_instr0 = gp->tsp.ShadInstr; - constants.shading_instr1 = gp->tsp1.ShadInstr; - constants.fog_control0 = gp->tsp.FogCtrl; - constants.fog_control1 = gp->tsp1.FogCtrl; - constants.use_alpha0 = gp->tsp.UseAlpha; - constants.use_alpha1 = gp->tsp1.UseAlpha; - constants.ignore_tex_alpha0 = gp->tsp.IgnoreTexA; - constants.ignore_tex_alpha1 = gp->tsp1.IgnoreTexA; - } - D3D11_MAPPED_SUBRESOURCE mappedSubres; - deviceContext->Map(pxlPolyConstants, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedSubres); - memcpy(mappedSubres.pData, &constants, sizeof(constants)); - deviceContext->Unmap(pxlPolyConstants, 0); - - if (!gp->isNaomi2()) - { - deviceContext->Map(vtxPolyConstants, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedSubres); - memcpy(mappedSubres.pData, &polyNumber, sizeof(polyNumber)); - deviceContext->Unmap(vtxPolyConstants, 0); - deviceContext->VSSetConstantBuffers(1, 1, &vtxPolyConstants.get()); - } - - if (pass == DX11OITShaders::Color) - { - // Apparently punch-through polys support blending, or at least some combinations - if (Type == ListType_Translucent || Type == ListType_Punch_Through) - deviceContext->OMSetBlendState(blendStates.getState(true, gp->tsp.SrcInstr, gp->tsp.DstInstr), nullptr, 0xffffffff); - else - deviceContext->OMSetBlendState(blendStates.getState(false, gp->tsp.SrcInstr, gp->tsp.DstInstr), nullptr, 0xffffffff); - } - if (useTexture) - { - for (int i = 0; i < 2; i++) - { - DX11Texture *texture = (DX11Texture *)(i == 0 ? gp->texture : gp->texture1); - if (texture == nullptr) - continue; - int slot = i == 0 ? 0 : 3; - deviceContext->PSSetShaderResources(slot, 1, &texture->textureView.get()); - TSP tsp = i == 0 ? gp->tsp : gp->tsp1; - bool linearFiltering; - if (config::TextureFiltering == 0) - linearFiltering = tsp.FilterMode != 0 && !gpuPalette; - else if (config::TextureFiltering == 1) - linearFiltering = false; - else - linearFiltering = true; - auto sampler = samplers->getSampler(linearFiltering, tsp.ClampU, tsp.ClampV, tsp.FlipU, tsp.FlipV); - deviceContext->PSSetSamplers(slot, 1, &sampler.get()); - } - } - - setCullMode(gp->isp.CullMode); - - //set Z mode, only if required - int zfunc; - if (Type == ListType_Punch_Through || (pass == DX11OITShaders::Depth && SortingEnabled)) - zfunc = 6; // GEQ - else - zfunc = gp->isp.DepthMode; - - bool zwriteEnable = false; - if (pass == DX11OITShaders::Depth || pass == DX11OITShaders::Color) - { - // Z Write Disable seems to be ignored for punch-through. - // Fixes Worms World Party, Bust-a-Move 4 and Re-Volt - if (Type == ListType_Punch_Through) - zwriteEnable = true; - else - zwriteEnable = !gp->isp.ZWriteDis; - } - bool needStencil = config::ModifierVolumes && pass == DX11OITShaders::Depth && Type != ListType_Translucent; - const u32 stencil = (gp->pcw.Shadow != 0) ? 0x80 : 0; - deviceContext->OMSetDepthStencilState(depthStencilStates.getState(true, zwriteEnable, zfunc, needStencil), stencil); - - if (gp->isNaomi2()) - n2Helper.setConstants(*gp, polyNumber, pvrrc); - } - - template - void drawList(const std::vector& gply, int first, int count) - { - if (count == 0) - return; - deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - - const PolyParam *params = &gply[first]; - - u32 firstVertexIdx = Type == ListType_Translucent ? pvrrc.idx[gply[0].first] : 0; - while (count-- > 0) - { - if (params->count > 2) - { - if ((Type == ListType_Opaque || (Type == ListType_Translucent && !SortingEnabled)) && params->isp.DepthMode == 0) - { - // depthFunc = never - params++; - continue; - } - setRenderState(params, (int)((params - &gply[0]) << 17) - firstVertexIdx); - deviceContext->DrawIndexed(params->count, params->first, 0); - } - - params++; - } - } - - template - void drawModVols(int first, int count, const ModifierVolumeParam *modVolParams) - { - if (count == 0 || pvrrc.modtrig.empty() || !config::ModifierVolumes) - return; - - deviceContext->IASetInputLayout(modVolInputLayout); - unsigned int stride = 3 * sizeof(float); - unsigned int offset = 0; - deviceContext->IASetVertexBuffers(0, 1, &modvolBuffer.get(), &stride, &offset); - deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - if (!Transparent) - deviceContext->PSSetShader(shaders.getModVolShader(), nullptr, 0); - deviceContext->RSSetScissorRects(1, &scissorRect); - - const ModifierVolumeParam *params = &modVolParams[first]; - int mod_base = -1; - int curMVMat = -1; - int curProjMat = -1; - - for (int cmv = 0; cmv < count; cmv++) - { - const ModifierVolumeParam& param = params[cmv]; - - u32 mv_mode = param.isp.DepthMode; - - if (mod_base == -1) - mod_base = param.first; - - if (param.count > 0) - { - if (param.isNaomi2() && (param.mvMatrix != curMVMat || param.projMatrix != curProjMat)) - { - curMVMat = param.mvMatrix; - curProjMat = param.projMatrix; - n2Helper.setConstants(pvrrc.matrices[param.mvMatrix].mat, pvrrc.matrices[param.projMatrix].mat); - } - deviceContext->VSSetShader(shaders.getMVVertexShader(param.isNaomi2()), nullptr, 0); - if (Transparent) - { - if (!param.isp.VolumeLast && mv_mode > 0) - // OR'ing (open volume or quad) - deviceContext->PSSetShader(shaders.getTrModVolShader(DepthStencilStates::Or), nullptr, 0); - else - // XOR'ing (closed volume) - deviceContext->PSSetShader(shaders.getTrModVolShader(DepthStencilStates::Xor), nullptr, 0); - } - else - { - if (!param.isp.VolumeLast && mv_mode > 0) - // OR'ing (open volume or quad) - deviceContext->OMSetDepthStencilState(depthStencilStates.getMVState(DepthStencilStates::Or), 2); - else - // XOR'ing (closed volume) - deviceContext->OMSetDepthStencilState(depthStencilStates.getMVState(DepthStencilStates::Xor), 0); - } - setCullMode(param.isp.CullMode); - deviceContext->Draw(param.count * 3, param.first * 3); - } - - if (mv_mode == 1 || mv_mode == 2) - { - // Sum the area - if (Transparent) - deviceContext->PSSetShader(shaders.getTrModVolShader(mv_mode == 1 ? DepthStencilStates::Inclusion : DepthStencilStates::Exclusion), nullptr, 0); - else - deviceContext->OMSetDepthStencilState(depthStencilStates.getMVState(mv_mode == 1 ? DepthStencilStates::Inclusion : DepthStencilStates::Exclusion), 1); - deviceContext->Draw((param.first + param.count - mod_base) * 3, mod_base * 3); - mod_base = -1; - } - } - - // Restore main input layout and vertex buffers - deviceContext->IASetInputLayout(mainInputLayout); - stride = sizeof(Vertex); - offset = 0; - deviceContext->IASetVertexBuffers(0, 1, &vertexBuffer.get(), &stride, &offset); - deviceContext->IASetIndexBuffer(indexBuffer, DXGI_FORMAT_R32_UINT, 0); - } - - void renderABuffer(bool lastPass) - { - if (!lastPass) - deviceContext->OMSetRenderTargetsAndUnorderedAccessViews(1, &multipassRenderTarget.get(), nullptr, 0, D3D11_KEEP_UNORDERED_ACCESS_VIEWS, nullptr, nullptr); - else if (pvrrc.isRTT) - deviceContext->OMSetRenderTargetsAndUnorderedAccessViews(1, &rttRenderTarget.get(), nullptr, 0, D3D11_KEEP_UNORDERED_ACCESS_VIEWS, nullptr, nullptr); - else - deviceContext->OMSetRenderTargetsAndUnorderedAccessViews(1, &fbRenderTarget.get(), nullptr, 0, D3D11_KEEP_UNORDERED_ACCESS_VIEWS, nullptr, nullptr); - deviceContext->OMSetBlendState(blendStates.getState(false), nullptr, 0xffffffff); - deviceContext->PSSetShaderResources(0, 1, &opaqueTextureView.get()); - auto sampler = samplers->getSampler(false); - deviceContext->PSSetSamplers(0, 1, &sampler.get()); - deviceContext->RSSetScissorRects(1, &scissorRect); - deviceContext->OMSetDepthStencilState(depthStencilStates.getState(false, false, 0, false), 0); - setCullMode(0); - - deviceContext->IASetInputLayout(finalInputLayout); - deviceContext->VSSetShader(shaders.getFinalVertexShader(), nullptr, 0); - deviceContext->PSSetShader(shaders.getFinalShader(), nullptr, 0); - - deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - deviceContext->Draw(4, 0); - } - - void drawStrips() - { - { - // tr_poly_params - std::vector trPolyParams(pvrrc.global_param_tr.size() * 2); - int i = 0; - for (const PolyParam& pp : pvrrc.global_param_tr) - { - trPolyParams[i++] = (pp.tsp.full & 0xffff00c0) | ((pp.isp.full >> 16) & 0xe400) | ((pp.pcw.full >> 7) & 1); - trPolyParams[i++] = pp.tsp1.full; - } - u32 newSize = (u32)(trPolyParams.size() * sizeof(u32)); - if (newSize > 0) - { - if (!trPolyParamsBuffer || trPolyParamsBufferSize < newSize) - { - trPolyParamsBufferView.reset(); - trPolyParamsBuffer.reset(); - D3D11_BUFFER_DESC desc{}; - desc.ByteWidth = newSize; - desc.Usage = D3D11_USAGE_DYNAMIC; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; - desc.StructureByteStride = sizeof(u32) * 2; // sizeof(struct PolyParam) - desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - - HRESULT hr = device->CreateBuffer(&desc, nullptr, &trPolyParamsBuffer.get()); - if (FAILED(hr)) - WARN_LOG(RENDERER, "TR poly params buffer creation failed"); - else - { - trPolyParamsBufferSize = newSize; - D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc{}; - viewDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; - viewDesc.Format = DXGI_FORMAT_UNKNOWN; - viewDesc.Buffer.NumElements = desc.ByteWidth / desc.StructureByteStride; - - hr = device->CreateShaderResourceView(trPolyParamsBuffer, &viewDesc, &trPolyParamsBufferView.get()); - if (FAILED(hr)) - WARN_LOG(RENDERER, "TR poly params buffer view creation failed"); - } - } - D3D11_MAPPED_SUBRESOURCE mappedSubres; - deviceContext->Map(trPolyParamsBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedSubres); - memcpy(mappedSubres.pData, trPolyParams.data(), newSize); - deviceContext->Unmap(trPolyParamsBuffer, 0); - - deviceContext->PSSetShaderResources(5, 1, &trPolyParamsBufferView.get()); - } - } - - buffers.bind(); - deviceContext->ClearDepthStencilView(depthTexView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 0.f, 0); - deviceContext->ClearDepthStencilView(depthStencilView2, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 0.f, 0); - - RenderPass previous_pass {}; - int render_pass_count = (int)pvrrc.render_passes.size(); - for (int render_pass = 0; render_pass < render_pass_count; render_pass++) - { - const RenderPass& current_pass = pvrrc.render_passes[render_pass]; - u32 op_count = current_pass.op_count - previous_pass.op_count; - u32 pt_count = current_pass.pt_count - previous_pass.pt_count; - u32 tr_count = current_pass.tr_count - previous_pass.tr_count; - u32 mvo_count = current_pass.mvo_count - previous_pass.mvo_count; - DEBUG_LOG(RENDERER, "Render pass %d OP %d PT %d TR %d MV %d Tr MV %d autosort %d", render_pass + 1, - op_count, pt_count, tr_count, mvo_count, - current_pass.mv_op_tr_shared ? mvo_count : current_pass.mvo_tr_count - previous_pass.mvo_tr_count, - current_pass.autosort); - - // - // PASS 1: Geometry pass to update depth and stencil - // - // unbind depth/stencil - ID3D11ShaderResourceView *p = nullptr; - deviceContext->PSSetShaderResources(4, 1, &p); - // disable color writes - deviceContext->OMSetBlendState(blendStates.getState(false, 0, 0, true), nullptr, 0xffffffff); - deviceContext->OMSetRenderTargetsAndUnorderedAccessViews(1, &opaqueRenderTarget.get(), depthStencilView2, 0, D3D11_KEEP_UNORDERED_ACCESS_VIEWS, nullptr, nullptr); - - drawList(pvrrc.global_param_op, previous_pass.op_count, op_count); - drawList(pvrrc.global_param_pt, previous_pass.pt_count, pt_count); - drawModVols(previous_pass.mvo_count, mvo_count, &pvrrc.global_param_mvo[0]); - - // - // PASS 2: Render OP and PT to opaque render target - // - deviceContext->OMSetRenderTargetsAndUnorderedAccessViews(1, &opaqueRenderTarget.get(), depthTexView, 0, D3D11_KEEP_UNORDERED_ACCESS_VIEWS, nullptr, nullptr); - deviceContext->PSSetShaderResources(4, 1, &stencilView.get()); - - drawList(pvrrc.global_param_op, previous_pass.op_count, op_count); - drawList(pvrrc.global_param_pt, previous_pass.pt_count, pt_count); - - // - // PASS 3: Render TR to a-buffers - // - if (current_pass.autosort) - { - deviceContext->PSSetShaderResources(4, 1, &depthView.get()); - // disable color writes - deviceContext->OMSetBlendState(blendStates.getState(false, 0, 0, true), nullptr, 0xffffffff); - drawList(pvrrc.global_param_tr, previous_pass.tr_count, tr_count); - if (render_pass < render_pass_count - 1) - { - // - // PASS 3b: Geometry pass with TR to update the depth for the next TA render pass - // - ID3D11ShaderResourceView *p = nullptr; - deviceContext->PSSetShaderResources(4, 1, &p); - deviceContext->OMSetRenderTargetsAndUnorderedAccessViews(1, &opaqueRenderTarget.get(), depthTexView, 0, D3D11_KEEP_UNORDERED_ACCESS_VIEWS, nullptr, nullptr); - drawList(pvrrc.global_param_tr, previous_pass.tr_count, tr_count); - } - ID3D11ShaderResourceView *p = nullptr; - deviceContext->PSSetShaderResources(4, 1, &p); - if (!theDX11Context.isIntel()) - { - // Intel Iris Plus 640 just crashes - if (current_pass.mv_op_tr_shared) - drawModVols(previous_pass.mvo_count, mvo_count, &pvrrc.global_param_mvo[0]); - else - drawModVols(previous_pass.mvo_tr_count, current_pass.mvo_tr_count - previous_pass.mvo_tr_count, &pvrrc.global_param_mvo_tr[0]); - } - } - else - { - ID3D11ShaderResourceView *p = nullptr; - deviceContext->PSSetShaderResources(4, 1, &p); - drawList(pvrrc.global_param_tr, previous_pass.tr_count, tr_count); - } - if (render_pass < render_pass_count - 1) - { - // - // PASS 3c: Render a-buffer to temporary texture - // - if (!multipassTex) - { - createTexAndRenderTarget(multipassTex, multipassRenderTarget, width, height); - multipassTextureView.reset(); - D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc{}; - viewDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; - viewDesc.Texture2D.MipLevels = 1; - device->CreateShaderResourceView(multipassTex, &viewDesc, &multipassTextureView.get()); - } - - renderABuffer(false); - std::swap(opaqueTex, multipassTex); - std::swap(opaqueRenderTarget, multipassRenderTarget); - std::swap(opaqueTextureView, multipassTextureView); - deviceContext->PSSetShaderResources(0, 1, &p); - deviceContext->IASetInputLayout(mainInputLayout); - - // Clear the stencil from this pass - deviceContext->ClearDepthStencilView(depthStencilView2, D3D11_CLEAR_STENCIL, 0.f, 0); - } - - previous_pass = current_pass; - } - - // - // PASS 4: Render a-buffers to screen - // - renderABuffer(true); - } - - bool Render() override - { - resize(pvrrc.framebufferWidth, pvrrc.framebufferHeight); - if (pixelBufferSize != config::PixelBufferSize) - { - buffers.init(device, deviceContext); - pixelBufferSize = config::PixelBufferSize; - } - - // Make sure to unbind the framebuffer view before setting it as render target - ID3D11ShaderResourceView *p = nullptr; - deviceContext->PSSetShaderResources(0, 1, &p); - // To avoid DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET warnings - deviceContext->OMSetRenderTargets(1, &fbRenderTarget.get(), nullptr); - configVertexShader(); - - bool is_rtt = pvrrc.isRTT; - - deviceContext->IASetInputLayout(mainInputLayout); - - n2Helper.resetCache(); - uploadGeometryBuffers(); - - updateFogTexture(); - updatePaletteTexture(); - - setupPixelShaderConstants(); - - drawStrips(); - - if (is_rtt) - { - readRttRenderTarget(pvrrc.fb_W_SOF1 & VRAM_MASK); - } - else if (config::EmulateFramebuffer) - { - writeFramebufferToVRAM(); - } - else - { - aspectRatio = getOutputFramebufferAspectRatio(); -#ifndef LIBRETRO - deviceContext->OMSetRenderTargets(1, &theDX11Context.getRenderTarget().get(), nullptr); - displayFramebuffer(); - DrawOSD(false); - theDX11Context.setFrameRendered(); -#else - theDX11Context.drawOverlay(width, height); - ID3D11RenderTargetView *nullView = nullptr; - deviceContext->OMSetRenderTargets(1, &nullView, nullptr); - deviceContext->PSSetShaderResources(0, 1, &fbTextureView.get()); -#endif - frameRendered = true; - frameRenderedOnce = true; - } - - return !is_rtt; - } - -private: - Buffers buffers; - DX11OITShaders shaders; - ComPtr opaqueTex; - ComPtr opaqueRenderTarget; - ComPtr opaqueTextureView; - ComPtr multipassTex; - ComPtr multipassRenderTarget; - ComPtr multipassTextureView; - ComPtr stencilView; - ComPtr depthView; - ComPtr depthStencilTex2; - ComPtr depthStencilView2; - ComPtr trPolyParamsBuffer; - u32 trPolyParamsBufferSize = 0; - ComPtr trPolyParamsBufferView; - ComPtr mainInputLayout; // FIXME - ComPtr finalInputLayout; - ComPtr vtxPolyConstants; - int64_t pixelBufferSize = 0; -}; - -Renderer *rend_OITDirectX11() -{ - return new DX11OITRenderer(); -} + + blob = shaders.getFinalVertexShaderBlob(); + success = SUCCEEDED(device->CreateInputLayout(MainLayout, 0, blob->GetBufferPointer(), blob->GetBufferSize(), &finalInputLayout.get())) && success; + + desc.ByteWidth = sizeof(int); + desc.ByteWidth = (((desc.ByteWidth - 1) >> 4) + 1) << 4; + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + success = SUCCEEDED(device->CreateBuffer(&desc, nullptr, &vtxPolyConstants.get())) && success; + + return success; + } + + void resize(int w, int h) override + { + if (w == (int)width && h == (int)height && opaqueTex != nullptr) + return; + DX11Renderer::resize(w, h); + buffers.resize(w, h); + + createTexAndRenderTarget(opaqueTex, opaqueRenderTarget, width, height); + multipassTex.reset(); + multipassRenderTarget.reset(); + multipassTextureView.reset(); + opaqueTextureView.reset(); + D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc{}; + viewDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + viewDesc.Texture2D.MipLevels = 1; + device->CreateShaderResourceView(opaqueTex, &viewDesc, &opaqueTextureView.get()); + + // For depth pass. Use a 32-bit format for depth to avoid loss of precision + createDepthTexAndView(depthStencilTex2, depthStencilView2, width, height, DXGI_FORMAT_R32G8X24_TYPELESS, D3D11_BIND_SHADER_RESOURCE); + stencilView.reset(); + viewDesc.Format = DXGI_FORMAT_X32_TYPELESS_G8X24_UINT; + device->CreateShaderResourceView(depthStencilTex2, &viewDesc, &stencilView.get()); + + depthView.reset(); + viewDesc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; + device->CreateShaderResourceView(depthStencilTex2, &viewDesc, &depthView.get()); + + createDepthTexAndView(depthTex, depthTexView, width, height, DXGI_FORMAT_R32G8X24_TYPELESS); + } + + void setRTTSize(int width, int height) override { + buffers.resize(width, height); + } + + void Term() override + { + vtxPolyConstants.reset(); + finalInputLayout.reset(); + mainInputLayout.reset(); + multipassTextureView.reset(); + multipassRenderTarget.reset(); + multipassTex.reset(); + opaqueTextureView.reset(); + opaqueRenderTarget.reset(); + opaqueTex.reset(); + shaders.term(); + buffers.term(); + DX11Renderer::Term(); + } + + template + void setRenderState(const PolyParam *gp, int polyNumber) + { + ComPtr vertexShader = shaders.getVertexShader(gp->pcw.Gouraud, gp->isNaomi2(), false, pass != DX11OITShaders::Depth); + deviceContext->VSSetShader(vertexShader, nullptr, 0); + + PixelPolyConstants constants; + if (gp->pcw.Texture && gp->tsp.FilterMode > 1 && Type != ListType_Punch_Through && gp->tcw.MipMapped == 1) + { + constants.trilinearAlpha = 0.25f * (gp->tsp.MipMapD & 0x3); + if (gp->tsp.FilterMode == 2) + // Trilinear pass A + constants.trilinearAlpha = 1.f - constants.trilinearAlpha; + } + else + constants.trilinearAlpha = 1.f; + + int clip_rect[4] = {}; + TileClipping clipmode = GetTileClip(gp->tileclip, matrices.GetViewportMatrix(), clip_rect); + bool gpuPalette = gp->texture != nullptr ? gp->texture->gpuPalette : false; + // Two volumes mode only supported for OP and PT + bool two_volumes_mode = (gp->tsp1.full != (u32)-1) && Type != ListType_Translucent; + bool useTexture; + + ComPtr pixelShader; + if (pass == DX11OITShaders::Depth) + { + useTexture = Type == ListType_Punch_Through ? gp->pcw.Texture : false; + pixelShader = shaders.getShader( + useTexture, + gp->tsp.UseAlpha, + gp->tsp.IgnoreTexA, + 0, + false, + 2, + false, + false, + gpuPalette, + gp->pcw.Gouraud, + useTexture, + clipmode == TileClipping::Inside, + false, + two_volumes_mode, + pass); + } + else + { + bool color_clamp = gp->tsp.ColorClamp && (pvrrc.fog_clamp_min.full != 0 || pvrrc.fog_clamp_max.full != 0xffffffff); + + int fog_ctrl = config::Fog ? gp->tsp.FogCtrl : 2; + useTexture = gp->pcw.Texture; + + pixelShader = shaders.getShader( + useTexture, + gp->tsp.UseAlpha, + gp->tsp.IgnoreTexA, + gp->tsp.ShadInstr, + gp->pcw.Offset, + fog_ctrl, + gp->tcw.PixelFmt == PixelBumpMap, + color_clamp, + gpuPalette, + gp->pcw.Gouraud, + Type == ListType_Punch_Through, + clipmode == TileClipping::Inside, + gp->pcw.Texture && gp->tsp.FilterMode == 0 && !gp->tsp.ClampU && !gp->tsp.ClampV && !gp->tsp.FlipU && !gp->tsp.FlipV, + two_volumes_mode, + pass); + + } + deviceContext->PSSetShader(pixelShader, nullptr, 0); + + if (gpuPalette) + { + if (gp->tcw.PixelFmt == PixelPal4) + constants.paletteIndex = (float)(gp->tcw.PalSelect << 4); + else + constants.paletteIndex = (float)((gp->tcw.PalSelect >> 4) << 8); + } + + if (clipmode == TileClipping::Outside) + { + RECT rect { clip_rect[0], clip_rect[1], clip_rect[0] + clip_rect[2], clip_rect[1] + clip_rect[3] }; + deviceContext->RSSetScissorRects(1, &rect); + } + else + { + deviceContext->RSSetScissorRects(1, &scissorRect); + if (clipmode == TileClipping::Inside) + { + constants.clipTest[0] = (float)clip_rect[0]; + constants.clipTest[1] = (float)clip_rect[1]; + constants.clipTest[2] = (float)(clip_rect[0] + clip_rect[2]); + constants.clipTest[3] = (float)(clip_rect[1] + clip_rect[3]); + } + } + constants.blend_mode0[0] = gp->tsp.SrcInstr; + constants.blend_mode0[1] = gp->tsp.DstInstr; + if (two_volumes_mode) + { + constants.blend_mode1[0] = gp->tsp1.SrcInstr; + constants.blend_mode1[1] = gp->tsp1.DstInstr; + constants.shading_instr0 = gp->tsp.ShadInstr; + constants.shading_instr1 = gp->tsp1.ShadInstr; + constants.fog_control0 = gp->tsp.FogCtrl; + constants.fog_control1 = gp->tsp1.FogCtrl; + constants.use_alpha0 = gp->tsp.UseAlpha; + constants.use_alpha1 = gp->tsp1.UseAlpha; + constants.ignore_tex_alpha0 = gp->tsp.IgnoreTexA; + constants.ignore_tex_alpha1 = gp->tsp1.IgnoreTexA; + } + D3D11_MAPPED_SUBRESOURCE mappedSubres; + deviceContext->Map(pxlPolyConstants, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedSubres); + memcpy(mappedSubres.pData, &constants, sizeof(constants)); + deviceContext->Unmap(pxlPolyConstants, 0); + + if (!gp->isNaomi2()) + { + deviceContext->Map(vtxPolyConstants, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedSubres); + memcpy(mappedSubres.pData, &polyNumber, sizeof(polyNumber)); + deviceContext->Unmap(vtxPolyConstants, 0); + deviceContext->VSSetConstantBuffers(1, 1, &vtxPolyConstants.get()); + } + + if (pass == DX11OITShaders::Color) + { + // Apparently punch-through polys support blending, or at least some combinations + if (Type == ListType_Translucent || Type == ListType_Punch_Through) + deviceContext->OMSetBlendState(blendStates.getState(true, gp->tsp.SrcInstr, gp->tsp.DstInstr), nullptr, 0xffffffff); + else + deviceContext->OMSetBlendState(blendStates.getState(false, gp->tsp.SrcInstr, gp->tsp.DstInstr), nullptr, 0xffffffff); + } + if (useTexture) + { + for (int i = 0; i < 2; i++) + { + DX11Texture *texture = (DX11Texture *)(i == 0 ? gp->texture : gp->texture1); + if (texture == nullptr) + continue; + int slot = i == 0 ? 0 : 3; + deviceContext->PSSetShaderResources(slot, 1, &texture->textureView.get()); + TSP tsp = i == 0 ? gp->tsp : gp->tsp1; + bool linearFiltering; + if (config::TextureFiltering == 0) + linearFiltering = tsp.FilterMode != 0 && !gpuPalette; + else if (config::TextureFiltering == 1) + linearFiltering = false; + else + linearFiltering = true; + auto sampler = samplers->getSampler(linearFiltering, tsp.ClampU, tsp.ClampV, tsp.FlipU, tsp.FlipV); + deviceContext->PSSetSamplers(slot, 1, &sampler.get()); + } + } + + setCullMode(gp->isp.CullMode); + + //set Z mode, only if required + int zfunc; + if (Type == ListType_Punch_Through || (pass == DX11OITShaders::Depth && SortingEnabled)) + zfunc = 6; // GEQ + else + zfunc = gp->isp.DepthMode; + + bool zwriteEnable = false; + if (pass == DX11OITShaders::Depth || pass == DX11OITShaders::Color) + { + // Z Write Disable seems to be ignored for punch-through. + // Fixes Worms World Party, Bust-a-Move 4 and Re-Volt + if (Type == ListType_Punch_Through) + zwriteEnable = true; + else + zwriteEnable = !gp->isp.ZWriteDis; + } + bool needStencil = config::ModifierVolumes && pass == DX11OITShaders::Depth && Type != ListType_Translucent; + const u32 stencil = (gp->pcw.Shadow != 0) ? 0x80 : 0; + deviceContext->OMSetDepthStencilState(depthStencilStates.getState(true, zwriteEnable, zfunc, needStencil), stencil); + + if (gp->isNaomi2()) + n2Helper.setConstants(*gp, polyNumber, pvrrc); + } + + template + void drawList(const std::vector& gply, int first, int count) + { + if (count == 0) + return; + deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + + const PolyParam *params = &gply[first]; + + u32 firstVertexIdx = Type == ListType_Translucent ? pvrrc.idx[gply[0].first] : 0; + while (count-- > 0) + { + if (params->count > 2) + { + if ((Type == ListType_Opaque || (Type == ListType_Translucent && !SortingEnabled)) && params->isp.DepthMode == 0) + { + // depthFunc = never + params++; + continue; + } + setRenderState(params, (int)((params - &gply[0]) << 17) - firstVertexIdx); + deviceContext->DrawIndexed(params->count, params->first, 0); + } + + params++; + } + } + + template + void drawModVols(int first, int count, const ModifierVolumeParam *modVolParams) + { + if (count == 0 || pvrrc.modtrig.empty() || !config::ModifierVolumes) + return; + + deviceContext->IASetInputLayout(modVolInputLayout); + unsigned int stride = 3 * sizeof(float); + unsigned int offset = 0; + deviceContext->IASetVertexBuffers(0, 1, &modvolBuffer.get(), &stride, &offset); + deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + if (!Transparent) + deviceContext->PSSetShader(shaders.getModVolShader(), nullptr, 0); + deviceContext->RSSetScissorRects(1, &scissorRect); + + const ModifierVolumeParam *params = &modVolParams[first]; + int mod_base = -1; + int curMVMat = -1; + int curProjMat = -1; + + for (int cmv = 0; cmv < count; cmv++) + { + const ModifierVolumeParam& param = params[cmv]; + + u32 mv_mode = param.isp.DepthMode; + + if (mod_base == -1) + mod_base = param.first; + + if (param.count > 0) + { + if (param.isNaomi2() && (param.mvMatrix != curMVMat || param.projMatrix != curProjMat)) + { + curMVMat = param.mvMatrix; + curProjMat = param.projMatrix; + n2Helper.setConstants(pvrrc.matrices[param.mvMatrix].mat, pvrrc.matrices[param.projMatrix].mat); + } + deviceContext->VSSetShader(shaders.getMVVertexShader(param.isNaomi2()), nullptr, 0); + if (Transparent) + { + if (!param.isp.VolumeLast && mv_mode > 0) + // OR'ing (open volume or quad) + deviceContext->PSSetShader(shaders.getTrModVolShader(DepthStencilStates::Or), nullptr, 0); + else + // XOR'ing (closed volume) + deviceContext->PSSetShader(shaders.getTrModVolShader(DepthStencilStates::Xor), nullptr, 0); + } + else + { + if (!param.isp.VolumeLast && mv_mode > 0) + // OR'ing (open volume or quad) + deviceContext->OMSetDepthStencilState(depthStencilStates.getMVState(DepthStencilStates::Or), 2); + else + // XOR'ing (closed volume) + deviceContext->OMSetDepthStencilState(depthStencilStates.getMVState(DepthStencilStates::Xor), 0); + } + setCullMode(param.isp.CullMode); + deviceContext->Draw(param.count * 3, param.first * 3); + } + + if (mv_mode == 1 || mv_mode == 2) + { + // Sum the area + if (Transparent) + deviceContext->PSSetShader(shaders.getTrModVolShader(mv_mode == 1 ? DepthStencilStates::Inclusion : DepthStencilStates::Exclusion), nullptr, 0); + else + deviceContext->OMSetDepthStencilState(depthStencilStates.getMVState(mv_mode == 1 ? DepthStencilStates::Inclusion : DepthStencilStates::Exclusion), 1); + deviceContext->Draw((param.first + param.count - mod_base) * 3, mod_base * 3); + mod_base = -1; + } + } + + // Restore main input layout and vertex buffers + deviceContext->IASetInputLayout(mainInputLayout); + stride = sizeof(Vertex); + offset = 0; + deviceContext->IASetVertexBuffers(0, 1, &vertexBuffer.get(), &stride, &offset); + deviceContext->IASetIndexBuffer(indexBuffer, DXGI_FORMAT_R32_UINT, 0); + } + + void renderABuffer(bool lastPass) + { + if (!lastPass) + deviceContext->OMSetRenderTargetsAndUnorderedAccessViews(1, &multipassRenderTarget.get(), nullptr, 0, D3D11_KEEP_UNORDERED_ACCESS_VIEWS, nullptr, nullptr); + else if (pvrrc.isRTT) + deviceContext->OMSetRenderTargetsAndUnorderedAccessViews(1, &rttRenderTarget.get(), nullptr, 0, D3D11_KEEP_UNORDERED_ACCESS_VIEWS, nullptr, nullptr); + else + deviceContext->OMSetRenderTargetsAndUnorderedAccessViews(1, &fbRenderTarget.get(), nullptr, 0, D3D11_KEEP_UNORDERED_ACCESS_VIEWS, nullptr, nullptr); + deviceContext->OMSetBlendState(blendStates.getState(false), nullptr, 0xffffffff); + deviceContext->PSSetShaderResources(0, 1, &opaqueTextureView.get()); + auto sampler = samplers->getSampler(false); + deviceContext->PSSetSamplers(0, 1, &sampler.get()); + deviceContext->RSSetScissorRects(1, &scissorRect); + deviceContext->OMSetDepthStencilState(depthStencilStates.getState(false, false, 0, false), 0); + setCullMode(0); + + deviceContext->IASetInputLayout(finalInputLayout); + deviceContext->VSSetShader(shaders.getFinalVertexShader(), nullptr, 0); + deviceContext->PSSetShader(shaders.getFinalShader(), nullptr, 0); + + deviceContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + deviceContext->Draw(4, 0); + } + + void drawStrips() + { + { + // tr_poly_params + std::vector trPolyParams(pvrrc.global_param_tr.size() * 2); + int i = 0; + for (const PolyParam& pp : pvrrc.global_param_tr) + { + trPolyParams[i++] = (pp.tsp.full & 0xffff00c0) | ((pp.isp.full >> 16) & 0xe400) | ((pp.pcw.full >> 7) & 1); + trPolyParams[i++] = pp.tsp1.full; + } + u32 newSize = (u32)(trPolyParams.size() * sizeof(u32)); + if (newSize > 0) + { + if (!trPolyParamsBuffer || trPolyParamsBufferSize < newSize) + { + trPolyParamsBufferView.reset(); + trPolyParamsBuffer.reset(); + D3D11_BUFFER_DESC desc{}; + desc.ByteWidth = newSize; + desc.Usage = D3D11_USAGE_DYNAMIC; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; + desc.StructureByteStride = sizeof(u32) * 2; // sizeof(struct PolyParam) + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + + HRESULT hr = device->CreateBuffer(&desc, nullptr, &trPolyParamsBuffer.get()); + if (FAILED(hr)) + WARN_LOG(RENDERER, "TR poly params buffer creation failed"); + else + { + trPolyParamsBufferSize = newSize; + D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc{}; + viewDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + viewDesc.Format = DXGI_FORMAT_UNKNOWN; + viewDesc.Buffer.NumElements = desc.ByteWidth / desc.StructureByteStride; + + hr = device->CreateShaderResourceView(trPolyParamsBuffer, &viewDesc, &trPolyParamsBufferView.get()); + if (FAILED(hr)) + WARN_LOG(RENDERER, "TR poly params buffer view creation failed"); + } + } + D3D11_MAPPED_SUBRESOURCE mappedSubres; + deviceContext->Map(trPolyParamsBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedSubres); + memcpy(mappedSubres.pData, trPolyParams.data(), newSize); + deviceContext->Unmap(trPolyParamsBuffer, 0); + + deviceContext->PSSetShaderResources(5, 1, &trPolyParamsBufferView.get()); + } + } + + buffers.bind(); + deviceContext->ClearDepthStencilView(depthTexView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 0.f, 0); + deviceContext->ClearDepthStencilView(depthStencilView2, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 0.f, 0); + + RenderPass previous_pass {}; + int render_pass_count = (int)pvrrc.render_passes.size(); + for (int render_pass = 0; render_pass < render_pass_count; render_pass++) + { + const RenderPass& current_pass = pvrrc.render_passes[render_pass]; + u32 op_count = current_pass.op_count - previous_pass.op_count; + u32 pt_count = current_pass.pt_count - previous_pass.pt_count; + u32 tr_count = current_pass.tr_count - previous_pass.tr_count; + u32 mvo_count = current_pass.mvo_count - previous_pass.mvo_count; + DEBUG_LOG(RENDERER, "Render pass %d OP %d PT %d TR %d MV %d Tr MV %d autosort %d", render_pass + 1, + op_count, pt_count, tr_count, mvo_count, + current_pass.mv_op_tr_shared ? mvo_count : current_pass.mvo_tr_count - previous_pass.mvo_tr_count, + current_pass.autosort); + + // + // PASS 1: Geometry pass to update depth and stencil + // + // unbind depth/stencil + ID3D11ShaderResourceView *p = nullptr; + deviceContext->PSSetShaderResources(4, 1, &p); + // disable color writes + deviceContext->OMSetBlendState(blendStates.getState(false, 0, 0, true), nullptr, 0xffffffff); + deviceContext->OMSetRenderTargetsAndUnorderedAccessViews(1, &opaqueRenderTarget.get(), depthStencilView2, 0, D3D11_KEEP_UNORDERED_ACCESS_VIEWS, nullptr, nullptr); + + drawList(pvrrc.global_param_op, previous_pass.op_count, op_count); + drawList(pvrrc.global_param_pt, previous_pass.pt_count, pt_count); + drawModVols(previous_pass.mvo_count, mvo_count, &pvrrc.global_param_mvo[0]); + + // + // PASS 2: Render OP and PT to opaque render target + // + deviceContext->OMSetRenderTargetsAndUnorderedAccessViews(1, &opaqueRenderTarget.get(), depthTexView, 0, D3D11_KEEP_UNORDERED_ACCESS_VIEWS, nullptr, nullptr); + deviceContext->PSSetShaderResources(4, 1, &stencilView.get()); + + drawList(pvrrc.global_param_op, previous_pass.op_count, op_count); + drawList(pvrrc.global_param_pt, previous_pass.pt_count, pt_count); + + // + // PASS 3: Render TR to a-buffers + // + if (current_pass.autosort) + { + deviceContext->PSSetShaderResources(4, 1, &depthView.get()); + // disable color writes + deviceContext->OMSetBlendState(blendStates.getState(false, 0, 0, true), nullptr, 0xffffffff); + drawList(pvrrc.global_param_tr, previous_pass.tr_count, tr_count); + if (render_pass < render_pass_count - 1) + { + // + // PASS 3b: Geometry pass with TR to update the depth for the next TA render pass + // + ID3D11ShaderResourceView *p = nullptr; + deviceContext->PSSetShaderResources(4, 1, &p); + deviceContext->OMSetRenderTargetsAndUnorderedAccessViews(1, &opaqueRenderTarget.get(), depthTexView, 0, D3D11_KEEP_UNORDERED_ACCESS_VIEWS, nullptr, nullptr); + drawList(pvrrc.global_param_tr, previous_pass.tr_count, tr_count); + } + ID3D11ShaderResourceView *p = nullptr; + deviceContext->PSSetShaderResources(4, 1, &p); + if (!theDX11Context.isIntel()) + { + // Intel Iris Plus 640 just crashes + if (current_pass.mv_op_tr_shared) + drawModVols(previous_pass.mvo_count, mvo_count, &pvrrc.global_param_mvo[0]); + else + drawModVols(previous_pass.mvo_tr_count, current_pass.mvo_tr_count - previous_pass.mvo_tr_count, &pvrrc.global_param_mvo_tr[0]); + } + } + else + { + ID3D11ShaderResourceView *p = nullptr; + deviceContext->PSSetShaderResources(4, 1, &p); + drawList(pvrrc.global_param_tr, previous_pass.tr_count, tr_count); + } + if (render_pass < render_pass_count - 1) + { + // + // PASS 3c: Render a-buffer to temporary texture + // + if (!multipassTex) + { + createTexAndRenderTarget(multipassTex, multipassRenderTarget, width, height); + multipassTextureView.reset(); + D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc{}; + viewDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + viewDesc.Texture2D.MipLevels = 1; + device->CreateShaderResourceView(multipassTex, &viewDesc, &multipassTextureView.get()); + } + + renderABuffer(false); + std::swap(opaqueTex, multipassTex); + std::swap(opaqueRenderTarget, multipassRenderTarget); + std::swap(opaqueTextureView, multipassTextureView); + deviceContext->PSSetShaderResources(0, 1, &p); + deviceContext->IASetInputLayout(mainInputLayout); + + // Clear the stencil from this pass + deviceContext->ClearDepthStencilView(depthStencilView2, D3D11_CLEAR_STENCIL, 0.f, 0); + } + + previous_pass = current_pass; + } + + // + // PASS 4: Render a-buffers to screen + // + renderABuffer(true); + } + + bool Render() override + { + resize(pvrrc.framebufferWidth, pvrrc.framebufferHeight); + if (pixelBufferSize != config::PixelBufferSize) + { + buffers.init(device, deviceContext); + pixelBufferSize = config::PixelBufferSize; + } + + // Make sure to unbind the framebuffer view before setting it as render target + ID3D11ShaderResourceView *p = nullptr; + deviceContext->PSSetShaderResources(0, 1, &p); + // To avoid DEVICE_DRAW_RENDERTARGETVIEW_NOT_SET warnings + deviceContext->OMSetRenderTargets(1, &fbRenderTarget.get(), nullptr); + configVertexShader(); + + bool is_rtt = pvrrc.isRTT; + + deviceContext->IASetInputLayout(mainInputLayout); + + n2Helper.resetCache(); + uploadGeometryBuffers(); + + updateFogTexture(); + updatePaletteTexture(); + + setupPixelShaderConstants(); + + drawStrips(); + + if (is_rtt) + { + readRttRenderTarget(pvrrc.fb_W_SOF1 & VRAM_MASK); + } + else if (config::EmulateFramebuffer) + { + writeFramebufferToVRAM(); + } + else + { + aspectRatio = getOutputFramebufferAspectRatio(); +#ifndef LIBRETRO + deviceContext->OMSetRenderTargets(1, &theDX11Context.getRenderTarget().get(), nullptr); + displayFramebuffer(); + DrawOSD(false); + theDX11Context.setFrameRendered(); +#else + theDX11Context.drawOverlay(width, height); + ID3D11RenderTargetView *nullView = nullptr; + deviceContext->OMSetRenderTargets(1, &nullView, nullptr); + deviceContext->PSSetShaderResources(0, 1, &fbTextureView.get()); +#endif + frameRendered = true; + frameRenderedOnce = true; + } + + return !is_rtt; + } + +private: + Buffers buffers; + DX11OITShaders shaders; + ComPtr opaqueTex; + ComPtr opaqueRenderTarget; + ComPtr opaqueTextureView; + ComPtr multipassTex; + ComPtr multipassRenderTarget; + ComPtr multipassTextureView; + ComPtr stencilView; + ComPtr depthView; + ComPtr depthStencilTex2; + ComPtr depthStencilView2; + ComPtr trPolyParamsBuffer; + u32 trPolyParamsBufferSize = 0; + ComPtr trPolyParamsBufferView; + ComPtr mainInputLayout; // FIXME + ComPtr finalInputLayout; + ComPtr vtxPolyConstants; + int64_t pixelBufferSize = 0; +}; + +Renderer *rend_OITDirectX11() +{ + return new DX11OITRenderer(); +} diff --git a/core/rend/gl4/gles.cpp b/core/rend/gl4/gles.cpp index f58a2a15b..f13d41df5 100644 --- a/core/rend/gl4/gles.cpp +++ b/core/rend/gl4/gles.cpp @@ -74,17 +74,21 @@ in vec4 in_pos; in vec4 in_base; in vec4 in_offs; in vec2 in_uv; +#if pp_TwoVolumes == 1 in vec4 in_base1; in vec4 in_offs1; in vec2 in_uv1; +#endif // Output INTERPOLATION out vec4 vtx_base; INTERPOLATION out vec4 vtx_offs; out vec3 vtx_uv; +#if pp_TwoVolumes == 1 INTERPOLATION out vec4 vtx_base1; INTERPOLATION out vec4 vtx_offs1; out vec2 vtx_uv1; +#endif flat out uint vtx_index; void main() @@ -97,20 +101,26 @@ void main() vtx_base = in_base; vtx_offs = in_offs; vtx_uv = vec3(in_uv, vpos.z); - vtx_base1 = in_base1; - vtx_offs1 = in_offs1; - vtx_uv1 = in_uv1; + #if pp_TwoVolumes == 1 + vtx_base1 = in_base1; + vtx_offs1 = in_offs1; + vtx_uv1 = in_uv1; + #endif vtx_index = uint(pp_Number) + uint(gl_VertexID); #if pp_Gouraud == 1 && DIV_POS_Z != 1 vtx_base *= vpos.z; vtx_offs *= vpos.z; - vtx_base1 *= vpos.z; - vtx_offs1 *= vpos.z; + #if pp_TwoVolumes == 1 + vtx_base1 *= vpos.z; + vtx_offs1 *= vpos.z; + #endif #endif #if DIV_POS_Z != 1 vtx_uv.xy *= vpos.z; - vtx_uv1 *= vpos.z; + #if pp_TwoVolumes == 1 + vtx_uv1 *= vpos.z; + #endif vpos.w = 1.0; vpos.z = 0.0; #endif @@ -171,9 +181,11 @@ uniform int fog_control[2]; INTERPOLATION in vec4 vtx_base; INTERPOLATION in vec4 vtx_offs; in vec3 vtx_uv; +#if pp_TwoVolumes == 1 INTERPOLATION in vec4 vtx_base1; INTERPOLATION in vec4 vtx_offs1; in vec2 vtx_uv1; +#endif flat in uint vtx_index; float fog_mode2(float w) @@ -277,21 +289,27 @@ void main() vec4 texcol; #if pp_Palette == 0 #if DIV_POS_Z == 1 - if (area1) - texcol = texture(tex1, vtx_uv1); - else - texcol = texture(tex0, vtx_uv.xy); + #if pp_TwoVolumes == 1 + if (area1) + texcol = texture(tex1, vtx_uv1); + else + #endif + texcol = texture(tex0, vtx_uv.xy); #else - if (area1) - texcol = textureProj(tex1, vec3(vtx_uv1.xy, vtx_uv.z)); - else - texcol = textureProj(tex0, vtx_uv); + #if pp_TwoVolumes == 1 + if (area1) + texcol = textureProj(tex1, vec3(vtx_uv1.xy, vtx_uv.z)); + else + #endif + texcol = textureProj(tex0, vtx_uv); #endif #else - if (area1) - texcol = palettePixel(tex1, vec3(vtx_uv1.xy, vtx_uv.z)); - else - texcol = palettePixel(tex0, vtx_uv); + #if pp_TwoVolumes == 1 + if (area1) + texcol = palettePixel(tex1, vec3(vtx_uv1.xy, vtx_uv.z)); + else + #endif + texcol = palettePixel(tex0, vtx_uv); #endif #if pp_BumpMap == 1 @@ -459,7 +477,9 @@ void main() class Vertex4Source : public OpenGl4Source { public: - Vertex4Source(bool gouraud, bool divPosZ) : OpenGl4Source() { + Vertex4Source(bool gouraud, bool divPosZ, bool twoVolumes) : OpenGl4Source() + { + addConstant("pp_TwoVolumes", twoVolumes); addConstant("pp_Gouraud", gouraud); addConstant("DIV_POS_Z", divPosZ); @@ -507,7 +527,7 @@ bool gl4CompilePipelineShader(gl4PipelineShader* s, const char *fragment_source if (s->naomi2) vertexSource = N2Vertex4Source(s).generate(); else - vertexSource = Vertex4Source(s->pp_Gouraud, s->divPosZ).generate(); + vertexSource = Vertex4Source(s->pp_Gouraud, s->divPosZ, s->pp_TwoVolumes).generate(); Fragment4ShaderSource fragmentSource(s); s->program = gl_CompileAndLink(vertex_source != nullptr ? vertex_source : vertexSource.c_str(), @@ -623,7 +643,7 @@ static void create_modvol_shader() { if (gl4.modvol_shader.program != 0) return; - Vertex4Source vertexShader(false, config::NativeDepthInterpolation); + Vertex4Source vertexShader(false, config::NativeDepthInterpolation, false); OpenGl4Source fragmentShader; fragmentShader.addConstant("DIV_POS_Z", config::NativeDepthInterpolation) .addSource(ShaderHeader) diff --git a/core/rend/vulkan/utils.h b/core/rend/vulkan/utils.h index 863affc0e..93f9fb66f 100644 --- a/core/rend/vulkan/utils.h +++ b/core/rend/vulkan/utils.h @@ -89,7 +89,7 @@ static const char GouraudSource[] = R"( class VulkanSource : public ShaderSource { public: - VulkanSource() : ShaderSource("#version 450") {} + VulkanSource() : ShaderSource("#version 430") {} }; diff --git a/core/rend/vulkan/vmallocator.h b/core/rend/vulkan/vmallocator.h index 9cacf6082..c6e89d4c2 100644 --- a/core/rend/vulkan/vmallocator.h +++ b/core/rend/vulkan/vmallocator.h @@ -21,8 +21,6 @@ #pragma once #include #include "vulkan.h" -#define VMA_NOT_NULL -#define VMA_NULLABLE #include "vk_mem_alloc.h" #if !defined(PRIu64) && defined(_WIN32) diff --git a/core/sdl/sdl_gamepad.h b/core/sdl/sdl_gamepad.h index d89c30a8a..c67cf4c2c 100644 --- a/core/sdl/sdl_gamepad.h +++ b/core/sdl/sdl_gamepad.h @@ -166,7 +166,16 @@ public: SDLGamepad(int maple_port, int joystick_idx, SDL_Joystick* sdl_joystick) : GamepadDevice(maple_port, "SDL"), sdl_joystick(sdl_joystick) { - _name = SDL_JoystickName(sdl_joystick); + const char *joyName = SDL_JoystickName(sdl_joystick); + if (joyName == nullptr) + { + WARN_LOG(INPUT, "Can't get joystick %d name: %s", joystick_idx, SDL_GetError()); + _name = "Joystick " + std::to_string(joystick_idx); + } + else + { + _name = joyName; + } sdl_joystick_instance = SDL_JoystickInstanceID(sdl_joystick); _unique_id = "sdl_joystick_" + std::to_string(sdl_joystick_instance); INFO_LOG(INPUT, "SDL: Opened joystick %d on port %d: '%s' unique_id=%s", sdl_joystick_instance, maple_port, _name.c_str(), _unique_id.c_str()); @@ -174,12 +183,19 @@ public: if (SDL_IsGameController(joystick_idx)) { sdl_controller = SDL_GameControllerOpen(joystick_idx); - SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForAxis(sdl_controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT); - if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) - leftTrigger = bind.value.axis; - bind = SDL_GameControllerGetBindForAxis(sdl_controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT); - if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) - rightTrigger = bind.value.axis; + if (sdl_controller == nullptr) + { + WARN_LOG(INPUT, "Can't open game controller %d: %s", joystick_idx, SDL_GetError()); + } + else + { + SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForAxis(sdl_controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT); + if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) + leftTrigger = bind.value.axis; + bind = SDL_GameControllerGetBindForAxis(sdl_controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT); + if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) + rightTrigger = bind.value.axis; + } } if (!find_mapping()) @@ -273,50 +289,51 @@ public: { "paddle4", "Paddle 4" }, { "touchpad", "Touchpad" }, }; - for (SDL_GameControllerButton button = SDL_CONTROLLER_BUTTON_A; button < SDL_CONTROLLER_BUTTON_MAX; button = (SDL_GameControllerButton)(button + 1)) - { - SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForButton(sdl_controller, button); - if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON && bind.value.button == (int)code) + if (sdl_controller != nullptr) + for (SDL_GameControllerButton button = SDL_CONTROLLER_BUTTON_A; button < SDL_CONTROLLER_BUTTON_MAX; button = (SDL_GameControllerButton)(button + 1)) { - const char *sdlButton = SDL_GameControllerGetStringForButton(button); - if (sdlButton == nullptr) - return nullptr; - for (const auto& button : buttonsTable) - if (!strcmp(button.sdlButton, sdlButton)) - return button.label; - return sdlButton; - } - if (bind.bindType == SDL_CONTROLLER_BINDTYPE_HAT && (code >> 8) - 1 == (u32)bind.value.hat.hat) - { - int hat; - const char *name; - switch (code & 0xff) + SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForButton(sdl_controller, button); + if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON && bind.value.button == (int)code) { - case 0: - hat = SDL_HAT_UP; - name = "DPad Up"; - break; - case 1: - hat = SDL_HAT_DOWN; - name = "DPad Down"; - break; - case 2: - hat = SDL_HAT_LEFT; - name = "DPad Left"; - break; - case 3: - hat = SDL_HAT_RIGHT; - name = "DPad Right"; - break; - default: - hat = 0; - name = nullptr; - break; + const char *sdlButton = SDL_GameControllerGetStringForButton(button); + if (sdlButton == nullptr) + return nullptr; + for (const auto& button : buttonsTable) + if (!strcmp(button.sdlButton, sdlButton)) + return button.label; + return sdlButton; + } + if (bind.bindType == SDL_CONTROLLER_BINDTYPE_HAT && (code >> 8) - 1 == (u32)bind.value.hat.hat) + { + int hat; + const char *name; + switch (code & 0xff) + { + case 0: + hat = SDL_HAT_UP; + name = "DPad Up"; + break; + case 1: + hat = SDL_HAT_DOWN; + name = "DPad Down"; + break; + case 2: + hat = SDL_HAT_LEFT; + name = "DPad Left"; + break; + case 3: + hat = SDL_HAT_RIGHT; + name = "DPad Right"; + break; + default: + hat = 0; + name = nullptr; + break; + } + if (hat == bind.value.hat.hat_mask) + return name; } - if (hat == bind.value.hat.hat_mask) - return name; } - } return nullptr; } @@ -336,20 +353,21 @@ public: { "righttrigger", "R2" }, }; - for (SDL_GameControllerAxis axis = SDL_CONTROLLER_AXIS_LEFTX; axis < SDL_CONTROLLER_AXIS_MAX; axis = (SDL_GameControllerAxis)(axis + 1)) - { - SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForAxis(sdl_controller, axis); - if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS && bind.value.axis == (int)code) + if (sdl_controller != nullptr) + for (SDL_GameControllerAxis axis = SDL_CONTROLLER_AXIS_LEFTX; axis < SDL_CONTROLLER_AXIS_MAX; axis = (SDL_GameControllerAxis)(axis + 1)) { - const char *sdlAxis = SDL_GameControllerGetStringForAxis(axis); - if (sdlAxis == nullptr) - return nullptr; - for (const auto& axis : axesTable) - if (!strcmp(axis.sdlAxis, sdlAxis)) - return axis.label; - return sdlAxis; + SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForAxis(sdl_controller, axis); + if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS && bind.value.axis == (int)code) + { + const char *sdlAxis = SDL_GameControllerGetStringForAxis(axis); + if (sdlAxis == nullptr) + return nullptr; + for (const auto& axis : axesTable) + if (!strcmp(axis.sdlAxis, sdlAxis)) + return axis.label; + return sdlAxis; + } } - } return nullptr; } diff --git a/shell/apple/emulator-ios/emulator/FlycastViewController.mm b/shell/apple/emulator-ios/emulator/FlycastViewController.mm index 08bcce745..5839df831 100644 --- a/shell/apple/emulator-ios/emulator/FlycastViewController.mm +++ b/shell/apple/emulator-ios/emulator/FlycastViewController.mm @@ -340,6 +340,12 @@ static void updateAudioSession(Event event, void *) return UIRectEdgeAll; } +- (void)viewDidDisappear:(BOOL)animated; +{ + [super viewDidDisappear:animated]; + mainui_term(); +} + - (void)dealloc { [self deinitKeyboard]; diff --git a/shell/apple/emulator-ios/emulator/PadViewController.xib b/shell/apple/emulator-ios/emulator/PadViewController.xib index 7987867e9..94a774c7a 100644 --- a/shell/apple/emulator-ios/emulator/PadViewController.xib +++ b/shell/apple/emulator-ios/emulator/PadViewController.xib @@ -51,13 +51,13 @@ - + - + - + @@ -144,7 +144,7 @@ - + diff --git a/shell/apple/emulator-ios/emulator/ios_gamepad.h b/shell/apple/emulator-ios/emulator/ios_gamepad.h index 688c7b4b3..5e4a4abd1 100644 --- a/shell/apple/emulator-ios/emulator/ios_gamepad.h +++ b/shell/apple/emulator-ios/emulator/ios_gamepad.h @@ -50,14 +50,12 @@ enum IOSButton { IOS_BTN_PADDLE4, IOS_BTN_TOUCHPAD, - IOS_BTN_MAX, - - IOS_BTN_UP_RIGHT = 10, + IOS_BTN_UP_RIGHT, IOS_BTN_UP_LEFT, IOS_BTN_DOWN_LEFT, IOS_BTN_DOWN_RIGHT, - }; + enum IOSAxis { IOS_AXIS_L1 = 1, IOS_AXIS_R1, diff --git a/shell/libretro/libretro_core_options_intl.h b/shell/libretro/libretro_core_options_intl.h index ac00eb1f5..1053b084d 100644 --- a/shell/libretro/libretro_core_options_intl.h +++ b/shell/libretro/libretro_core_options_intl.h @@ -13558,7 +13558,7 @@ struct retro_core_options_v2 options_da = { #define CATEGORY_VIDEO_LABEL_DE NULL #define CATEGORY_VIDEO_INFO_0_DE "Auflösung, sortierungsunabhängige Transparenz und visuelle Effekt-Einstellungen konfigurieren." #define CATEGORY_PERFORMANCE_LABEL_DE "Leistung" -#define CATEGORY_PERFORMANCE_INFO_0_DE "Einstellungen für Mehrgängiges Rendern und Frameskip ändern." +#define CATEGORY_PERFORMANCE_INFO_0_DE "Einstellungen für Mehrgängiges Rendern und Bilder überspringen ändern." #define CATEGORY_HACKS_LABEL_DE "Emulations-Hacks" #define CATEGORY_HACKS_INFO_0_DE "Breitbild-Überschreibungen, GD-ROM Ladegeschwindigkeit und Textur-Austausch-Einstellungen konfigurieren." #define CATEGORY_INPUT_LABEL_DE "Eingabe" @@ -32135,7 +32135,7 @@ struct retro_core_options_v2 options_hr = { #define OPTION_VAL_FRENCH_HU "francia" #define OPTION_VAL_SPANISH_HU "spanyol" #define OPTION_VAL_ITALIAN_HU "olasz" -#define CORE_OPTION_NAME_HLE_BIOS_LABEL_HU NULL +#define CORE_OPTION_NAME_HLE_BIOS_LABEL_HU "HLE BIOS (újraindítás szükséges)" #define CORE_OPTION_NAME_HLE_BIOS_INFO_0_HU "Mindenképp a magas szinten emulált BIOS használata." #define CORE_OPTION_NAME_BOOT_TO_BIOS_LABEL_HU "Indítás BIOS-ban (újraindítás szükséges)" #define CORE_OPTION_NAME_BOOT_TO_BIOS_INFO_0_HU "Belépés a Dreamcast BIOS menüjébe rögtön Indításkor." @@ -32147,10 +32147,10 @@ struct retro_core_options_v2 options_hr = { #define CORE_OPTION_NAME_ALLOW_SERVICE_BUTTONS_INFO_0_HU "A NAOMI szervizgombjának engedélyezése, a kabinet beállításaihoz." #define CORE_OPTION_NAME_FORCE_FREEPLAY_LABEL_HU "Ingyen játék a NAOMI játékokhoz" #define CORE_OPTION_NAME_FORCE_FREEPLAY_INFO_0_HU "Az érmebeállítások ingyen játékra állítása." -#define CORE_OPTION_NAME_EMULATE_BBA_LABEL_HU NULL -#define CORE_OPTION_NAME_EMULATE_BBA_INFO_0_HU NULL -#define CORE_OPTION_NAME_UPNP_LABEL_HU NULL -#define CORE_OPTION_NAME_UPNP_INFO_0_HU NULL +#define CORE_OPTION_NAME_EMULATE_BBA_LABEL_HU "Szélessávú adapter emulálása" +#define CORE_OPTION_NAME_EMULATE_BBA_INFO_0_HU "Modem helyett a szélessávú Ethernet adapter emulálása. (Újraindítás szükséges.)" +#define CORE_OPTION_NAME_UPNP_LABEL_HU "UPnP engedélyezése" +#define CORE_OPTION_NAME_UPNP_INFO_0_HU "Az internetre csatlakozó router automatikus konfigurálása az online játékokhoz UPnP-n keresztül." #define CORE_OPTION_NAME_INTERNAL_RESOLUTION_LABEL_HU "Belső felbontás" #define CORE_OPTION_NAME_INTERNAL_RESOLUTION_INFO_0_HU "A képelőállítás felbontása." #define OPTION_VAL_320X240_HU NULL @@ -32208,7 +32208,7 @@ struct retro_core_options_v2 options_hr = { #define CORE_OPTION_NAME_EMULATE_FRAMEBUFFER_LABEL_HU "Teljes framebuffer emuláció" #define CORE_OPTION_NAME_EMULATE_FRAMEBUFFER_INFO_0_HU "A VRAM framebuffer teljes emulálásának engedélyezése. Olyan játékokhoz hasznos, amelyek közvetlenül a VRAM-ban írják vagy olvassák a framebuffert. Bekapcsolva a belső felbontás mindenképpen 640x480 lesz és a teljesítmény erősen visszaeshet." #define CORE_OPTION_NAME_ENABLE_RTTB_LABEL_HU "RTT (Render to texture) puffer engedélyezése" -#define CORE_OPTION_NAME_ENABLE_RTTB_INFO_0_HU NULL +#define CORE_OPTION_NAME_ENABLE_RTTB_INFO_0_HU "Az előállított textúrák visszamásolása a GPU-ból a VRAM-ba. Ez a lehetőség rendszerint be van kapcsolva azoknál a játékoknál, amelyek igénylik. Bekapcsolt állapotban a textúra előállítás felméretezése kikapcsol, és hatással lehet a teljesítményre." #define CORE_OPTION_NAME_MIPMAPPING_LABEL_HU NULL #define CORE_OPTION_NAME_FOG_LABEL_HU "Köd effekt" #define CORE_OPTION_NAME_VOLUME_MODIFIER_ENABLE_LABEL_HU "Térfogatmódosító" @@ -32263,37 +32263,37 @@ struct retro_core_options_v2 options_hr = { #define CORE_OPTION_NAME_ENABLE_PURUPURU_INFO_0_HU "A kontroller erővisszacsatolásának engedélyezése." #define CORE_OPTION_NAME_NETWORK_OUTPUT_LABEL_HU "Digitális kimenetek sugárzása" #define CORE_OPTION_NAME_NETWORK_OUTPUT_INFO_0_HU "A digitális kimenetek és az erővisszacsatolás állapotának közzététele a 8000-es TCP porton. Kompatibilis a MAME \"-output network\" opciójával." -#define CORE_OPTION_NAME_SHOW_LIGHTGUN_SETTINGS_LABEL_HU NULL -#define CORE_OPTION_NAME_SHOW_LIGHTGUN_SETTINGS_INFO_0_HU NULL -#define CORE_OPTION_NAME_LIGHTGUN1_CROSSHAIR_LABEL_HU NULL +#define CORE_OPTION_NAME_SHOW_LIGHTGUN_SETTINGS_LABEL_HU "Fénypisztoly beállítások megjelenítése" +#define CORE_OPTION_NAME_SHOW_LIGHTGUN_SETTINGS_INFO_0_HU "A fénypisztoly célkereszt megjelenítés beállításai. Figyelem: a változtatás életbelépéséhez újra be kell lépni a gyorsmenübe." +#define CORE_OPTION_NAME_LIGHTGUN1_CROSSHAIR_LABEL_HU "1. fénypisztoly célkeresztjének megjelenítése" #define OPTION_VAL_WHITE_HU "Fehér" #define OPTION_VAL_RED_HU "Vörös" #define OPTION_VAL_GREEN_HU "Zöld" #define OPTION_VAL_BLUE_HU "Kék" -#define CORE_OPTION_NAME_LIGHTGUN2_CROSSHAIR_LABEL_HU NULL -#define CORE_OPTION_NAME_LIGHTGUN3_CROSSHAIR_LABEL_HU NULL -#define CORE_OPTION_NAME_LIGHTGUN4_CROSSHAIR_LABEL_HU NULL -#define CORE_OPTION_NAME_PER_CONTENT_VMUS_LABEL_HU NULL -#define CORE_OPTION_NAME_PER_CONTENT_VMUS_LABEL_CAT_HU NULL -#define CORE_OPTION_NAME_PER_CONTENT_VMUS_INFO_0_HU NULL +#define CORE_OPTION_NAME_LIGHTGUN2_CROSSHAIR_LABEL_HU "2. fénypisztoly célkeresztjének megjelenítése" +#define CORE_OPTION_NAME_LIGHTGUN3_CROSSHAIR_LABEL_HU "3. fénypisztoly célkeresztjének megjelenítése" +#define CORE_OPTION_NAME_LIGHTGUN4_CROSSHAIR_LABEL_HU "4. fénypisztoly célkeresztjének megjelenítése" +#define CORE_OPTION_NAME_PER_CONTENT_VMUS_LABEL_HU "Játékonként külön Visual Memory Unit/System (VMU)" +#define CORE_OPTION_NAME_PER_CONTENT_VMUS_LABEL_CAT_HU "Játékonként külön VMU" +#define CORE_OPTION_NAME_PER_CONTENT_VMUS_INFO_0_HU "Kikapcsolva minden játék ugyanazt a 4 VMU mentés fájlt (A1, B1, C1, D1) használja a RetroArch rendszerkönyvtárban. \"VMU A1\" beállításnál minden elindított játéknak külön VMU \"A1\" fájlt hoz létre. \"Minden VMU\" beállításnál minden elindított játéknak négy külön VMU fájlt (A1, B1, C1, D1) hoz létre." #define OPTION_VAL_VMU_A1_HU NULL -#define OPTION_VAL_ALL_VMUS_HU NULL -#define CORE_OPTION_NAME_SHOW_VMU_SCREEN_SETTINGS_LABEL_HU NULL -#define CORE_OPTION_NAME_SHOW_VMU_SCREEN_SETTINGS_LABEL_CAT_HU NULL -#define CORE_OPTION_NAME_SHOW_VMU_SCREEN_SETTINGS_INFO_0_HU NULL -#define CORE_OPTION_NAME_VMU1_SCREEN_DISPLAY_LABEL_HU NULL -#define CORE_OPTION_NAME_VMU1_SCREEN_POSITION_LABEL_HU NULL -#define OPTION_VAL_UPPER_LEFT_HU NULL -#define OPTION_VAL_UPPER_RIGHT_HU NULL -#define OPTION_VAL_LOWER_LEFT_HU NULL -#define OPTION_VAL_LOWER_RIGHT_HU NULL -#define CORE_OPTION_NAME_VMU1_SCREEN_SIZE_MULT_LABEL_HU NULL +#define OPTION_VAL_ALL_VMUS_HU "Minden VMU" +#define CORE_OPTION_NAME_SHOW_VMU_SCREEN_SETTINGS_LABEL_HU "Visual Memory Unit/System (VMU) megjelenítési beállítások jelenjenek meg" +#define CORE_OPTION_NAME_SHOW_VMU_SCREEN_SETTINGS_LABEL_CAT_HU "VMU megjelenítési beállítások jelenjenek meg" +#define CORE_OPTION_NAME_SHOW_VMU_SCREEN_SETTINGS_INFO_0_HU "Az emulált VMU LCD képernyő láthatósági, méret, helyzet, és szín beállításainak engedélyezése. Figyelem: a gyorsmenüt ki-be kell kapcsolni, hogy ez a beállítás érvényre jusson." +#define CORE_OPTION_NAME_VMU1_SCREEN_DISPLAY_LABEL_HU "VMU 1 képernyő megjelenítése" +#define CORE_OPTION_NAME_VMU1_SCREEN_POSITION_LABEL_HU "VMU 1 képernyő helyzete" +#define OPTION_VAL_UPPER_LEFT_HU "Bal felső" +#define OPTION_VAL_UPPER_RIGHT_HU "Jobb felső" +#define OPTION_VAL_LOWER_LEFT_HU "Bal alsó" +#define OPTION_VAL_LOWER_RIGHT_HU "Jobb alsó" +#define CORE_OPTION_NAME_VMU1_SCREEN_SIZE_MULT_LABEL_HU "VMU 1 képernyő mérete" #define OPTION_VAL_1X_HU NULL #define OPTION_VAL_3X_HU NULL #define OPTION_VAL_5X_HU NULL -#define CORE_OPTION_NAME_VMU1_PIXEL_ON_COLOR_LABEL_HU NULL -#define OPTION_VAL_DEFAULT_ON_00_HU NULL -#define OPTION_VAL_DEFAULT_OFF_01_HU NULL +#define CORE_OPTION_NAME_VMU1_PIXEL_ON_COLOR_LABEL_HU "VMU 1 képernyő bekapcsolt pixel színe" +#define OPTION_VAL_DEFAULT_ON_00_HU "Alapértelmezésben bekapcsolva" +#define OPTION_VAL_DEFAULT_OFF_01_HU "Alapértelmezésben kikapcsolva" #define OPTION_VAL_BLACK_02_HU "Fekete" #define OPTION_VAL_LIGHT_BLUE_04_HU "Világoskék" #define OPTION_VAL_CYAN_06_HU "Ciánkék" @@ -32317,8 +32317,8 @@ struct retro_core_options_v2 options_hr = { #define OPTION_VAL_LIGHT_PURPLE_4_25_HU "Világoslila (4)" #define OPTION_VAL_LIGHT_YELLOW_26_HU "Halványsárga" #define OPTION_VAL_LIGHT_YELLOW_2_27_HU "Halványsárga (2)" -#define CORE_OPTION_NAME_VMU1_PIXEL_OFF_COLOR_LABEL_HU NULL -#define CORE_OPTION_NAME_VMU1_SCREEN_OPACITY_LABEL_HU NULL +#define CORE_OPTION_NAME_VMU1_PIXEL_OFF_COLOR_LABEL_HU "VMU 1 képernyő kikapcsolt pixel színe" +#define CORE_OPTION_NAME_VMU1_SCREEN_OPACITY_LABEL_HU "VMU 1 képernyő átlátszatlansága" #define OPTION_VAL_40_HU NULL #define OPTION_VAL_50_HU NULL #define OPTION_VAL_60_HU NULL @@ -32326,24 +32326,24 @@ struct retro_core_options_v2 options_hr = { #define OPTION_VAL_80_HU NULL #define OPTION_VAL_90_HU NULL #define OPTION_VAL_100_HU NULL -#define CORE_OPTION_NAME_VMU2_SCREEN_DISPLAY_LABEL_HU NULL -#define CORE_OPTION_NAME_VMU2_SCREEN_POSITION_LABEL_HU NULL -#define CORE_OPTION_NAME_VMU2_SCREEN_SIZE_MULT_LABEL_HU NULL -#define CORE_OPTION_NAME_VMU2_PIXEL_ON_COLOR_LABEL_HU NULL -#define CORE_OPTION_NAME_VMU2_PIXEL_OFF_COLOR_LABEL_HU NULL -#define CORE_OPTION_NAME_VMU2_SCREEN_OPACITY_LABEL_HU NULL -#define CORE_OPTION_NAME_VMU3_SCREEN_DISPLAY_LABEL_HU NULL -#define CORE_OPTION_NAME_VMU3_SCREEN_POSITION_LABEL_HU NULL -#define CORE_OPTION_NAME_VMU3_SCREEN_SIZE_MULT_LABEL_HU NULL -#define CORE_OPTION_NAME_VMU3_PIXEL_ON_COLOR_LABEL_HU NULL -#define CORE_OPTION_NAME_VMU3_PIXEL_OFF_COLOR_LABEL_HU NULL -#define CORE_OPTION_NAME_VMU3_SCREEN_OPACITY_LABEL_HU NULL -#define CORE_OPTION_NAME_VMU4_SCREEN_DISPLAY_LABEL_HU NULL -#define CORE_OPTION_NAME_VMU4_SCREEN_POSITION_LABEL_HU NULL -#define CORE_OPTION_NAME_VMU4_SCREEN_SIZE_MULT_LABEL_HU NULL -#define CORE_OPTION_NAME_VMU4_PIXEL_ON_COLOR_LABEL_HU NULL -#define CORE_OPTION_NAME_VMU4_PIXEL_OFF_COLOR_LABEL_HU NULL -#define CORE_OPTION_NAME_VMU4_SCREEN_OPACITY_LABEL_HU NULL +#define CORE_OPTION_NAME_VMU2_SCREEN_DISPLAY_LABEL_HU "VMU 2 képernyő megjelenítése" +#define CORE_OPTION_NAME_VMU2_SCREEN_POSITION_LABEL_HU "VMU 2 képernyő helyzete" +#define CORE_OPTION_NAME_VMU2_SCREEN_SIZE_MULT_LABEL_HU "VMU 2 képernyő mérete" +#define CORE_OPTION_NAME_VMU2_PIXEL_ON_COLOR_LABEL_HU "VMU 2 képernyő bekapcsolt pixel színe" +#define CORE_OPTION_NAME_VMU2_PIXEL_OFF_COLOR_LABEL_HU "VMU 2 képernyő kikapcsolt pixel színe" +#define CORE_OPTION_NAME_VMU2_SCREEN_OPACITY_LABEL_HU "VMU 2 képernyő átlátszatlansága" +#define CORE_OPTION_NAME_VMU3_SCREEN_DISPLAY_LABEL_HU "VMU 3 képernyő megjelenítése" +#define CORE_OPTION_NAME_VMU3_SCREEN_POSITION_LABEL_HU "VMU 3 képernyő helyzete" +#define CORE_OPTION_NAME_VMU3_SCREEN_SIZE_MULT_LABEL_HU "VMU 3 képernyő mérete" +#define CORE_OPTION_NAME_VMU3_PIXEL_ON_COLOR_LABEL_HU "VMU 3 képernyő bekapcsolt pixel színe" +#define CORE_OPTION_NAME_VMU3_PIXEL_OFF_COLOR_LABEL_HU "VMU 3 képernyő kikapcsolt pixel színe" +#define CORE_OPTION_NAME_VMU3_SCREEN_OPACITY_LABEL_HU "VMU 3 képernyő átlátszatlansága" +#define CORE_OPTION_NAME_VMU4_SCREEN_DISPLAY_LABEL_HU "VMU 4 képernyő megjelenítése" +#define CORE_OPTION_NAME_VMU4_SCREEN_POSITION_LABEL_HU "VMU 4 képernyő helyzete" +#define CORE_OPTION_NAME_VMU4_SCREEN_SIZE_MULT_LABEL_HU "VMU 4 képernyő mérete" +#define CORE_OPTION_NAME_VMU4_PIXEL_ON_COLOR_LABEL_HU "VMU 4 képernyő bekapcsolt pixel színe" +#define CORE_OPTION_NAME_VMU4_PIXEL_OFF_COLOR_LABEL_HU "VMU 4 képernyő kikapcsolt pixel színe" +#define CORE_OPTION_NAME_VMU4_SCREEN_OPACITY_LABEL_HU "VMU 4 képernyő átlátszatlansága" struct retro_core_option_v2_category option_cats_hu[] = { { @@ -38883,7 +38883,7 @@ struct retro_core_options_v2 options_ja = { #define OPTION_VAL_FRENCH_KO "프랑스어" #define OPTION_VAL_SPANISH_KO "스페인어" #define OPTION_VAL_ITALIAN_KO "이탈리아어" -#define CORE_OPTION_NAME_HLE_BIOS_LABEL_KO NULL +#define CORE_OPTION_NAME_HLE_BIOS_LABEL_KO "HLE BIOS (재시작 필요)" #define CORE_OPTION_NAME_HLE_BIOS_INFO_0_KO "HLE BIOS 사용을 강제합니다." #define CORE_OPTION_NAME_BOOT_TO_BIOS_LABEL_KO "BIOS 로 부트 (재시작 필요)" #define CORE_OPTION_NAME_BOOT_TO_BIOS_INFO_0_KO "드림캐스트 BIOS 메뉴로 부팅합니다." @@ -38895,10 +38895,10 @@ struct retro_core_options_v2 options_ja = { #define CORE_OPTION_NAME_ALLOW_SERVICE_BUTTONS_INFO_0_KO "캐비넷 설정에 들어가기위한 NAOMI 서비스 버튼을 활성화합니다." #define CORE_OPTION_NAME_FORCE_FREEPLAY_LABEL_KO "NAOMI 게임을 무료 플레이로 설정" #define CORE_OPTION_NAME_FORCE_FREEPLAY_INFO_0_KO "무료 플레이를 위해 게임의 코인 설정을 수정합니다." -#define CORE_OPTION_NAME_EMULATE_BBA_LABEL_KO NULL -#define CORE_OPTION_NAME_EMULATE_BBA_INFO_0_KO NULL -#define CORE_OPTION_NAME_UPNP_LABEL_KO NULL -#define CORE_OPTION_NAME_UPNP_INFO_0_KO NULL +#define CORE_OPTION_NAME_EMULATE_BBA_LABEL_KO "브로드밴드 어댑터 에뮬레이션" +#define CORE_OPTION_NAME_EMULATE_BBA_INFO_0_KO "모뎀 대신 이더넷 브로드밴드 어댑터를 에뮬레이트합니다. (재시작 필요)" +#define CORE_OPTION_NAME_UPNP_LABEL_KO "UPnP 활성화" +#define CORE_OPTION_NAME_UPNP_INFO_0_KO "온라인 게임에서 UPnP를 사용해 자동으로 인터넷 라우터를 설정합니다." #define CORE_OPTION_NAME_INTERNAL_RESOLUTION_LABEL_KO "내부 해상도" #define CORE_OPTION_NAME_INTERNAL_RESOLUTION_INFO_0_KO "렌더링 해상도를 변경합니다." #define OPTION_VAL_320X240_KO NULL