summaryrefslogtreecommitdiff
path: root/vcl/skia/osx
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2021-08-23 17:57:48 +0200
committerLuboš Luňák <l.lunak@collabora.com>2021-08-24 13:17:23 +0200
commitd4afd3aeb4ef2727986551816c1ff9ad0ed12d04 (patch)
tree40694dde66cac18d071acc647ea107aea5c61c9f /vcl/skia/osx
parentddcdc2077fab2b6d9c4def4e4615185411cbe80a (diff)
initial Metal support for Mac/Skia
This also required changing SkiaSalGraphicsImpl to have sk_app::WindowContext as an internal detail inaccessible to the base class, since the Mac implementations cannot use it as is. Change-Id: I2424f0b887c79ee91c3bd0f1477b0745f9540247 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120909 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
Diffstat (limited to 'vcl/skia/osx')
-rw-r--r--vcl/skia/osx/gdiimpl.cxx99
-rw-r--r--vcl/skia/osx/rastercontext.cxx51
2 files changed, 79 insertions, 71 deletions
diff --git a/vcl/skia/osx/gdiimpl.cxx b/vcl/skia/osx/gdiimpl.cxx
index 8a879e2f7788..0014a98a404d 100644
--- a/vcl/skia/osx/gdiimpl.cxx
+++ b/vcl/skia/osx/gdiimpl.cxx
@@ -21,7 +21,7 @@
#include <skia/utils.hxx>
#include <skia/zone.hxx>
-#include <skia/osx/rastercontext.hxx>
+#include <tools/sk_app/mac/WindowContextFactory_mac.h>
#include <quartz/ctfonts.hxx>
@@ -43,6 +43,7 @@ AquaSkiaSalGraphicsImpl::AquaSkiaSalGraphicsImpl(AquaSalGraphics& rParent,
AquaSkiaSalGraphicsImpl::~AquaSkiaSalGraphicsImpl()
{
DeInit(); // mac code doesn't call DeInit()
+ assert(!mWindowContext);
}
void AquaSkiaSalGraphicsImpl::DeInit()
@@ -54,19 +55,31 @@ void AquaSkiaSalGraphicsImpl::DeInit()
void AquaSkiaSalGraphicsImpl::freeResources() {}
-void AquaSkiaSalGraphicsImpl::createWindowContext(bool forceRaster)
+void AquaSkiaSalGraphicsImpl::createWindowSurfaceInternal(bool forceRaster)
{
SkiaZone zone;
sk_app::DisplayParams displayParams;
displayParams.fColorType = kN32_SkColorType;
- forceRaster = true; // TODO
+ sk_app::window_context_factory::MacWindowInfo macWindow;
+ macWindow.fMainView = mrShared.mpFrame->mpNSView;
RenderMethod renderMethod = forceRaster ? RenderRaster : renderMethodToUse();
switch (renderMethod)
{
case RenderRaster:
- displayParams.fColorType = kRGBA_8888_SkColorType; // TODO
- mWindowContext.reset(
- new AquaSkiaWindowContextRaster(GetWidth(), GetHeight(), displayParams));
+ // RasterWindowContext_mac uses OpenGL internally, which we don't want,
+ // so use our own surface and do blitting to the screen ourselves.
+ mSurface = createSkSurface(GetWidth(), GetHeight());
+ break;
+ case RenderMetal:
+ // It appears that Metal surfaces cannot be read from, which may break things
+ // like copyArea(). Additionally sk_app::MetalWindowContext requires
+ // a new call to getBackbufferSurface() after every swapBuffers(), which
+ // normally would also require reading contents of the previous surface,
+ // because we do not redraw the complete area for every draw call.
+ // Handle that by using an offscreen surface and blit to the onscreen surface as necessary.
+ mSurface = createSkSurface(GetWidth(), GetHeight());
+ mWindowContext
+ = sk_app::window_context_factory::MakeMetalForMac(macWindow, displayParams);
break;
case RenderVulkan:
abort();
@@ -74,21 +87,50 @@ void AquaSkiaSalGraphicsImpl::createWindowContext(bool forceRaster)
}
}
+void AquaSkiaSalGraphicsImpl::destroyWindowSurfaceInternal()
+{
+ mWindowContext.reset();
+ mSurface.reset();
+}
+
//void AquaSkiaSalGraphicsImpl::Flush() { performFlush(); }
void AquaSkiaSalGraphicsImpl::performFlush()
{
SkiaZone zone;
flushDrawing();
- if (mWindowContext)
+ if (mSurface)
{
if (mDirtyRect.intersect(SkIRect::MakeWH(GetWidth(), GetHeight())))
- flushToScreen(mDirtyRect);
+ {
+ if (isGPU())
+ flushToScreenMetal(mDirtyRect);
+ else
+ flushToScreenRaster(mDirtyRect);
+ }
mDirtyRect.setEmpty();
}
}
-void AquaSkiaSalGraphicsImpl::flushToScreen(const SkIRect& rect)
+constexpr static uint32_t toCGBitmapType(SkColorType color, SkAlphaType alpha)
+{
+ if (alpha == kPremul_SkAlphaType)
+ {
+ return color == kBGRA_8888_SkColorType
+ ? (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little)
+ : (kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
+ }
+ else
+ {
+ assert(alpha == kOpaque_SkAlphaType);
+ return color == kBGRA_8888_SkColorType
+ ? (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little)
+ : (kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big);
+ }
+}
+
+// For Raster we use our own screen blitting (see above).
+void AquaSkiaSalGraphicsImpl::flushToScreenRaster(const SkIRect& rect)
{
// Based on AquaGraphicsBackend::drawBitmap().
if (!mrShared.checkContext())
@@ -105,8 +147,8 @@ void AquaSkiaSalGraphicsImpl::flushToScreen(const SkIRect& rect)
// pixel lines will be read from correct positions.
CGContextRef context
= CGBitmapContextCreate(pixmap.writable_addr32(rect.left(), rect.top()), rect.width(),
- rect.height(), 8, pixmap.rowBytes(), // TODO
- GetSalData()->mxRGBSpace, kCGImageAlphaNoneSkipLast); // TODO
+ rect.height(), 8, pixmap.rowBytes(), GetSalData()->mxRGBSpace,
+ toCGBitmapType(image->colorType(), image->alphaType()));
assert(context); // TODO
CGImageRef screenImage = CGBitmapContextCreateImage(context);
assert(screenImage); // TODO
@@ -131,6 +173,19 @@ void AquaSkiaSalGraphicsImpl::flushToScreen(const SkIRect& rect)
mrShared.refreshRect(rect.left(), rect.top(), rect.width(), rect.height());
}
+// For Metal we flush to the Metal surface and then swap buffers (see above).
+void AquaSkiaSalGraphicsImpl::flushToScreenMetal(const SkIRect&)
+{
+ // The rectangle argument is irrelevant, the whole surface must be used for Metal.
+ sk_sp<SkSurface> screenSurface = mWindowContext->getBackbufferSurface();
+ SkPaint paint;
+ paint.setBlendMode(SkBlendMode::kSrc); // copy as is
+ screenSurface->getCanvas()->drawImage(makeCheckedImageSnapshot(mSurface), 0, 0,
+ SkSamplingOptions(), &paint);
+ screenSurface->flushAndSubmit(); // Otherwise the window is not drawn sometimes.
+ mWindowContext->swapBuffers(nullptr);
+}
+
bool AquaSkiaSalGraphicsImpl::drawNativeControl(ControlType nType, ControlPart nPart,
const tools::Rectangle& rControlRegion,
ControlState nState, const ImplControlValue& aValue)
@@ -140,9 +195,9 @@ bool AquaSkiaSalGraphicsImpl::drawNativeControl(ControlType nType, ControlPart n
const size_t bytes = width * height * 4;
std::unique_ptr<sal_uInt8[]> data(new sal_uInt8[bytes]);
memset(data.get(), 0, bytes);
- CGContextRef context
- = CGBitmapContextCreate(data.get(), width, height, 8, width * 4, // TODO
- GetSalData()->mxRGBSpace, kCGImageAlphaPremultipliedLast); // TODO
+ CGContextRef context = CGBitmapContextCreate(
+ data.get(), width, height, 8, width * 4, GetSalData()->mxRGBSpace,
+ toCGBitmapType(mSurface->imageInfo().colorType(), kPremul_SkAlphaType));
assert(context); // TODO
// Flip upside down.
CGContextTranslateCTM(context, 0, height);
@@ -156,9 +211,10 @@ bool AquaSkiaSalGraphicsImpl::drawNativeControl(ControlType nType, ControlPart n
if (bOK)
{
SkBitmap bitmap;
- if (!bitmap.installPixels(
- SkImageInfo::Make(width, height, kRGBA_8888_SkColorType, kPremul_SkAlphaType),
- data.get(), width * 4))
+ if (!bitmap.installPixels(SkImageInfo::Make(width, height,
+ mSurface->imageInfo().colorType(),
+ kPremul_SkAlphaType),
+ data.get(), width * 4))
abort();
preDraw();
@@ -224,11 +280,14 @@ void AquaSkiaSalGraphicsImpl::drawTextLayout(const GenericSalLayout& rLayout)
drawGenericLayout(rLayout, mrShared.maTextColor, font, verticalFont);
}
-std::unique_ptr<sk_app::WindowContext> createVulkanWindowContext(bool /*temporary*/)
+std::unique_ptr<sk_app::WindowContext> createMetalWindowContext(bool /*temporary*/)
{
- return nullptr;
+ sk_app::DisplayParams displayParams;
+ sk_app::window_context_factory::MacWindowInfo macWindow;
+ macWindow.fMainView = nullptr;
+ return sk_app::window_context_factory::MakeMetalForMac(macWindow, displayParams);
}
-void AquaSkiaSalGraphicsImpl::prepareSkia() { SkiaHelper::prepareSkia(createVulkanWindowContext); }
+void AquaSkiaSalGraphicsImpl::prepareSkia() { SkiaHelper::prepareSkia(createMetalWindowContext); }
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/skia/osx/rastercontext.cxx b/vcl/skia/osx/rastercontext.cxx
deleted file mode 100644
index a2a514483710..000000000000
--- a/vcl/skia/osx/rastercontext.cxx
+++ /dev/null
@@ -1,51 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * This file is part of the LibreOffice project.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- *
- * Some of this code is based on Skia source code, covered by the following
- * license notice (see readlicense_oo for the full license):
- *
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- */
-
-#include <skia/osx/rastercontext.hxx>
-
-#include <SkSurface.h>
-
-AquaSkiaWindowContextRaster::AquaSkiaWindowContextRaster(int w, int h,
- const sk_app::DisplayParams& params)
- : WindowContext(params)
-{
- fWidth = w;
- fHeight = h;
- resize(w, h);
-}
-
-void AquaSkiaWindowContextRaster::resize(int w, int h)
-{
- fWidth = w;
- fHeight = h;
- createSurface();
-}
-
-void AquaSkiaWindowContextRaster::setDisplayParams(const sk_app::DisplayParams& params)
-{
- fDisplayParams = params;
-}
-
-void AquaSkiaWindowContextRaster::createSurface()
-{
- SkImageInfo info = SkImageInfo::Make(fWidth, fHeight, fDisplayParams.fColorType,
- kPremul_SkAlphaType, fDisplayParams.fColorSpace);
- mSurface = SkSurface::MakeRaster(info, &fDisplayParams.fSurfaceProps);
-}
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */