mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-07-25 10:37:11 +02:00
EXPERIMENTAL: Metal backend (#441)
This is not a continuation of the Metal backend; this is simply bringing the branch up to date and merging it as-is behind an experiment. --------- Co-authored-by: Isaac Marovitz <isaacryu@icloud.com> Co-authored-by: Samuliak <samuliak77@gmail.com> Co-authored-by: SamoZ256 <96914946+SamoZ256@users.noreply.github.com> Co-authored-by: Isaac Marovitz <42140194+IsaacMarovitz@users.noreply.github.com> Co-authored-by: riperiperi <rhy3756547@hotmail.com> Co-authored-by: Gabriel A <gab.dark.100@gmail.com>
This commit is contained in:
parent
3094df54dd
commit
852823104f
131 changed files with 14992 additions and 140 deletions
43
src/Ryujinx.Graphics.Metal/Shaders/Blit.metal
Normal file
43
src/Ryujinx.Graphics.Metal/Shaders/Blit.metal
Normal file
|
@ -0,0 +1,43 @@
|
|||
#include <metal_stdlib>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct CopyVertexOut {
|
||||
float4 position [[position]];
|
||||
float2 uv;
|
||||
};
|
||||
|
||||
struct TexCoords {
|
||||
float data[4];
|
||||
};
|
||||
|
||||
struct ConstantBuffers {
|
||||
constant TexCoords* tex_coord;
|
||||
};
|
||||
|
||||
struct Textures
|
||||
{
|
||||
texture2d<FORMAT, access::sample> texture;
|
||||
sampler sampler;
|
||||
};
|
||||
|
||||
vertex CopyVertexOut vertexMain(uint vid [[vertex_id]],
|
||||
constant ConstantBuffers &constant_buffers [[buffer(CONSTANT_BUFFERS_INDEX)]]) {
|
||||
CopyVertexOut out;
|
||||
|
||||
int low = vid & 1;
|
||||
int high = vid >> 1;
|
||||
out.uv.x = constant_buffers.tex_coord->data[low];
|
||||
out.uv.y = constant_buffers.tex_coord->data[2 + high];
|
||||
out.position.x = (float(low) - 0.5f) * 2.0f;
|
||||
out.position.y = (float(high) - 0.5f) * 2.0f;
|
||||
out.position.z = 0.0f;
|
||||
out.position.w = 1.0f;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
fragment FORMAT4 fragmentMain(CopyVertexOut in [[stage_in]],
|
||||
constant Textures &textures [[buffer(TEXTURES_INDEX)]]) {
|
||||
return textures.texture.sample(textures.sampler, in.uv);
|
||||
}
|
45
src/Ryujinx.Graphics.Metal/Shaders/BlitMs.metal
Normal file
45
src/Ryujinx.Graphics.Metal/Shaders/BlitMs.metal
Normal file
|
@ -0,0 +1,45 @@
|
|||
#include <metal_stdlib>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct CopyVertexOut {
|
||||
float4 position [[position]];
|
||||
float2 uv;
|
||||
};
|
||||
|
||||
struct TexCoords {
|
||||
float data[4];
|
||||
};
|
||||
|
||||
struct ConstantBuffers {
|
||||
constant TexCoords* tex_coord;
|
||||
};
|
||||
|
||||
struct Textures
|
||||
{
|
||||
texture2d_ms<FORMAT, access::read> texture;
|
||||
};
|
||||
|
||||
vertex CopyVertexOut vertexMain(uint vid [[vertex_id]],
|
||||
constant ConstantBuffers &constant_buffers [[buffer(CONSTANT_BUFFERS_INDEX)]]) {
|
||||
CopyVertexOut out;
|
||||
|
||||
int low = vid & 1;
|
||||
int high = vid >> 1;
|
||||
out.uv.x = constant_buffers.tex_coord->data[low];
|
||||
out.uv.y = constant_buffers.tex_coord->data[2 + high];
|
||||
out.position.x = (float(low) - 0.5f) * 2.0f;
|
||||
out.position.y = (float(high) - 0.5f) * 2.0f;
|
||||
out.position.z = 0.0f;
|
||||
out.position.w = 1.0f;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
fragment FORMAT4 fragmentMain(CopyVertexOut in [[stage_in]],
|
||||
constant Textures &textures [[buffer(TEXTURES_INDEX)]],
|
||||
uint sample_id [[sample_id]]) {
|
||||
uint2 tex_size = uint2(textures.texture.get_width(), textures.texture.get_height());
|
||||
uint2 tex_coord = uint2(in.uv * float2(tex_size));
|
||||
return textures.texture.read(tex_coord, sample_id);
|
||||
}
|
72
src/Ryujinx.Graphics.Metal/Shaders/ChangeBufferStride.metal
Normal file
72
src/Ryujinx.Graphics.Metal/Shaders/ChangeBufferStride.metal
Normal file
|
@ -0,0 +1,72 @@
|
|||
#include <metal_stdlib>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct StrideArguments {
|
||||
int4 data;
|
||||
};
|
||||
|
||||
struct InData {
|
||||
uint8_t data[1];
|
||||
};
|
||||
|
||||
struct OutData {
|
||||
uint8_t data[1];
|
||||
};
|
||||
|
||||
struct ConstantBuffers {
|
||||
constant StrideArguments* stride_arguments;
|
||||
};
|
||||
|
||||
struct StorageBuffers {
|
||||
device InData* in_data;
|
||||
device OutData* out_data;
|
||||
};
|
||||
|
||||
kernel void kernelMain(constant ConstantBuffers &constant_buffers [[buffer(CONSTANT_BUFFERS_INDEX)]],
|
||||
device StorageBuffers &storage_buffers [[buffer(STORAGE_BUFFERS_INDEX)]],
|
||||
uint3 thread_position_in_grid [[thread_position_in_grid]],
|
||||
uint3 threads_per_threadgroup [[threads_per_threadgroup]],
|
||||
uint3 threadgroups_per_grid [[threadgroups_per_grid]])
|
||||
{
|
||||
// Determine what slice of the stride copies this invocation will perform.
|
||||
|
||||
int sourceStride = constant_buffers.stride_arguments->data.x;
|
||||
int targetStride = constant_buffers.stride_arguments->data.y;
|
||||
int bufferSize = constant_buffers.stride_arguments->data.z;
|
||||
int sourceOffset = constant_buffers.stride_arguments->data.w;
|
||||
|
||||
int strideRemainder = targetStride - sourceStride;
|
||||
int invocations = int(threads_per_threadgroup.x * threadgroups_per_grid.x);
|
||||
|
||||
int copiesRequired = bufferSize / sourceStride;
|
||||
|
||||
// Find the copies that this invocation should perform.
|
||||
|
||||
// - Copies that all invocations perform.
|
||||
int allInvocationCopies = copiesRequired / invocations;
|
||||
|
||||
// - Extra remainder copy that this invocation performs.
|
||||
int index = int(thread_position_in_grid.x);
|
||||
int extra = (index < (copiesRequired % invocations)) ? 1 : 0;
|
||||
|
||||
int copyCount = allInvocationCopies + extra;
|
||||
|
||||
// Finally, get the starting offset. Make sure to count extra copies.
|
||||
|
||||
int startCopy = allInvocationCopies * index + min(copiesRequired % invocations, index);
|
||||
|
||||
int srcOffset = sourceOffset + startCopy * sourceStride;
|
||||
int dstOffset = startCopy * targetStride;
|
||||
|
||||
// Perform the copies for this region
|
||||
for (int i = 0; i < copyCount; i++) {
|
||||
for (int j = 0; j < sourceStride; j++) {
|
||||
storage_buffers.out_data->data[dstOffset++] = storage_buffers.in_data->data[srcOffset++];
|
||||
}
|
||||
|
||||
for (int j = 0; j < strideRemainder; j++) {
|
||||
storage_buffers.out_data->data[dstOffset++] = uint8_t(0);
|
||||
}
|
||||
}
|
||||
}
|
38
src/Ryujinx.Graphics.Metal/Shaders/ColorClear.metal
Normal file
38
src/Ryujinx.Graphics.Metal/Shaders/ColorClear.metal
Normal file
|
@ -0,0 +1,38 @@
|
|||
#include <metal_stdlib>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct VertexOut {
|
||||
float4 position [[position]];
|
||||
};
|
||||
|
||||
struct ClearColor {
|
||||
FORMAT4 data;
|
||||
};
|
||||
|
||||
struct ConstantBuffers {
|
||||
constant ClearColor* clear_color;
|
||||
};
|
||||
|
||||
vertex VertexOut vertexMain(ushort vid [[vertex_id]]) {
|
||||
int low = vid & 1;
|
||||
int high = vid >> 1;
|
||||
|
||||
VertexOut out;
|
||||
|
||||
out.position.x = (float(low) - 0.5f) * 2.0f;
|
||||
out.position.y = (float(high) - 0.5f) * 2.0f;
|
||||
out.position.z = 0.0f;
|
||||
out.position.w = 1.0f;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
struct FragmentOut {
|
||||
FORMAT4 color [[color(COLOR_ATTACHMENT_INDEX)]];
|
||||
};
|
||||
|
||||
fragment FragmentOut fragmentMain(VertexOut in [[stage_in]],
|
||||
constant ConstantBuffers &constant_buffers [[buffer(CONSTANT_BUFFERS_INDEX)]]) {
|
||||
return {constant_buffers.clear_color->data};
|
||||
}
|
66
src/Ryujinx.Graphics.Metal/Shaders/ConvertD32S8ToD24S8.metal
Normal file
66
src/Ryujinx.Graphics.Metal/Shaders/ConvertD32S8ToD24S8.metal
Normal file
|
@ -0,0 +1,66 @@
|
|||
#include <metal_stdlib>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct StrideArguments {
|
||||
int pixelCount;
|
||||
int dstStartOffset;
|
||||
};
|
||||
|
||||
struct InData {
|
||||
uint data[1];
|
||||
};
|
||||
|
||||
struct OutData {
|
||||
uint data[1];
|
||||
};
|
||||
|
||||
struct ConstantBuffers {
|
||||
constant StrideArguments* stride_arguments;
|
||||
};
|
||||
|
||||
struct StorageBuffers {
|
||||
device InData* in_data;
|
||||
device OutData* out_data;
|
||||
};
|
||||
|
||||
kernel void kernelMain(constant ConstantBuffers &constant_buffers [[buffer(CONSTANT_BUFFERS_INDEX)]],
|
||||
device StorageBuffers &storage_buffers [[buffer(STORAGE_BUFFERS_INDEX)]],
|
||||
uint3 thread_position_in_grid [[thread_position_in_grid]],
|
||||
uint3 threads_per_threadgroup [[threads_per_threadgroup]],
|
||||
uint3 threadgroups_per_grid [[threadgroups_per_grid]])
|
||||
{
|
||||
// Determine what slice of the stride copies this invocation will perform.
|
||||
int invocations = int(threads_per_threadgroup.x * threadgroups_per_grid.x);
|
||||
|
||||
int copiesRequired = constant_buffers.stride_arguments->pixelCount;
|
||||
|
||||
// Find the copies that this invocation should perform.
|
||||
|
||||
// - Copies that all invocations perform.
|
||||
int allInvocationCopies = copiesRequired / invocations;
|
||||
|
||||
// - Extra remainder copy that this invocation performs.
|
||||
int index = int(thread_position_in_grid.x);
|
||||
int extra = (index < (copiesRequired % invocations)) ? 1 : 0;
|
||||
|
||||
int copyCount = allInvocationCopies + extra;
|
||||
|
||||
// Finally, get the starting offset. Make sure to count extra copies.
|
||||
|
||||
int startCopy = allInvocationCopies * index + min(copiesRequired % invocations, index);
|
||||
|
||||
int srcOffset = startCopy * 2;
|
||||
int dstOffset = constant_buffers.stride_arguments->dstStartOffset + startCopy;
|
||||
|
||||
// Perform the conversion for this region.
|
||||
for (int i = 0; i < copyCount; i++)
|
||||
{
|
||||
float depth = as_type<float>(storage_buffers.in_data->data[srcOffset++]);
|
||||
uint stencil = storage_buffers.in_data->data[srcOffset++];
|
||||
|
||||
uint rescaledDepth = uint(clamp(depth, 0.0, 1.0) * 16777215.0);
|
||||
|
||||
storage_buffers.out_data->data[dstOffset++] = (rescaledDepth << 8) | (stencil & 0xff);
|
||||
}
|
||||
}
|
59
src/Ryujinx.Graphics.Metal/Shaders/ConvertIndexBuffer.metal
Normal file
59
src/Ryujinx.Graphics.Metal/Shaders/ConvertIndexBuffer.metal
Normal file
|
@ -0,0 +1,59 @@
|
|||
#include <metal_stdlib>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct IndexBufferPattern {
|
||||
int pattern[8];
|
||||
int primitiveVertices;
|
||||
int primitiveVerticesOut;
|
||||
int indexSize;
|
||||
int indexSizeOut;
|
||||
int baseIndex;
|
||||
int indexStride;
|
||||
int srcOffset;
|
||||
int totalPrimitives;
|
||||
};
|
||||
|
||||
struct InData {
|
||||
uint8_t data[1];
|
||||
};
|
||||
|
||||
struct OutData {
|
||||
uint8_t data[1];
|
||||
};
|
||||
|
||||
struct StorageBuffers {
|
||||
device InData* in_data;
|
||||
device OutData* out_data;
|
||||
constant IndexBufferPattern* index_buffer_pattern;
|
||||
};
|
||||
|
||||
kernel void kernelMain(device StorageBuffers &storage_buffers [[buffer(STORAGE_BUFFERS_INDEX)]],
|
||||
uint3 thread_position_in_grid [[thread_position_in_grid]])
|
||||
{
|
||||
int primitiveIndex = int(thread_position_in_grid.x);
|
||||
if (primitiveIndex >= storage_buffers.index_buffer_pattern->totalPrimitives)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int inOffset = primitiveIndex * storage_buffers.index_buffer_pattern->indexStride;
|
||||
int outOffset = primitiveIndex * storage_buffers.index_buffer_pattern->primitiveVerticesOut;
|
||||
|
||||
for (int i = 0; i < storage_buffers.index_buffer_pattern->primitiveVerticesOut; i++)
|
||||
{
|
||||
int j;
|
||||
int io = max(0, inOffset + storage_buffers.index_buffer_pattern->baseIndex + storage_buffers.index_buffer_pattern->pattern[i]) * storage_buffers.index_buffer_pattern->indexSize;
|
||||
int oo = (outOffset + i) * storage_buffers.index_buffer_pattern->indexSizeOut;
|
||||
|
||||
for (j = 0; j < storage_buffers.index_buffer_pattern->indexSize; j++)
|
||||
{
|
||||
storage_buffers.out_data->data[oo + j] = storage_buffers.in_data->data[storage_buffers.index_buffer_pattern->srcOffset + io + j];
|
||||
}
|
||||
|
||||
for(; j < storage_buffers.index_buffer_pattern->indexSizeOut; j++)
|
||||
{
|
||||
storage_buffers.out_data->data[oo + j] = uint8_t(0);
|
||||
}
|
||||
}
|
||||
}
|
27
src/Ryujinx.Graphics.Metal/Shaders/DepthBlit.metal
Normal file
27
src/Ryujinx.Graphics.Metal/Shaders/DepthBlit.metal
Normal file
|
@ -0,0 +1,27 @@
|
|||
#include <metal_stdlib>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct CopyVertexOut {
|
||||
float4 position [[position]];
|
||||
float2 uv;
|
||||
};
|
||||
|
||||
struct Textures
|
||||
{
|
||||
texture2d<float, access::sample> texture;
|
||||
sampler sampler;
|
||||
};
|
||||
|
||||
struct FragmentOut {
|
||||
float depth [[depth(any)]];
|
||||
};
|
||||
|
||||
fragment FragmentOut fragmentMain(CopyVertexOut in [[stage_in]],
|
||||
constant Textures &textures [[buffer(TEXTURES_INDEX)]]) {
|
||||
FragmentOut out;
|
||||
|
||||
out.depth = textures.texture.sample(textures.sampler, in.uv).r;
|
||||
|
||||
return out;
|
||||
}
|
29
src/Ryujinx.Graphics.Metal/Shaders/DepthBlitMs.metal
Normal file
29
src/Ryujinx.Graphics.Metal/Shaders/DepthBlitMs.metal
Normal file
|
@ -0,0 +1,29 @@
|
|||
#include <metal_stdlib>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct CopyVertexOut {
|
||||
float4 position [[position]];
|
||||
float2 uv;
|
||||
};
|
||||
|
||||
struct Textures
|
||||
{
|
||||
texture2d_ms<float, access::read> texture;
|
||||
};
|
||||
|
||||
struct FragmentOut {
|
||||
float depth [[depth(any)]];
|
||||
};
|
||||
|
||||
fragment FragmentOut fragmentMain(CopyVertexOut in [[stage_in]],
|
||||
constant Textures &textures [[buffer(TEXTURES_INDEX)]],
|
||||
uint sample_id [[sample_id]]) {
|
||||
FragmentOut out;
|
||||
|
||||
uint2 tex_size = uint2(textures.texture.get_width(), textures.texture.get_height());
|
||||
uint2 tex_coord = uint2(in.uv * float2(tex_size));
|
||||
out.depth = textures.texture.read(tex_coord, sample_id).r;
|
||||
|
||||
return out;
|
||||
}
|
42
src/Ryujinx.Graphics.Metal/Shaders/DepthStencilClear.metal
Normal file
42
src/Ryujinx.Graphics.Metal/Shaders/DepthStencilClear.metal
Normal file
|
@ -0,0 +1,42 @@
|
|||
#include <metal_stdlib>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct VertexOut {
|
||||
float4 position [[position]];
|
||||
};
|
||||
|
||||
struct FragmentOut {
|
||||
float depth [[depth(any)]];
|
||||
};
|
||||
|
||||
struct ClearDepth {
|
||||
float data;
|
||||
};
|
||||
|
||||
struct ConstantBuffers {
|
||||
constant ClearDepth* clear_depth;
|
||||
};
|
||||
|
||||
vertex VertexOut vertexMain(ushort vid [[vertex_id]]) {
|
||||
int low = vid & 1;
|
||||
int high = vid >> 1;
|
||||
|
||||
VertexOut out;
|
||||
|
||||
out.position.x = (float(low) - 0.5f) * 2.0f;
|
||||
out.position.y = (float(high) - 0.5f) * 2.0f;
|
||||
out.position.z = 0.0f;
|
||||
out.position.w = 1.0f;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
fragment FragmentOut fragmentMain(VertexOut in [[stage_in]],
|
||||
constant ConstantBuffers &constant_buffers [[buffer(CONSTANT_BUFFERS_INDEX)]]) {
|
||||
FragmentOut out;
|
||||
|
||||
out.depth = constant_buffers.clear_depth->data;
|
||||
|
||||
return out;
|
||||
}
|
27
src/Ryujinx.Graphics.Metal/Shaders/StencilBlit.metal
Normal file
27
src/Ryujinx.Graphics.Metal/Shaders/StencilBlit.metal
Normal file
|
@ -0,0 +1,27 @@
|
|||
#include <metal_stdlib>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct CopyVertexOut {
|
||||
float4 position [[position]];
|
||||
float2 uv;
|
||||
};
|
||||
|
||||
struct Textures
|
||||
{
|
||||
texture2d<uint, access::sample> texture;
|
||||
sampler sampler;
|
||||
};
|
||||
|
||||
struct FragmentOut {
|
||||
uint stencil [[stencil]];
|
||||
};
|
||||
|
||||
fragment FragmentOut fragmentMain(CopyVertexOut in [[stage_in]],
|
||||
constant Textures &textures [[buffer(TEXTURES_INDEX)]]) {
|
||||
FragmentOut out;
|
||||
|
||||
out.stencil = textures.texture.sample(textures.sampler, in.uv).r;
|
||||
|
||||
return out;
|
||||
}
|
29
src/Ryujinx.Graphics.Metal/Shaders/StencilBlitMs.metal
Normal file
29
src/Ryujinx.Graphics.Metal/Shaders/StencilBlitMs.metal
Normal file
|
@ -0,0 +1,29 @@
|
|||
#include <metal_stdlib>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct CopyVertexOut {
|
||||
float4 position [[position]];
|
||||
float2 uv;
|
||||
};
|
||||
|
||||
struct Textures
|
||||
{
|
||||
texture2d_ms<uint, access::read> texture;
|
||||
};
|
||||
|
||||
struct FragmentOut {
|
||||
uint stencil [[stencil]];
|
||||
};
|
||||
|
||||
fragment FragmentOut fragmentMain(CopyVertexOut in [[stage_in]],
|
||||
constant Textures &textures [[buffer(TEXTURES_INDEX)]],
|
||||
uint sample_id [[sample_id]]) {
|
||||
FragmentOut out;
|
||||
|
||||
uint2 tex_size = uint2(textures.texture.get_width(), textures.texture.get_height());
|
||||
uint2 tex_coord = uint2(in.uv * float2(tex_size));
|
||||
out.stencil = textures.texture.read(tex_coord, sample_id).r;
|
||||
|
||||
return out;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue