diff --git a/src/modules/graphics/metal/Graphics.h b/src/modules/graphics/metal/Graphics.h index 021e98703..b2d39aeb4 100644 --- a/src/modules/graphics/metal/Graphics.h +++ b/src/modules/graphics/metal/Graphics.h @@ -165,7 +165,7 @@ private: void endPass(); id getCachedDepthStencilState(const DepthState &depth, const StencilState &stencil); - void applyRenderState(id renderEncoder); + void applyRenderState(id renderEncoder, const vertex::Attributes &attributes); id commandQueue; diff --git a/src/modules/graphics/metal/Graphics.mm b/src/modules/graphics/metal/Graphics.mm index b8e928ce8..012e31aec 100644 --- a/src/modules/graphics/metal/Graphics.mm +++ b/src/modules/graphics/metal/Graphics.mm @@ -423,7 +423,7 @@ id Graphics::getCachedDepthStencilState(const DepthState & return state; } -void Graphics::applyRenderState(id encoder) +void Graphics::applyRenderState(id encoder, const vertex::Attributes &attributes) { const uint32 pipelineStateBits = STATEBIT_SHADER | STATEBIT_BLEND | STATEBIT_COLORMASK; @@ -492,7 +492,7 @@ void Graphics::applyRenderState(id encoder) } // TODO: attributes - if (dirtyState & pipelineStateBits) + if ((dirtyState & pipelineStateBits) != 0 || true) { // Shader *shader = (Shader *) state.shader.get(); Shader *shader = (Shader *) Shader::current; @@ -502,6 +502,7 @@ void Graphics::applyRenderState(id encoder) { Shader::RenderPipelineKey key; + key.vertexAttributes = attributes; key.blend = state.blend; key.colorChannelMask = state.colorMask; @@ -533,15 +534,32 @@ void Graphics::draw(const DrawCommand &cmd) { @autoreleasepool { id encoder = useRenderEncoder(); - applyRenderState(encoder); + applyRenderState(encoder, *cmd.attributes); - // TODO: vertex attributes + id mtltexture = (__bridge id)(void *) cmd.texture->getHandle(); - id texture = (__bridge id)(void *) cmd.texture->getHandle(); - [encoder setFragmentTexture:texture atIndex:0]; + [encoder setFragmentTexture:mtltexture atIndex:0]; + [encoder setFragmentSamplerState:((Texture *)cmd.texture)->getMTLSampler() atIndex:0]; [encoder setCullMode:MTLCullModeNone]; + uint32 allbits = cmd.buffers->useBits; + uint32 i = 0; + while (allbits) + { + uint32 bit = 1u << i; + + if (cmd.buffers->useBits & bit) + { + auto b = cmd.buffers->info[i]; + id buffer = (__bridge id)(void *)b.buffer->getHandle(); + [encoder setVertexBuffer:buffer offset:b.offset atIndex:i]; + } + + i++; + allbits >>= 1; + } + [encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:cmd.vertexStart vertexCount:cmd.vertexCount @@ -552,13 +570,32 @@ void Graphics::draw(const DrawIndexedCommand &cmd) { @autoreleasepool { id encoder = useRenderEncoder(); - applyRenderState(encoder); + applyRenderState(encoder, *cmd.attributes); - id texture = (__bridge id)(void *) cmd.texture->getHandle(); - [encoder setFragmentTexture:texture atIndex:0]; + id mtltexture = (__bridge id)(void *) cmd.texture->getHandle(); + + [encoder setFragmentTexture:mtltexture atIndex:0]; + [encoder setFragmentSamplerState:((Texture *)cmd.texture)->getMTLSampler() atIndex:0]; [encoder setCullMode:MTLCullModeNone]; + uint32 allbits = cmd.buffers->useBits; + uint32 i = 0; + while (allbits) + { + uint32 bit = 1u << i; + + if (cmd.buffers->useBits & bit) + { + auto b = cmd.buffers->info[i]; + id buffer = (__bridge id)(void *)b.buffer->getHandle(); + [encoder setVertexBuffer:buffer offset:b.offset atIndex:i]; + } + + i++; + allbits >>= 1; + } + auto indexType = cmd.indexType == INDEX_UINT32 ? MTLIndexTypeUInt32 : MTLIndexTypeUInt16; [encoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle @@ -576,16 +613,34 @@ void Graphics::drawQuads(int start, int count, const vertex::Attributes &attribu id encoder = useRenderEncoder(); - applyRenderState(encoder); + applyRenderState(encoder, attributes); - id tex = (__bridge id)(void *) texture->getHandle(); - [encoder setFragmentTexture:tex atIndex:0]; + id mtltexture = (__bridge id)(void *) texture->getHandle(); + + [encoder setFragmentTexture:mtltexture atIndex:0]; + [encoder setFragmentSamplerState:((Texture *)texture)->getMTLSampler() atIndex:0]; [encoder setCullMode:MTLCullModeNone]; + uint32 allbits = buffers.useBits; + uint32 i = 0; + while (allbits) + { + uint32 bit = 1u << i; + + if (buffers.useBits & bit) + { + auto b = buffers.info[i]; + id buffer = (__bridge id)(void *)b.buffer->getHandle(); + [encoder setVertexBuffer:buffer offset:b.offset atIndex:i]; + } + + i++; + allbits >>= 1; + } + id ib = (__bridge id)(void *) quadIndexBuffer->getHandle(); - // TODO: Set vertex buffers/attributes // TODO: support for iOS devices that don't support base vertex. int basevertex = start * 4; @@ -716,6 +771,7 @@ void Graphics::clear(OptionalColorf c, OptionalInt stencil, OptionalDouble depth // TODO: handle clearing mid-pass if (c.hasValue) { + gammaCorrectColor(c.value); auto color = MTLClearColorMake(c.value.r, c.value.g, c.value.b, c.value.a); for (int i = 0; i < MAX_COLOR_RENDER_TARGETS; i++) { @@ -758,7 +814,10 @@ void Graphics::clear(const std::vector &colors, OptionalInt sten { if (!colors[i].hasValue) continue; - const Colorf &c = colors[i].value; + + Colorf c = colors[i].value; + gammaCorrectColor(c); + passDesc.colorAttachments[i].clearColor = MTLClearColorMake(c.r, c.g, c.b, c.a); passDesc.colorAttachments[i].loadAction = MTLLoadActionClear; } diff --git a/src/modules/graphics/metal/Shader.mm b/src/modules/graphics/metal/Shader.mm index e1a004bc5..3aa4a1a25 100644 --- a/src/modules/graphics/metal/Shader.mm +++ b/src/modules/graphics/metal/Shader.mm @@ -40,6 +40,37 @@ static_assert(MAX_COLOR_RENDER_TARGETS <= 8, "Metal pipeline cache key only stor static MTLVertexFormat getMTLVertexFormat(vertex::DataType type, int components) { + switch (type) + { + case vertex::DATA_UNORM8: + if (components == 1) + return MTLVertexFormatUCharNormalized; + else if (components == 2) + return MTLVertexFormatUChar2Normalized; + else if (components == 3) + return MTLVertexFormatUChar3Normalized; + else + return MTLVertexFormatUChar4Normalized; + case vertex::DATA_UNORM16: + if (components == 1) + return MTLVertexFormatUShortNormalized; + else if (components == 2) + return MTLVertexFormatUShort2Normalized; + else if (components == 3) + return MTLVertexFormatUShort3Normalized; + else + return MTLVertexFormatUShort4Normalized; + case vertex::DATA_FLOAT: + if (components == 1) + return MTLVertexFormatFloat; + else if (components == 2) + return MTLVertexFormatFloat2; + else if (components == 3) + return MTLVertexFormatFloat3; + else + return MTLVertexFormatFloat4; + } + // TODO return MTLVertexFormatFloat4; } diff --git a/src/modules/graphics/metal/Texture.h b/src/modules/graphics/metal/Texture.h index 04d71dbfb..0c4fd128d 100644 --- a/src/modules/graphics/metal/Texture.h +++ b/src/modules/graphics/metal/Texture.h @@ -46,8 +46,11 @@ public: ptrdiff_t getHandle() const override { return (ptrdiff_t) texture; } ptrdiff_t getRenderTargetHandle() const override { return msaaTexture != nil ? (ptrdiff_t) msaaTexture : (ptrdiff_t) texture; } + int getMSAA() const override { return 1 /* TODO*/; } + id getMTLSampler() const { return sampler; } + private: void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd = nullptr) override;