[D3D12] Fix 4D5307DF fur textures
- Fixes issue https://github.com/xenia-canary/game-compatibility/issues/6 - Implements a copy texture logic
This commit is contained in:
@@ -582,21 +582,42 @@ void D3D12TextureCache::WriteActiveTextureBindfulSRV(
|
||||
const TextureBinding* binding = GetValidTextureBinding(fetch_constant_index);
|
||||
if (binding && AreDimensionsCompatible(host_shader_binding.dimension,
|
||||
binding->key.dimension)) {
|
||||
bool force_special_view =
|
||||
(host_shader_binding.dimension == xenos::FetchOpDimension::k2D &&
|
||||
binding->key.dimension == xenos::DataDimension::k3D);
|
||||
|
||||
const D3D12TextureBinding& d3d12_binding =
|
||||
d3d12_texture_bindings_[fetch_constant_index];
|
||||
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)) {
|
||||
descriptor_index = d3d12_binding.descriptor_index_signed;
|
||||
texture = IsSignedVersionSeparateForFormat(binding->key)
|
||||
? binding->texture_signed
|
||||
: binding->texture;
|
||||
|
||||
if (force_special_view && texture) {
|
||||
// Request the 2D view of the 3D texture on demand
|
||||
descriptor_index = FindOrCreateTextureDescriptor(
|
||||
*static_cast<D3D12Texture*>(texture),
|
||||
xenos::DataDimension::k2DOrStacked, true, binding->host_swizzle);
|
||||
} else {
|
||||
descriptor_index = d3d12_binding.descriptor_index_signed;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (texture_util::IsAnySignNotSigned(binding->swizzled_signs)) {
|
||||
descriptor_index = d3d12_binding.descriptor_index;
|
||||
texture = binding->texture;
|
||||
|
||||
if (force_special_view && texture) {
|
||||
// Request the 2D view of the 3D texture on demand
|
||||
descriptor_index = FindOrCreateTextureDescriptor(
|
||||
*static_cast<D3D12Texture*>(texture),
|
||||
xenos::DataDimension::k2DOrStacked, false, binding->host_swizzle);
|
||||
} else {
|
||||
descriptor_index = d3d12_binding.descriptor_index;
|
||||
texture = binding->texture;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -646,12 +667,44 @@ uint32_t D3D12TextureCache::GetActiveTextureBindlessSRVIndex(
|
||||
const TextureBinding* binding = GetValidTextureBinding(fetch_constant_index);
|
||||
if (binding && AreDimensionsCompatible(host_shader_binding.dimension,
|
||||
binding->key.dimension)) {
|
||||
// 3D Texture on 2D Request
|
||||
bool force_special_view =
|
||||
(host_shader_binding.dimension == xenos::FetchOpDimension::k2D &&
|
||||
binding->key.dimension == xenos::DataDimension::k3D);
|
||||
|
||||
const D3D12TextureBinding& d3d12_binding =
|
||||
d3d12_texture_bindings_[fetch_constant_index];
|
||||
descriptor_index = host_shader_binding.is_signed
|
||||
? d3d12_binding.descriptor_index_signed
|
||||
: d3d12_binding.descriptor_index;
|
||||
|
||||
// Helper lambda to get standard index
|
||||
uint32_t standard_index = host_shader_binding.is_signed
|
||||
? d3d12_binding.descriptor_index_signed
|
||||
: d3d12_binding.descriptor_index;
|
||||
|
||||
if (force_special_view) {
|
||||
// Determine which texture object to use
|
||||
Texture* texture = nullptr;
|
||||
if (host_shader_binding.is_signed) {
|
||||
texture = IsSignedVersionSeparateForFormat(binding->key)
|
||||
? binding->texture_signed
|
||||
: binding->texture;
|
||||
if (texture) {
|
||||
descriptor_index = FindOrCreateTextureDescriptor(
|
||||
*static_cast<D3D12Texture*>(texture),
|
||||
xenos::DataDimension::k2DOrStacked, true, binding->host_swizzle);
|
||||
}
|
||||
} else {
|
||||
texture = binding->texture;
|
||||
if (texture) {
|
||||
descriptor_index = FindOrCreateTextureDescriptor(
|
||||
*static_cast<D3D12Texture*>(texture),
|
||||
xenos::DataDimension::k2DOrStacked, false, binding->host_swizzle);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
descriptor_index = standard_index;
|
||||
}
|
||||
}
|
||||
|
||||
if (descriptor_index == UINT32_MAX) {
|
||||
switch (host_shader_binding.dimension) {
|
||||
case xenos::FetchOpDimension::k3DOrStacked:
|
||||
@@ -1756,36 +1809,117 @@ void D3D12TextureCache::UpdateTextureBindingsImpl(
|
||||
if (binding->texture &&
|
||||
texture_util::IsAnySignNotSigned(binding->swizzled_signs)) {
|
||||
d3d12_binding.descriptor_index = FindOrCreateTextureDescriptor(
|
||||
*static_cast<D3D12Texture*>(binding->texture), false,
|
||||
binding->host_swizzle);
|
||||
*static_cast<D3D12Texture*>(binding->texture),
|
||||
binding->key.dimension, false, binding->host_swizzle);
|
||||
}
|
||||
if (binding->texture_signed &&
|
||||
texture_util::IsAnySignSigned(binding->swizzled_signs)) {
|
||||
d3d12_binding.descriptor_index_signed = FindOrCreateTextureDescriptor(
|
||||
*static_cast<D3D12Texture*>(binding->texture_signed), true,
|
||||
binding->host_swizzle);
|
||||
*static_cast<D3D12Texture*>(binding->texture_signed),
|
||||
binding->key.dimension, true, binding->host_swizzle);
|
||||
}
|
||||
} else {
|
||||
D3D12Texture* texture = static_cast<D3D12Texture*>(binding->texture);
|
||||
if (texture) {
|
||||
if (texture_util::IsAnySignNotSigned(binding->swizzled_signs)) {
|
||||
d3d12_binding.descriptor_index = FindOrCreateTextureDescriptor(
|
||||
*texture, false, binding->host_swizzle);
|
||||
*texture, binding->key.dimension, false, binding->host_swizzle);
|
||||
}
|
||||
if (texture_util::IsAnySignSigned(binding->swizzled_signs)) {
|
||||
d3d12_binding.descriptor_index_signed = FindOrCreateTextureDescriptor(
|
||||
*texture, true, binding->host_swizzle);
|
||||
*texture, binding->key.dimension, true, binding->host_swizzle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ID3D12Resource* D3D12TextureCache::D3D12Texture::GetOrCreate3DAs2DResource(
|
||||
D3D12_RESOURCE_STATES end_state) {
|
||||
auto& d3d12_cache = static_cast<D3D12TextureCache&>(texture_cache());
|
||||
|
||||
// 1. If it already exists, just transition and return it.
|
||||
if (resource_3d_as_2d_) {
|
||||
if (resource_3d_as_2d_state_ != end_state) {
|
||||
d3d12_cache.command_processor_.PushTransitionBarrier(
|
||||
resource_3d_as_2d_.Get(), resource_3d_as_2d_state_, end_state);
|
||||
resource_3d_as_2d_state_ = end_state;
|
||||
}
|
||||
return resource_3d_as_2d_.Get();
|
||||
}
|
||||
|
||||
// 2. Create the 2D Alias Resource.
|
||||
D3D12_RESOURCE_DESC source_desc = resource_->GetDesc();
|
||||
|
||||
D3D12_RESOURCE_DESC desc = source_desc;
|
||||
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
|
||||
desc.DepthOrArraySize = 1;
|
||||
desc.MipLevels = 1;
|
||||
|
||||
const ui::d3d12::D3D12Provider& provider =
|
||||
d3d12_cache.command_processor_.GetD3D12Provider();
|
||||
ID3D12Device* device = provider.GetDevice();
|
||||
|
||||
if (FAILED(device->CreateCommittedResource(
|
||||
&ui::d3d12::util::kHeapPropertiesDefault,
|
||||
provider.GetHeapFlagCreateNotZeroed(), &desc,
|
||||
D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
|
||||
IID_PPV_ARGS(&resource_3d_as_2d_)))) {
|
||||
XELOGE("D3D12Texture: Failed to create 3D-as-2D alias resource");
|
||||
return nullptr;
|
||||
}
|
||||
resource_3d_as_2d_state_ = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
|
||||
// 3. Perform the Copy (Slice 0 of 3D -> 2D).
|
||||
// Transition MAIN 3D resource to COPY_SOURCE.
|
||||
D3D12_RESOURCE_STATES old_main_state =
|
||||
SetResourceState(D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||||
d3d12_cache.command_processor_.PushTransitionBarrier(
|
||||
resource(), old_main_state, D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||||
|
||||
auto& command_list = d3d12_cache.command_processor_.GetDeferredCommandList();
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION dest_loc = {};
|
||||
dest_loc.pResource = resource_3d_as_2d_.Get();
|
||||
dest_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||
dest_loc.SubresourceIndex = 0;
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION src_loc = {};
|
||||
src_loc.pResource = resource();
|
||||
src_loc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||
src_loc.SubresourceIndex = 0;
|
||||
|
||||
// Define the copy box to select ONLY Slice 0
|
||||
D3D12_BOX src_box;
|
||||
src_box.left = 0;
|
||||
src_box.top = 0;
|
||||
src_box.front = 0;
|
||||
src_box.right = static_cast<UINT>(source_desc.Width);
|
||||
src_box.bottom = source_desc.Height;
|
||||
src_box.back = 1; // CRITICAL: Only copy 1 depth slice!
|
||||
|
||||
command_list.D3DCopyTextureRegion(&dest_loc, 0, 0, 0, &src_loc, &src_box);
|
||||
|
||||
// 4. Restore States.
|
||||
d3d12_cache.command_processor_.PushTransitionBarrier(
|
||||
resource(), D3D12_RESOURCE_STATE_COPY_SOURCE, old_main_state);
|
||||
SetResourceState(old_main_state);
|
||||
|
||||
d3d12_cache.command_processor_.PushTransitionBarrier(
|
||||
resource_3d_as_2d_.Get(), D3D12_RESOURCE_STATE_COPY_DEST, end_state);
|
||||
resource_3d_as_2d_state_ = end_state;
|
||||
|
||||
return resource_3d_as_2d_.Get();
|
||||
}
|
||||
|
||||
uint32_t D3D12TextureCache::FindOrCreateTextureDescriptor(
|
||||
D3D12Texture& texture, bool is_signed, uint32_t host_swizzle) {
|
||||
D3D12Texture& texture, xenos::DataDimension dimension, bool is_signed,
|
||||
uint32_t host_swizzle) {
|
||||
D3D12Texture::SRVDescriptorKey descriptor_key;
|
||||
descriptor_key.key = 0;
|
||||
descriptor_key.is_signed = uint32_t(is_signed);
|
||||
descriptor_key.host_swizzle = host_swizzle;
|
||||
descriptor_key.dimension = uint32_t(dimension);
|
||||
|
||||
// Try to find an existing descriptor.
|
||||
uint32_t existing_descriptor_index =
|
||||
@@ -1797,7 +1931,7 @@ uint32_t D3D12TextureCache::FindOrCreateTextureDescriptor(
|
||||
TextureKey texture_key = texture.key();
|
||||
|
||||
// Create a new bindless or cached descriptor if supported.
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC desc;
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC desc = {}; // Zero out struct
|
||||
|
||||
if (IsSignedVersionSeparateForFormat(texture_key) &&
|
||||
texture_key.signed_separate != uint32_t(is_signed)) {
|
||||
@@ -1819,34 +1953,44 @@ uint32_t D3D12TextureCache::FindOrCreateTextureDescriptor(
|
||||
}
|
||||
|
||||
uint32_t mip_levels = texture_key.mip_max_level + 1;
|
||||
switch (texture_key.dimension) {
|
||||
case xenos::DataDimension::k1D:
|
||||
case xenos::DataDimension::k2DOrStacked:
|
||||
desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
|
||||
ID3D12Resource* resource_for_view = texture.resource();
|
||||
|
||||
if (dimension == xenos::DataDimension::k3D) {
|
||||
desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
|
||||
desc.Texture3D.MostDetailedMip = 0;
|
||||
desc.Texture3D.MipLevels = mip_levels;
|
||||
desc.Texture3D.ResourceMinLODClamp = 0.0f;
|
||||
} else if (dimension == xenos::DataDimension::kCube) {
|
||||
desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
|
||||
desc.TextureCube.MostDetailedMip = 0;
|
||||
desc.TextureCube.MipLevels = mip_levels;
|
||||
desc.TextureCube.ResourceMinLODClamp = 0.0f;
|
||||
} else {
|
||||
desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
|
||||
if (texture_key.dimension == xenos::DataDimension::k3D) {
|
||||
resource_for_view = texture.GetOrCreate3DAs2DResource(
|
||||
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
if (!resource_for_view) {
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
// Configure SRV for the new 2D resource
|
||||
desc.Texture2DArray.MostDetailedMip = 0;
|
||||
desc.Texture2DArray.MipLevels = 1;
|
||||
desc.Texture2DArray.FirstArraySlice = 0;
|
||||
desc.Texture2DArray.ArraySize = 1;
|
||||
desc.Texture2DArray.PlaneSlice = 0;
|
||||
desc.Texture2DArray.ResourceMinLODClamp = 0.0f;
|
||||
} else {
|
||||
// Standard behavior
|
||||
desc.Texture2DArray.MostDetailedMip = 0;
|
||||
desc.Texture2DArray.MipLevels = mip_levels;
|
||||
desc.Texture2DArray.FirstArraySlice = 0;
|
||||
desc.Texture2DArray.ArraySize = texture_key.GetDepthOrArraySize();
|
||||
desc.Texture2DArray.PlaneSlice = 0;
|
||||
desc.Texture2DArray.ResourceMinLODClamp = 0.0f;
|
||||
break;
|
||||
case xenos::DataDimension::k3D:
|
||||
desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
|
||||
desc.Texture3D.MostDetailedMip = 0;
|
||||
desc.Texture3D.MipLevels = mip_levels;
|
||||
desc.Texture3D.ResourceMinLODClamp = 0.0f;
|
||||
break;
|
||||
case xenos::DataDimension::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;
|
||||
@@ -1894,7 +2038,7 @@ uint32_t D3D12TextureCache::FindOrCreateTextureDescriptor(
|
||||
}
|
||||
}
|
||||
device->CreateShaderResourceView(
|
||||
texture.resource(), &desc,
|
||||
resource_for_view, &desc,
|
||||
GetTextureDescriptorCPUHandle(descriptor_index));
|
||||
texture.AddSRVDescriptorIndex(descriptor_key, descriptor_index);
|
||||
return descriptor_index;
|
||||
|
||||
@@ -551,6 +551,7 @@ class D3D12TextureCache final : public TextureCache {
|
||||
struct {
|
||||
uint32_t is_signed : 1;
|
||||
uint32_t host_swizzle : 12;
|
||||
uint32_t dimension : 2;
|
||||
};
|
||||
|
||||
SRVDescriptorKey() : key(0) { static_assert_size(*this, sizeof(key)); }
|
||||
@@ -568,6 +569,8 @@ class D3D12TextureCache final : public TextureCache {
|
||||
}
|
||||
};
|
||||
|
||||
ID3D12Resource* GetOrCreate3DAs2DResource(D3D12_RESOURCE_STATES end_state);
|
||||
|
||||
explicit D3D12Texture(D3D12TextureCache& texture_cache,
|
||||
const TextureKey& key, ID3D12Resource* resource,
|
||||
D3D12_RESOURCE_STATES resource_state);
|
||||
@@ -595,6 +598,10 @@ class D3D12TextureCache final : public TextureCache {
|
||||
Microsoft::WRL::ComPtr<ID3D12Resource> resource_;
|
||||
D3D12_RESOURCE_STATES resource_state_;
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3D12Resource> resource_3d_as_2d_;
|
||||
D3D12_RESOURCE_STATES resource_3d_as_2d_state_ =
|
||||
D3D12_RESOURCE_STATE_COMMON;
|
||||
|
||||
// For bindful - indices in the non-shader-visible descriptor cache for
|
||||
// copying to the shader-visible heap (much faster than recreating, which,
|
||||
// according to profiling, was often a bottleneck in many games).
|
||||
@@ -717,7 +724,8 @@ class D3D12TextureCache final : public TextureCache {
|
||||
case xenos::FetchOpDimension::k1D:
|
||||
case xenos::FetchOpDimension::k2D:
|
||||
return resource_dimension == xenos::DataDimension::k1D ||
|
||||
resource_dimension == xenos::DataDimension::k2DOrStacked;
|
||||
resource_dimension == xenos::DataDimension::k2DOrStacked ||
|
||||
resource_dimension == xenos::DataDimension::k3D;
|
||||
case xenos::FetchOpDimension::k3DOrStacked:
|
||||
return resource_dimension == xenos::DataDimension::k3D;
|
||||
case xenos::FetchOpDimension::kCube:
|
||||
@@ -730,8 +738,9 @@ class D3D12TextureCache final : public TextureCache {
|
||||
// Returns the index of an existing of a newly created non-shader-visible
|
||||
// cached (for bindful) or a shader-visible global (for bindless) descriptor,
|
||||
// or UINT32_MAX if failed to create.
|
||||
uint32_t FindOrCreateTextureDescriptor(D3D12Texture& texture, bool is_signed,
|
||||
uint32_t host_swizzle);
|
||||
uint32_t FindOrCreateTextureDescriptor(D3D12Texture& texture,
|
||||
xenos::DataDimension dimension,
|
||||
bool is_signed, uint32_t host_swizzle);
|
||||
void ReleaseTextureDescriptor(uint32_t descriptor_index);
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE GetTextureDescriptorCPUHandle(
|
||||
uint32_t descriptor_index) const;
|
||||
|
||||
Reference in New Issue
Block a user