aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--dm/DM.cpp32
-rw-r--r--gn/gpu.gni1
-rw-r--r--gn/tests.gni1
-rw-r--r--include/core/SkSurface.h25
-rw-r--r--include/gpu/GrBackendSemaphore.h69
-rw-r--r--src/gpu/GrGpu.h5
-rw-r--r--src/gpu/GrRenderTargetContext.cpp37
-rw-r--r--src/gpu/GrRenderTargetContext.h9
-rw-r--r--src/gpu/GrResourceProvider.cpp11
-rw-r--r--src/gpu/GrResourceProvider.h8
-rw-r--r--src/gpu/GrSemaphore.h7
-rw-r--r--src/gpu/SkGpuDevice.cpp15
-rw-r--r--src/gpu/SkGpuDevice.h2
-rw-r--r--src/gpu/gl/GrGLCaps.cpp8
-rw-r--r--src/gpu/gl/GrGLGpu.cpp13
-rw-r--r--src/gpu/gl/GrGLGpu.h4
-rw-r--r--src/gpu/gl/GrGLSemaphore.h25
-rw-r--r--src/gpu/ops/GrSemaphoreOp.cpp30
-rw-r--r--src/gpu/ops/GrSemaphoreOp.h14
-rw-r--r--src/gpu/vk/GrVkCommandBuffer.cpp23
-rw-r--r--src/gpu/vk/GrVkCommandBuffer.h2
-rw-r--r--src/gpu/vk/GrVkGpu.cpp40
-rw-r--r--src/gpu/vk/GrVkGpu.h16
-rw-r--r--src/gpu/vk/GrVkSemaphore.cpp30
-rw-r--r--src/gpu/vk/GrVkSemaphore.h15
-rw-r--r--src/image/SkSurface.cpp14
-rw-r--r--src/image/SkSurface_Base.h11
-rw-r--r--src/image/SkSurface_Gpu.cpp8
-rw-r--r--src/image/SkSurface_Gpu.h3
-rw-r--r--tests/OnFlushCallbackTest.cpp3
-rw-r--r--tests/SurfaceSemaphoreTest.cpp175
-rw-r--r--tools/gpu/GrContextFactory.h31
-rw-r--r--tools/gpu/GrTest.cpp4
33 files changed, 580 insertions, 111 deletions
diff --git a/dm/DM.cpp b/dm/DM.cpp
index d92b5ae3ce..58ccb1f4e8 100644
--- a/dm/DM.cpp
+++ b/dm/DM.cpp
@@ -1432,36 +1432,6 @@ bool IsRenderingGLContextType(sk_gpu_test::GrContextFactory::ContextType type) {
bool IsNullGLContextType(sk_gpu_test::GrContextFactory::ContextType type) {
return type == GrContextFactory::kNullGL_ContextType;
}
-const char* ContextTypeName(GrContextFactory::ContextType contextType) {
- switch (contextType) {
- case GrContextFactory::kGL_ContextType:
- return "OpenGL";
- case GrContextFactory::kGLES_ContextType:
- return "OpenGLES";
- case GrContextFactory::kANGLE_D3D9_ES2_ContextType:
- return "ANGLE D3D9 ES2";
- case GrContextFactory::kANGLE_D3D11_ES2_ContextType:
- return "ANGLE D3D11 ES2";
- case GrContextFactory::kANGLE_D3D11_ES3_ContextType:
- return "ANGLE D3D11 ES3";
- case GrContextFactory::kANGLE_GL_ES2_ContextType:
- return "ANGLE GL ES2";
- case GrContextFactory::kANGLE_GL_ES3_ContextType:
- return "ANGLE GL ES3";
- case GrContextFactory::kCommandBuffer_ContextType:
- return "Command Buffer";
- case GrContextFactory::kMESA_ContextType:
- return "Mesa";
- case GrContextFactory::kNullGL_ContextType:
- return "Null GL";
- case GrContextFactory::kDebugGL_ContextType:
- return "Debug GL";
- case GrContextFactory::kVulkan_ContextType:
- return "Vulkan";
- }
- SkDEBUGFAIL("Unreachable");
- return "Unknown";
-}
#else
bool IsGLContextType(int) { return false; }
bool IsVulkanContextType(int) { return false; }
@@ -1494,7 +1464,7 @@ void RunWithGPUTestContexts(GrContextTestFn* test, GrContextTypeFilterFn* contex
if (contextTypeFilter && !(*contextTypeFilter)(contextType)) {
continue;
}
- ReporterContext ctx(reporter, SkString(ContextTypeName(contextType)));
+ ReporterContext ctx(reporter, SkString(GrContextFactory::ContextTypeName(contextType)));
if (ctxInfo.grContext()) {
(*test)(reporter, ctxInfo);
}
diff --git a/gn/gpu.gni b/gn/gpu.gni
index aa840694ce..5c6b238144 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -8,6 +8,7 @@ _src = get_path_info("../src", "abspath")
_include = get_path_info("../include", "abspath")
skia_gpu_sources = [
+ "$_include/gpu/GrBackendSemaphore.h",
"$_include/gpu/GrBackendSurface.h",
"$_include/gpu/GrBlend.h",
"$_include/gpu/GrCaps.h",
diff --git a/gn/tests.gni b/gn/tests.gni
index f961c84002..80af7146e7 100644
--- a/gn/tests.gni
+++ b/gn/tests.gni
@@ -232,6 +232,7 @@ tests_sources = [
"$_tests/StrokerTest.cpp",
"$_tests/StrokeTest.cpp",
"$_tests/SubsetPath.cpp",
+ "$_tests/SurfaceSemaphoreTest.cpp",
"$_tests/SurfaceTest.cpp",
"$_tests/SVGDeviceTest.cpp",
"$_tests/SwizzlerTest.cpp",
diff --git a/include/core/SkSurface.h b/include/core/SkSurface.h
index efa2428ccb..6fad21721e 100644
--- a/include/core/SkSurface.h
+++ b/include/core/SkSurface.h
@@ -15,6 +15,7 @@
class SkCanvas;
class SkPaint;
class GrBackendRenderTarget;
+class GrBackendSemaphore;
class GrContext;
class GrRenderTarget;
@@ -323,9 +324,33 @@ public:
/**
* Issue any pending surface IO to the current backend 3D API and resolve any surface MSAA.
+ *
+ * The flush calls below are the new preferred way to flush calls to a surface, and this call
+ * will eventually be removed.
*/
void prepareForExternalIO();
+ /**
+ * Issue any pending surface IO to the current backend 3D API
+ */
+ void flush();
+
+ /**
+ * Issue any pending surface IO to the current backend 3D API. After issuing all commands, we
+ * will issue numSemaphore semaphores for the gpu to signal. We will then fill in the array
+ * signalSemaphores with the info on the semaphores we submitted. The client is reposonsible for
+ * allocating enough space in signalSemaphores to handle numSemaphores of GrBackendSemaphores.
+ * The client will also take ownership of the returned underlying backend semaphores.
+ */
+ void flushAndSignalSemaphores(int numSemaphores, GrBackendSemaphore* signalSemaphores);
+
+ /**
+ * Inserts a list of GPU semaphores that the current backend 3D API must wait on before
+ * executing any more commands on the GPU for this surface. Skia will take ownership of the
+ * underlying semaphores and delete them once they have been signaled and waited on.
+ */
+ void wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores);
+
protected:
SkSurface(int width, int height, const SkSurfaceProps*);
SkSurface(const SkImageInfo&, const SkSurfaceProps*);
diff --git a/include/gpu/GrBackendSemaphore.h b/include/gpu/GrBackendSemaphore.h
new file mode 100644
index 0000000000..668f6bb1c9
--- /dev/null
+++ b/include/gpu/GrBackendSemaphore.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrBackendSemaphore_DEFINED
+#define GrBackendSemaphore_DEFINED
+
+#include "GrTypes.h"
+
+#include "gl/GrGLTypes.h"
+
+#ifdef SK_VULKAN
+#include "vk/GrVkTypes.h"
+#endif
+
+/**
+ * Wrapper class for passing into and receiving data from Ganesh about a backend semaphore object.
+ */
+class GrBackendSemaphore {
+public:
+ // For convenience we just set the backend here to OpenGL. The GrBackendSemaphore cannot be used
+ // until either initGL or initVulkan are called which will set the appropriate GrBackend.
+ GrBackendSemaphore() : fBackend(kOpenGL_GrBackend), fGLSync(0), fIsInitialized(false) {}
+
+ void initGL(GrGLsync sync) {
+ fBackend = kOpenGL_GrBackend;
+ fGLSync = sync;
+ fIsInitialized = true;
+ }
+
+#ifdef SK_VULKAN
+ void initVulkan(VkSemaphore semaphore) {
+ fBackend = kVulkan_GrBackend;
+ fVkSemaphore = semaphore;
+ fIsInitialized = true;
+ }
+#endif
+
+ GrGLsync glSync() const {
+ if (!fIsInitialized || kOpenGL_GrBackend != fBackend) {
+ return 0;
+ }
+ return fGLSync;
+ }
+
+#ifdef SK_VULKAN
+ VkSemaphore vkSemaphore() const {
+ if (!fIsInitialized || kVulkan_GrBackend != fBackend) {
+ return VK_NULL_HANDLE;
+ }
+ return fVkSemaphore;
+ }
+#endif
+
+private:
+ GrBackend fBackend;
+ union {
+ GrGLsync fGLSync;
+#ifdef SK_VULKAN
+ VkSemaphore fVkSemaphore;
+#endif
+ };
+ bool fIsInitialized;
+};
+
+#endif
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 3c400a8b9c..418b8b418d 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -21,6 +21,7 @@
#include <map>
class GrBackendRenderTarget;
+class GrBackendSemaphore;
class GrBuffer;
class GrContext;
struct GrContextOptions;
@@ -376,7 +377,9 @@ public:
virtual bool waitFence(GrFence, uint64_t timeout = 1000) = 0;
virtual void deleteFence(GrFence) const = 0;
- virtual sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore() = 0;
+ virtual sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned = true) = 0;
+ virtual sk_sp<GrSemaphore> wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
+ GrWrapOwnership ownership) = 0;
virtual void insertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush = false) = 0;
virtual void waitSemaphore(sk_sp<GrSemaphore> semaphore) = 0;
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index c5a115faeb..17a7db8c81 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -9,6 +9,7 @@
#include "../private/GrAuditTrail.h"
#include "../private/SkShadowFlags.h"
#include "GrAppliedClip.h"
+#include "GrBackendSemaphore.h"
#include "GrColor.h"
#include "GrContextPriv.h"
#include "GrDrawingManager.h"
@@ -38,6 +39,7 @@
#include "ops/GrOvalOpFactory.h"
#include "ops/GrRectOpFactory.h"
#include "ops/GrRegionOp.h"
+#include "ops/GrSemaphoreOp.h"
#include "ops/GrShadowRRectOp.h"
#include "ops/GrStencilPathOp.h"
#include "text/GrAtlasTextContext.h"
@@ -508,7 +510,7 @@ void GrRenderTargetContext::drawRect(const GrClip& clip,
const SkStrokeRec& stroke = style->strokeRec();
if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
-
+
if (!fContext->caps()->useDrawInsteadOfClear()) {
// Check if this is a full RT draw and can be replaced with a clear. We don't bother
// checking cases where the RT is fully inside a stroke.
@@ -1429,13 +1431,44 @@ void GrRenderTargetContext::drawImageLattice(const GrClip& clip,
this->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op));
}
-void GrRenderTargetContext::prepareForExternalIO() {
+void GrRenderTargetContext::prepareForExternalIO(int numSemaphores,
+ GrBackendSemaphore* backendSemaphores) {
ASSERT_SINGLE_OWNER
RETURN_IF_ABANDONED
SkDEBUGCODE(this->validate();)
GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::prepareForExternalIO");
+ SkTArray<sk_sp<GrSemaphore>> semaphores(numSemaphores);
+ for (int i = 0; i < numSemaphores; ++i) {
+ semaphores.push_back(fContext->resourceProvider()->makeSemaphore(false));
+ std::unique_ptr<GrOp> signalOp(GrSemaphoreOp::MakeSignal(semaphores.back(),
+ fRenderTargetProxy.get()));
+ this->getOpList()->addOp(std::move(signalOp), *this->caps());
+ }
+
this->drawingManager()->prepareSurfaceForExternalIO(fRenderTargetProxy.get());
+
+ for (int i = 0; i < numSemaphores; ++i) {
+ semaphores[i]->setBackendSemaphore(&backendSemaphores[i]);
+ }
+}
+
+void GrRenderTargetContext::waitOnSemaphores(int numSemaphores,
+ const GrBackendSemaphore* waitSemaphores) {
+ ASSERT_SINGLE_OWNER
+ RETURN_IF_ABANDONED
+ SkDEBUGCODE(this->validate();)
+ GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::waitOnSemaphores");
+
+ AutoCheckFlush acf(this->drawingManager());
+
+ SkTArray<sk_sp<GrSemaphore>> semaphores(numSemaphores);
+ for (int i = 0; i < numSemaphores; ++i) {
+ sk_sp<GrSemaphore> sema = fContext->resourceProvider()->wrapBackendSemaphore(
+ waitSemaphores[i], kAdopt_GrWrapOwnership);
+ std::unique_ptr<GrOp> waitOp(GrSemaphoreOp::MakeWait(sema, fRenderTargetProxy.get()));
+ this->getOpList()->addOp(std::move(waitOp), *this->caps());
+ }
}
// Can 'path' be drawn as a pair of filled nested rectangles?
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index bc226044dd..a2369dd4fc 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -19,6 +19,7 @@
#include "SkRefCnt.h"
#include "SkSurfaceProps.h"
+class GrBackendSemaphore;
class GrClip;
class GrDrawingManager;
class GrDrawOp;
@@ -302,7 +303,13 @@ public:
* After this returns any pending surface IO will be issued to the backend 3D API and
* if the surface has MSAA it will be resolved.
*/
- void prepareForExternalIO();
+ void prepareForExternalIO(int numSemaphores, GrBackendSemaphore* backendSemaphores);
+
+ /**
+ * The next time this GrRenderTargetContext is flushed, the gpu will wait on the passed in
+ * semaphores before executing any commands.
+ */
+ void waitOnSemaphores(int numSemaphores, const GrBackendSemaphore* waitSemaphores);
GrFSAAType fsaaType() const { return fRenderTargetProxy->fsaaType(); }
const GrCaps* caps() const { return fContext->caps(); }
diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp
index 52340bb0e9..dccfaae875 100644
--- a/src/gpu/GrResourceProvider.cpp
+++ b/src/gpu/GrResourceProvider.cpp
@@ -7,6 +7,7 @@
#include "GrResourceProvider.h"
+#include "GrBackendSemaphore.h"
#include "GrBuffer.h"
#include "GrCaps.h"
#include "GrContext.h"
@@ -505,8 +506,14 @@ sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendTextureAsRenderTarget(
return this->gpu()->wrapBackendTextureAsRenderTarget(tex, origin, sampleCnt);
}
-sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore() {
- return fGpu->makeSemaphore();
+sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore(bool isOwned) {
+ return fGpu->makeSemaphore(isOwned);
+}
+
+sk_sp<GrSemaphore> GrResourceProvider::wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
+ GrWrapOwnership ownership) {
+ ASSERT_SINGLE_OWNER
+ return this->isAbandoned() ? nullptr : fGpu->wrapBackendSemaphore(semaphore, ownership);
}
void GrResourceProvider::takeOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore) {
diff --git a/src/gpu/GrResourceProvider.h b/src/gpu/GrResourceProvider.h
index 50264ef908..a6ddbc55b0 100644
--- a/src/gpu/GrResourceProvider.h
+++ b/src/gpu/GrResourceProvider.h
@@ -8,13 +8,14 @@
#ifndef GrResourceProvider_DEFINED
#define GrResourceProvider_DEFINED
-#include "GrBackendSurface.h"
#include "GrBuffer.h"
#include "GrPathRange.h"
#include "SkImageInfo.h"
#include "SkScalerContext.h"
class GrBackendRenderTarget;
+class GrBackendSemaphore;
+class GrBackendTexture;
class GrGpu;
class GrPath;
class GrRenderTarget;
@@ -227,7 +228,10 @@ public:
*/
GrGpuResource* findAndRefResourceByUniqueKey(const GrUniqueKey&);
- sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore();
+ sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned = true);
+
+ sk_sp<GrSemaphore> wrapBackendSemaphore(const GrBackendSemaphore&,
+ GrWrapOwnership = kBorrow_GrWrapOwnership);
// Takes the GrSemaphore and sets the ownership of the semaphore to the GrGpu object used by
// this class. This call is only used when passing a GrSemaphore from one context to another.
diff --git a/src/gpu/GrSemaphore.h b/src/gpu/GrSemaphore.h
index b4843ff780..f6148b015a 100644
--- a/src/gpu/GrSemaphore.h
+++ b/src/gpu/GrSemaphore.h
@@ -10,6 +10,7 @@
#include "SkRefCnt.h"
+class GrBackendSemaphore;
class GrGpu;
class GrSemaphore : public SkRefCnt {
@@ -20,9 +21,15 @@ private:
// GrSemaphore should not be used with its old context.
void resetGpu(const GrGpu* gpu) { fGpu = gpu; }
+ // The derived class will init the GrBackendSemaphore. This is used when flushing with signal
+ // semaphores so we can set the clients GrBackendSemaphore object after we've created the
+ // internal semaphore.
+ virtual void setBackendSemaphore(GrBackendSemaphore*) const = 0;
+
protected:
explicit GrSemaphore(const GrGpu* gpu) : fGpu(gpu) {}
+ friend class GrRenderTargetContext; // setBackendSemaphore
friend class GrResourceProvider; // resetGpu
const GrGpu* fGpu;
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index be842baf67..ee6e88d33a 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1730,10 +1730,23 @@ bool SkGpuDevice::onShouldDisableLCD(const SkPaint& paint) const {
return GrTextUtils::ShouldDisableLCD(paint);
}
+///////////////////////////////////////////////////////////////////////////////
+
void SkGpuDevice::flush() {
+ this->flushAndSignalSemaphores(0, nullptr);
+}
+
+void SkGpuDevice::flushAndSignalSemaphores(int numSemaphores,
+ GrBackendSemaphore* signalSemaphores) {
+ ASSERT_SINGLE_OWNER
+
+ fRenderTargetContext->prepareForExternalIO(numSemaphores, signalSemaphores);
+}
+
+void SkGpuDevice::wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
ASSERT_SINGLE_OWNER
- fRenderTargetContext->prepareForExternalIO();
+ fRenderTargetContext->waitOnSemaphores(numSemaphores, waitSemaphores);
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h
index 0b60a96516..317533db82 100644
--- a/src/gpu/SkGpuDevice.h
+++ b/src/gpu/SkGpuDevice.h
@@ -118,6 +118,8 @@ public:
sk_sp<SkSpecialImage> snapSpecial() override;
void flush() override;
+ void flushAndSignalSemaphores(int numSemaphores, GrBackendSemaphore* signalSemaphores);
+ void wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores);
bool onAccessPixels(SkPixmap*) override;
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index d52b73b2e8..95791f12bb 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -599,7 +599,7 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
}
if (kGL_GrGLStandard == standard) {
- if ((version >= GR_GL_VER(4, 0) || ctxInfo.hasExtension("GL_ARB_sample_shading")) &&
+ if ((version >= GR_GL_VER(4, 0) || ctxInfo.hasExtension("GL_ARB_sample_shading")) &&
ctxInfo.vendor() != kIntel_GrGLVendor) {
fSampleShadingSupport = true;
}
@@ -615,6 +615,12 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
} else if (version >= GR_GL_VER(3, 0)) {
fFenceSyncSupport = true;
}
+#ifdef SK_BUILD_FOR_MAC
+ if (kIntel_GrGLVendor == ctxInfo.vendor()) {
+ // See skia:6770
+ fFenceSyncSupport = false;
+ }
+#endif
// Safely moving textures between contexts requires fences.
fCrossContextTextureSupport = fFenceSyncSupport;
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index b3f8c2caa8..d40160044c 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -9,6 +9,7 @@
#include <cmath>
#include "../private/GrGLSL.h"
+#include "GrBackendSemaphore.h"
#include "GrBackendSurface.h"
#include "GrFixedClip.h"
#include "GrGLBuffer.h"
@@ -4288,10 +4289,16 @@ void GrGLGpu::deleteFence(GrFence fence) const {
this->deleteSync((GrGLsync)fence);
}
-sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrGLGpu::makeSemaphore() {
- return GrGLSemaphore::Make(this);
+sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrGLGpu::makeSemaphore(bool isOwned) {
+ return GrGLSemaphore::Make(this, isOwned);
}
+sk_sp<GrSemaphore> GrGLGpu::wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
+ GrWrapOwnership ownership) {
+ return GrGLSemaphore::MakeWrapped(this, semaphore.glSync(), ownership);
+}
+
+
void GrGLGpu::insertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) {
GrGLSemaphore* glSem = static_cast<GrGLSemaphore*>(semaphore.get());
@@ -4316,7 +4323,7 @@ void GrGLGpu::deleteSync(GrGLsync sync) const {
sk_sp<GrSemaphore> GrGLGpu::prepareTextureForCrossContextUsage(GrTexture* texture) {
// Set up a semaphore to be signaled once the data is ready, and flush GL
- sk_sp<GrSemaphore> semaphore = this->makeSemaphore();
+ sk_sp<GrSemaphore> semaphore = this->makeSemaphore(true);
this->insertSemaphore(semaphore, true);
return semaphore;
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index f121df3f01..80a12eb7cc 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -166,7 +166,9 @@ public:
bool waitFence(GrFence, uint64_t timeout) override;
void deleteFence(GrFence) const override;
- sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore() override;
+ sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned) override;
+ sk_sp<GrSemaphore> wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
+ GrWrapOwnership ownership) override;
void insertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) override;
void waitSemaphore(sk_sp<GrSemaphore> semaphore) override;
diff --git a/src/gpu/gl/GrGLSemaphore.h b/src/gpu/gl/GrGLSemaphore.h
index f439ebd294..cfc3de9951 100644
--- a/src/gpu/gl/GrGLSemaphore.h
+++ b/src/gpu/gl/GrGLSemaphore.h
@@ -10,16 +10,26 @@
#include "GrSemaphore.h"
-class GrGLGpu;
+#include "GrBackendSemaphore.h"
+#include "GrGLGpu.h"
class GrGLSemaphore : public GrSemaphore {
public:
- static sk_sp<GrGLSemaphore> Make(const GrGLGpu* gpu) {
- return sk_sp<GrGLSemaphore>(new GrGLSemaphore(gpu));
+ static sk_sp<GrGLSemaphore> Make(const GrGLGpu* gpu, bool isOwned) {
+ return sk_sp<GrGLSemaphore>(new GrGLSemaphore(gpu, isOwned));
+ }
+
+ static sk_sp<GrGLSemaphore> MakeWrapped(const GrGLGpu* gpu,
+ GrGLsync sync,
+ GrWrapOwnership ownership) {
+ auto sema = sk_sp<GrGLSemaphore>(new GrGLSemaphore(gpu,
+ kBorrow_GrWrapOwnership != ownership));
+ sema->setSync(sync);
+ return sema;
}
~GrGLSemaphore() override {
- if (fGpu) {
+ if (fIsOwned && fGpu) {
static_cast<const GrGLGpu*>(fGpu)->deleteSync(fSync);
}
}
@@ -28,9 +38,14 @@ public:
void setSync(const GrGLsync& sync) { fSync = sync; }
private:
- GrGLSemaphore(const GrGLGpu* gpu) : INHERITED(gpu), fSync(0) {}
+ GrGLSemaphore(const GrGLGpu* gpu, bool isOwned) : INHERITED(gpu), fSync(0), fIsOwned(isOwned) {}
+
+ void setBackendSemaphore(GrBackendSemaphore* backendSemaphore) const override {
+ backendSemaphore->initGL(fSync);
+ }
GrGLsync fSync;
+ bool fIsOwned;
typedef GrSemaphore INHERITED;
};
diff --git a/src/gpu/ops/GrSemaphoreOp.cpp b/src/gpu/ops/GrSemaphoreOp.cpp
index e83096d52a..f50d9c056d 100644
--- a/src/gpu/ops/GrSemaphoreOp.cpp
+++ b/src/gpu/ops/GrSemaphoreOp.cpp
@@ -14,15 +14,17 @@ class GrSignalSemaphoreOp final : public GrSemaphoreOp {
public:
DEFINE_OP_CLASS_ID
- static std::unique_ptr<GrSignalSemaphoreOp> Make(sk_sp<GrSemaphore> semaphore) {
- return std::unique_ptr<GrSignalSemaphoreOp>(new GrSignalSemaphoreOp(std::move(semaphore)));
+ static std::unique_ptr<GrSignalSemaphoreOp> Make(sk_sp<GrSemaphore> semaphore,
+ GrRenderTargetProxy* proxy) {
+ return std::unique_ptr<GrSignalSemaphoreOp>(new GrSignalSemaphoreOp(std::move(semaphore),
+ proxy));
}
const char* name() const override { return "SignalSemaphore"; }
private:
- explicit GrSignalSemaphoreOp(sk_sp<GrSemaphore> semaphore)
- : INHERITED(ClassID(), std::move(semaphore)) {}
+ explicit GrSignalSemaphoreOp(sk_sp<GrSemaphore> semaphore, GrRenderTargetProxy* proxy)
+ : INHERITED(ClassID(), std::move(semaphore), proxy) {}
void onExecute(GrOpFlushState* state) override {
state->gpu()->insertSemaphore(fSemaphore);
@@ -35,15 +37,17 @@ class GrWaitSemaphoreOp final : public GrSemaphoreOp {
public:
DEFINE_OP_CLASS_ID
- static std::unique_ptr<GrWaitSemaphoreOp> Make(sk_sp<GrSemaphore> semaphore) {
- return std::unique_ptr<GrWaitSemaphoreOp>(new GrWaitSemaphoreOp(std::move(semaphore)));
+ static std::unique_ptr<GrWaitSemaphoreOp> Make(sk_sp<GrSemaphore> semaphore,
+ GrRenderTargetProxy* proxy) {
+ return std::unique_ptr<GrWaitSemaphoreOp>(new GrWaitSemaphoreOp(std::move(semaphore),
+ proxy));
}
const char* name() const override { return "WaitSemaphore"; }
private:
- explicit GrWaitSemaphoreOp(sk_sp<GrSemaphore> semaphore)
- : INHERITED(ClassID(), std::move(semaphore)) {}
+ explicit GrWaitSemaphoreOp(sk_sp<GrSemaphore> semaphore, GrRenderTargetProxy* proxy)
+ : INHERITED(ClassID(), std::move(semaphore), proxy) {}
void onExecute(GrOpFlushState* state) override {
state->gpu()->waitSemaphore(fSemaphore);
@@ -54,12 +58,14 @@ private:
////////////////////////////////////////////////////////////////////////////////
-std::unique_ptr<GrSemaphoreOp> GrSemaphoreOp::MakeSignal(sk_sp<GrSemaphore> semaphore) {
- return GrSignalSemaphoreOp::Make(std::move(semaphore));
+std::unique_ptr<GrSemaphoreOp> GrSemaphoreOp::MakeSignal(sk_sp<GrSemaphore> semaphore,
+ GrRenderTargetProxy* proxy) {
+ return GrSignalSemaphoreOp::Make(std::move(semaphore), proxy);
}
-std::unique_ptr<GrSemaphoreOp> GrSemaphoreOp::MakeWait(sk_sp<GrSemaphore> semaphore) {
- return GrWaitSemaphoreOp::Make(std::move(semaphore));
+std::unique_ptr<GrSemaphoreOp> GrSemaphoreOp::MakeWait(sk_sp<GrSemaphore> semaphore,
+ GrRenderTargetProxy* proxy) {
+ return GrWaitSemaphoreOp::Make(std::move(semaphore), proxy);
}
diff --git a/src/gpu/ops/GrSemaphoreOp.h b/src/gpu/ops/GrSemaphoreOp.h
index a88b66cfc7..af9566aefd 100644
--- a/src/gpu/ops/GrSemaphoreOp.h
+++ b/src/gpu/ops/GrSemaphoreOp.h
@@ -10,18 +10,24 @@
#include "GrOp.h"
+#include "GrRenderTargetProxy.h"
#include "GrSemaphore.h"
#include "SkRefCnt.h"
class GrSemaphoreOp : public GrOp {
public:
- static std::unique_ptr<GrSemaphoreOp> MakeSignal(sk_sp<GrSemaphore> semaphore);
+ static std::unique_ptr<GrSemaphoreOp> MakeSignal(sk_sp<GrSemaphore> semaphore,
+ GrRenderTargetProxy* proxy);
- static std::unique_ptr<GrSemaphoreOp> MakeWait(sk_sp<GrSemaphore> semaphore);
+ static std::unique_ptr<GrSemaphoreOp> MakeWait(sk_sp<GrSemaphore> semaphore,
+ GrRenderTargetProxy* proxy);
protected:
- GrSemaphoreOp(uint32_t classId, sk_sp<GrSemaphore> semaphore)
- : INHERITED(classId), fSemaphore(std::move(semaphore)) {}
+ GrSemaphoreOp(uint32_t classId, sk_sp<GrSemaphore> semaphore, GrRenderTargetProxy* proxy)
+ : INHERITED(classId), fSemaphore(std::move(semaphore)) {
+ this->setBounds(SkRect::MakeIWH(proxy->width(), proxy->height()),
+ HasAABloat::kNo, IsZeroArea::kNo);
+ }
sk_sp<GrSemaphore> fSemaphore;
diff --git a/src/gpu/vk/GrVkCommandBuffer.cpp b/src/gpu/vk/GrVkCommandBuffer.cpp
index ea0a02cb34..63642d4ed0 100644
--- a/src/gpu/vk/GrVkCommandBuffer.cpp
+++ b/src/gpu/vk/GrVkCommandBuffer.cpp
@@ -402,7 +402,7 @@ void GrVkPrimaryCommandBuffer::submitToQueue(
const GrVkGpu* gpu,
VkQueue queue,
GrVkGpu::SyncQueue sync,
- const GrVkSemaphore::Resource* signalSemaphore,
+ SkTArray<const GrVkSemaphore::Resource*>& signalSemaphores,
SkTArray<const GrVkSemaphore::Resource*>& waitSemaphores) {
SkASSERT(!fIsActive);
@@ -418,23 +418,20 @@ void GrVkPrimaryCommandBuffer::submitToQueue(
GR_VK_CALL(gpu->vkInterface(), ResetFences(gpu->device(), 1, &fSubmitFence));
}
- if (signalSemaphore) {
- this->addResource(signalSemaphore);
+ int signalCount = signalSemaphores.count();
+ SkTArray<VkSemaphore> vkSignalSem(signalCount);
+ for (int i = 0; i < signalCount; ++i) {
+ this->addResource(signalSemaphores[i]);
+ vkSignalSem.push_back(signalSemaphores[i]->semaphore());
}
int waitCount = waitSemaphores.count();
SkTArray<VkSemaphore> vkWaitSems(waitCount);
SkTArray<VkPipelineStageFlags> vkWaitStages(waitCount);
- if (waitCount) {
- for (int i = 0; i < waitCount; ++i) {
- this->addResource(waitSemaphores[i]);
- vkWaitSems.push_back(waitSemaphores[i]->semaphore());
- vkWaitStages.push_back(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
- }
- }
- SkTArray<VkSemaphore> vkSignalSem;
- if (signalSemaphore) {
- vkSignalSem.push_back(signalSemaphore->semaphore());
+ for (int i = 0; i < waitCount; ++i) {
+ this->addResource(waitSemaphores[i]);
+ vkWaitSems.push_back(waitSemaphores[i]->semaphore());
+ vkWaitStages.push_back(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
}
VkSubmitInfo submitInfo;
diff --git a/src/gpu/vk/GrVkCommandBuffer.h b/src/gpu/vk/GrVkCommandBuffer.h
index 1f3c4a50e5..b387885fff 100644
--- a/src/gpu/vk/GrVkCommandBuffer.h
+++ b/src/gpu/vk/GrVkCommandBuffer.h
@@ -298,7 +298,7 @@ public:
const VkImageResolve* regions);
void submitToQueue(const GrVkGpu* gpu, VkQueue queue, GrVkGpu::SyncQueue sync,
- const GrVkSemaphore::Resource* signalSemaphore,
+ SkTArray<const GrVkSemaphore::Resource*>& signalSemaphores,
SkTArray<const GrVkSemaphore::Resource*>& waitSemaphores);
bool finished(const GrVkGpu* gpu) const;
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index f76f06cfc0..b10e9ed59d 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -7,6 +7,7 @@
#include "GrVkGpu.h"
+#include "GrBackendSemaphore.h"
#include "GrBackendSurface.h"
#include "GrContextOptions.h"
#include "GrGeometryProcessor.h"
@@ -191,6 +192,12 @@ void GrVkGpu::destroyResources() {
}
fSemaphoresToWaitOn.reset();
+ for (int i = 0; i < fSemaphoresToSignal.count(); ++i) {
+ fSemaphoresToSignal[i]->unref(this);
+ }
+ fSemaphoresToSignal.reset();
+
+
fCopyManager.destroyResources(this);
// must call this just before we destroy the command pool and VkDevice
@@ -226,12 +233,16 @@ void GrVkGpu::disconnect(DisconnectType type) {
for (int i = 0; i < fSemaphoresToWaitOn.count(); ++i) {
fSemaphoresToWaitOn[i]->unrefAndAbandon();
}
+ for (int i = 0; i < fSemaphoresToSignal.count(); ++i) {
+ fSemaphoresToSignal[i]->unrefAndAbandon();
+ }
fCopyManager.abandonResources();
// must call this just before we destroy the command pool and VkDevice
fResourceProvider.abandonResources();
}
fSemaphoresToWaitOn.reset();
+ fSemaphoresToSignal.reset();
#ifdef SK_ENABLE_VK_LAYERS
fCallback = VK_NULL_HANDLE;
#endif
@@ -249,17 +260,20 @@ GrGpuCommandBuffer* GrVkGpu::createCommandBuffer(
return new GrVkGpuCommandBuffer(this, colorInfo, stencilInfo);
}
-void GrVkGpu::submitCommandBuffer(SyncQueue sync,
- const GrVkSemaphore::Resource* signalSemaphore) {
+void GrVkGpu::submitCommandBuffer(SyncQueue sync) {
SkASSERT(fCurrentCmdBuffer);
fCurrentCmdBuffer->end(this);
- fCurrentCmdBuffer->submitToQueue(this, fQueue, sync, signalSemaphore, fSemaphoresToWaitOn);
+ fCurrentCmdBuffer->submitToQueue(this, fQueue, sync, fSemaphoresToSignal, fSemaphoresToWaitOn);
for (int i = 0; i < fSemaphoresToWaitOn.count(); ++i) {
fSemaphoresToWaitOn[i]->unref(this);
}
fSemaphoresToWaitOn.reset();
+ for (int i = 0; i < fSemaphoresToSignal.count(); ++i) {
+ fSemaphoresToSignal[i]->unref(this);
+ }
+ fSemaphoresToSignal.reset();
fResourceProvider.checkCommandBuffers();
@@ -1937,15 +1951,25 @@ void GrVkGpu::deleteFence(GrFence fence) const {
VK_CALL(DestroyFence(this->device(), (VkFence)fence, nullptr));
}
-sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrVkGpu::makeSemaphore() {
- return GrVkSemaphore::Make(this);
+sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrVkGpu::makeSemaphore(bool isOwned) {
+ return GrVkSemaphore::Make(this, isOwned);
+}
+
+sk_sp<GrSemaphore> GrVkGpu::wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
+ GrWrapOwnership ownership) {
+ return GrVkSemaphore::MakeWrapped(this, semaphore.vkSemaphore(), ownership);
}
-void GrVkGpu::insertSemaphore(sk_sp<GrSemaphore> semaphore, bool /*flush*/) {
+void GrVkGpu::insertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) {
GrVkSemaphore* vkSem = static_cast<GrVkSemaphore*>(semaphore.get());
- // We *always* flush, so ignore that parameter
- this->submitCommandBuffer(kSkip_SyncQueue, vkSem->getResource());
+ const GrVkSemaphore::Resource* resource = vkSem->getResource();
+ resource->ref();
+ fSemaphoresToSignal.push_back(resource);
+
+ if (flush) {
+ this->submitCommandBuffer(kSkip_SyncQueue);
+ }
}
void GrVkGpu::waitSemaphore(sk_sp<GrSemaphore> semaphore) {
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index f81daea336..236b34a3c1 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -131,7 +131,9 @@ public:
bool waitFence(GrFence, uint64_t timeout) override;
void deleteFence(GrFence) const override;
- sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore() override;
+ sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned) override;
+ sk_sp<GrSemaphore> wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
+ GrWrapOwnership ownership) override;
void insertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) override;
void waitSemaphore(sk_sp<GrSemaphore> semaphore) override;
@@ -208,12 +210,11 @@ private:
// Ends and submits the current command buffer to the queue and then creates a new command
// buffer and begins it. If sync is set to kForce_SyncQueue, the function will wait for all
- // work in the queue to finish before returning. If the signalSemaphore is not VK_NULL_HANDLE,
- // we will signal the semaphore at the end of this command buffer. If this GrVkGpu object has
- // any semaphores in fSemaphoresToWaitOn, we will add those wait semaphores to this command
- // buffer when submitting.
- void submitCommandBuffer(SyncQueue sync,
- const GrVkSemaphore::Resource* signalSemaphore = nullptr);
+ // work in the queue to finish before returning. If this GrVkGpu object has any semaphores in
+ // fSemaphoreToSignal, we will add those signal semaphores to the submission of this command
+ // buffer. If this GrVkGpu object has any semaphores in fSemaphoresToWaitOn, we will add those
+ // wait semaphores to the submission of this command buffer.
+ void submitCommandBuffer(SyncQueue sync);
void internalResolveRenderTarget(GrRenderTarget* target, bool requiresSubmit);
@@ -267,6 +268,7 @@ private:
GrVkPrimaryCommandBuffer* fCurrentCmdBuffer;
SkSTArray<1, const GrVkSemaphore::Resource*> fSemaphoresToWaitOn;
+ SkSTArray<1, const GrVkSemaphore::Resource*> fSemaphoresToSignal;
VkPhysicalDeviceMemoryProperties fPhysDevMemProps;
diff --git a/src/gpu/vk/GrVkSemaphore.cpp b/src/gpu/vk/GrVkSemaphore.cpp
index d84635f85e..d201458b27 100644
--- a/src/gpu/vk/GrVkSemaphore.cpp
+++ b/src/gpu/vk/GrVkSemaphore.cpp
@@ -7,6 +7,7 @@
#include "GrVkSemaphore.h"
+#include "GrBackendSemaphore.h"
#include "GrVkGpu.h"
#include "GrVkUtil.h"
@@ -15,7 +16,7 @@
#undef CreateSemaphore
#endif
-sk_sp<GrVkSemaphore> GrVkSemaphore::Make(const GrVkGpu* gpu) {
+sk_sp<GrVkSemaphore> GrVkSemaphore::Make(const GrVkGpu* gpu, bool isOwned) {
VkSemaphoreCreateInfo createInfo;
memset(&createInfo, 0, sizeof(VkFenceCreateInfo));
createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
@@ -25,11 +26,22 @@ sk_sp<GrVkSemaphore> GrVkSemaphore::Make(const GrVkGpu* gpu) {
GR_VK_CALL_ERRCHECK(gpu->vkInterface(),
CreateSemaphore(gpu->device(), &createInfo, nullptr, &semaphore));
- return sk_sp<GrVkSemaphore>(new GrVkSemaphore(gpu, semaphore));
+ return sk_sp<GrVkSemaphore>(new GrVkSemaphore(gpu, semaphore, isOwned));
}
-GrVkSemaphore::GrVkSemaphore(const GrVkGpu* gpu, VkSemaphore semaphore) : INHERITED(gpu) {
- fResource = new Resource(semaphore);
+sk_sp<GrVkSemaphore> GrVkSemaphore::MakeWrapped(const GrVkGpu* gpu,
+ VkSemaphore semaphore,
+ GrWrapOwnership ownership) {
+ if (VK_NULL_HANDLE == semaphore) {
+ return nullptr;
+ }
+ return sk_sp<GrVkSemaphore>(new GrVkSemaphore(gpu, semaphore,
+ kBorrow_GrWrapOwnership != ownership));
+}
+
+GrVkSemaphore::GrVkSemaphore(const GrVkGpu* gpu, VkSemaphore semaphore, bool isOwned)
+ : INHERITED(gpu) {
+ fResource = new Resource(semaphore, isOwned);
}
GrVkSemaphore::~GrVkSemaphore() {
@@ -41,7 +53,13 @@ GrVkSemaphore::~GrVkSemaphore() {
}
void GrVkSemaphore::Resource::freeGPUData(const GrVkGpu* gpu) const {
- GR_VK_CALL(gpu->vkInterface(),
- DestroySemaphore(gpu->device(), fSemaphore, nullptr));
+ if (fIsOwned) {
+ GR_VK_CALL(gpu->vkInterface(),
+ DestroySemaphore(gpu->device(), fSemaphore, nullptr));
+ }
+}
+
+void GrVkSemaphore::setBackendSemaphore(GrBackendSemaphore* backendSemaphore) const {
+ backendSemaphore->initVulkan(fResource->semaphore());
}
diff --git a/src/gpu/vk/GrVkSemaphore.h b/src/gpu/vk/GrVkSemaphore.h
index 0a3bc1742b..b99eb944f7 100644
--- a/src/gpu/vk/GrVkSemaphore.h
+++ b/src/gpu/vk/GrVkSemaphore.h
@@ -13,17 +13,23 @@
#include "vk/GrVkTypes.h"
+class GrBackendSemaphore;
class GrVkGpu;
class GrVkSemaphore : public GrSemaphore {
public:
- static sk_sp<GrVkSemaphore> Make(const GrVkGpu* gpu);
+ static sk_sp<GrVkSemaphore> Make(const GrVkGpu* gpu, bool isOwned);
+
+ static sk_sp<GrVkSemaphore> MakeWrapped(const GrVkGpu* gpu,
+ VkSemaphore semaphore,
+ GrWrapOwnership);
~GrVkSemaphore() override;
class Resource : public GrVkResource {
public:
- Resource(VkSemaphore semaphore) : INHERITED(), fSemaphore(semaphore) {}
+ Resource(VkSemaphore semaphore, bool isOwned)
+ : INHERITED(), fSemaphore(semaphore), fIsOwned(isOwned) {}
~Resource() override {}
@@ -38,6 +44,7 @@ public:
void freeGPUData(const GrVkGpu* gpu) const override;
VkSemaphore fSemaphore;
+ bool fIsOwned;
typedef GrVkResource INHERITED;
};
@@ -45,7 +52,9 @@ public:
const Resource* getResource() const { return fResource; }
private:
- GrVkSemaphore(const GrVkGpu* gpu, VkSemaphore semaphore);
+ GrVkSemaphore(const GrVkGpu* gpu, VkSemaphore semaphore, bool isOwned);
+
+ void setBackendSemaphore(GrBackendSemaphore*) const override;
const Resource* fResource;
diff --git a/src/image/SkSurface.cpp b/src/image/SkSurface.cpp
index cd2a5f185f..fbd9f836d6 100644
--- a/src/image/SkSurface.cpp
+++ b/src/image/SkSurface.cpp
@@ -184,7 +184,19 @@ bool SkSurface::getRenderTargetHandle(GrBackendObject* obj, BackendHandleAccess
}
void SkSurface::prepareForExternalIO() {
- asSB(this)->onPrepareForExternalIO();
+ this->flush();
+}
+
+void SkSurface::flush() {
+ asSB(this)->onFlush(0, nullptr);
+}
+
+void SkSurface::flushAndSignalSemaphores(int numSemaphores, GrBackendSemaphore* signalSemaphores) {
+ return asSB(this)->onFlush(numSemaphores, signalSemaphores);
+}
+
+void SkSurface::wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
+ asSB(this)->onWait(numSemaphores, waitSemaphores);
}
//////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/image/SkSurface_Base.h b/src/image/SkSurface_Base.h
index 1b0f9ff975..264a86fc9d 100644
--- a/src/image/SkSurface_Base.h
+++ b/src/image/SkSurface_Base.h
@@ -77,8 +77,17 @@ public:
/**
* Issue any pending surface IO to the current backend 3D API and resolve any surface MSAA.
+ * Inserts the requested number of semaphores for the gpu to signal when work is complete on the
+ * gpu and inits the array of GrBackendSemaphores with the signaled semaphores.
*/
- virtual void onPrepareForExternalIO() {}
+ virtual void onFlush(int numSemaphores, GrBackendSemaphore* signalSemaphores) {}
+
+ /**
+ * Caused the current backend 3D API to wait on the passed in semaphores before executing new
+ * commands on the gpu. Any previously submitting commands will not be blocked by these
+ * semaphores.
+ */
+ virtual void onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {}
inline SkCanvas* getCachedCanvas();
inline sk_sp<SkImage> refCachedImage();
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp
index d55888767a..0f4b2cb84e 100644
--- a/src/image/SkSurface_Gpu.cpp
+++ b/src/image/SkSurface_Gpu.cpp
@@ -166,8 +166,12 @@ void SkSurface_Gpu::onDiscard() {
fDevice->accessRenderTargetContext()->discard();
}
-void SkSurface_Gpu::onPrepareForExternalIO() {
- fDevice->flush();
+void SkSurface_Gpu::onFlush(int numSemaphores, GrBackendSemaphore* signalSemaphores) {
+ fDevice->flushAndSignalSemaphores(numSemaphores, signalSemaphores);
+}
+
+void SkSurface_Gpu::onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
+ fDevice->wait(numSemaphores, waitSemaphores);
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/image/SkSurface_Gpu.h b/src/image/SkSurface_Gpu.h
index cc8b87dc41..e22ae10bd8 100644
--- a/src/image/SkSurface_Gpu.h
+++ b/src/image/SkSurface_Gpu.h
@@ -26,7 +26,8 @@ public:
sk_sp<SkImage> onNewImageSnapshot() override;
void onCopyOnWrite(ContentChangeMode) override;
void onDiscard() override;
- void onPrepareForExternalIO() override;
+ void onFlush(int numSemaphores, GrBackendSemaphore* signalSemaphores) override;
+ void onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) override;
SkGpuDevice* getDevice() { return fDevice.get(); }
diff --git a/tests/OnFlushCallbackTest.cpp b/tests/OnFlushCallbackTest.cpp
index f4dd25f3fe..81cd5daa1d 100644
--- a/tests/OnFlushCallbackTest.cpp
+++ b/tests/OnFlushCallbackTest.cpp
@@ -9,6 +9,7 @@
#if SK_SUPPORT_GPU
+#include "GrBackendSemaphore.h"
#include "GrClip.h"
#include "GrContextPriv.h"
#include "GrDefaultGeoProcFactory.h"
@@ -575,7 +576,7 @@ DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(OnFlushCallbackTest, reporter, ctxInfo) {
rtc->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), r);
}
- rtc->prepareForExternalIO();
+ rtc->prepareForExternalIO(0, nullptr);
SkBitmap readBack;
readBack.allocN32Pixels(kFinalWidth, kFinalHeight);
diff --git a/tests/SurfaceSemaphoreTest.cpp b/tests/SurfaceSemaphoreTest.cpp
new file mode 100644
index 0000000000..72e8e05401
--- /dev/null
+++ b/tests/SurfaceSemaphoreTest.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkTypes.h"
+
+#if SK_SUPPORT_GPU
+#include "GrContextFactory.h"
+#include "GrTest.h"
+#include "Test.h"
+
+#include "GrBackendSemaphore.h"
+#include "GrBackendSurface.h"
+#include "SkCanvas.h"
+#include "SkSurface.h"
+
+#ifdef SK_VULKAN
+#include "vk/GrVkTypes.h"
+#endif
+
+static const int MAIN_W = 8, MAIN_H = 16;
+static const int CHILD_W = 16, CHILD_H = 16;
+
+void check_pixels(skiatest::Reporter* reporter, const SkBitmap& bitmap) {
+ const uint32_t* canvasPixels = static_cast<const uint32_t*>(bitmap.getPixels());
+
+ bool failureFound = false;
+ SkPMColor expectedPixel;
+ for (int cy = 0; cy < CHILD_H && !failureFound; ++cy) {
+ for (int cx = 0; cx < CHILD_W && !failureFound; ++cx) {
+ SkPMColor canvasPixel = canvasPixels[cy * CHILD_W + cx];
+ if (cy < CHILD_H / 2) {
+ if (cx < CHILD_W / 2) {
+ expectedPixel = 0xFF0000FF; // Red
+ } else {
+ expectedPixel = 0xFFFF0000; // Blue
+ }
+ } else {
+ expectedPixel = 0xFF00FF00; // Green
+ }
+ if (expectedPixel != canvasPixel) {
+ failureFound = true;
+ ERRORF(reporter, "Wrong color at %d, %d. Got 0x%08x when we expected 0x%08x",
+ cx, cy, canvasPixel, expectedPixel);
+ }
+ }
+ }
+}
+
+void draw_child(skiatest::Reporter* reporter,
+ const sk_gpu_test::ContextInfo& childInfo,
+ const GrBackendObject& backendImage,
+ const GrBackendSemaphore& semaphore) {
+ GrBackendTexture backendTexture = GrTest::CreateBackendTexture(childInfo.backend(),
+ MAIN_W, MAIN_H,
+ kRGBA_8888_GrPixelConfig,
+ backendImage);
+
+ childInfo.testContext()->makeCurrent();
+
+ const SkImageInfo childII = SkImageInfo::Make(CHILD_W, CHILD_H, kRGBA_8888_SkColorType,
+ kPremul_SkAlphaType);
+
+ GrContext* childCtx = childInfo.grContext();
+ sk_sp<SkSurface> childSurface(SkSurface::MakeRenderTarget(childCtx, SkBudgeted::kNo,
+ childII, 0, kTopLeft_GrSurfaceOrigin,
+ nullptr));
+
+ sk_sp<SkImage> childImage = SkImage::MakeFromTexture(childCtx,
+ backendTexture,
+ kTopLeft_GrSurfaceOrigin,
+ kPremul_SkAlphaType,
+ nullptr);
+
+ SkCanvas* childCanvas = childSurface->getCanvas();
+ childCanvas->clear(SK_ColorRED);
+
+ childSurface->wait(1, &semaphore);
+
+ childCanvas->drawImage(childImage, CHILD_W/2, 0);
+
+ SkPaint paint;
+ paint.setColor(SK_ColorGREEN);
+ SkIRect rect = SkIRect::MakeLTRB(0, CHILD_H/2, CHILD_W, CHILD_H);
+ childCanvas->drawIRect(rect, paint);
+
+ // read pixels
+ SkBitmap bitmap;
+ bitmap.allocPixels(childII);
+ childCanvas->readPixels(bitmap, 0, 0);
+
+ check_pixels(reporter, bitmap);
+}
+
+void surface_semaphore_test(skiatest::Reporter* reporter,
+ const sk_gpu_test::ContextInfo& mainInfo,
+ const sk_gpu_test::ContextInfo& childInfo1,
+ const sk_gpu_test::ContextInfo& childInfo2) {
+ GrContext* mainCtx = mainInfo.grContext();
+ if (!mainCtx->caps()->fenceSyncSupport()) {
+ return;
+ }
+
+ const SkImageInfo ii = SkImageInfo::Make(MAIN_W, MAIN_H, kRGBA_8888_SkColorType,
+ kPremul_SkAlphaType);
+
+ sk_sp<SkSurface> mainSurface(SkSurface::MakeRenderTarget(mainCtx, SkBudgeted::kNo,
+ ii, 0, kTopLeft_GrSurfaceOrigin,
+ nullptr));
+ SkCanvas* mainCanvas = mainSurface->getCanvas();
+ mainCanvas->clear(SK_ColorBLUE);
+
+ SkAutoTArray<GrBackendSemaphore> semaphores(2);
+
+ mainSurface->flushAndSignalSemaphores(2, semaphores.get());
+
+ sk_sp<SkImage> mainImage = mainSurface->makeImageSnapshot();
+ GrBackendObject backendImage = mainImage->getTextureHandle(false);
+
+ draw_child(reporter, childInfo1, backendImage, semaphores[0]);
+
+#ifdef SK_VULKAN
+ if (kVulkan_GrBackend == mainInfo.backend()) {
+ // In Vulkan we need to make sure we are sending the correct VkImageLayout in with the
+ // backendImage. After the first child draw the layout gets changed to SHADER_READ, so
+ // we just manually set that here.
+ GrVkImageInfo* vkInfo = (GrVkImageInfo*)backendImage;
+ vkInfo->updateImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+ }
+#endif
+
+ draw_child(reporter, childInfo2, backendImage, semaphores[1]);
+}
+
+DEF_GPUTEST(SurfaceSemaphores, reporter, factory) {
+#if defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_MAC)
+ static constexpr auto kNativeGLType = sk_gpu_test::GrContextFactory::kGL_ContextType;
+#else
+ static constexpr auto kNativeGLType = sk_gpu_test::GrContextFactory::kGLES_ContextType;
+#endif
+
+ for (int typeInt = 0; typeInt < sk_gpu_test::GrContextFactory::kContextTypeCnt; ++typeInt) {
+ sk_gpu_test::GrContextFactory::ContextType contextType =
+ (sk_gpu_test::GrContextFactory::ContextType) typeInt;
+ // Use "native" instead of explicitly trying OpenGL and OpenGL ES. Do not use GLES on
+ // desktop since tests do not account for not fixing http://skbug.com/2809
+ if (contextType == sk_gpu_test::GrContextFactory::kGL_ContextType ||
+ contextType == sk_gpu_test::GrContextFactory::kGLES_ContextType) {
+ if (contextType != kNativeGLType) {
+ continue;
+ }
+ }
+ sk_gpu_test::ContextInfo ctxInfo = factory->getContextInfo(
+ contextType, sk_gpu_test::GrContextFactory::ContextOverrides::kDisableNVPR);
+ if (!sk_gpu_test::GrContextFactory::IsRenderingContext(contextType)) {
+ continue;
+ }
+ skiatest::ReporterContext ctx(
+ reporter, SkString(sk_gpu_test::GrContextFactory::ContextTypeName(contextType)));
+ if (ctxInfo.grContext()) {
+ sk_gpu_test::ContextInfo child1 = factory->getSharedContextInfo(ctxInfo.grContext(), 0);
+ sk_gpu_test::ContextInfo child2 = factory->getSharedContextInfo(ctxInfo.grContext(), 1);
+ if (!child1.grContext() || !child2.grContext()) {
+ continue;
+ }
+
+ surface_semaphore_test(reporter, ctxInfo, child1, child2);
+ }
+ }
+}
+
+#endif
diff --git a/tools/gpu/GrContextFactory.h b/tools/gpu/GrContextFactory.h
index dff8d5180c..508249b8d8 100644
--- a/tools/gpu/GrContextFactory.h
+++ b/tools/gpu/GrContextFactory.h
@@ -83,6 +83,37 @@ public:
}
}
+ static const char* ContextTypeName(ContextType contextType) {
+ switch (contextType) {
+ case kGL_ContextType:
+ return "OpenGL";
+ case kGLES_ContextType:
+ return "OpenGLES";
+ case kANGLE_D3D9_ES2_ContextType:
+ return "ANGLE D3D9 ES2";
+ case kANGLE_D3D11_ES2_ContextType:
+ return "ANGLE D3D11 ES2";
+ case kANGLE_D3D11_ES3_ContextType:
+ return "ANGLE D3D11 ES3";
+ case kANGLE_GL_ES2_ContextType:
+ return "ANGLE GL ES2";
+ case kANGLE_GL_ES3_ContextType:
+ return "ANGLE GL ES3";
+ case kCommandBuffer_ContextType:
+ return "Command Buffer";
+ case kMESA_ContextType:
+ return "Mesa";
+ case kNullGL_ContextType:
+ return "Null GL";
+ case kDebugGL_ContextType:
+ return "Debug GL";
+ case kVulkan_ContextType:
+ return "Vulkan";
+ }
+ SkDEBUGFAIL("Unreachable");
+ return "Unknown";
+ }
+
explicit GrContextFactory(const GrContextOptions& opts);
GrContextFactory();
diff --git a/tools/gpu/GrTest.cpp b/tools/gpu/GrTest.cpp
index f182a966bc..93e5f6e3b9 100644
--- a/tools/gpu/GrTest.cpp
+++ b/tools/gpu/GrTest.cpp
@@ -346,7 +346,9 @@ public:
bool waitFence(GrFence, uint64_t) override { return true; }
void deleteFence(GrFence) const override {}
- sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore() override { return nullptr; }
+ sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT makeSemaphore(bool isOwned) override { return nullptr; }
+ sk_sp<GrSemaphore> wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
+ GrWrapOwnership ownership) override { return nullptr; }
void insertSemaphore(sk_sp<GrSemaphore> semaphore, bool flush) override {}
void waitSemaphore(sk_sp<GrSemaphore> semaphore) override {}
sk_sp<GrSemaphore> prepareTextureForCrossContextUsage(GrTexture*) override { return nullptr; }