Comparer les révisions

...

5 Révisions

Auteur SHA1 Message Date
Samuliak f5830983be
metal: bind sampler to shader 2024-04-09 18:52:25 +02:00
Samuliak 1a284e4bb7
metal: translate pixel formats 2024-04-09 17:30:55 +02:00
Samuliak efda44779f
fix(metal): fix buffer to texture copy 2024-04-09 16:31:04 +02:00
Samuliak 786cd8a708
metal: implement buffer to texture copy 2024-04-09 15:49:12 +02:00
Samuliak 0a2227d1f8
metal: bind and sample from texture 2024-04-09 15:23:44 +02:00
9 fichiers modifiés avec 250 ajouts et 13 suppressions

Voir le fichier

@ -0,0 +1,128 @@
// SPDX-FileCopyrightText: Copyright 2024 suyu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <Metal/Metal.hpp>
#include "video_core/engines/maxwell_3d.h"
#include "video_core/surface.h"
namespace Metal::MaxwellToMTL {
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
// TODO: replace some of the invalid formats with the correct ones and emulate those which don't map
// directly
constexpr std::array<MTL::PixelFormat, VideoCore::Surface::MaxPixelFormat> FORMAT_TABLE = {
MTL::PixelFormatInvalid, // A8B8G8R8_UNORM
MTL::PixelFormatInvalid, // A8B8G8R8_SNORM
MTL::PixelFormatInvalid, // A8B8G8R8_SINT
MTL::PixelFormatInvalid, // A8B8G8R8_UINT
MTL::PixelFormatInvalid, // R5G6B5_UNORM
MTL::PixelFormatB5G6R5Unorm, // B5G6R5_UNORM
MTL::PixelFormatInvalid, // A1R5G5B5_UNORM
MTL::PixelFormatRGBA8Unorm, // A2B10G10R10_UNORM (hack)
MTL::PixelFormatInvalid, // A2B10G10R10_UINT
MTL::PixelFormatInvalid, // A2R10G10B10_UNORM
MTL::PixelFormatInvalid, // A1B5G5R5_UNORM
MTL::PixelFormatInvalid, // A5B5G5R1_UNORM
MTL::PixelFormatR8Unorm, // R8_UNORM
MTL::PixelFormatR8Snorm, // R8_SNORM
MTL::PixelFormatR8Sint, // R8_SINT
MTL::PixelFormatR8Uint, // R8_UINT
MTL::PixelFormatRGBA16Float, // R16G16B16A16_FLOAT
MTL::PixelFormatRGBA16Unorm, // R16G16B16A16_UNORM
MTL::PixelFormatRGBA16Snorm, // R16G16B16A16_SNORM
MTL::PixelFormatRGBA16Sint, // R16G16B16A16_SINT
MTL::PixelFormatRGBA16Uint, // R16G16B16A16_UINT
MTL::PixelFormatInvalid, // B10G11R11_FLOAT
MTL::PixelFormatRGBA32Uint, // R32G32B32A32_UINT
MTL::PixelFormatBC1_RGBA, // BC1_RGBA_UNORM
MTL::PixelFormatInvalid, // BC2_UNORM
MTL::PixelFormatInvalid, // BC3_UNORM
MTL::PixelFormatBC4_RUnorm, // BC4_UNORM
MTL::PixelFormatBC4_RSnorm, // BC4_SNORM
MTL::PixelFormatInvalid, // BC5_UNORM
MTL::PixelFormatInvalid, // BC5_SNORM
MTL::PixelFormatInvalid, // BC7_UNORM
MTL::PixelFormatInvalid, // BC6H_UFLOAT
MTL::PixelFormatInvalid, // BC6H_SFLOAT
MTL::PixelFormatASTC_4x4_LDR, // ASTC_2D_4X4_UNORM
MTL::PixelFormatBGRA8Unorm, // B8G8R8A8_UNORM
MTL::PixelFormatRGBA32Float, // R32G32B32A32_FLOAT
MTL::PixelFormatRGBA32Sint, // R32G32B32A32_SINT
MTL::PixelFormatRG32Float, // R32G32_FLOAT
MTL::PixelFormatRG32Sint, // R32G32_SINT
MTL::PixelFormatR32Float, // R32_FLOAT
MTL::PixelFormatR16Float, // R16_FLOAT
MTL::PixelFormatR16Unorm, // R16_UNORM
MTL::PixelFormatR16Snorm, // R16_SNORM
MTL::PixelFormatR16Uint, // R16_UINT
MTL::PixelFormatR16Sint, // R16_SINT
MTL::PixelFormatRG16Unorm, // R16G16_UNORM
MTL::PixelFormatRG16Float, // R16G16_FLOAT
MTL::PixelFormatRG16Uint, // R16G16_UINT
MTL::PixelFormatRG16Sint, // R16G16_SINT
MTL::PixelFormatRG16Snorm, // R16G16_SNORM
MTL::PixelFormatInvalid, // R32G32B32_FLOAT
MTL::PixelFormatRGBA8Unorm, // A8B8G8R8_SRGB (hack)
MTL::PixelFormatRG8Unorm, // R8G8_UNORM
MTL::PixelFormatRG8Snorm, // R8G8_SNORM
MTL::PixelFormatRG8Sint, // R8G8_SINT
MTL::PixelFormatRG8Uint, // R8G8_UINT
MTL::PixelFormatRG32Uint, // R32G32_UINT
MTL::PixelFormatInvalid, // R16G16B16X16_FLOAT
MTL::PixelFormatR32Uint, // R32_UINT
MTL::PixelFormatR32Sint, // R32_SINT
MTL::PixelFormatASTC_8x8_LDR, // ASTC_2D_8X8_UNORM
MTL::PixelFormatASTC_8x5_LDR, // ASTC_2D_8X5_UNORM
MTL::PixelFormatASTC_5x4_LDR, // ASTC_2D_5X4_UNORM
MTL::PixelFormatBGRA8Unorm_sRGB, // B8G8R8A8_SRGB
MTL::PixelFormatBC1_RGBA_sRGB, // BC1_RGBA_SRGB
MTL::PixelFormatInvalid, // BC2_SRGB
MTL::PixelFormatInvalid, // BC3_SRGB
MTL::PixelFormatBC7_RGBAUnorm_sRGB, // BC7_SRGB
MTL::PixelFormatABGR4Unorm, // A4B4G4R4_UNORM
MTL::PixelFormatInvalid, // G4R4_UNORM
MTL::PixelFormatASTC_4x4_sRGB, // ASTC_2D_4X4_SRGB
MTL::PixelFormatASTC_8x8_sRGB, // ASTC_2D_8X8_SRGB
MTL::PixelFormatASTC_8x5_sRGB, // ASTC_2D_8X5_SRGB
MTL::PixelFormatASTC_5x4_sRGB, // ASTC_2D_5X4_SRGB
MTL::PixelFormatASTC_5x5_LDR, // ASTC_2D_5X5_UNORM
MTL::PixelFormatASTC_5x5_sRGB, // ASTC_2D_5X5_SRGB
MTL::PixelFormatASTC_10x8_LDR, // ASTC_2D_10X8_UNORM
MTL::PixelFormatASTC_10x8_sRGB, // ASTC_2D_10X8_SRGB
MTL::PixelFormatASTC_6x6_LDR, // ASTC_2D_6X6_UNORM
MTL::PixelFormatASTC_6x6_sRGB, // ASTC_2D_6X6_SRGB
MTL::PixelFormatASTC_10x6_LDR, // ASTC_2D_10X6_UNORM
MTL::PixelFormatASTC_10x6_sRGB, // ASTC_2D_10X6_SRGB
MTL::PixelFormatASTC_10x5_LDR, // ASTC_2D_10X5_UNORM
MTL::PixelFormatASTC_10x5_sRGB, // ASTC_2D_10X5_SRGB
MTL::PixelFormatASTC_10x10_LDR, // ASTC_2D_10X10_UNORM
MTL::PixelFormatASTC_10x10_sRGB, // ASTC_2D_10X10_SRGB
MTL::PixelFormatASTC_12x10_LDR, // ASTC_2D_12X10_UNORM
MTL::PixelFormatASTC_12x10_sRGB, // ASTC_2D_12X10_SRGB
MTL::PixelFormatASTC_12x12_LDR, // ASTC_2D_12X12_UNORM
MTL::PixelFormatASTC_12x12_sRGB, // ASTC_2D_12X12_SRGB
MTL::PixelFormatASTC_8x6_LDR, // ASTC_2D_8X6_UNORM
MTL::PixelFormatASTC_8x6_sRGB, // ASTC_2D_8X6_SRGB
MTL::PixelFormatASTC_6x5_LDR, // ASTC_2D_6X5_UNORM
MTL::PixelFormatASTC_6x5_sRGB, // ASTC_2D_6X5_SRGB
MTL::PixelFormatInvalid, // E5B9G9R9_FLOAT
MTL::PixelFormatDepth32Float, // D32_FLOAT
MTL::PixelFormatDepth16Unorm, // D16_UNORM
MTL::PixelFormatInvalid, // X8_D24_UNORM
MTL::PixelFormatStencil8, // S8_UINT
MTL::PixelFormatDepth24Unorm_Stencil8, // D24_UNORM_S8_UINT
MTL::PixelFormatInvalid, // S8_UINT_D24_UNORM
MTL::PixelFormatDepth32Float_Stencil8, // D32_FLOAT_S8_UINT
};
inline MTL::PixelFormat GetPixelFormat(VideoCore::Surface::PixelFormat pixel_format) {
ASSERT(static_cast<size_t>(pixel_format) < FORMAT_TABLE.size());
return FORMAT_TABLE[static_cast<size_t>(pixel_format)];
}
} // namespace Metal::MaxwellToMTL

Voir le fichier

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <iostream>
#include <span>
#include <boost/container/small_vector.hpp>
@ -62,6 +63,56 @@ void GraphicsPipeline::Configure(bool is_indexed) {
texture_cache.SynchronizeGraphicsDescriptors();
// Find resources
size_t stage = 4;
const auto& cbufs{maxwell3d->state.shader_stages[stage].const_buffers};
const auto read_handle{[&](const auto& desc, u32 index) {
ASSERT(cbufs[desc.cbuf_index].enabled);
const u32 index_offset{index << desc.size_shift};
const u32 offset{desc.cbuf_offset + index_offset};
const GPUVAddr addr{cbufs[desc.cbuf_index].address + offset};
if constexpr (std::is_same_v<decltype(desc), const Shader::TextureDescriptor&> ||
std::is_same_v<decltype(desc), const Shader::TextureBufferDescriptor&>) {
if (desc.has_secondary) {
ASSERT(cbufs[desc.secondary_cbuf_index].enabled);
const u32 second_offset{desc.secondary_cbuf_offset + index_offset};
const GPUVAddr separate_addr{cbufs[desc.secondary_cbuf_index].address +
second_offset};
const u32 lhs_raw{gpu_memory->Read<u32>(addr) << desc.shift_left};
const u32 rhs_raw{gpu_memory->Read<u32>(separate_addr)
<< desc.secondary_shift_left};
const u32 raw{lhs_raw | rhs_raw};
return TexturePair(raw, false);
}
}
auto a = gpu_memory->Read<u32>(addr);
// HACK: hardcode the image
if (a != 310378932)
a = 310378932;
return TexturePair(a, false);
}};
const Shader::Info& info{stage_infos[stage]};
std::array<VideoCommon::ImageViewInOut, 32> views;
std::array<VideoCommon::SamplerId, 32> samplers;
size_t view_index{};
size_t sampler_index{};
for (const auto& desc : info.texture_descriptors) {
for (u32 index = 0; index < desc.count; ++index) {
const auto handle{read_handle(desc, index)};
views[view_index++] = {handle.first};
VideoCommon::SamplerId sampler{texture_cache.GetGraphicsSamplerId(handle.second)};
samplers[sampler_index++] = sampler;
}
}
texture_cache.FillGraphicsImageViews<true>(std::span(views.data(), view_index));
// Begin render pass
texture_cache.UpdateRenderTargets(false);
const Framebuffer* const framebuffer = texture_cache.GetFramebuffer();
if (!framebuffer) {
@ -70,6 +121,18 @@ void GraphicsPipeline::Configure(bool is_indexed) {
command_recorder.BeginOrContinueRenderPass(framebuffer->GetHandle());
command_recorder.GetRenderCommandEncoder()->setRenderPipelineState(pipeline_state);
// Bind resources
// HACK: try to find a texture that we can bind
const VideoCommon::ImageViewInOut* views_it{views.data()};
const VideoCommon::SamplerId* samplers_it{samplers.data()};
ImageView& image_view{texture_cache.GetImageView(views_it->id)};
Sampler& sampler{texture_cache.GetSampler(*samplers_it)};
command_recorder.GetRenderCommandEncoder()->setFragmentTexture(image_view.GetHandle(), 0);
command_recorder.GetRenderCommandEncoder()->setFragmentSamplerState(sampler.GetHandle(), 0);
}
void GraphicsPipeline::MakePipeline(MTL::RenderPassDescriptor* render_pass) {

Voir le fichier

@ -298,8 +298,8 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
return out;
}
fragment float4 fragmentMain(VertexOut in [[stage_in]]) {
return float4(in.texCoord, 0.0, 1.0);
fragment float4 fragmentMain(VertexOut in [[stage_in]], texture2d<float> tex [[texture(0)]], sampler samplr [[sampler(0)]]) {
return tex.sample(samplr, in.texCoord);
}
)",
NS::ASCIIStringEncoding),

Voir le fichier

@ -48,6 +48,8 @@ void RasterizerMetal::Draw(bool is_indexed, u32 instance_count) {
if (!pipeline) {
return;
}
// Set the engine
pipeline->SetEngine(maxwell3d, gpu_memory);
pipeline->Configure(is_indexed);
// HACK: dummy draw call

Voir le fichier

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <iostream>
#include <utility>
#include <vector>
@ -77,9 +78,34 @@ StagingBufferRef StagingBufferPool::GetStreamBuffer(size_t size) {
StagingBufferRef StagingBufferPool::GetStagingBuffer(size_t size, MemoryUsage usage,
bool deferred) {
if (const std::optional<StagingBufferRef> ref = TryGetReservedBuffer(size, usage, deferred)) {
return *ref;
}
return CreateStagingBuffer(size, usage, deferred);
}
std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t size,
MemoryUsage usage,
bool deferred) {
StagingBuffers& cache_level = GetCache(usage)[Common::Log2Ceil64(size)];
// TODO: don't always return true
const auto is_free = [](const StagingBuffer& entry) { return true; };
auto& entries = cache_level.entries;
const auto hint_it = entries.begin() + cache_level.iterate_index;
auto it = std::find_if(entries.begin() + cache_level.iterate_index, entries.end(), is_free);
if (it == entries.end()) {
it = std::find_if(entries.begin(), hint_it, is_free);
if (it == hint_it) {
return std::nullopt;
}
}
cache_level.iterate_index = std::distance(entries.begin(), it) + 1;
return it->Ref();
}
StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage,
bool deferred) {
const u32 log2 = Common::Log2Ceil64(size);

Voir le fichier

@ -71,6 +71,9 @@ private:
StagingBufferRef GetStagingBuffer(size_t size, MemoryUsage usage, bool deferred = false);
std::optional<StagingBufferRef> TryGetReservedBuffer(size_t size, MemoryUsage usage,
bool deferred);
StagingBufferRef CreateStagingBuffer(size_t size, MemoryUsage usage, bool deferred);
StagingBuffersCache& GetCache(MemoryUsage usage);

Voir le fichier

@ -5,12 +5,15 @@
#include <array>
#include <span>
#include <vector>
#include <boost/container/small_vector.hpp>
#include "common/bit_cast.h"
#include "common/bit_util.h"
#include "common/settings.h"
#include "video_core/renderer_metal/maxwell_to_mtl.h"
#include "video_core/renderer_metal/mtl_command_recorder.h"
#include "video_core/renderer_metal/mtl_device.h"
#include "video_core/renderer_metal/mtl_texture_cache.h"
@ -53,16 +56,16 @@ void TextureCacheRuntime::FreeDeferredStagingBuffer(StagingBufferRef& ref) {
staging_buffer_pool.FreeDeferred(ref);
}
Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info, GPUVAddr gpu_addr_,
Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info, GPUVAddr gpu_addr_,
VAddr cpu_addr_)
: VideoCommon::ImageBase(info, gpu_addr_, cpu_addr_) {
: VideoCommon::ImageBase(info, gpu_addr_, cpu_addr_), runtime{&runtime_} {
MTL::TextureDescriptor* texture_descriptor = MTL::TextureDescriptor::alloc()->init();
// TODO: don't hardcode the format
texture_descriptor->setPixelFormat(MTL::PixelFormatRGBA8Unorm);
texture_descriptor->setPixelFormat(MaxwellToMTL::GetPixelFormat(info.format));
texture_descriptor->setWidth(info.size.width);
texture_descriptor->setHeight(info.size.height);
// TODO: set other parameters
texture = runtime.device.GetDevice()->newTexture(texture_descriptor);
texture = runtime->device.GetDevice()->newTexture(texture_descriptor);
}
Image::Image(const VideoCommon::NullImageParams& params) : VideoCommon::ImageBase{params} {}
@ -76,12 +79,22 @@ Image::~Image() {
// TODO: implement these
void Image::UploadMemory(MTL::Buffer* buffer, size_t offset,
std::span<const VideoCommon::BufferImageCopy> copies) {
;
for (const VideoCommon::BufferImageCopy& copy : copies) {
// TODO: query this from texture format
size_t bytes_per_pixel = 4;
size_t bytes_per_row = info.size.width * bytes_per_pixel;
size_t bytes_per_image = info.size.height * bytes_per_row;
MTL::Size size = MTL::Size::Make(info.size.width, info.size.height, 1);
MTL::Origin origin = MTL::Origin::Make(copy.image_offset.x, copy.image_offset.y,
copy.image_subresource.base_layer);
runtime->command_recorder.GetBlitCommandEncoder()->copyFromBuffer(
buffer, offset, bytes_per_row, bytes_per_image, size, texture, 0, 0, origin);
}
}
void Image::UploadMemory(const StagingBufferRef& map,
std::span<const VideoCommon::BufferImageCopy> copies) {
;
UploadMemory(map.buffer, map.offset, copies);
}
void Image::DownloadMemory(MTL::Buffer* buffer, size_t offset,

Voir le fichier

@ -116,7 +116,7 @@ public:
class Image : public VideoCommon::ImageBase {
public:
explicit Image(TextureCacheRuntime& runtime, const VideoCommon::ImageInfo& info,
explicit Image(TextureCacheRuntime& runtime_, const VideoCommon::ImageInfo& info,
GPUVAddr gpu_addr, VAddr cpu_addr);
explicit Image(const VideoCommon::NullImageParams&);
@ -162,7 +162,9 @@ public:
}
private:
MTL::Texture* texture = nil;
TextureCacheRuntime* runtime;
MTL::Texture* texture{nullptr};
bool initialized = false;
bool rescaled = false;

Voir le fichier

@ -49,8 +49,8 @@ size_t GetStreamBufferSize(const Device& device) {
StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_,
Scheduler& scheduler_)
: device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_},
stream_buffer_size{GetStreamBufferSize(device)}, region_size{stream_buffer_size /
StagingBufferPool::NUM_SYNCS} {
stream_buffer_size{GetStreamBufferSize(device)},
region_size{stream_buffer_size / StagingBufferPool::NUM_SYNCS} {
VkBufferCreateInfo stream_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,