mirror of
https://github.com/love2d/love.git
synced 2026-08-19 12:14:20 +02:00
metal: partial implementation of pipeline states.
Add BGRA8 pixel format.
This commit is contained in:
@@ -25,6 +25,9 @@
|
||||
#include "libraries/glslang/glslang/Public/ShaderLang.h"
|
||||
#include "libraries/glslang/SPIRV/GlslangToSpv.h"
|
||||
#include "libraries/spirv_cross/spirv_msl.hpp"
|
||||
#include "libraries/spirv_cross/spirv_reflect.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace love
|
||||
{
|
||||
@@ -33,8 +36,62 @@ namespace graphics
|
||||
namespace metal
|
||||
{
|
||||
|
||||
static_assert(MAX_COLOR_RENDER_TARGETS <= 8, "Metal pipeline cache key only stores 8 render target pixel formats.");
|
||||
|
||||
static MTLVertexFormat getMTLVertexFormat(vertex::DataType type, int components)
|
||||
{
|
||||
// TODO
|
||||
return MTLVertexFormatFloat4;
|
||||
}
|
||||
|
||||
static MTLBlendOperation getMTLBlendOperation(BlendOperation op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case BLENDOP_ADD: return MTLBlendOperationAdd;
|
||||
case BLENDOP_SUBTRACT: return MTLBlendOperationSubtract;
|
||||
case BLENDOP_REVERSE_SUBTRACT: return MTLBlendOperationReverseSubtract;
|
||||
case BLENDOP_MIN: return MTLBlendOperationMin;
|
||||
case BLENDOP_MAX: return MTLBlendOperationMax;
|
||||
case BLENDOP_MAX_ENUM: return MTLBlendOperationAdd;
|
||||
}
|
||||
return MTLBlendOperationAdd;
|
||||
}
|
||||
|
||||
static MTLBlendFactor getMTLBlendFactor(BlendFactor factor)
|
||||
{
|
||||
switch (factor)
|
||||
{
|
||||
case BLENDFACTOR_ZERO: return MTLBlendFactorZero;
|
||||
case BLENDFACTOR_ONE: return MTLBlendFactorOne;
|
||||
case BLENDFACTOR_SRC_COLOR: return MTLBlendFactorSourceColor;
|
||||
case BLENDFACTOR_ONE_MINUS_SRC_COLOR: return MTLBlendFactorOneMinusSourceColor;
|
||||
case BLENDFACTOR_SRC_ALPHA: return MTLBlendFactorSourceAlpha;
|
||||
case BLENDFACTOR_ONE_MINUS_SRC_ALPHA: return MTLBlendFactorOneMinusSourceAlpha;
|
||||
case BLENDFACTOR_DST_COLOR: return MTLBlendFactorDestinationColor;
|
||||
case BLENDFACTOR_ONE_MINUS_DST_COLOR: return MTLBlendFactorOneMinusDestinationColor;
|
||||
case BLENDFACTOR_DST_ALPHA: return MTLBlendFactorDestinationAlpha;
|
||||
case BLENDFACTOR_ONE_MINUS_DST_ALPHA: return MTLBlendFactorOneMinusDestinationAlpha;
|
||||
case BLENDFACTOR_SRC_ALPHA_SATURATED: return MTLBlendFactorSourceAlphaSaturated;
|
||||
case BLENDFACTOR_MAX_ENUM: return MTLBlendFactorZero;
|
||||
}
|
||||
return MTLBlendFactorZero;
|
||||
}
|
||||
|
||||
static EShLanguage getGLSLangStage(ShaderStage::StageType stage)
|
||||
{
|
||||
switch (stage)
|
||||
{
|
||||
case ShaderStage::STAGE_VERTEX: return EShLangVertex;
|
||||
case ShaderStage::STAGE_PIXEL: return EShLangFragment;
|
||||
case ShaderStage::STAGE_MAX_ENUM: return EShLangCount;
|
||||
}
|
||||
return EShLangCount;
|
||||
}
|
||||
|
||||
Shader::Shader(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage *pixel)
|
||||
: love::graphics::Shader(vertex, pixel)
|
||||
, functions()
|
||||
{ @autoreleasepool {
|
||||
auto gfx = Graphics::getInstance();
|
||||
|
||||
@@ -54,11 +111,13 @@ Shader::Shader(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage
|
||||
if (!program.link(EShMsgDefault))
|
||||
{
|
||||
//err = "Cannot compile shader:\n\n" + std::string(program.getInfoLog()) + "\n" + std::string(program.getInfoDebugLog());
|
||||
throw love::Exception("link failed!\n");
|
||||
}
|
||||
|
||||
for (int i = 0; i < EShLangCount; i++)
|
||||
for (int i = 0; i < ShaderStage::STAGE_MAX_ENUM; i++)
|
||||
{
|
||||
auto intermediate = program.getIntermediate((EShLanguage)i);
|
||||
auto glslangstage = getGLSLangStage((ShaderStage::StageType) i);
|
||||
auto intermediate = program.getIntermediate(glslangstage);
|
||||
if (intermediate == nullptr)
|
||||
continue;
|
||||
|
||||
@@ -103,7 +162,13 @@ Shader::Shader(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage
|
||||
|
||||
NSError *err = nil;
|
||||
id<MTLLibrary> library = [gfx->device newLibraryWithSource:nssource options:nil error:&err];
|
||||
if (library == nil && err != nil)
|
||||
{
|
||||
NSLog(@"errors: %@", err);
|
||||
throw love::Exception("Error compiling converted Metal shader code");
|
||||
}
|
||||
|
||||
functions[i] = [library newFunctionWithName:library.functionNames[0]];
|
||||
}
|
||||
catch (std::exception &e)
|
||||
{
|
||||
@@ -114,9 +179,127 @@ Shader::Shader(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage
|
||||
|
||||
Shader::~Shader()
|
||||
{ @autoreleasepool {
|
||||
for (int i = 0; i < ShaderStage::STAGE_MAX_ENUM; i++)
|
||||
functions[i] = nil;
|
||||
|
||||
for (const auto &kvp : cachedRenderPipelines)
|
||||
CFBridgingRelease(kvp.second);
|
||||
|
||||
cachedRenderPipelines.clear();
|
||||
}}
|
||||
|
||||
void Shader::attach()
|
||||
{
|
||||
if (current != this)
|
||||
{
|
||||
Graphics::flushBatchedDrawsGlobal();
|
||||
current = this;
|
||||
}
|
||||
}
|
||||
|
||||
id<MTLRenderPipelineState> Shader::getCachedRenderPipeline(const RenderPipelineKey &key)
|
||||
{
|
||||
auto it = cachedRenderPipelines.find(key);
|
||||
|
||||
if (it != cachedRenderPipelines.end())
|
||||
return (__bridge id<MTLRenderPipelineState>) it->second;
|
||||
|
||||
id<MTLDevice> device = Graphics::getInstance()->device;
|
||||
|
||||
MTLRenderPipelineDescriptor *desc = [MTLRenderPipelineDescriptor new];
|
||||
|
||||
desc.vertexFunction = functions[ShaderStage::STAGE_VERTEX];
|
||||
desc.fragmentFunction = functions[ShaderStage::STAGE_PIXEL];
|
||||
|
||||
desc.rasterSampleCount = std::max((int) key.msaa, 1);
|
||||
|
||||
for (int i = 0; i < MAX_COLOR_RENDER_TARGETS; i++)
|
||||
{
|
||||
PixelFormat format = (PixelFormat)((key.colorRenderTargetFormats >> (i * 8)) & 0xFF);
|
||||
if (format == PIXELFORMAT_UNKNOWN)
|
||||
continue;
|
||||
|
||||
MTLRenderPipelineColorAttachmentDescriptor *attachment = desc.colorAttachments[i];
|
||||
|
||||
bool isSRGB = false;
|
||||
MTLPixelFormat metalformat = Metal::convertPixelFormat(format, isSRGB);
|
||||
|
||||
attachment.pixelFormat = metalformat;
|
||||
|
||||
if (key.blend.enable)
|
||||
{
|
||||
attachment.blendingEnabled = YES;
|
||||
attachment.sourceRGBBlendFactor = getMTLBlendFactor(key.blend.srcFactorRGB);
|
||||
attachment.destinationRGBBlendFactor = getMTLBlendFactor(key.blend.dstFactorRGB);
|
||||
attachment.rgbBlendOperation = getMTLBlendOperation(key.blend.operationRGB);
|
||||
attachment.sourceAlphaBlendFactor = getMTLBlendFactor(key.blend.srcFactorA);
|
||||
attachment.destinationAlphaBlendFactor = getMTLBlendFactor(key.blend.dstFactorA);
|
||||
attachment.alphaBlendOperation = getMTLBlendOperation(key.blend.operationA);
|
||||
}
|
||||
|
||||
MTLColorWriteMask writeMask = MTLColorWriteMaskNone;
|
||||
if (key.colorChannelMask.r)
|
||||
writeMask |= MTLColorWriteMaskRed;
|
||||
if (key.colorChannelMask.g)
|
||||
writeMask |= MTLColorWriteMaskGreen;
|
||||
if (key.colorChannelMask.b)
|
||||
writeMask |= MTLColorWriteMaskBlue;
|
||||
if (key.colorChannelMask.a)
|
||||
writeMask |= MTLColorWriteMaskAlpha;
|
||||
|
||||
attachment.writeMask = writeMask;
|
||||
|
||||
desc.colorAttachments[i] = attachment;
|
||||
}
|
||||
|
||||
{
|
||||
MTLVertexDescriptor *vertdesc = [MTLVertexDescriptor vertexDescriptor];
|
||||
|
||||
const auto &attributes = key.vertexAttributes;
|
||||
uint32 allbits = attributes.enableBits;
|
||||
uint32 i = 0;
|
||||
while (allbits)
|
||||
{
|
||||
uint32 bit = 1u << i;
|
||||
|
||||
if (attributes.enableBits & bit)
|
||||
{
|
||||
const auto &attrib = attributes.attribs[i];
|
||||
|
||||
vertdesc.attributes[i].format = getMTLVertexFormat(attrib.type, attrib.components);
|
||||
vertdesc.attributes[i].offset = attrib.offsetFromVertex;
|
||||
vertdesc.attributes[i].bufferIndex = attrib.bufferIndex;
|
||||
|
||||
const auto &layout = attributes.bufferLayouts[attrib.bufferIndex];
|
||||
|
||||
bool instanced = attributes.instanceBits & (1u << attrib.bufferIndex);
|
||||
auto step = instanced ? MTLVertexStepFunctionPerInstance : MTLVertexStepFunctionPerVertex;
|
||||
|
||||
vertdesc.layouts[attrib.bufferIndex].stride = layout.stride;
|
||||
vertdesc.layouts[attrib.bufferIndex].stepFunction = step;
|
||||
}
|
||||
|
||||
i++;
|
||||
allbits >>= 1;
|
||||
}
|
||||
|
||||
desc.vertexDescriptor = vertdesc;
|
||||
}
|
||||
|
||||
NSError *err = nil;
|
||||
id<MTLRenderPipelineState> pipeline = [device newRenderPipelineStateWithDescriptor:desc error:&err];
|
||||
|
||||
if (err != nil)
|
||||
{
|
||||
NSLog(@"Error creating render pipeline: %@", err);
|
||||
return nil;
|
||||
}
|
||||
|
||||
cachedRenderPipelines[key] = CFBridgingRetain(pipeline);
|
||||
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
} // metal
|
||||
} // graphics
|
||||
} // love
|
||||
|
||||
Reference in New Issue
Block a user