diff options
author | Timothy Liang <timliang@google.com> | 2018-07-02 17:03:30 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-07-02 21:34:42 +0000 |
commit | ef21d7e47963c716895684f9f397e7cbcdb845ab (patch) | |
tree | d8425a1cb4d28bdcbb8c50ed8f9f439da11d5d17 | |
parent | 24289e05d55ccdc04ef239c7972d2b52e402ad0f (diff) |
implement onreadpixels for metal gpu backend
Bug: skia:
Change-Id: I1645f7e4e65766558f2b6744ce28d5f98ce852c6
Reviewed-on: https://skia-review.googlesource.com/138982
Commit-Queue: Timothy Liang <timliang@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
-rw-r--r-- | src/gpu/mtl/GrMtlGpu.h | 17 | ||||
-rw-r--r-- | src/gpu/mtl/GrMtlGpu.mm | 68 | ||||
-rw-r--r-- | src/gpu/mtl/GrMtlRenderTarget.h | 2 |
3 files changed, 84 insertions, 3 deletions
diff --git a/src/gpu/mtl/GrMtlGpu.h b/src/gpu/mtl/GrMtlGpu.h index 22fc733217..f8254031d1 100644 --- a/src/gpu/mtl/GrMtlGpu.h +++ b/src/gpu/mtl/GrMtlGpu.h @@ -31,6 +31,13 @@ public: id<MTLDevice> device() const { return fDevice; } + id<MTLCommandBuffer> commandBuffer() const { return fCmdBuffer; } + + enum SyncQueue { + kForce_SyncQueue, + kSkip_SyncQueue + }; + bool onCopySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin, GrSurface* src, GrSurfaceOrigin srcOrigin, const SkIRect& srcRect, @@ -89,9 +96,7 @@ private: } bool onReadPixels(GrSurface* surface, int left, int top, int width, int height, GrColorType, - void* buffer, size_t rowBytes) override { - return false; - } + void* buffer, size_t rowBytes) override; bool onWritePixels(GrSurface*, int left, int top, int width, int height, GrColorType, const GrMipLevel[], int) override { @@ -111,6 +116,11 @@ private: void onFinishFlush(bool insertedSemaphores) override {} + // Commits the current command buffer to the queue and then creates a new command buffer. If + // sync is set to kForce_SyncQueue, the function will wait for all work in the committed + // command buffer to finish before creating a new buffer and returning. + void submitCommandBuffer(SyncQueue sync); + GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget*, int width, int height) override { @@ -142,6 +152,7 @@ private: id<MTLDevice> fDevice; id<MTLCommandQueue> fQueue; + id<MTLCommandBuffer> fCmdBuffer; typedef GrGpu INHERITED; }; diff --git a/src/gpu/mtl/GrMtlGpu.mm b/src/gpu/mtl/GrMtlGpu.mm index 42b0739548..d9dd3160ab 100644 --- a/src/gpu/mtl/GrMtlGpu.mm +++ b/src/gpu/mtl/GrMtlGpu.mm @@ -10,6 +10,7 @@ #include "GrMtlTexture.h" #include "GrMtlTextureRenderTarget.h" #include "GrMtlUtil.h" +#include "SkConvertPixels.h" #if !__has_feature(objc_arc) #error This file must be compiled with Arc. Use -fobjc-arc flag @@ -92,6 +93,8 @@ GrMtlGpu::GrMtlGpu(GrContext* context, const GrContextOptions& options, fMtlCaps.reset(new GrMtlCaps(options, fDevice, featureSet)); fCaps = fMtlCaps; + fCmdBuffer = [fQueue commandBuffer]; + MTLTextureDescriptor* txDesc = [[MTLTextureDescriptor alloc] init]; txDesc.textureType = MTLTextureType3D; txDesc.height = 64; @@ -108,6 +111,15 @@ GrMtlGpu::GrMtlGpu(GrContext* context, const GrContextOptions& options, SkDebugf("ptr to queue: %p\n", fQueue); } +void GrMtlGpu::submitCommandBuffer(SyncQueue sync) { + SkASSERT(fCmdBuffer); + [fCmdBuffer commit]; + if (SyncQueue::kForce_SyncQueue == sync) { + [fCmdBuffer waitUntilCompleted]; + } + fCmdBuffer = [fQueue commandBuffer]; +} + sk_sp<GrTexture> GrMtlGpu::onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted, const GrMipLevel texels[], int mipLevelCount) { int mipLevels = !mipLevelCount ? 1 : mipLevelCount; @@ -234,3 +246,59 @@ sk_sp<GrRenderTarget> GrMtlGpu::onWrapBackendTextureAsRenderTarget( return GrMtlRenderTarget::MakeWrappedRenderTarget(this, surfDesc, mtlTexture); } +bool GrMtlGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height, + GrColorType dstColorType, void* buffer, size_t rowBytes) { + static const int MAX_BLIT_WIDTH = 32767; // in pixels + SkASSERT(surface); + if (width > MAX_BLIT_WIDTH) { + SkASSERT(false); // A texture/RT shouldn't be this wide anyway. + return false; + } + if (GrPixelConfigToColorType(surface->config()) != dstColorType) { + return false; + } + + id<MTLTexture> mtlTexture = nil; + GrMtlRenderTarget* renderTarget = static_cast<GrMtlRenderTarget*>(surface->asRenderTarget()); + GrMtlTexture* texture; + if (renderTarget) { + // TODO: Handle resolving rt here when MSAA is supported. Right now we just grab the render + // texture since we cannot currently have a multi-sampled rt. + mtlTexture = renderTarget->mtlRenderTexture(); + } else { + texture = static_cast<GrMtlTexture*>(surface->asTexture()); + if (texture) { + mtlTexture = texture->mtlTexture(); + } + } + + if (!mtlTexture) { + return false; + } + + int bpp = GrColorTypeBytesPerPixel(dstColorType); + size_t transBufferRowBytes = bpp * width; + size_t transBufferImageBytes = transBufferRowBytes * height; + + // TODO: implement some way of reusing buffers instead of making a new one every time. + id<MTLBuffer> transferBuffer = [fDevice newBufferWithLength: transBufferImageBytes + options: MTLResourceStorageModeShared]; + + id<MTLBlitCommandEncoder> blitCmdEncoder = [fCmdBuffer blitCommandEncoder]; + [blitCmdEncoder copyFromTexture: mtlTexture + sourceSlice: 0 + sourceLevel: 0 + sourceOrigin: MTLOriginMake(left, top, 0) + sourceSize: MTLSizeMake(width, height, 1) + toBuffer: transferBuffer + destinationOffset: 0 + destinationBytesPerRow: transBufferRowBytes + destinationBytesPerImage: transBufferImageBytes]; + [blitCmdEncoder endEncoding]; + + this->submitCommandBuffer(kForce_SyncQueue); + const void* mappedMemory = transferBuffer.contents; + + SkRectMemcpy(buffer, rowBytes, mappedMemory, transBufferRowBytes, transBufferRowBytes, height); + return true; +} diff --git a/src/gpu/mtl/GrMtlRenderTarget.h b/src/gpu/mtl/GrMtlRenderTarget.h index 02b0a61a0d..12f70647b0 100644 --- a/src/gpu/mtl/GrMtlRenderTarget.h +++ b/src/gpu/mtl/GrMtlRenderTarget.h @@ -39,6 +39,8 @@ public: return true; } + id<MTLTexture> mtlRenderTexture() const { return fRenderTexture; } + GrBackendRenderTarget getBackendRenderTarget() const override; protected: |