#ifdef _MSC_VER #include "stdafx.h" #include "stdafx_d3d12.h" #include "D3D12MemoryHelpers.h" #include "Utilities/VirtualMemory.h" void data_cache::store_and_protect_data(u64 key, u32 start, size_t size, u8 format, size_t w, size_t h, size_t d, size_t m, ComPtr data) { std::lock_guard lock(m_mut); m_address_to_data[key] = std::make_pair(texture_entry(format, w, h, d, m), data); protect_data(key, start, size); } void data_cache::protect_data(u64 key, u32 start, size_t size) { /// align start to 4096 byte static const u32 memory_page_size = 4096; u32 protected_range_start = start & ~(memory_page_size - 1); u32 protected_range_size = (u32)align(size, memory_page_size); m_protected_ranges.push_back(std::make_tuple(key, protected_range_start, protected_range_size)); utils::memory_protect(vm::base(protected_range_start), protected_range_size, utils::protection::ro); } bool data_cache::invalidate_address(u32 addr) { // In case 2 threads write to texture memory std::lock_guard lock(m_mut); bool handled = false; auto It = m_protected_ranges.begin(), E = m_protected_ranges.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) { u64 texadrr = std::get<0>(protectedTexture); m_address_to_data[texadrr].first.m_is_dirty = true; utils::memory_protect(vm::base(protectedRangeStart), protectedRangeSize, utils::protection::rw); m_protected_ranges.erase(currentIt); handled = true; } } return handled; } std::pair > *data_cache::find_data_if_available(u64 key) { std::lock_guard lock(m_mut); auto It = m_address_to_data.find(key); if (It == m_address_to_data.end()) return nullptr; return &It->second; } void data_cache::unprotect_all() { std::lock_guard lock(m_mut); for (auto &protectedTexture : m_protected_ranges) { u32 protectedRangeStart = std::get<1>(protectedTexture), protectedRangeSize = std::get<2>(protectedTexture); utils::memory_protect(vm::base(protectedRangeStart), protectedRangeSize, utils::protection::rw); } } ComPtr data_cache::remove_from_cache(u64 key) { auto result = m_address_to_data[key].second; m_address_to_data.erase(key); return result; } void resource_storage::reset() { descriptors_heap_index = 0; current_sampler_index = 0; sampler_descriptors_heap_index = 0; render_targets_descriptors_heap_index = 0; depth_stencil_descriptor_heap_index = 0; CHECK_HRESULT(command_allocator->Reset()); set_new_command_list(); } void resource_storage::set_new_command_list() { CHECK_HRESULT(command_list->Reset(command_allocator.Get(), nullptr)); ID3D12DescriptorHeap *descriptors[] = { descriptors_heap.Get(), sampler_descriptor_heap[sampler_descriptors_heap_index].Get(), }; command_list->SetDescriptorHeaps(2, descriptors); } void resource_storage::init(ID3D12Device *device) { in_use = false; m_device = device; ram_framebuffer = nullptr; // Create a global command allocator CHECK_HRESULT(device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(command_allocator.GetAddressOf()))); CHECK_HRESULT(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, command_allocator.Get(), nullptr, IID_PPV_ARGS(command_list.GetAddressOf()))); CHECK_HRESULT(command_list->Close()); D3D12_DESCRIPTOR_HEAP_DESC descriptor_heap_desc = { D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 50000, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE }; CHECK_HRESULT(device->CreateDescriptorHeap(&descriptor_heap_desc, IID_PPV_ARGS(&descriptors_heap))); D3D12_DESCRIPTOR_HEAP_DESC sampler_heap_desc = { D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER , 2048, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE }; CHECK_HRESULT(device->CreateDescriptorHeap(&sampler_heap_desc, IID_PPV_ARGS(&sampler_descriptor_heap[0]))); CHECK_HRESULT(device->CreateDescriptorHeap(&sampler_heap_desc, IID_PPV_ARGS(&sampler_descriptor_heap[1]))); D3D12_DESCRIPTOR_HEAP_DESC ds_descriptor_heap_desc = { D3D12_DESCRIPTOR_HEAP_TYPE_DSV , 10000}; device->CreateDescriptorHeap(&ds_descriptor_heap_desc, IID_PPV_ARGS(&depth_stencil_descriptor_heap)); D3D12_DESCRIPTOR_HEAP_DESC rtv_descriptor_heap_desc = { D3D12_DESCRIPTOR_HEAP_TYPE_RTV , 10000 }; device->CreateDescriptorHeap(&rtv_descriptor_heap_desc, IID_PPV_ARGS(&render_targets_descriptors_heap)); frame_finished_handle = CreateEventEx(nullptr, FALSE, FALSE, EVENT_ALL_ACCESS); fence_value = 0; CHECK_HRESULT(device->CreateFence(fence_value++, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(frame_finished_fence.GetAddressOf()))); } void resource_storage::wait_and_clean() { if (in_use) WaitForSingleObjectEx(frame_finished_handle, INFINITE, FALSE); else CHECK_HRESULT(command_list->Close()); reset(); dirty_textures.clear(); ram_framebuffer = nullptr; } void resource_storage::release() { dirty_textures.clear(); // NOTE: Should be released only after gfx pipeline last command has been finished. CloseHandle(frame_finished_handle); } #endif