[graphite] Add support to Mac Viewer.

Adds a type enum to WindowContext to determine which kind of
GPU context (GrDirectContext or skgpu::Context) we're using.

Bug: skia:12466
Change-Id: I288878740392a43cd9e82c925fbe2c372d140dc5
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/454699
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
Jim Van Verth 2021-09-30 16:27:30 -04:00 committed by SkCQ
parent 6868f78d40
commit 7bb0ff05ce
10 changed files with 345 additions and 5 deletions

View File

@ -2655,8 +2655,15 @@ if (skia_enable_tools) {
if (skia_use_metal) {
sources += [ "tools/sk_app/MetalWindowContext.mm" ]
sources += [ "tools/sk_app/MetalWindowContext.h" ]
if (skia_enable_graphite) {
sources += [ "tools/sk_app/GraphiteMetalWindowContext.mm" ]
sources += [ "tools/sk_app/GraphiteMetalWindowContext.h" ]
}
if (is_mac) {
sources += [ "tools/sk_app/mac/MetalWindowContext_mac.mm" ]
if (skia_enable_graphite) {
sources += [ "tools/sk_app/mac/GraphiteMetalWindowContext_mac.mm" ]
}
} else if (is_ios) {
sources += [ "tools/sk_app/ios/MetalWindowContext_ios.mm" ]
}

View File

@ -0,0 +1,56 @@
/*
* Copyright 2021 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GraphiteMetalWindowContext_DEFINED
#define GraphiteMetalWindowContext_DEFINED
#include "include/core/SkRefCnt.h"
#include "include/ports/SkCFObject.h"
#include "tools/sk_app/WindowContext.h"
#import <Metal/Metal.h>
#import <QuartzCore/CAMetalLayer.h>
class SkSurface;
namespace sk_app {
class GraphiteMetalWindowContext : public WindowContext {
public:
sk_sp<SkSurface> getBackbufferSurface() override;
bool isValid() override { return fValid; }
void swapBuffers() override;
void setDisplayParams(const DisplayParams& params) override;
void activate(bool isActive) override;
protected:
GraphiteMetalWindowContext(const DisplayParams&);
// This should be called by subclass constructor. It is also called when window/display
// parameters change. This will in turn call onInitializeContext().
void initializeContext();
virtual bool onInitializeContext() = 0;
// This should be called by subclass destructor. It is also called when window/display
// parameters change prior to initializing a new Metal context. This will in turn call
// onDestroyContext().
void destroyContext();
virtual void onDestroyContext() = 0;
bool fValid;
sk_cfp<id<MTLDevice>> fDevice;
sk_cfp<id<MTLCommandQueue>> fQueue;
CAMetalLayer* fMetalLayer;
CFTypeRef fDrawableHandle;
};
} // namespace sk_app
#endif

View File

@ -0,0 +1,127 @@
/*
* Copyright 2021 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkSurface.h"
#include "src/core/SkMathPriv.h"
#include "tools/sk_app/GraphiteMetalWindowContext.h"
#include "experimental/graphite/include/Context.h"
#include "experimental/graphite/include/mtl/MtlBackendContext.h"
using sk_app::DisplayParams;
using sk_app::GraphiteMetalWindowContext;
namespace sk_app {
GraphiteMetalWindowContext::GraphiteMetalWindowContext(const DisplayParams& params)
: WindowContext(params)
, fValid(false)
, fDrawableHandle(nil) {
fDisplayParams.fMSAASampleCount = GrNextPow2(fDisplayParams.fMSAASampleCount);
}
void GraphiteMetalWindowContext::initializeContext() {
SkASSERT(!fContext);
SkASSERT(!fGraphiteContext);
fDevice.reset(MTLCreateSystemDefaultDevice());
fQueue.reset([*fDevice newCommandQueue]);
if (fDisplayParams.fMSAASampleCount > 1) {
if (@available(macOS 10.11, iOS 9.0, *)) {
if (![*fDevice supportsTextureSampleCount:fDisplayParams.fMSAASampleCount]) {
return;
}
} else {
return;
}
}
fSampleCount = fDisplayParams.fMSAASampleCount;
fStencilBits = 8;
fValid = this->onInitializeContext();
skgpu::mtl::BackendContext backendContext = {};
backendContext.fDevice.retain((GrMTLHandle)fDevice.get());
backendContext.fQueue.retain((GrMTLHandle)fQueue.get());
fGraphiteContext = skgpu::Context::MakeMetal(backendContext);
// TODO
// if (!fGraphiteContext && fDisplayParams.fMSAASampleCount > 1) {
// fDisplayParams.fMSAASampleCount /= 2;
// this->initializeContext();
// return;
// }
}
void GraphiteMetalWindowContext::destroyContext() {
if (fGraphiteContext) {
// TODO?
// in case we have outstanding refs to this (lua?)
// fGraphiteContext->abandonContext();
fGraphiteContext.reset();
}
this->onDestroyContext();
fMetalLayer = nil;
fValid = false;
#if GR_METAL_SDK_VERSION >= 230
if (@available(macOS 11.0, iOS 14.0, *)) {
[fPipelineArchive release];
}
#endif
fQueue.reset();
fDevice.reset();
}
sk_sp<SkSurface> GraphiteMetalWindowContext::getBackbufferSurface() {
sk_sp<SkSurface> surface;
id<CAMetalDrawable> currentDrawable = [fMetalLayer nextDrawable];
// TODO
// GrMtlTextureInfo fbInfo;
// fbInfo.fTexture.retain(currentDrawable.texture);
//
// GrBackendRenderTarget backendRT(fWidth,
// fHeight,
// fSampleCount,
// fbInfo);
//
// surface = SkSurface::MakeFromBackendRenderTarget(fContext.get(), backendRT,
// kTopLeft_GrSurfaceOrigin,
// kBGRA_8888_SkColorType,
// fDisplayParams.fColorSpace,
// &fDisplayParams.fSurfaceProps);
fDrawableHandle = CFRetain((GrMTLHandle) currentDrawable);
return surface;
}
void GraphiteMetalWindowContext::swapBuffers() {
id<CAMetalDrawable> currentDrawable = (id<CAMetalDrawable>)fDrawableHandle;
id<MTLCommandBuffer> commandBuffer([*fQueue commandBuffer]);
commandBuffer.label = @"Present";
[commandBuffer presentDrawable:currentDrawable];
[commandBuffer commit];
// ARC is off in sk_app, so we need to release the CF ref manually
CFRelease(fDrawableHandle);
fDrawableHandle = nil;
}
void GraphiteMetalWindowContext::setDisplayParams(const DisplayParams& params) {
this->destroyContext();
fDisplayParams = params;
this->initializeContext();
}
void GraphiteMetalWindowContext::activate(bool isActive) {}
} //namespace sk_app

View File

@ -24,6 +24,10 @@ class SkSurface;
class SkSurfaceProps;
class SkString;
namespace skgpu {
class Context;
}
namespace sk_app {
class WindowContext;
@ -66,6 +70,9 @@ public:
#endif
#ifdef SK_METAL
kMetal_BackendType,
#ifdef SK_GRAPHITE_ENABLED
kGraphiteMetal_BackendType,
#endif
#endif
#ifdef SK_DIRECT3D
kDirect3D_BackendType,
@ -144,6 +151,7 @@ public:
// Returns null if there is not a GPU backend or if the backend is not yet created.
GrDirectContext* directContext() const;
skgpu::Context* graphiteContext() const;
protected:
Window();

View File

@ -8,13 +8,14 @@
#include "tools/sk_app/WindowContext.h"
#include "include/gpu/GrDirectContext.h"
#ifdef SK_GRAPHITE_ENABLED
#include "experimental/graphite/include/Context.h"
#endif
namespace sk_app {
WindowContext::WindowContext(const DisplayParams& params)
: fDisplayParams(params)
, fSampleCount(1)
, fStencilBits(0) {}
: fDisplayParams(params) {}
WindowContext::~WindowContext() {}

View File

@ -14,6 +14,11 @@
class GrDirectContext;
class SkSurface;
#ifdef SK_GRAPHITE_ENABLED
namespace skgpu {
class Context;
}
#endif
namespace sk_app {
@ -37,6 +42,9 @@ public:
virtual void setDisplayParams(const DisplayParams& params) = 0;
GrDirectContext* directContext() const { return fContext.get(); }
#ifdef SK_GRAPHITE_ENABLED
skgpu::Context* graphiteContext() const { return fGraphiteContext.get(); }
#endif
int width() const { return fWidth; }
int height() const { return fHeight; }
@ -47,6 +55,9 @@ protected:
virtual bool isGpuContext() { return true; }
sk_sp<GrDirectContext> fContext;
#if SK_GRAPHITE_ENABLED
sk_sp<skgpu::Context> fGraphiteContext;
#endif
int fWidth;
int fHeight;
@ -55,8 +66,8 @@ protected:
// parameters obtained from the native window
// Note that the platform .cpp file is responsible for
// initializing fSampleCount and fStencilBits!
int fSampleCount;
int fStencilBits;
int fSampleCount = 1;
int fStencilBits = 0;
};
} // namespace sk_app

View File

@ -0,0 +1,109 @@
/*
* Copyright 2021 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "tools/sk_app/GraphiteMetalWindowContext.h"
#include "tools/sk_app/mac/WindowContextFactory_mac.h"
#import <Cocoa/Cocoa.h>
#import <QuartzCore/CAConstraintLayoutManager.h>
using sk_app::DisplayParams;
using sk_app::window_context_factory::MacWindowInfo;
using sk_app::GraphiteMetalWindowContext;
namespace {
class GraphiteMetalWindowContext_mac : public GraphiteMetalWindowContext {
public:
GraphiteMetalWindowContext_mac(const MacWindowInfo&, const DisplayParams&);
~GraphiteMetalWindowContext_mac() override;
bool onInitializeContext() override;
void onDestroyContext() override;
void resize(int w, int h) override;
private:
NSView* fMainView;
using INHERITED = GraphiteMetalWindowContext;
};
GraphiteMetalWindowContext_mac::GraphiteMetalWindowContext_mac(const MacWindowInfo& info,
const DisplayParams& params)
: INHERITED(params)
, fMainView(info.fMainView) {
// any config code here (particularly for msaa)?
this->initializeContext();
}
GraphiteMetalWindowContext_mac::~GraphiteMetalWindowContext_mac() {
this->destroyContext();
}
bool GraphiteMetalWindowContext_mac::onInitializeContext() {
SkASSERT(nil != fMainView);
fMetalLayer = [CAMetalLayer layer];
fMetalLayer.device = fDevice.get();
fMetalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
// resize ignores the passed values and uses the fMainView directly.
this->resize(0, 0);
BOOL useVsync = fDisplayParams.fDisableVsync ? NO : YES;
fMetalLayer.displaySyncEnabled = useVsync; // TODO: need solution for 10.12 or lower
fMetalLayer.layoutManager = [CAConstraintLayoutManager layoutManager];
fMetalLayer.autoresizingMask = kCALayerHeightSizable | kCALayerWidthSizable;
fMetalLayer.contentsGravity = kCAGravityTopLeft;
fMetalLayer.magnificationFilter = kCAFilterNearest;
NSColorSpace* cs = fMainView.window.colorSpace;
fMetalLayer.colorspace = cs.CGColorSpace;
fMainView.layer = fMetalLayer;
fMainView.wantsLayer = YES;
return true;
}
void GraphiteMetalWindowContext_mac::onDestroyContext() {
fMainView.layer = nil;
fMainView.wantsLayer = NO;
}
void GraphiteMetalWindowContext_mac::resize(int w, int h) {
CGFloat backingScaleFactor = sk_app::GetBackingScaleFactor(fMainView);
CGSize backingSize = fMainView.bounds.size;
backingSize.width *= backingScaleFactor;
backingSize.height *= backingScaleFactor;
fMetalLayer.drawableSize = backingSize;
fMetalLayer.contentsScale = backingScaleFactor;
fWidth = backingSize.width;
fHeight = backingSize.height;
}
} // anonymous namespace
namespace sk_app {
namespace window_context_factory {
std::unique_ptr<WindowContext> MakeGraphiteMetalForMac(const MacWindowInfo& info,
const DisplayParams& params) {
std::unique_ptr<WindowContext> ctx(new GraphiteMetalWindowContext_mac(info, params));
if (!ctx->isValid()) {
return nullptr;
}
return ctx;
}
} // namespace window_context_factory
} // namespace sk_app

View File

@ -53,6 +53,9 @@ std::unique_ptr<WindowContext> MakeDawnMTLForMac(const MacWindowInfo&, const Dis
#ifdef SK_METAL
std::unique_ptr<WindowContext> MakeMetalForMac(const MacWindowInfo&, const DisplayParams&);
#ifdef SK_GRAPHITE_ENABLED
std::unique_ptr<WindowContext> MakeGraphiteMetalForMac(const MacWindowInfo&, const DisplayParams&);
#endif
#endif
} // namespace window_context_factory

View File

@ -136,6 +136,11 @@ bool Window_mac::attach(BackendType attachType) {
case kMetal_BackendType:
fWindowContext = MakeMetalForMac(info, fRequestedDisplayParams);
break;
#ifdef SK_GRAPHITE_ENABLED
case kGraphiteMetal_BackendType:
fWindowContext = MakeGraphiteMetalForMac(info, fRequestedDisplayParams);
break;
#endif
#endif
#ifdef SK_GL
case kNativeGL_BackendType:

View File

@ -200,6 +200,9 @@ const char* kBackendTypeStrings[sk_app::Window::kBackendTypeCount] = {
#endif
#ifdef SK_METAL
"Metal",
#ifdef SK_GRAPHITE_ENABLED
"Metal (Graphite)",
#endif
#endif
#ifdef SK_DIRECT3D
"Direct3D",
@ -227,6 +230,11 @@ static sk_app::Window::BackendType get_backend_type(const char* str) {
if (0 == strcmp(str, "mtl")) {
return sk_app::Window::kMetal_BackendType;
} else
#ifdef SK_GRAPHITE_ENABLED
if (0 == strcmp(str, "grmtl")) {
return sk_app::Window::kGraphiteMetal_BackendType;
} else
#endif
#endif
#ifdef SK_DIRECT3D
if (0 == strcmp(str, "d3d")) {
@ -1881,6 +1889,11 @@ void Viewer::drawImGui() {
#if defined(SK_METAL)
ImGui::SameLine();
ImGui::RadioButton("Metal", &newBackend, sk_app::Window::kMetal_BackendType);
#if defined(SK_GRAPHITE_ENABLED)
ImGui::SameLine();
ImGui::RadioButton("Metal (Graphite)", &newBackend,
sk_app::Window::kGraphiteMetal_BackendType);
#endif
#endif
#if defined(SK_DIRECT3D)
ImGui::SameLine();