Compare commits

...

4 Commits

Author SHA1 Message Date
Ty
eee71d54ef Darwin: Implement Mach exceptions ports instead of signals
Credit goes to the Julia language and Dolphin emulator for their free and open source implementations
2026-01-01 13:33:34 -05:00
TheLastRar
43e073a18d GS/DX12: Fix validation errors when depth testing and sampling 2026-01-01 01:20:13 +01:00
JordanTheToaster
bc41666d53 GameDB: Various fixes 2026-01-01 01:09:27 +01:00
PCSX2 Bot
5b85d6a758 [ci skip] PAD: Update to latest controller database. 2025-12-29 17:04:38 +01:00
7 changed files with 291 additions and 34 deletions

View File

@@ -17830,6 +17830,8 @@ SLES-51393:
SLES-51397:
name: "IndyCar Series"
region: "PAL-M5"
gsHWFixes:
halfPixelOffset: 5 # Aligns post-processing and fixes depth line.
SLES-51398:
name: "World Championship Snooker 2003"
region: "PAL-E"
@@ -19953,6 +19955,8 @@ SLES-52298:
name: "IndyCar Series 2005"
region: "PAL-M5"
compat: 5
gsHWFixes:
halfPixelOffset: 5 # Aligns post-processing and fixes depth line.
SLES-52308:
name: "Karaoke Stage"
region: "PAL-M5"
@@ -20123,6 +20127,9 @@ SLES-52378:
name: "Euro Rally Champion"
region: "PAL-M5"
compat: 5
gsHWFixes:
halfPixelOffset: 5 # Aligns post-processing and fixes depth line.
textureInsideRT: 1 # Fixes broken fog rendering.
SLES-52379:
name: "Shrek 2"
region: "PAL-E"
@@ -25057,6 +25064,8 @@ SLES-53957:
SLES-53958:
name: "Noble Racing"
region: "PAL-E"
gsHWFixes:
halfPixelOffset: 5 # Aligns post-processing and fixes depth line.
SLES-53959:
name: "Pac-Man World 3"
region: "PAL-M5"
@@ -66984,6 +66993,8 @@ SLUS-20641:
name: "IndyCar Series"
region: "NTSC-U"
compat: 5
gsHWFixes:
halfPixelOffset: 5 # Aligns post-processing and fixes depth line.
SLUS-20642:
name: "Auto Modellista"
region: "NTSC-U"

View File

@@ -850,6 +850,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
# Mac OS X
030000008f0e00000300000009010000,2 In 1 Joystick,a:b2,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:b3,y:b0,platform:Mac OS X,
03000000c82d00001930000000000000,8BitDo 64,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:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Mac OS X,
03000000c82d00001930000000020000,8BitDo 64,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:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Mac OS X,
03000000c82d00001930000001000000,8BitDo 64,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:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Mac OS X,
03000000c82d00000031000001000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
@@ -895,7 +896,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00001290000001000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00004028000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000160000001000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000260000001000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000261000000010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00001230000000010000,8BitDo Ultimate,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,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,

View File

@@ -11,6 +11,7 @@
#include "common/Threading.h"
#include "common/WindowInfo.h"
#include "common/HostSys.h"
#include "fmt/format.h"
#include <csignal>
#include <cstring>
@@ -19,12 +20,15 @@
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <thread>
#include <time.h>
#include <mach/mach_init.h>
#include <mach/mach_port.h>
#include <mach/mach_time.h>
#include <mach/mach_vm.h>
#include <mach/message.h>
#include <mach/task.h>
#include <mach/thread_state.h>
#include <mach/vm_map.h>
#include <mutex>
#include <ApplicationServices/ApplicationServices.h>
@@ -294,7 +298,7 @@ static CPUInfo CalcCPUInfo()
std::vector<DarwinMisc::CPUClass> classes = DarwinMisc::GetCPUClasses();
out.num_clusters = static_cast<u32>(classes.size());
out.num_big_cores = classes.empty() ? 0 : classes[0].num_physical;
out.num_threads = classes.empty() ? 0 : classes[0].num_logical;
out.num_threads = classes.empty() ? 0 : classes[0].num_logical;
out.num_small_cores = 0;
for (std::size_t i = 1; i < classes.size(); i++)
{
@@ -568,15 +572,206 @@ void HostSys::EndCodeWrite()
#endif // _M_ARM64
#define USE_MACH_EXCEPTION_PORTS
namespace PageFaultHandler
{
#ifdef USE_MACH_EXCEPTION_PORTS
static void SignalHandler(mach_port_t port);
#else
static void SignalHandler(int sig, siginfo_t* info, void* ctx);
#endif
static std::recursive_mutex s_exception_handler_mutex;
static bool s_in_exception_handler = false;
static bool s_installed = false;
} // namespace PageFaultHandler
#ifdef USE_MACH_EXCEPTION_PORTS
#if defined(_M_X86)
#define THREAD_STATE64_COUNT x86_THREAD_STATE64_COUNT
#define THREAD_STATE64 x86_THREAD_STATE64
#define thread_state64_t x86_thread_state64_t
#elif defined(_M_ARM64)
#define THREAD_STATE64_COUNT ARM_THREAD_STATE64_COUNT
#define THREAD_STATE64 ARM_THREAD_STATE64
#define thread_state64_t arm_thread_state64_t
#else
#error Unknown Darwin Platform
#endif
void PageFaultHandler::SignalHandler(mach_port_t port)
{
Threading::SetNameOfCurrentThread("Mach Exception Thread");
#pragma pack(4)
struct
{
mach_msg_header_t Head;
NDR_record_t NDR;
exception_type_t exception;
mach_msg_type_number_t codeCnt;
int64_t code[2];
int flavor;
mach_msg_type_number_t old_stateCnt;
natural_t old_state[THREAD_STATE64_COUNT];
mach_msg_trailer_t trailer;
} msg_in;
struct
{
mach_msg_header_t Head;
NDR_record_t NDR;
kern_return_t RetCode;
int flavor;
mach_msg_type_number_t new_stateCnt;
natural_t new_state[THREAD_STATE64_COUNT];
} msg_out;
#pragma pack()
memset(&msg_in, 0xee, sizeof(msg_in));
memset(&msg_out, 0xee, sizeof(msg_out));
mach_msg_size_t send_size = 0;
mach_msg_option_t option = MACH_RCV_MSG;
while (true)
{
kern_return_t r;
if ((r = mach_msg_overwrite(&msg_out.Head, option, send_size, sizeof(msg_in), port,
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL, &msg_in.Head, 0)))
{
pxFail(fmt::format("CRITICAL: mach_msg_overwrite: {:x}", r).c_str());
}
if (msg_in.Head.msgh_id == MACH_NOTIFY_NO_SENDERS)
{
// the other thread exited
mach_port_deallocate(mach_task_self(), port);
return;
}
if (msg_in.Head.msgh_id != 2406)
{
pxFailRel("unknown message received");
return;
}
if (msg_in.flavor != THREAD_STATE64)
{
pxFailRel(fmt::format("unknown flavour {}, expected {}", msg_in.flavor, THREAD_STATE64).c_str());
return;
}
s_exception_handler_mutex.lock();
thread_state64_t* state = (thread_state64_t*)msg_in.old_state;
HandlerResult result = HandlerResult::ExecuteNextHandler;
if (!s_in_exception_handler)
{
s_in_exception_handler = true;
#ifdef _M_ARM64
result = HandlePageFault(reinterpret_cast<void*>(state->__pc), reinterpret_cast<void*>(msg_in.code[1]), (msg_in.code[0] & 2) != 0);
#else
result = HandlePageFault(reinterpret_cast<void*>(state->__rip), reinterpret_cast<void*>(msg_in.code[1]), (msg_in.code[0] & 2) != 0);
#endif
s_in_exception_handler = false;
}
// Set up the reply.
msg_out.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(msg_in.Head.msgh_bits), 0);
msg_out.Head.msgh_remote_port = msg_in.Head.msgh_remote_port;
msg_out.Head.msgh_local_port = MACH_PORT_NULL;
msg_out.Head.msgh_id = msg_in.Head.msgh_id + 100;
msg_out.NDR = msg_in.NDR;
if (result != HandlerResult::ContinueExecution) // cooked
{
msg_out.RetCode = KERN_FAILURE;
msg_out.flavor = 0;
msg_out.new_stateCnt = 0;
// The crash handler on macOS or Linux doesn't use context passed to it
// Stubbing it here is fine
CrashHandler::CrashSignalHandler(-1, nullptr, nullptr);
pxFailRel("CrashSignalHandler returned when it should have terminated us!");
}
else
{
// Resumes execution right where we left off (re-executes instruction that caused the SIGSEGV)
msg_out.RetCode = KERN_SUCCESS;
msg_out.flavor = THREAD_STATE64;
msg_out.new_stateCnt = THREAD_STATE64_COUNT;
memcpy(msg_out.new_state, msg_in.old_state, THREAD_STATE64_COUNT * sizeof(natural_t));
}
msg_out.Head.msgh_size =
offsetof(__typeof__(msg_out), new_state) + msg_out.new_stateCnt * sizeof(natural_t);
send_size = msg_out.Head.msgh_size;
option |= MACH_SEND_MSG;
s_exception_handler_mutex.unlock();
}
}
bool PageFaultHandler::Install(Error* error)
{
exception_mask_t masks[EXC_TYPES_COUNT];
mach_port_t ports[EXC_TYPES_COUNT];
exception_behavior_t behaviors[EXC_TYPES_COUNT];
thread_state_flavor_t flavors[EXC_TYPES_COUNT];
mach_msg_type_number_t count = EXC_TYPES_COUNT;
kern_return_t r = task_get_exception_ports(mach_task_self(), EXC_MASK_ALL,
masks, &count, ports, behaviors, flavors);
mach_port_t port;
if ((r = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port)))
{
pxFailRel(fmt::format("mach_port_allocate: {:x}", r).c_str());
return false;
}
std::thread sig_thread(PageFaultHandler::SignalHandler, port);
sig_thread.detach();
if ((r = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND)))
{
mach_port_deallocate(mach_task_self(), port);
pxFailRel(fmt::format("mach_port_insert_right: {:x}", r).c_str());
return false;
}
task_set_exception_ports(mach_task_self(), EXC_MASK_BAD_ACCESS, MACH_PORT_NULL, EXCEPTION_DEFAULT, THREAD_STATE_NONE);
if ((r = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, port, EXCEPTION_STATE | MACH_EXCEPTION_CODES, THREAD_STATE64)))
{
mach_port_deallocate(mach_task_self(), port);
pxFailRel(fmt::format("thread_set_exception_ports: {:x}", r).c_str());
return false;
}
if ((r = mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, -1)))
{
mach_port_deallocate(mach_task_self(), port);
pxFailRel(fmt::format("mach_port_mod_refs: {:x}", r).c_str());
return false;
}
mach_port_t previous;
if ((r = mach_port_request_notification(mach_task_self(), port, MACH_NOTIFY_NO_SENDERS, 0, port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &previous)))
{
mach_port_deallocate(mach_task_self(), port);
pxFailRel(fmt::format("mach_port_mod_refs: {:x}", r).c_str());
return false;
}
s_installed = true;
return true;
}
#else
void PageFaultHandler::SignalHandler(int sig, siginfo_t* info, void* ctx)
{
#if defined(_M_X86)
@@ -644,3 +839,4 @@ bool PageFaultHandler::Install(Error* error)
s_installed = true;
return true;
}
#endif

View File

@@ -2181,13 +2181,13 @@ void GSDevice12::IASetIndexBuffer(const void* index, size_t count)
m_index_stream_buffer.CommitMemory(size);
}
void GSDevice12::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i& scissor)
void GSDevice12::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i& scissor, bool depth_read)
{
GSTexture12* vkRt = static_cast<GSTexture12*>(rt);
GSTexture12* vkDs = static_cast<GSTexture12*>(ds);
pxAssert(vkRt || vkDs);
if (m_current_render_target != vkRt || m_current_depth_target != vkDs)
if (m_current_render_target != vkRt || m_current_depth_target != vkDs || m_current_depth_read_only != depth_read)
{
// framebuffer change
EndRenderPass();
@@ -2214,13 +2214,14 @@ void GSDevice12::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector
m_current_render_target = vkRt;
m_current_depth_target = vkDs;
m_current_depth_read_only = depth_read;
if (!InRenderPass())
{
if (vkRt)
vkRt->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
if (vkDs)
vkDs->TransitionToState(D3D12_RESOURCE_STATE_DEPTH_WRITE);
vkDs->TransitionToState(depth_read ? (D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) : D3D12_RESOURCE_STATE_DEPTH_WRITE);
}
// This is used to set/initialize the framebuffer for tfx rendering.
@@ -3330,6 +3331,7 @@ void GSDevice12::UnbindTexture(GSTexture12* tex)
{
EndRenderPass();
m_current_depth_target = nullptr;
m_current_depth_read_only = false;
}
}
@@ -3450,7 +3452,7 @@ void GSDevice12::BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE color_b
D3D12_RENDER_PASS_DEPTH_STENCIL_DESC ds = {};
if (m_current_depth_target)
{
ds.cpuDescriptor = m_current_depth_target->GetWriteDescriptor();
ds.cpuDescriptor = m_current_depth_read_only ? m_current_depth_target->GetReadDepthViewDescriptor() : m_current_depth_target->GetWriteDescriptor();
ds.DepthEndingAccess.Type = depth_end;
ds.DepthBeginningAccess.Type = depth_begin;
if (depth_begin == D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR)
@@ -3470,7 +3472,8 @@ void GSDevice12::BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE color_b
}
GetCommandList()->BeginRenderPass(m_current_render_target ? 1 : 0,
m_current_render_target ? &rt : nullptr, m_current_depth_target ? &ds : nullptr, D3D12_RENDER_PASS_FLAG_NONE);
m_current_render_target ? &rt : nullptr, m_current_depth_target ? &ds : nullptr,
(m_current_depth_target && m_current_depth_read_only) ? (D3D12_RENDER_PASS_FLAG_BIND_READ_ONLY_DEPTH) : D3D12_RENDER_PASS_FLAG_NONE);
}
void GSDevice12::EndRenderPass()
@@ -3552,11 +3555,13 @@ __ri void GSDevice12::ApplyBaseState(u32 flags, ID3D12GraphicsCommandList* cmdli
if (m_current_render_target)
{
cmdlist->OMSetRenderTargets(1, &m_current_render_target->GetWriteDescriptor().cpu_handle, FALSE,
m_current_depth_target ? &m_current_depth_target->GetWriteDescriptor().cpu_handle : nullptr);
m_current_depth_target ?
(m_current_depth_read_only ? &m_current_depth_target->GetReadDepthViewDescriptor().cpu_handle : &m_current_depth_target->GetWriteDescriptor().cpu_handle) :
nullptr);
}
else if (m_current_depth_target)
{
cmdlist->OMSetRenderTargets(0, nullptr, FALSE, &m_current_depth_target->GetWriteDescriptor().cpu_handle);
cmdlist->OMSetRenderTargets(0, nullptr, FALSE, m_current_depth_read_only ? &m_current_depth_target->GetReadDepthViewDescriptor().cpu_handle : &m_current_depth_target->GetWriteDescriptor().cpu_handle);
}
}
}
@@ -3924,15 +3929,6 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
if (config.blend.constant_enable)
SetBlendConstants(config.blend.constant);
// Depth testing and sampling, bind resource as dsv read only and srv at the same time without the need of a copy.
if (config.tex && config.tex == config.ds)
{
EndRenderPass();
// Transition dsv as read only.
draw_ds->TransitionToState(D3D12_RESOURCE_STATE_DEPTH_READ);
}
// Primitive ID tracking DATE setup.
GSTexture12* date_image = nullptr;
if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking)
@@ -4034,7 +4030,8 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
Console.Warning("D3D12: Failed to allocate temp texture for RT copy.");
}
OMSetRenderTargets(draw_rt, draw_ds, config.scissor);
// For depth testing and sampling, use a read only dsv, otherwise use a write dsv
OMSetRenderTargets(draw_rt, draw_ds, config.scissor, config.tex && config.tex == config.ds);
// Begin render pass if new target or out of the area.
if (!m_in_render_pass)

View File

@@ -459,7 +459,7 @@ public:
void PSSetShaderResource(int i, GSTexture* sr, bool check_state, bool feedback = false);
void PSSetSampler(GSHWDrawConfig::SamplerSelector sel);
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i& scissor);
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i& scissor, bool depth_read = false);
void SetVSConstantBuffer(const GSHWDrawConfig::VSConstantBuffer& cb);
void SetPSConstantBuffer(const GSHWDrawConfig::PSConstantBuffer& cb);
@@ -580,6 +580,7 @@ private:
GSTexture12* m_current_render_target = nullptr;
GSTexture12* m_current_depth_target = nullptr;
bool m_current_depth_read_only = false;
D3D12_VIEWPORT m_viewport = {0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
GSVector4i m_scissor = GSVector4i::zero();

View File

@@ -17,13 +17,15 @@
GSTexture12::GSTexture12(Type type, Format format, int width, int height, int levels, DXGI_FORMAT dxgi_format,
wil::com_ptr_nothrow<ID3D12Resource> resource, wil::com_ptr_nothrow<ID3D12Resource> resource_fbl,
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation, const D3D12DescriptorHandle& srv_descriptor,
const D3D12DescriptorHandle& write_descriptor, const D3D12DescriptorHandle& uav_descriptor,
const D3D12DescriptorHandle& fbl_descriptor, WriteDescriptorType wdtype, D3D12_RESOURCE_STATES resource_state)
const D3D12DescriptorHandle& write_descriptor, const D3D12DescriptorHandle& ro_dsv_descriptor,
const D3D12DescriptorHandle& uav_descriptor, const D3D12DescriptorHandle& fbl_descriptor,
WriteDescriptorType wdtype, D3D12_RESOURCE_STATES resource_state)
: m_resource(std::move(resource))
, m_resource_fbl(std::move(resource_fbl))
, m_allocation(std::move(allocation))
, m_srv_descriptor(srv_descriptor)
, m_write_descriptor(write_descriptor)
, m_read_dsv_descriptor(ro_dsv_descriptor)
, m_uav_descriptor(uav_descriptor)
, m_fbl_descriptor(fbl_descriptor)
, m_write_descriptor_type(wdtype)
@@ -58,6 +60,7 @@ void GSTexture12::Destroy(bool defer)
break;
case WriteDescriptorType::DSV:
dev->DeferDescriptorDestruction(dev->GetDSVHeapManager(), &m_write_descriptor);
dev->DeferDescriptorDestruction(dev->GetDSVHeapManager(), &m_read_dsv_descriptor);
break;
case WriteDescriptorType::None:
default:
@@ -87,6 +90,7 @@ void GSTexture12::Destroy(bool defer)
break;
case WriteDescriptorType::DSV:
dev->GetDSVHeapManager().Free(&m_write_descriptor);
dev->GetDSVHeapManager().Free(&m_read_dsv_descriptor);
break;
case WriteDescriptorType::None:
default:
@@ -237,7 +241,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
}
}
D3D12DescriptorHandle srv_descriptor, write_descriptor, uav_descriptor, fbl_descriptor;
D3D12DescriptorHandle srv_descriptor, write_descriptor, ro_dsv_descriptor, uav_descriptor, fbl_descriptor;
WriteDescriptorType write_descriptor_type = WriteDescriptorType::None;
if (srv_format != DXGI_FORMAT_UNKNOWN)
{
@@ -261,11 +265,17 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
case Type::DepthStencil:
{
write_descriptor_type = WriteDescriptorType::DSV;
if (!CreateDSVDescriptor(resource.get(), dsv_format, &write_descriptor))
if (!CreateDSVDescriptor(resource.get(), dsv_format, &write_descriptor, false))
{
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
return {};
}
if (!CreateDSVDescriptor(resource.get(), dsv_format, &ro_dsv_descriptor, true))
{
dev->GetDSVHeapManager().Free(&write_descriptor);
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
return {};
}
}
break;
@@ -281,6 +291,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
dev->GetRTVHeapManager().Free(&write_descriptor);
break;
case WriteDescriptorType::DSV:
dev->GetDSVHeapManager().Free(&ro_dsv_descriptor);
dev->GetDSVHeapManager().Free(&write_descriptor);
break;
default:
@@ -301,6 +312,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
dev->GetRTVHeapManager().Free(&write_descriptor);
break;
case WriteDescriptorType::DSV:
dev->GetDSVHeapManager().Free(&ro_dsv_descriptor);
dev->GetDSVHeapManager().Free(&write_descriptor);
break;
default:
@@ -313,7 +325,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
return std::unique_ptr<GSTexture12>(
new GSTexture12(type, format, width, height, levels, dxgi_format, std::move(resource), std::move(resource_fbl), std::move(allocation),
srv_descriptor, write_descriptor, uav_descriptor, fbl_descriptor, write_descriptor_type, state));
srv_descriptor, write_descriptor, ro_dsv_descriptor, uav_descriptor, fbl_descriptor, write_descriptor_type, state));
}
std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resource> resource, Type type, Format format,
@@ -322,7 +334,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resou
{
const D3D12_RESOURCE_DESC desc = resource->GetDesc();
D3D12DescriptorHandle srv_descriptor, write_descriptor, uav_descriptor;
D3D12DescriptorHandle srv_descriptor, write_descriptor, ro_dsv_descriptor, uav_descriptor;
WriteDescriptorType write_descriptor_type = WriteDescriptorType::None;
if (srv_format != DXGI_FORMAT_UNKNOWN)
{
@@ -342,11 +354,17 @@ std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resou
else if (type == Type::DepthStencil)
{
write_descriptor_type = WriteDescriptorType::DSV;
if (!CreateDSVDescriptor(resource.get(), dsv_format, &write_descriptor))
if (!CreateDSVDescriptor(resource.get(), dsv_format, &write_descriptor, false))
{
GSDevice12::GetInstance()->GetDescriptorHeapManager().Free(&srv_descriptor);
return {};
}
if (!CreateDSVDescriptor(resource.get(), dsv_format, &ro_dsv_descriptor, true))
{
GSDevice12::GetInstance()->GetDSVHeapManager().Free(&write_descriptor);
GSDevice12::GetInstance()->GetDescriptorHeapManager().Free(&srv_descriptor);
return {};
}
}
if (uav_format != DXGI_FORMAT_UNKNOWN)
@@ -359,6 +377,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resou
GSDevice12::GetInstance()->GetRTVHeapManager().Free(&write_descriptor);
break;
case WriteDescriptorType::DSV:
GSDevice12::GetInstance()->GetDSVHeapManager().Free(&ro_dsv_descriptor);
GSDevice12::GetInstance()->GetDSVHeapManager().Free(&write_descriptor);
break;
default:
@@ -371,7 +390,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resou
}
return std::unique_ptr<GSTexture12>(new GSTexture12(type, format, static_cast<u32>(desc.Width), desc.Height,
desc.MipLevels, desc.Format, std::move(resource), {}, {}, srv_descriptor, write_descriptor, uav_descriptor,
desc.MipLevels, desc.Format, std::move(resource), {}, {}, srv_descriptor, write_descriptor, {}, uav_descriptor,
{}, write_descriptor_type, resource_state));
}
@@ -405,7 +424,7 @@ bool GSTexture12::CreateRTVDescriptor(ID3D12Resource* resource, DXGI_FORMAT form
return true;
}
bool GSTexture12::CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh)
bool GSTexture12::CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh, bool read_only)
{
if (!GSDevice12::GetInstance()->GetDSVHeapManager().Allocate(dh))
{
@@ -413,7 +432,7 @@ bool GSTexture12::CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT form
return false;
}
const D3D12_DEPTH_STENCIL_VIEW_DESC desc = {format, D3D12_DSV_DIMENSION_TEXTURE2D, D3D12_DSV_FLAG_NONE};
const D3D12_DEPTH_STENCIL_VIEW_DESC desc = {format, D3D12_DSV_DIMENSION_TEXTURE2D, read_only ? D3D12_DSV_FLAG_READ_ONLY_DEPTH : D3D12_DSV_FLAG_NONE };
GSDevice12::GetInstance()->GetDevice()->CreateDepthStencilView(resource, &desc, dh->cpu_handle);
return true;
}
@@ -708,7 +727,36 @@ void GSTexture12::TransitionToState(ID3D12GraphicsCommandList* cmdlist, D3D12_RE
if (m_resource_state == state)
return;
TransitionSubresourceToState(cmdlist, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, m_resource_state, state);
// Read only depth requires special handling as we might want to write stencil.
// Also batch the transition barriers as per recommendation from docs.
if (state == (D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE))
{
// Transition to read depth/write stencil
const D3D12_RESOURCE_BARRIER barriers[2] = {
{D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE,
{{m_resource.get(), 0, m_resource_state, (D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)}}},
{D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE,
{{m_resource.get(), 1, m_resource_state, D3D12_RESOURCE_STATE_DEPTH_WRITE}}},
};
GSDevice12::GetInstance()->GetCommandList()->ResourceBarrier(m_resource_state == D3D12_RESOURCE_STATE_DEPTH_WRITE ? 1 : 2, barriers);
}
else if (m_resource_state == (D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE))
{
// Transition from read depth/write stencil
const D3D12_RESOURCE_BARRIER barriers[2] = {
{D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE,
{{m_resource.get(), 0, (D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE), state}}},
{D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE,
{{m_resource.get(), 1, D3D12_RESOURCE_STATE_DEPTH_WRITE, state}}},
};
GSDevice12::GetInstance()->GetCommandList()->ResourceBarrier(state == D3D12_RESOURCE_STATE_DEPTH_WRITE ? 1 : 2, barriers);
}
else
{
// Normal transition
TransitionSubresourceToState(cmdlist, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, m_resource_state, state);
}
m_resource_state = state;
}

View File

@@ -30,6 +30,7 @@ public:
__fi const D3D12DescriptorHandle& GetSRVDescriptor() const { return m_srv_descriptor; }
__fi const D3D12DescriptorHandle& GetWriteDescriptor() const { return m_write_descriptor; }
__fi const D3D12DescriptorHandle& GetReadDepthViewDescriptor() const { return m_read_dsv_descriptor; }
__fi const D3D12DescriptorHandle& GetUAVDescriptor() const { return m_uav_descriptor; }
__fi const D3D12DescriptorHandle& GetFBLDescriptor() const { return m_fbl_descriptor; }
__fi D3D12_RESOURCE_STATES GetResourceState() const { return m_resource_state; }
@@ -72,13 +73,14 @@ private:
GSTexture12(Type type, Format format, int width, int height, int levels, DXGI_FORMAT dxgi_format,
wil::com_ptr_nothrow<ID3D12Resource> resource, wil::com_ptr_nothrow<ID3D12Resource> resource_fbl,
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation, const D3D12DescriptorHandle& srv_descriptor,
const D3D12DescriptorHandle& write_descriptor, const D3D12DescriptorHandle& uav_descriptor,
const D3D12DescriptorHandle& fbl_descriptor, WriteDescriptorType wdtype, D3D12_RESOURCE_STATES resource_state);
const D3D12DescriptorHandle& write_descriptor, const D3D12DescriptorHandle& ro_dsv_descriptor,
const D3D12DescriptorHandle& uav_descriptor, const D3D12DescriptorHandle& fbl_descriptor,
WriteDescriptorType wdtype, D3D12_RESOURCE_STATES resource_state);
static bool CreateSRVDescriptor(
ID3D12Resource* resource, u32 levels, DXGI_FORMAT format, D3D12DescriptorHandle* dh);
static bool CreateRTVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh);
static bool CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh);
static bool CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh, bool read_only);
static bool CreateUAVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh);
ID3D12GraphicsCommandList* GetCommandBufferForUpdate();
@@ -91,6 +93,7 @@ private:
D3D12DescriptorHandle m_srv_descriptor = {};
D3D12DescriptorHandle m_write_descriptor = {};
D3D12DescriptorHandle m_read_dsv_descriptor = {};
D3D12DescriptorHandle m_uav_descriptor = {};
D3D12DescriptorHandle m_fbl_descriptor = {};
WriteDescriptorType m_write_descriptor_type = WriteDescriptorType::None;