Format: src/backend/metal

This commit is contained in:
Corentin Wallez 2017-11-24 14:12:44 -05:00 committed by Corentin Wallez
parent 2d62a371ee
commit f58d84d488
29 changed files with 688 additions and 771 deletions

View File

@ -18,17 +18,15 @@
#include "backend/BlendState.h" #include "backend/BlendState.h"
#import <Metal/Metal.h> #import <Metal/Metal.h>
namespace backend { namespace backend { namespace metal {
namespace metal {
class BlendState : public BlendStateBase { class BlendState : public BlendStateBase {
public: public:
BlendState(BlendStateBuilder* builder); BlendState(BlendStateBuilder* builder);
void ApplyBlendState(MTLRenderPipelineColorAttachmentDescriptor* descriptor) const; void ApplyBlendState(MTLRenderPipelineColorAttachmentDescriptor* descriptor) const;
}; };
} }} // namespace backend::metal
}
#endif // BACKEND_METAL_BLENDSTATEMTL_H_ #endif // BACKEND_METAL_BLENDSTATEMTL_H_

View File

@ -16,13 +16,12 @@
#include "backend/metal/MetalBackend.h" #include "backend/metal/MetalBackend.h"
namespace backend { namespace backend { namespace metal {
namespace metal {
namespace { namespace {
MTLBlendFactor MetalBlendFactor(nxt::BlendFactor factor, bool alpha) { MTLBlendFactor MetalBlendFactor(nxt::BlendFactor factor, bool alpha) {
switch(factor) { switch (factor) {
case nxt::BlendFactor::Zero: case nxt::BlendFactor::Zero:
return MTLBlendFactorZero; return MTLBlendFactorZero;
case nxt::BlendFactor::One: case nxt::BlendFactor::One:
@ -48,12 +47,13 @@ namespace metal {
case nxt::BlendFactor::BlendColor: case nxt::BlendFactor::BlendColor:
return alpha ? MTLBlendFactorBlendAlpha : MTLBlendFactorBlendColor; return alpha ? MTLBlendFactorBlendAlpha : MTLBlendFactorBlendColor;
case nxt::BlendFactor::OneMinusBlendColor: case nxt::BlendFactor::OneMinusBlendColor:
return alpha ? MTLBlendFactorOneMinusBlendAlpha : MTLBlendFactorOneMinusBlendColor; return alpha ? MTLBlendFactorOneMinusBlendAlpha
: MTLBlendFactorOneMinusBlendColor;
} }
} }
MTLBlendOperation MetalBlendOperation(nxt::BlendOperation operation) { MTLBlendOperation MetalBlendOperation(nxt::BlendOperation operation) {
switch(operation) { switch (operation) {
case nxt::BlendOperation::Add: case nxt::BlendOperation::Add:
return MTLBlendOperationAdd; return MTLBlendOperationAdd;
case nxt::BlendOperation::Subtract: case nxt::BlendOperation::Subtract:
@ -68,14 +68,19 @@ namespace metal {
} }
MTLColorWriteMask MetalColorWriteMask(nxt::ColorWriteMask colorWriteMask) { MTLColorWriteMask MetalColorWriteMask(nxt::ColorWriteMask colorWriteMask) {
return ( return (((colorWriteMask & nxt::ColorWriteMask::Red) != nxt::ColorWriteMask::None
((colorWriteMask & nxt::ColorWriteMask::Red) != nxt::ColorWriteMask::None ? MTLColorWriteMaskRed : MTLColorWriteMaskNone) | ? MTLColorWriteMaskRed
((colorWriteMask & nxt::ColorWriteMask::Green) != nxt::ColorWriteMask::None ? MTLColorWriteMaskGreen : MTLColorWriteMaskNone) | : MTLColorWriteMaskNone) |
((colorWriteMask & nxt::ColorWriteMask::Blue) != nxt::ColorWriteMask::None ? MTLColorWriteMaskBlue : MTLColorWriteMaskNone) | ((colorWriteMask & nxt::ColorWriteMask::Green) != nxt::ColorWriteMask::None
((colorWriteMask & nxt::ColorWriteMask::Alpha) != nxt::ColorWriteMask::None ? MTLColorWriteMaskAlpha : MTLColorWriteMaskNone) ? MTLColorWriteMaskGreen
); : MTLColorWriteMaskNone) |
((colorWriteMask & nxt::ColorWriteMask::Blue) != nxt::ColorWriteMask::None
? MTLColorWriteMaskBlue
: MTLColorWriteMaskNone) |
((colorWriteMask & nxt::ColorWriteMask::Alpha) != nxt::ColorWriteMask::None
? MTLColorWriteMaskAlpha
: MTLColorWriteMaskNone));
} }
} }
BlendState::BlendState(BlendStateBuilder* builder) : BlendStateBase(builder) { BlendState::BlendState(BlendStateBuilder* builder) : BlendStateBase(builder) {
@ -92,5 +97,5 @@ namespace metal {
descriptor.alphaBlendOperation = MetalBlendOperation(info.alphaBlend.operation); descriptor.alphaBlendOperation = MetalBlendOperation(info.alphaBlend.operation);
descriptor.writeMask = MetalColorWriteMask(info.colorWriteMask); descriptor.writeMask = MetalColorWriteMask(info.colorWriteMask);
} }
}
} }} // namespace backend::metal

View File

@ -20,54 +20,53 @@
#import <Metal/Metal.h> #import <Metal/Metal.h>
namespace backend { namespace backend { namespace metal {
namespace metal {
class Device; class Device;
class Buffer : public BufferBase { class Buffer : public BufferBase {
public: public:
Buffer(BufferBuilder* builder); Buffer(BufferBuilder* builder);
~Buffer(); ~Buffer();
id<MTLBuffer> GetMTLBuffer(); id<MTLBuffer> GetMTLBuffer();
void OnMapReadCommandSerialFinished(uint32_t mapSerial, uint32_t offset); void OnMapReadCommandSerialFinished(uint32_t mapSerial, uint32_t offset);
private: private:
void SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) override; void SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) override;
void MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) override; void MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) override;
void UnmapImpl() override; void UnmapImpl() override;
void TransitionUsageImpl(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage) override; void TransitionUsageImpl(nxt::BufferUsageBit currentUsage,
nxt::BufferUsageBit targetUsage) override;
id<MTLBuffer> mMtlBuffer = nil; id<MTLBuffer> mMtlBuffer = nil;
}; };
class BufferView : public BufferViewBase { class BufferView : public BufferViewBase {
public: public:
BufferView(BufferViewBuilder* builder); BufferView(BufferViewBuilder* builder);
}; };
class MapReadRequestTracker { class MapReadRequestTracker {
public: public:
MapReadRequestTracker(Device* device); MapReadRequestTracker(Device* device);
~MapReadRequestTracker(); ~MapReadRequestTracker();
void Track(Buffer* buffer, uint32_t mapSerial, uint32_t offset); void Track(Buffer* buffer, uint32_t mapSerial, uint32_t offset);
void Tick(Serial finishedSerial); void Tick(Serial finishedSerial);
private: private:
Device* mDevice; Device* mDevice;
struct Request { struct Request {
Ref<Buffer> buffer; Ref<Buffer> buffer;
uint32_t mapSerial; uint32_t mapSerial;
uint32_t offset; uint32_t offset;
}; };
SerialQueue<Request> mInflightRequests; SerialQueue<Request> mInflightRequests;
}; };
} }} // namespace backend::metal
}
#endif // BACKEND_METAL_BUFFERMTL_H_ #endif // BACKEND_METAL_BUFFERMTL_H_

View File

@ -17,12 +17,9 @@
#include "backend/metal/MetalBackend.h" #include "backend/metal/MetalBackend.h"
#include "backend/metal/ResourceUploader.h" #include "backend/metal/ResourceUploader.h"
namespace backend { namespace backend { namespace metal {
namespace metal {
Buffer::Buffer(BufferBuilder* builder)
: BufferBase(builder) {
Buffer::Buffer(BufferBuilder* builder) : BufferBase(builder) {
MTLResourceOptions storageMode; MTLResourceOptions storageMode;
if (GetAllowedUsage() & (nxt::BufferUsageBit::MapRead | nxt::BufferUsageBit::MapWrite)) { if (GetAllowedUsage() & (nxt::BufferUsageBit::MapRead | nxt::BufferUsageBit::MapWrite)) {
storageMode = MTLResourceStorageModeShared; storageMode = MTLResourceStorageModeShared;
@ -31,7 +28,7 @@ namespace metal {
} }
mMtlBuffer = [ToBackend(GetDevice())->GetMTLDevice() newBufferWithLength:GetSize() mMtlBuffer = [ToBackend(GetDevice())->GetMTLDevice() newBufferWithLength:GetSize()
options:storageMode]; options:storageMode];
} }
Buffer::~Buffer() { Buffer::~Buffer() {
@ -50,7 +47,8 @@ namespace metal {
void Buffer::SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) { void Buffer::SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) {
auto* uploader = ToBackend(GetDevice())->GetResourceUploader(); auto* uploader = ToBackend(GetDevice())->GetResourceUploader();
uploader->BufferSubData(mMtlBuffer, start * sizeof(uint32_t), count * sizeof(uint32_t), data); uploader->BufferSubData(mMtlBuffer, start * sizeof(uint32_t), count * sizeof(uint32_t),
data);
} }
void Buffer::MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t) { void Buffer::MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t) {
@ -65,12 +63,10 @@ namespace metal {
void Buffer::TransitionUsageImpl(nxt::BufferUsageBit, nxt::BufferUsageBit) { void Buffer::TransitionUsageImpl(nxt::BufferUsageBit, nxt::BufferUsageBit) {
} }
BufferView::BufferView(BufferViewBuilder* builder) BufferView::BufferView(BufferViewBuilder* builder) : BufferViewBase(builder) {
: BufferViewBase(builder) {
} }
MapReadRequestTracker::MapReadRequestTracker(Device* device) MapReadRequestTracker::MapReadRequestTracker(Device* device) : mDevice(device) {
: mDevice(device) {
} }
MapReadRequestTracker::~MapReadRequestTracker() { MapReadRequestTracker::~MapReadRequestTracker() {
@ -92,5 +88,5 @@ namespace metal {
} }
mInflightRequests.ClearUpTo(finishedSerial); mInflightRequests.ClearUpTo(finishedSerial);
} }
}
} }} // namespace backend::metal

View File

@ -19,24 +19,22 @@
#import <Metal/Metal.h> #import <Metal/Metal.h>
namespace backend { namespace backend { namespace metal {
namespace metal {
class Device; class Device;
class CommandBuffer : public CommandBufferBase { class CommandBuffer : public CommandBufferBase {
public: public:
CommandBuffer(CommandBufferBuilder* builder); CommandBuffer(CommandBufferBuilder* builder);
~CommandBuffer(); ~CommandBuffer();
void FillCommands(id<MTLCommandBuffer> commandBuffer); void FillCommands(id<MTLCommandBuffer> commandBuffer);
private: private:
Device* mDevice; Device* mDevice;
CommandIterator mCommands; CommandIterator mCommands;
}; };
} }} // namespace backend::metal
}
#endif // BACKEND_METAL_COMMANDBUFFERMTL_H_ #endif // BACKEND_METAL_COMMANDBUFFERMTL_H_

View File

@ -25,8 +25,7 @@
#include "backend/metal/SamplerMTL.h" #include "backend/metal/SamplerMTL.h"
#include "backend/metal/TextureMTL.h" #include "backend/metal/TextureMTL.h"
namespace backend { namespace backend { namespace metal {
namespace metal {
namespace { namespace {
struct CurrentEncoders { struct CurrentEncoders {
@ -77,7 +76,8 @@ namespace metal {
const auto& info = currentRenderPass->GetSubpassInfo(subpass); const auto& info = currentRenderPass->GetSubpassInfo(subpass);
MTLRenderPassDescriptor* descriptor = [MTLRenderPassDescriptor renderPassDescriptor]; MTLRenderPassDescriptor* descriptor =
[MTLRenderPassDescriptor renderPassDescriptor];
for (unsigned int location : IterateBitSet(info.colorAttachmentsSet)) { for (unsigned int location : IterateBitSet(info.colorAttachmentsSet)) {
uint32_t attachment = info.colorAttachments[location]; uint32_t attachment = info.colorAttachments[location];
const auto& attachmentInfo = currentRenderPass->GetAttachmentInfo(attachment); const auto& attachmentInfo = currentRenderPass->GetAttachmentInfo(attachment);
@ -90,7 +90,9 @@ namespace metal {
if (isFirstUse && shouldClearOnFirstUse) { if (isFirstUse && shouldClearOnFirstUse) {
auto clearValue = currentFramebuffer->GetClearColor(location); auto clearValue = currentFramebuffer->GetClearColor(location);
descriptor.colorAttachments[location].loadAction = MTLLoadActionClear; descriptor.colorAttachments[location].loadAction = MTLLoadActionClear;
descriptor.colorAttachments[location].clearColor = MTLClearColorMake(clearValue.color[0], clearValue.color[1], clearValue.color[2], clearValue.color[3]); descriptor.colorAttachments[location].clearColor =
MTLClearColorMake(clearValue.color[0], clearValue.color[1],
clearValue.color[2], clearValue.color[3]);
} else { } else {
descriptor.colorAttachments[location].loadAction = MTLLoadActionLoad; descriptor.colorAttachments[location].loadAction = MTLLoadActionLoad;
} }
@ -113,7 +115,8 @@ namespace metal {
descriptor.depthAttachment.texture = texture; descriptor.depthAttachment.texture = texture;
descriptor.depthAttachment.storeAction = MTLStoreActionStore; descriptor.depthAttachment.storeAction = MTLStoreActionStore;
bool shouldClearDepthOnFirstUse = attachmentInfo.depthLoadOp == nxt::LoadOp::Clear; bool shouldClearDepthOnFirstUse =
attachmentInfo.depthLoadOp == nxt::LoadOp::Clear;
if (isFirstUse && shouldClearDepthOnFirstUse) { if (isFirstUse && shouldClearDepthOnFirstUse) {
descriptor.depthAttachment.loadAction = MTLLoadActionClear; descriptor.depthAttachment.loadAction = MTLLoadActionClear;
descriptor.depthAttachment.clearDepth = clearValues.depth; descriptor.depthAttachment.clearDepth = clearValues.depth;
@ -126,7 +129,8 @@ namespace metal {
descriptor.stencilAttachment.texture = texture; descriptor.stencilAttachment.texture = texture;
descriptor.stencilAttachment.storeAction = MTLStoreActionStore; descriptor.stencilAttachment.storeAction = MTLStoreActionStore;
bool shouldClearStencilOnFirstUse = attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear; bool shouldClearStencilOnFirstUse =
attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear;
if (isFirstUse && shouldClearStencilOnFirstUse) { if (isFirstUse && shouldClearStencilOnFirstUse) {
descriptor.stencilAttachment.loadAction = MTLLoadActionClear; descriptor.stencilAttachment.loadAction = MTLLoadActionClear;
descriptor.stencilAttachment.clearStencil = clearValues.stencil; descriptor.stencilAttachment.clearStencil = clearValues.stencil;
@ -149,7 +153,8 @@ namespace metal {
} }
CommandBuffer::CommandBuffer(CommandBufferBuilder* builder) CommandBuffer::CommandBuffer(CommandBufferBuilder* builder)
: CommandBufferBase(builder), mDevice(ToBackend(builder->GetDevice())), : CommandBufferBase(builder),
mDevice(ToBackend(builder->GetDevice())),
mCommands(builder->AcquireCommands()) { mCommands(builder->AcquireCommands()) {
} }
@ -172,431 +177,385 @@ namespace metal {
uint32_t currentSubpass = 0; uint32_t currentSubpass = 0;
while (mCommands.NextCommandId(&type)) { while (mCommands.NextCommandId(&type)) {
switch (type) { switch (type) {
case Command::BeginComputePass: case Command::BeginComputePass: {
{ mCommands.NextCommand<BeginComputePassCmd>();
mCommands.NextCommand<BeginComputePassCmd>(); encoders.BeginCompute(commandBuffer);
encoders.BeginCompute(commandBuffer);
pushConstants[nxt::ShaderStage::Compute].fill(0); pushConstants[nxt::ShaderStage::Compute].fill(0);
[encoders.compute setBytes: &pushConstants[nxt::ShaderStage::Compute] [encoders.compute setBytes:&pushConstants[nxt::ShaderStage::Compute]
length: sizeof(uint32_t) * kMaxPushConstants length:sizeof(uint32_t) * kMaxPushConstants
atIndex: 0]; atIndex:0];
} } break;
break;
case Command::BeginRenderPass: case Command::BeginRenderPass: {
{ BeginRenderPassCmd* beginRenderPassCmd =
BeginRenderPassCmd* beginRenderPassCmd = mCommands.NextCommand<BeginRenderPassCmd>(); mCommands.NextCommand<BeginRenderPassCmd>();
encoders.currentRenderPass = ToBackend(beginRenderPassCmd->renderPass.Get()); encoders.currentRenderPass = ToBackend(beginRenderPassCmd->renderPass.Get());
encoders.currentFramebuffer = ToBackend(beginRenderPassCmd->framebuffer.Get()); encoders.currentFramebuffer = ToBackend(beginRenderPassCmd->framebuffer.Get());
encoders.EnsureNoBlitEncoder(); encoders.EnsureNoBlitEncoder();
currentSubpass = 0; currentSubpass = 0;
} } break;
break;
case Command::BeginRenderSubpass: case Command::BeginRenderSubpass: {
{ mCommands.NextCommand<BeginRenderSubpassCmd>();
mCommands.NextCommand<BeginRenderSubpassCmd>(); encoders.BeginSubpass(commandBuffer, currentSubpass);
encoders.BeginSubpass(commandBuffer, currentSubpass);
pushConstants[nxt::ShaderStage::Vertex].fill(0); pushConstants[nxt::ShaderStage::Vertex].fill(0);
pushConstants[nxt::ShaderStage::Fragment].fill(0); pushConstants[nxt::ShaderStage::Fragment].fill(0);
[encoders.render setVertexBytes: &pushConstants[nxt::ShaderStage::Vertex] [encoders.render setVertexBytes:&pushConstants[nxt::ShaderStage::Vertex]
length: sizeof(uint32_t) * kMaxPushConstants length:sizeof(uint32_t) * kMaxPushConstants
atIndex: 0]; atIndex:0];
[encoders.render setFragmentBytes: &pushConstants[nxt::ShaderStage::Fragment] [encoders.render setFragmentBytes:&pushConstants[nxt::ShaderStage::Fragment]
length: sizeof(uint32_t) * kMaxPushConstants length:sizeof(uint32_t) * kMaxPushConstants
atIndex: 0]; atIndex:0];
} } break;
break;
case Command::CopyBufferToBuffer: case Command::CopyBufferToBuffer: {
{ CopyBufferToBufferCmd* copy = mCommands.NextCommand<CopyBufferToBufferCmd>();
CopyBufferToBufferCmd* copy = mCommands.NextCommand<CopyBufferToBufferCmd>(); auto& src = copy->source;
auto& src = copy->source; auto& dst = copy->destination;
auto& dst = copy->destination;
encoders.EnsureBlit(commandBuffer); encoders.EnsureBlit(commandBuffer);
[encoders.blit [encoders.blit copyFromBuffer:ToBackend(src.buffer)->GetMTLBuffer()
copyFromBuffer:ToBackend(src.buffer)->GetMTLBuffer() sourceOffset:src.offset
sourceOffset:src.offset toBuffer:ToBackend(dst.buffer)->GetMTLBuffer()
toBuffer:ToBackend(dst.buffer)->GetMTLBuffer() destinationOffset:dst.offset
destinationOffset:dst.offset size:copy->size];
size:copy->size]; } break;
}
break;
case Command::CopyBufferToTexture: case Command::CopyBufferToTexture: {
{ CopyBufferToTextureCmd* copy = mCommands.NextCommand<CopyBufferToTextureCmd>();
CopyBufferToTextureCmd* copy = mCommands.NextCommand<CopyBufferToTextureCmd>(); auto& src = copy->source;
auto& src = copy->source; auto& dst = copy->destination;
auto& dst = copy->destination; Buffer* buffer = ToBackend(src.buffer.Get());
Buffer* buffer = ToBackend(src.buffer.Get()); Texture* texture = ToBackend(dst.texture.Get());
Texture* texture = ToBackend(dst.texture.Get());
MTLOrigin origin; MTLOrigin origin;
origin.x = dst.x; origin.x = dst.x;
origin.y = dst.y; origin.y = dst.y;
origin.z = dst.z; origin.z = dst.z;
MTLSize size; MTLSize size;
size.width = dst.width; size.width = dst.width;
size.height = dst.height; size.height = dst.height;
size.depth = dst.depth; size.depth = dst.depth;
encoders.EnsureBlit(commandBuffer); encoders.EnsureBlit(commandBuffer);
[encoders.blit [encoders.blit copyFromBuffer:buffer->GetMTLBuffer()
copyFromBuffer:buffer->GetMTLBuffer() sourceOffset:src.offset
sourceOffset:src.offset sourceBytesPerRow:copy->rowPitch
sourceBytesPerRow:copy->rowPitch sourceBytesPerImage:(copy->rowPitch * dst.height)
sourceBytesPerImage:(copy->rowPitch * dst.height) sourceSize:size
sourceSize:size toTexture:texture->GetMTLTexture()
toTexture:texture->GetMTLTexture() destinationSlice:0
destinationSlice:0 destinationLevel:dst.level
destinationLevel:dst.level destinationOrigin:origin];
destinationOrigin:origin]; } break;
}
break;
case Command::CopyTextureToBuffer: case Command::CopyTextureToBuffer: {
{ CopyTextureToBufferCmd* copy = mCommands.NextCommand<CopyTextureToBufferCmd>();
CopyTextureToBufferCmd* copy = mCommands.NextCommand<CopyTextureToBufferCmd>(); auto& src = copy->source;
auto& src = copy->source; auto& dst = copy->destination;
auto& dst = copy->destination; Texture* texture = ToBackend(src.texture.Get());
Texture* texture = ToBackend(src.texture.Get()); Buffer* buffer = ToBackend(dst.buffer.Get());
Buffer* buffer = ToBackend(dst.buffer.Get());
MTLOrigin origin; MTLOrigin origin;
origin.x = src.x; origin.x = src.x;
origin.y = src.y; origin.y = src.y;
origin.z = src.z; origin.z = src.z;
MTLSize size; MTLSize size;
size.width = src.width; size.width = src.width;
size.height = src.height; size.height = src.height;
size.depth = src.depth; size.depth = src.depth;
encoders.EnsureBlit(commandBuffer); encoders.EnsureBlit(commandBuffer);
[encoders.blit [encoders.blit copyFromTexture:texture->GetMTLTexture()
copyFromTexture:texture->GetMTLTexture() sourceSlice:0
sourceSlice:0 sourceLevel:src.level
sourceLevel:src.level sourceOrigin:origin
sourceOrigin:origin sourceSize:size
sourceSize:size toBuffer:buffer->GetMTLBuffer()
toBuffer:buffer->GetMTLBuffer() destinationOffset:dst.offset
destinationOffset:dst.offset
destinationBytesPerRow:copy->rowPitch destinationBytesPerRow:copy->rowPitch
destinationBytesPerImage:copy->rowPitch * src.height]; destinationBytesPerImage:copy->rowPitch * src.height];
} } break;
break;
case Command::Dispatch: case Command::Dispatch: {
{ DispatchCmd* dispatch = mCommands.NextCommand<DispatchCmd>();
DispatchCmd* dispatch = mCommands.NextCommand<DispatchCmd>(); ASSERT(encoders.compute);
ASSERT(encoders.compute);
[encoders.compute dispatchThreadgroups:MTLSizeMake(dispatch->x, dispatch->y, dispatch->z) [encoders.compute
threadsPerThreadgroup: lastComputePipeline->GetLocalWorkGroupSize()]; dispatchThreadgroups:MTLSizeMake(dispatch->x, dispatch->y, dispatch->z)
} threadsPerThreadgroup:lastComputePipeline->GetLocalWorkGroupSize()];
break; } break;
case Command::DrawArrays: case Command::DrawArrays: {
{ DrawArraysCmd* draw = mCommands.NextCommand<DrawArraysCmd>();
DrawArraysCmd* draw = mCommands.NextCommand<DrawArraysCmd>();
ASSERT(encoders.render); ASSERT(encoders.render);
[encoders.render [encoders.render drawPrimitives:lastRenderPipeline->GetMTLPrimitiveTopology()
drawPrimitives:lastRenderPipeline->GetMTLPrimitiveTopology() vertexStart:draw->firstVertex
vertexStart:draw->firstVertex vertexCount:draw->vertexCount
vertexCount:draw->vertexCount instanceCount:draw->instanceCount
instanceCount:draw->instanceCount baseInstance:draw->firstInstance];
baseInstance:draw->firstInstance]; } break;
}
break;
case Command::DrawElements: case Command::DrawElements: {
{ DrawElementsCmd* draw = mCommands.NextCommand<DrawElementsCmd>();
DrawElementsCmd* draw = mCommands.NextCommand<DrawElementsCmd>();
ASSERT(encoders.render); ASSERT(encoders.render);
[encoders.render [encoders.render
drawIndexedPrimitives:lastRenderPipeline->GetMTLPrimitiveTopology() drawIndexedPrimitives:lastRenderPipeline->GetMTLPrimitiveTopology()
indexCount:draw->indexCount indexCount:draw->indexCount
indexType:lastRenderPipeline->GetMTLIndexType() indexType:lastRenderPipeline->GetMTLIndexType()
indexBuffer:indexBuffer indexBuffer:indexBuffer
indexBufferOffset:indexBufferOffset indexBufferOffset:indexBufferOffset
instanceCount:draw->instanceCount instanceCount:draw->instanceCount
baseVertex:0 baseVertex:0
baseInstance:draw->firstInstance]; baseInstance:draw->firstInstance];
} } break;
break;
case Command::EndComputePass: case Command::EndComputePass: {
{ mCommands.NextCommand<EndComputePassCmd>();
mCommands.NextCommand<EndComputePassCmd>(); encoders.EndCompute();
encoders.EndCompute(); } break;
}
break;
case Command::EndRenderPass: case Command::EndRenderPass: {
{ mCommands.NextCommand<EndRenderPassCmd>();
mCommands.NextCommand<EndRenderPassCmd>(); } break;
}
break;
case Command::EndRenderSubpass: case Command::EndRenderSubpass: {
{ mCommands.NextCommand<EndRenderSubpassCmd>();
mCommands.NextCommand<EndRenderSubpassCmd>(); encoders.EndSubpass();
encoders.EndSubpass(); currentSubpass += 1;
currentSubpass += 1; } break;
}
break;
case Command::SetComputePipeline: case Command::SetComputePipeline: {
{ SetComputePipelineCmd* cmd = mCommands.NextCommand<SetComputePipelineCmd>();
SetComputePipelineCmd* cmd = mCommands.NextCommand<SetComputePipelineCmd>(); lastComputePipeline = ToBackend(cmd->pipeline).Get();
lastComputePipeline = ToBackend(cmd->pipeline).Get();
ASSERT(encoders.compute); ASSERT(encoders.compute);
lastComputePipeline->Encode(encoders.compute); lastComputePipeline->Encode(encoders.compute);
} } break;
break;
case Command::SetRenderPipeline: case Command::SetRenderPipeline: {
{ SetRenderPipelineCmd* cmd = mCommands.NextCommand<SetRenderPipelineCmd>();
SetRenderPipelineCmd* cmd = mCommands.NextCommand<SetRenderPipelineCmd>(); lastRenderPipeline = ToBackend(cmd->pipeline).Get();
lastRenderPipeline = ToBackend(cmd->pipeline).Get();
ASSERT(encoders.render); ASSERT(encoders.render);
DepthStencilState* depthStencilState = ToBackend(lastRenderPipeline->GetDepthStencilState()); DepthStencilState* depthStencilState =
[encoders.render setDepthStencilState:depthStencilState->GetMTLDepthStencilState()]; ToBackend(lastRenderPipeline->GetDepthStencilState());
lastRenderPipeline->Encode(encoders.render); [encoders.render
} setDepthStencilState:depthStencilState->GetMTLDepthStencilState()];
break; lastRenderPipeline->Encode(encoders.render);
} break;
case Command::SetPushConstants: case Command::SetPushConstants: {
{ SetPushConstantsCmd* cmd = mCommands.NextCommand<SetPushConstantsCmd>();
SetPushConstantsCmd* cmd = mCommands.NextCommand<SetPushConstantsCmd>(); uint32_t* values = mCommands.NextData<uint32_t>(cmd->count);
uint32_t* values = mCommands.NextData<uint32_t>(cmd->count);
for (auto stage : IterateStages(cmd->stages)) { for (auto stage : IterateStages(cmd->stages)) {
memcpy(&pushConstants[stage][cmd->offset], values, cmd->count * sizeof(uint32_t)); memcpy(&pushConstants[stage][cmd->offset], values,
cmd->count * sizeof(uint32_t));
switch (stage) { switch (stage) {
case nxt::ShaderStage::Compute: case nxt::ShaderStage::Compute:
ASSERT(encoders.compute); ASSERT(encoders.compute);
[encoders.compute setBytes: &pushConstants[nxt::ShaderStage::Compute] [encoders.compute setBytes:&pushConstants[nxt::ShaderStage::Compute]
length: sizeof(uint32_t) * kMaxPushConstants length:sizeof(uint32_t) * kMaxPushConstants
atIndex: 0]; atIndex:0];
break; break;
case nxt::ShaderStage::Fragment: case nxt::ShaderStage::Fragment:
ASSERT(encoders.render); ASSERT(encoders.render);
[encoders.render setFragmentBytes: &pushConstants[nxt::ShaderStage::Fragment] [encoders.render
length: sizeof(uint32_t) * kMaxPushConstants setFragmentBytes:&pushConstants[nxt::ShaderStage::Fragment]
atIndex: 0]; length:sizeof(uint32_t) * kMaxPushConstants
break; atIndex:0];
case nxt::ShaderStage::Vertex: break;
ASSERT(encoders.render); case nxt::ShaderStage::Vertex:
[encoders.render setVertexBytes: &pushConstants[nxt::ShaderStage::Vertex] ASSERT(encoders.render);
length: sizeof(uint32_t) * kMaxPushConstants [encoders.render
atIndex: 0]; setVertexBytes:&pushConstants[nxt::ShaderStage::Vertex]
break; length:sizeof(uint32_t) * kMaxPushConstants
default: atIndex:0];
UNREACHABLE(); break;
break; default:
} UNREACHABLE();
break;
} }
} }
break; } break;
case Command::SetStencilReference: case Command::SetStencilReference: {
{ SetStencilReferenceCmd* cmd = mCommands.NextCommand<SetStencilReferenceCmd>();
SetStencilReferenceCmd* cmd = mCommands.NextCommand<SetStencilReferenceCmd>();
ASSERT(encoders.render); ASSERT(encoders.render);
[encoders.render setStencilReferenceValue:cmd->reference]; [encoders.render setStencilReferenceValue:cmd->reference];
} } break;
break;
case Command::SetBlendColor: case Command::SetBlendColor: {
{ SetBlendColorCmd* cmd = mCommands.NextCommand<SetBlendColorCmd>();
SetBlendColorCmd* cmd = mCommands.NextCommand<SetBlendColorCmd>();
ASSERT(encoders.render); ASSERT(encoders.render);
[encoders.render [encoders.render setBlendColorRed:cmd->r green:cmd->g blue:cmd->b alpha:cmd->a];
setBlendColorRed:cmd->r } break;
green:cmd->g
blue:cmd->b
alpha:cmd->a ];
}
break;
case Command::SetBindGroup: case Command::SetBindGroup: {
{ SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>();
SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>(); BindGroup* group = ToBackend(cmd->group.Get());
BindGroup* group = ToBackend(cmd->group.Get()); uint32_t groupIndex = cmd->index;
uint32_t groupIndex = cmd->index;
const auto& layout = group->GetLayout()->GetBindingInfo(); const auto& layout = group->GetLayout()->GetBindingInfo();
// TODO(kainino@chromium.org): Maintain buffers and offsets arrays in BindGroup so that we // TODO(kainino@chromium.org): Maintain buffers and offsets arrays in BindGroup
// only have to do one setVertexBuffers and one setFragmentBuffers call here. // so that we only have to do one setVertexBuffers and one setFragmentBuffers
for (size_t binding = 0; binding < layout.mask.size(); ++binding) { // call here.
if (!layout.mask[binding]) { for (size_t binding = 0; binding < layout.mask.size(); ++binding) {
continue; if (!layout.mask[binding]) {
} continue;
auto stage = layout.visibilities[binding];
bool vertStage = stage & nxt::ShaderStageBit::Vertex && lastRenderPipeline != nullptr;
bool fragStage = stage & nxt::ShaderStageBit::Fragment && lastRenderPipeline != nullptr;
bool computeStage = stage & nxt::ShaderStageBit::Compute && lastComputePipeline != nullptr;
uint32_t vertIndex = 0;
uint32_t fragIndex = 0;
uint32_t computeIndex = 0;
if (vertStage) {
ASSERT(lastRenderPipeline != nullptr);
vertIndex = ToBackend(lastRenderPipeline->GetLayout())->
GetBindingIndexInfo(nxt::ShaderStage::Vertex)[groupIndex][binding];
}
if (fragStage) {
ASSERT(lastRenderPipeline != nullptr);
fragIndex = ToBackend(lastRenderPipeline->GetLayout())->
GetBindingIndexInfo(nxt::ShaderStage::Fragment)[groupIndex][binding];
}
if (computeStage) {
ASSERT(lastComputePipeline != nullptr);
computeIndex = ToBackend(lastComputePipeline->GetLayout())->
GetBindingIndexInfo(nxt::ShaderStage::Compute)[groupIndex][binding];
}
switch (layout.types[binding]) {
case nxt::BindingType::UniformBuffer:
case nxt::BindingType::StorageBuffer:
{
BufferView* view = ToBackend(group->GetBindingAsBufferView(binding));
auto b = ToBackend(view->GetBuffer());
const id<MTLBuffer> buffer = b->GetMTLBuffer();
const NSUInteger offset = view->GetOffset();
if (vertStage) {
[encoders.render
setVertexBuffers:&buffer
offsets:&offset
withRange:NSMakeRange(vertIndex, 1)];
}
if (fragStage) {
[encoders.render
setFragmentBuffers:&buffer
offsets:&offset
withRange:NSMakeRange(fragIndex, 1)];
}
if (computeStage) {
[encoders.compute
setBuffers:&buffer
offsets:&offset
withRange:NSMakeRange(computeIndex, 1)];
}
}
break;
case nxt::BindingType::Sampler:
{
auto sampler = ToBackend(group->GetBindingAsSampler(binding));
if (vertStage) {
[encoders.render
setVertexSamplerState:sampler->GetMTLSamplerState()
atIndex:vertIndex];
}
if (fragStage) {
[encoders.render
setFragmentSamplerState:sampler->GetMTLSamplerState()
atIndex:fragIndex];
}
if (computeStage) {
[encoders.compute
setSamplerState:sampler->GetMTLSamplerState()
atIndex:computeIndex];
}
}
break;
case nxt::BindingType::SampledTexture:
{
auto texture = ToBackend(group->GetBindingAsTextureView(binding)->GetTexture());
if (vertStage) {
[encoders.render
setVertexTexture:texture->GetMTLTexture()
atIndex:vertIndex];
}
if (fragStage) {
[encoders.render
setFragmentTexture:texture->GetMTLTexture()
atIndex:fragIndex];
}
if (computeStage) {
[encoders.compute
setTexture:texture->GetMTLTexture()
atIndex:computeIndex];
}
}
break;
}
}
}
break;
case Command::SetIndexBuffer:
{
SetIndexBufferCmd* cmd = mCommands.NextCommand<SetIndexBufferCmd>();
auto b = ToBackend(cmd->buffer.Get());
indexBuffer = b->GetMTLBuffer();
indexBufferOffset = cmd->offset;
}
break;
case Command::SetVertexBuffers:
{
SetVertexBuffersCmd* cmd = mCommands.NextCommand<SetVertexBuffersCmd>();
auto buffers = mCommands.NextData<Ref<BufferBase>>(cmd->count);
auto offsets = mCommands.NextData<uint32_t>(cmd->count);
std::array<id<MTLBuffer>, kMaxVertexInputs> mtlBuffers;
std::array<NSUInteger, kMaxVertexInputs> mtlOffsets;
// Perhaps an "array of vertex buffers(+offsets?)" should be
// a NXT API primitive to avoid reconstructing this array?
for (uint32_t i = 0; i < cmd->count; ++i) {
Buffer* buffer = ToBackend(buffers[i].Get());
mtlBuffers[i] = buffer->GetMTLBuffer();
mtlOffsets[i] = offsets[i];
} }
ASSERT(encoders.render); auto stage = layout.visibilities[binding];
[encoders.render bool vertStage =
setVertexBuffers:mtlBuffers.data() stage & nxt::ShaderStageBit::Vertex && lastRenderPipeline != nullptr;
offsets:mtlOffsets.data() bool fragStage =
withRange:NSMakeRange(kMaxBindingsPerGroup + cmd->startSlot, cmd->count)]; stage & nxt::ShaderStageBit::Fragment && lastRenderPipeline != nullptr;
bool computeStage =
stage & nxt::ShaderStageBit::Compute && lastComputePipeline != nullptr;
uint32_t vertIndex = 0;
uint32_t fragIndex = 0;
uint32_t computeIndex = 0;
if (vertStage) {
ASSERT(lastRenderPipeline != nullptr);
vertIndex = ToBackend(lastRenderPipeline->GetLayout())
->GetBindingIndexInfo(
nxt::ShaderStage::Vertex)[groupIndex][binding];
}
if (fragStage) {
ASSERT(lastRenderPipeline != nullptr);
fragIndex = ToBackend(lastRenderPipeline->GetLayout())
->GetBindingIndexInfo(
nxt::ShaderStage::Fragment)[groupIndex][binding];
}
if (computeStage) {
ASSERT(lastComputePipeline != nullptr);
computeIndex = ToBackend(lastComputePipeline->GetLayout())
->GetBindingIndexInfo(
nxt::ShaderStage::Compute)[groupIndex][binding];
}
switch (layout.types[binding]) {
case nxt::BindingType::UniformBuffer:
case nxt::BindingType::StorageBuffer: {
BufferView* view =
ToBackend(group->GetBindingAsBufferView(binding));
auto b = ToBackend(view->GetBuffer());
const id<MTLBuffer> buffer = b->GetMTLBuffer();
const NSUInteger offset = view->GetOffset();
if (vertStage) {
[encoders.render setVertexBuffers:&buffer
offsets:&offset
withRange:NSMakeRange(vertIndex, 1)];
}
if (fragStage) {
[encoders.render setFragmentBuffers:&buffer
offsets:&offset
withRange:NSMakeRange(fragIndex, 1)];
}
if (computeStage) {
[encoders.compute setBuffers:&buffer
offsets:&offset
withRange:NSMakeRange(computeIndex, 1)];
}
} break;
case nxt::BindingType::Sampler: {
auto sampler = ToBackend(group->GetBindingAsSampler(binding));
if (vertStage) {
[encoders.render
setVertexSamplerState:sampler->GetMTLSamplerState()
atIndex:vertIndex];
}
if (fragStage) {
[encoders.render
setFragmentSamplerState:sampler->GetMTLSamplerState()
atIndex:fragIndex];
}
if (computeStage) {
[encoders.compute setSamplerState:sampler->GetMTLSamplerState()
atIndex:computeIndex];
}
} break;
case nxt::BindingType::SampledTexture: {
auto texture = ToBackend(
group->GetBindingAsTextureView(binding)->GetTexture());
if (vertStage) {
[encoders.render setVertexTexture:texture->GetMTLTexture()
atIndex:vertIndex];
}
if (fragStage) {
[encoders.render setFragmentTexture:texture->GetMTLTexture()
atIndex:fragIndex];
}
if (computeStage) {
[encoders.compute setTexture:texture->GetMTLTexture()
atIndex:computeIndex];
}
} break;
}
} }
break; } break;
case Command::TransitionBufferUsage: case Command::SetIndexBuffer: {
{ SetIndexBufferCmd* cmd = mCommands.NextCommand<SetIndexBufferCmd>();
TransitionBufferUsageCmd* cmd = mCommands.NextCommand<TransitionBufferUsageCmd>(); auto b = ToBackend(cmd->buffer.Get());
indexBuffer = b->GetMTLBuffer();
indexBufferOffset = cmd->offset;
} break;
cmd->buffer->UpdateUsageInternal(cmd->usage); case Command::SetVertexBuffers: {
SetVertexBuffersCmd* cmd = mCommands.NextCommand<SetVertexBuffersCmd>();
auto buffers = mCommands.NextData<Ref<BufferBase>>(cmd->count);
auto offsets = mCommands.NextData<uint32_t>(cmd->count);
std::array<id<MTLBuffer>, kMaxVertexInputs> mtlBuffers;
std::array<NSUInteger, kMaxVertexInputs> mtlOffsets;
// Perhaps an "array of vertex buffers(+offsets?)" should be
// a NXT API primitive to avoid reconstructing this array?
for (uint32_t i = 0; i < cmd->count; ++i) {
Buffer* buffer = ToBackend(buffers[i].Get());
mtlBuffers[i] = buffer->GetMTLBuffer();
mtlOffsets[i] = offsets[i];
} }
break;
case Command::TransitionTextureUsage: ASSERT(encoders.render);
{ [encoders.render
TransitionTextureUsageCmd* cmd = mCommands.NextCommand<TransitionTextureUsageCmd>(); setVertexBuffers:mtlBuffers.data()
offsets:mtlOffsets.data()
withRange:NSMakeRange(kMaxBindingsPerGroup + cmd->startSlot,
cmd->count)];
} break;
cmd->texture->UpdateUsageInternal(cmd->usage); case Command::TransitionBufferUsage: {
} TransitionBufferUsageCmd* cmd =
break; mCommands.NextCommand<TransitionBufferUsageCmd>();
cmd->buffer->UpdateUsageInternal(cmd->usage);
} break;
case Command::TransitionTextureUsage: {
TransitionTextureUsageCmd* cmd =
mCommands.NextCommand<TransitionTextureUsageCmd>();
cmd->texture->UpdateUsageInternal(cmd->usage);
} break;
} }
} }
@ -605,5 +564,4 @@ namespace metal {
ASSERT(encoders.compute == nil); ASSERT(encoders.compute == nil);
} }
} }} // namespace backend::metal
}

View File

@ -19,23 +19,21 @@
#import <Metal/Metal.h> #import <Metal/Metal.h>
namespace backend { namespace backend { namespace metal {
namespace metal {
class ComputePipeline : public ComputePipelineBase { class ComputePipeline : public ComputePipelineBase {
public: public:
ComputePipeline(ComputePipelineBuilder* builder); ComputePipeline(ComputePipelineBuilder* builder);
~ComputePipeline(); ~ComputePipeline();
void Encode(id<MTLComputeCommandEncoder> encoder); void Encode(id<MTLComputeCommandEncoder> encoder);
MTLSize GetLocalWorkGroupSize() const; MTLSize GetLocalWorkGroupSize() const;
private: private:
id<MTLComputePipelineState> mMtlComputePipelineState = nil; id<MTLComputePipelineState> mMtlComputePipelineState = nil;
MTLSize mLocalWorkgroupSize; MTLSize mLocalWorkgroupSize;
}; };
} }} // namespace backend::metal
}
#endif // BACKEND_METAL_COMPUTEPIPELINEMTL_H_ #endif // BACKEND_METAL_COMPUTEPIPELINEMTL_H_

View File

@ -17,12 +17,10 @@
#include "backend/metal/MetalBackend.h" #include "backend/metal/MetalBackend.h"
#include "backend/metal/ShaderModuleMTL.h" #include "backend/metal/ShaderModuleMTL.h"
namespace backend { namespace backend { namespace metal {
namespace metal {
ComputePipeline::ComputePipeline(ComputePipelineBuilder* builder) ComputePipeline::ComputePipeline(ComputePipelineBuilder* builder)
: ComputePipelineBase(builder) { : ComputePipelineBase(builder) {
auto mtlDevice = ToBackend(builder->GetDevice())->GetMTLDevice(); auto mtlDevice = ToBackend(builder->GetDevice())->GetMTLDevice();
const auto& module = ToBackend(builder->GetStageInfo(nxt::ShaderStage::Compute).module); const auto& module = ToBackend(builder->GetStageInfo(nxt::ShaderStage::Compute).module);
@ -30,9 +28,9 @@ namespace metal {
auto compilationData = module->GetFunction(entryPoint.c_str(), ToBackend(GetLayout())); auto compilationData = module->GetFunction(entryPoint.c_str(), ToBackend(GetLayout()));
NSError *error = nil; NSError* error = nil;
mMtlComputePipelineState = [mtlDevice mMtlComputePipelineState =
newComputePipelineStateWithFunction:compilationData.function error:&error]; [mtlDevice newComputePipelineStateWithFunction:compilationData.function error:&error];
if (error != nil) { if (error != nil) {
NSLog(@" error => %@", error); NSLog(@" error => %@", error);
builder->HandleError("Error creating pipeline state"); builder->HandleError("Error creating pipeline state");
@ -55,5 +53,4 @@ namespace metal {
return mLocalWorkgroupSize; return mLocalWorkgroupSize;
} }
} }} // namespace backend::metal
}

View File

@ -19,23 +19,21 @@
#import <Metal/Metal.h> #import <Metal/Metal.h>
namespace backend { namespace backend { namespace metal {
namespace metal {
class Device; class Device;
class DepthStencilState : public DepthStencilStateBase { class DepthStencilState : public DepthStencilStateBase {
public: public:
DepthStencilState(DepthStencilStateBuilder* builder); DepthStencilState(DepthStencilStateBuilder* builder);
~DepthStencilState(); ~DepthStencilState();
id<MTLDepthStencilState> GetMTLDepthStencilState(); id<MTLDepthStencilState> GetMTLDepthStencilState();
private: private:
id<MTLDepthStencilState> mMtlDepthStencilState = nil; id<MTLDepthStencilState> mMtlDepthStencilState = nil;
}; };
} }} // namespace backend::metal
}
#endif // BACKEND_METAL_DEPTHSTENCILSTATEMTL_H_ #endif // BACKEND_METAL_DEPTHSTENCILSTATEMTL_H_

View File

@ -16,8 +16,7 @@
#include "backend/metal/MetalBackend.h" #include "backend/metal/MetalBackend.h"
namespace backend { namespace backend { namespace metal {
namespace metal {
namespace { namespace {
MTLCompareFunction MetalDepthStencilCompareFunction(nxt::CompareFunction compareFunction) { MTLCompareFunction MetalDepthStencilCompareFunction(nxt::CompareFunction compareFunction) {
@ -68,7 +67,8 @@ namespace metal {
MTLDepthStencilDescriptor* mtlDepthStencilDescriptor = [MTLDepthStencilDescriptor new]; MTLDepthStencilDescriptor* mtlDepthStencilDescriptor = [MTLDepthStencilDescriptor new];
auto& depth = GetDepth(); auto& depth = GetDepth();
mtlDepthStencilDescriptor.depthCompareFunction = MetalDepthStencilCompareFunction(depth.compareFunction); mtlDepthStencilDescriptor.depthCompareFunction =
MetalDepthStencilCompareFunction(depth.compareFunction);
mtlDepthStencilDescriptor.depthWriteEnabled = depth.depthWriteEnabled; mtlDepthStencilDescriptor.depthWriteEnabled = depth.depthWriteEnabled;
auto& stencil = GetStencil(); auto& stencil = GetStencil();
@ -76,17 +76,23 @@ namespace metal {
MTLStencilDescriptor* backFaceStencil = [MTLStencilDescriptor new]; MTLStencilDescriptor* backFaceStencil = [MTLStencilDescriptor new];
MTLStencilDescriptor* frontFaceStencil = [MTLStencilDescriptor new]; MTLStencilDescriptor* frontFaceStencil = [MTLStencilDescriptor new];
backFaceStencil.stencilCompareFunction = MetalDepthStencilCompareFunction(stencil.back.compareFunction); backFaceStencil.stencilCompareFunction =
backFaceStencil.stencilFailureOperation = MetalStencilOperation(stencil.back.stencilFail); MetalDepthStencilCompareFunction(stencil.back.compareFunction);
backFaceStencil.stencilFailureOperation =
MetalStencilOperation(stencil.back.stencilFail);
backFaceStencil.depthFailureOperation = MetalStencilOperation(stencil.back.depthFail); backFaceStencil.depthFailureOperation = MetalStencilOperation(stencil.back.depthFail);
backFaceStencil.depthStencilPassOperation = MetalStencilOperation(stencil.back.depthStencilPass); backFaceStencil.depthStencilPassOperation =
MetalStencilOperation(stencil.back.depthStencilPass);
backFaceStencil.readMask = stencil.readMask; backFaceStencil.readMask = stencil.readMask;
backFaceStencil.writeMask = stencil.writeMask; backFaceStencil.writeMask = stencil.writeMask;
frontFaceStencil.stencilCompareFunction = MetalDepthStencilCompareFunction(stencil.front.compareFunction); frontFaceStencil.stencilCompareFunction =
frontFaceStencil.stencilFailureOperation = MetalStencilOperation(stencil.front.stencilFail); MetalDepthStencilCompareFunction(stencil.front.compareFunction);
frontFaceStencil.stencilFailureOperation =
MetalStencilOperation(stencil.front.stencilFail);
frontFaceStencil.depthFailureOperation = MetalStencilOperation(stencil.front.depthFail); frontFaceStencil.depthFailureOperation = MetalStencilOperation(stencil.front.depthFail);
frontFaceStencil.depthStencilPassOperation = MetalStencilOperation(stencil.front.depthStencilPass); frontFaceStencil.depthStencilPassOperation =
MetalStencilOperation(stencil.front.depthStencilPass);
frontFaceStencil.readMask = stencil.readMask; frontFaceStencil.readMask = stencil.readMask;
frontFaceStencil.writeMask = stencil.writeMask; frontFaceStencil.writeMask = stencil.writeMask;
@ -97,7 +103,8 @@ namespace metal {
} }
auto mtlDevice = ToBackend(builder->GetDevice())->GetMTLDevice(); auto mtlDevice = ToBackend(builder->GetDevice())->GetMTLDevice();
mMtlDepthStencilState = [mtlDevice newDepthStencilStateWithDescriptor:mtlDepthStencilDescriptor]; mMtlDepthStencilState =
[mtlDevice newDepthStencilStateWithDescriptor:mtlDepthStencilDescriptor];
[mtlDepthStencilDescriptor release]; [mtlDepthStencilDescriptor release];
} }
@ -110,5 +117,4 @@ namespace metal {
return mMtlDepthStencilState; return mMtlDepthStencilState;
} }
} }} // namespace backend::metal
}

View File

@ -12,13 +12,13 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include "backend/metal/MetalBackend.h"
#include "backend/metal/BlendStateMTL.h" #include "backend/metal/BlendStateMTL.h"
#include "backend/metal/BufferMTL.h" #include "backend/metal/BufferMTL.h"
#include "backend/metal/CommandBufferMTL.h" #include "backend/metal/CommandBufferMTL.h"
#include "backend/metal/ComputePipelineMTL.h" #include "backend/metal/ComputePipelineMTL.h"
#include "backend/metal/DepthStencilStateMTL.h" #include "backend/metal/DepthStencilStateMTL.h"
#include "backend/metal/InputStateMTL.h" #include "backend/metal/InputStateMTL.h"
#include "backend/metal/MetalBackend.h"
#include "backend/metal/PipelineLayoutMTL.h" #include "backend/metal/PipelineLayoutMTL.h"
#include "backend/metal/RenderPipelineMTL.h" #include "backend/metal/RenderPipelineMTL.h"
#include "backend/metal/SamplerMTL.h" #include "backend/metal/SamplerMTL.h"

View File

@ -19,21 +19,19 @@
#import <Metal/Metal.h> #import <Metal/Metal.h>
namespace backend { namespace backend { namespace metal {
namespace metal {
class InputState : public InputStateBase { class InputState : public InputStateBase {
public: public:
InputState(InputStateBuilder* builder); InputState(InputStateBuilder* builder);
~InputState(); ~InputState();
MTLVertexDescriptor* GetMTLVertexDescriptor(); MTLVertexDescriptor* GetMTLVertexDescriptor();
private: private:
MTLVertexDescriptor* mMtlVertexDescriptor = nil; MTLVertexDescriptor* mMtlVertexDescriptor = nil;
}; };
} }} // namespace backend::metal
}
#endif // BACKEND_METAL_COMMANDINPUTSTATEMTL_H_ #endif // BACKEND_METAL_COMMANDINPUTSTATEMTL_H_

View File

@ -17,8 +17,7 @@
#include "backend/metal/MetalBackend.h" #include "backend/metal/MetalBackend.h"
#include "common/BitSetIterator.h" #include "common/BitSetIterator.h"
namespace backend { namespace backend { namespace metal {
namespace metal {
namespace { namespace {
MTLVertexFormat VertexFormatType(nxt::VertexFormat format) { MTLVertexFormat VertexFormatType(nxt::VertexFormat format) {
@ -44,8 +43,7 @@ namespace metal {
} }
} }
InputState::InputState(InputStateBuilder* builder) InputState::InputState(InputStateBuilder* builder) : InputStateBase(builder) {
: InputStateBase(builder) {
mMtlVertexDescriptor = [MTLVertexDescriptor new]; mMtlVertexDescriptor = [MTLVertexDescriptor new];
const auto& attributesSetMask = GetAttributesSetMask(); const auto& attributesSetMask = GetAttributesSetMask();
@ -95,5 +93,4 @@ namespace metal {
return mMtlVertexDescriptor; return mMtlVertexDescriptor;
} }
} }} // namespace backend::metal
}

View File

@ -26,12 +26,11 @@
#include "backend/ToBackend.h" #include "backend/ToBackend.h"
#include "common/Serial.h" #include "common/Serial.h"
#include <type_traits>
#import <Metal/Metal.h> #import <Metal/Metal.h>
#import <QuartzCore/CAMetalLayer.h> #import <QuartzCore/CAMetalLayer.h>
#include <type_traits>
namespace backend { namespace backend { namespace metal {
namespace metal {
class BindGroup; class BindGroup;
class BindGroupLayout; class BindGroupLayout;
@ -77,7 +76,7 @@ namespace metal {
using TextureViewType = TextureView; using TextureViewType = TextureView;
}; };
template<typename T> template <typename T>
auto ToBackend(T&& common) -> decltype(ToBackendBase<MetalBackendTraits>(common)) { auto ToBackend(T&& common) -> decltype(ToBackendBase<MetalBackendTraits>(common)) {
return ToBackendBase<MetalBackendTraits>(common); return ToBackendBase<MetalBackendTraits>(common);
} }
@ -86,91 +85,90 @@ namespace metal {
class ResourceUploader; class ResourceUploader;
class Device : public DeviceBase { class Device : public DeviceBase {
public: public:
Device(id<MTLDevice> mtlDevice); Device(id<MTLDevice> mtlDevice);
~Device(); ~Device();
BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) override; BindGroupBase* CreateBindGroup(BindGroupBuilder* builder) override;
BindGroupLayoutBase* CreateBindGroupLayout(BindGroupLayoutBuilder* builder) override; BindGroupLayoutBase* CreateBindGroupLayout(BindGroupLayoutBuilder* builder) override;
BlendStateBase* CreateBlendState(BlendStateBuilder* builder) override; BlendStateBase* CreateBlendState(BlendStateBuilder* builder) override;
BufferBase* CreateBuffer(BufferBuilder* builder) override; BufferBase* CreateBuffer(BufferBuilder* builder) override;
BufferViewBase* CreateBufferView(BufferViewBuilder* builder) override; BufferViewBase* CreateBufferView(BufferViewBuilder* builder) override;
CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override; CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override;
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override; ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override; DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
InputStateBase* CreateInputState(InputStateBuilder* builder) override; InputStateBase* CreateInputState(InputStateBuilder* builder) override;
FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) override; FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) override;
PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override; PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
QueueBase* CreateQueue(QueueBuilder* builder) override; QueueBase* CreateQueue(QueueBuilder* builder) override;
RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) override; RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) override;
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override; RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
SamplerBase* CreateSampler(SamplerBuilder* builder) override; SamplerBase* CreateSampler(SamplerBuilder* builder) override;
ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override; ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override;
SwapChainBase* CreateSwapChain(SwapChainBuilder* builder) override; SwapChainBase* CreateSwapChain(SwapChainBuilder* builder) override;
TextureBase* CreateTexture(TextureBuilder* builder) override; TextureBase* CreateTexture(TextureBuilder* builder) override;
TextureViewBase* CreateTextureView(TextureViewBuilder* builder) override; TextureViewBase* CreateTextureView(TextureViewBuilder* builder) override;
void TickImpl() override; void TickImpl() override;
id<MTLDevice> GetMTLDevice(); id<MTLDevice> GetMTLDevice();
id<MTLCommandBuffer> GetPendingCommandBuffer(); id<MTLCommandBuffer> GetPendingCommandBuffer();
void SubmitPendingCommandBuffer(); void SubmitPendingCommandBuffer();
Serial GetPendingCommandSerial(); Serial GetPendingCommandSerial();
MapReadRequestTracker* GetMapReadTracker() const; MapReadRequestTracker* GetMapReadTracker() const;
ResourceUploader* GetResourceUploader() const; ResourceUploader* GetResourceUploader() const;
private: private:
void OnCompletedHandler(); void OnCompletedHandler();
id<MTLDevice> mMtlDevice = nil; id<MTLDevice> mMtlDevice = nil;
id<MTLCommandQueue> mCommandQueue = nil; id<MTLCommandQueue> mCommandQueue = nil;
MapReadRequestTracker* mMapReadTracker; MapReadRequestTracker* mMapReadTracker;
ResourceUploader* mResourceUploader; ResourceUploader* mResourceUploader;
Serial mFinishedCommandSerial = 0; Serial mFinishedCommandSerial = 0;
Serial mPendingCommandSerial = 1; Serial mPendingCommandSerial = 1;
id<MTLCommandBuffer> mPendingCommands = nil; id<MTLCommandBuffer> mPendingCommands = nil;
}; };
class BindGroup : public BindGroupBase { class BindGroup : public BindGroupBase {
public: public:
BindGroup(BindGroupBuilder* builder); BindGroup(BindGroupBuilder* builder);
}; };
class BindGroupLayout : public BindGroupLayoutBase { class BindGroupLayout : public BindGroupLayoutBase {
public: public:
BindGroupLayout(BindGroupLayoutBuilder* builder); BindGroupLayout(BindGroupLayoutBuilder* builder);
}; };
class Framebuffer : public FramebufferBase { class Framebuffer : public FramebufferBase {
public: public:
Framebuffer(FramebufferBuilder* builder); Framebuffer(FramebufferBuilder* builder);
~Framebuffer(); ~Framebuffer();
}; };
class Queue : public QueueBase { class Queue : public QueueBase {
public: public:
Queue(QueueBuilder* builder); Queue(QueueBuilder* builder);
~Queue(); ~Queue();
id<MTLCommandQueue> GetMTLCommandQueue(); id<MTLCommandQueue> GetMTLCommandQueue();
// NXT API // NXT API
void Submit(uint32_t numCommands, CommandBuffer* const * commands); void Submit(uint32_t numCommands, CommandBuffer* const* commands);
private: private:
id<MTLCommandQueue> mCommandQueue = nil; id<MTLCommandQueue> mCommandQueue = nil;
}; };
class RenderPass : public RenderPassBase { class RenderPass : public RenderPassBase {
public: public:
RenderPass(RenderPassBuilder* builder); RenderPass(RenderPassBuilder* builder);
~RenderPass(); ~RenderPass();
}; };
} }} // namespace backend::metal
}
#endif // BACKEND_METAL_METALBACKEND_H_ #endif // BACKEND_METAL_METALBACKEND_H_

View File

@ -20,8 +20,8 @@
#include "backend/metal/ComputePipelineMTL.h" #include "backend/metal/ComputePipelineMTL.h"
#include "backend/metal/DepthStencilStateMTL.h" #include "backend/metal/DepthStencilStateMTL.h"
#include "backend/metal/InputStateMTL.h" #include "backend/metal/InputStateMTL.h"
#include "backend/metal/RenderPipelineMTL.h"
#include "backend/metal/PipelineLayoutMTL.h" #include "backend/metal/PipelineLayoutMTL.h"
#include "backend/metal/RenderPipelineMTL.h"
#include "backend/metal/ResourceUploader.h" #include "backend/metal/ResourceUploader.h"
#include "backend/metal/SamplerMTL.h" #include "backend/metal/SamplerMTL.h"
#include "backend/metal/ShaderModuleMTL.h" #include "backend/metal/ShaderModuleMTL.h"
@ -30,8 +30,7 @@
#include <unistd.h> #include <unistd.h>
namespace backend { namespace backend { namespace metal {
namespace metal {
nxtProcTable GetNonValidatingProcs(); nxtProcTable GetNonValidatingProcs();
nxtProcTable GetValidatingProcs(); nxtProcTable GetValidatingProcs();
@ -45,18 +44,18 @@ namespace metal {
// Device // Device
Device::Device(id<MTLDevice> mtlDevice) Device::Device(id<MTLDevice> mtlDevice)
: mMtlDevice(mtlDevice), mMapReadTracker(new MapReadRequestTracker(this)), : mMtlDevice(mtlDevice),
mResourceUploader(new ResourceUploader(this)) { mMapReadTracker(new MapReadRequestTracker(this)),
mResourceUploader(new ResourceUploader(this)) {
[mMtlDevice retain]; [mMtlDevice retain];
mCommandQueue = [mMtlDevice newCommandQueue]; mCommandQueue = [mMtlDevice newCommandQueue];
} }
Device::~Device() { Device::~Device() {
// Wait for all commands to be finished so we can free resources // Wait for all commands to be finished so we can free resources SubmitPendingCommandBuffer
// SubmitPendingCommandBuffer may not increment the pendingCommandSerial if there // may not increment the pendingCommandSerial if there are no pending commands, so we can't
// are no pending commands, so we can't store the pendingSerial before // store the pendingSerial before SubmitPendingCommandBuffer then wait for it to be passed.
// SubmitPendingCommandBuffer then wait for it to be passed. Instead we submit and // Instead we submit and wait for the serial before the next pendingCommandSerial.
// wait for the serial before the next pendingCommandSerial.
SubmitPendingCommandBuffer(); SubmitPendingCommandBuffer();
while (mFinishedCommandSerial != mPendingCommandSerial - 1) { while (mFinishedCommandSerial != mPendingCommandSerial - 1) {
usleep(100); usleep(100);
@ -165,7 +164,8 @@ namespace metal {
// Ok, ObjC blocks are weird. My understanding is that local variables are captured by value // Ok, ObjC blocks are weird. My understanding is that local variables are captured by value
// so this-> works as expected. However it is unclear how members are captured, (are they // so this-> works as expected. However it is unclear how members are captured, (are they
// captured using this-> or by value?) so we make a copy of the pendingCommandSerial on the stack. // captured using this-> or by value?) so we make a copy of the pendingCommandSerial on the
// stack.
Serial pendingSerial = mPendingCommandSerial; Serial pendingSerial = mPendingCommandSerial;
[mPendingCommands addCompletedHandler:^(id<MTLCommandBuffer>) { [mPendingCommands addCompletedHandler:^(id<MTLCommandBuffer>) {
this->mFinishedCommandSerial = pendingSerial; this->mFinishedCommandSerial = pendingSerial;
@ -174,14 +174,14 @@ namespace metal {
[mPendingCommands commit]; [mPendingCommands commit];
[mPendingCommands release]; [mPendingCommands release];
mPendingCommands = nil; mPendingCommands = nil;
mPendingCommandSerial ++; mPendingCommandSerial++;
} }
uint64_t Device::GetPendingCommandSerial() { uint64_t Device::GetPendingCommandSerial() {
// If this is called, then it means some piece of code somewhere will wait for this serial to // If this is called, then it means some piece of code somewhere will wait for this serial
// complete. Make sure the pending command buffer is created so that it is on the worst case // to complete. Make sure the pending command buffer is created so that it is on the worst
// enqueued on the next Tick() and eventually increments the serial. Otherwise if no GPU work // case enqueued on the next Tick() and eventually increments the serial. Otherwise if no
// happens we could be waiting for this serial forever. // GPU work happens we could be waiting for this serial forever.
GetPendingCommandBuffer(); GetPendingCommandBuffer();
return mPendingCommandSerial; return mPendingCommandSerial;
} }
@ -196,8 +196,7 @@ namespace metal {
// Bind Group // Bind Group
BindGroup::BindGroup(BindGroupBuilder* builder) BindGroup::BindGroup(BindGroupBuilder* builder) : BindGroupBase(builder) {
: BindGroupBase(builder) {
} }
// Bind Group Layout // Bind Group Layout
@ -208,8 +207,7 @@ namespace metal {
// Framebuffer // Framebuffer
Framebuffer::Framebuffer(FramebufferBuilder* builder) Framebuffer::Framebuffer(FramebufferBuilder* builder) : FramebufferBase(builder) {
: FramebufferBase(builder) {
} }
Framebuffer::~Framebuffer() { Framebuffer::~Framebuffer() {
@ -217,8 +215,7 @@ namespace metal {
// Queue // Queue
Queue::Queue(QueueBuilder* builder) Queue::Queue(QueueBuilder* builder) : QueueBase(builder) {
: QueueBase(builder) {
Device* device = ToBackend(builder->GetDevice()); Device* device = ToBackend(builder->GetDevice());
mCommandQueue = [device->GetMTLDevice() newCommandQueue]; mCommandQueue = [device->GetMTLDevice() newCommandQueue];
} }
@ -232,7 +229,7 @@ namespace metal {
return mCommandQueue; return mCommandQueue;
} }
void Queue::Submit(uint32_t numCommands, CommandBuffer* const * commands) { void Queue::Submit(uint32_t numCommands, CommandBuffer* const* commands) {
Device* device = ToBackend(GetDevice()); Device* device = ToBackend(GetDevice());
id<MTLCommandBuffer> commandBuffer = device->GetPendingCommandBuffer(); id<MTLCommandBuffer> commandBuffer = device->GetPendingCommandBuffer();
@ -245,12 +242,10 @@ namespace metal {
// RenderPass // RenderPass
RenderPass::RenderPass(RenderPassBuilder* builder) RenderPass::RenderPass(RenderPassBuilder* builder) : RenderPassBase(builder) {
: RenderPassBase(builder) {
} }
RenderPass::~RenderPass() { RenderPass::~RenderPass() {
} }
} }} // namespace backend::metal
}

View File

@ -25,21 +25,20 @@ namespace spirv_cross {
class CompilerMSL; class CompilerMSL;
} }
namespace backend { namespace backend { namespace metal {
namespace metal {
class PipelineLayout : public PipelineLayoutBase { class PipelineLayout : public PipelineLayoutBase {
public: public:
PipelineLayout(PipelineLayoutBuilder* builder); PipelineLayout(PipelineLayoutBuilder* builder);
using BindingIndexInfo = std::array<std::array<uint32_t, kMaxBindingsPerGroup>, kMaxBindGroups>; using BindingIndexInfo =
const BindingIndexInfo& GetBindingIndexInfo(nxt::ShaderStage stage) const; std::array<std::array<uint32_t, kMaxBindingsPerGroup>, kMaxBindGroups>;
const BindingIndexInfo& GetBindingIndexInfo(nxt::ShaderStage stage) const;
private: private:
PerStage<BindingIndexInfo> mIndexInfo; PerStage<BindingIndexInfo> mIndexInfo;
}; };
} }} // namespace backend::metal
}
#endif // BACKEND_METAL_PIPELINELAYOUTMTL_H_ #endif // BACKEND_METAL_PIPELINELAYOUTMTL_H_

View File

@ -16,11 +16,9 @@
#include "backend/metal/MetalBackend.h" #include "backend/metal/MetalBackend.h"
namespace backend { namespace backend { namespace metal {
namespace metal {
PipelineLayout::PipelineLayout(PipelineLayoutBuilder* builder) PipelineLayout::PipelineLayout(PipelineLayoutBuilder* builder) : PipelineLayoutBase(builder) {
: PipelineLayoutBase(builder) {
// Each stage has its own numbering namespace in CompilerMSL. // Each stage has its own numbering namespace in CompilerMSL.
for (auto stage : IterateStages(kAllStages)) { for (auto stage : IterateStages(kAllStages)) {
// Buffer number 0 is reserved for push constants // Buffer number 0 is reserved for push constants
@ -58,9 +56,9 @@ namespace metal {
} }
} }
const PipelineLayout::BindingIndexInfo& PipelineLayout::GetBindingIndexInfo(nxt::ShaderStage stage) const { const PipelineLayout::BindingIndexInfo& PipelineLayout::GetBindingIndexInfo(
nxt::ShaderStage stage) const {
return mIndexInfo[stage]; return mIndexInfo[stage];
} }
} }} // namespace backend::metal
}

View File

@ -19,26 +19,24 @@
#import <Metal/Metal.h> #import <Metal/Metal.h>
namespace backend { namespace backend { namespace metal {
namespace metal {
class RenderPipeline : public RenderPipelineBase { class RenderPipeline : public RenderPipelineBase {
public: public:
RenderPipeline(RenderPipelineBuilder* builder); RenderPipeline(RenderPipelineBuilder* builder);
~RenderPipeline(); ~RenderPipeline();
MTLIndexType GetMTLIndexType() const; MTLIndexType GetMTLIndexType() const;
MTLPrimitiveType GetMTLPrimitiveTopology() const; MTLPrimitiveType GetMTLPrimitiveTopology() const;
void Encode(id<MTLRenderCommandEncoder> encoder); void Encode(id<MTLRenderCommandEncoder> encoder);
private: private:
MTLIndexType mMtlIndexType; MTLIndexType mMtlIndexType;
MTLPrimitiveType mMtlPrimitiveTopology; MTLPrimitiveType mMtlPrimitiveTopology;
id<MTLRenderPipelineState> mMtlRenderPipelineState = nil; id<MTLRenderPipelineState> mMtlRenderPipelineState = nil;
}; };
} }} // namespace backend::metal
}
#endif // BACKEND_METAL_RENDERPIPELINEMTL_H_ #endif // BACKEND_METAL_RENDERPIPELINEMTL_H_

View File

@ -22,8 +22,7 @@
#include "backend/metal/ShaderModuleMTL.h" #include "backend/metal/ShaderModuleMTL.h"
#include "backend/metal/TextureMTL.h" #include "backend/metal/TextureMTL.h"
namespace backend { namespace backend { namespace metal {
namespace metal {
namespace { namespace {
MTLPrimitiveType MTLPrimitiveTopology(nxt::PrimitiveTopology primitiveTopology) { MTLPrimitiveType MTLPrimitiveTopology(nxt::PrimitiveTopology primitiveTopology) {
@ -41,7 +40,8 @@ namespace metal {
} }
} }
MTLPrimitiveTopologyClass MTLInputPrimitiveTopology(nxt::PrimitiveTopology primitiveTopology) { MTLPrimitiveTopologyClass MTLInputPrimitiveTopology(
nxt::PrimitiveTopology primitiveTopology) {
switch (primitiveTopology) { switch (primitiveTopology) {
case nxt::PrimitiveTopology::PointList: case nxt::PrimitiveTopology::PointList:
return MTLPrimitiveTopologyClassPoint; return MTLPrimitiveTopologyClassPoint;
@ -68,7 +68,6 @@ namespace metal {
: RenderPipelineBase(builder), : RenderPipelineBase(builder),
mMtlIndexType(MTLIndexFormat(GetIndexFormat())), mMtlIndexType(MTLIndexFormat(GetIndexFormat())),
mMtlPrimitiveTopology(MTLPrimitiveTopology(GetPrimitiveTopology())) { mMtlPrimitiveTopology(MTLPrimitiveTopology(GetPrimitiveTopology())) {
auto mtlDevice = ToBackend(builder->GetDevice())->GetMTLDevice(); auto mtlDevice = ToBackend(builder->GetDevice())->GetMTLDevice();
MTLRenderPipelineDescriptor* descriptor = [MTLRenderPipelineDescriptor new]; MTLRenderPipelineDescriptor* descriptor = [MTLRenderPipelineDescriptor new];
@ -77,7 +76,8 @@ namespace metal {
const auto& module = ToBackend(builder->GetStageInfo(stage).module); const auto& module = ToBackend(builder->GetStageInfo(stage).module);
const auto& entryPoint = builder->GetStageInfo(stage).entryPoint; const auto& entryPoint = builder->GetStageInfo(stage).entryPoint;
id<MTLFunction> function = module->GetFunction(entryPoint.c_str(), ToBackend(GetLayout())).function; id<MTLFunction> function =
module->GetFunction(entryPoint.c_str(), ToBackend(GetLayout())).function;
switch (stage) { switch (stage) {
case nxt::ShaderStage::Vertex: case nxt::ShaderStage::Vertex:
@ -95,7 +95,8 @@ namespace metal {
auto& subpassInfo = renderPass->GetSubpassInfo(GetSubPass()); auto& subpassInfo = renderPass->GetSubpassInfo(GetSubPass());
if (subpassInfo.depthStencilAttachmentSet) { if (subpassInfo.depthStencilAttachmentSet) {
const auto& attachmentInfo = renderPass->GetAttachmentInfo(subpassInfo.depthStencilAttachment); const auto& attachmentInfo =
renderPass->GetAttachmentInfo(subpassInfo.depthStencilAttachment);
descriptor.depthAttachmentPixelFormat = MetalPixelFormat(attachmentInfo.format); descriptor.depthAttachmentPixelFormat = MetalPixelFormat(attachmentInfo.format);
descriptor.stencilAttachmentPixelFormat = MetalPixelFormat(attachmentInfo.format); descriptor.stencilAttachmentPixelFormat = MetalPixelFormat(attachmentInfo.format);
} }
@ -104,8 +105,10 @@ namespace metal {
uint32_t attachment = subpassInfo.colorAttachments[attachmentSlot]; uint32_t attachment = subpassInfo.colorAttachments[attachmentSlot];
const auto& attachmentInfo = renderPass->GetAttachmentInfo(attachment); const auto& attachmentInfo = renderPass->GetAttachmentInfo(attachment);
descriptor.colorAttachments[attachmentSlot].pixelFormat = MetalPixelFormat(attachmentInfo.format); descriptor.colorAttachments[attachmentSlot].pixelFormat =
ToBackend(GetBlendState(attachmentSlot))->ApplyBlendState(descriptor.colorAttachments[attachmentSlot]); MetalPixelFormat(attachmentInfo.format);
ToBackend(GetBlendState(attachmentSlot))
->ApplyBlendState(descriptor.colorAttachments[attachmentSlot]);
} }
descriptor.inputPrimitiveTopology = MTLInputPrimitiveTopology(GetPrimitiveTopology()); descriptor.inputPrimitiveTopology = MTLInputPrimitiveTopology(GetPrimitiveTopology());
@ -115,9 +118,9 @@ namespace metal {
// TODO(kainino@chromium.org): push constants, textures, samplers // TODO(kainino@chromium.org): push constants, textures, samplers
NSError *error = nil; NSError* error = nil;
mMtlRenderPipelineState = [mtlDevice mMtlRenderPipelineState =
newRenderPipelineStateWithDescriptor:descriptor error:&error]; [mtlDevice newRenderPipelineStateWithDescriptor:descriptor error:&error];
if (error != nil) { if (error != nil) {
NSLog(@" error => %@", error); NSLog(@" error => %@", error);
builder->HandleError("Error creating pipeline state"); builder->HandleError("Error creating pipeline state");
@ -144,5 +147,4 @@ namespace metal {
[encoder setRenderPipelineState:mMtlRenderPipelineState]; [encoder setRenderPipelineState:mMtlRenderPipelineState];
} }
} }} // namespace backend::metal
}

View File

@ -20,26 +20,23 @@
#import <Metal/Metal.h> #import <Metal/Metal.h>
namespace backend { namespace backend { namespace metal {
namespace metal {
class Device; class Device;
class ResourceUploader { class ResourceUploader {
public: public:
ResourceUploader(Device* device); ResourceUploader(Device* device);
~ResourceUploader(); ~ResourceUploader();
void BufferSubData(id<MTLBuffer> buffer, uint32_t start, uint32_t size, const void* data); void BufferSubData(id<MTLBuffer> buffer, uint32_t start, uint32_t size, const void* data);
void Tick(Serial finishedSerial); void Tick(Serial finishedSerial);
private: private:
Device* mDevice; Device* mDevice;
SerialQueue<id<MTLBuffer>> mInflightUploadBuffers; SerialQueue<id<MTLBuffer>> mInflightUploadBuffers;
}; };
}} // namespace backend::metal
} #endif // BACKEND_METAL_RESOURCEUPLOADER_H_
}
#endif // BACKEND_METAL_RESOURCEUPLOADER_H_

View File

@ -16,30 +16,32 @@
#include "backend/metal/MetalBackend.h" #include "backend/metal/MetalBackend.h"
namespace backend { namespace backend { namespace metal {
namespace metal {
ResourceUploader::ResourceUploader(Device* device) ResourceUploader::ResourceUploader(Device* device) : mDevice(device) {
: mDevice(device) {
} }
ResourceUploader::~ResourceUploader() { ResourceUploader::~ResourceUploader() {
ASSERT(mInflightUploadBuffers.Empty()); ASSERT(mInflightUploadBuffers.Empty());
} }
void ResourceUploader::BufferSubData(id<MTLBuffer> buffer, uint32_t start, uint32_t size, const void* data) { void ResourceUploader::BufferSubData(id<MTLBuffer> buffer,
// TODO(cwallez@chromium.org) use a ringbuffer instead of creating a small buffer for each update uint32_t start,
id<MTLBuffer> uploadBuffer = [mDevice->GetMTLDevice() newBufferWithLength:size uint32_t size,
options:MTLResourceStorageModeShared]; const void* data) {
// TODO(cwallez@chromium.org) use a ringbuffer instead of creating a small buffer for each
// update
id<MTLBuffer> uploadBuffer =
[mDevice->GetMTLDevice() newBufferWithLength:size options:MTLResourceStorageModeShared];
memcpy([uploadBuffer contents], data, size); memcpy([uploadBuffer contents], data, size);
id<MTLCommandBuffer> commandBuffer = mDevice->GetPendingCommandBuffer(); id<MTLCommandBuffer> commandBuffer = mDevice->GetPendingCommandBuffer();
id<MTLBlitCommandEncoder> encoder = [commandBuffer blitCommandEncoder]; id<MTLBlitCommandEncoder> encoder = [commandBuffer blitCommandEncoder];
[encoder copyFromBuffer:uploadBuffer [encoder copyFromBuffer:uploadBuffer
sourceOffset:0 sourceOffset:0
toBuffer:buffer toBuffer:buffer
destinationOffset:start destinationOffset:start
size:size]; size:size];
[encoder endEncoding]; [encoder endEncoding];
mInflightUploadBuffers.Enqueue(uploadBuffer, mDevice->GetPendingCommandSerial()); mInflightUploadBuffers.Enqueue(uploadBuffer, mDevice->GetPendingCommandSerial());
@ -52,5 +54,4 @@ namespace metal {
mInflightUploadBuffers.ClearUpTo(finishedSerial); mInflightUploadBuffers.ClearUpTo(finishedSerial);
} }
} }} // namespace backend::metal
}

View File

@ -19,21 +19,19 @@
#import <Metal/Metal.h> #import <Metal/Metal.h>
namespace backend { namespace backend { namespace metal {
namespace metal {
class Sampler : public SamplerBase { class Sampler : public SamplerBase {
public: public:
Sampler(SamplerBuilder* builder); Sampler(SamplerBuilder* builder);
~Sampler(); ~Sampler();
id<MTLSamplerState> GetMTLSamplerState(); id<MTLSamplerState> GetMTLSamplerState();
private: private:
id<MTLSamplerState> mMtlSamplerState = nil; id<MTLSamplerState> mMtlSamplerState = nil;
}; };
} }} // namespace backend::metal
}
#endif // BACKEND_METAL_SAMPLERMTL_H_ #endif // BACKEND_METAL_SAMPLERMTL_H_

View File

@ -16,8 +16,7 @@
#include "backend/metal/MetalBackend.h" #include "backend/metal/MetalBackend.h"
namespace backend { namespace backend { namespace metal {
namespace metal {
namespace { namespace {
MTLSamplerMinMagFilter FilterModeToMinMagFilter(nxt::FilterMode mode) { MTLSamplerMinMagFilter FilterModeToMinMagFilter(nxt::FilterMode mode) {
@ -39,8 +38,7 @@ namespace metal {
} }
} }
Sampler::Sampler(SamplerBuilder* builder) Sampler::Sampler(SamplerBuilder* builder) : SamplerBase(builder) {
: SamplerBase(builder) {
auto desc = [MTLSamplerDescriptor new]; auto desc = [MTLSamplerDescriptor new];
[desc autorelease]; [desc autorelease];
desc.minFilter = FilterModeToMinMagFilter(builder->GetMinFilter()); desc.minFilter = FilterModeToMinMagFilter(builder->GetMinFilter());
@ -60,5 +58,4 @@ namespace metal {
return mMtlSamplerState; return mMtlSamplerState;
} }
} }} // namespace backend::metal
}

View File

@ -23,29 +23,27 @@ namespace spirv_cross {
class CompilerMSL; class CompilerMSL;
} }
namespace backend { namespace backend { namespace metal {
namespace metal {
class PipelineLayout; class PipelineLayout;
class ShaderModule : public ShaderModuleBase { class ShaderModule : public ShaderModuleBase {
public: public:
ShaderModule(ShaderModuleBuilder* builder); ShaderModule(ShaderModuleBuilder* builder);
struct MetalFunctionData { struct MetalFunctionData {
id<MTLFunction> function; id<MTLFunction> function;
MTLSize localWorkgroupSize; MTLSize localWorkgroupSize;
}; };
MetalFunctionData GetFunction(const char* functionName, const PipelineLayout* layout) const; MetalFunctionData GetFunction(const char* functionName, const PipelineLayout* layout) const;
private: private:
// Calling compile on CompilerMSL somehow changes internal state that makes subsequent // Calling compile on CompilerMSL somehow changes internal state that makes subsequent
// compiles return invalid MSL. We keep the spirv around and recreate the compiler everytime // compiles return invalid MSL. We keep the spirv around and recreate the compiler everytime
// we need to use it. // we need to use it.
std::vector<uint32_t> mSpirv; std::vector<uint32_t> mSpirv;
}; };
} }} // namespace backend::metal
}
#endif // BACKEND_METAL_SHADERMODULEMTL_H_ #endif // BACKEND_METAL_SHADERMODULEMTL_H_

View File

@ -21,13 +21,12 @@
#include <sstream> #include <sstream>
namespace backend { namespace backend { namespace metal {
namespace metal {
namespace { namespace {
spv::ExecutionModel SpirvExecutionModelForStage(nxt::ShaderStage stage) { spv::ExecutionModel SpirvExecutionModelForStage(nxt::ShaderStage stage) {
switch(stage) { switch (stage) {
case nxt::ShaderStage::Vertex: case nxt::ShaderStage::Vertex:
return spv::ExecutionModelVertex; return spv::ExecutionModelVertex;
case nxt::ShaderStage::Fragment: case nxt::ShaderStage::Fragment:
@ -38,7 +37,6 @@ namespace metal {
UNREACHABLE(); UNREACHABLE();
} }
} }
} }
ShaderModule::ShaderModule(ShaderModuleBuilder* builder) ShaderModule::ShaderModule(ShaderModuleBuilder* builder)
@ -69,10 +67,8 @@ namespace metal {
// Create one resource binding entry per stage per binding. // Create one resource binding entry per stage per binding.
for (uint32_t group : IterateBitSet(layout->GetBindGroupsLayoutMask())) { for (uint32_t group : IterateBitSet(layout->GetBindGroupsLayoutMask())) {
const auto& bgInfo = layout->GetBindGroupLayout(group)->GetBindingInfo(); const auto& bgInfo = layout->GetBindGroupLayout(group)->GetBindingInfo();
for (uint32_t binding : IterateBitSet(bgInfo.mask)) { for (uint32_t binding : IterateBitSet(bgInfo.mask)) {
for (auto stage : IterateStages(bgInfo.visibilities[binding])) { for (auto stage : IterateStages(bgInfo.visibilities[binding])) {
uint32_t index = layout->GetBindingIndexInfo(stage)[group][binding]; uint32_t index = layout->GetBindingIndexInfo(stage)[group][binding];
@ -101,13 +97,15 @@ namespace metal {
NSString* mslSource = [NSString stringWithFormat:@"%s", msl.c_str()]; NSString* mslSource = [NSString stringWithFormat:@"%s", msl.c_str()];
auto mtlDevice = ToBackend(GetDevice())->GetMTLDevice(); auto mtlDevice = ToBackend(GetDevice())->GetMTLDevice();
NSError *error = nil; NSError* error = nil;
id<MTLLibrary> library = [mtlDevice newLibraryWithSource:mslSource options:nil error:&error]; id<MTLLibrary> library =
[mtlDevice newLibraryWithSource:mslSource options:nil error:&error];
if (error != nil) { if (error != nil) {
// TODO(cwallez@chromium.org): forward errors to caller // TODO(cwallez@chromium.org): forward errors to caller
NSLog(@"MTLDevice newLibraryWithSource => %@", error); NSLog(@"MTLDevice newLibraryWithSource => %@", error);
} }
// TODO(kainino@chromium.org): make this somehow more robust; it needs to behave like clean_func_name: // TODO(kainino@chromium.org): make this somehow more robust; it needs to behave like
// clean_func_name:
// https://github.com/KhronosGroup/SPIRV-Cross/blob/4e915e8c483e319d0dd7a1fa22318bef28f8cca3/spirv_msl.cpp#L1213 // https://github.com/KhronosGroup/SPIRV-Cross/blob/4e915e8c483e319d0dd7a1fa22318bef28f8cca3/spirv_msl.cpp#L1213
if (strcmp(functionName, "main") == 0) { if (strcmp(functionName, "main") == 0) {
functionName = "main0"; functionName = "main0";
@ -121,5 +119,4 @@ namespace metal {
return result; return result;
} }
} }} // namespace backend::metal
}

View File

@ -17,21 +17,19 @@
#include "backend/SwapChain.h" #include "backend/SwapChain.h"
namespace backend { namespace backend { namespace metal {
namespace metal {
class Device; class Device;
class SwapChain : public SwapChainBase { class SwapChain : public SwapChainBase {
public: public:
SwapChain(SwapChainBuilder* builder); SwapChain(SwapChainBuilder* builder);
~SwapChain(); ~SwapChain();
protected: protected:
TextureBase* GetNextTextureImpl(TextureBuilder* builder) override; TextureBase* GetNextTextureImpl(TextureBuilder* builder) override;
}; };
} }} // namespace backend::metal
}
#endif // BACKEND_METAL_SWAPCHAINGL_H_ #endif // BACKEND_METAL_SWAPCHAINGL_H_

View File

@ -19,11 +19,9 @@
#include <nxt/nxt_wsi.h> #include <nxt/nxt_wsi.h>
namespace backend { namespace backend { namespace metal {
namespace metal {
SwapChain::SwapChain(SwapChainBuilder* builder) SwapChain::SwapChain(SwapChainBuilder* builder) : SwapChainBase(builder) {
: SwapChainBase(builder) {
const auto& im = GetImplementation(); const auto& im = GetImplementation();
nxtWSIContextMetal wsiContext = {}; nxtWSIContextMetal wsiContext = {};
wsiContext.device = ToBackend(GetDevice())->GetMTLDevice(); wsiContext.device = ToBackend(GetDevice())->GetMTLDevice();
@ -46,5 +44,4 @@ namespace metal {
return new Texture(builder, nativeTexture); return new Texture(builder, nativeTexture);
} }
} }} // namespace backend::metal
}

View File

@ -19,31 +19,30 @@
#import <Metal/Metal.h> #import <Metal/Metal.h>
namespace backend { namespace backend { namespace metal {
namespace metal {
MTLPixelFormat MetalPixelFormat(nxt::TextureFormat format); MTLPixelFormat MetalPixelFormat(nxt::TextureFormat format);
class Texture : public TextureBase { class Texture : public TextureBase {
public: public:
Texture(TextureBuilder* builder); Texture(TextureBuilder* builder);
Texture(TextureBuilder* builder, id<MTLTexture> mtlTexture); Texture(TextureBuilder* builder, id<MTLTexture> mtlTexture);
~Texture(); ~Texture();
id<MTLTexture> GetMTLTexture(); id<MTLTexture> GetMTLTexture();
void TransitionUsageImpl(nxt::TextureUsageBit currentUsage, nxt::TextureUsageBit targetUsage) override; void TransitionUsageImpl(nxt::TextureUsageBit currentUsage,
nxt::TextureUsageBit targetUsage) override;
private: private:
id<MTLTexture> mMtlTexture = nil; id<MTLTexture> mMtlTexture = nil;
}; };
class TextureView : public TextureViewBase { class TextureView : public TextureViewBase {
public: public:
TextureView(TextureViewBuilder* builder); TextureView(TextureViewBuilder* builder);
}; };
} }} // namespace backend::metal
}
#endif // BACKEND_METAL_TEXTUREMTL_H_ #endif // BACKEND_METAL_TEXTUREMTL_H_

View File

@ -16,8 +16,7 @@
#include "backend/metal/MetalBackend.h" #include "backend/metal/MetalBackend.h"
namespace backend { namespace backend { namespace metal {
namespace metal {
MTLPixelFormat MetalPixelFormat(nxt::TextureFormat format) { MTLPixelFormat MetalPixelFormat(nxt::TextureFormat format) {
switch (format) { switch (format) {
@ -34,7 +33,7 @@ namespace metal {
namespace { namespace {
MTLTextureUsage MetalTextureUsage(nxt::TextureUsageBit usage) { MTLTextureUsage MetalTextureUsage(nxt::TextureUsageBit usage) {
MTLTextureUsage result = MTLTextureUsageUnknown; // This is 0 MTLTextureUsage result = MTLTextureUsageUnknown; // This is 0
if (usage & (nxt::TextureUsageBit::Storage)) { if (usage & (nxt::TextureUsageBit::Storage)) {
result |= MTLTextureUsageShaderWrite | MTLTextureUsageShaderRead; result |= MTLTextureUsageShaderWrite | MTLTextureUsageShaderRead;
@ -59,8 +58,7 @@ namespace metal {
} }
} }
Texture::Texture(TextureBuilder* builder) Texture::Texture(TextureBuilder* builder) : TextureBase(builder) {
: TextureBase(builder) {
auto desc = [MTLTextureDescriptor new]; auto desc = [MTLTextureDescriptor new];
[desc autorelease]; [desc autorelease];
desc.textureType = MetalTextureType(GetDimension()); desc.textureType = MetalTextureType(GetDimension());
@ -93,8 +91,7 @@ namespace metal {
void Texture::TransitionUsageImpl(nxt::TextureUsageBit, nxt::TextureUsageBit) { void Texture::TransitionUsageImpl(nxt::TextureUsageBit, nxt::TextureUsageBit) {
} }
TextureView::TextureView(TextureViewBuilder* builder) TextureView::TextureView(TextureViewBuilder* builder) : TextureViewBase(builder) {
: TextureViewBase(builder) {
} }
}
} }} // namespace backend::metal