[D3D12] Bindless textures/samplers
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include "third_party/xxhash/xxhash.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cfloat>
|
||||
#include <cstring>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
@@ -92,7 +93,6 @@ namespace d3d12 {
|
||||
#include "xenia/gpu/d3d12/shaders/dxbc/texture_tile_r10g11b11_rgba16_cs.h"
|
||||
#include "xenia/gpu/d3d12/shaders/dxbc/texture_tile_r11g11b10_rgba16_cs.h"
|
||||
|
||||
constexpr uint32_t TextureCache::Texture::kCachedSRVDescriptorSwizzleMissing;
|
||||
constexpr uint32_t TextureCache::SRVDescriptorCachePage::kHeapSize;
|
||||
constexpr uint32_t TextureCache::LoadConstants::kGuestPitchTiled;
|
||||
constexpr uint32_t TextureCache::kScaledResolveBufferSizeLog2;
|
||||
@@ -905,9 +905,11 @@ const TextureCache::ResolveTileModeInfo
|
||||
|
||||
TextureCache::TextureCache(D3D12CommandProcessor* command_processor,
|
||||
RegisterFile* register_file,
|
||||
bool bindless_resources_used,
|
||||
SharedMemory* shared_memory)
|
||||
: command_processor_(command_processor),
|
||||
register_file_(register_file),
|
||||
bindless_resources_used_(bindless_resources_used),
|
||||
shared_memory_(shared_memory) {}
|
||||
|
||||
TextureCache::~TextureCache() { Shutdown(); }
|
||||
@@ -920,7 +922,8 @@ bool TextureCache::Initialize(bool edram_rov_used) {
|
||||
// Not currently supported with the RTV/DSV output path for various reasons.
|
||||
// As of November 27th, 2018, PIX doesn't support tiled buffers.
|
||||
if (cvars::d3d12_resolution_scale >= 2 && edram_rov_used &&
|
||||
provider->GetTiledResourcesTier() >= 1 &&
|
||||
provider->GetTiledResourcesTier() !=
|
||||
D3D12_TILED_RESOURCES_TIER_NOT_SUPPORTED &&
|
||||
provider->GetGraphicsAnalysis() == nullptr &&
|
||||
provider->GetVirtualAddressBitsPerResource() >=
|
||||
kScaledResolveBufferSizeLog2) {
|
||||
@@ -947,28 +950,34 @@ bool TextureCache::Initialize(bool edram_rov_used) {
|
||||
scaled_resolve_heap_count_ = 0;
|
||||
|
||||
// Create the loading root signature.
|
||||
D3D12_ROOT_PARAMETER root_parameters[2];
|
||||
// Parameter 0 is constants (changed very often when untiling).
|
||||
D3D12_ROOT_PARAMETER root_parameters[3];
|
||||
// Parameter 0 is constants (changed multiple times when untiling).
|
||||
root_parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
|
||||
root_parameters[0].Descriptor.ShaderRegister = 0;
|
||||
root_parameters[0].Descriptor.RegisterSpace = 0;
|
||||
root_parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
// Parameter 1 is source and target.
|
||||
D3D12_DESCRIPTOR_RANGE root_copy_ranges[2];
|
||||
root_copy_ranges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
||||
root_copy_ranges[0].NumDescriptors = 1;
|
||||
root_copy_ranges[0].BaseShaderRegister = 0;
|
||||
root_copy_ranges[0].RegisterSpace = 0;
|
||||
root_copy_ranges[0].OffsetInDescriptorsFromTableStart = 0;
|
||||
root_copy_ranges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
|
||||
root_copy_ranges[1].NumDescriptors = 1;
|
||||
root_copy_ranges[1].BaseShaderRegister = 0;
|
||||
root_copy_ranges[1].RegisterSpace = 0;
|
||||
root_copy_ranges[1].OffsetInDescriptorsFromTableStart = 1;
|
||||
// Parameter 1 is the destination.
|
||||
D3D12_DESCRIPTOR_RANGE root_dest_range;
|
||||
root_dest_range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
|
||||
root_dest_range.NumDescriptors = 1;
|
||||
root_dest_range.BaseShaderRegister = 0;
|
||||
root_dest_range.RegisterSpace = 0;
|
||||
root_dest_range.OffsetInDescriptorsFromTableStart = 0;
|
||||
root_parameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
root_parameters[1].DescriptorTable.NumDescriptorRanges = 2;
|
||||
root_parameters[1].DescriptorTable.pDescriptorRanges = root_copy_ranges;
|
||||
root_parameters[1].DescriptorTable.NumDescriptorRanges = 1;
|
||||
root_parameters[1].DescriptorTable.pDescriptorRanges = &root_dest_range;
|
||||
root_parameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
// Parameter 2 is the source.
|
||||
D3D12_DESCRIPTOR_RANGE root_source_range;
|
||||
root_source_range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
||||
root_source_range.NumDescriptors = 1;
|
||||
root_source_range.BaseShaderRegister = 0;
|
||||
root_source_range.RegisterSpace = 0;
|
||||
root_source_range.OffsetInDescriptorsFromTableStart = 0;
|
||||
root_parameters[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
root_parameters[2].DescriptorTable.NumDescriptorRanges = 1;
|
||||
root_parameters[2].DescriptorTable.pDescriptorRanges = &root_source_range;
|
||||
root_parameters[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
D3D12_ROOT_SIGNATURE_DESC root_signature_desc;
|
||||
root_signature_desc.NumParameters = UINT(xe::countof(root_parameters));
|
||||
root_signature_desc.pParameters = root_parameters;
|
||||
@@ -1033,6 +1042,8 @@ bool TextureCache::Initialize(bool edram_rov_used) {
|
||||
}
|
||||
}
|
||||
|
||||
srv_descriptor_cache_allocated_ = 0;
|
||||
|
||||
// Create a heap with null SRV descriptors, since it's faster to copy a
|
||||
// descriptor than to create an SRV, and null descriptors are used a lot (for
|
||||
// the signed version when only unsigned is used, for instance).
|
||||
@@ -1137,6 +1148,14 @@ void TextureCache::ClearCache() {
|
||||
Texture* texture = texture_pair.second;
|
||||
shared_memory_->UnwatchMemoryRange(texture->base_watch_handle);
|
||||
shared_memory_->UnwatchMemoryRange(texture->mip_watch_handle);
|
||||
// Bindful descriptor cache will be cleared entirely now, so only release
|
||||
// bindless descriptors.
|
||||
if (bindless_resources_used_) {
|
||||
for (auto descriptor_pair : texture->srv_descriptors) {
|
||||
command_processor_->ReleaseViewBindlessDescriptorImmediately(
|
||||
descriptor_pair.second);
|
||||
}
|
||||
}
|
||||
texture->resource->Release();
|
||||
delete texture;
|
||||
}
|
||||
@@ -1148,6 +1167,7 @@ void TextureCache::ClearCache() {
|
||||
|
||||
// Clear texture descriptor cache.
|
||||
srv_descriptor_cache_free_.clear();
|
||||
srv_descriptor_cache_allocated_ = 0;
|
||||
for (auto& page : srv_descriptor_cache_) {
|
||||
page.heap->Release();
|
||||
}
|
||||
@@ -1155,7 +1175,7 @@ void TextureCache::ClearCache() {
|
||||
}
|
||||
|
||||
void TextureCache::TextureFetchConstantWritten(uint32_t index) {
|
||||
texture_keys_in_sync_ &= ~(1u << index);
|
||||
texture_bindings_in_sync_ &= ~(1u << index);
|
||||
}
|
||||
|
||||
void TextureCache::BeginFrame() {
|
||||
@@ -1214,12 +1234,18 @@ void TextureCache::BeginFrame() {
|
||||
// Exclude the texture from the memory usage counter.
|
||||
textures_total_size_ -= texture->resource_size;
|
||||
// Destroy the texture.
|
||||
if (texture->cached_srv_descriptor_swizzle !=
|
||||
Texture::kCachedSRVDescriptorSwizzleMissing) {
|
||||
srv_descriptor_cache_free_.push_back(texture->cached_srv_descriptor);
|
||||
}
|
||||
shared_memory_->UnwatchMemoryRange(texture->base_watch_handle);
|
||||
shared_memory_->UnwatchMemoryRange(texture->mip_watch_handle);
|
||||
if (bindless_resources_used_) {
|
||||
for (auto descriptor_pair : texture->srv_descriptors) {
|
||||
command_processor_->ReleaseViewBindlessDescriptorImmediately(
|
||||
descriptor_pair.second);
|
||||
}
|
||||
} else {
|
||||
for (auto descriptor_pair : texture->srv_descriptors) {
|
||||
srv_descriptor_cache_free_.push_back(descriptor_pair.second);
|
||||
}
|
||||
}
|
||||
texture->resource->Release();
|
||||
delete texture;
|
||||
}
|
||||
@@ -1262,8 +1288,10 @@ void TextureCache::RequestTextures(uint32_t used_texture_mask) {
|
||||
// loading may be needed in some draw call later, which may have the same
|
||||
// key for some binding as before the invalidation, but texture_invalidated_
|
||||
// being false (menu background in Halo 3).
|
||||
std::memset(texture_bindings_, 0, sizeof(texture_bindings_));
|
||||
texture_keys_in_sync_ = 0;
|
||||
for (size_t i = 0; i < xe::countof(texture_bindings_); ++i) {
|
||||
texture_bindings_[i].Clear();
|
||||
}
|
||||
texture_bindings_in_sync_ = 0;
|
||||
}
|
||||
|
||||
// Update the texture keys and the textures.
|
||||
@@ -1272,7 +1300,7 @@ void TextureCache::RequestTextures(uint32_t used_texture_mask) {
|
||||
while (xe::bit_scan_forward(textures_remaining, &index)) {
|
||||
uint32_t index_bit = uint32_t(1) << index;
|
||||
textures_remaining &= ~index_bit;
|
||||
if (texture_keys_in_sync_ & index_bit) {
|
||||
if (texture_bindings_in_sync_ & index_bit) {
|
||||
continue;
|
||||
}
|
||||
TextureBinding& binding = texture_bindings_[index];
|
||||
@@ -1282,10 +1310,12 @@ void TextureCache::RequestTextures(uint32_t used_texture_mask) {
|
||||
uint8_t old_swizzled_signs = binding.swizzled_signs;
|
||||
BindingInfoFromFetchConstant(fetch, binding.key, &binding.host_swizzle,
|
||||
&binding.swizzled_signs);
|
||||
texture_keys_in_sync_ |= index_bit;
|
||||
texture_bindings_in_sync_ |= index_bit;
|
||||
if (binding.key.IsInvalid()) {
|
||||
binding.texture = nullptr;
|
||||
binding.texture_signed = nullptr;
|
||||
binding.descriptor_index = UINT32_MAX;
|
||||
binding.descriptor_index_signed = UINT32_MAX;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1305,27 +1335,64 @@ void TextureCache::RequestTextures(uint32_t used_texture_mask) {
|
||||
if (key_changed ||
|
||||
!texture_util::IsAnySignNotSigned(old_swizzled_signs)) {
|
||||
binding.texture = FindOrCreateTexture(binding.key);
|
||||
binding.descriptor_index =
|
||||
binding.texture
|
||||
? FindOrCreateTextureDescriptor(*binding.texture, false,
|
||||
binding.host_swizzle)
|
||||
: UINT32_MAX;
|
||||
load_unsigned_data = true;
|
||||
}
|
||||
} else {
|
||||
binding.texture = nullptr;
|
||||
binding.descriptor_index = UINT32_MAX;
|
||||
}
|
||||
if (texture_util::IsAnySignSigned(binding.swizzled_signs)) {
|
||||
if (key_changed || !texture_util::IsAnySignSigned(old_swizzled_signs)) {
|
||||
TextureKey signed_key = binding.key;
|
||||
signed_key.signed_separate = 1;
|
||||
binding.texture_signed = FindOrCreateTexture(signed_key);
|
||||
binding.descriptor_index_signed =
|
||||
binding.texture
|
||||
? FindOrCreateTextureDescriptor(*binding.texture_signed, true,
|
||||
binding.host_swizzle)
|
||||
: UINT32_MAX;
|
||||
load_signed_data = true;
|
||||
}
|
||||
} else {
|
||||
binding.texture_signed = nullptr;
|
||||
binding.descriptor_index_signed = UINT32_MAX;
|
||||
}
|
||||
} else {
|
||||
// Same resource for both unsigned and signed, but descriptor formats may
|
||||
// be different.
|
||||
if (key_changed) {
|
||||
binding.texture = FindOrCreateTexture(binding.key);
|
||||
load_unsigned_data = true;
|
||||
}
|
||||
binding.texture_signed = nullptr;
|
||||
if (texture_util::IsAnySignNotSigned(binding.swizzled_signs)) {
|
||||
if (key_changed ||
|
||||
!texture_util::IsAnySignNotSigned(old_swizzled_signs)) {
|
||||
binding.descriptor_index =
|
||||
binding.texture
|
||||
? FindOrCreateTextureDescriptor(*binding.texture, false,
|
||||
binding.host_swizzle)
|
||||
: UINT32_MAX;
|
||||
}
|
||||
} else {
|
||||
binding.descriptor_index = UINT32_MAX;
|
||||
}
|
||||
if (texture_util::IsAnySignSigned(binding.swizzled_signs)) {
|
||||
if (key_changed || !texture_util::IsAnySignSigned(old_swizzled_signs)) {
|
||||
binding.descriptor_index_signed =
|
||||
binding.texture
|
||||
? FindOrCreateTextureDescriptor(*binding.texture, true,
|
||||
binding.host_swizzle)
|
||||
: UINT32_MAX;
|
||||
}
|
||||
} else {
|
||||
binding.descriptor_index_signed = UINT32_MAX;
|
||||
}
|
||||
}
|
||||
if (load_unsigned_data && binding.texture != nullptr) {
|
||||
LoadTextureData(binding.texture);
|
||||
@@ -1368,208 +1435,132 @@ void TextureCache::RequestTextures(uint32_t used_texture_mask) {
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t TextureCache::GetDescriptorHashForActiveTextures(
|
||||
const D3D12Shader::TextureSRV* texture_srvs,
|
||||
uint32_t texture_srv_count) const {
|
||||
XXH64_state_t hash_state;
|
||||
XXH64_reset(&hash_state, 0);
|
||||
for (uint32_t i = 0; i < texture_srv_count; ++i) {
|
||||
const D3D12Shader::TextureSRV& texture_srv = texture_srvs[i];
|
||||
// There can be multiple SRVs of the same texture.
|
||||
XXH64_update(&hash_state, &texture_srv.dimension,
|
||||
sizeof(texture_srv.dimension));
|
||||
XXH64_update(&hash_state, &texture_srv.is_signed,
|
||||
sizeof(texture_srv.is_signed));
|
||||
bool TextureCache::AreActiveTextureSRVKeysUpToDate(
|
||||
const TextureSRVKey* keys,
|
||||
const D3D12Shader::TextureBinding* host_shader_bindings,
|
||||
uint32_t host_shader_binding_count) const {
|
||||
for (uint32_t i = 0; i < host_shader_binding_count; ++i) {
|
||||
const TextureSRVKey& key = keys[i];
|
||||
const TextureBinding& binding =
|
||||
texture_bindings_[texture_srv.fetch_constant];
|
||||
XXH64_update(&hash_state, &binding.key, sizeof(binding.key));
|
||||
XXH64_update(&hash_state, &binding.host_swizzle,
|
||||
sizeof(binding.host_swizzle));
|
||||
XXH64_update(&hash_state, &binding.swizzled_signs,
|
||||
sizeof(binding.swizzled_signs));
|
||||
texture_bindings_[host_shader_bindings[i].fetch_constant];
|
||||
if (key.key != binding.key || key.host_swizzle != binding.host_swizzle ||
|
||||
key.swizzled_signs != binding.swizzled_signs) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return XXH64_digest(&hash_state);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TextureCache::WriteTextureSRV(const D3D12Shader::TextureSRV& texture_srv,
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE handle) {
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC desc;
|
||||
desc.Format = DXGI_FORMAT_UNKNOWN;
|
||||
Dimension binding_dimension;
|
||||
uint32_t mip_max_level, array_size;
|
||||
void TextureCache::WriteActiveTextureSRVKeys(
|
||||
TextureSRVKey* keys,
|
||||
const D3D12Shader::TextureBinding* host_shader_bindings,
|
||||
uint32_t host_shader_binding_count) const {
|
||||
for (uint32_t i = 0; i < host_shader_binding_count; ++i) {
|
||||
TextureSRVKey& key = keys[i];
|
||||
const TextureBinding& binding =
|
||||
texture_bindings_[host_shader_bindings[i].fetch_constant];
|
||||
key.key = binding.key;
|
||||
key.host_swizzle = binding.host_swizzle;
|
||||
key.swizzled_signs = binding.swizzled_signs;
|
||||
}
|
||||
}
|
||||
|
||||
void TextureCache::WriteActiveTextureBindfulSRV(
|
||||
const D3D12Shader::TextureBinding& host_shader_binding,
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE handle) {
|
||||
assert_false(bindless_resources_used_);
|
||||
const TextureBinding& binding =
|
||||
texture_bindings_[host_shader_binding.fetch_constant];
|
||||
uint32_t descriptor_index = UINT32_MAX;
|
||||
Texture* texture = nullptr;
|
||||
ID3D12Resource* resource = nullptr;
|
||||
|
||||
const TextureBinding& binding = texture_bindings_[texture_srv.fetch_constant];
|
||||
if (!binding.key.IsInvalid()) {
|
||||
TextureFormat format = binding.key.format;
|
||||
|
||||
if (IsSignedVersionSeparate(format) && texture_srv.is_signed) {
|
||||
texture = binding.texture_signed;
|
||||
} else {
|
||||
texture = binding.texture;
|
||||
}
|
||||
if (texture != nullptr) {
|
||||
resource = texture->resource;
|
||||
}
|
||||
|
||||
if (texture_srv.is_signed) {
|
||||
if (!binding.key.IsInvalid() &&
|
||||
AreDimensionsCompatible(host_shader_binding.dimension,
|
||||
binding.key.dimension)) {
|
||||
if (host_shader_binding.is_signed) {
|
||||
// Not supporting signed compressed textures - hopefully DXN and DXT5A are
|
||||
// not used as signed.
|
||||
if (texture_util::IsAnySignSigned(binding.swizzled_signs)) {
|
||||
desc.Format = host_formats_[uint32_t(format)].dxgi_format_snorm;
|
||||
if (desc.Format == DXGI_FORMAT_UNKNOWN) {
|
||||
unsupported_format_features_used_[uint32_t(format)] |=
|
||||
kUnsupportedSnormBit;
|
||||
}
|
||||
descriptor_index = binding.descriptor_index_signed;
|
||||
texture = IsSignedVersionSeparate(binding.key.format)
|
||||
? binding.texture_signed
|
||||
: binding.texture;
|
||||
}
|
||||
} else {
|
||||
if (texture_util::IsAnySignNotSigned(binding.swizzled_signs)) {
|
||||
desc.Format = GetDXGIUnormFormat(binding.key);
|
||||
if (desc.Format == DXGI_FORMAT_UNKNOWN) {
|
||||
unsupported_format_features_used_[uint32_t(format)] |=
|
||||
kUnsupportedUnormBit;
|
||||
}
|
||||
descriptor_index = binding.descriptor_index;
|
||||
texture = binding.texture;
|
||||
}
|
||||
}
|
||||
|
||||
binding_dimension = binding.key.dimension;
|
||||
mip_max_level = binding.key.mip_max_level;
|
||||
array_size = binding.key.depth;
|
||||
// XE_GPU_SWIZZLE and D3D12_SHADER_COMPONENT_MAPPING are the same except for
|
||||
// one bit.
|
||||
desc.Shader4ComponentMapping =
|
||||
binding.host_swizzle |
|
||||
D3D12_SHADER_COMPONENT_MAPPING_ALWAYS_SET_BIT_AVOIDING_ZEROMEM_MISTAKES;
|
||||
} else {
|
||||
binding_dimension = Dimension::k2D;
|
||||
mip_max_level = 0;
|
||||
array_size = 1;
|
||||
desc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
|
||||
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0);
|
||||
}
|
||||
|
||||
if (desc.Format == DXGI_FORMAT_UNKNOWN) {
|
||||
// A null descriptor must still have a valid format.
|
||||
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
resource = nullptr;
|
||||
}
|
||||
NullSRVDescriptorIndex null_descriptor_index;
|
||||
switch (texture_srv.dimension) {
|
||||
case TextureDimension::k3D:
|
||||
desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
|
||||
desc.Texture3D.MostDetailedMip = 0;
|
||||
desc.Texture3D.MipLevels = mip_max_level + 1;
|
||||
desc.Texture3D.ResourceMinLODClamp = 0.0f;
|
||||
if (binding_dimension != Dimension::k3D) {
|
||||
// Create a null descriptor so it's safe to sample this texture even
|
||||
// though it has different dimensions.
|
||||
resource = nullptr;
|
||||
}
|
||||
null_descriptor_index = NullSRVDescriptorIndex::k3D;
|
||||
break;
|
||||
case TextureDimension::kCube:
|
||||
desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
|
||||
desc.TextureCube.MostDetailedMip = 0;
|
||||
desc.TextureCube.MipLevels = mip_max_level + 1;
|
||||
desc.TextureCube.ResourceMinLODClamp = 0.0f;
|
||||
if (binding_dimension != Dimension::kCube) {
|
||||
resource = nullptr;
|
||||
}
|
||||
null_descriptor_index = NullSRVDescriptorIndex::kCube;
|
||||
break;
|
||||
default:
|
||||
desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
|
||||
desc.Texture2DArray.MostDetailedMip = 0;
|
||||
desc.Texture2DArray.MipLevels = mip_max_level + 1;
|
||||
desc.Texture2DArray.FirstArraySlice = 0;
|
||||
desc.Texture2DArray.ArraySize = array_size;
|
||||
desc.Texture2DArray.PlaneSlice = 0;
|
||||
desc.Texture2DArray.ResourceMinLODClamp = 0.0f;
|
||||
if (binding_dimension == Dimension::k3D ||
|
||||
binding_dimension == Dimension::kCube) {
|
||||
resource = nullptr;
|
||||
}
|
||||
null_descriptor_index = NullSRVDescriptorIndex::k2DArray;
|
||||
break;
|
||||
}
|
||||
|
||||
auto provider = command_processor_->GetD3D12Context()->GetD3D12Provider();
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE source_handle;
|
||||
if (descriptor_index != UINT32_MAX) {
|
||||
assert_not_null(texture);
|
||||
MarkTextureUsed(texture);
|
||||
source_handle = GetTextureDescriptorCPUHandle(descriptor_index);
|
||||
} else {
|
||||
NullSRVDescriptorIndex null_descriptor_index;
|
||||
switch (host_shader_binding.dimension) {
|
||||
case TextureDimension::k3D:
|
||||
null_descriptor_index = NullSRVDescriptorIndex::k3D;
|
||||
break;
|
||||
case TextureDimension::kCube:
|
||||
null_descriptor_index = NullSRVDescriptorIndex::kCube;
|
||||
break;
|
||||
default:
|
||||
assert_true(host_shader_binding.dimension == TextureDimension::k1D ||
|
||||
host_shader_binding.dimension == TextureDimension::k2D);
|
||||
null_descriptor_index = NullSRVDescriptorIndex::k2DArray;
|
||||
}
|
||||
source_handle = provider->OffsetViewDescriptor(
|
||||
null_srv_descriptor_heap_start_, uint32_t(null_descriptor_index));
|
||||
}
|
||||
auto device = provider->GetDevice();
|
||||
if (resource == nullptr) {
|
||||
// Copy a pre-made null descriptor since it's faster than to create an SRV.
|
||||
device->CopyDescriptorsSimple(
|
||||
1, handle,
|
||||
provider->OffsetViewDescriptor(null_srv_descriptor_heap_start_,
|
||||
uint32_t(null_descriptor_index)),
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
return;
|
||||
}
|
||||
MarkTextureUsed(texture);
|
||||
// Take the descriptor from the cache if it's cached, or create a new one in
|
||||
// the cache, or directly if this texture was already used with a different
|
||||
// swizzle. Profiling results say that CreateShaderResourceView takes the
|
||||
// longest time of draw call processing, and it's very noticeable in many
|
||||
// games.
|
||||
bool cached_handle_available = false;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE cached_handle = {};
|
||||
assert_not_null(texture);
|
||||
if (texture->cached_srv_descriptor_swizzle !=
|
||||
Texture::kCachedSRVDescriptorSwizzleMissing) {
|
||||
// Use an existing cached descriptor if it has the needed swizzle.
|
||||
if (binding.host_swizzle == texture->cached_srv_descriptor_swizzle) {
|
||||
cached_handle_available = true;
|
||||
cached_handle = texture->cached_srv_descriptor;
|
||||
}
|
||||
} else {
|
||||
// Try to create a new cached descriptor if it doesn't exist yet.
|
||||
if (!srv_descriptor_cache_free_.empty()) {
|
||||
cached_handle_available = true;
|
||||
cached_handle = srv_descriptor_cache_free_.back();
|
||||
srv_descriptor_cache_free_.pop_back();
|
||||
} else if (srv_descriptor_cache_.empty() ||
|
||||
srv_descriptor_cache_.back().current_usage >=
|
||||
SRVDescriptorCachePage::kHeapSize) {
|
||||
D3D12_DESCRIPTOR_HEAP_DESC new_heap_desc;
|
||||
new_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
|
||||
new_heap_desc.NumDescriptors = SRVDescriptorCachePage::kHeapSize;
|
||||
new_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
||||
new_heap_desc.NodeMask = 0;
|
||||
ID3D12DescriptorHeap* new_heap;
|
||||
if (SUCCEEDED(device->CreateDescriptorHeap(&new_heap_desc,
|
||||
IID_PPV_ARGS(&new_heap)))) {
|
||||
SRVDescriptorCachePage new_page;
|
||||
new_page.heap = new_heap;
|
||||
new_page.heap_start = new_heap->GetCPUDescriptorHandleForHeapStart();
|
||||
new_page.current_usage = 1;
|
||||
cached_handle_available = true;
|
||||
cached_handle = new_page.heap_start;
|
||||
srv_descriptor_cache_.push_back(new_page);
|
||||
}
|
||||
} else {
|
||||
SRVDescriptorCachePage& page = srv_descriptor_cache_.back();
|
||||
cached_handle_available = true;
|
||||
cached_handle =
|
||||
provider->OffsetViewDescriptor(page.heap_start, page.current_usage);
|
||||
++page.current_usage;
|
||||
}
|
||||
if (cached_handle_available) {
|
||||
device->CreateShaderResourceView(resource, &desc, cached_handle);
|
||||
texture->cached_srv_descriptor = cached_handle;
|
||||
texture->cached_srv_descriptor_swizzle = binding.host_swizzle;
|
||||
}
|
||||
}
|
||||
if (cached_handle_available) {
|
||||
device->CopyDescriptorsSimple(1, handle, cached_handle,
|
||||
{
|
||||
#if FINE_GRAINED_DRAW_SCOPES
|
||||
SCOPE_profile_cpu_i(
|
||||
"gpu",
|
||||
"xe::gpu::d3d12::TextureCache::WriteActiveTextureBindfulSRV->"
|
||||
"CopyDescriptorsSimple");
|
||||
#endif // FINE_GRAINED_DRAW_SCOPES
|
||||
device->CopyDescriptorsSimple(1, handle, source_handle,
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
} else {
|
||||
device->CreateShaderResourceView(resource, &desc, handle);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t TextureCache::GetActiveTextureBindlessSRVIndex(
|
||||
const D3D12Shader::TextureBinding& host_shader_binding) {
|
||||
assert_true(bindless_resources_used_);
|
||||
uint32_t descriptor_index = UINT32_MAX;
|
||||
const TextureBinding& binding =
|
||||
texture_bindings_[host_shader_binding.fetch_constant];
|
||||
if (!binding.key.IsInvalid() &&
|
||||
AreDimensionsCompatible(host_shader_binding.dimension,
|
||||
binding.key.dimension)) {
|
||||
descriptor_index = host_shader_binding.is_signed
|
||||
? binding.descriptor_index_signed
|
||||
: binding.descriptor_index;
|
||||
}
|
||||
if (descriptor_index == UINT32_MAX) {
|
||||
switch (host_shader_binding.dimension) {
|
||||
case TextureDimension::k3D:
|
||||
descriptor_index =
|
||||
uint32_t(D3D12CommandProcessor::SystemBindlessView::kNullTexture3D);
|
||||
break;
|
||||
case TextureDimension::kCube:
|
||||
descriptor_index = uint32_t(
|
||||
D3D12CommandProcessor::SystemBindlessView::kNullTextureCube);
|
||||
break;
|
||||
default:
|
||||
assert_true(host_shader_binding.dimension == TextureDimension::k1D ||
|
||||
host_shader_binding.dimension == TextureDimension::k2D);
|
||||
descriptor_index = uint32_t(
|
||||
D3D12CommandProcessor::SystemBindlessView::kNullTexture2DArray);
|
||||
}
|
||||
}
|
||||
return descriptor_index;
|
||||
}
|
||||
|
||||
TextureCache::SamplerParameters TextureCache::GetSamplerParameters(
|
||||
const D3D12Shader::SamplerBinding& binding) const {
|
||||
auto& regs = *register_file_;
|
||||
@@ -1583,12 +1574,11 @@ TextureCache::SamplerParameters TextureCache::GetSamplerParameters(
|
||||
parameters.clamp_z = fetch.clamp_z;
|
||||
parameters.border_color = fetch.border_color;
|
||||
|
||||
uint32_t mip_min_level, mip_max_level;
|
||||
uint32_t mip_min_level;
|
||||
texture_util::GetSubresourcesFromFetchConstant(
|
||||
fetch, nullptr, nullptr, nullptr, nullptr, nullptr, &mip_min_level,
|
||||
&mip_max_level, binding.mip_filter);
|
||||
nullptr, binding.mip_filter);
|
||||
parameters.mip_min_level = mip_min_level;
|
||||
parameters.mip_max_level = std::max(mip_max_level, mip_min_level);
|
||||
|
||||
AnisoFilter aniso_filter = binding.aniso_filter == AnisoFilter::kUseFetchConst
|
||||
? fetch.aniso_filter
|
||||
@@ -1675,7 +1665,8 @@ void TextureCache::WriteSampler(SamplerParameters parameters,
|
||||
desc.BorderColor[3] = 0.0f;
|
||||
}
|
||||
desc.MinLOD = float(parameters.mip_min_level);
|
||||
desc.MaxLOD = float(parameters.mip_max_level);
|
||||
// Maximum mip level is in the texture resource itself.
|
||||
desc.MaxLOD = FLT_MAX;
|
||||
auto device =
|
||||
command_processor_->GetD3D12Context()->GetD3D12Provider()->GetDevice();
|
||||
device->CreateSampler(&desc, handle);
|
||||
@@ -1737,8 +1728,8 @@ bool TextureCache::TileResolvedTexture(
|
||||
resolve_tile_mode_info_[uint32_t(resolve_tile_mode)];
|
||||
|
||||
auto command_list = command_processor_->GetDeferredCommandList();
|
||||
auto provider = command_processor_->GetD3D12Context()->GetD3D12Provider();
|
||||
auto device = provider->GetDevice();
|
||||
auto device =
|
||||
command_processor_->GetD3D12Context()->GetD3D12Provider()->GetDevice();
|
||||
uint32_t resolution_scale_log2 = IsResolutionScale2X() ? 1 : 0;
|
||||
|
||||
texture_base &= 0x1FFFFFFF;
|
||||
@@ -1811,12 +1802,8 @@ bool TextureCache::TileResolvedTexture(
|
||||
}
|
||||
|
||||
// Tile the texture.
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE descriptor_cpu_start;
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE descriptor_gpu_start;
|
||||
if (command_processor_->RequestViewDescriptors(
|
||||
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid, 2, 2,
|
||||
descriptor_cpu_start, descriptor_gpu_start) ==
|
||||
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) {
|
||||
ui::d3d12::util::DescriptorCPUGPUHandlePair descriptors[2];
|
||||
if (!command_processor_->RequestOneUseSingleViewDescriptors(2, descriptors)) {
|
||||
return false;
|
||||
}
|
||||
if (resolution_scale_log2) {
|
||||
@@ -1826,19 +1813,15 @@ bool TextureCache::TileResolvedTexture(
|
||||
}
|
||||
command_processor_->SubmitBarriers();
|
||||
command_list->D3DSetComputeRootSignature(resolve_tile_root_signature_);
|
||||
|
||||
ResolveTileConstants resolve_tile_constants;
|
||||
resolve_tile_constants.info = uint32_t(endian) | (uint32_t(format) << 3) |
|
||||
(resolution_scale_log2 << 9) |
|
||||
((texture_pitch >> 5) << 10) |
|
||||
(is_3d ? ((texture_height >> 5) << 19) : 0);
|
||||
resolve_tile_constants.offset = offset_x | (offset_y << 5) | (offset_z << 10);
|
||||
resolve_tile_constants.size = resolve_width | (resolve_height << 16);
|
||||
resolve_tile_constants.host_base = uint32_t(footprint.Offset);
|
||||
resolve_tile_constants.host_pitch = uint32_t(footprint.Footprint.RowPitch);
|
||||
ui::d3d12::util::CreateRawBufferSRV(device, descriptor_cpu_start, buffer,
|
||||
|
||||
// TODO(Triang3l): Use precreated bindless descriptors here after overall
|
||||
// cleanup/optimization involving typed buffers.
|
||||
ui::d3d12::util::CreateRawBufferSRV(device, descriptors[1].first, buffer,
|
||||
buffer_size);
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE descriptor_cpu_uav =
|
||||
provider->OffsetViewDescriptor(descriptor_cpu_start, 1);
|
||||
command_list->D3DSetComputeRootDescriptorTable(2, descriptors[1].second);
|
||||
|
||||
if (resolve_tile_mode_info.typed_uav_format != DXGI_FORMAT_UNKNOWN) {
|
||||
// Not sure if this alignment is actually needed in Direct3D 12, but for
|
||||
// safety. Also not using the full 512 MB buffer as a typed UAV because
|
||||
@@ -1862,22 +1845,32 @@ bool TextureCache::TileResolvedTexture(
|
||||
device->CreateUnorderedAccessView(resolution_scale_log2
|
||||
? scaled_resolve_buffer_
|
||||
: shared_memory_->GetBuffer(),
|
||||
nullptr, &uav_desc, descriptor_cpu_uav);
|
||||
nullptr, &uav_desc, descriptors[0].first);
|
||||
} else {
|
||||
if (resolution_scale_log2) {
|
||||
resolve_tile_constants.guest_base = texture_base & 0xFFF;
|
||||
CreateScaledResolveBufferRawUAV(
|
||||
descriptor_cpu_uav, texture_base >> 12,
|
||||
descriptors[0].first, texture_base >> 12,
|
||||
((texture_base + texture_size - 1) >> 12) - (texture_base >> 12) + 1);
|
||||
} else {
|
||||
resolve_tile_constants.guest_base = texture_base;
|
||||
shared_memory_->WriteRawUAVDescriptor(descriptor_cpu_uav);
|
||||
shared_memory_->WriteRawUAVDescriptor(descriptors[0].first);
|
||||
}
|
||||
}
|
||||
command_list->D3DSetComputeRootDescriptorTable(1, descriptor_gpu_start);
|
||||
command_list->D3DSetComputeRootDescriptorTable(1, descriptors[0].second);
|
||||
|
||||
resolve_tile_constants.info = uint32_t(endian) | (uint32_t(format) << 3) |
|
||||
(resolution_scale_log2 << 9) |
|
||||
((texture_pitch >> 5) << 10) |
|
||||
(is_3d ? ((texture_height >> 5) << 19) : 0);
|
||||
resolve_tile_constants.offset = offset_x | (offset_y << 5) | (offset_z << 10);
|
||||
resolve_tile_constants.size = resolve_width | (resolve_height << 16);
|
||||
resolve_tile_constants.host_base = uint32_t(footprint.Offset);
|
||||
resolve_tile_constants.host_pitch = uint32_t(footprint.Footprint.RowPitch);
|
||||
command_list->D3DSetComputeRoot32BitConstants(
|
||||
0, sizeof(resolve_tile_constants) / sizeof(uint32_t),
|
||||
&resolve_tile_constants, 0);
|
||||
|
||||
command_processor_->SetComputePipeline(
|
||||
resolve_tile_pipelines_[uint32_t(resolve_tile_mode)]);
|
||||
// Each group processes 32x32 texels after resolution scaling has been
|
||||
@@ -2339,8 +2332,6 @@ TextureCache::Texture* TextureCache::FindOrCreateTexture(TextureKey key) {
|
||||
}
|
||||
texture->base_watch_handle = nullptr;
|
||||
texture->mip_watch_handle = nullptr;
|
||||
texture->cached_srv_descriptor_swizzle =
|
||||
Texture::kCachedSRVDescriptorSwizzleMissing;
|
||||
textures_.insert(std::make_pair(map_key, texture));
|
||||
COUNT_profile_set("gpu/texture_cache/textures", textures_.size());
|
||||
textures_total_size_ += texture->resource_size;
|
||||
@@ -2364,8 +2355,8 @@ bool TextureCache::LoadTextureData(Texture* texture) {
|
||||
}
|
||||
|
||||
auto command_list = command_processor_->GetDeferredCommandList();
|
||||
auto provider = command_processor_->GetD3D12Context()->GetD3D12Provider();
|
||||
auto device = provider->GetDevice();
|
||||
auto device =
|
||||
command_processor_->GetD3D12Context()->GetD3D12Provider()->GetDevice();
|
||||
|
||||
// Get the pipeline.
|
||||
LoadMode load_mode = GetLoadMode(texture->key);
|
||||
@@ -2453,16 +2444,19 @@ bool TextureCache::LoadTextureData(Texture* texture) {
|
||||
// descriptors for base and mips.
|
||||
bool separate_base_and_mips_descriptors =
|
||||
scaled_resolve && mip_first == 0 && mip_last != 0;
|
||||
// TODO(Triang3l): Use precreated bindless descriptors here after overall
|
||||
// cleanup/optimization involving typed buffers.
|
||||
uint32_t descriptor_count = separate_base_and_mips_descriptors ? 4 : 2;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE descriptor_cpu_start;
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE descriptor_gpu_start;
|
||||
if (command_processor_->RequestViewDescriptors(
|
||||
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid, descriptor_count,
|
||||
descriptor_count, descriptor_cpu_start, descriptor_gpu_start) ==
|
||||
ui::d3d12::DescriptorHeapPool::kHeapIndexInvalid) {
|
||||
command_processor_->ReleaseScratchGPUBuffer(copy_buffer, copy_buffer_state);
|
||||
ui::d3d12::util::DescriptorCPUGPUHandlePair descriptors[4];
|
||||
if (!command_processor_->RequestOneUseSingleViewDescriptors(descriptor_count,
|
||||
descriptors)) {
|
||||
return false;
|
||||
}
|
||||
// Create two destination descriptors since the table has both.
|
||||
for (uint32_t i = 0; i < descriptor_count; i += 2) {
|
||||
ui::d3d12::util::CreateRawBufferUAV(device, descriptors[i].first,
|
||||
copy_buffer, uint32_t(host_slice_size));
|
||||
}
|
||||
if (scaled_resolve) {
|
||||
// TODO(Triang3l): Allow partial invalidation of scaled textures - send a
|
||||
// part of scaled_resolve_pages_ to the shader and choose the source
|
||||
@@ -2470,35 +2464,28 @@ bool TextureCache::LoadTextureData(Texture* texture) {
|
||||
// it's not, duplicate the texels from the unscaled version - will be
|
||||
// blocky with filtering, but better than nothing.
|
||||
UseScaledResolveBufferForReading();
|
||||
uint32_t srv_descriptor_offset = 0;
|
||||
uint32_t source_descriptor_index = 1;
|
||||
if (mip_first == 0) {
|
||||
CreateScaledResolveBufferRawSRV(
|
||||
provider->OffsetViewDescriptor(descriptor_cpu_start,
|
||||
srv_descriptor_offset),
|
||||
texture->key.base_page, (texture->base_size + 0xFFF) >> 12);
|
||||
srv_descriptor_offset += 2;
|
||||
descriptors[source_descriptor_index].first, texture->key.base_page,
|
||||
(texture->base_size + 0xFFF) >> 12);
|
||||
source_descriptor_index += 2;
|
||||
}
|
||||
if (mip_last != 0) {
|
||||
CreateScaledResolveBufferRawSRV(
|
||||
provider->OffsetViewDescriptor(descriptor_cpu_start,
|
||||
srv_descriptor_offset),
|
||||
texture->key.mip_page, (texture->mip_size + 0xFFF) >> 12);
|
||||
descriptors[source_descriptor_index].first, texture->key.mip_page,
|
||||
(texture->mip_size + 0xFFF) >> 12);
|
||||
}
|
||||
} else {
|
||||
shared_memory_->UseForReading();
|
||||
shared_memory_->WriteRawSRVDescriptor(descriptor_cpu_start);
|
||||
}
|
||||
// Create two destination descriptors since the table has both.
|
||||
for (uint32_t i = 1; i < descriptor_count; i += 2) {
|
||||
ui::d3d12::util::CreateRawBufferUAV(
|
||||
device, provider->OffsetViewDescriptor(descriptor_cpu_start, i),
|
||||
copy_buffer, uint32_t(host_slice_size));
|
||||
shared_memory_->WriteRawSRVDescriptor(descriptors[1].first);
|
||||
}
|
||||
command_processor_->SetComputePipeline(pipeline);
|
||||
command_list->D3DSetComputeRootSignature(load_root_signature_);
|
||||
if (!separate_base_and_mips_descriptors) {
|
||||
// Will be bound later.
|
||||
command_list->D3DSetComputeRootDescriptorTable(1, descriptor_gpu_start);
|
||||
// Will be bound later if separate base and mip descriptors.
|
||||
command_list->D3DSetComputeRootDescriptorTable(2, descriptors[1].second);
|
||||
command_list->D3DSetComputeRootDescriptorTable(1, descriptors[0].second);
|
||||
}
|
||||
|
||||
// Submit commands.
|
||||
@@ -2575,14 +2562,11 @@ bool TextureCache::LoadTextureData(Texture* texture) {
|
||||
}
|
||||
std::memcpy(cbuffer_mapping, &load_constants, sizeof(load_constants));
|
||||
command_list->D3DSetComputeRootConstantBufferView(0, cbuffer_gpu_address);
|
||||
if (separate_base_and_mips_descriptors) {
|
||||
if (j == 0) {
|
||||
command_list->D3DSetComputeRootDescriptorTable(1,
|
||||
descriptor_gpu_start);
|
||||
} else if (j == 1) {
|
||||
command_list->D3DSetComputeRootDescriptorTable(
|
||||
1, provider->OffsetViewDescriptor(descriptor_gpu_start, 2));
|
||||
}
|
||||
if (separate_base_and_mips_descriptors && j <= 1) {
|
||||
command_list->D3DSetComputeRootDescriptorTable(
|
||||
2, descriptors[j * 2 + 1].second);
|
||||
command_list->D3DSetComputeRootDescriptorTable(
|
||||
1, descriptors[j * 2].second);
|
||||
}
|
||||
command_processor_->SubmitBarriers();
|
||||
// Each thread group processes 32x32x1 blocks after resolution scaling has
|
||||
@@ -2642,6 +2626,138 @@ bool TextureCache::LoadTextureData(Texture* texture) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t TextureCache::FindOrCreateTextureDescriptor(Texture& texture,
|
||||
bool is_signed,
|
||||
uint32_t host_swizzle) {
|
||||
uint32_t descriptor_key = uint32_t(is_signed) | (host_swizzle << 1);
|
||||
|
||||
// Try to find an existing descriptor.
|
||||
auto it = texture.srv_descriptors.find(descriptor_key);
|
||||
if (it != texture.srv_descriptors.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Create a new bindless or cached descriptor if supported.
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC desc;
|
||||
|
||||
TextureFormat format = texture.key.format;
|
||||
if (IsSignedVersionSeparate(format) &&
|
||||
texture.key.signed_separate != uint32_t(is_signed)) {
|
||||
// Not the version with the needed signedness.
|
||||
return UINT32_MAX;
|
||||
}
|
||||
if (is_signed) {
|
||||
// Not supporting signed compressed textures - hopefully DXN and DXT5A are
|
||||
// not used as signed.
|
||||
desc.Format = host_formats_[uint32_t(format)].dxgi_format_snorm;
|
||||
} else {
|
||||
desc.Format = GetDXGIUnormFormat(texture.key);
|
||||
}
|
||||
if (desc.Format == DXGI_FORMAT_UNKNOWN) {
|
||||
unsupported_format_features_used_[uint32_t(format)] |=
|
||||
is_signed ? kUnsupportedSnormBit : kUnsupportedUnormBit;
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
uint32_t mip_levels = texture.key.mip_max_level + 1;
|
||||
switch (texture.key.dimension) {
|
||||
case Dimension::k1D:
|
||||
case Dimension::k2D:
|
||||
desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
|
||||
desc.Texture2DArray.MostDetailedMip = 0;
|
||||
desc.Texture2DArray.MipLevels = mip_levels;
|
||||
desc.Texture2DArray.FirstArraySlice = 0;
|
||||
desc.Texture2DArray.ArraySize = texture.key.depth;
|
||||
desc.Texture2DArray.PlaneSlice = 0;
|
||||
desc.Texture2DArray.ResourceMinLODClamp = 0.0f;
|
||||
break;
|
||||
case Dimension::k3D:
|
||||
desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
|
||||
desc.Texture3D.MostDetailedMip = 0;
|
||||
desc.Texture3D.MipLevels = mip_levels;
|
||||
desc.Texture3D.ResourceMinLODClamp = 0.0f;
|
||||
break;
|
||||
case Dimension::kCube:
|
||||
desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
|
||||
desc.TextureCube.MostDetailedMip = 0;
|
||||
desc.TextureCube.MipLevels = mip_levels;
|
||||
desc.TextureCube.ResourceMinLODClamp = 0.0f;
|
||||
break;
|
||||
default:
|
||||
assert_unhandled_case(texture.key.dimension);
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
desc.Shader4ComponentMapping =
|
||||
host_swizzle |
|
||||
D3D12_SHADER_COMPONENT_MAPPING_ALWAYS_SET_BIT_AVOIDING_ZEROMEM_MISTAKES;
|
||||
|
||||
auto device =
|
||||
command_processor_->GetD3D12Context()->GetD3D12Provider()->GetDevice();
|
||||
uint32_t descriptor_index;
|
||||
if (bindless_resources_used_) {
|
||||
descriptor_index =
|
||||
command_processor_->RequestPersistentViewBindlessDescriptor();
|
||||
if (descriptor_index == UINT32_MAX) {
|
||||
XELOGE(
|
||||
"Failed to create a texture descriptor - no free bindless view "
|
||||
"descriptors");
|
||||
return UINT32_MAX;
|
||||
}
|
||||
} else {
|
||||
if (!srv_descriptor_cache_free_.empty()) {
|
||||
descriptor_index = srv_descriptor_cache_free_.back();
|
||||
srv_descriptor_cache_free_.pop_back();
|
||||
} else {
|
||||
// Allocated + 1 (including the descriptor that is being added), rounded
|
||||
// up to SRVDescriptorCachePage::kHeapSize, (allocated + 1 + size - 1).
|
||||
uint32_t cache_pages_needed = (srv_descriptor_cache_allocated_ +
|
||||
SRVDescriptorCachePage::kHeapSize) /
|
||||
SRVDescriptorCachePage::kHeapSize;
|
||||
if (srv_descriptor_cache_.size() < cache_pages_needed) {
|
||||
D3D12_DESCRIPTOR_HEAP_DESC cache_heap_desc;
|
||||
cache_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
|
||||
cache_heap_desc.NumDescriptors = SRVDescriptorCachePage::kHeapSize;
|
||||
cache_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
|
||||
cache_heap_desc.NodeMask = 0;
|
||||
while (srv_descriptor_cache_.size() < cache_pages_needed) {
|
||||
SRVDescriptorCachePage cache_page;
|
||||
if (FAILED(device->CreateDescriptorHeap(
|
||||
&cache_heap_desc, IID_PPV_ARGS(&cache_page.heap)))) {
|
||||
XELOGE(
|
||||
"Failed to create a texture descriptor - couldn't create a "
|
||||
"descriptor cache heap");
|
||||
return UINT32_MAX;
|
||||
}
|
||||
cache_page.heap_start =
|
||||
cache_page.heap->GetCPUDescriptorHandleForHeapStart();
|
||||
srv_descriptor_cache_.push_back(cache_page);
|
||||
}
|
||||
}
|
||||
descriptor_index = srv_descriptor_cache_allocated_++;
|
||||
}
|
||||
}
|
||||
device->CreateShaderResourceView(
|
||||
texture.resource, &desc, GetTextureDescriptorCPUHandle(descriptor_index));
|
||||
texture.srv_descriptors.insert({descriptor_key, descriptor_index});
|
||||
return descriptor_index;
|
||||
}
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE TextureCache::GetTextureDescriptorCPUHandle(
|
||||
uint32_t descriptor_index) const {
|
||||
auto provider = command_processor_->GetD3D12Context()->GetD3D12Provider();
|
||||
if (bindless_resources_used_) {
|
||||
return provider->OffsetViewDescriptor(
|
||||
command_processor_->GetViewBindlessHeapCPUStart(), descriptor_index);
|
||||
}
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE heap_start =
|
||||
srv_descriptor_cache_[descriptor_index /
|
||||
SRVDescriptorCachePage::kHeapSize]
|
||||
.heap_start;
|
||||
uint32_t heap_offset = descriptor_index % SRVDescriptorCachePage::kHeapSize;
|
||||
return provider->OffsetViewDescriptor(heap_start, heap_offset);
|
||||
}
|
||||
|
||||
void TextureCache::MarkTextureUsed(Texture* texture) {
|
||||
uint64_t current_frame = command_processor_->GetCurrentFrame();
|
||||
// This is called very frequently, don't relink unless needed for caching.
|
||||
@@ -2687,8 +2803,10 @@ void TextureCache::WatchCallback(Texture* texture, bool is_mip) {
|
||||
}
|
||||
|
||||
void TextureCache::ClearBindings() {
|
||||
std::memset(texture_bindings_, 0, sizeof(texture_bindings_));
|
||||
texture_keys_in_sync_ = 0;
|
||||
for (size_t i = 0; i < xe::countof(texture_bindings_); ++i) {
|
||||
texture_bindings_[i].Clear();
|
||||
}
|
||||
texture_bindings_in_sync_ = 0;
|
||||
// Already reset everything.
|
||||
texture_invalidated_.store(false, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user