Skip to content

Commit

Permalink
Merge pull request RPCS3#1243 from vlj/d3d12
Browse files Browse the repository at this point in the history
D3d12: Small code and performance improvements.
  • Loading branch information
tambry committed Oct 5, 2015
2 parents cd71125 + d511153 commit ebf28f8
Show file tree
Hide file tree
Showing 8 changed files with 244 additions and 105 deletions.
8 changes: 6 additions & 2 deletions rpcs3/Emu/RSX/Common/BufferUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,15 @@ std::vector<VertexBufferFormat> FormatVertexData(const RSXVertexData *m_vertex_d
const RSXVertexData &vertexData = m_vertex_data[i];
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
size_t stride = vertexData.stride;
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;

for (VertexBufferFormat &vbf : Result)
Expand Down
80 changes: 20 additions & 60 deletions rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,7 @@ void D3D12GSRender::ResourceStorage::WaitAndClean()

Reset();

for (auto tmp : m_dirtyTextures)
tmp->Release();
m_dirtyTextures.clear();

m_RAMFramebuffer = nullptr;
}
Expand All @@ -119,30 +118,11 @@ void D3D12GSRender::Shader::Release()

extern std::function<bool(u32 addr)> gfxHandler;

bool D3D12GSRender::invalidateTexture(u32 addr)
bool D3D12GSRender::invalidateAddress(u32 addr)
{
bool handled = false;
auto It = m_protectedTextures.begin(), E = m_protectedTextures.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 < 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;
bool result = false;
result |= m_textureCache.invalidateAddress(addr);
return result;
}

D3D12DLLManagement::D3D12DLLManagement()
Expand All @@ -158,8 +138,13 @@ D3D12DLLManagement::~D3D12DLLManagement()
D3D12GSRender::D3D12GSRender()
: 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) {
bool result = invalidateTexture(addr);
bool result = invalidateAddress(addr);
if (result)
LOG_WARNING(RSX, "Reporting Cell writing to %x", addr);
return result;
Expand All @@ -174,20 +159,9 @@ D3D12GSRender::D3D12GSRender()
Microsoft::WRL::ComPtr<IDXGIFactory4> dxgiFactory;
ThrowIfFailed(CreateDXGIFactory(IID_PPV_ARGS(&dxgiFactory)));
// Create adapter
IDXGIAdapter* adaptater = nullptr;
switch (Ini.GSD3DAdaptater.GetValue())
{
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)));
ComPtr<IDXGIAdapter> adaptater = nullptr;
ThrowIfFailed(dxgiFactory->EnumAdapters(Ini.GSD3DAdaptater.GetValue(), adaptater.GetAddressOf()));
ThrowIfFailed(wrapD3D12CreateDevice(adaptater.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device)));

// Queues
D3D12_COMMAND_QUEUE_DESC copyQueueDesc = {}, graphicQueueDesc = {};
Expand All @@ -201,9 +175,6 @@ D3D12GSRender::D3D12GSRender()
g_descriptorStrideSamplers = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);

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
DXGI_SWAP_CHAIN_DESC swapChain = {};
Expand Down Expand Up @@ -305,12 +276,7 @@ D3D12GSRender::~D3D12GSRender()
CloseHandle(handle);

{
std::lock_guard<std::mutex> lock(mut);
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);
}
m_textureCache.unprotedAll();
}

gfxHandler = [this](u32) { return false; };
Expand All @@ -326,10 +292,6 @@ D3D12GSRender::~D3D12GSRender()
m_perFrameStorage[0].Release();
m_perFrameStorage[1].Release();
m_rtts.Release();
for (auto &tmp : m_texToClean)
tmp->Release();
for (auto &tmp : m_texturesCache)
tmp.second->Release();
m_outputScalingPass.Release();

ReleaseD2DStructures();
Expand Down Expand Up @@ -851,9 +813,7 @@ void D3D12GSRender::Flip()
storage.m_frameFinishedFence->SetEventOnCompletion(storage.m_fenceValue, storage.m_frameFinishedHandle);
storage.m_fenceValue++;

storage.m_dirtyTextures = m_texToClean;
storage.m_inUse = true;
m_texToClean.clear();

// 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
Expand Down Expand Up @@ -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,
&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;
Expand Down Expand Up @@ -1110,10 +1070,10 @@ void D3D12GSRender::semaphorePGRAPHBackendRelease(u32 offset, u32 value)
break;
}

if (m_context_dma_color_a) invalidateTexture(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_c) invalidateTexture(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_a) invalidateAddress(GetAddress(m_surface_offset_a, m_context_dma_color_a - 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) invalidateAddress(GetAddress(m_surface_offset_c, m_context_dma_color_c - 0xfeed0000));
if (m_context_dma_color_d) invalidateAddress(GetAddress(m_surface_offset_d, m_context_dma_color_d - 0xfeed0000));
}
if (needTransfer)
{
Expand Down
138 changes: 124 additions & 14 deletions rpcs3/Emu/RSX/D3D12/D3D12GSRender.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ class GSFrameBase2
virtual void DeleteContext(void* ctx) = 0;
virtual void Flip(void* ctx) = 0;
virtual HWND getHandle() const = 0;
virtual void SetAdaptaterName(const wchar_t *) = 0;
};

typedef GSFrameBase2*(*GetGSFrameCb2)();
Expand Down Expand Up @@ -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.
*/
Expand All @@ -213,22 +324,14 @@ class D3D12GSRender : public GSRender
ComPtr<ID3D12DescriptorHeap> m_backbufferAsRendertarget[2];
// m_rootSignatures[N] is RS with N texture/sample
ComPtr<ID3D12RootSignature> m_rootSignatures[17];
/**
* Mutex protecting m_texturesCache and m_Textoclean access
* Memory protection fault catch can be generated by any thread and
* modifies these two members.
*/
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);

// TODO: Use a tree structure to parse more efficiently
DataCache m_textureCache;
bool invalidateAddress(u32 addr);

// Copy of RTT to be used as texture
std::unordered_map<u32, ID3D12Resource* > m_texturesRTTs;

std::unordered_map<u32, ID3D12Resource*> m_texturesCache;
// std::vector<PostDrawObj> m_post_draw_objs;

PipelineStateObjectCache m_cachePSO;
std::pair<ID3D12PipelineState *, size_t> *m_PSO;

Expand Down Expand Up @@ -311,7 +414,7 @@ class D3D12GSRender : public GSRender


/// Texture that were invalidated
std::vector<ID3D12Resource *> m_dirtyTextures;
std::list<ComPtr<ID3D12Resource> > m_dirtyTextures;

size_t m_getPosConstantsHeap;
size_t m_getPosVertexIndexHeap;
Expand Down Expand Up @@ -359,6 +462,13 @@ class D3D12GSRender : public GSRender
ID3D12Resource *m_dummyTexture;

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:
GSFrameBase2 *m_frame;
u32 m_draw_frames;
Expand Down
14 changes: 14 additions & 0 deletions rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,20 @@

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
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;
Expand Down

0 comments on commit ebf28f8

Please sign in to comment.