From 1366fd1cb5283953ec6290d578d81236acb7234d Mon Sep 17 00:00:00 2001 From: Try Date: Mon, 22 Apr 2024 22:55:19 +0200 Subject: [PATCH] MSL: native image-atomic #59 --- Engine/gapi/metal/mtdescriptorarray.cpp | 3 ++ Engine/gapi/metal/mtdescriptorarray.h | 1 + Engine/gapi/metal/mtdevice.h | 6 +++- Engine/gapi/metal/mtdevice.mm | 45 ++++++++++++++----------- Engine/gapi/metal/mtshader.cpp | 13 +++++-- Engine/gapi/metal/mttexture.cpp | 26 ++++++++++++-- Engine/gapi/metal/mttexture.h | 1 + Engine/gapi/metalapi.cpp | 3 +- Tests/tests/gapi/metal_test.cpp | 6 ++++ 9 files changed, 77 insertions(+), 27 deletions(-) diff --git a/Engine/gapi/metal/mtdescriptorarray.cpp b/Engine/gapi/metal/mtdescriptorarray.cpp index affa9703..928efe4d 100644 --- a/Engine/gapi/metal/mtdescriptorarray.cpp +++ b/Engine/gapi/metal/mtdescriptorarray.cpp @@ -20,6 +20,9 @@ void MtDescriptorArray::set(size_t id, AbstractGraphicsApi::Texture *tex, const auto& t = *reinterpret_cast(tex); desc[id].val = &t.view(smp.mapping,mipLevel); desc[id].sampler = &dev.samplers.get(smp); + if(t.linearMem!=nullptr) + desc[id].valAtom = t.linearMem.get(); else + desc[id].valAtom = nullptr; } void MtDescriptorArray::set(size_t id, const Sampler& smp) { diff --git a/Engine/gapi/metal/mtdescriptorarray.h b/Engine/gapi/metal/mtdescriptorarray.h index 4bd16896..c501edd2 100644 --- a/Engine/gapi/metal/mtdescriptorarray.h +++ b/Engine/gapi/metal/mtdescriptorarray.h @@ -32,6 +32,7 @@ class MtDescriptorArray : public AbstractGraphicsApi::Desc { struct Desc { void* val = nullptr; + void* valAtom = nullptr; MTL::SamplerState* sampler = nullptr; size_t offset = 0; size_t length = 0; diff --git a/Engine/gapi/metal/mtdevice.h b/Engine/gapi/metal/mtdevice.h index 464509f5..94ecba71 100644 --- a/Engine/gapi/metal/mtdevice.h +++ b/Engine/gapi/metal/mtdevice.h @@ -249,6 +249,9 @@ class MtDevice : public AbstractGraphicsApi::Device { void onFinish(); void waitIdle() override; + bool useNativeImageAtomic() const; + uint32_t linearImageAlignment() const; + static void handleError(NS::Error* err); NsPtr impl; @@ -262,8 +265,9 @@ class MtDevice : public AbstractGraphicsApi::Device { MtSamplerCache samplers; bool validation = false; uint32_t mslVersion = 0; + uint32_t ui32align = 0; - static void deductProps(AbstractGraphicsApi::Props& prop, MTL::Device& dev, uint32_t& mslVersion); + static void deductProps(AbstractGraphicsApi::Props& prop, MTL::Device& dev); }; inline void mtAssert(void* obj, NS::Error* err) { diff --git a/Engine/gapi/metal/mtdevice.mm b/Engine/gapi/metal/mtdevice.mm index 8e0ebae1..351f7e9c 100644 --- a/Engine/gapi/metal/mtdevice.mm +++ b/Engine/gapi/metal/mtdevice.mm @@ -29,6 +29,12 @@ return NsPtr(nullptr); } +static uint32_t languageVersion() { + auto opt = NsPtr::init(); + // clamp version to hight-most tested in engine + return std::min(MTL::LanguageVersion3_1, opt->languageVersion()); + } + MtDevice::MtDevice(std::string_view name, bool validation) : impl(mkDevice(name)), samplers(*impl), validation(validation) { if(impl.get()==nullptr) @@ -38,7 +44,10 @@ if(queue.get()==nullptr) throw std::system_error(Tempest::GraphicsErrc::NoDevice); - deductProps(prop,*impl,mslVersion); + mslVersion = languageVersion(); + // mslVersion = spirv_cross::CompilerMSL::Options::make_msl_version(2,2); //testing + ui32align = impl->minimumLinearTextureAlignmentForPixelFormat(MTL::PixelFormatR32Uint); + deductProps(prop,*impl); } MtDevice::~MtDevice() { @@ -72,7 +81,7 @@ throw DeviceLostException(); } -void MtDevice::deductProps(AbstractGraphicsApi::Props& prop, MTL::Device& dev, uint32_t& mslVersion) { +void MtDevice::deductProps(AbstractGraphicsApi::Props& prop, MTL::Device& dev) { int32_t majorVersion = 0, minorVersion = 0; if([[NSProcessInfo processInfo] respondsToSelector:@selector(operatingSystemVersion)]) { NSOperatingSystemVersion ver = [[NSProcessInfo processInfo] operatingSystemVersion]; @@ -85,13 +94,6 @@ prop.type = DeviceType::Integrated; else prop.type = DeviceType::Discrete; - mslVersion = spirv_cross::CompilerMSL::Options::make_msl_version(2,0); -#ifdef __OSX__ - if(dev.supportsFeatureSet(MTL::FeatureSet_macOS_GPUFamily1_v3)){ - mslVersion = spirv_cross::CompilerMSL::Options::make_msl_version(2,2); - } -#endif - // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf static const TextureFormat smp[] = {TextureFormat::R8, TextureFormat::RG8, TextureFormat::RGBA8, TextureFormat::R16, TextureFormat::RG16, TextureFormat::RGBA16, @@ -173,17 +175,10 @@ #endif } - if(dev.supportsFamily(MTL::GPUFamilyMetal3)) { - // TODO: spirv-cross support - if(dev.supportsFamily(MTL::GPUFamilyApple6) || - dev.supportsFamily(MTL::GPUFamilyApple7) || - dev.supportsFamily(MTL::GPUFamilyApple8) || - dev.supportsFamily(MTL::GPUFamilyMac2)) { - //atomBit |= uint64_t(1) << TextureFormat::R32U; - } - if(dev.supportsFamily(MTL::GPUFamilyApple8)) { - //atomBit |= uint64_t(1) << TextureFormat::RG32U; - } + const uint32_t mslVersion = languageVersion(); + // native or emulated + if(mslVersion>=spirv_cross::CompilerMSL::Options::make_msl_version(3,1)) { + atomBit |= uint64_t(1) << TextureFormat::R32U; } prop.setSamplerFormats(smpBit); @@ -240,6 +235,7 @@ prop.storeAndAtomicVs = false; prop.storeAndAtomicFs = false; #else + if(mslVersion>=spirv_cross::CompilerMSL::Options::make_msl_version(2,2)) { // 2.1 for buffers // 2.2 for images @@ -284,4 +280,13 @@ #endif } +bool MtDevice::useNativeImageAtomic() const { + uint32_t v3_1 = spirv_cross::CompilerMSL::Options::make_msl_version(3,1,0); + return mslVersion>=v3_1; + } + +uint32_t MtDevice::linearImageAlignment() const { + return ui32align; + } #endif + diff --git a/Engine/gapi/metal/mtshader.cpp b/Engine/gapi/metal/mtshader.cpp index ec1452c9..2676bafa 100644 --- a/Engine/gapi/metal/mtshader.cpp +++ b/Engine/gapi/metal/mtshader.cpp @@ -41,6 +41,12 @@ MtShader::MtShader(MtDevice& dev, const void* source, size_t srcSize) { optMSL.runtime_array_rich_descriptor = true; } + if(!dev.useNativeImageAtomic()) { + const uint32_t align = dev.linearImageAlignment(); + optMSL.r32ui_linear_texture_alignment = align; + optMSL.r32ui_alignment_constant_id = 0; + } + for(auto& cap:comp.get_declared_capabilities()) { switch(cap) { case spv::CapabilityRayQueryKHR: { @@ -138,7 +144,7 @@ MtShader::MtShader(MtDevice& dev, const void* source, size_t srcSize) { if(err!=nullptr) { #if !defined(NDEBUG) const char* e = err->localizedDescription()->utf8String(); - Log::d("cros-compile error: \"",e,"\""); + Log::d("cros-compile error: \"",e,"\"\n"); Log::d(msl); #endif throw std::system_error(Tempest::GraphicsErrc::InvalidShaderModule); @@ -150,7 +156,10 @@ MtShader::MtShader(MtDevice& dev, const void* source, size_t srcSize) { auto main = NsPtr(NS::String::string("main0",NS::UTF8StringEncoding)); main->retain(); - impl = NsPtr(library->newFunction(main.get())); + + auto cvar = NsPtr::init(); + //cvar->setConstantValues(); + impl = NsPtr(library->newFunction(main.get(), cvar.get(), &err)); } MtShader::~MtShader() { diff --git a/Engine/gapi/metal/mttexture.cpp b/Engine/gapi/metal/mttexture.cpp index ecaae966..dc9853be 100644 --- a/Engine/gapi/metal/mttexture.cpp +++ b/Engine/gapi/metal/mttexture.cpp @@ -27,12 +27,18 @@ static MTL::TextureSwizzle swizzle(ComponentSwizzle cs, MTL::TextureSwizzle def) return def; } +static uint32_t alignedSize(uint32_t w, uint32_t h, uint32_t a) { + return ((w*sizeof(uint32_t)+a-1) & ~(a-1)) * (h); + } + MtTexture::MtTexture(MtDevice& d, const uint32_t w, const uint32_t h, const uint32_t depth, uint32_t mipCnt, TextureFormat frm, bool storageTex) :dev(d), mipCnt(mipCnt) { MTL::TextureUsage usage = MTL::TextureUsageRenderTarget | MTL::TextureUsageShaderRead; if(storageTex) usage |= MTL::TextureUsageShaderWrite; + if(d.prop.hasAtomicFormat(frm) && d.useNativeImageAtomic()) + usage |= MTL::TextureUsageShaderAtomic; impl = alloc(frm,w,h,depth,mipCnt,MTL::StorageModePrivate,usage); } @@ -99,13 +105,22 @@ NsPtr MtTexture::alloc(TextureFormat frm, if(desc==nullptr) throw std::system_error(GraphicsErrc::OutOfHostMemory); + const bool linear = ((umode & MTL::TextureUsageShaderWrite) && dev.prop.hasAtomicFormat(frm) && !dev.useNativeImageAtomic()); + if(linear) { + const uint32_t align = dev.linearImageAlignment(); + const uint32_t memSize = alignedSize(w,h,align); + linearMem = NsPtr(dev.impl->newBuffer(memSize,MTL::ResourceStorageModePrivate)); + if(linearMem==nullptr) + throw std::system_error(GraphicsErrc::OutOfVideoMemory); + } + desc->setTextureType(d==1 ? MTL::TextureType2D : MTL::TextureType3D); desc->setPixelFormat(nativeFormat(frm)); desc->setWidth(w); desc->setHeight(h); desc->setDepth(d); desc->setMipmapLevelCount(mips); - desc->setCpuCacheMode(MTL::CPUCacheModeWriteCombined); + desc->setCpuCacheMode(MTL::CPUCacheModeDefaultCache); desc->setStorageMode(smode); desc->setUsage(umode); desc->setAllowGPUOptimizedContents(true); @@ -117,7 +132,14 @@ NsPtr MtTexture::alloc(TextureFormat frm, sw.alpha = MTL::TextureSwizzleAlpha; desc->setSwizzle(sw); - auto ret = NsPtr(dev.impl->newTexture(desc.get())); + NsPtr ret; + if(linear) { + const uint32_t align = dev.linearImageAlignment(); + const uint32_t bpr = alignedSize(w,1,align); + ret = NsPtr(linearMem->newTexture(desc.get(), 0, bpr)); + } else { + ret = NsPtr(dev.impl->newTexture(desc.get())); + } if(ret==nullptr) throw std::system_error(GraphicsErrc::OutOfVideoMemory); return ret; diff --git a/Engine/gapi/metal/mttexture.h b/Engine/gapi/metal/mttexture.h index c6c14911..b9bbe363 100644 --- a/Engine/gapi/metal/mttexture.h +++ b/Engine/gapi/metal/mttexture.h @@ -26,6 +26,7 @@ class MtTexture : public Tempest::AbstractGraphicsApi::Texture { MTL::Texture& view(ComponentMapping m, uint32_t mipLevel); MtDevice& dev; + NsPtr linearMem; NsPtr impl; const uint32_t mipCnt = 0; diff --git a/Engine/gapi/metalapi.cpp b/Engine/gapi/metalapi.cpp index 0f0a8327..77feadbf 100644 --- a/Engine/gapi/metalapi.cpp +++ b/Engine/gapi/metalapi.cpp @@ -44,8 +44,7 @@ std::vector MetalApi::devices() const { try { std::vector p(dev->count()); for(size_t i=0; i(dev->object(i)),mslVer); + MtDevice::deductProps(p[i],*reinterpret_cast(dev->object(i))); } dev->release(); return p; diff --git a/Tests/tests/gapi/metal_test.cpp b/Tests/tests/gapi/metal_test.cpp index 6702c302..df642e5f 100644 --- a/Tests/tests/gapi/metal_test.cpp +++ b/Tests/tests/gapi/metal_test.cpp @@ -139,6 +139,12 @@ TEST(MetalApi,ComputeImage) { #endif } +TEST(MetalApi,AtomicImage) { +#if defined(__OSX__) + GapiTestCommon::AtomicImage("MetalApi_AtomicImage.png"); +#endif + } + TEST(MetalApi,MipMaps) { #if defined(__OSX__) GapiTestCommon::MipMaps ("MetalApi_MipMaps_RGBA8.png");