mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-11 01:08:39 +12:00
Merge pull request #1243 from vlj/d3d12
D3d12: Small code and performance improvements.
This commit is contained in:
commit
ebf28f8da0
8 changed files with 244 additions and 105 deletions
|
@ -20,11 +20,15 @@ std::vector<VertexBufferFormat> FormatVertexData(const RSXVertexData *m_vertex_d
|
||||||
const RSXVertexData &vertexData = m_vertex_data[i];
|
const RSXVertexData &vertexData = m_vertex_data[i];
|
||||||
if (!vertexData.IsEnabled()) continue;
|
if (!vertexData.IsEnabled()) continue;
|
||||||
|
|
||||||
size_t elementCount = vertex_data_size[i] / (vertexData.size * vertexData.GetTypeSize());
|
size_t elementCount = ((vertexData.addr) ? vertex_data_size[i] : m_vertex_data[i].data.size()) / (vertexData.size * vertexData.GetTypeSize());
|
||||||
|
|
||||||
// If there is a single element, stride is 0, use the size of element instead
|
// If there is a single element, stride is 0, use the size of element instead
|
||||||
size_t stride = vertexData.stride;
|
size_t stride = vertexData.stride;
|
||||||
size_t elementSize = vertexData.GetTypeSize();
|
size_t elementSize = vertexData.GetTypeSize();
|
||||||
std::pair<size_t, size_t> range = std::make_pair(vertexData.addr + base_offset, vertexData.addr + base_offset + elementSize * vertexData.size + (elementCount - 1) * stride - 1);
|
size_t start = vertexData.addr + base_offset;
|
||||||
|
size_t end = start + elementSize * vertexData.size + (elementCount - 1) * stride - 1;
|
||||||
|
std::pair<size_t, size_t> range = std::make_pair(start, end);
|
||||||
|
assert(start < end);
|
||||||
bool isMerged = false;
|
bool isMerged = false;
|
||||||
|
|
||||||
for (VertexBufferFormat &vbf : Result)
|
for (VertexBufferFormat &vbf : Result)
|
||||||
|
|
|
@ -93,8 +93,7 @@ void D3D12GSRender::ResourceStorage::WaitAndClean()
|
||||||
|
|
||||||
Reset();
|
Reset();
|
||||||
|
|
||||||
for (auto tmp : m_dirtyTextures)
|
m_dirtyTextures.clear();
|
||||||
tmp->Release();
|
|
||||||
|
|
||||||
m_RAMFramebuffer = nullptr;
|
m_RAMFramebuffer = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -119,30 +118,11 @@ void D3D12GSRender::Shader::Release()
|
||||||
|
|
||||||
extern std::function<bool(u32 addr)> gfxHandler;
|
extern std::function<bool(u32 addr)> gfxHandler;
|
||||||
|
|
||||||
bool D3D12GSRender::invalidateTexture(u32 addr)
|
bool D3D12GSRender::invalidateAddress(u32 addr)
|
||||||
{
|
{
|
||||||
bool handled = false;
|
bool result = false;
|
||||||
auto It = m_protectedTextures.begin(), E = m_protectedTextures.end();
|
result |= m_textureCache.invalidateAddress(addr);
|
||||||
for (; It != E;)
|
return result;
|
||||||
{
|
|
||||||
auto currentIt = It;
|
|
||||||
++It;
|
|
||||||
auto protectedTexture = *currentIt;
|
|
||||||
u32 protectedRangeStart = std::get<1>(protectedTexture), protectedRangeSize = std::get<2>(protectedTexture);
|
|
||||||
if (addr - protectedRangeStart < protectedRangeSize)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mut);
|
|
||||||
u32 texadrr = std::get<0>(protectedTexture);
|
|
||||||
ID3D12Resource *texToErase = m_texturesCache[texadrr];
|
|
||||||
m_texturesCache.erase(texadrr);
|
|
||||||
m_texToClean.push_back(texToErase);
|
|
||||||
|
|
||||||
vm::page_protect(protectedRangeStart, protectedRangeSize, 0, vm::page_writable, 0);
|
|
||||||
m_protectedTextures.erase(currentIt);
|
|
||||||
handled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return handled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D12DLLManagement::D3D12DLLManagement()
|
D3D12DLLManagement::D3D12DLLManagement()
|
||||||
|
@ -158,8 +138,13 @@ D3D12DLLManagement::~D3D12DLLManagement()
|
||||||
D3D12GSRender::D3D12GSRender()
|
D3D12GSRender::D3D12GSRender()
|
||||||
: GSRender(), m_D3D12Lib(), m_PSO(nullptr)
|
: GSRender(), m_D3D12Lib(), m_PSO(nullptr)
|
||||||
{
|
{
|
||||||
|
m_previous_address_a = 0;
|
||||||
|
m_previous_address_b = 0;
|
||||||
|
m_previous_address_c = 0;
|
||||||
|
m_previous_address_d = 0;
|
||||||
|
m_previous_address_z = 0;
|
||||||
gfxHandler = [this](u32 addr) {
|
gfxHandler = [this](u32 addr) {
|
||||||
bool result = invalidateTexture(addr);
|
bool result = invalidateAddress(addr);
|
||||||
if (result)
|
if (result)
|
||||||
LOG_WARNING(RSX, "Reporting Cell writing to %x", addr);
|
LOG_WARNING(RSX, "Reporting Cell writing to %x", addr);
|
||||||
return result;
|
return result;
|
||||||
|
@ -174,20 +159,9 @@ D3D12GSRender::D3D12GSRender()
|
||||||
Microsoft::WRL::ComPtr<IDXGIFactory4> dxgiFactory;
|
Microsoft::WRL::ComPtr<IDXGIFactory4> dxgiFactory;
|
||||||
ThrowIfFailed(CreateDXGIFactory(IID_PPV_ARGS(&dxgiFactory)));
|
ThrowIfFailed(CreateDXGIFactory(IID_PPV_ARGS(&dxgiFactory)));
|
||||||
// Create adapter
|
// Create adapter
|
||||||
IDXGIAdapter* adaptater = nullptr;
|
ComPtr<IDXGIAdapter> adaptater = nullptr;
|
||||||
switch (Ini.GSD3DAdaptater.GetValue())
|
ThrowIfFailed(dxgiFactory->EnumAdapters(Ini.GSD3DAdaptater.GetValue(), adaptater.GetAddressOf()));
|
||||||
{
|
ThrowIfFailed(wrapD3D12CreateDevice(adaptater.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device)));
|
||||||
case 0: // WARP
|
|
||||||
ThrowIfFailed(dxgiFactory->EnumWarpAdapter(IID_PPV_ARGS(&adaptater)));
|
|
||||||
break;
|
|
||||||
case 1: // Default
|
|
||||||
dxgiFactory->EnumAdapters(0, &adaptater);
|
|
||||||
break;
|
|
||||||
default: // Adaptater 0, 1, ...
|
|
||||||
dxgiFactory->EnumAdapters(Ini.GSD3DAdaptater.GetValue() - 2,&adaptater);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ThrowIfFailed(wrapD3D12CreateDevice(adaptater, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device)));
|
|
||||||
|
|
||||||
// Queues
|
// Queues
|
||||||
D3D12_COMMAND_QUEUE_DESC copyQueueDesc = {}, graphicQueueDesc = {};
|
D3D12_COMMAND_QUEUE_DESC copyQueueDesc = {}, graphicQueueDesc = {};
|
||||||
|
@ -201,9 +175,6 @@ D3D12GSRender::D3D12GSRender()
|
||||||
g_descriptorStrideSamplers = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
|
g_descriptorStrideSamplers = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
|
||||||
|
|
||||||
m_frame = GetGSFrame();
|
m_frame = GetGSFrame();
|
||||||
DXGI_ADAPTER_DESC adaptaterDesc;
|
|
||||||
adaptater->GetDesc(&adaptaterDesc);
|
|
||||||
m_frame->SetAdaptaterName(adaptaterDesc.Description);
|
|
||||||
|
|
||||||
// Create swap chain and put them in a descriptor heap as rendertarget
|
// Create swap chain and put them in a descriptor heap as rendertarget
|
||||||
DXGI_SWAP_CHAIN_DESC swapChain = {};
|
DXGI_SWAP_CHAIN_DESC swapChain = {};
|
||||||
|
@ -305,12 +276,7 @@ D3D12GSRender::~D3D12GSRender()
|
||||||
CloseHandle(handle);
|
CloseHandle(handle);
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mut);
|
m_textureCache.unprotedAll();
|
||||||
for (auto &protectedTexture : m_protectedTextures)
|
|
||||||
{
|
|
||||||
u32 protectedRangeStart = std::get<1>(protectedTexture), protectedRangeSize = std::get<2>(protectedTexture);
|
|
||||||
vm::page_protect(protectedRangeStart, protectedRangeSize, 0, vm::page_writable, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gfxHandler = [this](u32) { return false; };
|
gfxHandler = [this](u32) { return false; };
|
||||||
|
@ -326,10 +292,6 @@ D3D12GSRender::~D3D12GSRender()
|
||||||
m_perFrameStorage[0].Release();
|
m_perFrameStorage[0].Release();
|
||||||
m_perFrameStorage[1].Release();
|
m_perFrameStorage[1].Release();
|
||||||
m_rtts.Release();
|
m_rtts.Release();
|
||||||
for (auto &tmp : m_texToClean)
|
|
||||||
tmp->Release();
|
|
||||||
for (auto &tmp : m_texturesCache)
|
|
||||||
tmp.second->Release();
|
|
||||||
m_outputScalingPass.Release();
|
m_outputScalingPass.Release();
|
||||||
|
|
||||||
ReleaseD2DStructures();
|
ReleaseD2DStructures();
|
||||||
|
@ -851,9 +813,7 @@ void D3D12GSRender::Flip()
|
||||||
storage.m_frameFinishedFence->SetEventOnCompletion(storage.m_fenceValue, storage.m_frameFinishedHandle);
|
storage.m_frameFinishedFence->SetEventOnCompletion(storage.m_fenceValue, storage.m_frameFinishedHandle);
|
||||||
storage.m_fenceValue++;
|
storage.m_fenceValue++;
|
||||||
|
|
||||||
storage.m_dirtyTextures = m_texToClean;
|
|
||||||
storage.m_inUse = true;
|
storage.m_inUse = true;
|
||||||
m_texToClean.clear();
|
|
||||||
|
|
||||||
// Get the put pos - 1. This way after cleaning we can set the get ptr to
|
// Get the put pos - 1. This way after cleaning we can set the get ptr to
|
||||||
// this value, allowing heap to proceed even if we cleant before allocating
|
// this value, allowing heap to proceed even if we cleant before allocating
|
||||||
|
@ -1072,7 +1032,7 @@ void D3D12GSRender::semaphorePGRAPHBackendRelease(u32 offset, u32 value)
|
||||||
getCurrentResourceStorage().m_commandList->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(writeDest.Get(), { 0, { DXGI_FORMAT_R8_UNORM, m_surface_clip_w, m_surface_clip_h, 1, (UINT)depthRowPitch } }), 0, 0, 0,
|
getCurrentResourceStorage().m_commandList->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(writeDest.Get(), { 0, { DXGI_FORMAT_R8_UNORM, m_surface_clip_w, m_surface_clip_h, 1, (UINT)depthRowPitch } }), 0, 0, 0,
|
||||||
&CD3DX12_TEXTURE_COPY_LOCATION(depthConverted.Get(), 0), nullptr);
|
&CD3DX12_TEXTURE_COPY_LOCATION(depthConverted.Get(), 0), nullptr);
|
||||||
|
|
||||||
invalidateTexture(GetAddress(m_surface_offset_z, m_context_dma_z - 0xfeed0000));
|
invalidateAddress(GetAddress(m_surface_offset_z, m_context_dma_z - 0xfeed0000));
|
||||||
}
|
}
|
||||||
|
|
||||||
ID3D12Resource *rtt0, *rtt1, *rtt2, *rtt3;
|
ID3D12Resource *rtt0, *rtt1, *rtt2, *rtt3;
|
||||||
|
@ -1110,10 +1070,10 @@ void D3D12GSRender::semaphorePGRAPHBackendRelease(u32 offset, u32 value)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_context_dma_color_a) invalidateTexture(GetAddress(m_surface_offset_a, m_context_dma_color_a - 0xfeed0000));
|
if (m_context_dma_color_a) invalidateAddress(GetAddress(m_surface_offset_a, m_context_dma_color_a - 0xfeed0000));
|
||||||
if (m_context_dma_color_b) invalidateTexture(GetAddress(m_surface_offset_b, m_context_dma_color_b - 0xfeed0000));
|
if (m_context_dma_color_b) invalidateAddress(GetAddress(m_surface_offset_b, m_context_dma_color_b - 0xfeed0000));
|
||||||
if (m_context_dma_color_c) invalidateTexture(GetAddress(m_surface_offset_c, m_context_dma_color_c - 0xfeed0000));
|
if (m_context_dma_color_c) invalidateAddress(GetAddress(m_surface_offset_c, m_context_dma_color_c - 0xfeed0000));
|
||||||
if (m_context_dma_color_d) invalidateTexture(GetAddress(m_surface_offset_d, m_context_dma_color_d - 0xfeed0000));
|
if (m_context_dma_color_d) invalidateAddress(GetAddress(m_surface_offset_d, m_context_dma_color_d - 0xfeed0000));
|
||||||
}
|
}
|
||||||
if (needTransfer)
|
if (needTransfer)
|
||||||
{
|
{
|
||||||
|
|
|
@ -57,7 +57,6 @@ public:
|
||||||
virtual void DeleteContext(void* ctx) = 0;
|
virtual void DeleteContext(void* ctx) = 0;
|
||||||
virtual void Flip(void* ctx) = 0;
|
virtual void Flip(void* ctx) = 0;
|
||||||
virtual HWND getHandle() const = 0;
|
virtual HWND getHandle() const = 0;
|
||||||
virtual void SetAdaptaterName(const wchar_t *) = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef GSFrameBase2*(*GetGSFrameCb2)();
|
typedef GSFrameBase2*(*GetGSFrameCb2)();
|
||||||
|
@ -190,6 +189,118 @@ struct DataHeap
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TextureEntry
|
||||||
|
{
|
||||||
|
int m_format;
|
||||||
|
size_t m_width;
|
||||||
|
size_t m_height;
|
||||||
|
size_t m_mipmap;
|
||||||
|
bool m_isDirty;
|
||||||
|
|
||||||
|
TextureEntry() : m_format(0), m_width(0), m_height(0), m_isDirty(true)
|
||||||
|
{}
|
||||||
|
|
||||||
|
TextureEntry(int f, size_t w, size_t h, size_t m) : m_format(f), m_width(w), m_height(h), m_isDirty(false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool operator==(const TextureEntry &other)
|
||||||
|
{
|
||||||
|
return (m_format == other.m_format && m_width == other.m_width && m_height == other.m_height);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages cache of data (texture/vertex/index)
|
||||||
|
*/
|
||||||
|
struct DataCache
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Mutex protecting m_dataCache access
|
||||||
|
* Memory protection fault catch can be generated by any thread and
|
||||||
|
* modifies it.
|
||||||
|
*/
|
||||||
|
std::mutex mut;
|
||||||
|
|
||||||
|
std::unordered_map<u64, std::pair<TextureEntry, ComPtr<ID3D12Resource>> > m_dataCache; // Storage
|
||||||
|
std::list <std::tuple<u64, u32, u32> > m_protectedRange; // address, start of protected range, size of protected range
|
||||||
|
public:
|
||||||
|
void storeAndProtectData(u64 key, u32 start, size_t size, int format, size_t w, size_t h, size_t m, ComPtr<ID3D12Resource> data)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mut);
|
||||||
|
m_dataCache[key] = std::make_pair(TextureEntry(format, w, h, m), data);
|
||||||
|
protectData(key, start, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make memory from start to start + size write protected.
|
||||||
|
* Associate key to this range so that when a write is detected, data at key is marked dirty.
|
||||||
|
*/
|
||||||
|
void protectData(u64 key, u32 start, size_t size)
|
||||||
|
{
|
||||||
|
/// align start to 4096 byte
|
||||||
|
u32 protected_range_start = align(start, 4096);
|
||||||
|
u32 protected_range_size = (u32)align(size, 4096);
|
||||||
|
m_protectedRange.push_back(std::make_tuple(key, protected_range_start, protected_range_size));
|
||||||
|
vm::page_protect(protected_range_start, protected_range_size, 0, 0, vm::page_writable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// remove all data containing addr from cache, unprotect them. Returns false if no data is modified.
|
||||||
|
bool invalidateAddress(u32 addr)
|
||||||
|
{
|
||||||
|
bool handled = false;
|
||||||
|
auto It = m_protectedRange.begin(), E = m_protectedRange.end();
|
||||||
|
for (; It != E;)
|
||||||
|
{
|
||||||
|
auto currentIt = It;
|
||||||
|
++It;
|
||||||
|
auto protectedTexture = *currentIt;
|
||||||
|
u32 protectedRangeStart = std::get<1>(protectedTexture), protectedRangeSize = std::get<2>(protectedTexture);
|
||||||
|
if (addr >= protectedRangeStart && addr <= protectedRangeSize + protectedRangeStart)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mut);
|
||||||
|
u64 texadrr = std::get<0>(protectedTexture);
|
||||||
|
m_dataCache[texadrr].first.m_isDirty = true;
|
||||||
|
|
||||||
|
vm::page_protect(protectedRangeStart, protectedRangeSize, 0, vm::page_writable, 0);
|
||||||
|
m_protectedRange.erase(currentIt);
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<TextureEntry, ComPtr<ID3D12Resource> > *findDataIfAvailable(u64 key)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mut);
|
||||||
|
auto It = m_dataCache.find(key);
|
||||||
|
if (It == m_dataCache.end())
|
||||||
|
return nullptr;
|
||||||
|
return &It->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unprotedAll()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mut);
|
||||||
|
for (auto &protectedTexture : m_protectedRange)
|
||||||
|
{
|
||||||
|
u32 protectedRangeStart = std::get<1>(protectedTexture), protectedRangeSize = std::get<2>(protectedTexture);
|
||||||
|
vm::page_protect(protectedRangeStart, protectedRangeSize, 0, vm::page_writable, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove data stored at key, and returns a ComPtr owning it.
|
||||||
|
* The caller is responsible for releasing the ComPtr.
|
||||||
|
*/
|
||||||
|
ComPtr<ID3D12Resource> removeFromCache(u64 key)
|
||||||
|
{
|
||||||
|
auto result = m_dataCache[key].second;
|
||||||
|
m_dataCache.erase(key);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Structure used to load/unload D3D12 lib.
|
* Structure used to load/unload D3D12 lib.
|
||||||
*/
|
*/
|
||||||
|
@ -213,22 +324,14 @@ private:
|
||||||
ComPtr<ID3D12DescriptorHeap> m_backbufferAsRendertarget[2];
|
ComPtr<ID3D12DescriptorHeap> m_backbufferAsRendertarget[2];
|
||||||
// m_rootSignatures[N] is RS with N texture/sample
|
// m_rootSignatures[N] is RS with N texture/sample
|
||||||
ComPtr<ID3D12RootSignature> m_rootSignatures[17];
|
ComPtr<ID3D12RootSignature> m_rootSignatures[17];
|
||||||
/**
|
|
||||||
* Mutex protecting m_texturesCache and m_Textoclean access
|
// TODO: Use a tree structure to parse more efficiently
|
||||||
* Memory protection fault catch can be generated by any thread and
|
DataCache m_textureCache;
|
||||||
* modifies these two members.
|
bool invalidateAddress(u32 addr);
|
||||||
*/
|
|
||||||
std::mutex mut;
|
|
||||||
std::list <std::tuple<u32, u32, u32> > m_protectedTextures; // Texaddress, start of protected range, size of protected range
|
|
||||||
std::vector<ID3D12Resource *> m_texToClean;
|
|
||||||
bool invalidateTexture(u32 addr);
|
|
||||||
|
|
||||||
// Copy of RTT to be used as texture
|
// Copy of RTT to be used as texture
|
||||||
std::unordered_map<u32, ID3D12Resource* > m_texturesRTTs;
|
std::unordered_map<u32, ID3D12Resource* > m_texturesRTTs;
|
||||||
|
|
||||||
std::unordered_map<u32, ID3D12Resource*> m_texturesCache;
|
|
||||||
// std::vector<PostDrawObj> m_post_draw_objs;
|
|
||||||
|
|
||||||
PipelineStateObjectCache m_cachePSO;
|
PipelineStateObjectCache m_cachePSO;
|
||||||
std::pair<ID3D12PipelineState *, size_t> *m_PSO;
|
std::pair<ID3D12PipelineState *, size_t> *m_PSO;
|
||||||
|
|
||||||
|
@ -311,7 +414,7 @@ private:
|
||||||
|
|
||||||
|
|
||||||
/// Texture that were invalidated
|
/// Texture that were invalidated
|
||||||
std::vector<ID3D12Resource *> m_dirtyTextures;
|
std::list<ComPtr<ID3D12Resource> > m_dirtyTextures;
|
||||||
|
|
||||||
size_t m_getPosConstantsHeap;
|
size_t m_getPosConstantsHeap;
|
||||||
size_t m_getPosVertexIndexHeap;
|
size_t m_getPosVertexIndexHeap;
|
||||||
|
@ -359,6 +462,13 @@ private:
|
||||||
ID3D12Resource *m_dummyTexture;
|
ID3D12Resource *m_dummyTexture;
|
||||||
|
|
||||||
size_t m_lastWidth, m_lastHeight, m_lastDepth;
|
size_t m_lastWidth, m_lastHeight, m_lastDepth;
|
||||||
|
|
||||||
|
// Store previous fbo addresses to detect RTT config changes.
|
||||||
|
u32 m_previous_address_a;
|
||||||
|
u32 m_previous_address_b;
|
||||||
|
u32 m_previous_address_c;
|
||||||
|
u32 m_previous_address_d;
|
||||||
|
u32 m_previous_address_z;
|
||||||
public:
|
public:
|
||||||
GSFrameBase2 *m_frame;
|
GSFrameBase2 *m_frame;
|
||||||
u32 m_draw_frames;
|
u32 m_draw_frames;
|
||||||
|
|
|
@ -14,6 +14,20 @@
|
||||||
|
|
||||||
void D3D12GSRender::PrepareRenderTargets(ID3D12GraphicsCommandList *copycmdlist)
|
void D3D12GSRender::PrepareRenderTargets(ID3D12GraphicsCommandList *copycmdlist)
|
||||||
{
|
{
|
||||||
|
// Exit early if there is no rtt changes
|
||||||
|
if ((m_previous_address_a == m_surface_offset_a) &&
|
||||||
|
(m_previous_address_b == m_surface_offset_b) &&
|
||||||
|
(m_previous_address_c == m_surface_offset_c) &&
|
||||||
|
(m_previous_address_d == m_surface_offset_d) &&
|
||||||
|
(m_previous_address_z == m_surface_offset_z))
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_previous_address_a = m_surface_offset_a;
|
||||||
|
m_previous_address_b = m_surface_offset_b;
|
||||||
|
m_previous_address_c = m_surface_offset_c;
|
||||||
|
m_previous_address_d = m_surface_offset_d;
|
||||||
|
m_previous_address_z = m_surface_offset_z;
|
||||||
|
|
||||||
// FBO location has changed, previous data might be copied
|
// FBO location has changed, previous data might be copied
|
||||||
u32 address_a = m_set_context_dma_color_a ? GetAddress(m_surface_offset_a, m_context_dma_color_a - 0xfeed0000) : 0;
|
u32 address_a = m_set_context_dma_color_a ? GetAddress(m_surface_offset_a, m_context_dma_color_a - 0xfeed0000) : 0;
|
||||||
u32 address_b = m_set_context_dma_color_b ? GetAddress(m_surface_offset_b, m_context_dma_color_b - 0xfeed0000) : 0;
|
u32 address_b = m_set_context_dma_color_b ? GetAddress(m_surface_offset_b, m_context_dma_color_b - 0xfeed0000) : 0;
|
||||||
|
|
|
@ -126,13 +126,13 @@ D3D12_SAMPLER_DESC getSamplerDesc(const RSXTexture &texture)
|
||||||
* using a temporary texture buffer.
|
* using a temporary texture buffer.
|
||||||
*/
|
*/
|
||||||
static
|
static
|
||||||
ID3D12Resource *uploadSingleTexture(
|
ComPtr<ID3D12Resource> uploadSingleTexture(
|
||||||
const RSXTexture &texture,
|
const RSXTexture &texture,
|
||||||
ID3D12Device *device,
|
ID3D12Device *device,
|
||||||
ID3D12GraphicsCommandList *commandList,
|
ID3D12GraphicsCommandList *commandList,
|
||||||
DataHeap<ID3D12Resource, 65536> &textureBuffersHeap)
|
DataHeap<ID3D12Resource, 65536> &textureBuffersHeap)
|
||||||
{
|
{
|
||||||
ID3D12Resource *vramTexture;
|
ComPtr<ID3D12Resource> vramTexture;
|
||||||
size_t w = texture.GetWidth(), h = texture.GetHeight();
|
size_t w = texture.GetWidth(), h = texture.GetHeight();
|
||||||
|
|
||||||
int format = texture.GetFormat() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN);
|
int format = texture.GetFormat() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN);
|
||||||
|
@ -157,21 +157,61 @@ ID3D12Resource *uploadSingleTexture(
|
||||||
&texturedesc,
|
&texturedesc,
|
||||||
D3D12_RESOURCE_STATE_COPY_DEST,
|
D3D12_RESOURCE_STATE_COPY_DEST,
|
||||||
nullptr,
|
nullptr,
|
||||||
IID_PPV_ARGS(&vramTexture)
|
IID_PPV_ARGS(vramTexture.GetAddressOf())
|
||||||
));
|
));
|
||||||
|
|
||||||
size_t miplevel = 0;
|
size_t miplevel = 0;
|
||||||
for (const MipmapLevelInfo mli : mipInfos)
|
for (const MipmapLevelInfo mli : mipInfos)
|
||||||
{
|
{
|
||||||
commandList->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(vramTexture, (UINT)miplevel), 0, 0, 0,
|
commandList->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(vramTexture.Get(), (UINT)miplevel), 0, 0, 0,
|
||||||
&CD3DX12_TEXTURE_COPY_LOCATION(textureBuffersHeap.m_heap, { heapOffset + mli.offset, { dxgiFormat, (UINT)mli.width, (UINT)mli.height, 1, (UINT)mli.rowPitch } }), nullptr);
|
&CD3DX12_TEXTURE_COPY_LOCATION(textureBuffersHeap.m_heap, { heapOffset + mli.offset, { dxgiFormat, (UINT)mli.width, (UINT)mli.height, 1, (UINT)mli.rowPitch } }), nullptr);
|
||||||
miplevel++;
|
miplevel++;
|
||||||
}
|
}
|
||||||
|
|
||||||
commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(vramTexture, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ));
|
commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(vramTexture.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ));
|
||||||
return vramTexture;
|
return vramTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void updateExistingTexture(
|
||||||
|
const RSXTexture &texture,
|
||||||
|
ID3D12GraphicsCommandList *commandList,
|
||||||
|
DataHeap<ID3D12Resource, 65536> &textureBuffersHeap,
|
||||||
|
ID3D12Resource *existingTexture)
|
||||||
|
{
|
||||||
|
size_t w = texture.GetWidth(), h = texture.GetHeight();
|
||||||
|
|
||||||
|
int format = texture.GetFormat() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN);
|
||||||
|
DXGI_FORMAT dxgiFormat = getTextureDXGIFormat(format);
|
||||||
|
|
||||||
|
size_t textureSize = getPlacedTextureStorageSpace(texture, 256);
|
||||||
|
assert(textureBuffersHeap.canAlloc(textureSize));
|
||||||
|
size_t heapOffset = textureBuffersHeap.alloc(textureSize);
|
||||||
|
|
||||||
|
void *buffer;
|
||||||
|
ThrowIfFailed(textureBuffersHeap.m_heap->Map(0, &CD3DX12_RANGE(heapOffset, heapOffset + textureSize), &buffer));
|
||||||
|
void *textureData = (char*)buffer + heapOffset;
|
||||||
|
std::vector<MipmapLevelInfo> mipInfos = uploadPlacedTexture(texture, 256, textureData);
|
||||||
|
textureBuffersHeap.m_heap->Unmap(0, &CD3DX12_RANGE(heapOffset, heapOffset + textureSize));
|
||||||
|
|
||||||
|
commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(existingTexture, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_COPY_DEST));
|
||||||
|
size_t miplevel = 0;
|
||||||
|
for (const MipmapLevelInfo mli : mipInfos)
|
||||||
|
{
|
||||||
|
commandList->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(existingTexture, (UINT)miplevel), 0, 0, 0,
|
||||||
|
&CD3DX12_TEXTURE_COPY_LOCATION(textureBuffersHeap.m_heap, { heapOffset + mli.offset,{ dxgiFormat, (UINT)mli.width, (UINT)mli.height, 1, (UINT)mli.rowPitch } }), nullptr);
|
||||||
|
miplevel++;
|
||||||
|
}
|
||||||
|
|
||||||
|
commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(existingTexture, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get number of bytes occupied by texture in RSX mem
|
* Get number of bytes occupied by texture in RSX mem
|
||||||
*/
|
*/
|
||||||
|
@ -246,7 +286,6 @@ size_t getTextureSize(const RSXTexture &texture)
|
||||||
|
|
||||||
size_t D3D12GSRender::UploadTextures(ID3D12GraphicsCommandList *cmdlist)
|
size_t D3D12GSRender::UploadTextures(ID3D12GraphicsCommandList *cmdlist)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mut);
|
|
||||||
size_t usedTexture = 0;
|
size_t usedTexture = 0;
|
||||||
|
|
||||||
for (u32 i = 0; i < m_textures_count; ++i)
|
for (u32 i = 0; i < m_textures_count; ++i)
|
||||||
|
@ -263,26 +302,29 @@ size_t D3D12GSRender::UploadTextures(ID3D12GraphicsCommandList *cmdlist)
|
||||||
|
|
||||||
ID3D12Resource *vramTexture;
|
ID3D12Resource *vramTexture;
|
||||||
std::unordered_map<u32, ID3D12Resource* >::const_iterator ItRTT = m_rtts.m_renderTargets.find(texaddr);
|
std::unordered_map<u32, ID3D12Resource* >::const_iterator ItRTT = m_rtts.m_renderTargets.find(texaddr);
|
||||||
std::unordered_map<u32, ID3D12Resource* >::const_iterator ItCache = m_texturesCache.find(texaddr);
|
std::pair<TextureEntry, ComPtr<ID3D12Resource> > *cachedTex = m_textureCache.findDataIfAvailable(texaddr);
|
||||||
bool isRenderTarget = false;
|
bool isRenderTarget = false;
|
||||||
if (ItRTT != m_rtts.m_renderTargets.end())
|
if (ItRTT != m_rtts.m_renderTargets.end())
|
||||||
{
|
{
|
||||||
vramTexture = ItRTT->second;
|
vramTexture = ItRTT->second;
|
||||||
isRenderTarget = true;
|
isRenderTarget = true;
|
||||||
}
|
}
|
||||||
else if (ItCache != m_texturesCache.end())
|
else if (cachedTex != nullptr && (cachedTex->first == TextureEntry(format, w, h, m_textures[i].GetMipmap())))
|
||||||
{
|
{
|
||||||
vramTexture = ItCache->second;
|
if (cachedTex->first.m_isDirty)
|
||||||
|
{
|
||||||
|
updateExistingTexture(m_textures[i], cmdlist, m_textureUploadData, cachedTex->second.Get());
|
||||||
|
m_textureCache.protectData(texaddr, texaddr, getTextureSize(m_textures[i]));
|
||||||
|
}
|
||||||
|
vramTexture = cachedTex->second.Get();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
vramTexture = uploadSingleTexture(m_textures[i], m_device.Get(), cmdlist, m_textureUploadData);
|
if (cachedTex != nullptr)
|
||||||
m_texturesCache[texaddr] = vramTexture;
|
getCurrentResourceStorage().m_dirtyTextures.push_back(m_textureCache.removeFromCache(texaddr));
|
||||||
|
ComPtr<ID3D12Resource> tex = uploadSingleTexture(m_textures[i], m_device.Get(), cmdlist, m_textureUploadData);
|
||||||
u32 s = (u32)align(getTextureSize(m_textures[i]), 4096);
|
vramTexture = tex.Get();
|
||||||
LOG_WARNING(RSX, "PROTECTING %x of size %d", align(texaddr, 4096), s);
|
m_textureCache.storeAndProtectData(texaddr, texaddr, getTextureSize(m_textures[i]), format, w, h, m_textures[i].GetMipmap(), tex);
|
||||||
m_protectedTextures.push_back(std::make_tuple(texaddr, align(texaddr, 4096), s));
|
|
||||||
vm::page_protect(align(texaddr, 4096), s, 0, 0, vm::page_writable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||||
|
|
|
@ -20,11 +20,6 @@ D3DGSFrame::~D3DGSFrame()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3DGSFrame::SetAdaptaterName(const wchar_t *name)
|
|
||||||
{
|
|
||||||
AdaptaterName = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
void D3DGSFrame::Close()
|
void D3DGSFrame::Close()
|
||||||
{
|
{
|
||||||
GSFrame::Close();
|
GSFrame::Close();
|
||||||
|
@ -69,7 +64,7 @@ void D3DGSFrame::Flip(void* context)
|
||||||
// canvas->SwapBuffers();
|
// canvas->SwapBuffers();
|
||||||
m_frames++;
|
m_frames++;
|
||||||
|
|
||||||
const std::string sub_title = Emu.GetTitle() + (Emu.GetTitleID().length() ? " [" + Emu.GetTitleID() + "] | " : " | ") + AdaptaterName.ToStdString() + " | ";
|
const std::string sub_title = Emu.GetTitle() + (Emu.GetTitleID().length() ? " [" + Emu.GetTitleID() + "] | " : " | ") + " | ";
|
||||||
|
|
||||||
if (fps_t.GetElapsedTimeInSec() >= 0.5)
|
if (fps_t.GetElapsedTimeInSec() >= 0.5)
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,7 +9,6 @@ struct D3DGSFrame : public GSFrame, public GSFrameBase2
|
||||||
{
|
{
|
||||||
wxWindow* canvas;
|
wxWindow* canvas;
|
||||||
u32 m_frames;
|
u32 m_frames;
|
||||||
wxString AdaptaterName;
|
|
||||||
|
|
||||||
D3DGSFrame();
|
D3DGSFrame();
|
||||||
~D3DGSFrame();
|
~D3DGSFrame();
|
||||||
|
@ -29,7 +28,6 @@ struct D3DGSFrame : public GSFrame, public GSFrameBase2
|
||||||
|
|
||||||
virtual void SetViewport(int x, int y, u32 w, u32 h) override;
|
virtual void SetViewport(int x, int y, u32 w, u32 h) override;
|
||||||
virtual HWND getHandle() const override;
|
virtual HWND getHandle() const override;
|
||||||
virtual void SetAdaptaterName(const wchar_t *) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual void OnSize(wxSizeEvent& event);
|
virtual void OnSize(wxSizeEvent& event);
|
||||||
|
|
|
@ -7,6 +7,13 @@
|
||||||
#include "Utilities/Log.h"
|
#include "Utilities/Log.h"
|
||||||
#include <wx/radiobox.h>
|
#include <wx/radiobox.h>
|
||||||
|
|
||||||
|
#if defined(DX12_SUPPORT)
|
||||||
|
#undef GetHwnd
|
||||||
|
#include <d3d12.h>
|
||||||
|
#include <wrl/client.h>
|
||||||
|
#include <dxgi1_4.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
SettingsDialog::SettingsDialog(wxWindow *parent)
|
SettingsDialog::SettingsDialog(wxWindow *parent)
|
||||||
: wxDialog(parent, wxID_ANY, "Settings", wxDefaultPosition)
|
: wxDialog(parent, wxID_ANY, "Settings", wxDefaultPosition)
|
||||||
{
|
{
|
||||||
|
@ -159,11 +166,20 @@ SettingsDialog::SettingsDialog(wxWindow *parent)
|
||||||
cbox_gs_render->Append("DirectX 12");
|
cbox_gs_render->Append("DirectX 12");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
cbox_gs_d3d_adaptater->Append("WARP");
|
#if defined(DX12_SUPPORT)
|
||||||
cbox_gs_d3d_adaptater->Append("Default");
|
unsigned id = 0;
|
||||||
cbox_gs_d3d_adaptater->Append("Renderer 0");
|
Microsoft::WRL::ComPtr<IDXGIFactory4> dxgiFactory;
|
||||||
cbox_gs_d3d_adaptater->Append("Renderer 1");
|
CreateDXGIFactory(IID_PPV_ARGS(&dxgiFactory));
|
||||||
cbox_gs_d3d_adaptater->Append("Renderer 2");
|
Microsoft::WRL::ComPtr<IDXGIAdapter> adapter;
|
||||||
|
|
||||||
|
while (dxgiFactory->EnumAdapters(id, adapter.GetAddressOf()) != DXGI_ERROR_NOT_FOUND)
|
||||||
|
{
|
||||||
|
DXGI_ADAPTER_DESC adapterDesc;
|
||||||
|
adapter->GetDesc(&adapterDesc);
|
||||||
|
cbox_gs_d3d_adaptater->Append(adapterDesc.Description);
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(DX12_SUPPORT)
|
#if !defined(DX12_SUPPORT)
|
||||||
cbox_gs_d3d_adaptater->Enable(false);
|
cbox_gs_d3d_adaptater->Enable(false);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue