aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Timothy Liang <timliang@google.com>2018-07-02 17:03:30 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-07-02 21:34:42 +0000
commitef21d7e47963c716895684f9f397e7cbcdb845ab (patch)
treed8425a1cb4d28bdcbb8c50ed8f9f439da11d5d17
parent24289e05d55ccdc04ef239c7972d2b52e402ad0f (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.h17
-rw-r--r--src/gpu/mtl/GrMtlGpu.mm68
-rw-r--r--src/gpu/mtl/GrMtlRenderTarget.h2
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: