diff --git a/src/modules/graphics/metal/Buffer.h b/src/modules/graphics/metal/Buffer.h index 95ee76aa8..2ae14accf 100644 --- a/src/modules/graphics/metal/Buffer.h +++ b/src/modules/graphics/metal/Buffer.h @@ -42,13 +42,15 @@ public: void setMappedRangeModified(size_t offset, size_t size) override; void fill(size_t offset, size_t size, const void *data) override; ptrdiff_t getHandle() const override { return (ptrdiff_t) buffer; } - ptrdiff_t getTexelBufferHandle() const override { return 0; } + ptrdiff_t getTexelBufferHandle() const override { return (ptrdiff_t) texture; } void copyTo(size_t offset, size_t size, love::graphics::Buffer *other, size_t otheroffset) override; private: id buffer; + id texture; + char *memoryMap; NSRange mappedRange; diff --git a/src/modules/graphics/metal/Buffer.mm b/src/modules/graphics/metal/Buffer.mm index 3a2b11999..0be88287b 100644 --- a/src/modules/graphics/metal/Buffer.mm +++ b/src/modules/graphics/metal/Buffer.mm @@ -27,13 +27,61 @@ namespace graphics namespace metal { +static MTLPixelFormat getMTLPixelFormat(DataFormat format) +{ + switch (format) + { + case DATAFORMAT_FLOAT: return MTLPixelFormatR32Float; + case DATAFORMAT_FLOAT_VEC2: return MTLPixelFormatRG32Float; + case DATAFORMAT_FLOAT_VEC4: return MTLPixelFormatRGBA32Float; + case DATAFORMAT_INT32: return MTLPixelFormatR32Sint; + case DATAFORMAT_INT32_VEC2: return MTLPixelFormatRG32Sint; + case DATAFORMAT_INT32_VEC4: return MTLPixelFormatRGBA32Sint; + case DATAFORMAT_UINT32: return MTLPixelFormatR32Uint; + case DATAFORMAT_UINT32_VEC2: return MTLPixelFormatRG32Uint; + case DATAFORMAT_UINT32_VEC4: return MTLPixelFormatRGBA32Uint; + case DATAFORMAT_UNORM8_VEC4: return MTLPixelFormatRGBA8Unorm; + case DATAFORMAT_SNORM8_VEC4: return MTLPixelFormatRGBA8Snorm; + case DATAFORMAT_INT8_VEC4: return MTLPixelFormatRGBA8Sint; + case DATAFORMAT_UINT8_VEC4: return MTLPixelFormatRGBA8Uint; + case DATAFORMAT_UNORM16_VEC2: return MTLPixelFormatRG16Unorm; + case DATAFORMAT_UNORM16_VEC4: return MTLPixelFormatRGBA16Unorm; + case DATAFORMAT_INT16_VEC2: return MTLPixelFormatRG16Sint; + case DATAFORMAT_INT16_VEC4: return MTLPixelFormatRGBA16Sint; + case DATAFORMAT_UINT16: return MTLPixelFormatR16Uint; + case DATAFORMAT_UINT16_VEC2: return MTLPixelFormatRG16Uint; + case DATAFORMAT_UINT16_VEC4: return MTLPixelFormatRGBA16Uint; + default: return MTLPixelFormatInvalid; + } +} + Buffer::Buffer(love::graphics::Graphics *gfx, id device, const Settings &settings, const std::vector &format, const void *data, size_t size, size_t arraylength) : love::graphics::Buffer(gfx, settings, format, size, arraylength) + , texture(nil) , mappedRange() { @autoreleasepool { + size = getSize(); + arraylength = getArrayLength(); + MTLResourceOptions opts = MTLResourceStorageModeManaged; buffer = [device newBufferWithLength:size options:opts]; + if (buffer == nil) + throw love::Exception("Could not create buffer (out of VRAM?)"); + + if (typeFlags & TYPEFLAG_TEXEL) + { + MTLPixelFormat pixformat = getMTLPixelFormat(getDataMember(0).decl.format); + auto desc = [MTLTextureDescriptor textureBufferDescriptorWithPixelFormat:pixformat + width:size + resourceOptions:opts + usage:MTLTextureUsageShaderRead]; + texture = [buffer newTextureWithDescriptor:desc offset:0 bytesPerRow:size]; + + if (texture == nil) + throw love::Exception("Could not create Metal texel buffer."); + } + // TODO: synchronization etc memoryMap = (char *) buffer.contents;