mirror of
https://github.com/love2d/love.git
synced 2026-08-12 16:40:57 +02:00
metal: nogame and error screens work.
- implement love.graphics.setColor - implement default textures - hacky implementation of default uniform data - use texture swizzles to set up LA8 (text) texture data - shader reflection work
This commit is contained in:
@@ -159,7 +159,7 @@ love::Type Texture::type("Texture", &Drawable::type);
|
||||
int Texture::textureCount = 0;
|
||||
int64 Texture::totalGraphicsMemory = 0;
|
||||
|
||||
Texture::Texture(const Settings &settings, const Slices *slices)
|
||||
Texture::Texture(Graphics *gfx, const Settings &settings, const Slices *slices)
|
||||
: texType(settings.type)
|
||||
, format(settings.format)
|
||||
, renderTarget(settings.renderTarget)
|
||||
@@ -178,8 +178,6 @@ Texture::Texture(const Settings &settings, const Slices *slices)
|
||||
, graphicsMemorySize(0)
|
||||
, usingDefaultTexture(false)
|
||||
{
|
||||
auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
|
||||
|
||||
if (slices != nullptr && slices->getMipmapCount() > 0 && slices->getSliceCount() > 0)
|
||||
{
|
||||
texType = slices->getTextureType();
|
||||
|
||||
@@ -201,7 +201,7 @@ public:
|
||||
|
||||
static int64 totalGraphicsMemory;
|
||||
|
||||
Texture(const Settings &settings, const Slices *slices);
|
||||
Texture(Graphics *gfx, const Settings &settings, const Slices *slices);
|
||||
virtual ~Texture();
|
||||
|
||||
// Drawable.
|
||||
|
||||
@@ -109,12 +109,17 @@ public:
|
||||
|
||||
id<MTLSamplerState> getCachedSampler(const SamplerState &s);
|
||||
|
||||
static Graphics *getInstance() { return Module::getInstance<Graphics>(M_GRAPHICS); }
|
||||
StreamBuffer *getUniformBuffer() const { return uniformBuffer; }
|
||||
Buffer *getDefaultAttributesBuffer() const { return defaultAttributesBuffer; }
|
||||
|
||||
static Graphics *getInstance() { return graphicsInstance; }
|
||||
|
||||
id<MTLDevice> device;
|
||||
|
||||
private:
|
||||
|
||||
static Graphics *graphicsInstance;
|
||||
|
||||
enum StateType
|
||||
{
|
||||
STATE_BLEND,
|
||||
@@ -166,6 +171,7 @@ private:
|
||||
|
||||
id<MTLDepthStencilState> getCachedDepthStencilState(const DepthState &depth, const StencilState &stencil);
|
||||
void applyRenderState(id<MTLRenderCommandEncoder> renderEncoder, const vertex::Attributes &attributes);
|
||||
void applyShaderUniforms(id<MTLRenderCommandEncoder> renderEncoder, Shader *shader);
|
||||
|
||||
id<MTLCommandQueue> commandQueue;
|
||||
|
||||
@@ -180,6 +186,14 @@ private:
|
||||
uint32 dirtyRenderState;
|
||||
bool windowHasStencil;
|
||||
|
||||
StreamBuffer *uniformBuffer;
|
||||
StreamBuffer::MapInfo uniformBufferData;
|
||||
size_t uniformBufferOffset;
|
||||
|
||||
Buffer *defaultAttributesBuffer;
|
||||
|
||||
Texture *defaultTextures[TEXTURE_MAX_ENUM];
|
||||
|
||||
std::map<uint64, void *> cachedSamplers;
|
||||
|
||||
}; // Graphics
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "ShaderStage.h"
|
||||
#include "window/Window.h"
|
||||
#include "image/Image.h"
|
||||
#include "common/memory.h"
|
||||
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
|
||||
@@ -110,6 +111,8 @@ love::graphics::Graphics *createInstance()
|
||||
return instance;
|
||||
}
|
||||
|
||||
Graphics *Graphics::graphicsInstance = nullptr;
|
||||
|
||||
Graphics::Graphics()
|
||||
: device(nil)
|
||||
, commandQueue(nil)
|
||||
@@ -121,7 +124,11 @@ Graphics::Graphics()
|
||||
, passDesc(nil)
|
||||
, dirtyRenderState(STATEBIT_ALL)
|
||||
, windowHasStencil(false)
|
||||
, uniformBufferOffset(0)
|
||||
, defaultAttributesBuffer(nullptr)
|
||||
, defaultTextures()
|
||||
{ @autoreleasepool {
|
||||
graphicsInstance = this;
|
||||
device = MTLCreateSystemDefaultDevice();
|
||||
if (device == nil)
|
||||
throw love::Exception("Metal is not supported on this system.");
|
||||
@@ -131,6 +138,23 @@ Graphics::Graphics()
|
||||
|
||||
initCapabilities();
|
||||
|
||||
uniformBuffer = CreateStreamBuffer(device, BUFFER_UNIFORM, 1024 * 1024 * 1);
|
||||
uniformBufferData = uniformBuffer->map(uniformBuffer->getSize());
|
||||
|
||||
float defaultAttributes[4] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
defaultAttributesBuffer = newBuffer(sizeof(float) * 4, defaultAttributes, BUFFER_VERTEX, vertex::USAGE_STATIC, 0);
|
||||
|
||||
uint8 defaultpixel[] = {255, 255, 255, 255};
|
||||
for (int i = 0; i < TEXTURE_MAX_ENUM; i++)
|
||||
{
|
||||
Texture::Settings settings;
|
||||
settings.type = (TextureType) i;
|
||||
settings.format = PIXELFORMAT_RGBA8_UNORM;
|
||||
defaultTextures[i] = newTexture(settings);
|
||||
Rect r = {0, 0, 1, 1};
|
||||
defaultTextures[i]->replacePixels(defaultpixel, sizeof(defaultpixel), 0, 0, r, false);
|
||||
}
|
||||
|
||||
auto window = Module::getInstance<love::window::Window>(M_WINDOW);
|
||||
|
||||
if (window != nullptr)
|
||||
@@ -156,12 +180,19 @@ Graphics::Graphics()
|
||||
Graphics::~Graphics()
|
||||
{ @autoreleasepool {
|
||||
submitCommandBuffer();
|
||||
delete uniformBuffer;
|
||||
delete defaultAttributesBuffer;
|
||||
passDesc = nil;
|
||||
commandQueue = nil;
|
||||
device = nil;
|
||||
|
||||
for (int i = 0; i < TEXTURE_MAX_ENUM; i++)
|
||||
defaultTextures[i]->release();
|
||||
|
||||
for (auto &kvp : cachedSamplers)
|
||||
CFBridgingRelease(kvp.second);
|
||||
|
||||
graphicsInstance = nullptr;
|
||||
}}
|
||||
|
||||
love::graphics::StreamBuffer *Graphics::newStreamBuffer(BufferType type, size_t size)
|
||||
@@ -171,7 +202,7 @@ love::graphics::StreamBuffer *Graphics::newStreamBuffer(BufferType type, size_t
|
||||
|
||||
love::graphics::Texture *Graphics::newTexture(const Texture::Settings &settings, const Texture::Slices *data)
|
||||
{
|
||||
return new Texture(device, settings, data);
|
||||
return new Texture(this, device, settings, data);
|
||||
}
|
||||
|
||||
love::graphics::ShaderStage *Graphics::newShaderStageInternal(ShaderStage::StageType stage, const std::string &cachekey, const std::string &source, bool gles)
|
||||
@@ -322,6 +353,10 @@ id<MTLRenderCommandEncoder> Graphics::useRenderEncoder()
|
||||
}
|
||||
|
||||
renderEncoder = [useCommandBuffer() renderCommandEncoderWithDescriptor:passDesc];
|
||||
|
||||
id<MTLBuffer> defaultbuffer = (__bridge id<MTLBuffer>)(void *)defaultAttributesBuffer->getHandle();
|
||||
[renderEncoder setVertexBuffer:defaultbuffer offset:0 atIndex:DEFAULT_VERTEX_BUFFER_BINDING];
|
||||
|
||||
dirtyRenderState = STATEBIT_ALL;
|
||||
}
|
||||
|
||||
@@ -530,16 +565,85 @@ void Graphics::applyRenderState(id<MTLRenderCommandEncoder> encoder, const verte
|
||||
dirtyRenderState = 0;
|
||||
}
|
||||
|
||||
void Graphics::applyShaderUniforms(id<MTLRenderCommandEncoder> renderEncoder, love::graphics::Shader *shader)
|
||||
{
|
||||
Shader *s = (Shader *)shader;
|
||||
|
||||
#ifdef LOVE_MACOS
|
||||
size_t alignment = 256;
|
||||
#else
|
||||
size_t alignment = 16;
|
||||
#endif
|
||||
|
||||
// TODO: use the size of all uniforms
|
||||
size_t size = sizeof(Shader::BuiltinUniformData);
|
||||
|
||||
Shader::BuiltinUniformData data;
|
||||
|
||||
data.transformMatrix = getTransform();
|
||||
data.projectionMatrix = getProjection();
|
||||
|
||||
// The normal matrix is the transpose of the inverse of the rotation portion
|
||||
// (top-left 3x3) of the transform matrix.
|
||||
{
|
||||
Matrix3 normalmatrix = Matrix3(data.transformMatrix).transposedInverse();
|
||||
const float *e = normalmatrix.getElements();
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
data.normalMatrix[i].x = e[i * 3 + 0];
|
||||
data.normalMatrix[i].y = e[i * 3 + 1];
|
||||
data.normalMatrix[i].z = e[i * 3 + 2];
|
||||
data.normalMatrix[i].w = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: should be active RT dimensions
|
||||
data.screenSizeParams.x = getPixelWidth();
|
||||
data.screenSizeParams.y = getPixelHeight();
|
||||
|
||||
data.screenSizeParams.z = 1.0f;
|
||||
data.screenSizeParams.w = 0.0f;
|
||||
|
||||
data.constantColor = getColor();
|
||||
gammaCorrectColor(data.constantColor);
|
||||
|
||||
if (uniformBufferData.size < uniformBufferOffset + size)
|
||||
{
|
||||
size_t newsize = uniformBuffer->getSize() * 2;
|
||||
delete uniformBuffer;
|
||||
uniformBuffer = CreateStreamBuffer(device, BUFFER_UNIFORM, newsize);
|
||||
uniformBufferData = uniformBuffer->map(uniformBuffer->getSize());
|
||||
uniformBufferOffset = 0;
|
||||
}
|
||||
|
||||
memcpy(uniformBufferData.data + uniformBufferOffset, &data, sizeof(Shader::BuiltinUniformData));
|
||||
|
||||
id<MTLBuffer> buffer = (__bridge id<MTLBuffer>)(void *)uniformBuffer->getHandle();
|
||||
int index = Shader::getUniformBufferBinding();
|
||||
|
||||
// TODO: bind shader textures/samplers
|
||||
|
||||
[renderEncoder setVertexBuffer:buffer offset:uniformBufferOffset atIndex:index];
|
||||
[renderEncoder setFragmentBuffer:buffer offset:uniformBufferOffset atIndex:index];
|
||||
|
||||
uniformBufferOffset += alignUp(size, alignment);
|
||||
}
|
||||
|
||||
void Graphics::draw(const DrawCommand &cmd)
|
||||
{ @autoreleasepool {
|
||||
id<MTLRenderCommandEncoder> encoder = useRenderEncoder();
|
||||
|
||||
applyRenderState(encoder, *cmd.attributes);
|
||||
applyShaderUniforms(encoder, Shader::current);
|
||||
|
||||
id<MTLTexture> mtltexture = (__bridge id<MTLTexture>)(void *) cmd.texture->getHandle();
|
||||
love::graphics::Texture *texture = cmd.texture;
|
||||
if (texture == nullptr)
|
||||
texture = defaultTextures[TEXTURE_2D];
|
||||
|
||||
id<MTLTexture> mtltexture = (__bridge id<MTLTexture>)(void *) texture->getHandle();
|
||||
|
||||
[encoder setFragmentTexture:mtltexture atIndex:0];
|
||||
[encoder setFragmentSamplerState:((Texture *)cmd.texture)->getMTLSampler() atIndex:0];
|
||||
[encoder setFragmentSamplerState:((Texture *)texture)->getMTLSampler() atIndex:0];
|
||||
|
||||
[encoder setCullMode:MTLCullModeNone];
|
||||
|
||||
@@ -553,7 +657,7 @@ void Graphics::draw(const DrawCommand &cmd)
|
||||
{
|
||||
auto b = cmd.buffers->info[i];
|
||||
id<MTLBuffer> buffer = (__bridge id<MTLBuffer>)(void *)b.buffer->getHandle();
|
||||
[encoder setVertexBuffer:buffer offset:b.offset atIndex:i];
|
||||
[encoder setVertexBuffer:buffer offset:b.offset atIndex:i + VERTEX_BUFFER_BINDING_START];
|
||||
}
|
||||
|
||||
i++;
|
||||
@@ -571,11 +675,16 @@ void Graphics::draw(const DrawIndexedCommand &cmd)
|
||||
id<MTLRenderCommandEncoder> encoder = useRenderEncoder();
|
||||
|
||||
applyRenderState(encoder, *cmd.attributes);
|
||||
applyShaderUniforms(encoder, Shader::current);
|
||||
|
||||
id<MTLTexture> mtltexture = (__bridge id<MTLTexture>)(void *) cmd.texture->getHandle();
|
||||
love::graphics::Texture *texture = cmd.texture;
|
||||
if (texture == nullptr)
|
||||
texture = defaultTextures[TEXTURE_2D];
|
||||
|
||||
id<MTLTexture> mtltexture = (__bridge id<MTLTexture>)(void *) texture->getHandle();
|
||||
|
||||
[encoder setFragmentTexture:mtltexture atIndex:0];
|
||||
[encoder setFragmentSamplerState:((Texture *)cmd.texture)->getMTLSampler() atIndex:0];
|
||||
[encoder setFragmentSamplerState:((Texture *)texture)->getMTLSampler() atIndex:0];
|
||||
|
||||
[encoder setCullMode:MTLCullModeNone];
|
||||
|
||||
@@ -589,7 +698,7 @@ void Graphics::draw(const DrawIndexedCommand &cmd)
|
||||
{
|
||||
auto b = cmd.buffers->info[i];
|
||||
id<MTLBuffer> buffer = (__bridge id<MTLBuffer>)(void *)b.buffer->getHandle();
|
||||
[encoder setVertexBuffer:buffer offset:b.offset atIndex:i];
|
||||
[encoder setVertexBuffer:buffer offset:b.offset atIndex:i + VERTEX_BUFFER_BINDING_START];
|
||||
}
|
||||
|
||||
i++;
|
||||
@@ -614,6 +723,10 @@ void Graphics::drawQuads(int start, int count, const vertex::Attributes &attribu
|
||||
id<MTLRenderCommandEncoder> encoder = useRenderEncoder();
|
||||
|
||||
applyRenderState(encoder, attributes);
|
||||
applyShaderUniforms(encoder, Shader::current);
|
||||
|
||||
if (texture == nullptr)
|
||||
texture = defaultTextures[TEXTURE_2D];
|
||||
|
||||
id<MTLTexture> mtltexture = (__bridge id<MTLTexture>)(void *) texture->getHandle();
|
||||
|
||||
@@ -632,7 +745,7 @@ void Graphics::drawQuads(int start, int count, const vertex::Attributes &attribu
|
||||
{
|
||||
auto b = buffers.info[i];
|
||||
id<MTLBuffer> buffer = (__bridge id<MTLBuffer>)(void *)b.buffer->getHandle();
|
||||
[encoder setVertexBuffer:buffer offset:b.offset atIndex:i];
|
||||
[encoder setVertexBuffer:buffer offset:b.offset atIndex:i + VERTEX_BUFFER_BINDING_START];
|
||||
}
|
||||
|
||||
i++;
|
||||
@@ -915,6 +1028,10 @@ void Graphics::present(void *screenshotCallbackData)
|
||||
buffer->nextFrame();
|
||||
batchedDrawState.indexBuffer->nextFrame();
|
||||
|
||||
uniformBuffer->nextFrame();
|
||||
uniformBufferData = uniformBuffer->map(uniformBuffer->getSize());
|
||||
uniformBufferOffset = 0;
|
||||
|
||||
id<MTLCommandBuffer> cmd = getCommandBuffer();
|
||||
|
||||
if (cmd != nil && activeDrawable != nil)
|
||||
@@ -950,7 +1067,12 @@ void Graphics::present(void *screenshotCallbackData)
|
||||
|
||||
void Graphics::setColor(Colorf c)
|
||||
{
|
||||
// TODO
|
||||
c.r = std::min(std::max(c.r, 0.0f), 1.0f);
|
||||
c.g = std::min(std::max(c.g, 0.0f), 1.0f);
|
||||
c.b = std::min(std::max(c.b, 0.0f), 1.0f);
|
||||
c.a = std::min(std::max(c.a, 0.0f), 1.0f);
|
||||
|
||||
states.back().color = c;
|
||||
}
|
||||
|
||||
void Graphics::setScissor(const Rect &rect)
|
||||
|
||||
@@ -36,7 +36,14 @@ class Metal
|
||||
{
|
||||
public:
|
||||
|
||||
static MTLPixelFormat convertPixelFormat(PixelFormat format, bool &isSRGB);
|
||||
struct PixelFormatDesc
|
||||
{
|
||||
MTLPixelFormat format;
|
||||
bool swizzled = false;
|
||||
MTLTextureSwizzleChannels swizzle;
|
||||
};
|
||||
|
||||
static PixelFormatDesc convertPixelFormat(PixelFormat format, bool &isSRGB);
|
||||
|
||||
}; // Metal
|
||||
|
||||
|
||||
@@ -28,9 +28,10 @@ namespace graphics
|
||||
namespace metal
|
||||
{
|
||||
|
||||
MTLPixelFormat Metal::convertPixelFormat(PixelFormat format, bool &isSRGB)
|
||||
Metal::PixelFormatDesc Metal::convertPixelFormat(PixelFormat format, bool &isSRGB)
|
||||
{
|
||||
MTLPixelFormat mtlformat = MTLPixelFormatRGBA8Unorm;
|
||||
PixelFormatDesc desc = {};
|
||||
|
||||
if (isSRGB)
|
||||
format = getSRGBPixelFormat(format);
|
||||
@@ -87,10 +88,11 @@ MTLPixelFormat Metal::convertPixelFormat(PixelFormat format, bool &isSRGB)
|
||||
break;
|
||||
|
||||
case PIXELFORMAT_LA8_UNORM:
|
||||
// TODO: Swizzle
|
||||
// TODO: fall back to RGBA8 when swizzle isn't available. Pixel format
|
||||
// size calculation will need to be adjusted as well
|
||||
mtlformat = MTLPixelFormatRG8Unorm;
|
||||
desc.swizzled = true;
|
||||
desc.swizzle = MTLTextureSwizzleChannelsMake(MTLTextureSwizzleRed, MTLTextureSwizzleRed, MTLTextureSwizzleRed, MTLTextureSwizzleGreen);
|
||||
break;
|
||||
|
||||
case PIXELFORMAT_RGBA4_UNORM:
|
||||
@@ -346,7 +348,8 @@ MTLPixelFormat Metal::convertPixelFormat(PixelFormat format, bool &isSRGB)
|
||||
break;
|
||||
}
|
||||
|
||||
return mtlformat;
|
||||
desc.format = mtlformat;
|
||||
return desc;
|
||||
}
|
||||
|
||||
Metal metal;
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#import <Metal/MTLRenderPipeline.h>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace love
|
||||
@@ -39,6 +40,9 @@ namespace graphics
|
||||
namespace metal
|
||||
{
|
||||
|
||||
static const int DEFAULT_VERTEX_BUFFER_BINDING = 1;
|
||||
static const int VERTEX_BUFFER_BINDING_START = 2;
|
||||
|
||||
class Shader final : public love::graphics::Shader
|
||||
{
|
||||
public:
|
||||
@@ -69,9 +73,9 @@ public:
|
||||
// Implements Shader.
|
||||
void attach() override;
|
||||
std::string getWarnings() const override { return ""; }
|
||||
int getVertexAttributeIndex(const std::string &name) override { return -1; }
|
||||
const UniformInfo *getUniformInfo(const std::string &name) const override { return nullptr; }
|
||||
const UniformInfo *getUniformInfo(BuiltinUniform builtin) const override { return nullptr; }
|
||||
int getVertexAttributeIndex(const std::string &name) override;
|
||||
const UniformInfo *getUniformInfo(const std::string &name) const override;
|
||||
const UniformInfo *getUniformInfo(BuiltinUniform builtin) const override;
|
||||
void updateUniform(const UniformInfo *info, int count) override {}
|
||||
void sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count) override {}
|
||||
bool hasUniform(const std::string &name) const override { return false; }
|
||||
@@ -80,6 +84,8 @@ public:
|
||||
|
||||
id<MTLRenderPipelineState> getCachedRenderPipeline(const RenderPipelineKey &key);
|
||||
|
||||
static int getUniformBufferBinding();
|
||||
|
||||
private:
|
||||
|
||||
struct RenderPipelineHasher
|
||||
@@ -92,6 +98,11 @@ private:
|
||||
|
||||
id<MTLFunction> functions[ShaderStage::STAGE_MAX_ENUM];
|
||||
|
||||
UniformInfo *builtinUniformInfo[BUILTIN_MAX_ENUM];
|
||||
std::map<std::string, UniformInfo> uniforms;
|
||||
|
||||
std::map<std::string, int> attributes;
|
||||
|
||||
std::unordered_map<RenderPipelineKey, const void *, RenderPipelineHasher> cachedRenderPipelines;
|
||||
|
||||
}; // Metal
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "Shader.h"
|
||||
#include "Graphics.h"
|
||||
#include "common/int.h"
|
||||
|
||||
// glslang
|
||||
#include "libraries/glslang/glslang/Public/ShaderLang.h"
|
||||
@@ -123,6 +124,7 @@ static EShLanguage getGLSLangStage(ShaderStage::StageType stage)
|
||||
Shader::Shader(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage *pixel)
|
||||
: love::graphics::Shader(vertex, pixel)
|
||||
, functions()
|
||||
, builtinUniformInfo()
|
||||
{ @autoreleasepool {
|
||||
auto gfx = Graphics::getInstance();
|
||||
|
||||
@@ -145,6 +147,9 @@ Shader::Shader(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage
|
||||
throw love::Exception("link failed!\n");
|
||||
}
|
||||
|
||||
std::map<std::string, int> varyings;
|
||||
int nextVaryingLocation = 0;
|
||||
|
||||
for (int i = 0; i < ShaderStage::STAGE_MAX_ENUM; i++)
|
||||
{
|
||||
auto glslangstage = getGLSLangStage((ShaderStage::StageType) i);
|
||||
@@ -169,11 +174,54 @@ Shader::Shader(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage
|
||||
// Compile to GLSL, ready to give to GL driver.
|
||||
try
|
||||
{
|
||||
|
||||
// printf("GLSL INPUT SOURCE:\n\n%s\n\n", pixel->getSource().c_str());
|
||||
|
||||
CompilerMSL msl(std::move(spirv));
|
||||
|
||||
auto interfacevars = msl.get_active_interface_variables();
|
||||
|
||||
msl.set_enabled_interface_variables(interfacevars);
|
||||
|
||||
ShaderResources resources = msl.get_shader_resources();
|
||||
|
||||
for (const auto &resource : resources.sampled_images)
|
||||
{
|
||||
BuiltinUniform builtin = BUILTIN_MAX_ENUM;
|
||||
if (getConstant(resource.name.c_str(), builtin))
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &resource : resources.uniform_buffers)
|
||||
{
|
||||
if (resource.name == "love_UniformsPerDrawBuffer")
|
||||
{
|
||||
msl.set_decoration(resource.id, spv::DecorationBinding, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ShaderStage::STAGE_VERTEX)
|
||||
{
|
||||
for (const auto &varying : resources.stage_outputs)
|
||||
{
|
||||
// printf("vertex shader output %s: %d\n", inp.name.c_str(), msl.get_decoration(inp.id, spv::DecorationLocation));
|
||||
varyings[varying.name] = nextVaryingLocation;
|
||||
msl.set_decoration(varying.id, spv::DecorationLocation, nextVaryingLocation++);
|
||||
}
|
||||
}
|
||||
else if (i == ShaderStage::STAGE_PIXEL)
|
||||
{
|
||||
for (const auto &varying : resources.stage_inputs)
|
||||
{
|
||||
const auto it = varyings.find(varying.name);
|
||||
if (it != varyings.end())
|
||||
msl.set_decoration(varying.id, spv::DecorationLocation, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
printf("ubos: %d, storage: %d, inputs: %d, outputs: %d, images: %d, samplers: %d, push: %d\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;
|
||||
|
||||
#ifdef LOVE_IOS
|
||||
@@ -185,7 +233,7 @@ Shader::Shader(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage
|
||||
msl.set_msl_options(options);
|
||||
|
||||
std::string source = msl.compile();
|
||||
// printf("MSL SOURCE:\n\n%s\n\n", source.c_str());
|
||||
// printf("MSL SOURCE for stage %d:\n\n%s\n\n", i, source.c_str());
|
||||
|
||||
NSString *nssource = [[NSString alloc] initWithBytes:source.c_str()
|
||||
length:source.length()
|
||||
@@ -200,6 +248,15 @@ Shader::Shader(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage
|
||||
}
|
||||
|
||||
functions[i] = [library newFunctionWithName:library.functionNames[0]];
|
||||
|
||||
for (const auto &var : interfacevars)
|
||||
{
|
||||
spv::StorageClass storage = msl.get_storage_class(var);
|
||||
const std::string &name = msl.get_name(var);
|
||||
|
||||
if (i == ShaderStage::STAGE_VERTEX && storage == spv::StorageClassInput)
|
||||
attributes[name] = msl.get_decoration(var, spv::DecorationLocation);
|
||||
}
|
||||
}
|
||||
catch (std::exception &e)
|
||||
{
|
||||
@@ -228,6 +285,23 @@ void Shader::attach()
|
||||
}
|
||||
}
|
||||
|
||||
int Shader::getVertexAttributeIndex(const std::string &name)
|
||||
{
|
||||
const auto it = attributes.find(name);
|
||||
return it != attributes.end() ? it->second : -1;
|
||||
}
|
||||
|
||||
const Shader::UniformInfo *Shader::getUniformInfo(const std::string &name) const
|
||||
{
|
||||
const auto it = uniforms.find(name);
|
||||
return it != uniforms.end() ? &(it->second) : nullptr;
|
||||
}
|
||||
|
||||
const Shader::UniformInfo *Shader::getUniformInfo(BuiltinUniform builtin) const
|
||||
{
|
||||
return builtinUniformInfo[(int)builtin];
|
||||
}
|
||||
|
||||
id<MTLRenderPipelineState> Shader::getCachedRenderPipeline(const RenderPipelineKey &key)
|
||||
{
|
||||
auto it = cachedRenderPipelines.find(key);
|
||||
@@ -253,9 +327,8 @@ id<MTLRenderPipelineState> Shader::getCachedRenderPipeline(const RenderPipelineK
|
||||
MTLRenderPipelineColorAttachmentDescriptor *attachment = desc.colorAttachments[i];
|
||||
|
||||
bool isSRGB = false;
|
||||
MTLPixelFormat metalformat = Metal::convertPixelFormat(format, isSRGB);
|
||||
|
||||
attachment.pixelFormat = metalformat;
|
||||
auto formatdesc = Metal::convertPixelFormat(format, isSRGB);
|
||||
attachment.pixelFormat = formatdesc.format;
|
||||
|
||||
if (key.blend.enable)
|
||||
{
|
||||
@@ -283,35 +356,47 @@ id<MTLRenderPipelineState> Shader::getCachedRenderPipeline(const RenderPipelineK
|
||||
desc.colorAttachments[i] = attachment;
|
||||
}
|
||||
|
||||
// TODO: depth/stencil attachment formats
|
||||
|
||||
|
||||
{
|
||||
MTLVertexDescriptor *vertdesc = [MTLVertexDescriptor vertexDescriptor];
|
||||
|
||||
const auto &attributes = key.vertexAttributes;
|
||||
uint32 allbits = attributes.enableBits;
|
||||
uint32 i = 0;
|
||||
while (allbits)
|
||||
|
||||
for (const auto &pair : this->attributes)
|
||||
{
|
||||
int i = pair.second;
|
||||
uint32 bit = 1u << i;
|
||||
|
||||
if (attributes.enableBits & bit)
|
||||
{
|
||||
const auto &attrib = attributes.attribs[i];
|
||||
int metalBufferIndex = attrib.bufferIndex + VERTEX_BUFFER_BINDING_START;
|
||||
|
||||
vertdesc.attributes[i].format = getMTLVertexFormat(attrib.type, attrib.components);
|
||||
vertdesc.attributes[i].offset = attrib.offsetFromVertex;
|
||||
vertdesc.attributes[i].bufferIndex = attrib.bufferIndex;
|
||||
vertdesc.attributes[i].bufferIndex = metalBufferIndex;
|
||||
|
||||
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;
|
||||
vertdesc.layouts[metalBufferIndex].stride = layout.stride;
|
||||
vertdesc.layouts[metalBufferIndex].stepFunction = step;
|
||||
}
|
||||
else
|
||||
{
|
||||
vertdesc.attributes[i].format = MTLVertexFormatFloat4;
|
||||
vertdesc.attributes[i].offset = 0;
|
||||
vertdesc.attributes[i].bufferIndex = DEFAULT_VERTEX_BUFFER_BINDING;
|
||||
|
||||
i++;
|
||||
allbits >>= 1;
|
||||
vertdesc.layouts[DEFAULT_VERTEX_BUFFER_BINDING].stride = sizeof(float) * 4;
|
||||
vertdesc.layouts[DEFAULT_VERTEX_BUFFER_BINDING].stepFunction = MTLVertexStepFunctionConstant;
|
||||
vertdesc.layouts[DEFAULT_VERTEX_BUFFER_BINDING].stepRate = 0;
|
||||
}
|
||||
}
|
||||
|
||||
desc.vertexDescriptor = vertdesc;
|
||||
@@ -331,6 +416,11 @@ id<MTLRenderPipelineState> Shader::getCachedRenderPipeline(const RenderPipelineK
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
int Shader::getUniformBufferBinding()
|
||||
{
|
||||
return spirv_cross::ResourceBindingPushConstantBinding;
|
||||
}
|
||||
|
||||
} // metal
|
||||
} // graphics
|
||||
} // love
|
||||
|
||||
@@ -37,7 +37,7 @@ class Texture final : public love::graphics::Texture
|
||||
{
|
||||
public:
|
||||
|
||||
Texture(id<MTLDevice> device, const Settings &settings, const Slices *data);
|
||||
Texture(love::graphics::Graphics *gfx, id<MTLDevice> device, const Settings &settings, const Slices *data);
|
||||
virtual ~Texture();
|
||||
|
||||
void generateMipmaps() override;
|
||||
|
||||
@@ -41,8 +41,8 @@ static MTLTextureType getMTLTextureType(TextureType type, int msaa)
|
||||
return MTLTextureType2D;
|
||||
}
|
||||
|
||||
Texture::Texture(id<MTLDevice> device, const Settings &settings, const Slices *data)
|
||||
: love::graphics::Texture(settings, data)
|
||||
Texture::Texture(love::graphics::Graphics *gfx, id<MTLDevice> device, const Settings &settings, const Slices *data)
|
||||
: love::graphics::Texture(gfx, settings, data)
|
||||
, texture(nil)
|
||||
, msaaTexture(nil)
|
||||
, sampler(nil)
|
||||
@@ -52,13 +52,17 @@ Texture::Texture(id<MTLDevice> device, const Settings &settings, const Slices *d
|
||||
int w = pixelWidth;
|
||||
int h = pixelHeight;
|
||||
|
||||
auto formatdesc = Metal::convertPixelFormat(format, sRGB);
|
||||
|
||||
desc.width = w;
|
||||
desc.height = h;
|
||||
desc.depth = depth;
|
||||
desc.arrayLength = layers;
|
||||
desc.mipmapLevelCount = mipmapCount;
|
||||
desc.textureType = getMTLTextureType(texType, 1);
|
||||
desc.pixelFormat = Metal::convertPixelFormat(format, sRGB);
|
||||
desc.pixelFormat = formatdesc.format;
|
||||
if (formatdesc.swizzled)
|
||||
desc.swizzle = formatdesc.swizzle;
|
||||
desc.storageMode = MTLStorageModePrivate;
|
||||
|
||||
if (readable)
|
||||
|
||||
@@ -149,7 +149,7 @@ love::graphics::StreamBuffer *Graphics::newStreamBuffer(BufferType type, size_t
|
||||
|
||||
love::graphics::Texture *Graphics::newTexture(const Texture::Settings &settings, const Texture::Slices *data)
|
||||
{
|
||||
return new Texture(settings, data);
|
||||
return new Texture(this, settings, data);
|
||||
}
|
||||
|
||||
love::graphics::ShaderStage *Graphics::newShaderStageInternal(ShaderStage::StageType stage, const std::string &cachekey, const std::string &source, bool gles)
|
||||
|
||||
@@ -188,8 +188,8 @@ static GLenum newRenderbuffer(int width, int height, int &samples, PixelFormat p
|
||||
return status;
|
||||
}
|
||||
|
||||
Texture::Texture(const Settings &settings, const Slices *data)
|
||||
: love::graphics::Texture(settings, data)
|
||||
Texture::Texture(love::graphics::Graphics *gfx, const Settings &settings, const Slices *data)
|
||||
: love::graphics::Texture(gfx, settings, data)
|
||||
, slices(settings.type)
|
||||
, fbo(0)
|
||||
, texture(0)
|
||||
|
||||
@@ -38,7 +38,7 @@ class Texture final : public love::graphics::Texture, public Volatile
|
||||
{
|
||||
public:
|
||||
|
||||
Texture(const Settings &settings, const Slices *data);
|
||||
Texture(love::graphics::Graphics *gfx, const Settings &settings, const Slices *data);
|
||||
|
||||
virtual ~Texture();
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ enum BufferType
|
||||
{
|
||||
BUFFER_VERTEX = 0,
|
||||
BUFFER_INDEX,
|
||||
BUFFER_UNIFORM,
|
||||
BUFFER_MAX_ENUM
|
||||
};
|
||||
|
||||
@@ -223,9 +224,9 @@ struct BufferBindings
|
||||
|
||||
struct AttributeInfo
|
||||
{
|
||||
DataType type;
|
||||
uint8 components;
|
||||
uint8 bufferIndex;
|
||||
DataType type : 4;
|
||||
uint8 components : 4;
|
||||
uint16 offsetFromVertex;
|
||||
};
|
||||
|
||||
|
||||
@@ -44,6 +44,11 @@ GLSL.SYNTAX = [[
|
||||
#else
|
||||
#define LOVE_HIGHP_OR_MEDIUMP mediump
|
||||
#endif
|
||||
#if __VERSION__ >= 300
|
||||
#define LOVE_IO_LOCATION(x) layout (location = x)
|
||||
#else
|
||||
#define LOVE_IO_LOCATION(x)
|
||||
#endif
|
||||
#define number float
|
||||
#define Image sampler2D
|
||||
#define ArrayImage sampler2DArray
|
||||
@@ -71,7 +76,13 @@ GLSL.UNIFORMS = [[
|
||||
// According to the GLSL ES 1.0 spec, uniform precision must match between stages,
|
||||
// but we can't guarantee that highp is always supported in fragment shaders...
|
||||
// We *really* don't want to use mediump for these in vertex shaders though.
|
||||
#ifdef LOVE_USE_UNIFORM_BUFFERS
|
||||
layout (std140) uniform love_UniformsPerDrawBuffer {
|
||||
LOVE_HIGHP_OR_MEDIUMP vec4 love_UniformsPerDraw[13];
|
||||
};
|
||||
#else
|
||||
uniform LOVE_HIGHP_OR_MEDIUMP vec4 love_UniformsPerDraw[13];
|
||||
#endif
|
||||
|
||||
// These are initialized in love_initializeBuiltinUniforms below. GLSL ES can't
|
||||
// do it as an initializer.
|
||||
@@ -91,6 +102,7 @@ LOVE_HIGHP_OR_MEDIUMP vec4 ConstantColor;
|
||||
#define ViewNormalFromLocal NormalMatrix
|
||||
|
||||
void love_initializeBuiltinUniforms() {
|
||||
#if 1
|
||||
TransformMatrix = mat4(
|
||||
love_UniformsPerDraw[0],
|
||||
love_UniformsPerDraw[1],
|
||||
@@ -113,6 +125,7 @@ void love_initializeBuiltinUniforms() {
|
||||
|
||||
love_ScreenSize = love_UniformsPerDraw[11];
|
||||
ConstantColor = love_UniformsPerDraw[12];
|
||||
#endif
|
||||
}
|
||||
]]
|
||||
|
||||
@@ -247,9 +260,9 @@ void setPointSize() {
|
||||
}]],
|
||||
|
||||
MAIN = [[
|
||||
attribute vec4 VertexPosition;
|
||||
attribute vec4 VertexTexCoord;
|
||||
attribute vec4 VertexColor;
|
||||
LOVE_IO_LOCATION(0) attribute vec4 VertexPosition;
|
||||
LOVE_IO_LOCATION(1) attribute vec4 VertexTexCoord;
|
||||
LOVE_IO_LOCATION(2) attribute vec4 VertexColor;
|
||||
|
||||
varying vec4 VaryingTexCoord;
|
||||
varying vec4 VaryingColor;
|
||||
@@ -280,10 +293,10 @@ GLSL.PIXEL = {
|
||||
// TODO: We should use reflection or something instead of this, to determine
|
||||
// how many outputs are actually used in the shader code.
|
||||
#ifdef LOVE_MULTI_RENDER_TARGETS
|
||||
layout(location = 0) out vec4 love_RenderTargets[love_MaxRenderTargets];
|
||||
LOVE_IO_LOCATION(0) out vec4 love_RenderTargets[love_MaxRenderTargets];
|
||||
#define love_PixelColor love_RenderTargets[0]
|
||||
#else
|
||||
layout(location = 0) out vec4 love_PixelColor;
|
||||
LOVE_IO_LOCATION(0) out vec4 love_PixelColor;
|
||||
#endif
|
||||
#else
|
||||
#ifdef LOVE_MULTI_RENDER_TARGETS
|
||||
@@ -352,7 +365,7 @@ local function getLanguageTarget(code)
|
||||
return (code:match("^%s*#pragma language (%w+)")) or "glsl1"
|
||||
end
|
||||
|
||||
local function createShaderStageCode(stage, code, lang, gles, glsl1on3, gammacorrect, custom, multirendertarget)
|
||||
local function createShaderStageCode(stage, code, lang, gles, glsl1on3, gammacorrect, custom, multirendertarget, useubo)
|
||||
stage = stage:upper()
|
||||
local lines = {
|
||||
GLSL.VERSION[lang][gles],
|
||||
@@ -360,6 +373,7 @@ local function createShaderStageCode(stage, code, lang, gles, glsl1on3, gammacor
|
||||
glsl1on3 and "#define LOVE_GLSL1_ON_GLSL3 1" or "",
|
||||
gammacorrect and "#define LOVE_GAMMA_CORRECT 1" or "",
|
||||
multirendertarget and "#define LOVE_MULTI_RENDER_TARGETS 1" or "",
|
||||
useubo and "#define LOVE_USE_UNIFORM_BUFFERS 1" or "",
|
||||
GLSL.SYNTAX,
|
||||
GLSL[stage].HEADER,
|
||||
GLSL.UNIFORMS,
|
||||
@@ -420,6 +434,8 @@ function love.graphics._shaderCodeToGLSL(gles, arg1, arg2)
|
||||
local supportsGLSL3 = graphicsfeatures.glsl3
|
||||
local supportsGLSL4 = graphicsfeatures.glsl4
|
||||
local gammacorrect = love.graphics.isGammaCorrect()
|
||||
local renderer = love.graphics.getRenderer()
|
||||
local useubo = renderer == "Metal"
|
||||
|
||||
local targetlang = getLanguageTarget(pixelcode or vertexcode)
|
||||
if getLanguageTarget(vertexcode or pixelcode) ~= targetlang then
|
||||
@@ -446,10 +462,10 @@ function love.graphics._shaderCodeToGLSL(gles, arg1, arg2)
|
||||
end
|
||||
|
||||
if vertexcode then
|
||||
vertexcode = createShaderStageCode("VERTEX", vertexcode, lang, gles, glsl1on3, gammacorrect)
|
||||
vertexcode = createShaderStageCode("VERTEX", vertexcode, lang, gles, glsl1on3, gammacorrect, false, false, useubo)
|
||||
end
|
||||
if pixelcode then
|
||||
pixelcode = createShaderStageCode("PIXEL", pixelcode, lang, gles, glsl1on3, gammacorrect, is_custompixel, is_multicanvas)
|
||||
pixelcode = createShaderStageCode("PIXEL", pixelcode, lang, gles, glsl1on3, gammacorrect, is_custompixel, is_multicanvas, useubo)
|
||||
end
|
||||
|
||||
return vertexcode, pixelcode
|
||||
@@ -485,14 +501,17 @@ local langs = {
|
||||
essl3 = {target="glsl3", gles=true},
|
||||
}
|
||||
|
||||
-- FIXME: this is temporary until a glslang pull request is merged in.
|
||||
local useubo = true
|
||||
|
||||
for lang, info in pairs(langs) do
|
||||
for _, gammacorrect in ipairs{false, true} do
|
||||
local t = gammacorrect and defaults_gammacorrect or defaults
|
||||
t[lang] = {
|
||||
vertex = createShaderStageCode("VERTEX", defaultcode.vertex, info.target, info.gles, false, gammacorrect),
|
||||
pixel = createShaderStageCode("PIXEL", defaultcode.pixel, info.target, info.gles, false, gammacorrect, false),
|
||||
videopixel = createShaderStageCode("PIXEL", defaultcode.videopixel, info.target, info.gles, false, gammacorrect, true),
|
||||
arraypixel = createShaderStageCode("PIXEL", defaultcode.arraypixel, info.target, info.gles, false, gammacorrect, true),
|
||||
vertex = createShaderStageCode("VERTEX", defaultcode.vertex, info.target, info.gles, false, gammacorrect, false, false, useubo),
|
||||
pixel = createShaderStageCode("PIXEL", defaultcode.pixel, info.target, info.gles, false, gammacorrect, false, false, useubo),
|
||||
videopixel = createShaderStageCode("PIXEL", defaultcode.videopixel, info.target, info.gles, false, gammacorrect, true, false, useubo),
|
||||
arraypixel = createShaderStageCode("PIXEL", defaultcode.arraypixel, info.target, info.gles, false, gammacorrect, true, false, useubo),
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user