mirror of
https://github.com/par274/sharpemu.git
synced 2026-08-01 15:39:47 +08:00
[Gpu] Sample 2D array textures with real layers (#471)
Texture arrays were uploaded and viewed as plain 2D images, so every layer index in a shader resolved to slice 0. The guest-texture gate also rejected array, 3D and cube descriptor types outright, sending those resources to the 1x1 black fallback. UI atlases hit this constantly, since they pack several sheets as array slices and pick one per vertex. In Demon's Souls the settings menu bottom bar stretched a mid-atlas crop across itself, and slider thumbs and button prompts drew the wrong sheet. The MIMG decoder already had Dimension and IsArray, so IsArrayedImageBinding makes one rule out of them for the SPIR-V translator and the Vulkan backend to share. Both have to agree or the declared image type and the bound view type mismatch. Sample and gather bindings with an array address now declare an arrayed image and pass (u, v, slice). AgcExports reads every slice at the per-slice mip-chain stride and passes the layers packed in one buffer, which uploads as a 2D array image in a single copy region. Load and store bindings are unchanged. Arrayed bindings that resolve to a fallback or to a single-layer guest image get a one-layer 2D array view so the descriptor still matches the shader. Tested on Demon's Souls (PPSA01342): the bottom bar, slider thumbs and button prompts draw their correct sheets. 470 tests pass.
This commit is contained in:
@@ -313,7 +313,8 @@ public static partial class Gen5SpirvTranslator
|
||||
uint ComponentType,
|
||||
uint VectorType,
|
||||
ImageComponentKind ComponentKind,
|
||||
bool IsStorage);
|
||||
bool IsStorage,
|
||||
bool Arrayed);
|
||||
|
||||
private readonly record struct SpirvVertexInput(
|
||||
uint Variable,
|
||||
@@ -1000,11 +1001,13 @@ public static partial class Gen5SpirvTranslator
|
||||
SpirvCapability.StorageImageExtendedFormats);
|
||||
}
|
||||
|
||||
var isArrayed = !isStorage &&
|
||||
Gen5ShaderTranslator.IsArrayedImageBinding(binding);
|
||||
var imageType = _module.TypeImage(
|
||||
componentType,
|
||||
SpirvImageDim.Dim2D,
|
||||
depth: false,
|
||||
arrayed: false,
|
||||
arrayed: isArrayed,
|
||||
multisampled: false,
|
||||
sampled: isStorage ? 2u : 1u,
|
||||
isStorage ? format : SpirvImageFormat.Unknown);
|
||||
@@ -1031,7 +1034,8 @@ public static partial class Gen5SpirvTranslator
|
||||
componentType,
|
||||
_module.TypeVector(componentType, 4),
|
||||
componentKind,
|
||||
isStorage));
|
||||
isStorage,
|
||||
isArrayed));
|
||||
_interfaces.Add(variable);
|
||||
}
|
||||
}
|
||||
@@ -3529,12 +3533,16 @@ public static partial class Gen5SpirvTranslator
|
||||
addressCursor += 4;
|
||||
}
|
||||
|
||||
var coordinates = BuildFloatCoordinates(image, addressCursor);
|
||||
var coordinates = resource.Arrayed
|
||||
? BuildFloatArrayCoordinates(image, addressCursor)
|
||||
: BuildFloatCoordinates(image, addressCursor);
|
||||
var explicitLod = hasGradients || hasZeroLod || hasLod;
|
||||
var lod = hasZeroLod
|
||||
? Float(0)
|
||||
: hasLod
|
||||
? LoadImageFloatAddress(image, addressCursor + 2)
|
||||
? LoadImageFloatAddress(
|
||||
image,
|
||||
addressCursor + (resource.Arrayed ? 3 : 2))
|
||||
: lodOrBias;
|
||||
if (hasOffset)
|
||||
{
|
||||
@@ -3619,7 +3627,9 @@ public static partial class Gen5SpirvTranslator
|
||||
addressCursor += ImageFullAddressSlots(image);
|
||||
}
|
||||
|
||||
var coordinates = BuildFloatCoordinates(image, addressCursor);
|
||||
var coordinates = resource.Arrayed
|
||||
? BuildFloatArrayCoordinates(image, addressCursor)
|
||||
: BuildFloatCoordinates(image, addressCursor);
|
||||
var operands = new List<uint>
|
||||
{
|
||||
imageObject,
|
||||
@@ -3823,6 +3833,19 @@ public static partial class Gen5SpirvTranslator
|
||||
y);
|
||||
}
|
||||
|
||||
private uint BuildFloatArrayCoordinates(Gen5ImageControl image, int start)
|
||||
{
|
||||
var x = LoadImageFloatAddress(image, start);
|
||||
var y = LoadImageFloatAddress(image, start + 1);
|
||||
var slice = LoadImageFloatAddress(image, start + 2);
|
||||
return _module.AddInstruction(
|
||||
SpirvOp.CompositeConstruct,
|
||||
_vec3Type,
|
||||
x,
|
||||
y,
|
||||
slice);
|
||||
}
|
||||
|
||||
private static int ImageAddressRegister(
|
||||
Gen5ImageControl image,
|
||||
int component) => image.A16 ? component / 2 : component;
|
||||
@@ -4140,9 +4163,20 @@ public static partial class Gen5SpirvTranslator
|
||||
signedLod);
|
||||
var size = _module.AddInstruction(
|
||||
SpirvOp.ImageQuerySizeLod,
|
||||
ivec2,
|
||||
resource.Arrayed ? _module.TypeVector(_intType, 3) : ivec2,
|
||||
image,
|
||||
clampedLod);
|
||||
if (resource.Arrayed)
|
||||
{
|
||||
size = _module.AddInstruction(
|
||||
SpirvOp.VectorShuffle,
|
||||
ivec2,
|
||||
size,
|
||||
size,
|
||||
0u,
|
||||
1u);
|
||||
}
|
||||
|
||||
var sizeFloat = _module.AddInstruction(
|
||||
SpirvOp.ConvertSToF,
|
||||
_vec2Type,
|
||||
@@ -4156,11 +4190,34 @@ public static partial class Gen5SpirvTranslator
|
||||
_vec2Type,
|
||||
offsetFloat,
|
||||
sizeFloat);
|
||||
if (!resource.Arrayed)
|
||||
{
|
||||
return _module.AddInstruction(
|
||||
SpirvOp.FAdd,
|
||||
_vec2Type,
|
||||
coordinates,
|
||||
normalizedOffset);
|
||||
}
|
||||
|
||||
var offsetVec3 = _module.AddInstruction(
|
||||
SpirvOp.CompositeConstruct,
|
||||
_vec3Type,
|
||||
_module.AddInstruction(
|
||||
SpirvOp.CompositeExtract,
|
||||
_floatType,
|
||||
normalizedOffset,
|
||||
0u),
|
||||
_module.AddInstruction(
|
||||
SpirvOp.CompositeExtract,
|
||||
_floatType,
|
||||
normalizedOffset,
|
||||
1u),
|
||||
Float(0));
|
||||
return _module.AddInstruction(
|
||||
SpirvOp.FAdd,
|
||||
_vec2Type,
|
||||
_vec3Type,
|
||||
coordinates,
|
||||
normalizedOffset);
|
||||
offsetVec3);
|
||||
}
|
||||
|
||||
private bool TryEmitExport(
|
||||
|
||||
Reference in New Issue
Block a user