Skip to content

Commit

Permalink
MSL: native image-atomic
Browse files Browse the repository at this point in the history
  • Loading branch information
Try committed Apr 22, 2024
1 parent bf3efed commit 1366fd1
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 27 deletions.
3 changes: 3 additions & 0 deletions Engine/gapi/metal/mtdescriptorarray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ void MtDescriptorArray::set(size_t id, AbstractGraphicsApi::Texture *tex, const
auto& t = *reinterpret_cast<MtTexture*>(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) {
Expand Down
1 change: 1 addition & 0 deletions Engine/gapi/metal/mtdescriptorarray.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 5 additions & 1 deletion Engine/gapi/metal/mtdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<MTL::Device> impl;
Expand All @@ -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) {
Expand Down
45 changes: 25 additions & 20 deletions Engine/gapi/metal/mtdevice.mm
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@
return NsPtr<MTL::Device>(nullptr);
}

static uint32_t languageVersion() {
auto opt = NsPtr<MTL::CompileOptions>::init();
// clamp version to hight-most tested in engine
return std::min<uint32_t>(MTL::LanguageVersion3_1, opt->languageVersion());
}

MtDevice::MtDevice(std::string_view name, bool validation)
: impl(mkDevice(name)), samplers(*impl), validation(validation) {
if(impl.get()==nullptr)
Expand All @@ -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() {
Expand Down Expand Up @@ -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];
Expand All @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

13 changes: 11 additions & 2 deletions Engine/gapi/metal/mtshader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down Expand Up @@ -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);
Expand All @@ -150,7 +156,10 @@ MtShader::MtShader(MtDevice& dev, const void* source, size_t srcSize) {

auto main = NsPtr<NS::String>(NS::String::string("main0",NS::UTF8StringEncoding));
main->retain();
impl = NsPtr<MTL::Function>(library->newFunction(main.get()));

auto cvar = NsPtr<MTL::FunctionConstantValues>::init();
//cvar->setConstantValues();
impl = NsPtr<MTL::Function>(library->newFunction(main.get(), cvar.get(), &err));
}

MtShader::~MtShader() {
Expand Down
26 changes: 24 additions & 2 deletions Engine/gapi/metal/mttexture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -99,13 +105,22 @@ NsPtr<MTL::Texture> 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<MTL::Buffer>(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);
Expand All @@ -117,7 +132,14 @@ NsPtr<MTL::Texture> MtTexture::alloc(TextureFormat frm,
sw.alpha = MTL::TextureSwizzleAlpha;
desc->setSwizzle(sw);

auto ret = NsPtr<MTL::Texture>(dev.impl->newTexture(desc.get()));
NsPtr<MTL::Texture> ret;
if(linear) {
const uint32_t align = dev.linearImageAlignment();
const uint32_t bpr = alignedSize(w,1,align);
ret = NsPtr<MTL::Texture>(linearMem->newTexture(desc.get(), 0, bpr));
} else {
ret = NsPtr<MTL::Texture>(dev.impl->newTexture(desc.get()));
}
if(ret==nullptr)
throw std::system_error(GraphicsErrc::OutOfVideoMemory);
return ret;
Expand Down
1 change: 1 addition & 0 deletions Engine/gapi/metal/mttexture.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class MtTexture : public Tempest::AbstractGraphicsApi::Texture {
MTL::Texture& view(ComponentMapping m, uint32_t mipLevel);

MtDevice& dev;
NsPtr<MTL::Buffer> linearMem;
NsPtr<MTL::Texture> impl;
const uint32_t mipCnt = 0;

Expand Down
3 changes: 1 addition & 2 deletions Engine/gapi/metalapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ std::vector<AbstractGraphicsApi::Props> MetalApi::devices() const {
try {
std::vector<AbstractGraphicsApi::Props> p(dev->count());
for(size_t i=0; i<p.size(); ++i) {
uint32_t mslVer = 0;
MtDevice::deductProps(p[i],*reinterpret_cast<MTL::Device*>(dev->object(i)),mslVer);
MtDevice::deductProps(p[i],*reinterpret_cast<MTL::Device*>(dev->object(i)));
}
dev->release();
return p;
Expand Down
6 changes: 6 additions & 0 deletions Tests/tests/gapi/metal_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,12 @@ TEST(MetalApi,ComputeImage) {
#endif
}

TEST(MetalApi,AtomicImage) {
#if defined(__OSX__)
GapiTestCommon::AtomicImage<MetalApi>("MetalApi_AtomicImage.png");
#endif
}

TEST(MetalApi,MipMaps) {
#if defined(__OSX__)
GapiTestCommon::MipMaps<MetalApi,TextureFormat::RGBA8> ("MetalApi_MipMaps_RGBA8.png");
Expand Down

0 comments on commit 1366fd1

Please sign in to comment.