mirror of
https://github.com/love2d/love.git
synced 2026-08-17 19:23:38 +02:00
metal: initial shader texture binding implementation.
rework metal shader compilation/parsing.
This commit is contained in:
@@ -243,6 +243,7 @@ public:
|
|||||||
love::image::ImageData *newImageData(love::image::Image *module, int slice, int mipmap, const Rect &rect);
|
love::image::ImageData *newImageData(love::image::Image *module, int slice, int mipmap, const Rect &rect);
|
||||||
|
|
||||||
virtual ptrdiff_t getRenderTargetHandle() const = 0;
|
virtual ptrdiff_t getRenderTargetHandle() const = 0;
|
||||||
|
virtual ptrdiff_t getSamplerHandle() const = 0;
|
||||||
|
|
||||||
TextureType getTextureType() const;
|
TextureType getTextureType() const;
|
||||||
PixelFormat getPixelFormat() const;
|
PixelFormat getPixelFormat() const;
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ private:
|
|||||||
|
|
||||||
id<MTLDepthStencilState> getCachedDepthStencilState(const DepthState &depth, const StencilState &stencil);
|
id<MTLDepthStencilState> getCachedDepthStencilState(const DepthState &depth, const StencilState &stencil);
|
||||||
void applyRenderState(id<MTLRenderCommandEncoder> renderEncoder, const VertexAttributes &attributes);
|
void applyRenderState(id<MTLRenderCommandEncoder> renderEncoder, const VertexAttributes &attributes);
|
||||||
void applyShaderUniforms(id<MTLRenderCommandEncoder> renderEncoder, Shader *shader);
|
void applyShaderUniforms(id<MTLRenderCommandEncoder> renderEncoder, Shader *shader, Texture *maintex);
|
||||||
|
|
||||||
id<MTLCommandQueue> commandQueue;
|
id<MTLCommandQueue> commandQueue;
|
||||||
|
|
||||||
|
|||||||
@@ -130,6 +130,11 @@ static inline id<MTLTexture> getMTLTexture(love::graphics::Texture *tex)
|
|||||||
return tex ? (__bridge id<MTLTexture>)(void *) tex->getHandle() : nil;
|
return tex ? (__bridge id<MTLTexture>)(void *) tex->getHandle() : nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline id<MTLSamplerState> getMTLSampler(love::graphics::Texture *tex)
|
||||||
|
{
|
||||||
|
return tex ? (__bridge id<MTLSamplerState>)(void *) tex->getSamplerHandle() : nil;
|
||||||
|
}
|
||||||
|
|
||||||
static inline id<MTLTexture> getMTLRenderTarget(love::graphics::Texture *tex)
|
static inline id<MTLTexture> getMTLRenderTarget(love::graphics::Texture *tex)
|
||||||
{
|
{
|
||||||
return tex ? (__bridge id<MTLTexture>)(void *) tex->getRenderTargetHandle() : nil;
|
return tex ? (__bridge id<MTLTexture>)(void *) tex->getRenderTargetHandle() : nil;
|
||||||
@@ -688,7 +693,7 @@ void Graphics::applyRenderState(id<MTLRenderCommandEncoder> encoder, const Verte
|
|||||||
dirtyRenderState = 0;
|
dirtyRenderState = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::applyShaderUniforms(id<MTLRenderCommandEncoder> renderEncoder, love::graphics::Shader *shader)
|
void Graphics::applyShaderUniforms(id<MTLRenderCommandEncoder> renderEncoder, love::graphics::Shader *shader, love::graphics::Texture *maintex)
|
||||||
{
|
{
|
||||||
Shader *s = (Shader *)shader;
|
Shader *s = (Shader *)shader;
|
||||||
|
|
||||||
@@ -747,14 +752,47 @@ void Graphics::applyShaderUniforms(id<MTLRenderCommandEncoder> renderEncoder, lo
|
|||||||
memcpy(uniformBufferData.data + uniformBufferOffset, bufferdata, size);
|
memcpy(uniformBufferData.data + uniformBufferOffset, bufferdata, size);
|
||||||
|
|
||||||
id<MTLBuffer> buffer = getMTLBuffer(uniformBuffer);
|
id<MTLBuffer> buffer = getMTLBuffer(uniformBuffer);
|
||||||
int index = Shader::getUniformBufferBinding();
|
int uniformindex = Shader::getUniformBufferBinding();
|
||||||
|
|
||||||
// TODO: bind shader textures/samplers
|
[renderEncoder setVertexBuffer:buffer offset:uniformBufferOffset atIndex:uniformindex];
|
||||||
|
[renderEncoder setFragmentBuffer:buffer offset:uniformBufferOffset atIndex:uniformindex];
|
||||||
[renderEncoder setVertexBuffer:buffer offset:uniformBufferOffset atIndex:index];
|
|
||||||
[renderEncoder setFragmentBuffer:buffer offset:uniformBufferOffset atIndex:index];
|
|
||||||
|
|
||||||
uniformBufferOffset += alignUp(size, alignment);
|
uniformBufferOffset += alignUp(size, alignment);
|
||||||
|
|
||||||
|
for (const Shader::TextureBinding &b : s->getTextureBindings())
|
||||||
|
{
|
||||||
|
id<MTLTexture> texture = b.texture;
|
||||||
|
id<MTLSamplerState> sampler = b.sampler;
|
||||||
|
|
||||||
|
if (b.isMainTexture)
|
||||||
|
{
|
||||||
|
if (maintex == nullptr)
|
||||||
|
{
|
||||||
|
auto textype = shader->getMainTextureType();
|
||||||
|
if (textype != TEXTURE_MAX_ENUM)
|
||||||
|
maintex = defaultTextures[textype];
|
||||||
|
}
|
||||||
|
|
||||||
|
texture = getMTLTexture(maintex);
|
||||||
|
sampler = getMTLSampler(maintex);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8 texindex = b.texturestages[ShaderStage::STAGE_VERTEX];
|
||||||
|
uint8 sampindex = b.samplerstages[ShaderStage::STAGE_VERTEX];
|
||||||
|
|
||||||
|
if (texindex != LOVE_UINT8_MAX)
|
||||||
|
[renderEncoder setVertexTexture:texture atIndex:texindex];
|
||||||
|
if (sampindex != LOVE_UINT8_MAX)
|
||||||
|
[renderEncoder setVertexSamplerState:sampler atIndex:sampindex];
|
||||||
|
|
||||||
|
texindex = b.texturestages[ShaderStage::STAGE_PIXEL];
|
||||||
|
sampindex = b.samplerstages[ShaderStage::STAGE_PIXEL];
|
||||||
|
|
||||||
|
if (texindex != LOVE_UINT8_MAX)
|
||||||
|
[renderEncoder setFragmentTexture:texture atIndex:texindex];
|
||||||
|
if (sampindex != LOVE_UINT8_MAX)
|
||||||
|
[renderEncoder setFragmentSamplerState:sampler atIndex:sampindex];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setVertexBuffers(id<MTLRenderCommandEncoder> encoder, const BufferBindings *buffers)
|
static void setVertexBuffers(id<MTLRenderCommandEncoder> encoder, const BufferBindings *buffers)
|
||||||
@@ -782,16 +820,7 @@ void Graphics::draw(const DrawCommand &cmd)
|
|||||||
id<MTLRenderCommandEncoder> encoder = useRenderEncoder();
|
id<MTLRenderCommandEncoder> encoder = useRenderEncoder();
|
||||||
|
|
||||||
applyRenderState(encoder, *cmd.attributes);
|
applyRenderState(encoder, *cmd.attributes);
|
||||||
applyShaderUniforms(encoder, Shader::current);
|
applyShaderUniforms(encoder, Shader::current, cmd.texture);
|
||||||
|
|
||||||
love::graphics::Texture *texture = cmd.texture;
|
|
||||||
if (texture == nullptr)
|
|
||||||
texture = defaultTextures[TEXTURE_2D];
|
|
||||||
|
|
||||||
id<MTLTexture> mtltexture = getMTLTexture(texture);
|
|
||||||
|
|
||||||
[encoder setFragmentTexture:mtltexture atIndex:0];
|
|
||||||
[encoder setFragmentSamplerState:((Texture *)texture)->getMTLSampler() atIndex:0];
|
|
||||||
|
|
||||||
[encoder setCullMode:MTLCullModeNone];
|
[encoder setCullMode:MTLCullModeNone];
|
||||||
|
|
||||||
@@ -808,16 +837,7 @@ void Graphics::draw(const DrawIndexedCommand &cmd)
|
|||||||
id<MTLRenderCommandEncoder> encoder = useRenderEncoder();
|
id<MTLRenderCommandEncoder> encoder = useRenderEncoder();
|
||||||
|
|
||||||
applyRenderState(encoder, *cmd.attributes);
|
applyRenderState(encoder, *cmd.attributes);
|
||||||
applyShaderUniforms(encoder, Shader::current);
|
applyShaderUniforms(encoder, Shader::current, cmd.texture);
|
||||||
|
|
||||||
love::graphics::Texture *texture = cmd.texture;
|
|
||||||
if (texture == nullptr)
|
|
||||||
texture = defaultTextures[TEXTURE_2D];
|
|
||||||
|
|
||||||
id<MTLTexture> mtltexture = getMTLTexture(texture);
|
|
||||||
|
|
||||||
[encoder setFragmentTexture:mtltexture atIndex:0];
|
|
||||||
[encoder setFragmentSamplerState:((Texture *)texture)->getMTLSampler() atIndex:0];
|
|
||||||
|
|
||||||
[encoder setCullMode:MTLCullModeNone];
|
[encoder setCullMode:MTLCullModeNone];
|
||||||
|
|
||||||
@@ -841,15 +861,7 @@ void Graphics::drawQuads(int start, int count, const VertexAttributes &attribute
|
|||||||
id<MTLRenderCommandEncoder> encoder = useRenderEncoder();
|
id<MTLRenderCommandEncoder> encoder = useRenderEncoder();
|
||||||
|
|
||||||
applyRenderState(encoder, attributes);
|
applyRenderState(encoder, attributes);
|
||||||
applyShaderUniforms(encoder, Shader::current);
|
applyShaderUniforms(encoder, Shader::current, texture);
|
||||||
|
|
||||||
if (texture == nullptr)
|
|
||||||
texture = defaultTextures[TEXTURE_2D];
|
|
||||||
|
|
||||||
id<MTLTexture> mtltexture = getMTLTexture(texture);
|
|
||||||
|
|
||||||
[encoder setFragmentTexture:mtltexture atIndex:0];
|
|
||||||
[encoder setFragmentSamplerState:((Texture *)texture)->getMTLSampler() atIndex:0];
|
|
||||||
|
|
||||||
[encoder setCullMode:MTLCullModeNone];
|
[encoder setCullMode:MTLCullModeNone];
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "libraries/xxHash/xxhash.h"
|
#include "libraries/xxHash/xxhash.h"
|
||||||
|
#include "common/int.h"
|
||||||
#include "graphics/Shader.h"
|
#include "graphics/Shader.h"
|
||||||
#include "graphics/Graphics.h"
|
#include "graphics/Graphics.h"
|
||||||
#include "graphics/renderstate.h"
|
#include "graphics/renderstate.h"
|
||||||
@@ -33,6 +34,11 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
namespace glslang
|
||||||
|
{
|
||||||
|
class TProgram;
|
||||||
|
}
|
||||||
|
|
||||||
namespace love
|
namespace love
|
||||||
{
|
{
|
||||||
namespace graphics
|
namespace graphics
|
||||||
@@ -67,6 +73,17 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TextureBinding
|
||||||
|
{
|
||||||
|
id<MTLTexture> texture;
|
||||||
|
id<MTLSamplerState> sampler;
|
||||||
|
|
||||||
|
bool isMainTexture;
|
||||||
|
|
||||||
|
uint8 texturestages[ShaderStage::STAGE_MAX_ENUM];
|
||||||
|
uint8 samplerstages[ShaderStage::STAGE_MAX_ENUM];
|
||||||
|
};
|
||||||
|
|
||||||
Shader(id<MTLDevice> device, love::graphics::ShaderStage *vertex, love::graphics::ShaderStage *pixel);
|
Shader(id<MTLDevice> device, love::graphics::ShaderStage *vertex, love::graphics::ShaderStage *pixel);
|
||||||
virtual ~Shader();
|
virtual ~Shader();
|
||||||
|
|
||||||
@@ -86,6 +103,7 @@ public:
|
|||||||
id<MTLRenderPipelineState> getCachedRenderPipeline(const RenderPipelineKey &key);
|
id<MTLRenderPipelineState> getCachedRenderPipeline(const RenderPipelineKey &key);
|
||||||
|
|
||||||
static int getUniformBufferBinding();
|
static int getUniformBufferBinding();
|
||||||
|
const std::vector<TextureBinding> &getTextureBindings() const { return textureBindings; }
|
||||||
|
|
||||||
uint8 *getLocalUniformBufferData() { return localUniformBufferData; }
|
uint8 *getLocalUniformBufferData() { return localUniformBufferData; }
|
||||||
size_t getLocalUniformBufferSize() const { return localUniformBufferSize; }
|
size_t getLocalUniformBufferSize() const { return localUniformBufferSize; }
|
||||||
@@ -101,6 +119,8 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void compileFromGLSLang(id<MTLDevice> device, const glslang::TProgram &program);
|
||||||
|
|
||||||
id<MTLFunction> functions[ShaderStage::STAGE_MAX_ENUM];
|
id<MTLFunction> functions[ShaderStage::STAGE_MAX_ENUM];
|
||||||
|
|
||||||
UniformInfo *builtinUniformInfo[BUILTIN_MAX_ENUM];
|
UniformInfo *builtinUniformInfo[BUILTIN_MAX_ENUM];
|
||||||
@@ -112,6 +132,8 @@ private:
|
|||||||
|
|
||||||
std::map<std::string, int> attributes;
|
std::map<std::string, int> attributes;
|
||||||
|
|
||||||
|
std::vector<TextureBinding> textureBindings;
|
||||||
|
|
||||||
std::unordered_map<RenderPipelineKey, const void *, RenderPipelineHasher> cachedRenderPipelines;
|
std::unordered_map<RenderPipelineKey, const void *, RenderPipelineHasher> cachedRenderPipelines;
|
||||||
|
|
||||||
}; // Metal
|
}; // Metal
|
||||||
|
|||||||
@@ -39,6 +39,114 @@ namespace metal
|
|||||||
|
|
||||||
static_assert(MAX_COLOR_RENDER_TARGETS <= 8, "Metal pipeline cache key only stores 8 render target pixel formats.");
|
static_assert(MAX_COLOR_RENDER_TARGETS <= 8, "Metal pipeline cache key only stores 8 render target pixel formats.");
|
||||||
|
|
||||||
|
// TODO: Use love.graphics to determine actual limits?
|
||||||
|
static const TBuiltInResource defaultTBuiltInResource = {
|
||||||
|
/* .MaxLights = */ 32,
|
||||||
|
/* .MaxClipPlanes = */ 6,
|
||||||
|
/* .MaxTextureUnits = */ 32,
|
||||||
|
/* .MaxTextureCoords = */ 32,
|
||||||
|
/* .MaxVertexAttribs = */ 64,
|
||||||
|
/* .MaxVertexUniformComponents = */ 16384,
|
||||||
|
/* .MaxVaryingFloats = */ 128,
|
||||||
|
/* .MaxVertexTextureImageUnits = */ 32,
|
||||||
|
/* .MaxCombinedTextureImageUnits = */ 80,
|
||||||
|
/* .MaxTextureImageUnits = */ 32,
|
||||||
|
/* .MaxFragmentUniformComponents = */ 16384,
|
||||||
|
/* .MaxDrawBuffers = */ 8,
|
||||||
|
/* .MaxVertexUniformVectors = */ 4096,
|
||||||
|
/* .MaxVaryingVectors = */ 32,
|
||||||
|
/* .MaxFragmentUniformVectors = */ 4096,
|
||||||
|
/* .MaxVertexOutputVectors = */ 32,
|
||||||
|
/* .MaxFragmentInputVectors = */ 31,
|
||||||
|
/* .MinProgramTexelOffset = */ -8,
|
||||||
|
/* .MaxProgramTexelOffset = */ 7,
|
||||||
|
/* .MaxClipDistances = */ 8,
|
||||||
|
/* .MaxComputeWorkGroupCountX = */ 65535,
|
||||||
|
/* .MaxComputeWorkGroupCountY = */ 65535,
|
||||||
|
/* .MaxComputeWorkGroupCountZ = */ 65535,
|
||||||
|
/* .MaxComputeWorkGroupSizeX = */ 1024,
|
||||||
|
/* .MaxComputeWorkGroupSizeY = */ 1024,
|
||||||
|
/* .MaxComputeWorkGroupSizeZ = */ 64,
|
||||||
|
/* .MaxComputeUniformComponents = */ 1024,
|
||||||
|
/* .MaxComputeTextureImageUnits = */ 32,
|
||||||
|
/* .MaxComputeImageUniforms = */ 16,
|
||||||
|
/* .MaxComputeAtomicCounters = */ 4096,
|
||||||
|
/* .MaxComputeAtomicCounterBuffers = */ 8,
|
||||||
|
/* .MaxVaryingComponents = */ 128,
|
||||||
|
/* .MaxVertexOutputComponents = */ 128,
|
||||||
|
/* .MaxGeometryInputComponents = */ 128,
|
||||||
|
/* .MaxGeometryOutputComponents = */ 128,
|
||||||
|
/* .MaxFragmentInputComponents = */ 128,
|
||||||
|
/* .MaxImageUnits = */ 192,
|
||||||
|
/* .MaxCombinedImageUnitsAndFragmentOutputs = */ 144,
|
||||||
|
/* .MaxCombinedShaderOutputResources = */ 144,
|
||||||
|
/* .MaxImageSamples = */ 32,
|
||||||
|
/* .MaxVertexImageUniforms = */ 16,
|
||||||
|
/* .MaxTessControlImageUniforms = */ 16,
|
||||||
|
/* .MaxTessEvaluationImageUniforms = */ 16,
|
||||||
|
/* .MaxGeometryImageUniforms = */ 16,
|
||||||
|
/* .MaxFragmentImageUniforms = */ 16,
|
||||||
|
/* .MaxCombinedImageUniforms = */ 80,
|
||||||
|
/* .MaxGeometryTextureImageUnits = */ 16,
|
||||||
|
/* .MaxGeometryOutputVertices = */ 256,
|
||||||
|
/* .MaxGeometryTotalOutputComponents = */ 1024,
|
||||||
|
/* .MaxGeometryUniformComponents = */ 1024,
|
||||||
|
/* .MaxGeometryVaryingComponents = */ 64,
|
||||||
|
/* .MaxTessControlInputComponents = */ 128,
|
||||||
|
/* .MaxTessControlOutputComponents = */ 128,
|
||||||
|
/* .MaxTessControlTextureImageUnits = */ 16,
|
||||||
|
/* .MaxTessControlUniformComponents = */ 1024,
|
||||||
|
/* .MaxTessControlTotalOutputComponents = */ 4096,
|
||||||
|
/* .MaxTessEvaluationInputComponents = */ 128,
|
||||||
|
/* .MaxTessEvaluationOutputComponents = */ 128,
|
||||||
|
/* .MaxTessEvaluationTextureImageUnits = */ 16,
|
||||||
|
/* .MaxTessEvaluationUniformComponents = */ 1024,
|
||||||
|
/* .MaxTessPatchComponents = */ 120,
|
||||||
|
/* .MaxPatchVertices = */ 32,
|
||||||
|
/* .MaxTessGenLevel = */ 64,
|
||||||
|
/* .MaxViewports = */ 16,
|
||||||
|
/* .MaxVertexAtomicCounters = */ 4096,
|
||||||
|
/* .MaxTessControlAtomicCounters = */ 4096,
|
||||||
|
/* .MaxTessEvaluationAtomicCounters = */ 4096,
|
||||||
|
/* .MaxGeometryAtomicCounters = */ 4096,
|
||||||
|
/* .MaxFragmentAtomicCounters = */ 4096,
|
||||||
|
/* .MaxCombinedAtomicCounters = */ 4096,
|
||||||
|
/* .MaxAtomicCounterBindings = */ 8,
|
||||||
|
/* .MaxVertexAtomicCounterBuffers = */ 8,
|
||||||
|
/* .MaxTessControlAtomicCounterBuffers = */ 8,
|
||||||
|
/* .MaxTessEvaluationAtomicCounterBuffers = */ 8,
|
||||||
|
/* .MaxGeometryAtomicCounterBuffers = */ 8,
|
||||||
|
/* .MaxFragmentAtomicCounterBuffers = */ 8,
|
||||||
|
/* .MaxCombinedAtomicCounterBuffers = */ 8,
|
||||||
|
/* .MaxAtomicCounterBufferSize = */ 16384,
|
||||||
|
/* .MaxTransformFeedbackBuffers = */ 4,
|
||||||
|
/* .MaxTransformFeedbackInterleavedComponents = */ 64,
|
||||||
|
/* .MaxCullDistances = */ 8,
|
||||||
|
/* .MaxCombinedClipAndCullDistances = */ 8,
|
||||||
|
/* .MaxSamples = */ 32,
|
||||||
|
/* .maxMeshOutputVerticesNV = */ 256,
|
||||||
|
/* .maxMeshOutputPrimitivesNV = */ 512,
|
||||||
|
/* .maxMeshWorkGroupSizeX_NV = */ 32,
|
||||||
|
/* .maxMeshWorkGroupSizeY_NV = */ 1,
|
||||||
|
/* .maxMeshWorkGroupSizeZ_NV = */ 1,
|
||||||
|
/* .maxTaskWorkGroupSizeX_NV = */ 32,
|
||||||
|
/* .maxTaskWorkGroupSizeY_NV = */ 1,
|
||||||
|
/* .maxTaskWorkGroupSizeZ_NV = */ 1,
|
||||||
|
/* .maxMeshViewCountNV = */ 4,
|
||||||
|
/* .maxDualSourceDrawBuffersEXT = */ 1,
|
||||||
|
/* .limits = */ {
|
||||||
|
/* .nonInductiveForLoops = */ 1,
|
||||||
|
/* .whileLoops = */ 1,
|
||||||
|
/* .doWhileLoops = */ 1,
|
||||||
|
/* .generalUniformIndexing = */ 1,
|
||||||
|
/* .generalAttributeMatrixVectorIndexing = */ 1,
|
||||||
|
/* .generalVaryingIndexing = */ 1,
|
||||||
|
/* .generalSamplerIndexing = */ 1,
|
||||||
|
/* .generalVariableIndexing = */ 1,
|
||||||
|
/* .generalConstantMatrixVectorIndexing = */ 1,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static MTLVertexFormat getMTLVertexFormat(DataFormat format)
|
static MTLVertexFormat getMTLVertexFormat(DataFormat format)
|
||||||
{
|
{
|
||||||
switch (format)
|
switch (format)
|
||||||
@@ -114,6 +222,16 @@ static MTLBlendFactor getMTLBlendFactor(BlendFactor factor)
|
|||||||
return MTLBlendFactorZero;
|
return MTLBlendFactorZero;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline id<MTLTexture> getMTLTexture(love::graphics::Texture *tex)
|
||||||
|
{
|
||||||
|
return tex ? (__bridge id<MTLTexture>)(void *) tex->getHandle() : nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline id<MTLSamplerState> getMTLSampler(love::graphics::Texture *tex)
|
||||||
|
{
|
||||||
|
return tex ? (__bridge id<MTLSamplerState>)(void *) tex->getSamplerHandle() : nil;
|
||||||
|
}
|
||||||
|
|
||||||
static EShLanguage getGLSLangStage(ShaderStage::StageType stage)
|
static EShLanguage getGLSLangStage(ShaderStage::StageType stage)
|
||||||
{
|
{
|
||||||
switch (stage)
|
switch (stage)
|
||||||
@@ -134,30 +252,107 @@ Shader::Shader(id<MTLDevice> device, love::graphics::ShaderStage *vertex, love::
|
|||||||
, builtinUniformDataOffset(0)
|
, builtinUniformDataOffset(0)
|
||||||
{ @autoreleasepool {
|
{ @autoreleasepool {
|
||||||
using namespace glslang;
|
using namespace glslang;
|
||||||
using namespace spirv_cross;
|
|
||||||
|
|
||||||
// TODO: can this be done in ShaderStage (no linking)?
|
TShader *glslangShaders[ShaderStage::STAGE_MAX_ENUM] = {};
|
||||||
|
|
||||||
glslang::TProgram program;
|
TProgram *program = new TProgram();
|
||||||
|
|
||||||
if (vertex != nullptr)
|
auto cleanup = [&]()
|
||||||
program.addShader((TShader *) vertex->getHandle());
|
|
||||||
|
|
||||||
if (pixel != nullptr)
|
|
||||||
program.addShader((TShader *) pixel->getHandle());
|
|
||||||
|
|
||||||
if (!program.link(EShMsgDefault))
|
|
||||||
{
|
{
|
||||||
//err = "Cannot compile shader:\n\n" + std::string(program.getInfoLog()) + "\n" + std::string(program.getInfoDebugLog());
|
delete program;
|
||||||
throw love::Exception("link failed!\n");
|
for (int i = 0; i < ShaderStage::STAGE_MAX_ENUM; i++)
|
||||||
|
delete glslangShaders[i];
|
||||||
|
};
|
||||||
|
|
||||||
|
// We can't do this in ShaderStage because the mapIO call modifies the
|
||||||
|
// TShader internals in a manner that prevents it from being shared.
|
||||||
|
for (int i = 0; i < ShaderStage::STAGE_MAX_ENUM; i++)
|
||||||
|
{
|
||||||
|
if (!stages[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto stage = (ShaderStage::StageType) i;
|
||||||
|
auto glslangstage = getGLSLangStage(stage);
|
||||||
|
auto tshader = new TShader(glslangstage);
|
||||||
|
|
||||||
|
glslangShaders[i] = tshader;
|
||||||
|
|
||||||
|
tshader->setEnvInput(EShSourceGlsl, glslangstage, EShClientVulkan, 450);
|
||||||
|
tshader->setEnvClient(EShClientVulkan, EShTargetVulkan_1_2);
|
||||||
|
tshader->setEnvTarget(EShTargetSpv, EShTargetSpv_1_5);
|
||||||
|
tshader->setAutoMapLocations(true);
|
||||||
|
tshader->setAutoMapBindings(true);
|
||||||
|
|
||||||
|
// Needed for local uniforms to work (they will be converted into a
|
||||||
|
// uniform block).
|
||||||
|
// https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GL_EXT_vulkan_glsl_relaxed.txt
|
||||||
|
tshader->setEnvInputVulkanRulesRelaxed();
|
||||||
|
tshader->setGlobalUniformBinding(0);
|
||||||
|
tshader->setGlobalUniformSet(0);
|
||||||
|
|
||||||
|
const std::string &source = stages[i]->getSource();
|
||||||
|
const char *csrc = source.c_str();
|
||||||
|
int srclen = (int) source.length();
|
||||||
|
tshader->setStringsWithLengths(&csrc, &srclen, 1);
|
||||||
|
|
||||||
|
int defaultversion = 450;
|
||||||
|
EProfile defaultprofile = ECoreProfile;
|
||||||
|
bool forcedefault = false;
|
||||||
|
bool forwardcompat = true;
|
||||||
|
|
||||||
|
if (!tshader->parse(&defaultTBuiltInResource, defaultversion, defaultprofile, forcedefault, forwardcompat, EShMsgSuppressWarnings))
|
||||||
|
{
|
||||||
|
const char *stagename = "unknown";
|
||||||
|
ShaderStage::getConstant(stage, stagename);
|
||||||
|
|
||||||
|
std::string err = "Error parsing " + std::string(stagename) + " shader:\n\n"
|
||||||
|
+ std::string(tshader->getInfoLog()) + "\n"
|
||||||
|
+ std::string(tshader->getInfoDebugLog());
|
||||||
|
|
||||||
|
cleanup();
|
||||||
|
throw love::Exception("%s", err.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
program->addShader(tshader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!program->link(EShMsgDefault))
|
||||||
|
{
|
||||||
|
//err = "Cannot compile shader:\n\n" + std::string(program->getInfoLog()) + "\n" + std::string(program->getInfoDebugLog());
|
||||||
|
cleanup();
|
||||||
|
throw love::Exception("link failed! %s\n", program->getInfoLog());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!program->mapIO())
|
||||||
|
{
|
||||||
|
cleanup();
|
||||||
|
throw love::Exception("mapIO failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
compileFromGLSLang(device, *program);
|
||||||
|
}
|
||||||
|
catch (love::Exception &)
|
||||||
|
{
|
||||||
|
cleanup();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup();
|
||||||
|
}}
|
||||||
|
|
||||||
|
void Shader::compileFromGLSLang(id<MTLDevice> device, const glslang::TProgram &program)
|
||||||
|
{
|
||||||
|
using namespace glslang;
|
||||||
|
using namespace spirv_cross;
|
||||||
|
|
||||||
std::map<std::string, int> varyings;
|
std::map<std::string, int> varyings;
|
||||||
int nextVaryingLocation = 0;
|
int nextVaryingLocation = 0;
|
||||||
|
|
||||||
for (int i = 0; i < ShaderStage::STAGE_MAX_ENUM; i++)
|
for (int stageindex = 0; stageindex < ShaderStage::STAGE_MAX_ENUM; stageindex++)
|
||||||
{
|
{
|
||||||
auto glslangstage = getGLSLangStage((ShaderStage::StageType) i);
|
auto glslangstage = getGLSLangStage((ShaderStage::StageType) stageindex);
|
||||||
auto intermediate = program.getIntermediate(glslangstage);
|
auto intermediate = program.getIntermediate(glslangstage);
|
||||||
if (intermediate == nullptr)
|
if (intermediate == nullptr)
|
||||||
continue;
|
continue;
|
||||||
@@ -186,44 +381,41 @@ Shader::Shader(id<MTLDevice> device, love::graphics::ShaderStage *vertex, love::
|
|||||||
|
|
||||||
for (const auto &resource : resources.sampled_images)
|
for (const auto &resource : resources.sampled_images)
|
||||||
{
|
{
|
||||||
// TODO: set MainTex to binding 0
|
const SPIRType &basetype = msl.get_type(resource.base_type_id);
|
||||||
int binding = msl.get_decoration(resource.id, spv::DecorationBinding);
|
const SPIRType &type = msl.get_type(resource.type_id);
|
||||||
const SPIRType &type = msl.get_type(resource.base_type_id);
|
|
||||||
|
|
||||||
auto it = uniforms.find(resource.name);
|
|
||||||
if (it != uniforms.end())
|
|
||||||
{
|
|
||||||
if (it->second.ints[0] != binding)
|
|
||||||
throw love::Exception("texture binding mismatch for %s: %d vs %d", resource.name.c_str(), it->second.ints[0], binding);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
UniformInfo u = {};
|
UniformInfo u = {};
|
||||||
u.baseType = UNIFORM_SAMPLER;
|
u.baseType = UNIFORM_SAMPLER;
|
||||||
u.name = resource.name;
|
u.name = resource.name;
|
||||||
|
u.count = type.array.empty() ? 1 : type.array[0];
|
||||||
u.location = 0;
|
u.location = 0;
|
||||||
u.data = malloc(sizeof(int) * 1);
|
u.data = malloc(sizeof(int) * u.count);
|
||||||
u.ints[0] = binding;
|
for (int i = 0; i < u.count; i++)
|
||||||
// printf("binding for %s: %d\n", u.name.c_str(), binding);
|
u.ints[i] = -1; // Will initialize below.
|
||||||
|
|
||||||
switch (type.image.dim)
|
// printf("%s binding: %d, set: %d\n", u.name.c_str(), msl.get_decoration(resource.id, spv::DecorationBinding), msl.get_decoration(resource.id, spv::DecorationDescriptorSet));
|
||||||
|
|
||||||
|
switch (basetype.image.dim)
|
||||||
{
|
{
|
||||||
case spv::Dim2D:
|
case spv::Dim2D:
|
||||||
u.textureType = type.image.arrayed ? TEXTURE_2D_ARRAY : TEXTURE_2D;
|
u.textureType = basetype.image.arrayed ? TEXTURE_2D_ARRAY : TEXTURE_2D;
|
||||||
u.textures = new love::graphics::Texture*[1];
|
u.textures = new love::graphics::Texture*[u.count];
|
||||||
u.textures[0] = nullptr;
|
for (int i = 0; i < u.count; i++)
|
||||||
|
u.textures[i] = nullptr;
|
||||||
break;
|
break;
|
||||||
case spv::Dim3D:
|
case spv::Dim3D:
|
||||||
u.textureType = TEXTURE_VOLUME;
|
u.textureType = TEXTURE_VOLUME;
|
||||||
u.textures = new love::graphics::Texture*[1];
|
u.textures = new love::graphics::Texture*[u.count];
|
||||||
u.textures[0] = nullptr;
|
for (int i = 0; i < u.count; i++)
|
||||||
|
u.textures[i] = nullptr;
|
||||||
break;
|
break;
|
||||||
case spv::DimCube:
|
case spv::DimCube:
|
||||||
if (type.image.arrayed)
|
if (basetype.image.arrayed)
|
||||||
throw love::Exception("Cubemap Arrays are not currently supported.");
|
throw love::Exception("Cubemap Arrays are not currently supported.");
|
||||||
u.textureType = TEXTURE_CUBE;
|
u.textureType = TEXTURE_CUBE;
|
||||||
u.textures = new love::graphics::Texture*[1];
|
u.textures = new love::graphics::Texture*[u.count];
|
||||||
u.textures[0] = nullptr;
|
for (int i = 0; i < u.count; i++)
|
||||||
|
u.textures[i] = nullptr;
|
||||||
break;
|
break;
|
||||||
case spv::DimBuffer:
|
case spv::DimBuffer:
|
||||||
// TODO: are texel buffers sampled images in glslang?
|
// TODO: are texel buffers sampled images in glslang?
|
||||||
@@ -234,22 +426,22 @@ Shader::Shader(id<MTLDevice> device, love::graphics::ShaderStage *vertex, love::
|
|||||||
|
|
||||||
uniforms[u.name] = u;
|
uniforms[u.name] = u;
|
||||||
|
|
||||||
BuiltinUniform builtin = BUILTIN_MAX_ENUM;
|
BuiltinUniform builtin;
|
||||||
if (getConstant(resource.name.c_str(), builtin))
|
if (getConstant(resource.name.c_str(), builtin))
|
||||||
builtinUniformInfo[builtin] = &uniforms[u.name];
|
builtinUniformInfo[builtin] = &uniforms[u.name];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &resource : resources.uniform_buffers)
|
for (const auto &resource : resources.uniform_buffers)
|
||||||
{
|
{
|
||||||
auto it = uniforms.find(resource.name);
|
|
||||||
if (it != uniforms.end())
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resource.name == "gl_DefaultUniformBlock")
|
if (resource.name == "gl_DefaultUniformBlock")
|
||||||
{
|
{
|
||||||
msl.set_decoration(resource.id, spv::DecorationBinding, 0);
|
MSLResourceBinding binding;
|
||||||
|
binding.stage = msl.get_execution_model();
|
||||||
|
binding.binding = msl.get_decoration(resource.id, spv::DecorationBinding);
|
||||||
|
binding.desc_set = msl.get_decoration(resource.id, spv::DecorationDescriptorSet);
|
||||||
|
binding.msl_buffer = getUniformBufferBinding();
|
||||||
|
msl.add_msl_resource_binding(binding);
|
||||||
|
|
||||||
const SPIRType &type = msl.get_type(resource.base_type_id);
|
const SPIRType &type = msl.get_type(resource.base_type_id);
|
||||||
const auto &membertypes = type.member_types;
|
const auto &membertypes = type.member_types;
|
||||||
|
|
||||||
@@ -276,7 +468,7 @@ Shader::Shader(id<MTLDevice> device, love::graphics::ShaderStage *vertex, love::
|
|||||||
UniformInfo u = {};
|
UniformInfo u = {};
|
||||||
u.name = msl.get_name(membertypes[uindex]);
|
u.name = msl.get_name(membertypes[uindex]);
|
||||||
u.dataSize = membersize;
|
u.dataSize = membersize;
|
||||||
u.count = std::max<size_t>(1, membertype.array.size());
|
u.count = membertype.array.empty() ? 1 : membertype.array[0];
|
||||||
|
|
||||||
switch (membertype.basetype)
|
switch (membertype.basetype)
|
||||||
{
|
{
|
||||||
@@ -333,7 +525,7 @@ Shader::Shader(id<MTLDevice> device, love::graphics::ShaderStage *vertex, love::
|
|||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == ShaderStage::STAGE_VERTEX)
|
if (stageindex == ShaderStage::STAGE_VERTEX)
|
||||||
{
|
{
|
||||||
int nextattributeindex = ATTRIB_MAX_ENUM;
|
int nextattributeindex = ATTRIB_MAX_ENUM;
|
||||||
|
|
||||||
@@ -353,7 +545,6 @@ Shader::Shader(id<MTLDevice> device, love::graphics::ShaderStage *vertex, love::
|
|||||||
index = nextattributeindex++;
|
index = nextattributeindex++;
|
||||||
|
|
||||||
msl.set_decoration(var, spv::DecorationLocation, index);
|
msl.set_decoration(var, spv::DecorationLocation, index);
|
||||||
|
|
||||||
attributes[name] = msl.get_decoration(var, spv::DecorationLocation);
|
attributes[name] = msl.get_decoration(var, spv::DecorationLocation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -365,7 +556,7 @@ Shader::Shader(id<MTLDevice> device, love::graphics::ShaderStage *vertex, love::
|
|||||||
msl.set_decoration(varying.id, spv::DecorationLocation, nextVaryingLocation++);
|
msl.set_decoration(varying.id, spv::DecorationLocation, nextVaryingLocation++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (i == ShaderStage::STAGE_PIXEL)
|
else if (stageindex == ShaderStage::STAGE_PIXEL)
|
||||||
{
|
{
|
||||||
for (const auto &varying : resources.stage_inputs)
|
for (const auto &varying : resources.stage_inputs)
|
||||||
{
|
{
|
||||||
@@ -375,12 +566,11 @@ Shader::Shader(id<MTLDevice> device, love::graphics::ShaderStage *vertex, love::
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("// ubos: %ld, storage: %ld, inputs: %ld, outputs: %ld, images: %ld, samplers: %ld, push: %ld\n", resources.uniform_buffers.size(), resources.storage_buffers.size(), resources.stage_inputs.size(), resources.stage_outputs.size(), resources.storage_images.size(), resources.sampled_images.size(), resources.push_constant_buffers.size());
|
// printf("// ubos: %ld, storage: %ld, inputs: %ld, outputs: %ld, images: %ld, samplers: %ld, push: %ld\n", resources.uniform_buffers.size(), resources.storage_buffers.size(), resources.stage_inputs.size(), resources.stage_outputs.size(), resources.storage_images.size(), resources.sampled_images.size(), resources.push_constant_buffers.size());
|
||||||
|
|
||||||
CompilerMSL::Options options;
|
CompilerMSL::Options options;
|
||||||
|
|
||||||
options.set_msl_version(2, 1);
|
options.set_msl_version(2, 1);
|
||||||
|
|
||||||
options.texture_buffer_native = true;
|
options.texture_buffer_native = true;
|
||||||
|
|
||||||
#ifdef LOVE_IOS
|
#ifdef LOVE_IOS
|
||||||
@@ -406,14 +596,56 @@ Shader::Shader(id<MTLDevice> device, love::graphics::ShaderStage *vertex, love::
|
|||||||
throw love::Exception("Error compiling converted Metal shader code");
|
throw love::Exception("Error compiling converted Metal shader code");
|
||||||
}
|
}
|
||||||
|
|
||||||
functions[i] = [library newFunctionWithName:library.functionNames[0]];
|
functions[stageindex] = [library newFunctionWithName:library.functionNames[0]];
|
||||||
|
|
||||||
|
for (const auto &resource : resources.sampled_images)
|
||||||
|
{
|
||||||
|
auto it = uniforms.find(resource.name);
|
||||||
|
if (it == uniforms.end())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
UniformInfo &u = it->second;
|
||||||
|
|
||||||
|
uint32 texturebinding = msl.get_automatic_msl_resource_binding(resource.id);
|
||||||
|
uint32 samplerbinding = msl.get_automatic_msl_resource_binding_secondary(resource.id);
|
||||||
|
|
||||||
|
if (texturebinding == (uint32)-1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (int i = 0; i < u.count; i++)
|
||||||
|
{
|
||||||
|
if (u.ints[i] == -1)
|
||||||
|
{
|
||||||
|
u.ints[i] = (int)textureBindings.size();
|
||||||
|
TextureBinding b = {};
|
||||||
|
|
||||||
|
b.texture = nil; // TODO: matching default texture
|
||||||
|
b.sampler = nil;
|
||||||
|
|
||||||
|
BuiltinUniform builtin = BUILTIN_MAX_ENUM;
|
||||||
|
if (getConstant(u.name.c_str(), builtin) && builtin == BUILTIN_TEXTURE_MAIN)
|
||||||
|
b.isMainTexture = true;
|
||||||
|
|
||||||
|
for (uint8 &stagebinding : b.texturestages)
|
||||||
|
stagebinding = LOVE_UINT8_MAX;
|
||||||
|
for (uint8 &stagebinding : b.samplerstages)
|
||||||
|
stagebinding = LOVE_UINT8_MAX;
|
||||||
|
|
||||||
|
textureBindings.push_back(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &b = textureBindings[u.ints[i]];
|
||||||
|
b.texturestages[stageindex] = (uint8) texturebinding;
|
||||||
|
b.samplerstages[stageindex] = (uint8) samplerbinding;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception &e)
|
catch (std::exception &e)
|
||||||
{
|
{
|
||||||
printf("Error parsing SPIR-V shader source: %s\n", e.what());
|
printf("Error parsing SPIR-V shader source: %s\n", e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}}
|
}
|
||||||
|
|
||||||
Shader::~Shader()
|
Shader::~Shader()
|
||||||
{ @autoreleasepool {
|
{ @autoreleasepool {
|
||||||
@@ -469,12 +701,46 @@ void Shader::updateUniform(const UniformInfo * /*info*/, int /*count*/)
|
|||||||
{
|
{
|
||||||
// Nothing needed here, All uniform data will be memcpy'd to the main
|
// Nothing needed here, All uniform data will be memcpy'd to the main
|
||||||
// uniform buffer before drawing.
|
// uniform buffer before drawing.
|
||||||
|
// FIXME: do we need to copy to a second buffer here, in order for batch
|
||||||
|
// flushing to work (and possibly padding)?
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count)
|
void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count)
|
||||||
{
|
{ @autoreleasepool {
|
||||||
// TODO
|
if (info->baseType != UNIFORM_SAMPLER)
|
||||||
}
|
return;
|
||||||
|
|
||||||
|
bool shaderactive = current == this;
|
||||||
|
|
||||||
|
if (shaderactive)
|
||||||
|
Graphics::flushBatchedDrawsGlobal();
|
||||||
|
|
||||||
|
count = std::min(count, info->count);
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
love::graphics::Texture *tex = textures[i];
|
||||||
|
|
||||||
|
if (tex != nullptr)
|
||||||
|
{
|
||||||
|
if (!validateTexture(info, tex, false))
|
||||||
|
continue;
|
||||||
|
tex->retain();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: matching default texture
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->textures[i] != nullptr)
|
||||||
|
info->textures[i]->release();
|
||||||
|
|
||||||
|
info->textures[i] = tex;
|
||||||
|
|
||||||
|
textureBindings[info->ints[i]].texture = getMTLTexture(tex);
|
||||||
|
textureBindings[info->ints[i]].sampler = getMTLSampler(tex);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count)
|
void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -35,12 +35,7 @@ public:
|
|||||||
|
|
||||||
ShaderStage(love::graphics::Graphics *gfx, StageType stage, const std::string &source, bool gles, const std::string &cachekey);
|
ShaderStage(love::graphics::Graphics *gfx, StageType stage, const std::string &source, bool gles, const std::string &cachekey);
|
||||||
virtual ~ShaderStage();
|
virtual ~ShaderStage();
|
||||||
|
ptrdiff_t getHandle() const override { return 0; }
|
||||||
ptrdiff_t getHandle() const override { return (ptrdiff_t) glslangShader; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
glslang::TShader *glslangShader;
|
|
||||||
|
|
||||||
}; // ShaderStage
|
}; // ShaderStage
|
||||||
|
|
||||||
|
|||||||
@@ -22,114 +22,6 @@
|
|||||||
|
|
||||||
#include "libraries/glslang/glslang/Public/ShaderLang.h"
|
#include "libraries/glslang/glslang/Public/ShaderLang.h"
|
||||||
|
|
||||||
// TODO: Use love.graphics to determine actual limits?
|
|
||||||
static const TBuiltInResource defaultTBuiltInResource = {
|
|
||||||
/* .MaxLights = */ 32,
|
|
||||||
/* .MaxClipPlanes = */ 6,
|
|
||||||
/* .MaxTextureUnits = */ 32,
|
|
||||||
/* .MaxTextureCoords = */ 32,
|
|
||||||
/* .MaxVertexAttribs = */ 64,
|
|
||||||
/* .MaxVertexUniformComponents = */ 16384,
|
|
||||||
/* .MaxVaryingFloats = */ 128,
|
|
||||||
/* .MaxVertexTextureImageUnits = */ 32,
|
|
||||||
/* .MaxCombinedTextureImageUnits = */ 80,
|
|
||||||
/* .MaxTextureImageUnits = */ 32,
|
|
||||||
/* .MaxFragmentUniformComponents = */ 16384,
|
|
||||||
/* .MaxDrawBuffers = */ 8,
|
|
||||||
/* .MaxVertexUniformVectors = */ 4096,
|
|
||||||
/* .MaxVaryingVectors = */ 32,
|
|
||||||
/* .MaxFragmentUniformVectors = */ 4096,
|
|
||||||
/* .MaxVertexOutputVectors = */ 32,
|
|
||||||
/* .MaxFragmentInputVectors = */ 31,
|
|
||||||
/* .MinProgramTexelOffset = */ -8,
|
|
||||||
/* .MaxProgramTexelOffset = */ 7,
|
|
||||||
/* .MaxClipDistances = */ 8,
|
|
||||||
/* .MaxComputeWorkGroupCountX = */ 65535,
|
|
||||||
/* .MaxComputeWorkGroupCountY = */ 65535,
|
|
||||||
/* .MaxComputeWorkGroupCountZ = */ 65535,
|
|
||||||
/* .MaxComputeWorkGroupSizeX = */ 1024,
|
|
||||||
/* .MaxComputeWorkGroupSizeY = */ 1024,
|
|
||||||
/* .MaxComputeWorkGroupSizeZ = */ 64,
|
|
||||||
/* .MaxComputeUniformComponents = */ 1024,
|
|
||||||
/* .MaxComputeTextureImageUnits = */ 32,
|
|
||||||
/* .MaxComputeImageUniforms = */ 16,
|
|
||||||
/* .MaxComputeAtomicCounters = */ 4096,
|
|
||||||
/* .MaxComputeAtomicCounterBuffers = */ 8,
|
|
||||||
/* .MaxVaryingComponents = */ 128,
|
|
||||||
/* .MaxVertexOutputComponents = */ 128,
|
|
||||||
/* .MaxGeometryInputComponents = */ 128,
|
|
||||||
/* .MaxGeometryOutputComponents = */ 128,
|
|
||||||
/* .MaxFragmentInputComponents = */ 128,
|
|
||||||
/* .MaxImageUnits = */ 192,
|
|
||||||
/* .MaxCombinedImageUnitsAndFragmentOutputs = */ 144,
|
|
||||||
/* .MaxCombinedShaderOutputResources = */ 144,
|
|
||||||
/* .MaxImageSamples = */ 32,
|
|
||||||
/* .MaxVertexImageUniforms = */ 16,
|
|
||||||
/* .MaxTessControlImageUniforms = */ 16,
|
|
||||||
/* .MaxTessEvaluationImageUniforms = */ 16,
|
|
||||||
/* .MaxGeometryImageUniforms = */ 16,
|
|
||||||
/* .MaxFragmentImageUniforms = */ 16,
|
|
||||||
/* .MaxCombinedImageUniforms = */ 80,
|
|
||||||
/* .MaxGeometryTextureImageUnits = */ 16,
|
|
||||||
/* .MaxGeometryOutputVertices = */ 256,
|
|
||||||
/* .MaxGeometryTotalOutputComponents = */ 1024,
|
|
||||||
/* .MaxGeometryUniformComponents = */ 1024,
|
|
||||||
/* .MaxGeometryVaryingComponents = */ 64,
|
|
||||||
/* .MaxTessControlInputComponents = */ 128,
|
|
||||||
/* .MaxTessControlOutputComponents = */ 128,
|
|
||||||
/* .MaxTessControlTextureImageUnits = */ 16,
|
|
||||||
/* .MaxTessControlUniformComponents = */ 1024,
|
|
||||||
/* .MaxTessControlTotalOutputComponents = */ 4096,
|
|
||||||
/* .MaxTessEvaluationInputComponents = */ 128,
|
|
||||||
/* .MaxTessEvaluationOutputComponents = */ 128,
|
|
||||||
/* .MaxTessEvaluationTextureImageUnits = */ 16,
|
|
||||||
/* .MaxTessEvaluationUniformComponents = */ 1024,
|
|
||||||
/* .MaxTessPatchComponents = */ 120,
|
|
||||||
/* .MaxPatchVertices = */ 32,
|
|
||||||
/* .MaxTessGenLevel = */ 64,
|
|
||||||
/* .MaxViewports = */ 16,
|
|
||||||
/* .MaxVertexAtomicCounters = */ 4096,
|
|
||||||
/* .MaxTessControlAtomicCounters = */ 4096,
|
|
||||||
/* .MaxTessEvaluationAtomicCounters = */ 4096,
|
|
||||||
/* .MaxGeometryAtomicCounters = */ 4096,
|
|
||||||
/* .MaxFragmentAtomicCounters = */ 4096,
|
|
||||||
/* .MaxCombinedAtomicCounters = */ 4096,
|
|
||||||
/* .MaxAtomicCounterBindings = */ 8,
|
|
||||||
/* .MaxVertexAtomicCounterBuffers = */ 8,
|
|
||||||
/* .MaxTessControlAtomicCounterBuffers = */ 8,
|
|
||||||
/* .MaxTessEvaluationAtomicCounterBuffers = */ 8,
|
|
||||||
/* .MaxGeometryAtomicCounterBuffers = */ 8,
|
|
||||||
/* .MaxFragmentAtomicCounterBuffers = */ 8,
|
|
||||||
/* .MaxCombinedAtomicCounterBuffers = */ 8,
|
|
||||||
/* .MaxAtomicCounterBufferSize = */ 16384,
|
|
||||||
/* .MaxTransformFeedbackBuffers = */ 4,
|
|
||||||
/* .MaxTransformFeedbackInterleavedComponents = */ 64,
|
|
||||||
/* .MaxCullDistances = */ 8,
|
|
||||||
/* .MaxCombinedClipAndCullDistances = */ 8,
|
|
||||||
/* .MaxSamples = */ 32,
|
|
||||||
/* .maxMeshOutputVerticesNV = */ 256,
|
|
||||||
/* .maxMeshOutputPrimitivesNV = */ 512,
|
|
||||||
/* .maxMeshWorkGroupSizeX_NV = */ 32,
|
|
||||||
/* .maxMeshWorkGroupSizeY_NV = */ 1,
|
|
||||||
/* .maxMeshWorkGroupSizeZ_NV = */ 1,
|
|
||||||
/* .maxTaskWorkGroupSizeX_NV = */ 32,
|
|
||||||
/* .maxTaskWorkGroupSizeY_NV = */ 1,
|
|
||||||
/* .maxTaskWorkGroupSizeZ_NV = */ 1,
|
|
||||||
/* .maxMeshViewCountNV = */ 4,
|
|
||||||
/* .maxDualSourceDrawBuffersEXT = */ 1,
|
|
||||||
/* .limits = */ {
|
|
||||||
/* .nonInductiveForLoops = */ 1,
|
|
||||||
/* .whileLoops = */ 1,
|
|
||||||
/* .doWhileLoops = */ 1,
|
|
||||||
/* .generalUniformIndexing = */ 1,
|
|
||||||
/* .generalAttributeMatrixVectorIndexing = */ 1,
|
|
||||||
/* .generalVaryingIndexing = */ 1,
|
|
||||||
/* .generalSamplerIndexing = */ 1,
|
|
||||||
/* .generalVariableIndexing = */ 1,
|
|
||||||
/* .generalConstantMatrixVectorIndexing = */ 1,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace love
|
namespace love
|
||||||
{
|
{
|
||||||
namespace graphics
|
namespace graphics
|
||||||
@@ -140,57 +32,13 @@ namespace metal
|
|||||||
ShaderStage::ShaderStage(love::graphics::Graphics *gfx, StageType stage, const std::string &source, bool gles, const std::string &cachekey)
|
ShaderStage::ShaderStage(love::graphics::Graphics *gfx, StageType stage, const std::string &source, bool gles, const std::string &cachekey)
|
||||||
: love::graphics::ShaderStage(gfx, stage, source, gles, cachekey)
|
: love::graphics::ShaderStage(gfx, stage, source, gles, cachekey)
|
||||||
{
|
{
|
||||||
using namespace glslang;
|
// Can't store anything in here since the next part of the compilation
|
||||||
|
// pipeline (glslang to generate spir-v) requires linking stages together
|
||||||
EShLanguage glslangStage = EShLangCount;
|
// destructively.
|
||||||
if (stage == STAGE_VERTEX)
|
|
||||||
glslangStage = EShLangVertex;
|
|
||||||
else if (stage == STAGE_PIXEL)
|
|
||||||
glslangStage = EShLangFragment;
|
|
||||||
else
|
|
||||||
throw love::Exception("Cannot compile shader stage: unknown stage type.");
|
|
||||||
|
|
||||||
glslangShader = new TShader(glslangStage);
|
|
||||||
|
|
||||||
// We can't reuse the validation glslang shader object in the base class,
|
|
||||||
// because we need these options set (and the language set to >= 300).
|
|
||||||
glslangShader->setEnvInput(EShSourceGlsl, glslangStage, EShClientVulkan, 450);
|
|
||||||
glslangShader->setEnvClient(EShClientVulkan, EShTargetVulkan_1_2);
|
|
||||||
glslangShader->setEnvTarget(EShTargetSpv, EShTargetSpv_1_5);
|
|
||||||
glslangShader->setAutoMapLocations(true);
|
|
||||||
glslangShader->setAutoMapBindings(true);
|
|
||||||
|
|
||||||
// Needed for local uniforms to work (they will be converted into a uniform
|
|
||||||
// block).
|
|
||||||
// https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GL_EXT_vulkan_glsl_relaxed.txt
|
|
||||||
glslangShader->setEnvInputVulkanRulesRelaxed();
|
|
||||||
|
|
||||||
const char *csrc = source.c_str();
|
|
||||||
int srclen = (int) source.length();
|
|
||||||
glslangShader->setStringsWithLengths(&csrc, &srclen, 1);
|
|
||||||
|
|
||||||
int defaultversion = gles ? 300 : 330;
|
|
||||||
EProfile defaultprofile = gles ? EEsProfile : ECoreProfile;
|
|
||||||
bool forcedefault = false;
|
|
||||||
bool forwardcompat = true;
|
|
||||||
|
|
||||||
if (!glslangShader->parse(&defaultTBuiltInResource, defaultversion, defaultprofile, forcedefault, forwardcompat, EShMsgSuppressWarnings))
|
|
||||||
{
|
|
||||||
const char *stagename = "unknown";
|
|
||||||
getConstant(stage, stagename);
|
|
||||||
|
|
||||||
std::string err = "Error parsing " + std::string(stagename) + " shader:\n\n"
|
|
||||||
+ std::string(glslangShader->getInfoLog()) + "\n"
|
|
||||||
+ std::string(glslangShader->getInfoDebugLog());
|
|
||||||
|
|
||||||
delete glslangShader;
|
|
||||||
throw love::Exception("%s", err.c_str());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderStage::~ShaderStage()
|
ShaderStage::~ShaderStage()
|
||||||
{
|
{
|
||||||
delete glslangShader;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // metal
|
} // metal
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ public:
|
|||||||
|
|
||||||
ptrdiff_t getHandle() const override { return (ptrdiff_t) texture; }
|
ptrdiff_t getHandle() const override { return (ptrdiff_t) texture; }
|
||||||
ptrdiff_t getRenderTargetHandle() const override { return msaaTexture != nil ? (ptrdiff_t) msaaTexture : (ptrdiff_t) texture; }
|
ptrdiff_t getRenderTargetHandle() const override { return msaaTexture != nil ? (ptrdiff_t) msaaTexture : (ptrdiff_t) texture; }
|
||||||
|
ptrdiff_t getSamplerHandle() const override { return (ptrdiff_t) sampler; }
|
||||||
|
|
||||||
int getMSAA() const override { return 1 /* TODO*/; }
|
int getMSAA() const override { return 1 /* TODO*/; }
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ public:
|
|||||||
|
|
||||||
ptrdiff_t getHandle() const override;
|
ptrdiff_t getHandle() const override;
|
||||||
ptrdiff_t getRenderTargetHandle() const override;
|
ptrdiff_t getRenderTargetHandle() const override;
|
||||||
|
ptrdiff_t getSamplerHandle() const override { return 0; }
|
||||||
int getMSAA() const override { return actualSamples; }
|
int getMSAA() const override { return actualSamples; }
|
||||||
|
|
||||||
inline GLuint getFBO() const { return fbo; }
|
inline GLuint getFBO() const { return fbo; }
|
||||||
|
|||||||
Reference in New Issue
Block a user