[D3D12] Fix 8192 texture size storage
This commit is contained in:
parent
d813f7435b
commit
9606ff2a31
|
@ -1263,7 +1263,7 @@ void TextureCache::RequestTextures(uint32_t used_texture_mask) {
|
|||
BindingInfoFromFetchConstant(fetch, binding.key, &binding.host_swizzle,
|
||||
&binding.swizzled_signs);
|
||||
texture_bindings_in_sync_ |= index_bit;
|
||||
if (binding.key.IsInvalid()) {
|
||||
if (!binding.key.is_valid) {
|
||||
binding.texture = nullptr;
|
||||
binding.texture_signed = nullptr;
|
||||
binding.descriptor_index = UINT32_MAX;
|
||||
|
@ -1425,7 +1425,7 @@ void TextureCache::WriteActiveTextureBindfulSRV(
|
|||
texture_bindings_[host_shader_binding.fetch_constant];
|
||||
uint32_t descriptor_index = UINT32_MAX;
|
||||
Texture* texture = nullptr;
|
||||
if (!binding.key.IsInvalid() &&
|
||||
if (binding.key.is_valid &&
|
||||
AreDimensionsCompatible(host_shader_binding.dimension,
|
||||
binding.key.dimension)) {
|
||||
if (host_shader_binding.is_signed) {
|
||||
|
@ -1487,7 +1487,7 @@ uint32_t TextureCache::GetActiveTextureBindlessSRVIndex(
|
|||
uint32_t descriptor_index = UINT32_MAX;
|
||||
const TextureBinding& binding =
|
||||
texture_bindings_[host_shader_binding.fetch_constant];
|
||||
if (!binding.key.IsInvalid() &&
|
||||
if (binding.key.is_valid &&
|
||||
AreDimensionsCompatible(host_shader_binding.dimension,
|
||||
binding.key.dimension)) {
|
||||
descriptor_index = host_shader_binding.is_signed
|
||||
|
@ -2026,7 +2026,7 @@ TextureCache::LoadMode TextureCache::GetLoadMode(TextureKey key) {
|
|||
if (key.signed_separate) {
|
||||
return host_format.load_mode_snorm;
|
||||
}
|
||||
if (IsDecompressionNeeded(key.format, key.width, key.height)) {
|
||||
if (IsDecompressionNeeded(key.format, key.GetWidth(), key.GetHeight())) {
|
||||
return host_format.decompress_mode;
|
||||
}
|
||||
return host_format.load_mode;
|
||||
|
@ -2071,11 +2071,11 @@ void TextureCache::BindingInfoFromFetchConstant(
|
|||
return;
|
||||
}
|
||||
|
||||
uint32_t width, height, depth_or_faces;
|
||||
uint32_t width_minus_1, height_minus_1, depth_or_array_size_minus_1;
|
||||
uint32_t base_page, mip_page, mip_max_level;
|
||||
texture_util::GetSubresourcesFromFetchConstant(
|
||||
fetch, &width, &height, &depth_or_faces, &base_page, &mip_page, nullptr,
|
||||
&mip_max_level);
|
||||
fetch, &width_minus_1, &height_minus_1, &depth_or_array_size_minus_1,
|
||||
&base_page, &mip_page, nullptr, &mip_max_level);
|
||||
if (base_page == 0 && mip_page == 0) {
|
||||
// No texture data at all.
|
||||
return;
|
||||
|
@ -2083,11 +2083,11 @@ void TextureCache::BindingInfoFromFetchConstant(
|
|||
if (fetch.dimension == xenos::DataDimension::k1D) {
|
||||
bool is_invalid_1d = false;
|
||||
// TODO(Triang3l): Support long 1D textures.
|
||||
if (width > xenos::kTexture2DCubeMaxWidthHeight) {
|
||||
if (width_minus_1 >= xenos::kTexture2DCubeMaxWidthHeight) {
|
||||
XELOGE(
|
||||
"1D texture is too wide ({}) - ignoring! Report the game to Xenia "
|
||||
"developers",
|
||||
width);
|
||||
width_minus_1 + 1);
|
||||
is_invalid_1d = true;
|
||||
}
|
||||
assert_false(fetch.tiled);
|
||||
|
@ -2116,9 +2116,9 @@ void TextureCache::BindingInfoFromFetchConstant(
|
|||
key_out.base_page = base_page;
|
||||
key_out.mip_page = mip_page;
|
||||
key_out.dimension = fetch.dimension;
|
||||
key_out.width = width;
|
||||
key_out.height = height;
|
||||
key_out.depth = depth_or_faces;
|
||||
key_out.width_minus_1 = width_minus_1;
|
||||
key_out.height_minus_1 = height_minus_1;
|
||||
key_out.depth_or_array_size_minus_1 = depth_or_array_size_minus_1;
|
||||
key_out.pitch = fetch.pitch;
|
||||
key_out.mip_max_level = mip_max_level;
|
||||
key_out.tiled = fetch.tiled;
|
||||
|
@ -2126,6 +2126,8 @@ void TextureCache::BindingInfoFromFetchConstant(
|
|||
key_out.format = format;
|
||||
key_out.endianness = fetch.endianness;
|
||||
|
||||
key_out.is_valid = 1;
|
||||
|
||||
if (host_swizzle_out != nullptr) {
|
||||
uint32_t host_swizzle = 0;
|
||||
for (uint32_t i = 0; i < 4; ++i) {
|
||||
|
@ -2154,8 +2156,8 @@ void TextureCache::LogTextureKeyAction(TextureKey key, const char* action) {
|
|||
"{} {} {}{}x{}x{} {} {} texture with {} {}packed mip level{}, "
|
||||
"base at 0x{:08X} (pitch {}), mips at 0x{:08X}",
|
||||
action, key.tiled ? "tiled" : "linear",
|
||||
key.scaled_resolve ? "scaled " : "", key.width, key.height, key.depth,
|
||||
dimension_names_[uint32_t(key.dimension)],
|
||||
key.scaled_resolve ? "scaled " : "", key.GetWidth(), key.GetHeight(),
|
||||
key.GetDepthOrArraySize(), dimension_names_[uint32_t(key.dimension)],
|
||||
FormatInfo::Get(key.format)->name, key.mip_max_level + 1,
|
||||
key.packed_mips ? "" : "un", key.mip_max_level != 0 ? "s" : "",
|
||||
key.base_page << 12, key.pitch << 5, key.mip_page << 12);
|
||||
|
@ -2168,8 +2170,8 @@ void TextureCache::LogTextureAction(const Texture* texture,
|
|||
"base at 0x{:08X} (pitch {}, size 0x{:08X}), mips at 0x{:08X} (size "
|
||||
"0x{:08X})",
|
||||
action, texture->key.tiled ? "tiled" : "linear",
|
||||
texture->key.scaled_resolve ? "scaled " : "", texture->key.width,
|
||||
texture->key.height, texture->key.depth,
|
||||
texture->key.scaled_resolve ? "scaled " : "", texture->key.GetWidth(),
|
||||
texture->key.GetHeight(), texture->key.GetDepthOrArraySize(),
|
||||
dimension_names_[uint32_t(texture->key.dimension)],
|
||||
FormatInfo::Get(texture->key.format)->name,
|
||||
texture->key.mip_max_level + 1, texture->key.packed_mips ? "" : "un",
|
||||
|
@ -2186,9 +2188,9 @@ TextureCache::Texture* TextureCache::FindOrCreateTexture(TextureKey key) {
|
|||
load_pipelines_scaled_[uint32_t(load_mode)] != nullptr) {
|
||||
texture_util::TextureGuestLayout scaled_resolve_guest_layout =
|
||||
texture_util::GetGuestTextureLayout(
|
||||
key.dimension, key.pitch, key.width, key.height, key.depth,
|
||||
key.tiled, key.format, key.packed_mips, key.base_page != 0,
|
||||
key.mip_max_level);
|
||||
key.dimension, key.pitch, key.GetWidth(), key.GetHeight(),
|
||||
key.GetDepthOrArraySize(), key.tiled, key.format, key.packed_mips,
|
||||
key.base_page != 0, key.mip_max_level);
|
||||
if ((scaled_resolve_guest_layout.base.level_data_extent_bytes &&
|
||||
IsRangeScaledResolved(
|
||||
key.base_page << 12,
|
||||
|
@ -2201,8 +2203,8 @@ TextureCache::Texture* TextureCache::FindOrCreateTexture(TextureKey key) {
|
|||
}
|
||||
}
|
||||
}
|
||||
uint32_t host_width = key.width;
|
||||
uint32_t host_height = key.height;
|
||||
uint32_t host_width = key.GetWidth();
|
||||
uint32_t host_height = key.GetHeight();
|
||||
if (key.scaled_resolve) {
|
||||
host_width *= draw_resolution_scale_x_;
|
||||
host_height *= draw_resolution_scale_y_;
|
||||
|
@ -2210,9 +2212,11 @@ TextureCache::Texture* TextureCache::FindOrCreateTexture(TextureKey key) {
|
|||
// With 3x resolution scaling, a 2D texture may become bigger than the
|
||||
// Direct3D 11 limit, and with 2x, a 3D one as well.
|
||||
uint32_t max_host_width_height = GetMaxHostTextureWidthHeight(key.dimension);
|
||||
uint32_t max_host_depth = GetMaxHostTextureDepth(key.dimension);
|
||||
uint32_t max_host_depth_or_array_size =
|
||||
GetMaxHostTextureDepthOrArraySize(key.dimension);
|
||||
if (host_width > max_host_width_height ||
|
||||
host_height > max_host_width_height || key.depth > max_host_depth) {
|
||||
host_height > max_host_width_height ||
|
||||
key.GetDepthOrArraySize() > max_host_depth_or_array_size) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -2242,7 +2246,7 @@ TextureCache::Texture* TextureCache::FindOrCreateTexture(TextureKey key) {
|
|||
desc.Alignment = 0;
|
||||
desc.Width = host_width;
|
||||
desc.Height = host_height;
|
||||
desc.DepthOrArraySize = key.depth;
|
||||
desc.DepthOrArraySize = key.GetDepthOrArraySize();
|
||||
desc.MipLevels = key.mip_max_level + 1;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.SampleDesc.Quality = 0;
|
||||
|
@ -2283,8 +2287,9 @@ TextureCache::Texture* TextureCache::FindOrCreateTexture(TextureKey key) {
|
|||
texture->base_resolved = key.scaled_resolve;
|
||||
texture->mips_resolved = key.scaled_resolve;
|
||||
texture->guest_layout = texture_util::GetGuestTextureLayout(
|
||||
key.dimension, key.pitch, key.width, key.height, key.depth, key.tiled,
|
||||
key.format, key.packed_mips, key.base_page != 0, key.mip_max_level);
|
||||
key.dimension, key.pitch, key.GetWidth(), key.GetHeight(),
|
||||
key.GetDepthOrArraySize(), key.tiled, key.format, key.packed_mips,
|
||||
key.base_page != 0, key.mip_max_level);
|
||||
// Never try to upload data that doesn't exist.
|
||||
texture->base_in_sync = !texture->guest_layout.base.level_data_extent_bytes;
|
||||
texture->mips_in_sync = !texture->guest_layout.mips_total_extent_bytes;
|
||||
|
@ -2368,9 +2373,9 @@ bool TextureCache::LoadTextureData(Texture* texture) {
|
|||
// Get the guest layout.
|
||||
xenos::DataDimension dimension = texture->key.dimension;
|
||||
bool is_3d = dimension == xenos::DataDimension::k3D;
|
||||
uint32_t width = texture->key.width;
|
||||
uint32_t height = texture->key.height;
|
||||
uint32_t depth_or_array_size = texture->key.depth;
|
||||
uint32_t width = texture->key.GetWidth();
|
||||
uint32_t height = texture->key.GetHeight();
|
||||
uint32_t depth_or_array_size = texture->key.GetDepthOrArraySize();
|
||||
uint32_t depth = is_3d ? depth_or_array_size : 1;
|
||||
uint32_t array_size = is_3d ? 1 : depth_or_array_size;
|
||||
xenos::TextureFormat guest_format = texture->key.format;
|
||||
|
@ -2845,7 +2850,7 @@ uint32_t TextureCache::FindOrCreateTextureDescriptor(Texture& texture,
|
|||
desc.Texture2DArray.MostDetailedMip = 0;
|
||||
desc.Texture2DArray.MipLevels = mip_levels;
|
||||
desc.Texture2DArray.FirstArraySlice = 0;
|
||||
desc.Texture2DArray.ArraySize = texture.key.depth;
|
||||
desc.Texture2DArray.ArraySize = texture.key.GetDepthOrArraySize();
|
||||
desc.Texture2DArray.PlaneSlice = 0;
|
||||
desc.Texture2DArray.ResourceMinLODClamp = 0.0f;
|
||||
break;
|
||||
|
|
|
@ -62,20 +62,24 @@ class D3D12CommandProcessor;
|
|||
// because textures are streamed this way anyway.
|
||||
class TextureCache {
|
||||
struct TextureKey {
|
||||
// Dimensions minus 1 are stored similarly to how they're stored in fetch
|
||||
// constants so fewer bits can be used, while the maximum size (8192 for 2D)
|
||||
// can still be encoded (a 8192x sky texture is used in 4D530910).
|
||||
|
||||
// Physical 4 KB page with the base mip level, disregarding A/C/E address
|
||||
// range prefix.
|
||||
uint32_t base_page : 17; // 17 total
|
||||
xenos::DataDimension dimension : 2; // 19
|
||||
uint32_t width : 13; // 32
|
||||
uint32_t width_minus_1 : 13; // 32
|
||||
|
||||
uint32_t height : 13; // 45
|
||||
uint32_t height_minus_1 : 13; // 45
|
||||
uint32_t tiled : 1; // 46
|
||||
uint32_t packed_mips : 1; // 47
|
||||
// Physical 4 KB page with mip 1 and smaller.
|
||||
uint32_t mip_page : 17; // 64
|
||||
|
||||
// Layers for stacked and 3D, 6 for cube, 1 for other dimensions.
|
||||
uint32_t depth : 10; // 74
|
||||
// (Layers for stacked and 3D, 6 for cube, 1 for other dimensions) - 1.
|
||||
uint32_t depth_or_array_size_minus_1 : 10; // 74
|
||||
uint32_t pitch : 9; // 83
|
||||
uint32_t mip_max_level : 4; // 87
|
||||
xenos::TextureFormat format : 6; // 93
|
||||
|
@ -86,6 +90,8 @@ class TextureCache {
|
|||
|
||||
// Whether this texture is a resolution-scaled resolve target.
|
||||
uint32_t scaled_resolve : 1; // 97
|
||||
// Least important in ==, so placed last.
|
||||
uint32_t is_valid : 1; // 98
|
||||
|
||||
TextureKey() { MakeInvalid(); }
|
||||
TextureKey(const TextureKey& key) {
|
||||
|
@ -95,16 +101,17 @@ class TextureCache {
|
|||
std::memcpy(this, &key, sizeof(*this));
|
||||
return *this;
|
||||
}
|
||||
bool IsInvalid() const {
|
||||
// Zero size is enough for a binding to be invalid (not possible on the
|
||||
// real GPU since dimensions minus 1 are stored).
|
||||
return !width;
|
||||
}
|
||||
void MakeInvalid() {
|
||||
// Zero everything, including the padding, for a stable hash.
|
||||
std::memset(this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
uint32_t GetWidth() const { return width_minus_1 + 1; }
|
||||
uint32_t GetHeight() const { return height_minus_1 + 1; }
|
||||
uint32_t GetDepthOrArraySize() const {
|
||||
return depth_or_array_size_minus_1 + 1;
|
||||
}
|
||||
|
||||
using Hasher = xe::hash::XXHasher<TextureKey>;
|
||||
bool operator==(const TextureKey& key) const {
|
||||
return !std::memcmp(this, &key, sizeof(*this));
|
||||
|
@ -544,7 +551,8 @@ class TextureCache {
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
static uint32_t GetMaxHostTextureDepth(xenos::DataDimension dimension) {
|
||||
static uint32_t GetMaxHostTextureDepthOrArraySize(
|
||||
xenos::DataDimension dimension) {
|
||||
switch (dimension) {
|
||||
case xenos::DataDimension::k1D:
|
||||
case xenos::DataDimension::k2DOrStacked:
|
||||
|
@ -609,7 +617,7 @@ class TextureCache {
|
|||
: host_format.dxgi_format_resource;
|
||||
}
|
||||
static DXGI_FORMAT GetDXGIResourceFormat(TextureKey key) {
|
||||
return GetDXGIResourceFormat(key.format, key.width, key.height);
|
||||
return GetDXGIResourceFormat(key.format, key.GetWidth(), key.GetHeight());
|
||||
}
|
||||
static DXGI_FORMAT GetDXGIUnormFormat(xenos::TextureFormat format,
|
||||
uint32_t width, uint32_t height) {
|
||||
|
@ -619,7 +627,7 @@ class TextureCache {
|
|||
: host_format.dxgi_format_unorm;
|
||||
}
|
||||
static DXGI_FORMAT GetDXGIUnormFormat(TextureKey key) {
|
||||
return GetDXGIUnormFormat(key.format, key.width, key.height);
|
||||
return GetDXGIUnormFormat(key.format, key.GetWidth(), key.GetHeight());
|
||||
}
|
||||
|
||||
static LoadMode GetLoadMode(TextureKey key);
|
||||
|
|
|
@ -20,55 +20,58 @@ namespace gpu {
|
|||
namespace texture_util {
|
||||
|
||||
void GetSubresourcesFromFetchConstant(
|
||||
const xenos::xe_gpu_texture_fetch_t& fetch, uint32_t* width_out,
|
||||
uint32_t* height_out, uint32_t* depth_or_faces_out, uint32_t* base_page_out,
|
||||
uint32_t* mip_page_out, uint32_t* mip_min_level_out,
|
||||
uint32_t* mip_max_level_out, xenos::TextureFilter sampler_mip_filter) {
|
||||
uint32_t width = 0, height = 0, depth_or_faces = 0;
|
||||
const xenos::xe_gpu_texture_fetch_t& fetch, uint32_t* width_minus_1_out,
|
||||
uint32_t* height_minus_1_out, uint32_t* depth_or_array_size_minus_1_out,
|
||||
uint32_t* base_page_out, uint32_t* mip_page_out,
|
||||
uint32_t* mip_min_level_out, uint32_t* mip_max_level_out,
|
||||
xenos::TextureFilter sampler_mip_filter) {
|
||||
uint32_t width_minus_1 = 0;
|
||||
uint32_t height_minus_1 = 0;
|
||||
uint32_t depth_or_array_size_minus_1 = 0;
|
||||
switch (fetch.dimension) {
|
||||
case xenos::DataDimension::k1D:
|
||||
assert_false(fetch.stacked);
|
||||
assert_false(fetch.tiled);
|
||||
assert_false(fetch.packed_mips);
|
||||
width = fetch.size_1d.width;
|
||||
width_minus_1 = fetch.size_1d.width;
|
||||
break;
|
||||
case xenos::DataDimension::k2DOrStacked:
|
||||
width = fetch.size_2d.width;
|
||||
height = fetch.size_2d.height;
|
||||
depth_or_faces = fetch.stacked ? fetch.size_2d.stack_depth : 0;
|
||||
width_minus_1 = fetch.size_2d.width;
|
||||
height_minus_1 = fetch.size_2d.height;
|
||||
depth_or_array_size_minus_1 =
|
||||
fetch.stacked ? fetch.size_2d.stack_depth : 0;
|
||||
break;
|
||||
case xenos::DataDimension::k3D:
|
||||
assert_false(fetch.stacked);
|
||||
width = fetch.size_3d.width;
|
||||
height = fetch.size_3d.height;
|
||||
depth_or_faces = fetch.size_3d.depth;
|
||||
width_minus_1 = fetch.size_3d.width;
|
||||
height_minus_1 = fetch.size_3d.height;
|
||||
depth_or_array_size_minus_1 = fetch.size_3d.depth;
|
||||
break;
|
||||
case xenos::DataDimension::kCube:
|
||||
assert_false(fetch.stacked);
|
||||
assert_true(fetch.size_2d.stack_depth == 5);
|
||||
width = fetch.size_2d.width;
|
||||
height = fetch.size_2d.height;
|
||||
depth_or_faces = 5;
|
||||
width_minus_1 = fetch.size_2d.width;
|
||||
height_minus_1 = fetch.size_2d.height;
|
||||
depth_or_array_size_minus_1 = 5;
|
||||
break;
|
||||
}
|
||||
++width;
|
||||
++height;
|
||||
++depth_or_faces;
|
||||
if (width_out) {
|
||||
*width_out = width;
|
||||
if (width_minus_1_out) {
|
||||
*width_minus_1_out = width_minus_1;
|
||||
}
|
||||
if (height_out) {
|
||||
*height_out = height;
|
||||
if (height_minus_1_out) {
|
||||
*height_minus_1_out = height_minus_1;
|
||||
}
|
||||
if (depth_or_faces_out) {
|
||||
*depth_or_faces_out = depth_or_faces;
|
||||
if (depth_or_array_size_minus_1_out) {
|
||||
*depth_or_array_size_minus_1_out = depth_or_array_size_minus_1;
|
||||
}
|
||||
|
||||
uint32_t longest_axis = std::max(width, height);
|
||||
uint32_t longest_axis_minus_1 = std::max(width_minus_1, height_minus_1);
|
||||
if (fetch.dimension == xenos::DataDimension::k3D) {
|
||||
longest_axis = std::max(longest_axis, depth_or_faces);
|
||||
longest_axis_minus_1 =
|
||||
std::max(longest_axis_minus_1, depth_or_array_size_minus_1);
|
||||
}
|
||||
uint32_t size_mip_max_level = xe::log2_floor(longest_axis);
|
||||
uint32_t size_mip_max_level =
|
||||
xe::log2_floor(longest_axis_minus_1 + uint32_t(1));
|
||||
xenos::TextureFilter mip_filter =
|
||||
sampler_mip_filter == xenos::TextureFilter::kUseFetchConst
|
||||
? fetch.mip_filter
|
||||
|
|
|
@ -27,10 +27,10 @@ namespace texture_util {
|
|||
// mip range based on real presence of the base level and mips. Returns 6 faces
|
||||
// for cube textures.
|
||||
void GetSubresourcesFromFetchConstant(
|
||||
const xenos::xe_gpu_texture_fetch_t& fetch, uint32_t* width_out,
|
||||
uint32_t* height_out, uint32_t* depth_or_faces_out, uint32_t* base_page_out,
|
||||
uint32_t* mip_page_out, uint32_t* mip_min_level_out,
|
||||
uint32_t* mip_max_level_out,
|
||||
const xenos::xe_gpu_texture_fetch_t& fetch, uint32_t* width_minus_1_out,
|
||||
uint32_t* height_minus_1_out, uint32_t* depth_or_array_size_minus_1_out,
|
||||
uint32_t* base_page_out, uint32_t* mip_page_out,
|
||||
uint32_t* mip_min_level_out, uint32_t* mip_max_level_out,
|
||||
xenos::TextureFilter sampler_mip_filter =
|
||||
xenos::TextureFilter::kUseFetchConst);
|
||||
|
||||
|
|
Loading…
Reference in New Issue