From 84741b308496409f4ff662658167221fc6801bbe Mon Sep 17 00:00:00 2001 From: jvanverth Date: Fri, 30 Sep 2016 08:39:02 -0700 Subject: [PATCH] Add fence support for TransferBuffers BUG=skia:4604 GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2384463003 Review-Url: https://codereview.chromium.org/2384463003 --- include/gpu/GrCaps.h | 4 ++++ include/gpu/GrTypesPriv.h | 5 +++++ include/gpu/gl/GrGLFunctions.h | 5 +++++ include/gpu/gl/GrGLInterface.h | 5 +++++ include/gpu/gl/GrGLTypes.h | 1 + src/gpu/GrCaps.cpp | 4 ++++ src/gpu/GrGpu.cpp | 9 ++++++++- src/gpu/GrGpu.h | 6 +++++- src/gpu/gl/GrGLAssembleInterface.cpp | 14 +++++++++++++- src/gpu/gl/GrGLCaps.cpp | 9 +++++++++ src/gpu/gl/GrGLDefines.h | 8 ++++++++ src/gpu/gl/GrGLGpu.cpp | 16 ++++++++++++++++ src/gpu/gl/GrGLGpu.h | 4 ++++ src/gpu/gl/GrGLInterface.cpp | 18 ++++++++++++++++++ src/gpu/gl/GrGLTestInterface.cpp | 3 +++ src/gpu/gl/GrGLTestInterface.h | 3 +++ src/gpu/vk/GrVkCaps.cpp | 1 + src/gpu/vk/GrVkGpu.cpp | 28 ++++++++++++++++++++++++++++ src/gpu/vk/GrVkGpu.h | 4 ++++ tools/gpu/GrTest.cpp | 4 ++++ 20 files changed, 148 insertions(+), 3 deletions(-) diff --git a/include/gpu/GrCaps.h b/include/gpu/GrCaps.h index b7c91c4..a97be72 100644 --- a/include/gpu/GrCaps.h +++ b/include/gpu/GrCaps.h @@ -286,6 +286,8 @@ public: bool sampleShadingSupport() const { return fSampleShadingSupport; } + bool fenceSyncSupport() const { return fFenceSyncSupport; } + protected: /** Subclasses must call this at the end of their constructors in order to apply caps overrides requested by the client. Note that overrides will only reduce the caps never @@ -324,6 +326,8 @@ protected: bool fPreferVRAMUseOverFlushes : 1; bool fSampleShadingSupport : 1; + // TODO: this may need to be an enum to support different fence types + bool fFenceSyncSupport : 1; InstancedSupport fInstancedSupport; diff --git a/include/gpu/GrTypesPriv.h b/include/gpu/GrTypesPriv.h index d60fab1..636e72a 100644 --- a/include/gpu/GrTypesPriv.h +++ b/include/gpu/GrTypesPriv.h @@ -482,4 +482,9 @@ template T * const * sk_sp_address_as_pointer_address(sk_sp cons return reinterpret_cast(sp); } +/* + * Object for CPU-GPU synchronization + */ +typedef intptr_t GrFence; + #endif diff --git a/include/gpu/gl/GrGLFunctions.h b/include/gpu/gl/GrGLFunctions.h index 7e720cd..eccd1bf 100644 --- a/include/gpu/gl/GrGLFunctions.h +++ b/include/gpu/gl/GrGLFunctions.h @@ -345,6 +345,11 @@ typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLFlushMappedNamedBufferRangeProc)(GrGL // OpenGL 3.1 typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLTextureBufferProc)(GrGLuint texture, GrGLenum target, GrGLenum internalformat, GrGLuint buffer); +/* ARB_sync */ +typedef GrGLsync (GR_GL_FUNCTION_TYPE* GrGLFenceSyncProc)(GrGLenum condition, GrGLbitfield flags); +typedef GrGLenum (GR_GL_FUNCTION_TYPE* GrGLClientWaitSyncProc)(GrGLsync sync, GrGLbitfield flags, GrGLuint64 timeout); +typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDeleteSyncProc)(GrGLsync sync); + /* KHR_debug */ typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDebugMessageControlProc)(GrGLenum source, GrGLenum type, GrGLenum severity, GrGLsizei count, const GrGLuint* ids, GrGLboolean enabled); typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDebugMessageInsertProc)(GrGLenum source, GrGLenum type, GrGLuint id, GrGLenum severity, GrGLsizei length, const GrGLchar* buf); diff --git a/include/gpu/gl/GrGLInterface.h b/include/gpu/gl/GrGLInterface.h index 27184ad..60109ec 100644 --- a/include/gpu/gl/GrGLInterface.h +++ b/include/gpu/gl/GrGLInterface.h @@ -452,6 +452,11 @@ public: // OpenGL 3.1 GrGLFunction fTextureBuffer; + /* ARB_sync */ + GrGLFunction fFenceSync; + GrGLFunction fClientWaitSync; + GrGLFunction fDeleteSync; + /* KHR_debug */ GrGLFunction fDebugMessageControl; GrGLFunction fDebugMessageInsert; diff --git a/include/gpu/gl/GrGLTypes.h b/include/gpu/gl/GrGLTypes.h index d0edcf1..5b9e31d 100644 --- a/include/gpu/gl/GrGLTypes.h +++ b/include/gpu/gl/GrGLTypes.h @@ -58,6 +58,7 @@ typedef signed long int GrGLintptr; typedef signed long int GrGLsizeiptr; #endif typedef void* GrGLeglImage; +typedef void* GrGLsync; struct GrGLDrawArraysIndirectCommand { GrGLuint fCount; diff --git a/src/gpu/GrCaps.cpp b/src/gpu/GrCaps.cpp index 9f92210..0f77b5a 100644 --- a/src/gpu/GrCaps.cpp +++ b/src/gpu/GrCaps.cpp @@ -103,6 +103,7 @@ GrCaps::GrCaps(const GrContextOptions& options) { fFullClearIsFree = false; fMustClearUploadedBufferData = false; fSampleShadingSupport = false; + fFenceSyncSupport = false; fUseDrawInsteadOfClear = false; @@ -189,6 +190,9 @@ SkString GrCaps::dump() const { r.appendf("Prefer client-side dynamic buffers : %s\n", gNY[fPreferClientSideDynamicBuffers]); r.appendf("Full screen clear is free : %s\n", gNY[fFullClearIsFree]); r.appendf("Must clear buffer memory : %s\n", gNY[fMustClearUploadedBufferData]); + r.appendf("Sample shading support : %s\n", gNY[fSampleShadingSupport]); + r.appendf("Fence sync support : %s\n", gNY[fFenceSyncSupport]); + r.appendf("Draw Instead of Clear [workaround] : %s\n", gNY[fUseDrawInsteadOfClear]); r.appendf("Draw Instead of TexSubImage [workaround] : %s\n", gNY[fUseDrawInsteadOfPartialRenderTargetWrite]); diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp index e14e892..0de9fed 100644 --- a/src/gpu/GrGpu.cpp +++ b/src/gpu/GrGpu.cpp @@ -402,8 +402,9 @@ bool GrGpu::writePixels(GrSurface* surface, bool GrGpu::transferPixels(GrSurface* surface, int left, int top, int width, int height, GrPixelConfig config, GrBuffer* transferBuffer, - size_t offset, size_t rowBytes) { + size_t offset, size_t rowBytes, GrFence* fence) { SkASSERT(transferBuffer); + SkASSERT(fence); this->handleDirtyContext(); if (this->onTransferPixels(surface, left, top, width, height, config, @@ -411,6 +412,12 @@ bool GrGpu::transferPixels(GrSurface* surface, SkIRect rect = SkIRect::MakeXYWH(left, top, width, height); this->didWriteToSurface(surface, &rect); fStats.incTransfersToTexture(); + + if (*fence) { + this->deleteFence(*fence); + } + *fence = this->insertFence(); + return true; } return false; diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h index 3e3a4cd..b8703dc 100644 --- a/src/gpu/GrGpu.h +++ b/src/gpu/GrGpu.h @@ -305,7 +305,7 @@ public: bool transferPixels(GrSurface* surface, int left, int top, int width, int height, GrPixelConfig config, GrBuffer* transferBuffer, - size_t offset, size_t rowBytes); + size_t offset, size_t rowBytes, GrFence* fence); /** * This is can be called before allocating a texture to be a dst for copySurface. This is only @@ -371,6 +371,10 @@ public: // Provides a hook for post-flush actions (e.g. PLS reset and Vulkan command buffer submits). virtual void finishDrawTarget() {} + virtual GrFence SK_WARN_UNUSED_RESULT insertFence() const = 0; + virtual bool waitFence(GrFence, uint64_t timeout = 1000) const = 0; + virtual void deleteFence(GrFence) const = 0; + /////////////////////////////////////////////////////////////////////////// // Debugging and Stats diff --git a/src/gpu/gl/GrGLAssembleInterface.cpp b/src/gpu/gl/GrGLAssembleInterface.cpp index e804dd6..b435655 100644 --- a/src/gpu/gl/GrGLAssembleInterface.cpp +++ b/src/gpu/gl/GrGLAssembleInterface.cpp @@ -522,10 +522,16 @@ const GrGLInterface* GrGLAssembleGLInterface(void* ctx, GrGLGetProc get) { GET_EGL_PROC_SUFFIX(DestroyImage, KHR); } - if (glVer >= GR_GL_VER(4,0) || extensions.has("GL_ARB_sample_shading")) { + if (glVer >= GR_GL_VER(4, 0) || extensions.has("GL_ARB_sample_shading")) { GET_PROC(MinSampleShading); } + if (glVer >= GR_GL_VER(3, 2) || extensions.has("GL_ARB_sync")) { + GET_PROC(FenceSync); + GET_PROC(ClientWaitSync); + GET_PROC(DeleteSync); + } + interface->fStandard = kGL_GrGLStandard; interface->fExtensions.swap(&extensions); @@ -919,6 +925,12 @@ const GrGLInterface* GrGLAssembleGLESInterface(void* ctx, GrGLGetProc get) { GET_PROC_SUFFIX(MinSampleShading, OES); } + if (version >= GR_GL_VER(3, 0)) { + GET_PROC(FenceSync); + GET_PROC(ClientWaitSync); + GET_PROC(DeleteSync); + } + interface->fStandard = kGLES_GrGLStandard; interface->fExtensions.swap(&extensions); diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index feb3eb6..1a7b105 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -550,6 +550,15 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, fSampleShadingSupport = true; } + // TODO: support CHROMIUM_sync_point and maybe KHR_fence_sync + if (kGL_GrGLStandard == standard) { + if (version >= GR_GL_VER(3, 2) || ctxInfo.hasExtension("GL_ARB_sync")) { + fFenceSyncSupport = true; + } + } else if (version >= GR_GL_VER(3, 0)) { + fFenceSyncSupport = true; + } + // We support manual mip-map generation (via iterative downsampling draw calls). This fixes // bugs on some cards/drivers that produce incorrect mip-maps for sRGB textures when using // glGenerateMipmap. Our implementation requires mip-level sampling control. Additionally, diff --git a/src/gpu/gl/GrGLDefines.h b/src/gpu/gl/GrGLDefines.h index 8cd3751..8dc7af1 100644 --- a/src/gpu/gl/GrGLDefines.h +++ b/src/gpu/gl/GrGLDefines.h @@ -967,6 +967,14 @@ #define GR_GL_INCLUSIVE 0x8f10 #define GR_GL_EXCLUSIVE 0x8f11 +/* GL_ARB_sync */ +#define GR_GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 +#define GR_GL_ALREADY_SIGNALED 0x911A +#define GR_GL_TIMEOUT_EXPIRED 0x911B +#define GR_GL_CONDITION_SATISFIED 0x911C +#define GR_GL_WAIT_FAILED 0x911D +#define GR_GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 + /* EGL Defines */ #define GR_EGL_NO_DISPLAY ((GrEGLDisplay)0) #define GR_EGL_EXTENSIONS 0x3055 diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index fcd3270..5755702 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -4694,3 +4694,19 @@ bool GrGLGpu::onMakeCopyForTextureParams(GrTexture* texture, const GrTexturePara } return false; } + +GrFence SK_WARN_UNUSED_RESULT GrGLGpu::insertFence() const { + GrGLsync fence; + GL_CALL_RET(fence, FenceSync(GR_GL_SYNC_GPU_COMMANDS_COMPLETE, 0)); + return (GrFence)fence; +} + +bool GrGLGpu::waitFence(GrFence fence, uint64_t timeout) const { + GrGLenum result; + GL_CALL_RET(result, ClientWaitSync((GrGLsync)fence, GR_GL_SYNC_FLUSH_COMMANDS_BIT, timeout)); + return (GR_GL_CONDITION_SATISFIED == result); +} + +void GrGLGpu::deleteFence(GrFence fence) const { + GL_CALL(DeleteSync((GrGLsync)fence)); +} diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h index 20616e4..7ba79b2 100644 --- a/src/gpu/gl/GrGLGpu.h +++ b/src/gpu/gl/GrGLGpu.h @@ -144,6 +144,10 @@ public: void finishDrawTarget() override; + GrFence SK_WARN_UNUSED_RESULT insertFence() const override; + bool waitFence(GrFence, uint64_t timeout) const override; + void deleteFence(GrFence) const override; + private: GrGLGpu(GrGLContext* ctx, GrContext* context); diff --git a/src/gpu/gl/GrGLInterface.cpp b/src/gpu/gl/GrGLInterface.cpp index c3fc8a8..0a157dd 100644 --- a/src/gpu/gl/GrGLInterface.cpp +++ b/src/gpu/gl/GrGLInterface.cpp @@ -786,6 +786,24 @@ bool GrGLInterface::validate() const { } } + if (kGL_GrGLStandard == fStandard) { + if (glVer >= GR_GL_VER(3, 2) || fExtensions.has("GL_ARB_sync")) { + if (nullptr == fFunctions.fFenceSync || + nullptr == fFunctions.fClientWaitSync || + nullptr == fFunctions.fDeleteSync) { + RETURN_FALSE_INTERFACE + } + } + } else if (kGLES_GrGLStandard == fStandard) { + if (glVer >= GR_GL_VER(3, 0)) { + if (nullptr == fFunctions.fFenceSync || + nullptr == fFunctions.fClientWaitSync || + nullptr == fFunctions.fDeleteSync) { + RETURN_FALSE_INTERFACE + } + } + } + if (fExtensions.has("EGL_KHR_image") || fExtensions.has("EGL_KHR_image_base")) { if (nullptr == fFunctions.fEGLCreateImage || nullptr == fFunctions.fEGLDestroyImage) { diff --git a/src/gpu/gl/GrGLTestInterface.cpp b/src/gpu/gl/GrGLTestInterface.cpp index 10968a7..d871ef6 100644 --- a/src/gpu/gl/GrGLTestInterface.cpp +++ b/src/gpu/gl/GrGLTestInterface.cpp @@ -312,6 +312,9 @@ GrGLTestInterface::GrGLTestInterface() { fFunctions.fMapNamedBufferRange = bind_to_member(this, &GrGLTestInterface::mapNamedBufferRange); fFunctions.fFlushMappedNamedBufferRange = bind_to_member(this, &GrGLTestInterface::flushMappedNamedBufferRange); fFunctions.fTextureBuffer = bind_to_member(this, &GrGLTestInterface::textureBuffer); + fFunctions.fFenceSync = bind_to_member(this, &GrGLTestInterface::fenceSync); + fFunctions.fClientWaitSync = bind_to_member(this, &GrGLTestInterface::clientWaitSync); + fFunctions.fDeleteSync = bind_to_member(this, &GrGLTestInterface::deleteSync); fFunctions.fDebugMessageControl = bind_to_member(this, &GrGLTestInterface::debugMessageControl); fFunctions.fDebugMessageInsert = bind_to_member(this, &GrGLTestInterface::debugMessageInsert); fFunctions.fDebugMessageCallback = bind_to_member(this, &GrGLTestInterface::debugMessageCallback); diff --git a/src/gpu/gl/GrGLTestInterface.h b/src/gpu/gl/GrGLTestInterface.h index fc837bf..ef00df3 100644 --- a/src/gpu/gl/GrGLTestInterface.h +++ b/src/gpu/gl/GrGLTestInterface.h @@ -317,6 +317,9 @@ public: virtual GrGLvoid* mapNamedBufferRange(GrGLuint buffer, GrGLintptr offset, GrGLsizeiptr length, GrGLbitfield access) { return nullptr; } virtual GrGLvoid flushMappedNamedBufferRange(GrGLuint buffer, GrGLintptr offset, GrGLsizeiptr length) {} virtual GrGLvoid textureBuffer(GrGLuint texture, GrGLenum target, GrGLenum internalformat, GrGLuint buffer) {} + virtual GrGLsync fenceSync(GrGLenum condition, GrGLbitfield flags) { return nullptr; } + virtual GrGLenum clientWaitSync(GrGLsync sync, GrGLbitfield flags, GrGLuint64 timeout) { return GR_GL_WAIT_FAILED; } + virtual GrGLvoid deleteSync(GrGLsync sync) {} virtual GrGLvoid debugMessageControl(GrGLenum source, GrGLenum type, GrGLenum severity, GrGLsizei count, const GrGLuint* ids, GrGLboolean enabled) {} virtual GrGLvoid debugMessageInsert(GrGLenum source, GrGLenum type, GrGLuint id, GrGLenum severity, GrGLsizei length, const GrGLchar* buf) {} virtual GrGLvoid debugMessageCallback(GRGLDEBUGPROC callback, const GrGLvoid* userParam) {} diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp index e72e723..d982756 100644 --- a/src/gpu/vk/GrVkCaps.cpp +++ b/src/gpu/vk/GrVkCaps.cpp @@ -36,6 +36,7 @@ GrVkCaps::GrVkCaps(const GrContextOptions& contextOptions, const GrVkInterface* fOversizedStencilSupport = false; //TODO: figure this out fUseDrawInsteadOfClear = false; + fFenceSyncSupport = true; // always available in Vulkan fMapBufferFlags = kNone_MapFlags; //TODO: figure this out fBufferMapThreshold = SK_MaxS32; //TODO: figure this out diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp index c143219..60a8763 100644 --- a/src/gpu/vk/GrVkGpu.cpp +++ b/src/gpu/vk/GrVkGpu.cpp @@ -1888,3 +1888,31 @@ void GrVkGpu::submitSecondaryCommandBuffer(GrVkSecondaryCommandBuffer* buffer, this->didWriteToSurface(target, &bounds); } +GrFence SK_WARN_UNUSED_RESULT GrVkGpu::insertFence() const { + VkFenceCreateInfo createInfo; + memset(&createInfo, 0, sizeof(VkFenceCreateInfo)); + createInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + createInfo.pNext = nullptr; + createInfo.flags = 0; + VkFence fence = VK_NULL_HANDLE; + VkResult result = GR_VK_CALL(this->vkInterface(), CreateFence(this->device(), &createInfo, + nullptr, &fence)); + // TODO: verify that all QueueSubmits before this will finish before this fence signals + if (VK_SUCCESS == result) { + GR_VK_CALL(this->vkInterface(), QueueSubmit(this->queue(), 0, nullptr, fence)); + } + return (GrFence)fence; +} + +bool GrVkGpu::waitFence(GrFence fence, uint64_t timeout) const { + VkResult result = GR_VK_CALL(this->vkInterface(), WaitForFences(this->device(), 1, + (VkFence*)&fence, + VK_TRUE, + timeout)); + return (VK_SUCCESS == result); +} + +void GrVkGpu::deleteFence(GrFence fence) const { + GR_VK_CALL(this->vkInterface(), DestroyFence(this->device(), (VkFence)fence, nullptr)); +} + diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h index eeaacf3..273f28c 100644 --- a/src/gpu/vk/GrVkGpu.h +++ b/src/gpu/vk/GrVkGpu.h @@ -141,6 +141,10 @@ public: void finishDrawTarget() override; + GrFence SK_WARN_UNUSED_RESULT insertFence() const override; + bool waitFence(GrFence, uint64_t timeout) const override; + void deleteFence(GrFence) const override; + void generateMipmap(GrVkTexture* tex); bool updateBuffer(GrVkBuffer* buffer, const void* src, VkDeviceSize offset, VkDeviceSize size); diff --git a/tools/gpu/GrTest.cpp b/tools/gpu/GrTest.cpp index b99cf06..2e17902 100644 --- a/tools/gpu/GrTest.cpp +++ b/tools/gpu/GrTest.cpp @@ -318,6 +318,10 @@ public: void drawDebugWireRect(GrRenderTarget*, const SkIRect&, GrColor) override {} + GrFence SK_WARN_UNUSED_RESULT insertFence() const override { return 0; } + bool waitFence(GrFence, uint64_t) const override { return true; } + void deleteFence(GrFence) const override {} + private: void onResetContext(uint32_t resetBits) override {} -- 2.7.4