mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-27 21:21:56 +08:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ac35b97430 |
@@ -3609,7 +3609,7 @@ public static class AgcExports
|
|||||||
',',
|
',',
|
||||||
draw.GlobalMemoryBindings.Select((binding, index) =>
|
draw.GlobalMemoryBindings.Select((binding, index) =>
|
||||||
$"{index}:0x{binding.BaseAddress:X16}:{binding.Data.Length}:" +
|
$"{index}:0x{binding.BaseAddress:X16}:{binding.Data.Length}:" +
|
||||||
Convert.ToHexString(binding.Data.AsSpan(0, Math.Min(binding.Data.Length, 256)))));
|
Convert.ToHexString(binding.Data.AsSpan(0, Math.Min(binding.Data.Length, 32)))));
|
||||||
var indices = draw.IndexBuffer is { } indexBuffer
|
var indices = draw.IndexBuffer is { } indexBuffer
|
||||||
? $"{(indexBuffer.Is32Bit ? 32 : 16)}:" +
|
? $"{(indexBuffer.Is32Bit ? 32 : 16)}:" +
|
||||||
Convert.ToHexString(indexBuffer.Data.AsSpan(0, Math.Min(indexBuffer.Data.Length, 32)))
|
Convert.ToHexString(indexBuffer.Data.AsSpan(0, Math.Min(indexBuffer.Data.Length, 32)))
|
||||||
@@ -3744,7 +3744,7 @@ public static class AgcExports
|
|||||||
descriptor.Width > 8192 ||
|
descriptor.Width > 8192 ||
|
||||||
descriptor.Height > 8192)
|
descriptor.Height > 8192)
|
||||||
{
|
{
|
||||||
texture = CreateFallbackGuestDrawTexture(isStorage, descriptor.Format, descriptor.NumberType);
|
texture = CreateFallbackGuestDrawTexture(isStorage);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3762,7 +3762,7 @@ public static class AgcExports
|
|||||||
sourceByteCount > MaxPresentedTextureBytes ||
|
sourceByteCount > MaxPresentedTextureBytes ||
|
||||||
sourceByteCount > int.MaxValue)
|
sourceByteCount > int.MaxValue)
|
||||||
{
|
{
|
||||||
texture = CreateFallbackGuestDrawTexture(isStorage, descriptor.Format, descriptor.NumberType);
|
texture = CreateFallbackGuestDrawTexture(isStorage);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3825,7 +3825,7 @@ public static class AgcExports
|
|||||||
var source = new byte[(int)sourceByteCount];
|
var source = new byte[(int)sourceByteCount];
|
||||||
if (!ctx.Memory.TryRead(descriptor.Address, source))
|
if (!ctx.Memory.TryRead(descriptor.Address, source))
|
||||||
{
|
{
|
||||||
texture = CreateFallbackGuestDrawTexture(isStorage, descriptor.Format, descriptor.NumberType);
|
texture = CreateFallbackGuestDrawTexture(isStorage);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3868,25 +3868,18 @@ public static class AgcExports
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static VulkanGuestDrawTexture CreateFallbackGuestDrawTexture(
|
private static VulkanGuestDrawTexture CreateFallbackGuestDrawTexture(bool isStorage = false) =>
|
||||||
bool isStorage,
|
new(
|
||||||
uint format,
|
|
||||||
uint numberType)
|
|
||||||
{
|
|
||||||
var fallbackFormat = format == 0 ? 10u : format;
|
|
||||||
var fallbackNumberType = numberType;
|
|
||||||
return new(
|
|
||||||
0,
|
0,
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
fallbackFormat,
|
56,
|
||||||
fallbackNumberType,
|
NumberType: 0,
|
||||||
[0, 0, 0, 255],
|
[0, 0, 0, 255],
|
||||||
IsFallback: true,
|
IsFallback: true,
|
||||||
IsStorage: isStorage,
|
IsStorage: isStorage,
|
||||||
MipLevels: 1,
|
MipLevels: 1,
|
||||||
MipLevel: 0);
|
MipLevel: 0);
|
||||||
}
|
|
||||||
|
|
||||||
private static VulkanGuestSampler ToVulkanSampler(IReadOnlyList<uint> descriptor) =>
|
private static VulkanGuestSampler ToVulkanSampler(IReadOnlyList<uint> descriptor) =>
|
||||||
descriptor.Count >= 4
|
descriptor.Count >= 4
|
||||||
|
|||||||
@@ -467,6 +467,9 @@ internal static partial class Gen5SpirvTranslator
|
|||||||
_imageBindingByPc.TryAdd(binding.Pc, index);
|
_imageBindingByPc.TryAdd(binding.Pc, index);
|
||||||
var isStorage =
|
var isStorage =
|
||||||
Gen5ShaderTranslator.IsStorageImageOperation(binding.Opcode);
|
Gen5ShaderTranslator.IsStorageImageOperation(binding.Opcode);
|
||||||
|
var isDepth =
|
||||||
|
binding.Opcode.Contains("SampleC", StringComparison.Ordinal) ||
|
||||||
|
binding.Opcode.Contains("Gather4C", StringComparison.Ordinal);
|
||||||
var (format, componentKind) =
|
var (format, componentKind) =
|
||||||
DecodeImageFormat(binding.ResourceDescriptor);
|
DecodeImageFormat(binding.ResourceDescriptor);
|
||||||
var componentType = componentKind switch
|
var componentType = componentKind switch
|
||||||
@@ -491,7 +494,7 @@ internal static partial class Gen5SpirvTranslator
|
|||||||
var imageType = _module.TypeImage(
|
var imageType = _module.TypeImage(
|
||||||
componentType,
|
componentType,
|
||||||
SpirvImageDim.Dim2D,
|
SpirvImageDim.Dim2D,
|
||||||
depth: false,
|
depth: isDepth,
|
||||||
arrayed: false,
|
arrayed: false,
|
||||||
multisampled: false,
|
multisampled: false,
|
||||||
sampled: isStorage ? 2u : 1u,
|
sampled: isStorage ? 2u : 1u,
|
||||||
@@ -1658,14 +1661,18 @@ internal static partial class Gen5SpirvTranslator
|
|||||||
var offset = hasOffset ? BuildImageOffset(image, 0) : 0u;
|
var offset = hasOffset ? BuildImageOffset(image, 0) : 0u;
|
||||||
var imageOperands =
|
var imageOperands =
|
||||||
(explicitLod ? 2u : 0u) | (hasOffset ? 0x10u : 0u);
|
(explicitLod ? 2u : 0u) | (hasOffset ? 0x10u : 0u);
|
||||||
var reference = hasCompare
|
|
||||||
? Bitcast(_floatType, LoadV(image.GetAddressRegister(hasOffset ? 1 : 0)))
|
|
||||||
: 0u;
|
|
||||||
var operands = new List<uint>
|
var operands = new List<uint>
|
||||||
{
|
{
|
||||||
imageObject,
|
imageObject,
|
||||||
coordinates,
|
coordinates,
|
||||||
};
|
};
|
||||||
|
if (hasCompare)
|
||||||
|
{
|
||||||
|
operands.Add(
|
||||||
|
Bitcast(
|
||||||
|
_floatType,
|
||||||
|
LoadV(image.GetAddressRegister(hasOffset ? 1 : 0))));
|
||||||
|
}
|
||||||
|
|
||||||
if (imageOperands != 0)
|
if (imageOperands != 0)
|
||||||
{
|
{
|
||||||
@@ -1682,14 +1689,29 @@ internal static partial class Gen5SpirvTranslator
|
|||||||
}
|
}
|
||||||
|
|
||||||
sampled = _module.AddInstruction(
|
sampled = _module.AddInstruction(
|
||||||
explicitLod
|
hasCompare
|
||||||
? SpirvOp.ImageSampleExplicitLod
|
? explicitLod
|
||||||
: SpirvOp.ImageSampleImplicitLod,
|
? SpirvOp.ImageSampleDrefExplicitLod
|
||||||
resource.VectorType,
|
: SpirvOp.ImageSampleDrefImplicitLod
|
||||||
|
: explicitLod
|
||||||
|
? SpirvOp.ImageSampleExplicitLod
|
||||||
|
: SpirvOp.ImageSampleImplicitLod,
|
||||||
|
hasCompare ? resource.ComponentType : resource.VectorType,
|
||||||
[.. operands]);
|
[.. operands]);
|
||||||
if (hasCompare)
|
if (hasCompare)
|
||||||
{
|
{
|
||||||
sampled = EmitManualDepthCompare(resource, sampled, reference);
|
var scalar = sampled;
|
||||||
|
sampled = _module.AddInstruction(
|
||||||
|
SpirvOp.CompositeConstruct,
|
||||||
|
resource.VectorType,
|
||||||
|
scalar,
|
||||||
|
scalar,
|
||||||
|
scalar,
|
||||||
|
resource.ComponentKind == ImageComponentKind.Float
|
||||||
|
? Float(1)
|
||||||
|
: resource.ComponentKind == ImageComponentKind.Uint
|
||||||
|
? UInt(1)
|
||||||
|
: _module.Constant(_intType, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (instruction.Opcode.StartsWith(
|
else if (instruction.Opcode.StartsWith(
|
||||||
@@ -1703,9 +1725,6 @@ internal static partial class Gen5SpirvTranslator
|
|||||||
var start = (hasOffset ? 1 : 0) + (hasCompare ? 1 : 0);
|
var start = (hasOffset ? 1 : 0) + (hasCompare ? 1 : 0);
|
||||||
var coordinates = BuildFloatCoordinates(image, start);
|
var coordinates = BuildFloatCoordinates(image, start);
|
||||||
var offset = hasOffset ? BuildImageOffset(image, 0) : 0u;
|
var offset = hasOffset ? BuildImageOffset(image, 0) : 0u;
|
||||||
var reference = hasCompare
|
|
||||||
? Bitcast(_floatType, LoadV(image.GetAddressRegister(hasOffset ? 1 : 0)))
|
|
||||||
: 0u;
|
|
||||||
var operands = new List<uint>
|
var operands = new List<uint>
|
||||||
{
|
{
|
||||||
imageObject,
|
imageObject,
|
||||||
@@ -1713,7 +1732,10 @@ internal static partial class Gen5SpirvTranslator
|
|||||||
};
|
};
|
||||||
if (hasCompare)
|
if (hasCompare)
|
||||||
{
|
{
|
||||||
operands.Add(UInt(0));
|
operands.Add(
|
||||||
|
Bitcast(
|
||||||
|
_floatType,
|
||||||
|
LoadV(image.GetAddressRegister(hasOffset ? 1 : 0))));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1734,28 +1756,11 @@ internal static partial class Gen5SpirvTranslator
|
|||||||
}
|
}
|
||||||
|
|
||||||
sampled = _module.AddInstruction(
|
sampled = _module.AddInstruction(
|
||||||
SpirvOp.ImageGather,
|
hasCompare
|
||||||
|
? SpirvOp.ImageDrefGather
|
||||||
|
: SpirvOp.ImageGather,
|
||||||
resource.VectorType,
|
resource.VectorType,
|
||||||
[.. operands]);
|
[.. operands]);
|
||||||
if (hasCompare)
|
|
||||||
{
|
|
||||||
var compared = new uint[4];
|
|
||||||
for (var component = 0u; component < 4; component++)
|
|
||||||
{
|
|
||||||
var texel = _module.AddInstruction(
|
|
||||||
SpirvOp.CompositeExtract,
|
|
||||||
resource.ComponentType,
|
|
||||||
sampled,
|
|
||||||
component);
|
|
||||||
compared[component] = EmitDepthCompareScalar(resource, texel, reference);
|
|
||||||
}
|
|
||||||
|
|
||||||
sampled = _module.AddInstruction(
|
|
||||||
SpirvOp.CompositeConstruct,
|
|
||||||
resource.VectorType,
|
|
||||||
compared);
|
|
||||||
}
|
|
||||||
|
|
||||||
writeAllComponents = true;
|
writeAllComponents = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1789,67 +1794,6 @@ internal static partial class Gen5SpirvTranslator
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private uint EmitDepthCompareScalar(
|
|
||||||
SpirvImageResource resource,
|
|
||||||
uint texel,
|
|
||||||
uint reference)
|
|
||||||
{
|
|
||||||
var texelAsFloat = resource.ComponentKind switch
|
|
||||||
{
|
|
||||||
ImageComponentKind.Uint => _module.AddInstruction(
|
|
||||||
SpirvOp.ConvertUToF, _floatType, texel),
|
|
||||||
ImageComponentKind.Sint => _module.AddInstruction(
|
|
||||||
SpirvOp.ConvertSToF, _floatType, texel),
|
|
||||||
_ => texel,
|
|
||||||
};
|
|
||||||
var passes = _module.AddInstruction(
|
|
||||||
SpirvOp.FOrdLessThanEqual,
|
|
||||||
_boolType,
|
|
||||||
reference,
|
|
||||||
texelAsFloat);
|
|
||||||
return _module.AddInstruction(
|
|
||||||
SpirvOp.Select,
|
|
||||||
resource.ComponentType,
|
|
||||||
passes,
|
|
||||||
resource.ComponentKind switch
|
|
||||||
{
|
|
||||||
ImageComponentKind.Uint => UInt(1),
|
|
||||||
ImageComponentKind.Sint => _module.Constant(_intType, 1),
|
|
||||||
_ => Float(1),
|
|
||||||
},
|
|
||||||
resource.ComponentKind switch
|
|
||||||
{
|
|
||||||
ImageComponentKind.Uint => UInt(0),
|
|
||||||
ImageComponentKind.Sint => _module.Constant(_intType, 0),
|
|
||||||
_ => Float(0),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private uint EmitManualDepthCompare(
|
|
||||||
SpirvImageResource resource,
|
|
||||||
uint sampledVector,
|
|
||||||
uint reference)
|
|
||||||
{
|
|
||||||
var texel = _module.AddInstruction(
|
|
||||||
SpirvOp.CompositeExtract,
|
|
||||||
resource.ComponentType,
|
|
||||||
sampledVector,
|
|
||||||
0u);
|
|
||||||
var scalar = EmitDepthCompareScalar(resource, texel, reference);
|
|
||||||
return _module.AddInstruction(
|
|
||||||
SpirvOp.CompositeConstruct,
|
|
||||||
resource.VectorType,
|
|
||||||
scalar,
|
|
||||||
scalar,
|
|
||||||
scalar,
|
|
||||||
resource.ComponentKind switch
|
|
||||||
{
|
|
||||||
ImageComponentKind.Uint => UInt(1),
|
|
||||||
ImageComponentKind.Sint => _module.Constant(_intType, 1),
|
|
||||||
_ => Float(1),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private uint BuildFloatCoordinates(Gen5ImageControl image, int start)
|
private uint BuildFloatCoordinates(Gen5ImageControl image, int start)
|
||||||
{
|
{
|
||||||
var x = Bitcast(
|
var x = Bitcast(
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
// Copyright (C) 2026 SharpEmu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
using SharpEmu.HLE;
|
||||||
|
|
||||||
|
namespace SharpEmu.Libs.Kernel;
|
||||||
|
|
||||||
|
public static class KernelExceptionCompatExports
|
||||||
|
{
|
||||||
|
private static readonly HashSet<int> AllowedSignals = new() { 1, 4, 8, 10, 11, 30 };
|
||||||
|
private static readonly Dictionary<int, ulong> _installedHandlers = new();
|
||||||
|
private static readonly object _gate = new();
|
||||||
|
|
||||||
|
[SysAbiExport(
|
||||||
|
Nid = "WkwEd3N7w0Y",
|
||||||
|
ExportName = "sceKernelInstallExceptionHandler",
|
||||||
|
Target = Generation.Gen4 | Generation.Gen5,
|
||||||
|
LibraryName = "libKernel")]
|
||||||
|
public static int InstallExceptionHandler(CpuContext ctx)
|
||||||
|
{
|
||||||
|
var signum = unchecked((int)ctx[CpuRegister.Rdi]);
|
||||||
|
var handler = ctx[CpuRegister.Rsi];
|
||||||
|
|
||||||
|
if (!AllowedSignals.Contains(signum))
|
||||||
|
{
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (_gate)
|
||||||
|
{
|
||||||
|
if (_installedHandlers.ContainsKey(signum))
|
||||||
|
{
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_ALREADY_EXISTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
_installedHandlers[signum] = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx[CpuRegister.Rax] = 0;
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
[SysAbiExport(
|
||||||
|
Nid = "Qhv5ARAoOEc",
|
||||||
|
ExportName = "sceKernelRemoveExceptionHandler",
|
||||||
|
Target = Generation.Gen4 | Generation.Gen5,
|
||||||
|
LibraryName = "libKernel")]
|
||||||
|
public static int RemoveExceptionHandler(CpuContext ctx)
|
||||||
|
{
|
||||||
|
var signum = unchecked((int)ctx[CpuRegister.Rdi]);
|
||||||
|
|
||||||
|
if (!AllowedSignals.Contains(signum))
|
||||||
|
{
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (_gate)
|
||||||
|
{
|
||||||
|
_installedHandlers.Remove(signum);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx[CpuRegister.Rax] = 0;
|
||||||
|
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -365,6 +365,13 @@ public static class KernelExports
|
|||||||
LibraryName = "libKernel")]
|
LibraryName = "libKernel")]
|
||||||
public static int KernelOpen(CpuContext ctx) => KernelMemoryCompatExports.KernelOpenUnderscore(ctx);
|
public static int KernelOpen(CpuContext ctx) => KernelMemoryCompatExports.KernelOpenUnderscore(ctx);
|
||||||
|
|
||||||
|
[SysAbiExport(
|
||||||
|
Nid = "mqQMh1zPPT8",
|
||||||
|
ExportName = "fstat",
|
||||||
|
Target = Generation.Gen4 | Generation.Gen5,
|
||||||
|
LibraryName = "libc")]
|
||||||
|
public static int Fstat(CpuContext ctx) => KernelMemoryCompatExports.KernelFstat(ctx);
|
||||||
|
|
||||||
[SysAbiExport(
|
[SysAbiExport(
|
||||||
Nid = "hcuQgD53UxM",
|
Nid = "hcuQgD53UxM",
|
||||||
ExportName = "printf",
|
ExportName = "printf",
|
||||||
|
|||||||
@@ -95,6 +95,13 @@ public static class KernelPthreadCompatExports
|
|||||||
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SysAbiExport(
|
||||||
|
Nid = "7Xl257M4VNI",
|
||||||
|
ExportName = "pthread_equal",
|
||||||
|
Target = Generation.Gen4 | Generation.Gen5,
|
||||||
|
LibraryName = "libc")]
|
||||||
|
public static int PosixPthreadEqual(CpuContext ctx) => PthreadEqual(ctx);
|
||||||
|
|
||||||
[SysAbiExport(
|
[SysAbiExport(
|
||||||
Nid = "T72hz6ffq08",
|
Nid = "T72hz6ffq08",
|
||||||
ExportName = "scePthreadYield",
|
ExportName = "scePthreadYield",
|
||||||
|
|||||||
@@ -1459,20 +1459,8 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
VertexPipelineStoresAndAtomics = supportedFeatures.VertexPipelineStoresAndAtomics,
|
VertexPipelineStoresAndAtomics = supportedFeatures.VertexPipelineStoresAndAtomics,
|
||||||
FragmentStoresAndAtomics = supportedFeatures.FragmentStoresAndAtomics,
|
FragmentStoresAndAtomics = supportedFeatures.FragmentStoresAndAtomics,
|
||||||
ShaderInt64 = supportedFeatures.ShaderInt64,
|
ShaderInt64 = supportedFeatures.ShaderInt64,
|
||||||
ShaderImageGatherExtended = supportedFeatures.ShaderImageGatherExtended,
|
|
||||||
ShaderStorageImageExtendedFormats = supportedFeatures.ShaderStorageImageExtendedFormats,
|
|
||||||
ShaderStorageImageReadWithoutFormat = supportedFeatures.ShaderStorageImageReadWithoutFormat,
|
|
||||||
ShaderStorageImageWriteWithoutFormat = supportedFeatures.ShaderStorageImageWriteWithoutFormat,
|
|
||||||
RobustBufferAccess = supportedFeatures.RobustBufferAccess,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!supportedFeatures.RobustBufferAccess)
|
|
||||||
{
|
|
||||||
Console.Error.WriteLine(
|
|
||||||
"[LOADER][WARN] GPU does not support robustBufferAccess " +
|
|
||||||
"translated shaders performing out-of-bounds buffer access may cause device loss.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!supportedFeatures.ShaderInt64)
|
if (!supportedFeatures.ShaderInt64)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine(
|
Console.Error.WriteLine(
|
||||||
@@ -1487,95 +1475,17 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
"translated shaders using storage buffers in vertex/fragment stages may fail.");
|
"translated shaders using storage buffers in vertex/fragment stages may fail.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!supportedFeatures.ShaderImageGatherExtended)
|
|
||||||
{
|
|
||||||
Console.Error.WriteLine(
|
|
||||||
"[LOADER][WARN] GPU does not support shaderImageGatherExtended " +
|
|
||||||
"translated shaders using image gather with offsets/LOD/bias will fail.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!supportedFeatures.ShaderStorageImageReadWithoutFormat ||
|
|
||||||
!supportedFeatures.ShaderStorageImageWriteWithoutFormat)
|
|
||||||
{
|
|
||||||
Console.Error.WriteLine(
|
|
||||||
"[LOADER][WARN] GPU does not support shaderStorageImage(Read|Write)WithoutFormat " +
|
|
||||||
"translated shaders using unformatted storage image load/store will fail.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var maintenance8Features = new PhysicalDeviceMaintenance8FeaturesKHR
|
|
||||||
{
|
|
||||||
SType = StructureType.PhysicalDeviceMaintenance8FeaturesKhr,
|
|
||||||
};
|
|
||||||
var robustness2Features = new PhysicalDeviceRobustness2FeaturesEXT
|
|
||||||
{
|
|
||||||
SType = StructureType.PhysicalDeviceRobustness2FeaturesExt,
|
|
||||||
PNext = &maintenance8Features,
|
|
||||||
};
|
|
||||||
var featuresQuery = new PhysicalDeviceFeatures2
|
|
||||||
{
|
|
||||||
SType = StructureType.PhysicalDeviceFeatures2,
|
|
||||||
PNext = &robustness2Features,
|
|
||||||
};
|
|
||||||
_vk.GetPhysicalDeviceFeatures2(_physicalDevice, &featuresQuery);
|
|
||||||
var supportsMaintenance8 = maintenance8Features.Maintenance8;
|
|
||||||
var supportsRobustImageAccess2 = robustness2Features.RobustImageAccess2;
|
|
||||||
var supportsNullDescriptor = robustness2Features.NullDescriptor;
|
|
||||||
var supportsRobustness2 = supportsRobustImageAccess2 || supportsNullDescriptor;
|
|
||||||
if (!supportsMaintenance8)
|
|
||||||
{
|
|
||||||
Console.Error.WriteLine(
|
|
||||||
"[LOADER][WARN] GPU does not support VK_KHR_maintenance8 " +
|
|
||||||
"translated shaders using a dynamic texel offset on non-gather image samples will fail.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!supportsRobustImageAccess2)
|
|
||||||
{
|
|
||||||
Console.Error.WriteLine(
|
|
||||||
"[LOADER][WARN] GPU does not support VK_EXT_robustness2 robustImageAccess2 " +
|
|
||||||
"translated shaders performing out-of-bounds image access may cause device loss.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var swapchainExtension = (byte*)SilkMarshal.StringToPtr("VK_KHR_swapchain");
|
var swapchainExtension = (byte*)SilkMarshal.StringToPtr("VK_KHR_swapchain");
|
||||||
var maintenance8Extension = (byte*)SilkMarshal.StringToPtr("VK_KHR_maintenance8");
|
|
||||||
var robustness2Extension = (byte*)SilkMarshal.StringToPtr("VK_EXT_robustness2");
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var extensions = stackalloc byte*[3];
|
|
||||||
var extensionCount = 0u;
|
|
||||||
extensions[extensionCount++] = swapchainExtension;
|
|
||||||
if (supportsMaintenance8)
|
|
||||||
{
|
|
||||||
extensions[extensionCount++] = maintenance8Extension;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportsRobustness2)
|
|
||||||
{
|
|
||||||
extensions[extensionCount++] = robustness2Extension;
|
|
||||||
}
|
|
||||||
|
|
||||||
maintenance8Features.Maintenance8 = supportsMaintenance8;
|
|
||||||
maintenance8Features.PNext = null;
|
|
||||||
robustness2Features.RobustBufferAccess2 =
|
|
||||||
supportsRobustImageAccess2 && supportedFeatures.RobustBufferAccess;
|
|
||||||
robustness2Features.RobustImageAccess2 = supportsRobustImageAccess2;
|
|
||||||
robustness2Features.NullDescriptor = supportsNullDescriptor;
|
|
||||||
robustness2Features.PNext = supportsMaintenance8 ? &maintenance8Features : null;
|
|
||||||
var features2 = new PhysicalDeviceFeatures2
|
|
||||||
{
|
|
||||||
SType = StructureType.PhysicalDeviceFeatures2,
|
|
||||||
PNext = supportsRobustness2
|
|
||||||
? &robustness2Features
|
|
||||||
: (supportsMaintenance8 ? &maintenance8Features : null),
|
|
||||||
Features = enabledFeatures,
|
|
||||||
};
|
|
||||||
var createInfo = new DeviceCreateInfo
|
var createInfo = new DeviceCreateInfo
|
||||||
{
|
{
|
||||||
SType = StructureType.DeviceCreateInfo,
|
SType = StructureType.DeviceCreateInfo,
|
||||||
PNext = &features2,
|
|
||||||
QueueCreateInfoCount = 1,
|
QueueCreateInfoCount = 1,
|
||||||
PQueueCreateInfos = &queueInfo,
|
PQueueCreateInfos = &queueInfo,
|
||||||
EnabledExtensionCount = extensionCount,
|
EnabledExtensionCount = 1,
|
||||||
PpEnabledExtensionNames = extensions,
|
PpEnabledExtensionNames = &swapchainExtension,
|
||||||
|
PEnabledFeatures = &enabledFeatures,
|
||||||
};
|
};
|
||||||
|
|
||||||
Check(_vk.CreateDevice(_physicalDevice, &createInfo, null, out _device), "vkCreateDevice");
|
Check(_vk.CreateDevice(_physicalDevice, &createInfo, null, out _device), "vkCreateDevice");
|
||||||
@@ -1583,8 +1493,6 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
SilkMarshal.Free((nint)swapchainExtension);
|
SilkMarshal.Free((nint)swapchainExtension);
|
||||||
SilkMarshal.Free((nint)maintenance8Extension);
|
|
||||||
SilkMarshal.Free((nint)robustness2Extension);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_vk.GetDeviceQueue(_device, _queueFamilyIndex, 0, out _queue);
|
_vk.GetDeviceQueue(_device, _queueFamilyIndex, 0, out _queue);
|
||||||
@@ -1749,39 +1657,6 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
resources.DebugName));
|
resources.DebugName));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SubmitGuestCommandBufferAndWait(CommandBuffer commandBuffer)
|
|
||||||
{
|
|
||||||
var fenceInfo = new FenceCreateInfo
|
|
||||||
{
|
|
||||||
SType = StructureType.FenceCreateInfo,
|
|
||||||
};
|
|
||||||
Fence fence;
|
|
||||||
Check(
|
|
||||||
_vk.CreateFence(_device, &fenceInfo, null, out fence),
|
|
||||||
"vkCreateFence(guest chunk)");
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var submitInfo = new SubmitInfo
|
|
||||||
{
|
|
||||||
SType = StructureType.SubmitInfo,
|
|
||||||
CommandBufferCount = 1,
|
|
||||||
PCommandBuffers = &commandBuffer,
|
|
||||||
};
|
|
||||||
Check(
|
|
||||||
_vk.QueueSubmit(_queue, 1, &submitInfo, fence),
|
|
||||||
"vkQueueSubmit(guest chunk)");
|
|
||||||
Check(
|
|
||||||
_vk.WaitForFences(_device, 1, &fence, true, ulong.MaxValue),
|
|
||||||
"vkWaitForFences(guest chunk)");
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_vk.DestroyFence(_device, fence, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
_vk.FreeCommandBuffers(_device, _commandPool, 1, &commandBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EnsureGuestSubmissionCapacity()
|
private void EnsureGuestSubmissionCapacity()
|
||||||
{
|
{
|
||||||
CollectCompletedGuestSubmissions(waitForOldest: false);
|
CollectCompletedGuestSubmissions(waitForOldest: false);
|
||||||
@@ -2766,7 +2641,6 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
var pipelineInfo = new ComputePipelineCreateInfo
|
var pipelineInfo = new ComputePipelineCreateInfo
|
||||||
{
|
{
|
||||||
SType = StructureType.ComputePipelineCreateInfo,
|
SType = StructureType.ComputePipelineCreateInfo,
|
||||||
Flags = PipelineCreateFlags.CreateDispatchBaseBit,
|
|
||||||
Stage = stage,
|
Stage = stage,
|
||||||
Layout = resources.PipelineLayout,
|
Layout = resources.PipelineLayout,
|
||||||
};
|
};
|
||||||
@@ -3112,13 +2986,9 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
}
|
}
|
||||||
_vk.UnmapMemory(_device, stagingMemory);
|
_vk.UnmapMemory(_device, stagingMemory);
|
||||||
|
|
||||||
var supportsAttachmentUsage = !IsBlockCompressedFormat(vkFormat);
|
|
||||||
var imageInfo = new ImageCreateInfo
|
var imageInfo = new ImageCreateInfo
|
||||||
{
|
{
|
||||||
SType = StructureType.ImageCreateInfo,
|
SType = StructureType.ImageCreateInfo,
|
||||||
Flags = supportsAttachmentUsage
|
|
||||||
? ImageCreateFlags.CreateMutableFormatBit | ImageCreateFlags.CreateExtendedUsageBit
|
|
||||||
: 0,
|
|
||||||
ImageType = ImageType.Type2D,
|
ImageType = ImageType.Type2D,
|
||||||
Format = vkFormat,
|
Format = vkFormat,
|
||||||
Extent = new Extent3D(width, height, 1),
|
Extent = new Extent3D(width, height, 1),
|
||||||
@@ -3126,13 +2996,7 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
ArrayLayers = 1,
|
ArrayLayers = 1,
|
||||||
Samples = SampleCountFlags.Count1Bit,
|
Samples = SampleCountFlags.Count1Bit,
|
||||||
Tiling = ImageTiling.Optimal,
|
Tiling = ImageTiling.Optimal,
|
||||||
Usage = supportsAttachmentUsage
|
Usage = ImageUsageFlags.TransferDstBit | ImageUsageFlags.SampledBit,
|
||||||
? ImageUsageFlags.TransferDstBit |
|
|
||||||
ImageUsageFlags.SampledBit |
|
|
||||||
ImageUsageFlags.ColorAttachmentBit |
|
|
||||||
ImageUsageFlags.StorageBit |
|
|
||||||
ImageUsageFlags.TransferSrcBit
|
|
||||||
: ImageUsageFlags.TransferDstBit | ImageUsageFlags.SampledBit,
|
|
||||||
SharingMode = SharingMode.Exclusive,
|
SharingMode = SharingMode.Exclusive,
|
||||||
InitialLayout = ImageLayout.Undefined,
|
InitialLayout = ImageLayout.Undefined,
|
||||||
};
|
};
|
||||||
@@ -3967,12 +3831,6 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
_ => Format.Undefined,
|
_ => Format.Undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
private static bool IsBlockCompressedFormat(Format format) =>
|
|
||||||
format is Format.BC1RgbaUnormBlock or
|
|
||||||
Format.BC1RgbaSrgbBlock or
|
|
||||||
Format.BC7UnormBlock or
|
|
||||||
Format.BC7SrgbBlock;
|
|
||||||
|
|
||||||
private VkBuffer CreateBuffer(
|
private VkBuffer CreateBuffer(
|
||||||
ulong size,
|
ulong size,
|
||||||
BufferUsageFlags usage,
|
BufferUsageFlags usage,
|
||||||
@@ -4026,19 +3884,8 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
throw new InvalidOperationException("No compatible Vulkan host-visible memory type was found.");
|
throw new InvalidOperationException("No compatible Vulkan host-visible memory type was found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private const uint MaxComputeZSlicesPerSubmission = 8;
|
|
||||||
|
|
||||||
private void ExecuteComputeDispatch(VulkanComputeGuestDispatch work)
|
private void ExecuteComputeDispatch(VulkanComputeGuestDispatch work)
|
||||||
{
|
{
|
||||||
if (AddressListContains("SHARPEMU_SKIP_COMPUTE_CS", work.ShaderAddress))
|
|
||||||
{
|
|
||||||
TraceVulkanShader(
|
|
||||||
$"vk.compute_skip cs=0x{work.ShaderAddress:X16} " +
|
|
||||||
$"groups={work.GroupCountX}x{work.GroupCountY}x{work.GroupCountZ} " +
|
|
||||||
$"textures={work.Textures.Count}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TranslatedDrawResources? resources = null;
|
TranslatedDrawResources? resources = null;
|
||||||
CommandBuffer commandBuffer = default;
|
CommandBuffer commandBuffer = default;
|
||||||
var submitted = false;
|
var submitted = false;
|
||||||
@@ -4046,95 +3893,59 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
{
|
{
|
||||||
EnsureGuestSubmissionCapacity();
|
EnsureGuestSubmissionCapacity();
|
||||||
resources = CreateComputeDispatchResources(work);
|
resources = CreateComputeDispatchResources(work);
|
||||||
|
commandBuffer = AllocateGuestCommandBuffer();
|
||||||
var batchCount = Math.Max(
|
_commandBuffer = commandBuffer;
|
||||||
1u,
|
var beginInfo = new CommandBufferBeginInfo
|
||||||
(uint)Math.Ceiling(work.GroupCountZ / (double)MaxComputeZSlicesPerSubmission));
|
|
||||||
|
|
||||||
for (var batchIndex = 0u; batchIndex < batchCount; batchIndex++)
|
|
||||||
{
|
{
|
||||||
var zStart = batchIndex * MaxComputeZSlicesPerSubmission;
|
SType = StructureType.CommandBufferBeginInfo,
|
||||||
var zCount = Math.Min(MaxComputeZSlicesPerSubmission, work.GroupCountZ - zStart);
|
Flags = CommandBufferUsageFlags.OneTimeSubmitBit,
|
||||||
var isFirstBatch = batchIndex == 0;
|
};
|
||||||
var isLastBatch = batchIndex == batchCount - 1;
|
Check(
|
||||||
|
_vk.BeginCommandBuffer(_commandBuffer, &beginInfo),
|
||||||
|
"vkBeginCommandBuffer(compute)");
|
||||||
|
|
||||||
commandBuffer = AllocateGuestCommandBuffer();
|
BeginDebugLabel(_commandBuffer, resources.DebugName);
|
||||||
_commandBuffer = commandBuffer;
|
RecordTextureUploads(resources, PipelineStageFlags.ComputeShaderBit);
|
||||||
var beginInfo = new CommandBufferBeginInfo
|
RecordStorageImagesForWrite(resources, PipelineStageFlags.ComputeShaderBit);
|
||||||
{
|
_vk.CmdBindPipeline(
|
||||||
SType = StructureType.CommandBufferBeginInfo,
|
_commandBuffer,
|
||||||
Flags = CommandBufferUsageFlags.OneTimeSubmitBit,
|
PipelineBindPoint.Compute,
|
||||||
};
|
resources.Pipeline);
|
||||||
Check(
|
if (resources.DescriptorSet.Handle != 0)
|
||||||
_vk.BeginCommandBuffer(_commandBuffer, &beginInfo),
|
{
|
||||||
"vkBeginCommandBuffer(compute)");
|
var descriptorSet = resources.DescriptorSet;
|
||||||
|
_vk.CmdBindDescriptorSets(
|
||||||
BeginDebugLabel(_commandBuffer, resources.DebugName);
|
|
||||||
if (isFirstBatch)
|
|
||||||
{
|
|
||||||
RecordTextureUploads(resources, PipelineStageFlags.ComputeShaderBit);
|
|
||||||
RecordStorageImagesForWrite(resources, PipelineStageFlags.ComputeShaderBit);
|
|
||||||
}
|
|
||||||
|
|
||||||
_vk.CmdBindPipeline(
|
|
||||||
_commandBuffer,
|
_commandBuffer,
|
||||||
PipelineBindPoint.Compute,
|
PipelineBindPoint.Compute,
|
||||||
resources.Pipeline);
|
resources.PipelineLayout,
|
||||||
if (resources.DescriptorSet.Handle != 0)
|
0,
|
||||||
{
|
1,
|
||||||
var descriptorSet = resources.DescriptorSet;
|
&descriptorSet,
|
||||||
_vk.CmdBindDescriptorSets(
|
0,
|
||||||
_commandBuffer,
|
null);
|
||||||
PipelineBindPoint.Compute,
|
|
||||||
resources.PipelineLayout,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
&descriptorSet,
|
|
||||||
0,
|
|
||||||
null);
|
|
||||||
}
|
|
||||||
|
|
||||||
RecordChunkedComputeDispatch(_commandBuffer, work, zStart, zCount);
|
|
||||||
|
|
||||||
if (isLastBatch)
|
|
||||||
{
|
|
||||||
RecordStorageImagesForRead(resources, PipelineStageFlags.ComputeShaderBit);
|
|
||||||
}
|
|
||||||
|
|
||||||
EndDebugLabel(_commandBuffer);
|
|
||||||
Check(_vk.EndCommandBuffer(_commandBuffer), "vkEndCommandBuffer(compute)");
|
|
||||||
|
|
||||||
TraceVulkanShader(
|
|
||||||
$"vk.compute_submit cs=0x{work.ShaderAddress:X16} " +
|
|
||||||
$"batch={batchIndex}/{batchCount} z={zStart}..{zStart + zCount}");
|
|
||||||
if (isLastBatch)
|
|
||||||
{
|
|
||||||
SubmitGuestCommandBuffer(
|
|
||||||
commandBuffer,
|
|
||||||
resources,
|
|
||||||
GetTraceImages(resources));
|
|
||||||
submitted = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SubmitGuestCommandBufferAndWait(commandBuffer);
|
|
||||||
commandBuffer = default;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RecordChunkedComputeDispatch(_commandBuffer, work);
|
||||||
|
RecordStorageImagesForRead(resources, PipelineStageFlags.ComputeShaderBit);
|
||||||
|
EndDebugLabel(_commandBuffer);
|
||||||
|
|
||||||
|
Check(_vk.EndCommandBuffer(_commandBuffer), "vkEndCommandBuffer(compute)");
|
||||||
|
SubmitGuestCommandBuffer(
|
||||||
|
commandBuffer,
|
||||||
|
resources,
|
||||||
|
GetTraceImages(resources));
|
||||||
|
submitted = true;
|
||||||
MarkSampledImagesInitialized(resources);
|
MarkSampledImagesInitialized(resources);
|
||||||
MarkStorageImagesInitialized(resources, traceContents: false);
|
MarkStorageImagesInitialized(resources, traceContents: false);
|
||||||
TraceVulkanShader(
|
TraceVulkanShader(
|
||||||
$"vk.compute_dispatch groups={work.GroupCountX}x" +
|
$"vk.compute_dispatch groups={work.GroupCountX}x" +
|
||||||
$"{work.GroupCountY}x{work.GroupCountZ} " +
|
$"{work.GroupCountY}x{work.GroupCountZ} " +
|
||||||
$"textures={work.Textures.Count} cs=0x{work.ShaderAddress:X16} " +
|
$"textures={work.Textures.Count} cs=0x{work.ShaderAddress:X16}");
|
||||||
$"batches={batchCount}");
|
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine(
|
Console.Error.WriteLine(
|
||||||
$"[LOADER][ERROR] Vulkan compute dispatch failed " +
|
$"[LOADER][ERROR] Vulkan compute dispatch failed: {exception.Message}");
|
||||||
$"cs=0x{work.ShaderAddress:X16}: {exception.Message}");
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -4157,9 +3968,7 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
|
|
||||||
private void RecordChunkedComputeDispatch(
|
private void RecordChunkedComputeDispatch(
|
||||||
CommandBuffer commandBuffer,
|
CommandBuffer commandBuffer,
|
||||||
VulkanComputeGuestDispatch work,
|
VulkanComputeGuestDispatch work)
|
||||||
uint zStart,
|
|
||||||
uint zCount)
|
|
||||||
{
|
{
|
||||||
const uint maxWorkgroupsPerCommand = 4096;
|
const uint maxWorkgroupsPerCommand = 4096;
|
||||||
var yChunk = Math.Max(
|
var yChunk = Math.Max(
|
||||||
@@ -4169,7 +3978,7 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
maxWorkgroupsPerCommand / Math.Max(work.GroupCountX, 1u)));
|
maxWorkgroupsPerCommand / Math.Max(work.GroupCountX, 1u)));
|
||||||
var commandCount = 0u;
|
var commandCount = 0u;
|
||||||
|
|
||||||
for (var z = zStart; z < zStart + zCount; z++)
|
for (var z = 0u; z < work.GroupCountZ; z++)
|
||||||
{
|
{
|
||||||
for (var y = 0u; y < work.GroupCountY; y += yChunk)
|
for (var y = 0u; y < work.GroupCountY; y += yChunk)
|
||||||
{
|
{
|
||||||
@@ -4191,7 +4000,7 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
TraceVulkanShader(
|
TraceVulkanShader(
|
||||||
$"vk.compute_chunked cs=0x{work.ShaderAddress:X16} " +
|
$"vk.compute_chunked cs=0x{work.ShaderAddress:X16} " +
|
||||||
$"groups={work.GroupCountX}x{work.GroupCountY}x{work.GroupCountZ} " +
|
$"groups={work.GroupCountX}x{work.GroupCountY}x{work.GroupCountZ} " +
|
||||||
$"z_range={zStart}..{zStart + zCount} commands={commandCount} y_chunk={yChunk}");
|
$"commands={commandCount} y_chunk={yChunk}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4399,23 +4208,6 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
existing.MipLevels == mipLevels &&
|
existing.MipLevels == mipLevels &&
|
||||||
existing.Format == format)
|
existing.Format == format)
|
||||||
{
|
{
|
||||||
if (existing.RenderPass.Handle == 0)
|
|
||||||
{
|
|
||||||
var attachmentView = existing.MipViews.Length > 0
|
|
||||||
? existing.MipViews[0]
|
|
||||||
: existing.View;
|
|
||||||
var (promotedRenderPass, promotedFramebuffer) = CreateRenderPassAndFramebuffer(
|
|
||||||
existing.Format,
|
|
||||||
attachmentView,
|
|
||||||
existing.Width,
|
|
||||||
existing.Height);
|
|
||||||
existing.RenderPass = promotedRenderPass;
|
|
||||||
existing.Framebuffer = promotedFramebuffer;
|
|
||||||
var promotedName = GuestImageDebugName(target, format);
|
|
||||||
SetDebugName(ObjectType.RenderPass, promotedRenderPass.Handle, $"{promotedName} renderpass");
|
|
||||||
SetDebugName(ObjectType.Framebuffer, promotedFramebuffer.Handle, $"{promotedName} framebuffer");
|
|
||||||
}
|
|
||||||
|
|
||||||
return existing;
|
return existing;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4496,48 +4288,6 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
mipViews[mipLevel] = mipView;
|
mipViews[mipLevel] = mipView;
|
||||||
}
|
}
|
||||||
|
|
||||||
var (renderPass, framebuffer) = CreateRenderPassAndFramebuffer(
|
|
||||||
format,
|
|
||||||
mipViews[0],
|
|
||||||
target.Width,
|
|
||||||
target.Height);
|
|
||||||
|
|
||||||
var resource = new GuestImageResource
|
|
||||||
{
|
|
||||||
Address = target.Address,
|
|
||||||
Width = target.Width,
|
|
||||||
Height = target.Height,
|
|
||||||
MipLevels = mipLevels,
|
|
||||||
Format = format,
|
|
||||||
Image = image,
|
|
||||||
Memory = memory,
|
|
||||||
View = view,
|
|
||||||
MipViews = mipViews,
|
|
||||||
RenderPass = renderPass,
|
|
||||||
Framebuffer = framebuffer,
|
|
||||||
};
|
|
||||||
var debugName = GuestImageDebugName(target, format);
|
|
||||||
SetDebugName(ObjectType.Image, image.Handle, $"{debugName} image");
|
|
||||||
SetDebugName(ObjectType.ImageView, view.Handle, $"{debugName} view");
|
|
||||||
for (var mipLevel = 0; mipLevel < mipViews.Length; mipLevel++)
|
|
||||||
{
|
|
||||||
SetDebugName(
|
|
||||||
ObjectType.ImageView,
|
|
||||||
mipViews[mipLevel].Handle,
|
|
||||||
$"{debugName} mip{mipLevel}");
|
|
||||||
}
|
|
||||||
SetDebugName(ObjectType.RenderPass, renderPass.Handle, $"{debugName} renderpass");
|
|
||||||
SetDebugName(ObjectType.Framebuffer, framebuffer.Handle, $"{debugName} framebuffer");
|
|
||||||
_guestImages.Add(target.Address, resource);
|
|
||||||
return resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
private (RenderPass RenderPass, Framebuffer Framebuffer) CreateRenderPassAndFramebuffer(
|
|
||||||
Format format,
|
|
||||||
ImageView attachmentView,
|
|
||||||
uint width,
|
|
||||||
uint height)
|
|
||||||
{
|
|
||||||
var colorAttachment = new AttachmentDescription
|
var colorAttachment = new AttachmentDescription
|
||||||
{
|
{
|
||||||
Format = format,
|
Format = format,
|
||||||
@@ -4572,22 +4322,49 @@ internal static unsafe class VulkanVideoPresenter
|
|||||||
_vk.CreateRenderPass(_device, &renderPassInfo, null, out var renderPass),
|
_vk.CreateRenderPass(_device, &renderPassInfo, null, out var renderPass),
|
||||||
"vkCreateRenderPass(offscreen)");
|
"vkCreateRenderPass(offscreen)");
|
||||||
|
|
||||||
var attachment = attachmentView;
|
var attachment = mipViews[0];
|
||||||
var framebufferInfo = new FramebufferCreateInfo
|
var framebufferInfo = new FramebufferCreateInfo
|
||||||
{
|
{
|
||||||
SType = StructureType.FramebufferCreateInfo,
|
SType = StructureType.FramebufferCreateInfo,
|
||||||
RenderPass = renderPass,
|
RenderPass = renderPass,
|
||||||
AttachmentCount = 1,
|
AttachmentCount = 1,
|
||||||
PAttachments = &attachment,
|
PAttachments = &attachment,
|
||||||
Width = width,
|
Width = target.Width,
|
||||||
Height = height,
|
Height = target.Height,
|
||||||
Layers = 1,
|
Layers = 1,
|
||||||
};
|
};
|
||||||
Check(
|
Check(
|
||||||
_vk.CreateFramebuffer(_device, &framebufferInfo, null, out var framebuffer),
|
_vk.CreateFramebuffer(_device, &framebufferInfo, null, out var framebuffer),
|
||||||
"vkCreateFramebuffer(offscreen)");
|
"vkCreateFramebuffer(offscreen)");
|
||||||
|
|
||||||
return (renderPass, framebuffer);
|
var resource = new GuestImageResource
|
||||||
|
{
|
||||||
|
Address = target.Address,
|
||||||
|
Width = target.Width,
|
||||||
|
Height = target.Height,
|
||||||
|
MipLevels = mipLevels,
|
||||||
|
Format = format,
|
||||||
|
Image = image,
|
||||||
|
Memory = memory,
|
||||||
|
View = view,
|
||||||
|
MipViews = mipViews,
|
||||||
|
RenderPass = renderPass,
|
||||||
|
Framebuffer = framebuffer,
|
||||||
|
};
|
||||||
|
var debugName = GuestImageDebugName(target, format);
|
||||||
|
SetDebugName(ObjectType.Image, image.Handle, $"{debugName} image");
|
||||||
|
SetDebugName(ObjectType.ImageView, view.Handle, $"{debugName} view");
|
||||||
|
for (var mipLevel = 0; mipLevel < mipViews.Length; mipLevel++)
|
||||||
|
{
|
||||||
|
SetDebugName(
|
||||||
|
ObjectType.ImageView,
|
||||||
|
mipViews[mipLevel].Handle,
|
||||||
|
$"{debugName} mip{mipLevel}");
|
||||||
|
}
|
||||||
|
SetDebugName(ObjectType.RenderPass, renderPass.Handle, $"{debugName} renderpass");
|
||||||
|
SetDebugName(ObjectType.Framebuffer, framebuffer.Handle, $"{debugName} framebuffer");
|
||||||
|
_guestImages.Add(target.Address, resource);
|
||||||
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static uint ClampMipLevels(uint width, uint height, uint requestedMipLevels)
|
private static uint ClampMipLevels(uint width, uint height, uint requestedMipLevels)
|
||||||
|
|||||||
Reference in New Issue
Block a user