Update metal backend for Image+Canvas->Texture changes

This commit is contained in:
Alex Szpakowski
2020-02-15 15:44:23 -04:00
parent 742a954655
commit 64b38459cf
8 changed files with 158 additions and 306 deletions
@@ -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 = "<group>"; };
FA18CECD23DBC6E000263725 /* Shader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Shader.h; sourceTree = "<group>"; };
FA18CECE23DBC6E000263725 /* StreamBuffer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = StreamBuffer.mm; sourceTree = "<group>"; };
FA18CECF23DBC6E000263725 /* Canvas.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Canvas.mm; sourceTree = "<group>"; };
FA18CED023DBC6E000263725 /* Metal.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Metal.mm; sourceTree = "<group>"; };
FA18CED123DBC6E000263725 /* Shader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Shader.mm; sourceTree = "<group>"; };
FA18CED223DBC6E000263725 /* StreamBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StreamBuffer.h; sourceTree = "<group>"; };
FA18CED323DBC6E000263725 /* Graphics.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Graphics.mm; sourceTree = "<group>"; };
FA18CED423DBC6E000263725 /* Metal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Metal.h; sourceTree = "<group>"; };
FA18CED523DBC6E000263725 /* Graphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Graphics.h; sourceTree = "<group>"; };
FA18CED623DBC6E000263725 /* Canvas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Canvas.h; sourceTree = "<group>"; };
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 = "<group>"; };
FA18CEEB23DBC8EB00263725 /* Buffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Buffer.h; sourceTree = "<group>"; };
FA18CEEC23DC9B3E00263725 /* Image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Image.h; sourceTree = "<group>"; };
FA18CEED23DC9B3E00263725 /* Image.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Image.mm; sourceTree = "<group>"; };
FA18CEEC23DC9B3E00263725 /* Texture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Texture.h; sourceTree = "<group>"; };
FA18CEED23DC9B3E00263725 /* Texture.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Texture.mm; sourceTree = "<group>"; };
FA18CEF223DCF67800263725 /* spirv_parser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = spirv_parser.hpp; sourceTree = "<group>"; };
FA18CEF323DCF67800263725 /* spirv_glsl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_glsl.cpp; sourceTree = "<group>"; };
FA18CEF423DCF67800263725 /* spirv_cross_error_handling.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = spirv_cross_error_handling.hpp; sourceTree = "<group>"; };
@@ -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 = "<group>";
@@ -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 */,
-76
View File
@@ -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<MTLDevice> 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<MTLBlitCommandEncoder> encoder = Graphics::getInstance()->useBlitEncoder();
[encoder generateMipmapsForTexture:texture];
}}
} // metal
} // graphics
} // love
+7 -10
View File
@@ -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<OptionalColorf> &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<MTLBlitCommandEncoder> getBlitEncoder() const { return blitEncoder; }
void submitBlitEncoder();
id<MTLSamplerState> getCachedSampler(const Texture::Filter &f, const Texture::Wrap &w, float maxAnisotropy, Optional<CompareMode> depthSampleMode);
id<MTLSamplerState> getCachedSampler(const SamplerState &s);
static Graphics *getInstance() { return Module::getInstance<Graphics>(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;
+66 -75
View File
@@ -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<MTLSamplerState> Graphics::getCachedSampler(const Texture::Filter &f, const Texture::Wrap &w, float maxAnisotropy, Optional<CompareMode> depthSampleMode)
id<MTLSamplerState> Graphics::getCachedSampler(const SamplerState &s)
{ @autoreleasepool {
id<MTLSamplerState> 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<MTLRenderCommandEncoder> 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();
-65
View File
@@ -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<MTLDevice> device, const Slices &data, const Settings &settings);
Image(id<MTLDevice> 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<MTLDevice> device);
id<MTLTexture> texture;
id<MTLSamplerState> sampler;
}; // Image
} // metal
} // graphics
} // love
+2 -2
View File
@@ -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:
@@ -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<MTLDevice> device, const Settings &settings);
virtual ~Canvas();
Texture(id<MTLDevice> 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<CompareMode> 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<MTLTexture> texture;
id<MTLTexture> 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<MTLTexture> texture;
id<MTLSamplerState> sampler;
}; // Texture
} // metal
} // graphics
@@ -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<MTLDevice> 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<MTLDevice> device, const Settings &settings, const Slices *data)
: love::graphics::Texture(settings, data)
, texture(nil)
, sampler(nil)
{ @autoreleasepool {
create(device);
}}
Image::Image(id<MTLDevice> 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<MTLDevice> 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<MTLDevice> 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<uint8> 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<MTLBuffer> 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<MTLBlitCommandEncoder> encoder = Graphics::getInstance()->useBlitEncoder();
[encoder generateMipmapsForTexture:texture];
}}