boo/lib/graphicsdev/Metal.mm

1139 lines
41 KiB
Plaintext
Raw Normal View History

2015-11-16 22:03:46 +00:00
#include "../mac/CocoaCommon.hpp"
#if BOO_HAS_METAL
2016-03-08 21:18:38 +00:00
#include "logvisor/logvisor.hpp"
#include "boo/graphicsdev/Metal.hpp"
#include "boo/IGraphicsContext.hpp"
#include <vector>
2015-12-27 04:20:07 +00:00
#if !__has_feature(objc_arc)
#error ARC Required
#endif
#define MAX_UNIFORM_COUNT 8
#define MAX_TEXTURE_COUNT 8
namespace boo
{
2016-03-08 21:18:38 +00:00
static logvisor::Module Log("boo::Metal");
2015-11-09 02:24:45 +00:00
struct MetalCommandQueue;
2015-12-18 21:33:53 +00:00
ThreadLocalPtr<struct MetalData> MetalDataFactory::m_deferredData;
2015-11-09 02:24:45 +00:00
struct MetalData : IGraphicsData
{
std::vector<std::unique_ptr<class MetalShaderPipeline>> m_SPs;
std::vector<std::unique_ptr<struct MetalShaderDataBinding>> m_SBinds;
std::vector<std::unique_ptr<class MetalGraphicsBufferS>> m_SBufs;
std::vector<std::unique_ptr<class MetalGraphicsBufferD>> m_DBufs;
std::vector<std::unique_ptr<class MetalTextureS>> m_STexs;
2015-11-28 04:07:53 +00:00
std::vector<std::unique_ptr<class MetalTextureSA>> m_SATexs;
2015-11-09 02:24:45 +00:00
std::vector<std::unique_ptr<class MetalTextureD>> m_DTexs;
std::vector<std::unique_ptr<class MetalTextureR>> m_RTexs;
std::vector<std::unique_ptr<struct MetalVertexFormat>> m_VFmts;
};
2015-11-09 06:45:14 +00:00
#define MTL_STATIC MTLResourceCPUCacheModeWriteCombined|MTLResourceStorageModeShared
2015-11-09 02:24:45 +00:00
#define MTL_DYNAMIC MTLResourceCPUCacheModeWriteCombined|MTLResourceStorageModeShared
2015-11-09 02:24:45 +00:00
class MetalGraphicsBufferS : public IGraphicsBufferS
{
2015-11-09 02:24:45 +00:00
friend class MetalDataFactory;
friend struct MetalCommandQueue;
MetalGraphicsBufferS(BufferUse use, MetalContext* ctx, const void* data, size_t stride, size_t count)
: m_stride(stride), m_count(count), m_sz(stride * count)
{
2016-01-11 22:26:40 +00:00
m_buf = [ctx->m_dev newBufferWithBytes:data length:m_sz options:MTL_STATIC];
}
public:
size_t m_stride;
size_t m_count;
2015-11-09 02:24:45 +00:00
size_t m_sz;
2016-01-11 22:26:40 +00:00
id<MTLBuffer> m_buf;
2015-11-09 02:24:45 +00:00
~MetalGraphicsBufferS() = default;
};
2015-11-09 02:24:45 +00:00
class MetalGraphicsBufferD : public IGraphicsBufferD
{
2015-11-09 02:24:45 +00:00
friend class MetalDataFactory;
friend struct MetalCommandQueue;
MetalCommandQueue* m_q;
2015-12-02 22:25:30 +00:00
std::unique_ptr<uint8_t[]> m_cpuBuf;
int m_validSlots = 0;
2015-11-09 02:24:45 +00:00
MetalGraphicsBufferD(MetalCommandQueue* q, BufferUse use, MetalContext* ctx, size_t stride, size_t count)
: m_q(q), m_stride(stride), m_count(count), m_sz(stride * count)
{
2015-12-02 22:25:30 +00:00
m_cpuBuf.reset(new uint8_t[m_sz]);
2016-01-11 22:26:40 +00:00
m_bufs[0] = [ctx->m_dev newBufferWithLength:m_sz options:MTL_DYNAMIC];
m_bufs[1] = [ctx->m_dev newBufferWithLength:m_sz options:MTL_DYNAMIC];
}
2015-12-02 22:25:30 +00:00
void update(int b);
public:
size_t m_stride;
size_t m_count;
2015-11-09 02:24:45 +00:00
size_t m_sz;
2016-01-11 22:26:40 +00:00
id<MTLBuffer> m_bufs[2];
2015-11-09 02:24:45 +00:00
MetalGraphicsBufferD() = default;
2016-02-16 19:41:16 +00:00
void load(const void* data, size_t sz);
void* map(size_t sz);
void unmap();
};
2015-11-09 02:24:45 +00:00
class MetalTextureS : public ITextureS
{
2015-11-09 02:24:45 +00:00
friend class MetalDataFactory;
MetalTextureS(MetalContext* ctx, size_t width, size_t height, size_t mips,
TextureFormat fmt, const void* data, size_t sz)
{
2015-11-28 04:07:53 +00:00
MTLPixelFormat pfmt = MTLPixelFormatRGBA8Unorm;
2016-02-16 19:41:16 +00:00
NSUInteger ppitchNum = 4;
NSUInteger ppitchDenom = 1;
2015-11-28 04:07:53 +00:00
switch (fmt)
{
case TextureFormat::I8:
pfmt = MTLPixelFormatR8Unorm;
2016-02-16 19:41:16 +00:00
ppitchNum = 1;
2015-11-28 04:07:53 +00:00
break;
2016-02-16 19:41:16 +00:00
case TextureFormat::DXT1:
pfmt = MTLPixelFormatBC1_RGBA;
ppitchNum = 1;
ppitchDenom = 2;
2015-11-28 04:07:53 +00:00
default: break;
}
2016-02-16 19:41:16 +00:00
2015-11-18 23:55:25 +00:00
@autoreleasepool
{
2016-01-11 22:26:40 +00:00
MTLTextureDescriptor* desc =
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pfmt
width:width height:height
mipmapped:(mips>1)?YES:NO];
desc.usage = MTLTextureUsageShaderRead;
desc.mipmapLevelCount = mips;
m_tex = [ctx->m_dev newTextureWithDescriptor:desc];
const uint8_t* dataIt = reinterpret_cast<const uint8_t*>(data);
for (size_t i=0 ; i<mips ; ++i)
{
[m_tex replaceRegion:MTLRegionMake2D(0, 0, width, height)
mipmapLevel:i
withBytes:dataIt
2016-02-16 19:41:16 +00:00
bytesPerRow:width * ppitchNum / ppitchDenom];
dataIt += width * height * ppitchNum / ppitchDenom;
2016-01-11 22:26:40 +00:00
width /= 2;
height /= 2;
}
}
}
public:
2016-01-11 22:26:40 +00:00
id<MTLTexture> m_tex;
2015-11-09 02:24:45 +00:00
~MetalTextureS() = default;
};
2016-02-16 19:41:16 +00:00
2015-11-28 04:07:53 +00:00
class MetalTextureSA : public ITextureSA
{
friend class MetalDataFactory;
MetalTextureSA(MetalContext* ctx, size_t width, size_t height, size_t layers,
TextureFormat fmt, const void* data, size_t sz)
{
MTLPixelFormat pfmt = MTLPixelFormatRGBA8Unorm;
NSUInteger ppitch = 4;
switch (fmt)
{
case TextureFormat::I8:
pfmt = MTLPixelFormatR8Unorm;
ppitch = 1;
break;
default: break;
}
2016-02-16 19:41:16 +00:00
2015-11-28 04:07:53 +00:00
@autoreleasepool
{
2016-01-11 22:26:40 +00:00
MTLTextureDescriptor* desc =
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:pfmt
width:width height:height
mipmapped:NO];
desc.textureType = MTLTextureType2DArray;
desc.arrayLength = layers;
desc.usage = MTLTextureUsageShaderRead;
m_tex = [ctx->m_dev newTextureWithDescriptor:desc];
const uint8_t* dataIt = reinterpret_cast<const uint8_t*>(data);
for (size_t i=0 ; i<layers ; ++i)
{
[m_tex replaceRegion:MTLRegionMake2D(0, 0, width, height)
mipmapLevel:0
slice:i
withBytes:dataIt
bytesPerRow:width * ppitch
bytesPerImage:width * height * ppitch];
dataIt += width * height * ppitch;
}
2015-11-28 04:07:53 +00:00
}
}
public:
2016-01-11 22:26:40 +00:00
id<MTLTexture> m_tex;
2015-11-28 04:07:53 +00:00
~MetalTextureSA() = default;
};
2016-02-16 19:41:16 +00:00
2015-11-09 02:24:45 +00:00
class MetalTextureD : public ITextureD
{
2015-11-09 02:24:45 +00:00
friend class MetalDataFactory;
friend struct MetalCommandQueue;
MetalCommandQueue* m_q;
size_t m_width = 0;
size_t m_height = 0;
2015-12-02 22:25:30 +00:00
std::unique_ptr<uint8_t[]> m_cpuBuf;
size_t m_cpuSz;
size_t m_pxPitch;
int m_validSlots = 0;
2015-11-09 02:24:45 +00:00
MetalTextureD(MetalCommandQueue* q, MetalContext* ctx, size_t width, size_t height, TextureFormat fmt)
: m_q(q), m_width(width), m_height(height)
{
2015-12-02 22:25:30 +00:00
MTLPixelFormat format;
switch (fmt)
{
case TextureFormat::RGBA8:
format = MTLPixelFormatRGBA8Unorm;
m_pxPitch = 4;
break;
case TextureFormat::I8:
format = MTLPixelFormatR8Unorm;
m_pxPitch = 1;
break;
default:
2016-03-08 21:18:38 +00:00
Log.report(logvisor::Fatal, "unsupported tex format");
2015-12-02 22:25:30 +00:00
}
2016-02-16 19:41:16 +00:00
2015-12-02 22:25:30 +00:00
m_cpuSz = width * height * m_pxPitch;
m_cpuBuf.reset(new uint8_t[m_cpuSz]);
2016-02-16 19:41:16 +00:00
2015-11-18 23:55:25 +00:00
@autoreleasepool
{
2016-01-11 22:26:40 +00:00
MTLTextureDescriptor* desc =
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format
width:width height:height
mipmapped:NO];
desc.usage = MTLTextureUsageShaderRead;
m_texs[0] = [ctx->m_dev newTextureWithDescriptor:desc];
m_texs[1] = [ctx->m_dev newTextureWithDescriptor:desc];
2015-11-18 23:55:25 +00:00
}
}
2015-12-02 22:25:30 +00:00
void update(int b);
public:
2016-01-11 22:26:40 +00:00
id<MTLTexture> m_texs[2];
2015-11-09 02:24:45 +00:00
~MetalTextureD() = default;
2016-02-16 19:41:16 +00:00
void load(const void* data, size_t sz);
void* map(size_t sz);
void unmap();
};
2016-02-16 19:41:16 +00:00
2015-11-09 02:24:45 +00:00
class MetalTextureR : public ITextureR
{
2015-11-09 02:24:45 +00:00
friend class MetalDataFactory;
friend struct MetalCommandQueue;
size_t m_width = 0;
size_t m_height = 0;
size_t m_samples = 0;
bool m_enableShaderBindTexture;
2016-02-16 19:41:16 +00:00
void Setup(MetalContext* ctx, size_t width, size_t height, size_t samples,
bool enableShaderBindTexture)
{
m_width = width;
m_height = height;
2015-11-09 06:45:14 +00:00
@autoreleasepool
{
2016-01-11 22:26:40 +00:00
MTLTextureDescriptor* desc =
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
width:width height:height
mipmapped:NO];
desc.storageMode = MTLStorageModePrivate;
2015-11-09 02:24:45 +00:00
2016-01-11 22:26:40 +00:00
if (samples > 1)
{
desc.textureType = MTLTextureType2DMultisample;
desc.sampleCount = samples;
desc.usage = MTLTextureUsageRenderTarget;
m_colorTex = [ctx->m_dev newTextureWithDescriptor:desc];
2016-01-11 22:26:40 +00:00
if (enableShaderBindTexture)
{
desc.usage = MTLTextureUsageShaderRead;
m_colorBindTex = [ctx->m_dev newTextureWithDescriptor:desc];
}
desc.usage = MTLTextureUsageRenderTarget;
2016-01-11 22:26:40 +00:00
desc.pixelFormat = MTLPixelFormatDepth32Float;
m_depthTex = [ctx->m_dev newTextureWithDescriptor:desc];
}
else
{
desc.textureType = MTLTextureType2D;
desc.sampleCount = 1;
desc.usage = MTLTextureUsageRenderTarget;
m_colorTex = [ctx->m_dev newTextureWithDescriptor:desc];
if (enableShaderBindTexture)
{
desc.usage = MTLTextureUsageShaderRead;
m_colorBindTex = [ctx->m_dev newTextureWithDescriptor:desc];
}
desc.usage = MTLTextureUsageRenderTarget;
2016-01-11 22:26:40 +00:00
desc.pixelFormat = MTLPixelFormatDepth32Float;
m_depthTex = [ctx->m_dev newTextureWithDescriptor:desc];
}
2016-01-11 22:26:40 +00:00
2016-04-03 06:18:30 +00:00
{
m_passDesc = [MTLRenderPassDescriptor renderPassDescriptor];
m_passDesc.colorAttachments[0].texture = m_colorTex;
m_passDesc.colorAttachments[0].loadAction = MTLLoadActionLoad;
m_passDesc.colorAttachments[0].storeAction = MTLStoreActionStore;
m_passDesc.depthAttachment.texture = m_depthTex;
m_passDesc.depthAttachment.loadAction = MTLLoadActionLoad;
m_passDesc.depthAttachment.storeAction = MTLStoreActionStore;
2016-04-03 06:22:03 +00:00
m_passDesc.depthAttachment.clearDepth = 0.f;
2016-04-03 06:18:30 +00:00
}
{
m_clearDepthPassDesc = [MTLRenderPassDescriptor renderPassDescriptor];
2016-01-11 22:26:40 +00:00
2016-04-03 06:18:30 +00:00
m_clearDepthPassDesc.colorAttachments[0].texture = m_colorTex;
m_clearDepthPassDesc.colorAttachments[0].loadAction = MTLLoadActionLoad;
m_clearDepthPassDesc.colorAttachments[0].storeAction = MTLStoreActionStore;
2016-04-03 06:18:30 +00:00
m_clearDepthPassDesc.depthAttachment.texture = m_depthTex;
m_clearDepthPassDesc.depthAttachment.loadAction = MTLLoadActionClear;
m_clearDepthPassDesc.depthAttachment.storeAction = MTLStoreActionStore;
m_clearDepthPassDesc.depthAttachment.clearDepth = 0.f;
}
{
m_clearColorPassDesc = [MTLRenderPassDescriptor renderPassDescriptor];
m_clearColorPassDesc.colorAttachments[0].texture = m_colorTex;
m_clearColorPassDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
m_clearColorPassDesc.colorAttachments[0].storeAction = MTLStoreActionStore;
m_clearColorPassDesc.depthAttachment.texture = m_depthTex;
m_clearColorPassDesc.depthAttachment.loadAction = MTLLoadActionLoad;
m_clearColorPassDesc.depthAttachment.storeAction = MTLStoreActionStore;
2016-04-03 06:22:03 +00:00
m_clearColorPassDesc.depthAttachment.clearDepth = 0.f;
2016-04-03 06:18:30 +00:00
}
{
m_clearBothPassDesc = [MTLRenderPassDescriptor renderPassDescriptor];
m_clearBothPassDesc.colorAttachments[0].texture = m_colorTex;
m_clearBothPassDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
m_clearBothPassDesc.colorAttachments[0].storeAction = MTLStoreActionStore;
m_clearBothPassDesc.depthAttachment.texture = m_depthTex;
m_clearBothPassDesc.depthAttachment.loadAction = MTLLoadActionClear;
m_clearBothPassDesc.depthAttachment.storeAction = MTLStoreActionStore;
2016-04-03 06:22:03 +00:00
m_clearBothPassDesc.depthAttachment.clearDepth = 0.f;
2016-04-03 06:18:30 +00:00
}
}
}
2016-02-16 19:41:16 +00:00
MetalTextureR(MetalContext* ctx, size_t width, size_t height, size_t samples,
bool enableShaderBindTexture)
: m_width(width), m_height(height), m_samples(samples), m_enableShaderBindTexture(enableShaderBindTexture)
{
if (samples == 0) m_samples = 1;
Setup(ctx, width, height, samples, enableShaderBindTexture);
}
public:
size_t samples() const {return m_samples;}
id<MTLTexture> m_colorTex;
2016-01-11 22:26:40 +00:00
id<MTLTexture> m_depthTex;
id<MTLTexture> m_colorBindTex;
2016-01-11 22:26:40 +00:00
MTLRenderPassDescriptor* m_passDesc;
2016-04-03 06:18:30 +00:00
MTLRenderPassDescriptor* m_clearDepthPassDesc;
MTLRenderPassDescriptor* m_clearColorPassDesc;
MTLRenderPassDescriptor* m_clearBothPassDesc;
2015-11-09 02:24:45 +00:00
~MetalTextureR() = default;
2016-02-16 19:41:16 +00:00
2015-11-09 02:24:45 +00:00
void resize(MetalContext* ctx, size_t width, size_t height)
{
if (width < 1)
width = 1;
if (height < 1)
height = 1;
m_width = width;
m_height = height;
Setup(ctx, width, height, m_samples, m_enableShaderBindTexture);
}
};
2016-02-16 19:41:16 +00:00
static const size_t SEMANTIC_SIZE_TABLE[] =
{
2015-11-28 04:07:53 +00:00
0,
12,
2015-11-28 04:07:53 +00:00
16,
12,
2015-11-28 04:07:53 +00:00
16,
16,
4,
8,
2015-11-28 04:07:53 +00:00
16,
16,
16
};
2015-11-09 02:24:45 +00:00
static const MTLVertexFormat SEMANTIC_TYPE_TABLE[] =
{
2015-11-28 04:07:53 +00:00
MTLVertexFormatInvalid,
2015-11-09 02:24:45 +00:00
MTLVertexFormatFloat3,
2015-11-28 04:07:53 +00:00
MTLVertexFormatFloat4,
2015-11-09 02:24:45 +00:00
MTLVertexFormatFloat3,
2015-11-28 04:07:53 +00:00
MTLVertexFormatFloat4,
MTLVertexFormatFloat4,
2015-11-09 02:24:45 +00:00
MTLVertexFormatUChar4Normalized,
MTLVertexFormatFloat2,
2015-11-28 04:07:53 +00:00
MTLVertexFormatFloat4,
MTLVertexFormatFloat4,
2015-11-09 02:24:45 +00:00
MTLVertexFormatFloat4
};
2015-11-09 02:24:45 +00:00
struct MetalVertexFormat : IVertexFormat
{
size_t m_elementCount;
2016-01-11 22:26:40 +00:00
MTLVertexDescriptor* m_vdesc;
2015-11-09 02:24:45 +00:00
MetalVertexFormat(size_t elementCount, const VertexElementDescriptor* elements)
: m_elementCount(elementCount)
{
2015-11-09 02:24:45 +00:00
size_t stride = 0;
2015-11-28 04:07:53 +00:00
size_t instStride = 0;
2015-11-09 02:24:45 +00:00
for (size_t i=0 ; i<elementCount ; ++i)
{
const VertexElementDescriptor* elemin = &elements[i];
2015-11-28 04:07:53 +00:00
int semantic = int(elemin->semantic & VertexSemantic::SemanticMask);
if ((elemin->semantic & VertexSemantic::Instanced) != VertexSemantic::None)
instStride += SEMANTIC_SIZE_TABLE[semantic];
else
stride += SEMANTIC_SIZE_TABLE[semantic];
2015-11-09 02:24:45 +00:00
}
2016-02-16 19:41:16 +00:00
2015-11-09 02:24:45 +00:00
m_vdesc = [MTLVertexDescriptor vertexDescriptor];
2016-01-11 22:26:40 +00:00
MTLVertexBufferLayoutDescriptor* layoutDesc = m_vdesc.layouts[0];
2015-11-09 06:45:14 +00:00
layoutDesc.stride = stride;
layoutDesc.stepFunction = MTLVertexStepFunctionPerVertex;
layoutDesc.stepRate = 1;
2016-02-16 19:41:16 +00:00
2016-01-11 22:26:40 +00:00
layoutDesc = m_vdesc.layouts[1];
2015-11-28 04:07:53 +00:00
layoutDesc.stride = instStride;
layoutDesc.stepFunction = MTLVertexStepFunctionPerInstance;
layoutDesc.stepRate = 1;
2016-02-16 19:41:16 +00:00
size_t offset = 0;
2015-11-28 04:07:53 +00:00
size_t instOffset = 0;
for (size_t i=0 ; i<elementCount ; ++i)
{
const VertexElementDescriptor* elemin = &elements[i];
2016-01-11 22:26:40 +00:00
MTLVertexAttributeDescriptor* attrDesc = m_vdesc.attributes[i];
2015-11-28 04:07:53 +00:00
int semantic = int(elemin->semantic & VertexSemantic::SemanticMask);
if ((elemin->semantic & VertexSemantic::Instanced) != VertexSemantic::None)
{
attrDesc.offset = instOffset;
attrDesc.bufferIndex = 1;
instOffset += SEMANTIC_SIZE_TABLE[semantic];
}
else
{
attrDesc.offset = offset;
attrDesc.bufferIndex = 0;
offset += SEMANTIC_SIZE_TABLE[semantic];
}
attrDesc.format = SEMANTIC_TYPE_TABLE[semantic];
}
}
};
2016-02-16 19:41:16 +00:00
2015-11-09 02:24:45 +00:00
static const MTLBlendFactor BLEND_FACTOR_TABLE[] =
{
MTLBlendFactorZero,
MTLBlendFactorOne,
MTLBlendFactorSourceColor,
MTLBlendFactorOneMinusSourceColor,
MTLBlendFactorDestinationColor,
MTLBlendFactorOneMinusDestinationColor,
MTLBlendFactorSourceAlpha,
MTLBlendFactorOneMinusSourceAlpha,
MTLBlendFactorDestinationAlpha,
MTLBlendFactorOneMinusDestinationAlpha
};
static const MTLPrimitiveType PRIMITIVE_TABLE[] =
{
MTLPrimitiveTypeTriangle,
MTLPrimitiveTypeTriangleStrip
};
2015-11-09 02:24:45 +00:00
class MetalShaderPipeline : public IShaderPipeline
{
2015-11-09 02:24:45 +00:00
friend class MetalDataFactory;
friend class MetalCommandQueue;
2015-11-09 02:24:45 +00:00
MTLCullMode m_cullMode = MTLCullModeNone;
MTLPrimitiveType m_drawPrim;
2016-02-16 19:41:16 +00:00
2015-11-09 02:24:45 +00:00
MetalShaderPipeline(MetalContext* ctx, id<MTLFunction> vert, id<MTLFunction> frag,
2015-11-28 04:07:53 +00:00
const MetalVertexFormat* vtxFmt, NSUInteger targetSamples,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
bool depthTest, bool depthWrite, bool backfaceCulling)
: m_drawPrim(PRIMITIVE_TABLE[int(prim)])
{
2015-11-09 02:24:45 +00:00
if (backfaceCulling)
m_cullMode = MTLCullModeBack;
2016-02-16 19:41:16 +00:00
2016-01-11 22:26:40 +00:00
MTLRenderPipelineDescriptor* desc = [MTLRenderPipelineDescriptor new];
desc.vertexFunction = vert;
desc.fragmentFunction = frag;
desc.vertexDescriptor = vtxFmt->m_vdesc;
desc.sampleCount = targetSamples;
desc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
desc.colorAttachments[0].blendingEnabled = dstFac != BlendFactor::Zero;
desc.colorAttachments[0].sourceRGBBlendFactor = BLEND_FACTOR_TABLE[int(srcFac)];
desc.colorAttachments[0].destinationRGBBlendFactor = BLEND_FACTOR_TABLE[int(dstFac)];
desc.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float;
desc.inputPrimitiveTopology = MTLPrimitiveTopologyClassTriangle;
2015-11-09 02:24:45 +00:00
NSError* err = nullptr;
2016-01-11 22:26:40 +00:00
m_state = [ctx->m_dev newRenderPipelineStateWithDescriptor:desc error:&err];
2015-11-09 02:24:45 +00:00
if (err)
2016-03-08 21:18:38 +00:00
Log.report(logvisor::Fatal, "error making shader pipeline: %s",
2015-11-09 02:24:45 +00:00
[[err localizedDescription] UTF8String]);
2016-02-16 19:41:16 +00:00
2016-01-11 22:26:40 +00:00
MTLDepthStencilDescriptor* dsDesc = [MTLDepthStencilDescriptor new];
2015-11-09 02:24:45 +00:00
if (depthTest)
dsDesc.depthCompareFunction = MTLCompareFunctionGreaterEqual;
2016-01-11 22:26:40 +00:00
dsDesc.depthWriteEnabled = depthWrite;
m_dsState = [ctx->m_dev newDepthStencilStateWithDescriptor:dsDesc];
}
public:
2016-01-11 22:26:40 +00:00
id<MTLRenderPipelineState> m_state;
id<MTLDepthStencilState> m_dsState;
2015-11-09 02:24:45 +00:00
~MetalShaderPipeline() = default;
MetalShaderPipeline& operator=(const MetalShaderPipeline&) = delete;
MetalShaderPipeline(const MetalShaderPipeline&) = delete;
2016-02-16 19:41:16 +00:00
2015-11-09 02:24:45 +00:00
void bind(id<MTLRenderCommandEncoder> enc)
{
2016-01-11 22:26:40 +00:00
[enc setRenderPipelineState:m_state];
[enc setDepthStencilState:m_dsState];
2015-11-09 02:24:45 +00:00
[enc setCullMode:m_cullMode];
}
2015-11-09 02:24:45 +00:00
};
2016-02-16 19:41:16 +00:00
2015-11-09 02:24:45 +00:00
static id<MTLBuffer> GetBufferGPUResource(const IGraphicsBuffer* buf, int idx)
{
if (buf->dynamic())
{
2015-11-09 02:24:45 +00:00
const MetalGraphicsBufferD* cbuf = static_cast<const MetalGraphicsBufferD*>(buf);
2016-01-11 22:26:40 +00:00
return cbuf->m_bufs[idx];
}
else
{
2015-11-09 02:24:45 +00:00
const MetalGraphicsBufferS* cbuf = static_cast<const MetalGraphicsBufferS*>(buf);
2016-01-11 22:26:40 +00:00
return cbuf->m_buf;
}
}
2015-11-09 02:24:45 +00:00
static id<MTLTexture> GetTextureGPUResource(const ITexture* tex, int idx)
{
2015-11-28 04:07:53 +00:00
switch (tex->type())
{
case TextureType::Dynamic:
{
2015-11-09 02:24:45 +00:00
const MetalTextureD* ctex = static_cast<const MetalTextureD*>(tex);
2016-01-11 22:26:40 +00:00
return ctex->m_texs[idx];
}
2015-11-28 04:07:53 +00:00
case TextureType::Static:
{
2015-11-09 02:24:45 +00:00
const MetalTextureS* ctex = static_cast<const MetalTextureS*>(tex);
2016-01-11 22:26:40 +00:00
return ctex->m_tex;
}
2015-11-28 04:07:53 +00:00
case TextureType::StaticArray:
{
const MetalTextureSA* ctex = static_cast<const MetalTextureSA*>(tex);
2016-01-11 22:26:40 +00:00
return ctex->m_tex;
2015-11-28 04:07:53 +00:00
}
case TextureType::Render:
{
2015-11-09 02:24:45 +00:00
const MetalTextureR* ctex = static_cast<const MetalTextureR*>(tex);
return ctex->m_colorBindTex;
}
2015-11-28 04:07:53 +00:00
default: break;
}
2015-11-09 02:24:45 +00:00
return nullptr;
}
2015-11-09 02:24:45 +00:00
struct MetalShaderDataBinding : IShaderDataBinding
{
2015-11-09 02:24:45 +00:00
MetalShaderPipeline* m_pipeline;
IGraphicsBuffer* m_vbuf;
2015-11-28 04:07:53 +00:00
IGraphicsBuffer* m_instVbo;
IGraphicsBuffer* m_ibuf;
size_t m_ubufCount;
std::unique_ptr<IGraphicsBuffer*[]> m_ubufs;
2016-04-05 02:37:46 +00:00
std::unique_ptr<size_t[]> m_ubufOffs;
std::unique_ptr<bool[]> m_fubufs;
size_t m_texCount;
std::unique_ptr<ITexture*[]> m_texs;
2015-11-09 02:24:45 +00:00
MetalShaderDataBinding(MetalContext* ctx,
IShaderPipeline* pipeline,
2015-11-28 04:07:53 +00:00
IGraphicsBuffer* vbuf, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibuf,
2016-04-04 06:13:11 +00:00
size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages,
2016-03-30 21:07:12 +00:00
const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, ITexture** texs)
2015-11-09 02:24:45 +00:00
: m_pipeline(static_cast<MetalShaderPipeline*>(pipeline)),
m_vbuf(vbuf),
2015-11-28 04:07:53 +00:00
m_instVbo(instVbo),
m_ibuf(ibuf),
m_ubufCount(ubufCount),
m_ubufs(new IGraphicsBuffer*[ubufCount]),
m_texCount(texCount),
m_texs(new ITexture*[texCount])
{
2016-04-05 02:37:46 +00:00
if (ubufCount && ubufStages)
2016-03-30 21:07:12 +00:00
{
2016-04-05 02:37:46 +00:00
m_fubufs.reset(new bool[ubufCount]);
for (size_t i=0 ; i<ubufCount ; ++i)
m_fubufs[i] = ubufStages[i] == PipelineStage::Fragment;
}
if (ubufCount && ubufOffs && ubufSizes)
{
m_ubufOffs.reset(new size_t[ubufCount]);
2016-03-30 21:07:12 +00:00
for (size_t i=0 ; i<ubufCount ; ++i)
{
#ifndef NDEBUG
if (ubufOffs[i] % 256)
Log.report(logvisor::Fatal, "non-256-byte-aligned uniform-offset %d provided to newShaderDataBinding", int(i));
#endif
2016-04-05 02:37:46 +00:00
m_ubufOffs[i] = ubufOffs[i];
2016-03-30 21:07:12 +00:00
}
}
for (size_t i=0 ; i<ubufCount ; ++i)
2016-03-30 21:07:12 +00:00
{
#ifndef NDEBUG
if (!ubufs[i])
Log.report(logvisor::Fatal, "null uniform-buffer %d provided to newShaderDataBinding", int(i));
#endif
m_ubufs[i] = ubufs[i];
2016-03-30 21:07:12 +00:00
}
for (size_t i=0 ; i<texCount ; ++i)
2016-03-30 21:07:12 +00:00
{
m_texs[i] = texs[i];
2016-03-30 21:07:12 +00:00
}
}
2016-02-16 19:41:16 +00:00
2015-11-09 02:24:45 +00:00
void bind(id<MTLRenderCommandEncoder> enc, int b)
{
2015-11-09 02:24:45 +00:00
m_pipeline->bind(enc);
2015-11-28 04:07:53 +00:00
if (m_vbuf)
[enc setVertexBuffer:GetBufferGPUResource(m_vbuf, b) offset:0 atIndex:0];
if (m_instVbo)
[enc setVertexBuffer:GetBufferGPUResource(m_instVbo, b) offset:0 atIndex:1];
2016-04-05 02:37:46 +00:00
if (m_ubufOffs)
2016-03-30 21:07:12 +00:00
for (size_t i=0 ; i<m_ubufCount ; ++i)
2016-04-05 02:37:46 +00:00
{
if (m_fubufs && m_fubufs[i])
[enc setFragmentBuffer:GetBufferGPUResource(m_ubufs[i], b) offset:m_ubufOffs[i] atIndex:i+2];
2016-04-04 06:13:11 +00:00
else
2016-04-05 02:37:46 +00:00
[enc setVertexBuffer:GetBufferGPUResource(m_ubufs[i], b) offset:m_ubufOffs[i] atIndex:i+2];
}
2016-03-30 21:07:12 +00:00
else
for (size_t i=0 ; i<m_ubufCount ; ++i)
2016-04-05 02:37:46 +00:00
{
if (m_fubufs && m_fubufs[i])
[enc setFragmentBuffer:GetBufferGPUResource(m_ubufs[i], b) offset:0 atIndex:i+2];
else
[enc setVertexBuffer:GetBufferGPUResource(m_ubufs[i], b) offset:0 atIndex:i+2];
}
2015-11-09 02:24:45 +00:00
for (size_t i=0 ; i<m_texCount ; ++i)
2016-07-31 20:25:02 +00:00
if (m_texs[i])
[enc setFragmentTexture:GetTextureGPUResource(m_texs[i], b) atIndex:i];
}
};
2015-11-09 02:24:45 +00:00
struct MetalCommandQueue : IGraphicsCommandQueue
{
2015-11-21 02:16:15 +00:00
Platform platform() const {return IGraphicsDataFactory::Platform::Metal;}
2015-11-09 02:24:45 +00:00
const char* platformName() const {return "Metal";}
MetalContext* m_ctx;
IWindow* m_parentWindow;
IGraphicsContext* m_parent;
2016-01-11 22:26:40 +00:00
id<MTLCommandBuffer> m_cmdBuf;
id<MTLRenderCommandEncoder> m_enc;
2015-12-05 01:12:52 +00:00
bool m_running = true;
2016-02-16 19:41:16 +00:00
size_t m_fillBuf = 0;
size_t m_drawBuf = 0;
2016-02-16 19:41:16 +00:00
2015-11-09 02:24:45 +00:00
MetalCommandQueue(MetalContext* ctx, IWindow* parentWindow, IGraphicsContext* parent)
: m_ctx(ctx), m_parentWindow(parentWindow), m_parent(parent)
{
2015-11-09 06:45:14 +00:00
@autoreleasepool
{
2016-01-11 22:26:40 +00:00
m_cmdBuf = [ctx->m_q commandBuffer];
2015-11-09 06:45:14 +00:00
}
}
2016-02-16 19:41:16 +00:00
2015-12-05 01:12:52 +00:00
void stopRenderer()
{
m_running = false;
if (m_inProgress)
2016-01-11 22:26:40 +00:00
[m_cmdBuf waitUntilCompleted];
2015-12-05 01:12:52 +00:00
}
2016-02-16 19:41:16 +00:00
2015-12-05 01:12:52 +00:00
~MetalCommandQueue()
{
if (m_running) stopRenderer();
}
2016-02-16 19:41:16 +00:00
2015-11-09 02:24:45 +00:00
MetalShaderDataBinding* m_boundData = nullptr;
MTLPrimitiveType m_currentPrimitive = MTLPrimitiveTypeTriangle;
void setShaderDataBinding(IShaderDataBinding* binding)
{
2015-11-09 02:24:45 +00:00
MetalShaderDataBinding* cbind = static_cast<MetalShaderDataBinding*>(binding);
2016-01-11 22:26:40 +00:00
cbind->bind(m_enc, m_fillBuf);
2015-11-09 02:24:45 +00:00
m_boundData = cbind;
m_currentPrimitive = cbind->m_pipeline->m_drawPrim;
}
2016-02-16 19:41:16 +00:00
2015-11-09 02:24:45 +00:00
MetalTextureR* m_boundTarget = nullptr;
2016-04-03 06:18:30 +00:00
void _setRenderTarget(ITextureR* target, bool clearColor, bool clearDepth)
{
2015-11-09 02:24:45 +00:00
MetalTextureR* ctarget = static_cast<MetalTextureR*>(target);
2016-01-11 22:26:40 +00:00
[m_enc endEncoding];
2015-11-18 23:55:25 +00:00
@autoreleasepool
{
2016-04-03 06:18:30 +00:00
if (clearColor && clearDepth)
m_enc = [m_cmdBuf renderCommandEncoderWithDescriptor:ctarget->m_clearBothPassDesc];
else if (clearColor)
m_enc = [m_cmdBuf renderCommandEncoderWithDescriptor:ctarget->m_clearColorPassDesc];
else if (clearDepth)
m_enc = [m_cmdBuf renderCommandEncoderWithDescriptor:ctarget->m_clearDepthPassDesc];
else
m_enc = [m_cmdBuf renderCommandEncoderWithDescriptor:ctarget->m_passDesc];
[m_enc setFrontFacingWinding:MTLWindingCounterClockwise];
2015-11-18 23:55:25 +00:00
}
m_boundTarget = ctarget;
}
2016-02-16 19:41:16 +00:00
2016-04-03 06:18:30 +00:00
void setRenderTarget(ITextureR* target)
{
_setRenderTarget(target, false, false);
}
MTLViewport m_boundVp = {};
2016-04-05 02:37:46 +00:00
void setViewport(const SWindowRect& rect, float znear, float zfar)
{
m_boundVp = MTLViewport{double(rect.location[0]), double(rect.location[1]),
double(rect.size[0]), double(rect.size[1]), znear, zfar};
[m_enc setViewport:m_boundVp];
}
2016-02-16 19:41:16 +00:00
MTLScissorRect m_boundScissor = {};
2015-11-28 04:07:53 +00:00
void setScissor(const SWindowRect& rect)
{
if (m_boundTarget)
{
SWindowRect intersectRect = rect.intersect(SWindowRect(0, 0, m_boundTarget->m_width, m_boundTarget->m_height));
m_boundScissor = MTLScissorRect{NSUInteger(intersectRect.location[0]),
NSUInteger(m_boundTarget->m_height - intersectRect.location[1] - intersectRect.size[1]),
NSUInteger(intersectRect.size[0]), NSUInteger(intersectRect.size[1])};
[m_enc setScissorRect:m_boundScissor];
}
2015-11-28 04:07:53 +00:00
}
2016-02-16 19:41:16 +00:00
2015-11-09 02:24:45 +00:00
std::unordered_map<MetalTextureR*, std::pair<size_t, size_t>> m_texResizes;
void resizeRenderTexture(ITextureR* tex, size_t width, size_t height)
{
2015-11-09 02:24:45 +00:00
MetalTextureR* ctex = static_cast<MetalTextureR*>(tex);
m_texResizes[ctex] = std::make_pair(width, height);
}
2015-12-21 00:40:52 +00:00
void schedulePostFrameHandler(std::function<void(void)>&& func)
{
func();
}
2016-02-16 19:41:16 +00:00
2015-11-18 23:55:25 +00:00
void flushBufferUpdates() {}
2016-02-16 19:41:16 +00:00
float m_clearColor[4] = {0.0,0.0,0.0,1.0};
void setClearColor(const float rgba[4])
{
m_clearColor[0] = rgba[0];
m_clearColor[1] = rgba[1];
m_clearColor[2] = rgba[2];
m_clearColor[3] = rgba[3];
}
2016-02-16 19:41:16 +00:00
void clearTarget(bool render=true, bool depth=true)
{
if (!m_boundTarget)
return;
2016-04-03 06:18:30 +00:00
_setRenderTarget(m_boundTarget, render, depth);
}
2016-02-16 19:41:16 +00:00
void draw(size_t start, size_t count)
{
[m_enc drawPrimitives:m_currentPrimitive vertexStart:start vertexCount:count];
}
2016-02-16 19:41:16 +00:00
void drawIndexed(size_t start, size_t count)
{
[m_enc drawIndexedPrimitives:m_currentPrimitive
2016-01-11 22:26:40 +00:00
indexCount:count
indexType:MTLIndexTypeUInt32
indexBuffer:GetBufferGPUResource(m_boundData->m_ibuf, m_fillBuf)
indexBufferOffset:start*4];
}
2016-02-16 19:41:16 +00:00
void drawInstances(size_t start, size_t count, size_t instCount)
{
[m_enc drawPrimitives:m_currentPrimitive
2016-02-24 21:07:48 +00:00
vertexStart:start vertexCount:count instanceCount:instCount];
}
2016-02-16 19:41:16 +00:00
void drawInstancesIndexed(size_t start, size_t count, size_t instCount)
{
[m_enc drawIndexedPrimitives:m_currentPrimitive
2016-01-11 22:26:40 +00:00
indexCount:count
indexType:MTLIndexTypeUInt32
indexBuffer:GetBufferGPUResource(m_boundData->m_ibuf, m_fillBuf)
indexBufferOffset:start*4
instanceCount:instCount];
}
2016-02-16 19:41:16 +00:00
2016-02-25 05:06:13 +00:00
void resolveBindTexture(ITextureR* texture, const SWindowRect& rect, bool tlOrigin, bool color, bool depth)
{
MetalTextureR* tex = static_cast<MetalTextureR*>(texture);
if (color && tex->m_enableShaderBindTexture)
{
[m_enc endEncoding];
@autoreleasepool
{
SWindowRect intersectRect = rect.intersect(SWindowRect(0, 0, tex->m_width, tex->m_height));
NSUInteger y = tlOrigin ? intersectRect.location[1] : int(tex->m_height) - intersectRect.location[1] - intersectRect.size[1];
MTLOrigin origin = {NSUInteger(intersectRect.location[0]), y, 0};
id<MTLBlitCommandEncoder> blitEnc = [m_cmdBuf blitCommandEncoder];
[blitEnc copyFromTexture:tex->m_colorTex
sourceSlice:0
sourceLevel:0
sourceOrigin:origin
sourceSize:MTLSizeMake(intersectRect.size[0], intersectRect.size[1], 1)
toTexture:tex->m_colorBindTex
destinationSlice:0
destinationLevel:0
destinationOrigin:origin];
[blitEnc endEncoding];
m_enc = [m_cmdBuf renderCommandEncoderWithDescriptor:tex->m_passDesc];
2016-04-03 06:18:30 +00:00
[m_enc setFrontFacingWinding:MTLWindingCounterClockwise];
if (m_boundVp.width || m_boundVp.height)
[m_enc setViewport:m_boundVp];
if (m_boundScissor.width || m_boundScissor.height)
[m_enc setScissorRect:m_boundScissor];
}
}
2016-02-25 05:06:13 +00:00
}
MetalTextureR* m_needsDisplay = nullptr;
void resolveDisplay(ITextureR* source)
{
m_needsDisplay = static_cast<MetalTextureR*>(source);
2015-11-09 02:24:45 +00:00
}
2016-02-16 19:41:16 +00:00
2015-11-09 02:24:45 +00:00
bool m_inProgress = false;
void execute()
{
2015-12-05 01:12:52 +00:00
if (!m_running)
return;
2016-02-16 19:41:16 +00:00
2015-12-02 22:25:30 +00:00
/* Update dynamic data here */
MetalDataFactory* gfxF = static_cast<MetalDataFactory*>(m_parent->getDataFactory());
2015-12-18 21:33:53 +00:00
std::unique_lock<std::mutex> datalk(gfxF->m_committedMutex);
2015-12-02 22:25:30 +00:00
for (MetalData* d : gfxF->m_committedData)
{
for (std::unique_ptr<MetalGraphicsBufferD>& b : d->m_DBufs)
b->update(m_fillBuf);
for (std::unique_ptr<MetalTextureD>& t : d->m_DTexs)
t->update(m_fillBuf);
}
2015-12-18 21:33:53 +00:00
datalk.unlock();
2016-02-16 19:41:16 +00:00
2015-11-09 06:45:14 +00:00
@autoreleasepool
{
2016-01-11 22:26:40 +00:00
[m_enc endEncoding];
m_enc = nullptr;
2016-02-16 19:41:16 +00:00
2015-11-09 06:45:14 +00:00
/* Abandon if in progress (renderer too slow) */
if (m_inProgress)
{
2016-01-11 22:26:40 +00:00
m_cmdBuf = [m_ctx->m_q commandBuffer];
2015-11-09 06:45:14 +00:00
return;
}
2016-02-16 19:41:16 +00:00
2015-11-09 06:45:14 +00:00
/* Perform texture resizes */
if (m_texResizes.size())
{
for (const auto& resize : m_texResizes)
resize.first->resize(m_ctx, resize.second.first, resize.second.second);
m_texResizes.clear();
2016-01-11 22:26:40 +00:00
m_cmdBuf = [m_ctx->m_q commandBuffer];
2015-11-09 06:45:14 +00:00
return;
}
2016-02-16 19:41:16 +00:00
/* Wrap up and present if needed */
if (m_needsDisplay)
{
MetalContext::Window& w = m_ctx->m_windows[m_parentWindow];
@autoreleasepool
{
{
std::unique_lock<std::mutex> lk(w.m_resizeLock);
if (w.m_needsResize)
{
w.m_metalLayer.drawableSize = w.m_size;
w.m_needsResize = NO;
m_needsDisplay = nullptr;
return;
}
}
id<CAMetalDrawable> drawable = [w.m_metalLayer nextDrawable];
if (drawable)
{
id<MTLTexture> dest = drawable.texture;
if (m_needsDisplay->m_colorTex.width == dest.width &&
m_needsDisplay->m_colorTex.height == dest.height)
{
2016-01-11 22:26:40 +00:00
id<MTLBlitCommandEncoder> blitEnc = [m_cmdBuf blitCommandEncoder];
[blitEnc copyFromTexture:m_needsDisplay->m_colorTex
sourceSlice:0
sourceLevel:0
sourceOrigin:MTLOriginMake(0, 0, 0)
sourceSize:MTLSizeMake(dest.width, dest.height, 1)
toTexture:dest
destinationSlice:0
destinationLevel:0
destinationOrigin:MTLOriginMake(0, 0, 0)];
[blitEnc endEncoding];
2016-01-11 22:26:40 +00:00
[m_cmdBuf presentDrawable:drawable];
}
}
}
m_needsDisplay = nullptr;
}
2016-02-16 19:41:16 +00:00
2015-11-09 06:45:14 +00:00
m_drawBuf = m_fillBuf;
2015-12-02 22:25:30 +00:00
m_fillBuf ^= 1;
2016-02-16 19:41:16 +00:00
2016-01-11 22:26:40 +00:00
[m_cmdBuf addCompletedHandler:^(id<MTLCommandBuffer> buf) {m_inProgress = false;}];
2015-11-09 06:45:14 +00:00
m_inProgress = true;
2016-01-11 22:26:40 +00:00
[m_cmdBuf commit];
m_cmdBuf = [m_ctx->m_q commandBuffer];
}
}
};
2016-02-16 19:41:16 +00:00
2015-12-02 22:25:30 +00:00
void MetalGraphicsBufferD::update(int b)
{
int slot = 1 << b;
if ((slot & m_validSlots) == 0)
{
2016-01-11 22:26:40 +00:00
id<MTLBuffer> res = m_bufs[b];
2015-12-02 22:25:30 +00:00
memcpy(res.contents, m_cpuBuf.get(), m_sz);
m_validSlots |= slot;
}
}
2015-11-09 02:24:45 +00:00
void MetalGraphicsBufferD::load(const void* data, size_t sz)
{
2015-12-02 22:25:30 +00:00
size_t bufSz = std::min(sz, m_sz);
memcpy(m_cpuBuf.get(), data, bufSz);
m_validSlots = 0;
}
2015-11-09 02:24:45 +00:00
void* MetalGraphicsBufferD::map(size_t sz)
{
2015-12-02 22:25:30 +00:00
if (sz > m_sz)
return nullptr;
return m_cpuBuf.get();
}
void MetalGraphicsBufferD::unmap()
{
m_validSlots = 0;
}
2015-12-02 22:25:30 +00:00
void MetalTextureD::update(int b)
{
int slot = 1 << b;
if ((slot & m_validSlots) == 0)
{
2016-01-11 22:26:40 +00:00
id<MTLTexture> res = m_texs[b];
2015-12-02 22:25:30 +00:00
[res replaceRegion:MTLRegionMake2D(0, 0, m_width, m_height)
mipmapLevel:0 withBytes:m_cpuBuf.get() bytesPerRow:m_width*m_pxPitch];
m_validSlots |= slot;
}
}
2015-11-09 02:24:45 +00:00
void MetalTextureD::load(const void* data, size_t sz)
{
2015-12-02 22:25:30 +00:00
size_t bufSz = std::min(sz, m_cpuSz);
memcpy(m_cpuBuf.get(), data, bufSz);
m_validSlots = 0;
}
2015-11-09 02:24:45 +00:00
void* MetalTextureD::map(size_t sz)
{
2015-12-02 22:25:30 +00:00
if (sz > m_cpuSz)
return nullptr;
return m_cpuBuf.get();
}
2015-11-09 02:24:45 +00:00
void MetalTextureD::unmap()
{
2015-12-02 22:25:30 +00:00
m_validSlots = 0;
}
2016-02-16 19:41:16 +00:00
2016-02-24 21:07:48 +00:00
MetalDataFactory::MetalDataFactory(IGraphicsContext* parent, MetalContext* ctx, uint32_t sampleCount)
: m_parent(parent), m_ctx(ctx), m_sampleCount(sampleCount) {}
2016-02-16 19:41:16 +00:00
2016-03-30 21:07:12 +00:00
IGraphicsBufferS* MetalDataFactory::Context::newStaticBuffer(BufferUse use, const void* data, size_t stride, size_t count)
{
2016-03-30 21:07:12 +00:00
MetalGraphicsBufferS* retval = new MetalGraphicsBufferS(use, m_parent.m_ctx, data, stride, count);
2015-12-18 21:33:53 +00:00
m_deferredData->m_SBufs.emplace_back(retval);
2015-11-09 02:24:45 +00:00
return retval;
}
2016-03-30 21:07:12 +00:00
IGraphicsBufferD* MetalDataFactory::Context::newDynamicBuffer(BufferUse use, size_t stride, size_t count)
{
2016-03-30 21:07:12 +00:00
MetalCommandQueue* q = static_cast<MetalCommandQueue*>(m_parent.m_parent->getCommandQueue());
MetalGraphicsBufferD* retval = new MetalGraphicsBufferD(q, use, m_parent.m_ctx, stride, count);
2015-12-18 21:33:53 +00:00
m_deferredData->m_DBufs.emplace_back(retval);
2015-11-09 02:24:45 +00:00
return retval;
}
2016-03-30 21:07:12 +00:00
ITextureS* MetalDataFactory::Context::newStaticTexture(size_t width, size_t height, size_t mips, TextureFormat fmt,
const void* data, size_t sz)
{
2016-03-30 21:07:12 +00:00
MetalTextureS* retval = new MetalTextureS(m_parent.m_ctx, width, height, mips, fmt, data, sz);
2015-12-18 21:33:53 +00:00
m_deferredData->m_STexs.emplace_back(retval);
2015-11-09 02:24:45 +00:00
return retval;
}
2016-03-30 21:07:12 +00:00
ITextureSA* MetalDataFactory::Context::newStaticArrayTexture(size_t width, size_t height, size_t layers, TextureFormat fmt,
const void* data, size_t sz)
{
2016-03-30 21:07:12 +00:00
MetalTextureSA* retval = new MetalTextureSA(m_parent.m_ctx, width, height, layers, fmt, data, sz);
2015-12-18 21:33:53 +00:00
m_deferredData->m_SATexs.emplace_back(retval);
2015-11-28 04:07:53 +00:00
return retval;
}
2016-03-30 21:07:12 +00:00
ITextureD* MetalDataFactory::Context::newDynamicTexture(size_t width, size_t height, TextureFormat fmt)
{
2016-03-30 21:07:12 +00:00
MetalCommandQueue* q = static_cast<MetalCommandQueue*>(m_parent.m_parent->getCommandQueue());
MetalTextureD* retval = new MetalTextureD(q, m_parent.m_ctx, width, height, fmt);
2015-12-18 21:33:53 +00:00
m_deferredData->m_DTexs.emplace_back(retval);
2015-11-09 02:24:45 +00:00
return retval;
}
2016-03-30 21:07:12 +00:00
ITextureR* MetalDataFactory::Context::newRenderTexture(size_t width, size_t height,
bool enableShaderColorBinding, bool enableShaderDepthBinding)
{
2016-03-30 21:07:12 +00:00
MetalTextureR* retval = new MetalTextureR(m_parent.m_ctx, width, height, m_parent.m_sampleCount, enableShaderColorBinding);
2015-12-18 21:33:53 +00:00
m_deferredData->m_RTexs.emplace_back(retval);
2015-11-09 02:24:45 +00:00
return retval;
}
2016-03-30 21:07:12 +00:00
IVertexFormat* MetalDataFactory::Context::newVertexFormat(size_t elementCount, const VertexElementDescriptor* elements)
{
2015-11-09 02:24:45 +00:00
MetalVertexFormat* retval = new struct MetalVertexFormat(elementCount, elements);
2015-12-18 21:33:53 +00:00
m_deferredData->m_VFmts.emplace_back(retval);
2015-11-09 02:24:45 +00:00
return retval;
}
2016-03-30 21:07:12 +00:00
IShaderPipeline* MetalDataFactory::Context::newShaderPipeline(const char* vertSource, const char* fragSource,
IVertexFormat* vtxFmt, unsigned targetSamples,
BlendFactor srcFac, BlendFactor dstFac, Primitive prim,
bool depthTest, bool depthWrite, bool backfaceCulling)
{
2016-01-11 22:26:40 +00:00
MTLCompileOptions* compOpts = [MTLCompileOptions new];
compOpts.languageVersion = MTLLanguageVersion1_1;
2015-11-09 02:24:45 +00:00
NSError* err = nullptr;
2016-02-16 19:41:16 +00:00
2016-03-30 21:07:12 +00:00
id<MTLLibrary> vertShaderLib = [m_parent.m_ctx->m_dev newLibraryWithSource:@(vertSource)
options:compOpts
error:&err];
2016-08-03 23:45:52 +00:00
if (!vertShaderLib)
2016-03-08 21:18:38 +00:00
Log.report(logvisor::Fatal, "error compiling vert shader: %s", [[err localizedDescription] UTF8String]);
2016-01-11 22:26:40 +00:00
id<MTLFunction> vertFunc = [vertShaderLib newFunctionWithName:@"vmain"];
2016-02-16 19:41:16 +00:00
2016-03-30 21:07:12 +00:00
id<MTLLibrary> fragShaderLib = [m_parent.m_ctx->m_dev newLibraryWithSource:@(fragSource)
options:compOpts
error:&err];
2016-08-03 23:45:52 +00:00
if (!fragShaderLib)
2016-03-08 21:18:38 +00:00
Log.report(logvisor::Fatal, "error compiling frag shader: %s", [[err localizedDescription] UTF8String]);
2016-01-11 22:26:40 +00:00
id<MTLFunction> fragFunc = [fragShaderLib newFunctionWithName:@"fmain"];
2016-02-16 19:41:16 +00:00
2016-03-30 21:07:12 +00:00
MetalShaderPipeline* retval = new MetalShaderPipeline(m_parent.m_ctx, vertFunc, fragFunc,
2015-11-28 04:07:53 +00:00
static_cast<const MetalVertexFormat*>(vtxFmt), targetSamples,
srcFac, dstFac, prim, depthTest, depthWrite, backfaceCulling);
2015-12-18 21:33:53 +00:00
m_deferredData->m_SPs.emplace_back(retval);
2015-11-09 02:24:45 +00:00
return retval;
}
IShaderDataBinding*
2016-03-30 21:07:12 +00:00
MetalDataFactory::Context::newShaderDataBinding(IShaderPipeline* pipeline,
IVertexFormat* vtxFormat,
IGraphicsBuffer* vbuf, IGraphicsBuffer* instVbo, IGraphicsBuffer* ibuf,
2016-04-04 06:13:11 +00:00
size_t ubufCount, IGraphicsBuffer** ubufs, const PipelineStage* ubufStages,
2016-03-30 21:07:12 +00:00
const size_t* ubufOffs, const size_t* ubufSizes,
size_t texCount, ITexture** texs)
{
2015-11-09 02:24:45 +00:00
MetalShaderDataBinding* retval =
2016-03-30 21:07:12 +00:00
new MetalShaderDataBinding(m_parent.m_ctx, pipeline, vbuf, instVbo, ibuf,
2016-04-04 06:13:11 +00:00
ubufCount, ubufs, ubufStages, ubufOffs, ubufSizes, texCount, texs);
2015-12-18 21:33:53 +00:00
m_deferredData->m_SBinds.emplace_back(retval);
2015-11-09 02:24:45 +00:00
return retval;
}
2016-03-30 21:07:12 +00:00
GraphicsDataToken MetalDataFactory::commitTransaction(const FactoryCommitFunc& trans)
{
2016-03-30 21:07:12 +00:00
if (m_deferredData.get())
Log.report(logvisor::Fatal, "nested commitTransaction usage detected");
m_deferredData.reset(new MetalData());
MetalDataFactory::Context ctx(*this);
if (!trans(ctx))
{
delete m_deferredData.get();
m_deferredData.reset();
2015-12-18 21:33:53 +00:00
return GraphicsDataToken(this, nullptr);
2016-03-30 21:07:12 +00:00
}
2015-12-18 21:33:53 +00:00
std::unique_lock<std::mutex> lk(m_committedMutex);
MetalData* retval = m_deferredData.get();
m_deferredData.reset();
2015-11-09 02:24:45 +00:00
m_committedData.insert(retval);
2015-12-18 21:33:53 +00:00
return GraphicsDataToken(this, retval);
}
2015-11-09 02:24:45 +00:00
void MetalDataFactory::destroyData(IGraphicsData* d)
{
2015-12-18 21:33:53 +00:00
std::unique_lock<std::mutex> lk(m_committedMutex);
2015-11-09 02:24:45 +00:00
MetalData* data = static_cast<MetalData*>(d);
m_committedData.erase(data);
delete data;
}
void MetalDataFactory::destroyAllData()
{
2015-12-18 21:33:53 +00:00
std::unique_lock<std::mutex> lk(m_committedMutex);
2015-11-09 02:24:45 +00:00
for (IGraphicsData* data : m_committedData)
delete static_cast<MetalData*>(data);
m_committedData.clear();
}
2016-02-16 19:41:16 +00:00
2015-11-09 02:24:45 +00:00
IGraphicsCommandQueue* _NewMetalCommandQueue(MetalContext* ctx, IWindow* parentWindow,
IGraphicsContext* parent)
{
2015-11-09 02:24:45 +00:00
return new struct MetalCommandQueue(ctx, parentWindow, parent);
}
2016-02-16 19:41:16 +00:00
}
2015-11-16 22:03:46 +00:00
#endif