diff --git a/src/modules/graphics/Font.cpp b/src/modules/graphics/Font.cpp index d635d654f..fb4e52702 100644 --- a/src/modules/graphics/Font.cpp +++ b/src/modules/graphics/Font.cpp @@ -82,6 +82,10 @@ Font::Font(love::font::Rasterizer *r, const SamplerState &s) pixelFormat = gd->getFormat(); gd->release(); + auto gfx = Module::getInstance(Module::M_GRAPHICS); + if (pixelFormat == PIXELFORMAT_LA8_UNORM && !gfx->isPixelFormatSupported(pixelFormat, PIXELFORMATUSAGEFLAGS_SAMPLE)) + pixelFormat = PIXELFORMAT_RGBA8_UNORM; + if (!r->hasGlyph(9)) // No tab character in the Rasterizer. useSpacesAsTab = true; @@ -158,18 +162,30 @@ void Font::createTexture() texture->setSamplerState(samplerState); { - size_t bpp = getPixelFormatBlockSize(pixelFormat); + size_t datasize = getPixelFormatSliceSize(pixelFormat, size.width, size.height); size_t pixelcount = size.width * size.height; - // Initialize the texture with transparent white for Luminance-Alpha - // formats (since we keep luminance constant and vary alpha in those - // glyphs), and transparent black otherwise. - std::vector emptydata(pixelcount * bpp, 0); + // Initialize the texture with transparent white for truetype fonts + // (since we keep luminance constant and vary alpha in those glyphs), + // and transparent black otherwise. + std::vector emptydata(datasize, 0); - if (pixelFormat == PIXELFORMAT_LA8_UNORM) + if (rasterizers[0]->getDataType() == font::Rasterizer::DATA_TRUETYPE) { - for (size_t i = 0; i < pixelcount; i++) - emptydata[i * 2 + 0] = 255; + if (pixelFormat == PIXELFORMAT_LA8_UNORM) + { + for (size_t i = 0; i < pixelcount; i++) + emptydata[i * 2 + 0] = 255; + } + else if (pixelFormat == PIXELFORMAT_RGBA8_UNORM) + { + for (size_t i = 0; i < pixelcount; i++) + { + emptydata[i * 4 + 0] = 255; + emptydata[i * 4 + 1] = 255; + emptydata[i * 4 + 2] = 255; + } + } } Rect rect = {0, 0, size.width, size.height}; @@ -281,7 +297,32 @@ const Font::Glyph &Font::addGlyph(uint32 glyph) g.texture = texture; Rect rect = {textureX, textureY, gd->getWidth(), gd->getHeight()}; - texture->replacePixels(gd->getData(), gd->getSize(), 0, 0, rect, false); + + if (pixelFormat != gd->getFormat()) + { + if (!(pixelFormat == PIXELFORMAT_RGBA8_UNORM && gd->getFormat() == PIXELFORMAT_LA8_UNORM)) + throw love::Exception("Cannot upload font glyphs to texture atlas: unexpected format conversion."); + + const uint8 *src = (const uint8 *) gd->getData(); + + size_t dstsize = getPixelFormatSliceSize(pixelFormat, w, h); + std::vector dst(dstsize, 0); + uint8 *dstdata = dst.data(); + + for (int pixel = 0; pixel < w * h; pixel++) + { + dstdata[pixel * 4 + 0] = src[pixel * 2 + 0]; + dstdata[pixel * 4 + 1] = src[pixel * 2 + 0]; + dstdata[pixel * 4 + 2] = src[pixel * 2 + 0]; + dstdata[pixel * 4 + 3] = src[pixel * 2 + 1]; + } + + texture->replacePixels(dstdata, dstsize, 0, 0, rect, false); + } + else + { + texture->replacePixels(gd->getData(), gd->getSize(), 0, 0, rect, false); + } double tX = (double) textureX, tY = (double) textureY; double tWidth = (double) textureWidth, tHeight = (double) textureHeight; diff --git a/src/modules/graphics/metal/Graphics.mm b/src/modules/graphics/metal/Graphics.mm index 05481b58c..32ba3706d 100644 --- a/src/modules/graphics/metal/Graphics.mm +++ b/src/modules/graphics/metal/Graphics.mm @@ -1813,7 +1813,6 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, PixelFormatUsageFlags format = getSRGBPixelFormat(format); const uint32 sample = PIXELFORMATUSAGEFLAGS_SAMPLE; - const uint32 linear = PIXELFORMATUSAGEFLAGS_LINEAR; const uint32 rt = PIXELFORMATUSAGEFLAGS_RENDERTARGET; const uint32 blend = PIXELFORMATUSAGEFLAGS_BLEND; const uint32 msaa = PIXELFORMATUSAGEFLAGS_MSAA; @@ -1858,8 +1857,12 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, PixelFormatUsageFlags flags |= all; break; case PIXELFORMAT_LA8_UNORM: - // TODO - flags |= commonsample; + // Requires texture swizzle support. + if (@available(macOS 10.15, iOS 13, *)) + { + if (families.apple[1] || families.mac[2] || families.macCatalyst[2]) + flags |= commonsample; + } break; case PIXELFORMAT_RG16_UNORM: if (families.apple[1]) diff --git a/src/modules/graphics/metal/Metal.h b/src/modules/graphics/metal/Metal.h index 41af98c58..43cec8c61 100644 --- a/src/modules/graphics/metal/Metal.h +++ b/src/modules/graphics/metal/Metal.h @@ -36,14 +36,13 @@ class Metal { public: - struct API_AVAILABLE(macos(10.15), ios(13.0)) PixelFormatDesc + struct PixelFormatDesc { MTLPixelFormat format; bool swizzled = false; - MTLTextureSwizzleChannels swizzle; + API_AVAILABLE(macos(10.15), ios(13.0)) MTLTextureSwizzleChannels swizzle; }; - API_AVAILABLE(macos(10.15), ios(13.0)) static PixelFormatDesc convertPixelFormat(id device, PixelFormat format, bool &isSRGB); }; // Metal diff --git a/src/modules/graphics/metal/Metal.mm b/src/modules/graphics/metal/Metal.mm index 192a6853a..179ac1673 100644 --- a/src/modules/graphics/metal/Metal.mm +++ b/src/modules/graphics/metal/Metal.mm @@ -143,11 +143,16 @@ Metal::PixelFormatDesc Metal::convertPixelFormat(id device, PixelForm break; case PIXELFORMAT_LA8_UNORM: - // 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); + // Only supported on some systems. + if (@available(macOS 10.15, iOS 13, *)) + { + mtlformat = MTLPixelFormatRG8Unorm; + desc.swizzled = true; + desc.swizzle.red = MTLTextureSwizzleRed; + desc.swizzle.green = MTLTextureSwizzleRed; + desc.swizzle.blue = MTLTextureSwizzleRed; + desc.swizzle.alpha = MTLTextureSwizzleGreen; + } break; case PIXELFORMAT_RGBA4_UNORM: diff --git a/src/modules/graphics/metal/Shader.mm b/src/modules/graphics/metal/Shader.mm index 2d2405a04..b36c5be0c 100644 --- a/src/modules/graphics/metal/Shader.mm +++ b/src/modules/graphics/metal/Shader.mm @@ -1064,14 +1064,9 @@ id Shader::getCachedRenderPipeline(const RenderPipelineK MTLRenderPipelineColorAttachmentDescriptor *attachment = desc.colorAttachments[i]; - if (@available(macOS 10.15, iOS 13.0, *)) - { - // We already don't really support metal on older systems, this just - // silences a compiler warning about it. - bool isSRGB = false; - auto formatdesc = Metal::convertPixelFormat(device, format, isSRGB); - attachment.pixelFormat = formatdesc.format; - } + bool isSRGB = false; + auto formatdesc = Metal::convertPixelFormat(device, format, isSRGB); + attachment.pixelFormat = formatdesc.format; if (key.blend.enable) { diff --git a/src/modules/graphics/metal/Texture.mm b/src/modules/graphics/metal/Texture.mm index f09a73f37..c4b8c8b82 100644 --- a/src/modules/graphics/metal/Texture.mm +++ b/src/modules/graphics/metal/Texture.mm @@ -61,17 +61,17 @@ Texture::Texture(love::graphics::Graphics *gfxbase, id device, const desc.arrayLength = layers; desc.mipmapLevelCount = mipmapCount; desc.textureType = getMTLTextureType(texType, 1); - if (@available(macOS 10.15, iOS 13, *)) + + auto formatdesc = Metal::convertPixelFormat(device, format, sRGB); + desc.pixelFormat = formatdesc.format; + if (formatdesc.swizzled) { - // We already don't really support metal on older systems, this just - // silences a compiler warning about it. - auto formatdesc = Metal::convertPixelFormat(device, format, sRGB); - desc.pixelFormat = formatdesc.format; - if (formatdesc.swizzled) + // Swizzled formats are already only used on supported systems, this + // just silences a compiler warning about it. + if (@available(macOS 10.15, iOS 13, *)) desc.swizzle = formatdesc.swizzle; } - else - throw love::Exception("Metal backend is only supported on macOS 10.15+ and iOS 13+."); + desc.storageMode = MTLStorageModePrivate; if (readable)