Use LazyProxy to set up Metal swapchain.

The purpose of this is to delay acquiring the next drawable in the
swapchain to avoid stalling and gain better parallel execution between
the CPU and GPU.

Change-Id: I40ef7672394fd00616de43685530d2feaf7cab2d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/249005
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
Jim Van Verth 2019-10-17 14:58:37 -04:00 committed by Skia Commit-Bot
parent 7b86d4e8a2
commit cbf59e0e39
3 changed files with 74 additions and 34 deletions

View File

@ -5,13 +5,23 @@
* found in the LICENSE file.
*/
#include "include/core/SkRefCnt.h"
#include "include/core/SkSurface.h"
#include "include/gpu/GrBackendSurface.h"
#include "include/gpu/GrContext.h"
#include "include/gpu/mtl/GrMtlTypes.h"
#include "src/gpu/GrContextPriv.h"
#include "src/gpu/GrProxyProvider.h"
#include "src/gpu/GrRenderTargetContext.h"
#include "src/gpu/GrResourceProvider.h"
#include "src/gpu/GrResourceProviderPriv.h"
#include "src/image/SkSurface_Gpu.h"
#if SK_SUPPORT_GPU
#include "include/gpu/GrSurface.h"
#include "src/gpu/mtl/GrMtlRenderTarget.h"
#ifdef SK_METAL
#import <Metal/Metal.h>
#import <QuartzCore/CAMetalLayer.h>
@ -24,37 +34,68 @@ sk_sp<SkSurface> SkSurface::MakeFromCAMetalLayer(GrContext* context,
sk_sp<SkColorSpace> colorSpace,
const SkSurfaceProps* surfaceProps,
GrMTLHandle* drawable) {
// TODO: Apple recommends grabbing the drawable (which we're implicitly doing here)
// for as little time as possible. I'm not sure it matters for our test apps, but
// you can get better throughput by doing any offscreen renders, texture uploads, or
// other non-dependant tasks first before grabbing the drawable.
GrProxyProvider* proxyProvider = context->priv().proxyProvider();
const GrCaps* caps = context->priv().caps();
CAMetalLayer* metalLayer = (__bridge CAMetalLayer*)layer;
id<CAMetalDrawable> currentDrawable = [metalLayer nextDrawable];
GrBackendFormat backendFormat = GrBackendFormat::MakeMtl(metalLayer.pixelFormat);
GrMtlTextureInfo fbInfo;
fbInfo.fTexture.retain((__bridge const void*)(currentDrawable.texture));
GrColorType grColorType = SkColorTypeToGrColorType(colorType);
CGSize size = [metalLayer drawableSize];
sk_sp<SkSurface> surface;
if (sampleCnt <= 1) {
GrBackendRenderTarget backendRT(size.width,
size.height,
sampleCnt,
fbInfo);
surface = SkSurface::MakeFromBackendRenderTarget(context, backendRT, origin, colorType,
colorSpace, surfaceProps);
} else {
GrBackendTexture backendTexture(size.width,
size.height,
GrMipMapped::kNo,
fbInfo);
surface = SkSurface::MakeFromBackendTexture(context, backendTexture, origin, sampleCnt,
colorType, colorSpace, surfaceProps);
GrPixelConfig config = caps->getConfigFromBackendFormat(backendFormat, grColorType);
if (config == kUnknown_GrPixelConfig) {
return nullptr;
}
*drawable = (__bridge_retained GrMTLHandle) currentDrawable;
GrSurfaceDesc desc;
desc.fWidth = metalLayer.frame.size.width;
desc.fHeight = metalLayer.frame.size.height;
desc.fConfig = config;
sk_sp<GrRenderTargetProxy> proxy = proxyProvider->createLazyRenderTargetProxy(
[layer, drawable, sampleCnt, config](GrResourceProvider* resourceProvider) {
CAMetalLayer* metalLayer = (__bridge CAMetalLayer*)layer;
id<CAMetalDrawable> currentDrawable = [metalLayer nextDrawable];
CGSize size = [metalLayer drawableSize];
GrSurfaceDesc desc;
desc.fWidth = size.width;
desc.fHeight = size.height;
desc.fConfig = config;
GrMtlGpu* mtlGpu = (GrMtlGpu*) resourceProvider->priv().gpu();
auto surface = GrMtlRenderTarget::MakeWrappedRenderTarget(mtlGpu, desc, sampleCnt,
currentDrawable.texture);
if (surface && sampleCnt > 1) {
surface->setRequiresManualMSAAResolve();
}
*drawable = (__bridge_retained GrMTLHandle) currentDrawable;
return GrSurfaceProxy::LazyCallbackResult(std::move(surface));
},
backendFormat,
desc,
sampleCnt,
origin,
sampleCnt > 1 ? GrInternalSurfaceFlags::kRequiresManualMSAAResolve
: GrInternalSurfaceFlags::kNone,
nullptr, // not textureable
GrMipMapsStatus::kNotAllocated,
SkBackingFit::kExact,
SkBudgeted::kYes,
GrProtected::kNo,
false,
GrSurfaceProxy::UseAllocator::kYes);
auto c = context->priv().makeWrappedSurfaceContext(std::move(proxy),
grColorType,
kPremul_SkAlphaType,
colorSpace,
surfaceProps);
SkASSERT(c->asRenderTargetContext());
std::unique_ptr<GrRenderTargetContext> rtc(c.release()->asRenderTargetContext());
sk_sp<SkSurface> surface = SkSurface_Gpu::MakeWrappedRenderTarget(context, std::move(rtc));
return surface;
}
#endif

View File

@ -44,7 +44,7 @@ protected:
id<MTLDevice> fDevice;
id<MTLCommandQueue> fQueue;
CAMetalLayer* fMetalLayer;
id<CAMetalDrawable> fCurrentDrawable;
GrMTLHandle fDrawableHandle;
};
} // namespace sk_app

View File

@ -76,28 +76,27 @@ void MetalWindowContext::destroyContext() {
sk_sp<SkSurface> MetalWindowContext::getBackbufferSurface() {
sk_sp<SkSurface> surface;
if (fContext) {
GrMTLHandle drawable;
surface = SkSurface::MakeFromCAMetalLayer(fContext.get(), (__bridge GrMTLHandle)fMetalLayer,
kTopLeft_GrSurfaceOrigin, fSampleCount,
kBGRA_8888_SkColorType,
fDisplayParams.fColorSpace,
&fDisplayParams.fSurfaceProps,
&drawable);
// ARC is off in sk_app, so we need to release the CF ref manually
fCurrentDrawable = (id<CAMetalDrawable>)drawable;
CFRelease(drawable);
&fDrawableHandle);
}
return surface;
}
void MetalWindowContext::swapBuffers() {
// ARC is off in sk_app, so we need to release the CF ref manually
id<CAMetalDrawable> currentDrawable = (id<CAMetalDrawable>)fDrawableHandle;
CFRelease(fDrawableHandle);
id<MTLCommandBuffer> commandBuffer = [fQueue commandBuffer];
commandBuffer.label = @"Present";
[commandBuffer presentDrawable:fCurrentDrawable];
[commandBuffer presentDrawable:currentDrawable];
[commandBuffer commit];
fCurrentDrawable = nil;
}
void MetalWindowContext::setDisplayParams(const DisplayParams& params) {