diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index 1ad92302b..c25f58ae8 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -781,8 +781,6 @@ FA18CED723DBC6E000263725 /* Shader.h in Headers */ = {isa = PBXBuildFile; fileRef = FA18CECD23DBC6E000263725 /* Shader.h */; }; FA18CED823DBC6E000263725 /* StreamBuffer.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA18CECE23DBC6E000263725 /* StreamBuffer.mm */; }; FA18CED923DBC6E000263725 /* StreamBuffer.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA18CECE23DBC6E000263725 /* StreamBuffer.mm */; }; - FA18CEDA23DBC6E000263725 /* Canvas.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA18CECF23DBC6E000263725 /* Canvas.mm */; }; - FA18CEDB23DBC6E000263725 /* Canvas.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA18CECF23DBC6E000263725 /* Canvas.mm */; }; FA18CEDC23DBC6E000263725 /* Metal.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA18CED023DBC6E000263725 /* Metal.mm */; }; FA18CEDD23DBC6E000263725 /* Metal.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA18CED023DBC6E000263725 /* Metal.mm */; }; FA18CEDE23DBC6E000263725 /* Shader.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA18CED123DBC6E000263725 /* Shader.mm */; }; @@ -792,13 +790,11 @@ FA18CEE223DBC6E000263725 /* Graphics.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA18CED323DBC6E000263725 /* Graphics.mm */; }; FA18CEE323DBC6E000263725 /* Metal.h in Headers */ = {isa = PBXBuildFile; fileRef = FA18CED423DBC6E000263725 /* Metal.h */; }; FA18CEE423DBC6E000263725 /* Graphics.h in Headers */ = {isa = PBXBuildFile; fileRef = FA18CED523DBC6E000263725 /* Graphics.h */; }; - FA18CEE523DBC6E000263725 /* Canvas.h in Headers */ = {isa = PBXBuildFile; fileRef = FA18CED623DBC6E000263725 /* Canvas.h */; }; FA18CEE723DBC6F700263725 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA18CEE623DBC6F700263725 /* Metal.framework */; }; FA18CEE923DBC8D400263725 /* Buffer.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA18CEE823DBC8D400263725 /* Buffer.mm */; }; FA18CEEA23DBC8D400263725 /* Buffer.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA18CEE823DBC8D400263725 /* Buffer.mm */; }; - FA18CEEE23DC9B3E00263725 /* Image.h in Headers */ = {isa = PBXBuildFile; fileRef = FA18CEEC23DC9B3E00263725 /* Image.h */; }; - FA18CEEF23DC9B3E00263725 /* Image.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA18CEED23DC9B3E00263725 /* Image.mm */; }; - FA18CEF023DC9B3E00263725 /* Image.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA18CEED23DC9B3E00263725 /* Image.mm */; }; + FA18CEEF23DC9B3E00263725 /* Texture.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA18CEED23DC9B3E00263725 /* Texture.mm */; }; + FA18CEF023DC9B3E00263725 /* Texture.mm in Sources */ = {isa = PBXBuildFile; fileRef = FA18CEED23DC9B3E00263725 /* Texture.mm */; }; FA18CF1623DCF67900263725 /* spirv_parser.hpp in Headers */ = {isa = PBXBuildFile; fileRef = FA18CEF223DCF67800263725 /* spirv_parser.hpp */; }; FA18CF1723DCF67900263725 /* spirv_glsl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA18CEF323DCF67800263725 /* spirv_glsl.cpp */; }; FA18CF1823DCF67900263725 /* spirv_glsl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA18CEF323DCF67800263725 /* spirv_glsl.cpp */; }; @@ -1855,19 +1851,17 @@ FA15DFAB1F9B8C850042AB22 /* StringMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StringMap.cpp; sourceTree = ""; }; FA18CECD23DBC6E000263725 /* Shader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Shader.h; sourceTree = ""; }; FA18CECE23DBC6E000263725 /* StreamBuffer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = StreamBuffer.mm; sourceTree = ""; }; - FA18CECF23DBC6E000263725 /* Canvas.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Canvas.mm; sourceTree = ""; }; FA18CED023DBC6E000263725 /* Metal.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Metal.mm; sourceTree = ""; }; FA18CED123DBC6E000263725 /* Shader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Shader.mm; sourceTree = ""; }; FA18CED223DBC6E000263725 /* StreamBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StreamBuffer.h; sourceTree = ""; }; FA18CED323DBC6E000263725 /* Graphics.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Graphics.mm; sourceTree = ""; }; FA18CED423DBC6E000263725 /* Metal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Metal.h; sourceTree = ""; }; FA18CED523DBC6E000263725 /* Graphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Graphics.h; sourceTree = ""; }; - FA18CED623DBC6E000263725 /* Canvas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Canvas.h; sourceTree = ""; }; FA18CEE623DBC6F700263725 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; }; FA18CEE823DBC8D400263725 /* Buffer.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = Buffer.mm; sourceTree = ""; }; FA18CEEB23DBC8EB00263725 /* Buffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Buffer.h; sourceTree = ""; }; - FA18CEEC23DC9B3E00263725 /* Image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Image.h; sourceTree = ""; }; - FA18CEED23DC9B3E00263725 /* Image.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Image.mm; sourceTree = ""; }; + FA18CEEC23DC9B3E00263725 /* Texture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Texture.h; sourceTree = ""; }; + FA18CEED23DC9B3E00263725 /* Texture.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Texture.mm; sourceTree = ""; }; FA18CEF223DCF67800263725 /* spirv_parser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = spirv_parser.hpp; sourceTree = ""; }; FA18CEF323DCF67800263725 /* spirv_glsl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_glsl.cpp; sourceTree = ""; }; FA18CEF423DCF67800263725 /* spirv_cross_error_handling.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = spirv_cross_error_handling.hpp; sourceTree = ""; }; @@ -3473,12 +3467,8 @@ children = ( FA18CEEB23DBC8EB00263725 /* Buffer.h */, FA18CEE823DBC8D400263725 /* Buffer.mm */, - FA18CED623DBC6E000263725 /* Canvas.h */, - FA18CECF23DBC6E000263725 /* Canvas.mm */, FA18CED523DBC6E000263725 /* Graphics.h */, FA18CED323DBC6E000263725 /* Graphics.mm */, - FA18CEEC23DC9B3E00263725 /* Image.h */, - FA18CEED23DC9B3E00263725 /* Image.mm */, FA18CED423DBC6E000263725 /* Metal.h */, FA18CED023DBC6E000263725 /* Metal.mm */, FA18CECD23DBC6E000263725 /* Shader.h */, @@ -3487,6 +3477,8 @@ FA18CF4423DD1A8000263725 /* ShaderStage.mm */, FA18CED223DBC6E000263725 /* StreamBuffer.h */, FA18CECE23DBC6E000263725 /* StreamBuffer.mm */, + FA18CEEC23DC9B3E00263725 /* Texture.h */, + FA18CEED23DC9B3E00263725 /* Texture.mm */, ); path = metal; sourceTree = ""; @@ -4141,7 +4133,6 @@ FA0B7E2F1A95902C000E1D17 /* RopeJoint.h in Headers */, FA0B7D141A95902C000E1D17 /* Font.h in Headers */, FA0B7E591A95902C000E1D17 /* wrap_Joint.h in Headers */, - FA18CEE523DBC6E000263725 /* Canvas.h in Headers */, FA0B7A631A958EA3000E1D17 /* b2ContactManager.h in Headers */, FA0B7E771A95902C000E1D17 /* wrap_WeldJoint.h in Headers */, FA0B7A911A958EA3000E1D17 /* b2FrictionJoint.h in Headers */, @@ -4600,7 +4591,6 @@ FA0B7A3F1A958EA3000E1D17 /* b2ChainShape.cpp in Sources */, FA0B7E921A95902C000E1D17 /* ModPlugDecoder.cpp in Sources */, FA0B7E521A95902C000E1D17 /* wrap_FrictionJoint.cpp in Sources */, - FA18CEDB23DBC6E000263725 /* Canvas.mm in Sources */, FADF54351E3DAE6E00012CC0 /* wrap_SpriteBatch.cpp in Sources */, FA4F2BB51DE1E4C300CA37D7 /* wrap_RecordingDevice.cpp in Sources */, FA0B7A311A958EA3000E1D17 /* b2CollidePolygon.cpp in Sources */, @@ -4700,7 +4690,7 @@ FA0B7CD41A95902C000E1D17 /* Source.cpp in Sources */, FAA3A9AF1B7D465A00CED060 /* android.cpp in Sources */, FAE64A812071363100BC7981 /* physfs_archiver_dir.c in Sources */, - FA18CEF023DC9B3E00263725 /* Image.mm in Sources */, + FA18CEF023DC9B3E00263725 /* Texture.mm in Sources */, FA0B7CD11A95902C000E1D17 /* Audio.cpp in Sources */, FA4F2B7B1DE0181B00CA37D7 /* xxhash.c in Sources */, FA0B7D131A95902C000E1D17 /* Font.cpp in Sources */, @@ -4984,7 +4974,6 @@ FA0B7E0F1A95902C000E1D17 /* FrictionJoint.cpp in Sources */, FA620A351AA2F8DB005DB4C2 /* wrap_Texture.cpp in Sources */, FAF140771E20934C00F898D2 /* iomapper.cpp in Sources */, - FA18CEDA23DBC6E000263725 /* Canvas.mm in Sources */, FA0B7D091A95902C000E1D17 /* wrap_FileData.cpp in Sources */, FA18CEDC23DBC6E000263725 /* Metal.mm in Sources */, FA0B7B341A958EA3000E1D17 /* wuff_convert.c in Sources */, @@ -5310,7 +5299,7 @@ FA0B7D281A95902C000E1D17 /* wrap_GlyphData.cpp in Sources */, FA0B7DE21A95902C000E1D17 /* wrap_RandomGenerator.cpp in Sources */, FAF6C9F223C2DE2900D7B5BC /* SPVRemapper.cpp in Sources */, - FA18CEEF23DC9B3E00263725 /* Image.mm in Sources */, + FA18CEEF23DC9B3E00263725 /* Texture.mm in Sources */, FACA02F61F5E396B0084B28F /* wrap_DataModule.cpp in Sources */, FA0B79401A958E3B000E1D17 /* utf8.cpp in Sources */, FA0B79241A958E3B000E1D17 /* Exception.cpp in Sources */, diff --git a/src/modules/graphics/metal/Canvas.mm b/src/modules/graphics/metal/Canvas.mm deleted file mode 100644 index 55e15e577..000000000 --- a/src/modules/graphics/metal/Canvas.mm +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright (c) 2006-2020 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#include "Canvas.h" -#include "Graphics.h" - -namespace love -{ -namespace graphics -{ -namespace metal -{ - -Canvas::Canvas(id device, const Settings &settings) - : love::graphics::Canvas(settings) -{ @autoreleasepool { - MTLTextureDescriptor *desc = [MTLTextureDescriptor new]; - - // TODO: sampleCount validation - desc.sampleCount = getRequestedMSAA(); - - desc.width = pixelWidth; - desc.height = pixelHeight; - desc.depth = depth; - desc.arrayLength = layers; - desc.mipmapLevelCount = mipmapCount; - desc.textureType = Metal::getTextureType(texType, getRequestedMSAA()); - - bool sRGB = false; - desc.pixelFormat = Metal::convertPixelFormat(format, sRGB); - - desc.storageMode = MTLStorageModePrivate; - desc.usage = MTLTextureUsageRenderTarget; - - if (isReadable()) - desc.usage |= MTLTextureUsageShaderRead; - - texture = [device newTextureWithDescriptor:desc]; - - if (texture == nil) - throw love::Exception("Out of graphics memory."); - - // TODO: initialize texture to transparent black. -}} - -Canvas::~Canvas() -{ @autoreleasepool { - texture = nil; -}} - -void Canvas::generateMipmaps() -{ @autoreleasepool { - id encoder = Graphics::getInstance()->useBlitEncoder(); - [encoder generateMipmapsForTexture:texture]; -}} - -} // metal -} // graphics -} // love diff --git a/src/modules/graphics/metal/Graphics.h b/src/modules/graphics/metal/Graphics.h index d7aa86f63..b947ce04f 100644 --- a/src/modules/graphics/metal/Graphics.h +++ b/src/modules/graphics/metal/Graphics.h @@ -40,9 +40,7 @@ public: // Implements Module. const char *getName() const override { return "love.graphics.metal"; } - love::graphics::Image *newImage(const Image::Slices &data, const Image::Settings &settings) override; - love::graphics::Image *newImage(TextureType textype, PixelFormat format, int width, int height, int slices, const Image::Settings &settings) override; - love::graphics::Canvas *newCanvas(const Canvas::Settings &settings) override; + love::graphics::Texture *newTexture(const Texture::Settings &settings, const Texture::Slices *data = nullptr) override; love::graphics::Buffer *newBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags) override; void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override; @@ -53,7 +51,7 @@ public: void draw(const DrawCommand &cmd) override; void draw(const DrawIndexedCommand &cmd) override; - void drawQuads(int start, int count, const vertex::Attributes &attributes, const vertex::BufferBindings &buffers, Texture *texture) override; + void drawQuads(int start, int count, const vertex::Attributes &attributes, const vertex::BufferBindings &buffers, love::graphics::Texture *texture) override; void clear(OptionalColorf color, OptionalInt stencil, OptionalDouble depth) override; void clear(const std::vector &colors, OptionalInt stencil, OptionalDouble depth) override; @@ -83,10 +81,9 @@ public: void setPointSize(float size) override; void setWireframe(bool enable) override; - - bool isCanvasFormatSupported(PixelFormat format) const override; - bool isCanvasFormatSupported(PixelFormat format, bool readable) const override; - bool isImageFormatSupported(PixelFormat format, bool sRGB) const override; + + PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable, bool sRGB) const override; + bool isPixelFormatSupported(PixelFormat format, bool rendertarget, bool readable, bool sRGB = false) override; Renderer getRenderer() const override; bool usesGLSLES() const override; RendererInfo getRendererInfo() const override; @@ -105,7 +102,7 @@ public: id getBlitEncoder() const { return blitEncoder; } void submitBlitEncoder(); - id getCachedSampler(const Texture::Filter &f, const Texture::Wrap &w, float maxAnisotropy, Optional depthSampleMode); + id getCachedSampler(const SamplerState &s); static Graphics *getInstance() { return Module::getInstance(M_GRAPHICS); } @@ -164,7 +161,7 @@ private: love::graphics::ShaderStage *newShaderStageInternal(ShaderStage::StageType stage, const std::string &cachekey, const std::string &source, bool gles) override; love::graphics::Shader *newShaderInternal(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage *pixel) override; love::graphics::StreamBuffer *newStreamBuffer(BufferType type, size_t size) override; - void setCanvasInternal(const RenderTargets &rts, int w, int h, int pixelw, int pixelh, bool hasSRGBcanvas) override; + void setRenderTargetsInternal(const RenderTargets &rts, int w, int h, int pixelw, int pixelh, bool hasSRGBcanvas) override; void initCapabilities() override; void getAPIStats(int &shaderswitches) const override; diff --git a/src/modules/graphics/metal/Graphics.mm b/src/modules/graphics/metal/Graphics.mm index 7becbc481..9c8ed905f 100644 --- a/src/modules/graphics/metal/Graphics.mm +++ b/src/modules/graphics/metal/Graphics.mm @@ -21,8 +21,7 @@ #include "Graphics.h" #include "StreamBuffer.h" #include "Buffer.h" -#include "Canvas.h" -#include "Image.h" +#include "Texture.h" #include "Shader.h" #include "window/Window.h" #include "image/Image.h" @@ -34,44 +33,43 @@ namespace graphics namespace metal { -static MTLSamplerMinMagFilter getMTLSamplerFilter(Texture::FilterMode mode) +static MTLSamplerMinMagFilter getMTLSamplerFilter(SamplerState::FilterMode mode) { switch (mode) { - case Texture::FILTER_NONE: return MTLSamplerMinMagFilterLinear; - case Texture::FILTER_LINEAR: return MTLSamplerMinMagFilterLinear; - case Texture::FILTER_NEAREST: return MTLSamplerMinMagFilterNearest; - case Texture::FILTER_MAX_ENUM: return MTLSamplerMinMagFilterLinear; + case SamplerState::FILTER_LINEAR: return MTLSamplerMinMagFilterLinear; + case SamplerState::FILTER_NEAREST: return MTLSamplerMinMagFilterNearest; + case SamplerState::FILTER_MAX_ENUM: return MTLSamplerMinMagFilterLinear; } return MTLSamplerMinMagFilterLinear; } -static MTLSamplerMipFilter getMTLSamplerMipFilter(Texture::FilterMode mode) +static MTLSamplerMipFilter getMTLSamplerMipFilter(SamplerState::MipmapFilterMode mode) { switch (mode) { - case Texture::FILTER_NONE: return MTLSamplerMipFilterNotMipmapped; - case Texture::FILTER_LINEAR: return MTLSamplerMipFilterLinear; - case Texture::FILTER_NEAREST: return MTLSamplerMipFilterNearest; - case Texture::FILTER_MAX_ENUM: return MTLSamplerMipFilterNotMipmapped; + case SamplerState::MIPMAP_FILTER_NONE: return MTLSamplerMipFilterNotMipmapped; + case SamplerState::MIPMAP_FILTER_LINEAR: return MTLSamplerMipFilterLinear; + case SamplerState::MIPMAP_FILTER_NEAREST: return MTLSamplerMipFilterNearest; + case SamplerState::MIPMAP_FILTER_MAX_ENUM: return MTLSamplerMipFilterNotMipmapped; } return MTLSamplerMipFilterNotMipmapped; } -static MTLSamplerAddressMode getMTLSamplerAddressMode(Texture::WrapMode mode) +static MTLSamplerAddressMode getMTLSamplerAddressMode(SamplerState::WrapMode mode) { switch (mode) { - case Texture::WRAP_CLAMP: return MTLSamplerAddressModeClampToEdge; - case Texture::WRAP_CLAMP_ZERO: return MTLSamplerAddressModeClampToZero; + case SamplerState::WRAP_CLAMP: return MTLSamplerAddressModeClampToEdge; + case SamplerState::WRAP_CLAMP_ZERO: return MTLSamplerAddressModeClampToZero; #ifdef LOVE_MACOS - case Texture::WRAP_CLAMP_ONE: return MTLSamplerAddressModeClampToBorderColor; + case SamplerState::WRAP_CLAMP_ONE: return MTLSamplerAddressModeClampToBorderColor; #else - case Texture::WRAP_CLAMP_ONE: return MTLSamplerAddressModeClampToZero; + case SamplerState::WRAP_CLAMP_ONE: return MTLSamplerAddressModeClampToZero; #endif - case Texture::WRAP_REPEAT: return MTLSamplerAddressModeRepeat; - case Texture::WRAP_MIRRORED_REPEAT: return MTLSamplerAddressModeMirrorRepeat; - case Texture::WRAP_MAX_ENUM: return MTLSamplerAddressModeClampToEdge; + case SamplerState::WRAP_REPEAT: return MTLSamplerAddressModeRepeat; + case SamplerState::WRAP_MIRRORED_REPEAT: return MTLSamplerAddressModeMirrorRepeat; + case SamplerState::WRAP_MAX_ENUM: return MTLSamplerAddressModeClampToEdge; } return MTLSamplerAddressModeClampToEdge; } @@ -202,19 +200,9 @@ love::graphics::StreamBuffer *Graphics::newStreamBuffer(BufferType type, size_t return CreateStreamBuffer(device, type, size); } -love::graphics::Image *Graphics::newImage(const Image::Slices &data, const Image::Settings &settings) +love::graphics::Texture *Graphics::newTexture(const Texture::Settings &settings, const Texture::Slices *data) { - return new Image(device, data, settings); -} - -love::graphics::Image *Graphics::newImage(TextureType textype, PixelFormat format, int width, int height, int slices, const Image::Settings &settings) -{ - return new Image(device, textype, format, width, height, slices, settings); -} - -love::graphics::Canvas *Graphics::newCanvas(const Canvas::Settings &settings) -{ - return new Canvas(device, settings); + return new Texture(device, settings, data); } love::graphics::ShaderStage *Graphics::newShaderStageInternal(ShaderStage::StageType stage, const std::string &cachekey, const std::string &source, bool gles) @@ -245,9 +233,9 @@ void Graphics::initCapabilities() } } - capabilities.features[FEATURE_MULTI_CANVAS_FORMATS] = true; + capabilities.features[FEATURE_MULTI_RENDER_TARGET_FORMATS] = true; capabilities.features[FEATURE_CLAMP_ZERO] = true; - capabilities.features[FEATURE_BLENDMINMAX] = true; + capabilities.features[FEATURE_BLEND_MINMAX] = true; capabilities.features[FEATURE_LIGHTEN] = true; capabilities.features[FEATURE_FULL_NPOT] = true; capabilities.features[FEATURE_PIXEL_SHADER_HIGHP] = true; @@ -263,8 +251,8 @@ void Graphics::initCapabilities() capabilities.limits[LIMIT_TEXTURE_LAYERS] = 2048; capabilities.limits[LIMIT_VOLUME_TEXTURE_SIZE] = 2048; capabilities.limits[LIMIT_CUBE_TEXTURE_SIZE] = 16384; // TODO - capabilities.limits[LIMIT_MULTI_CANVAS] = 8; // TODO - capabilities.limits[LIMIT_CANVAS_MSAA] = msaa; + capabilities.limits[LIMIT_RENDER_TARGETS] = 8; // TODO + capabilities.limits[LIMIT_TEXTURE_MSAA] = msaa; capabilities.limits[LIMIT_ANISOTROPY] = 16.0f; static_assert(LIMIT_MAX_ENUM == 8, "Graphics::initCapabilities must be updated when adding a new system limit!"); @@ -279,7 +267,7 @@ void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelh this->pixelWidth = pixelwidth; this->pixelHeight = pixelheight; - if (!isCanvasActive()) + if (!isRenderTargetActive()) { dirtyRenderState |= STATEBIT_VIEWPORT | STATEBIT_SCISSOR; @@ -343,10 +331,10 @@ void Graphics::unSetMode() submitCommandBuffer(); - for (auto temp : temporaryCanvases) - temp.canvas->release(); + for (auto temp : temporaryTextures) + temp.texture->release(); - temporaryCanvases.clear(); + temporaryTextures.clear(); created = false; } @@ -418,28 +406,31 @@ void Graphics::submitBlitEncoder() } } -id Graphics::getCachedSampler(const Texture::Filter &f, const Texture::Wrap &w, float maxAnisotropy, Optional depthSampleMode) +id Graphics::getCachedSampler(const SamplerState &s) { @autoreleasepool { id sampler = nil; { MTLSamplerDescriptor *desc = [MTLSamplerDescriptor new]; - desc.minFilter = getMTLSamplerFilter(f.min); - desc.magFilter = getMTLSamplerFilter(f.mag); - desc.mipFilter = getMTLSamplerMipFilter(f.mipmap); - desc.maxAnisotropy = std::max(1.0f, std::min(maxAnisotropy, 16.0f)); + desc.minFilter = getMTLSamplerFilter(s.minFilter); + desc.magFilter = getMTLSamplerFilter(s.magFilter); + desc.mipFilter = getMTLSamplerMipFilter(s.mipmapFilter); + desc.maxAnisotropy = std::max(1.0f, std::min((float)s.maxAnisotropy, 16.0f)); - desc.sAddressMode = getMTLSamplerAddressMode(w.s); - desc.tAddressMode = getMTLSamplerAddressMode(w.t); - desc.rAddressMode = getMTLSamplerAddressMode(w.r); + desc.sAddressMode = getMTLSamplerAddressMode(s.wrapU); + desc.tAddressMode = getMTLSamplerAddressMode(s.wrapV); + desc.rAddressMode = getMTLSamplerAddressMode(s.wrapW); #ifdef LOVE_MACOS desc.borderColor = MTLSamplerBorderColorOpaqueWhite; #endif - if (depthSampleMode.hasValue) - desc.compareFunction = getMTLCompareFunction(depthSampleMode.value); + desc.lodMinClamp = s.minLod; + desc.lodMaxClamp = s.maxLod; + + if (s.depthSampleMode.hasValue) + desc.compareFunction = getMTLCompareFunction(s.depthSampleMode.value); sampler = [device newSamplerStateWithDescriptor:desc]; } @@ -531,10 +522,10 @@ void Graphics::applyRenderState(id encoder) int rth = 0; const auto &rt = state.renderTargets.getFirstTarget(); - if (rt.canvas.get()) + if (rt.texture.get()) { - rtw = rt.canvas->getPixelWidth(); - rth = rt.canvas->getPixelHeight(); + rtw = rt.texture->getPixelWidth(); + rth = rt.texture->getPixelHeight(); } else { @@ -653,7 +644,7 @@ void Graphics::draw(const DrawIndexedCommand &cmd) instanceCount:cmd.instanceCount]; }} -void Graphics::drawQuads(int start, int count, const vertex::Attributes &attributes, const vertex::BufferBindings &buffers, Texture *texture) +void Graphics::drawQuads(int start, int count, const vertex::Attributes &attributes, const vertex::BufferBindings &buffers, love::graphics::Texture *texture) { @autoreleasepool { const int MAX_VERTICES_PER_DRAW = LOVE_UINT16_MAX; const int MAX_QUADS_PER_DRAW = MAX_VERTICES_PER_DRAW / 4; @@ -693,7 +684,7 @@ void Graphics::drawQuads(int start, int count, const vertex::Attributes &attribu } }} -void Graphics::setCanvasInternal(const RenderTargets &rts, int w, int h, int pixelw, int pixelh, bool hasSRGBcanvas) +void Graphics::setRenderTargetsInternal(const RenderTargets &rts, int w, int h, int pixelw, int pixelh, bool hasSRGBcanvas) { const DisplayState &state = states.back(); // TODO @@ -707,7 +698,7 @@ void Graphics::setCanvasInternal(const RenderTargets &rts, int w, int h, int pix void Graphics::endPass() { auto &rts = states.back().renderTargets; - love::graphics::Canvas *depthstencil = rts.depthStencil.canvas.get(); + love::graphics::Texture *depthstencil = rts.depthStencil.texture.get(); // Discard the depth/stencil buffer if we're using an internal cached one. if (depthstencil == nullptr && (rts.temporaryRTFlags & (TEMPORARY_RT_DEPTH | TEMPORARY_RT_STENCIL)) != 0) @@ -715,15 +706,15 @@ void Graphics::endPass() // Resolve MSAA buffers. MSAA is only supported for 2D render targets so we // don't have to worry about resolving to slices. - if (rts.colors.size() > 0 && rts.colors[0].canvas->getMSAA() > 1) + if (rts.colors.size() > 0 && rts.colors[0].texture->getMSAA() > 1) { int mip = rts.colors[0].mipmap; - int w = rts.colors[0].canvas->getPixelWidth(mip); - int h = rts.colors[0].canvas->getPixelHeight(mip); + int w = rts.colors[0].texture->getPixelWidth(mip); + int h = rts.colors[0].texture->getPixelHeight(mip); for (int i = 0; i < (int) rts.colors.size(); i++) { - Canvas *c = (Canvas *) rts.colors[i].canvas.get(); + Texture *c = (Texture *) rts.colors[i].texture.get(); if (!c->isReadable()) continue; @@ -739,12 +730,12 @@ void Graphics::endPass() for (const auto &rt : rts.colors) { - if (rt.canvas->getMipmapMode() == Canvas::MIPMAPS_AUTO && rt.mipmap == 0) - rt.canvas->generateMipmaps(); + if (rt.texture->getMipmapsMode() == Texture::MIPMAPS_AUTO && rt.mipmap == 0) + rt.texture->generateMipmaps(); } int dsmipmap = rts.depthStencil.mipmap; - if (depthstencil != nullptr && depthstencil->getMipmapMode() == Canvas::MIPMAPS_AUTO && dsmipmap == 0) + if (depthstencil != nullptr && depthstencil->getMipmapsMode() == Texture::MIPMAPS_AUTO && dsmipmap == 0) depthstencil->generateMipmaps(); } @@ -786,8 +777,8 @@ void Graphics::present(void *screenshotCallbackData) if (!isActive()) return; - if (isCanvasActive()) - throw love::Exception("present cannot be called while a Canvas is active."); + if (isRenderTargetActive()) + throw love::Exception("present cannot be called while a render target is active."); deprecations.draw(this); @@ -865,20 +856,20 @@ void Graphics::present(void *screenshotCallbackData) // Reset the per-frame stat counts. drawCalls = 0; //gl.stats.shaderSwitches = 0; - canvasSwitchCount = 0; + renderTargetSwitchCount = 0; drawCallsBatched = 0; // This assumes temporary canvases will only be used within a render pass. - for (int i = (int) temporaryCanvases.size() - 1; i >= 0; i--) + for (int i = (int) temporaryTextures.size() - 1; i >= 0; i--) { - if (temporaryCanvases[i].framesSinceUse >= MAX_TEMPORARY_CANVAS_UNUSED_FRAMES) + if (temporaryTextures[i].framesSinceUse >= MAX_TEMPORARY_TEXTURE_UNUSED_FRAMES) { - temporaryCanvases[i].canvas->release(); - temporaryCanvases[i] = temporaryCanvases.back(); - temporaryCanvases.pop_back(); + temporaryTextures[i].texture->release(); + temporaryTextures[i] = temporaryTextures.back(); + temporaryTextures.pop_back(); } else - temporaryCanvases[i].framesSinceUse++; + temporaryTextures[i].framesSinceUse++; } } @@ -906,11 +897,11 @@ void Graphics::setScissor() void Graphics::drawToStencilBuffer(StencilAction action, int value) { const auto &rts = states.back().renderTargets; - love::graphics::Canvas *dscanvas = rts.depthStencil.canvas.get(); + love::graphics::Texture *dstexture = rts.depthStencil.texture.get(); - if (!isCanvasActive() && !windowHasStencil) + if (!isRenderTargetActive() && !windowHasStencil) throw love::Exception("The window must have stenciling enabled to draw to the main screen's stencil buffer."); - else if (isCanvasActive() && (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) == 0 && (dscanvas == nullptr || !isPixelFormatStencil(dscanvas->getPixelFormat()))) + else if (isRenderTargetActive() && (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) == 0 && (dstexture == nullptr || !isPixelFormatStencil(dstexture->getPixelFormat()))) throw love::Exception("Drawing to the stencil buffer with a Canvas active requires either stencil=true or a custom stencil-type Canvas to be used, in setCanvas."); flushStreamDraws(); diff --git a/src/modules/graphics/metal/Image.h b/src/modules/graphics/metal/Image.h deleted file mode 100644 index 9bc48e650..000000000 --- a/src/modules/graphics/metal/Image.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright (c) 2006-2020 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#pragma once - -#include "common/config.h" -#include "common/Color.h" -#include "common/int.h" -#include "graphics/Image.h" -#include "Metal.h" - -namespace love -{ -namespace graphics -{ -namespace metal -{ - -class Image final : public love::graphics::Image -{ -public: - - Image(id device, const Slices &data, const Settings &settings); - Image(id device, TextureType textype, PixelFormat format, int width, int height, int slices, const Settings &settings); - virtual ~Image(); - - ptrdiff_t getHandle() const override { return (ptrdiff_t) texture; } - - void setFilter(const Texture::Filter &f) override; - bool setWrap(const Texture::Wrap &w) override; - - bool setMipmapSharpness(float sharpness) override; - -private: - - void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r) override; - void generateMipmaps() override; - - void create(id device); - - id texture; - id sampler; - -}; // Image - -} // metal -} // graphics -} // love diff --git a/src/modules/graphics/metal/Shader.h b/src/modules/graphics/metal/Shader.h index c6cfd1f38..39f7eeea3 100644 --- a/src/modules/graphics/metal/Shader.h +++ b/src/modules/graphics/metal/Shader.h @@ -45,10 +45,10 @@ public: 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, Texture **textures, int count) override; + void sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count) override; bool hasUniform(const std::string &name) const override; ptrdiff_t getHandle() const override; - void setVideoTextures(Texture *ytexture, Texture *cbtexture, Texture *crtexture) override; + void setVideoTextures(love::graphics::Texture *ytexture, love::graphics::Texture *cbtexture, love::graphics::Texture *crtexture) override; private: diff --git a/src/modules/graphics/metal/Canvas.h b/src/modules/graphics/metal/Texture.h similarity index 70% rename from src/modules/graphics/metal/Canvas.h rename to src/modules/graphics/metal/Texture.h index a0aa9fca6..adf328177 100644 --- a/src/modules/graphics/metal/Canvas.h +++ b/src/modules/graphics/metal/Texture.h @@ -23,7 +23,7 @@ #include "common/config.h" #include "common/Color.h" #include "common/int.h" -#include "graphics/Canvas.h" +#include "graphics/Texture.h" #include "Metal.h" namespace love @@ -33,39 +33,29 @@ namespace graphics namespace metal { -class Canvas final : public love::graphics::Canvas +class Texture final : public love::graphics::Texture { public: - Canvas(id device, const Settings &settings); - virtual ~Canvas(); + Texture(id device, const Settings &settings, const Slices *data); + virtual ~Texture(); - // Implements Texture. - void setFilter(const Texture::Filter &f) override; - bool setWrap(const Texture::Wrap &w) override; - bool setMipmapSharpness(float sharpness) override; - void setDepthSampleMode(Optional mode) override; - ptrdiff_t getHandle() const override { return (ptrdiff_t) texture; } - - love::image::ImageData *newImageData(love::image::Image *module, int slice, int mipmap, const Rect &rect) override; void generateMipmaps() override; + love::image::ImageData *newImageData(love::image::Image *module, int slice, int mipmap, const Rect &rect) override; + void setSamplerState(const SamplerState &s) override; - int getMSAA() const override - { - return 0; - } - - ptrdiff_t getRenderTargetHandle() const override - { - return (ptrdiff_t) texture; - } + ptrdiff_t getHandle() const override { return (ptrdiff_t) texture; } + ptrdiff_t getRenderTargetHandle() const override { return (ptrdiff_t) texture; /* TODO */ } + int getMSAA() const override { return 1 /* TODO*/; } private: - id texture; - id resolveTexture; + void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd = nullptr) override; -}; // Canvas + id texture; + id sampler; + +}; // Texture } // metal } // graphics diff --git a/src/modules/graphics/metal/Image.mm b/src/modules/graphics/metal/Texture.mm similarity index 61% rename from src/modules/graphics/metal/Image.mm rename to src/modules/graphics/metal/Texture.mm index b8716d175..f1d0cfd8c 100644 --- a/src/modules/graphics/metal/Image.mm +++ b/src/modules/graphics/metal/Texture.mm @@ -18,7 +18,7 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#include "Image.h" +#include "Texture.h" #include "Graphics.h" namespace love @@ -28,48 +28,39 @@ namespace graphics namespace metal { -Image::Image(id device, TextureType textype, PixelFormat format, int width, int height, int slices, const Settings &settings) - : love::graphics::Image(textype, format, width, height, slices, settings) +Texture::Texture(id device, const Settings &settings, const Slices *data) + : love::graphics::Texture(settings, data) , texture(nil) , sampler(nil) { @autoreleasepool { - create(device); -}} - -Image::Image(id device, const Slices &slices, const Settings &settings) - : love::graphics::Image(slices, settings) - , texture(nil) - , sampler(nil) -{ @autoreleasepool { - create(device); -}} - -Image::~Image() -{ @autoreleasepool { - texture = nil; - sampler = nil; -}} - -void Image::create(id device) -{ MTLTextureDescriptor *desc = [MTLTextureDescriptor new]; - desc.width = pixelWidth; - desc.height = pixelHeight; + int w = pixelWidth; + int h = pixelHeight; + + // TODO: sampleCount validation + desc.sampleCount = getRequestedMSAA(); + + desc.width = w; + desc.height = h; desc.depth = depth; desc.arrayLength = layers; desc.mipmapLevelCount = mipmapCount; - desc.textureType = Metal::getTextureType(texType, 1); + desc.textureType = Metal::getTextureType(texType, (int)desc.sampleCount); desc.pixelFormat = Metal::convertPixelFormat(format, sRGB); - desc.usage = MTLTextureUsageShaderRead; desc.storageMode = MTLStorageModePrivate; + if (readable) + desc.usage |= MTLTextureUsageShaderRead; + if (renderTarget) + desc.usage |= MTLTextureUsageRenderTarget; + texture = [device newTextureWithDescriptor:desc]; if (texture == nil) throw love::Exception("Out of graphics memory."); - int mipcount = mipmapsType == MIPMAPS_GENERATED ? 1 : getMipmapCount(); + int mipcount = getMipmapCount(); int slicecount = 1; if (texType == TEXTURE_VOLUME) @@ -83,17 +74,41 @@ void Image::create(id device) { for (int slice = 0; slice < slicecount; slice++) { - love::image::ImageDataBase *imgd = data.get(slice, mip); + auto imgd = data != nullptr ? data->get(slice, mip) : nullptr; if (imgd != nullptr) uploadImageData(imgd, mip, slice, 0, 0); } } - if (mipmapsType == MIPMAPS_GENERATED) - generateMipmaps(); -} + if (data == nullptr || data->get(0, 0) == nullptr) + { + // Initialize all slices to transparent black. + if (!isPixelFormatDepthStencil(format)) + { + std::vector emptydata(getPixelFormatSliceSize(format, w, h)); + Rect r = {0, 0, w, h}; + for (int i = 0; i < slicecount; i++) + uploadByteData(format, emptydata.data(), emptydata.size(), 0, i, r); + } + else + { + // TODO + } + } -void Image::uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r) + // Non-readable textures can't have mipmaps (enforced in the base class), + // so generateMipmaps here is fine - when they aren't already initialized. + if (getMipmapCount() > 1 && (data == nullptr || data->getMipmapCount() <= 1)) + generateMipmaps(); +}} + +Texture::~Texture() +{ @autoreleasepool { + texture = nil; + sampler = nil; +}} + +void Texture::uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *) { @autoreleasepool { auto gfx = Graphics::getInstance(); id buffer = [gfx->device newBufferWithBytes:data @@ -127,10 +142,19 @@ void Image::uploadByteData(PixelFormat pixelformat, const void *data, size_t siz break; } + size_t rowSize = 0; + if (isCompressed()) + rowSize = getPixelFormatCompressedBlockRowSize(format, r.w); + else + rowSize = getPixelFormatUncompressedRowSize(format, r.w); + + // TODO: Verify this is correct for compressed formats at small sizes. + size_t sliceSize = getPixelFormatSliceSize(format, r.w, r.h); + [encoder copyFromBuffer:buffer sourceOffset:0 - sourceBytesPerRow:getPixelFormatRowStride(pixelformat, r.w) - sourceBytesPerImage:0 // TODO? + sourceBytesPerRow:rowSize + sourceBytesPerImage:sliceSize sourceSize:MTLSizeMake(r.w, r.h, 1) toTexture:texture destinationSlice:slice @@ -139,8 +163,10 @@ void Image::uploadByteData(PixelFormat pixelformat, const void *data, size_t siz options:options]; }} -void Image::generateMipmaps() +void Texture::generateMipmaps() { @autoreleasepool { + // TODO: alternate method for non-color-renderable and non-filterable + // pixel formats. id encoder = Graphics::getInstance()->useBlitEncoder(); [encoder generateMipmapsForTexture:texture]; }}