From 9d2dca5740c8096ab3380c2fdb1c65bc358fa8a8 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sat, 13 Jun 2020 20:29:23 -0300 Subject: [PATCH] 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 --- src/modules/graphics/Texture.cpp | 4 +- src/modules/graphics/Texture.h | 2 +- src/modules/graphics/metal/Graphics.h | 16 ++- src/modules/graphics/metal/Graphics.mm | 140 +++++++++++++++++-- src/modules/graphics/metal/Metal.h | 9 +- src/modules/graphics/metal/Metal.mm | 9 +- src/modules/graphics/metal/Shader.h | 17 ++- src/modules/graphics/metal/Shader.mm | 114 +++++++++++++-- src/modules/graphics/metal/Texture.h | 2 +- src/modules/graphics/metal/Texture.mm | 10 +- src/modules/graphics/opengl/Graphics.cpp | 2 +- src/modules/graphics/opengl/Texture.cpp | 4 +- src/modules/graphics/opengl/Texture.h | 2 +- src/modules/graphics/vertex.h | 5 +- src/modules/graphics/wrap_GraphicsShader.lua | 43 ++++-- 15 files changed, 324 insertions(+), 55 deletions(-) diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index b20b2b7d9..266904468 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -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(Module::M_GRAPHICS); - if (slices != nullptr && slices->getMipmapCount() > 0 && slices->getSliceCount() > 0) { texType = slices->getTextureType(); diff --git a/src/modules/graphics/Texture.h b/src/modules/graphics/Texture.h index 1f4e52671..9db40ff6f 100644 --- a/src/modules/graphics/Texture.h +++ b/src/modules/graphics/Texture.h @@ -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. diff --git a/src/modules/graphics/metal/Graphics.h b/src/modules/graphics/metal/Graphics.h index b2d39aeb4..b664d7117 100644 --- a/src/modules/graphics/metal/Graphics.h +++ b/src/modules/graphics/metal/Graphics.h @@ -109,12 +109,17 @@ public: id getCachedSampler(const SamplerState &s); - static Graphics *getInstance() { return Module::getInstance(M_GRAPHICS); } + StreamBuffer *getUniformBuffer() const { return uniformBuffer; } + Buffer *getDefaultAttributesBuffer() const { return defaultAttributesBuffer; } + + static Graphics *getInstance() { return graphicsInstance; } id device; private: + static Graphics *graphicsInstance; + enum StateType { STATE_BLEND, @@ -166,6 +171,7 @@ private: id getCachedDepthStencilState(const DepthState &depth, const StencilState &stencil); void applyRenderState(id renderEncoder, const vertex::Attributes &attributes); + void applyShaderUniforms(id renderEncoder, Shader *shader); id 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 cachedSamplers; }; // Graphics diff --git a/src/modules/graphics/metal/Graphics.mm b/src/modules/graphics/metal/Graphics.mm index 012e31aec..096834ff1 100644 --- a/src/modules/graphics/metal/Graphics.mm +++ b/src/modules/graphics/metal/Graphics.mm @@ -26,6 +26,7 @@ #include "ShaderStage.h" #include "window/Window.h" #include "image/Image.h" +#include "common/memory.h" #import @@ -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(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 Graphics::useRenderEncoder() } renderEncoder = [useCommandBuffer() renderCommandEncoderWithDescriptor:passDesc]; + + id defaultbuffer = (__bridge id)(void *)defaultAttributesBuffer->getHandle(); + [renderEncoder setVertexBuffer:defaultbuffer offset:0 atIndex:DEFAULT_VERTEX_BUFFER_BINDING]; + dirtyRenderState = STATEBIT_ALL; } @@ -530,16 +565,85 @@ void Graphics::applyRenderState(id encoder, const verte dirtyRenderState = 0; } +void Graphics::applyShaderUniforms(id 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 buffer = (__bridge id)(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 encoder = useRenderEncoder(); applyRenderState(encoder, *cmd.attributes); + applyShaderUniforms(encoder, Shader::current); - id mtltexture = (__bridge id)(void *) cmd.texture->getHandle(); + love::graphics::Texture *texture = cmd.texture; + if (texture == nullptr) + texture = defaultTextures[TEXTURE_2D]; + + id mtltexture = (__bridge id)(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 buffer = (__bridge id)(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 encoder = useRenderEncoder(); applyRenderState(encoder, *cmd.attributes); + applyShaderUniforms(encoder, Shader::current); - id mtltexture = (__bridge id)(void *) cmd.texture->getHandle(); + love::graphics::Texture *texture = cmd.texture; + if (texture == nullptr) + texture = defaultTextures[TEXTURE_2D]; + + id mtltexture = (__bridge id)(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 buffer = (__bridge id)(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 encoder = useRenderEncoder(); applyRenderState(encoder, attributes); + applyShaderUniforms(encoder, Shader::current); + + if (texture == nullptr) + texture = defaultTextures[TEXTURE_2D]; id mtltexture = (__bridge id)(void *) texture->getHandle(); @@ -632,7 +745,7 @@ void Graphics::drawQuads(int start, int count, const vertex::Attributes &attribu { auto b = buffers.info[i]; id buffer = (__bridge id)(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 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) diff --git a/src/modules/graphics/metal/Metal.h b/src/modules/graphics/metal/Metal.h index 0e15a2b80..087cb2595 100644 --- a/src/modules/graphics/metal/Metal.h +++ b/src/modules/graphics/metal/Metal.h @@ -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 diff --git a/src/modules/graphics/metal/Metal.mm b/src/modules/graphics/metal/Metal.mm index f6b0427ec..53707816c 100644 --- a/src/modules/graphics/metal/Metal.mm +++ b/src/modules/graphics/metal/Metal.mm @@ -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; diff --git a/src/modules/graphics/metal/Shader.h b/src/modules/graphics/metal/Shader.h index f18cfed94..61126cd42 100644 --- a/src/modules/graphics/metal/Shader.h +++ b/src/modules/graphics/metal/Shader.h @@ -30,6 +30,7 @@ #import #include +#include #include 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 getCachedRenderPipeline(const RenderPipelineKey &key); + static int getUniformBufferBinding(); + private: struct RenderPipelineHasher @@ -92,6 +98,11 @@ private: id functions[ShaderStage::STAGE_MAX_ENUM]; + UniformInfo *builtinUniformInfo[BUILTIN_MAX_ENUM]; + std::map uniforms; + + std::map attributes; + std::unordered_map cachedRenderPipelines; }; // Metal diff --git a/src/modules/graphics/metal/Shader.mm b/src/modules/graphics/metal/Shader.mm index 3aa4a1a25..49f339153 100644 --- a/src/modules/graphics/metal/Shader.mm +++ b/src/modules/graphics/metal/Shader.mm @@ -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 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 Shader::getCachedRenderPipeline(const RenderPipelineKey &key) { auto it = cachedRenderPipelines.find(key); @@ -253,9 +327,8 @@ id 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 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 Shader::getCachedRenderPipeline(const RenderPipelineK return pipeline; } +int Shader::getUniformBufferBinding() +{ + return spirv_cross::ResourceBindingPushConstantBinding; +} + } // metal } // graphics } // love diff --git a/src/modules/graphics/metal/Texture.h b/src/modules/graphics/metal/Texture.h index 0c4fd128d..7e7ac1438 100644 --- a/src/modules/graphics/metal/Texture.h +++ b/src/modules/graphics/metal/Texture.h @@ -37,7 +37,7 @@ class Texture final : public love::graphics::Texture { public: - Texture(id device, const Settings &settings, const Slices *data); + Texture(love::graphics::Graphics *gfx, id device, const Settings &settings, const Slices *data); virtual ~Texture(); void generateMipmaps() override; diff --git a/src/modules/graphics/metal/Texture.mm b/src/modules/graphics/metal/Texture.mm index 7fff37932..2d2e484d1 100644 --- a/src/modules/graphics/metal/Texture.mm +++ b/src/modules/graphics/metal/Texture.mm @@ -41,8 +41,8 @@ static MTLTextureType getMTLTextureType(TextureType type, int msaa) return MTLTextureType2D; } -Texture::Texture(id device, const Settings &settings, const Slices *data) - : love::graphics::Texture(settings, data) +Texture::Texture(love::graphics::Graphics *gfx, id 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 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) diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index fc4b21ddf..8a5c178ff 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -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) diff --git a/src/modules/graphics/opengl/Texture.cpp b/src/modules/graphics/opengl/Texture.cpp index b54b42eb0..0b1fe9021 100644 --- a/src/modules/graphics/opengl/Texture.cpp +++ b/src/modules/graphics/opengl/Texture.cpp @@ -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) diff --git a/src/modules/graphics/opengl/Texture.h b/src/modules/graphics/opengl/Texture.h index 4f0d871d3..a63723552 100644 --- a/src/modules/graphics/opengl/Texture.h +++ b/src/modules/graphics/opengl/Texture.h @@ -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(); diff --git a/src/modules/graphics/vertex.h b/src/modules/graphics/vertex.h index 8d4e75dcc..aafbe1322 100644 --- a/src/modules/graphics/vertex.h +++ b/src/modules/graphics/vertex.h @@ -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; }; diff --git a/src/modules/graphics/wrap_GraphicsShader.lua b/src/modules/graphics/wrap_GraphicsShader.lua index f0631c6f6..3c74e63e7 100644 --- a/src/modules/graphics/wrap_GraphicsShader.lua +++ b/src/modules/graphics/wrap_GraphicsShader.lua @@ -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