Move GPU fences into sk_gpu_test

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2383383002

Review-Url: https://codereview.chromium.org/2383383002
This commit is contained in:
csmartdalton 2016-10-04 11:08:45 -07:00 committed by Commit bot
parent d36baa7a4a
commit 421a3c1cc1
9 changed files with 145 additions and 134 deletions

View File

@ -442,7 +442,6 @@
'<(skia_include_path)/private/SkFixed.h',
'<(skia_include_path)/private/SkFloatBits.h',
'<(skia_include_path)/private/SkFloatingPoint.h',
'<(skia_include_path)/private/SkGpuFenceSync.h',
'<(skia_include_path)/private/SkMiniRecorder.h',
'<(skia_include_path)/private/SkMutex.h',
'<(skia_include_path)/private/SkOnce.h',

View File

@ -1,30 +0,0 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkGpuFenceSync_DEFINED
#define SkGpuFenceSync_DEFINED
#include "SkTypes.h"
typedef void* SkPlatformGpuFence;
constexpr static SkPlatformGpuFence kInvalidPlatformGpuFence = nullptr;
/*
* This class provides an interface to interact with fence syncs. A fence sync is an object that the
* client can insert into the GPU command stream, and then at any future time, wait until all
* commands that were issued before the fence have completed.
*/
class SkGpuFenceSync {
public:
virtual SkPlatformGpuFence SK_WARN_UNUSED_RESULT insertFence() const = 0;
virtual bool waitFence(SkPlatformGpuFence) const = 0;
virtual void deleteFence(SkPlatformGpuFence) const = 0;
virtual ~SkGpuFenceSync() {}
};
#endif

34
tools/gpu/FenceSync.h Normal file
View File

@ -0,0 +1,34 @@
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef FenceSync_DEFINED
#define FenceSync_DEFINED
#include "SkTypes.h"
namespace sk_gpu_test {
using PlatformFence = intptr_t;
static constexpr PlatformFence kInvalidPlatformFence = 0;
/*
* This class provides an interface to interact with fence syncs. A fence sync is an object that the
* client can insert into the GPU command stream, and then at any future time, wait until all
* commands that were issued before the fence have completed.
*/
class FenceSync {
public:
virtual PlatformFence SK_WARN_UNUSED_RESULT insertFence() const = 0;
virtual bool waitFence(PlatformFence) const = 0;
virtual void deleteFence(PlatformFence) const = 0;
virtual ~FenceSync() {}
};
}
#endif

View File

@ -9,8 +9,8 @@
#ifndef TestContext_DEFINED
#define TestContext_DEFINED
#include "FenceSync.h"
#include "GrTypes.h"
#include "../private/SkGpuFenceSync.h"
#include "../private/SkTemplates.h"
namespace sk_gpu_test {
@ -25,6 +25,7 @@ public:
virtual bool isValid() const = 0;
bool fenceSyncSupport() const { return fFenceSync != nullptr; }
FenceSync* fenceSync() { SkASSERT(fFenceSync); return fFenceSync; }
bool getMaxGpuFrameLag(int *maxFrameLag) const {
if (!fFenceSync) {
@ -73,13 +74,8 @@ public:
/** Wait until all GPU work is finished. */
virtual void finish() = 0;
/**
* returns the fencesync object owned by this GLTestContext
*/
SkGpuFenceSync *fenceSync() { return fFenceSync; }
protected:
SkGpuFenceSync* fFenceSync;
FenceSync* fFenceSync;
TestContext();
@ -94,7 +90,7 @@ private:
kMaxFrameLag = 3
};
SkPlatformGpuFence fFrameFences[kMaxFrameLag - 1];
PlatformFence fFrameFences[kMaxFrameLag - 1];
int fCurrentFenceIdx;
typedef SkNoncopyable INHERITED;

View File

@ -8,21 +8,24 @@
#include "GLTestContext.h"
#include "gl/GrGLUtil.h"
namespace sk_gpu_test {
class GLTestContext::GLFenceSync : public SkGpuFenceSync {
public:
static GLFenceSync* CreateIfSupported(const GLTestContext*);
namespace {
SkPlatformGpuFence SK_WARN_UNUSED_RESULT insertFence() const override;
bool waitFence(SkPlatformGpuFence fence) const override;
void deleteFence(SkPlatformGpuFence fence) const override;
class GLFenceSync : public sk_gpu_test::FenceSync {
public:
static GLFenceSync* CreateIfSupported(const sk_gpu_test::GLTestContext*);
sk_gpu_test::PlatformFence SK_WARN_UNUSED_RESULT insertFence() const override;
bool waitFence(sk_gpu_test::PlatformFence fence) const override;
void deleteFence(sk_gpu_test::PlatformFence fence) const override;
private:
GLFenceSync() {}
GLFenceSync(const sk_gpu_test::GLTestContext*, const char* ext = "");
static const GrGLenum GL_SYNC_GPU_COMMANDS_COMPLETE = 0x9117;
static const GrGLenum GL_WAIT_FAILED = 0x911d;
static const GrGLbitfield GL_SYNC_FLUSH_COMMANDS_BIT = 0x00000001;
bool validate() { return fGLFenceSync && fGLClientWaitSync && fGLDeleteSync; }
static constexpr GrGLenum GL_SYNC_GPU_COMMANDS_COMPLETE = 0x9117;
static constexpr GrGLenum GL_WAIT_FAILED = 0x911d;
static constexpr GrGLbitfield GL_SYNC_FLUSH_COMMANDS_BIT = 0x00000001;
typedef struct __GLsync *GLsync;
@ -34,16 +37,57 @@ private:
GLClientWaitSyncProc fGLClientWaitSync;
GLDeleteSyncProc fGLDeleteSync;
typedef SkGpuFenceSync INHERITED;
typedef FenceSync INHERITED;
};
GLFenceSync* GLFenceSync::CreateIfSupported(const sk_gpu_test::GLTestContext* ctx) {
SkAutoTDelete<GLFenceSync> ret;
if (kGL_GrGLStandard == ctx->gl()->fStandard) {
if (GrGLGetVersion(ctx->gl()) < GR_GL_VER(3,2) && !ctx->gl()->hasExtension("GL_ARB_sync")) {
return nullptr;
}
ret.reset(new GLFenceSync(ctx));
} else {
if (!ctx->gl()->hasExtension("GL_APPLE_sync")) {
return nullptr;
}
ret.reset(new GLFenceSync(ctx, "APPLE"));
}
return ret->validate() ? ret.release() : nullptr;
}
GLFenceSync::GLFenceSync(const sk_gpu_test::GLTestContext* ctx, const char* ext) {
ctx->getGLProcAddress(&fGLFenceSync, "glFenceSync");
ctx->getGLProcAddress(&fGLClientWaitSync, "glClientWaitSync");
ctx->getGLProcAddress(&fGLDeleteSync, "glDeleteSync");
}
sk_gpu_test::PlatformFence GLFenceSync::insertFence() const {
__GLsync* glsync = fGLFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
return reinterpret_cast<sk_gpu_test::PlatformFence>(glsync);
}
bool GLFenceSync::waitFence(sk_gpu_test::PlatformFence fence) const {
GLsync glsync = reinterpret_cast<GLsync>(fence);
return GL_WAIT_FAILED != fGLClientWaitSync(glsync, GL_SYNC_FLUSH_COMMANDS_BIT, -1);
}
void GLFenceSync::deleteFence(sk_gpu_test::PlatformFence fence) const {
GLsync glsync = reinterpret_cast<GLsync>(fence);
fGLDeleteSync(glsync);
}
} // anonymous namespace
namespace sk_gpu_test {
GLTestContext::GLTestContext() : TestContext() {}
GLTestContext::~GLTestContext() {
SkASSERT(nullptr == fGL.get());
}
void GLTestContext::init(const GrGLInterface* gl, SkGpuFenceSync* fenceSync) {
void GLTestContext::init(const GrGLInterface* gl, FenceSync* fenceSync) {
SkASSERT(!fGL.get());
fGL.reset(gl);
fFenceSync = fenceSync ? fenceSync : GLFenceSync::CreateIfSupported(this);
@ -73,55 +117,6 @@ void GLTestContext::finish() {
}
}
GLTestContext::GLFenceSync* GLTestContext::GLFenceSync::CreateIfSupported(const GLTestContext* ctx) {
SkAutoTDelete<GLFenceSync> ret(new GLFenceSync);
if (kGL_GrGLStandard == ctx->gl()->fStandard) {
const GrGLubyte* versionStr;
GR_GL_CALL_RET(ctx->gl(), versionStr, GetString(GR_GL_VERSION));
GrGLVersion version = GrGLGetVersionFromString(reinterpret_cast<const char*>(versionStr));
if (version < GR_GL_VER(3,2) && !ctx->gl()->hasExtension("GL_ARB_sync")) {
return nullptr;
}
ret->fGLFenceSync = reinterpret_cast<GLFenceSyncProc>(
ctx->onPlatformGetProcAddress("glFenceSync"));
ret->fGLClientWaitSync = reinterpret_cast<GLClientWaitSyncProc>(
ctx->onPlatformGetProcAddress("glClientWaitSync"));
ret->fGLDeleteSync = reinterpret_cast<GLDeleteSyncProc>(
ctx->onPlatformGetProcAddress("glDeleteSync"));
} else {
if (!ctx->gl()->hasExtension("GL_APPLE_sync")) {
return nullptr;
}
ret->fGLFenceSync = reinterpret_cast<GLFenceSyncProc>(
ctx->onPlatformGetProcAddress("glFenceSyncAPPLE"));
ret->fGLClientWaitSync = reinterpret_cast<GLClientWaitSyncProc>(
ctx->onPlatformGetProcAddress("glClientWaitSyncAPPLE"));
ret->fGLDeleteSync = reinterpret_cast<GLDeleteSyncProc>(
ctx->onPlatformGetProcAddress("glDeleteSyncAPPLE"));
}
if (!ret->fGLFenceSync || !ret->fGLClientWaitSync || !ret->fGLDeleteSync) {
return nullptr;
}
return ret.release();
}
SkPlatformGpuFence GLTestContext::GLFenceSync::insertFence() const {
return fGLFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
}
bool GLTestContext::GLFenceSync::waitFence(SkPlatformGpuFence fence) const {
GLsync glsync = static_cast<GLsync>(fence);
return GL_WAIT_FAILED != fGLClientWaitSync(glsync, GL_SYNC_FLUSH_COMMANDS_BIT, -1);
}
void GLTestContext::GLFenceSync::deleteFence(SkPlatformGpuFence fence) const {
GLsync glsync = static_cast<GLsync>(fence);
fGLDeleteSync(glsync);
}
GrGLint GLTestContext::createTextureRectangle(int width, int height, GrGLenum internalFormat,
GrGLenum externalFormat, GrGLenum externalType,
GrGLvoid* data) {

View File

@ -59,27 +59,39 @@ public:
*/
virtual GLTestContext *createNew() const { return nullptr; }
template<typename Ret, typename... Args>
void getGLProcAddress(Ret(GR_GL_FUNCTION_TYPE** out)(Args...),
const char* name, const char* ext = nullptr) const {
using Proc = Ret(GR_GL_FUNCTION_TYPE*)(Args...);
if (!SkStrStartsWith(name, "gl")) {
SkFAIL("getGLProcAddress: proc name must have 'gl' prefix");
*out = nullptr;
} else if (ext) {
SkString fullname(name);
fullname.append(ext);
*out = reinterpret_cast<Proc>(this->onPlatformGetProcAddress(fullname.c_str()));
} else {
*out = reinterpret_cast<Proc>(this->onPlatformGetProcAddress(name));
}
}
protected:
GLTestContext();
/*
* Methods that sublcasses must call from their constructors and destructors.
*/
void init(const GrGLInterface *, SkGpuFenceSync * = NULL);
void init(const GrGLInterface *, FenceSync* = nullptr);
void teardown() override;
virtual GrGLFuncPtr onPlatformGetProcAddress(const char *) const = 0;
private:
class GLFenceSync; // SkGpuFenceSync implementation that uses the OpenGL functionality.
/** Subclass provides the gl interface object if construction was
* successful. */
SkAutoTUnref<const GrGLInterface> fGL;
friend class GLFenceSync; // For onPlatformGetProcAddress.
typedef TestContext INHERITED;
};

View File

@ -20,20 +20,20 @@
namespace {
// TODO: Share this class with ANGLE if/when it gets support for EGL_KHR_fence_sync.
class EGLFenceSync : public SkGpuFenceSync {
class EGLFenceSync : public sk_gpu_test::FenceSync {
public:
static EGLFenceSync* CreateIfSupported(EGLDisplay);
SkPlatformGpuFence SK_WARN_UNUSED_RESULT insertFence() const override;
bool waitFence(SkPlatformGpuFence fence) const override;
void deleteFence(SkPlatformGpuFence fence) const override;
sk_gpu_test::PlatformFence SK_WARN_UNUSED_RESULT insertFence() const override;
bool waitFence(sk_gpu_test::PlatformFence fence) const override;
void deleteFence(sk_gpu_test::PlatformFence fence) const override;
private:
EGLFenceSync(EGLDisplay display) : fDisplay(display) {}
EGLDisplay fDisplay;
typedef SkGpuFenceSync INHERITED;
typedef sk_gpu_test::FenceSync INHERITED;
};
class EGLGLTestContext : public sk_gpu_test::GLTestContext {
@ -301,12 +301,13 @@ EGLFenceSync* EGLFenceSync::CreateIfSupported(EGLDisplay display) {
return new EGLFenceSync(display);
}
SkPlatformGpuFence EGLFenceSync::insertFence() const {
return eglCreateSyncKHR(fDisplay, EGL_SYNC_FENCE_KHR, nullptr);
sk_gpu_test::PlatformFence EGLFenceSync::insertFence() const {
EGLSyncKHR eglsync = eglCreateSyncKHR(fDisplay, EGL_SYNC_FENCE_KHR, nullptr);
return reinterpret_cast<sk_gpu_test::PlatformFence>(eglsync);
}
bool EGLFenceSync::waitFence(SkPlatformGpuFence platformFence) const {
EGLSyncKHR eglsync = static_cast<EGLSyncKHR>(platformFence);
bool EGLFenceSync::waitFence(sk_gpu_test::PlatformFence platformFence) const {
EGLSyncKHR eglsync = reinterpret_cast<EGLSyncKHR>(platformFence);
return EGL_CONDITION_SATISFIED_KHR ==
eglClientWaitSyncKHR(fDisplay,
eglsync,
@ -314,8 +315,8 @@ bool EGLFenceSync::waitFence(SkPlatformGpuFence platformFence) const {
EGL_FOREVER_KHR);
}
void EGLFenceSync::deleteFence(SkPlatformGpuFence platformFence) const {
EGLSyncKHR eglsync = static_cast<EGLSyncKHR>(platformFence);
void EGLFenceSync::deleteFence(sk_gpu_test::PlatformFence platformFence) const {
EGLSyncKHR eglsync = reinterpret_cast<EGLSyncKHR>(platformFence);
eglDestroySyncKHR(fDisplay, eglsync);
}

View File

@ -15,11 +15,11 @@
namespace {
/**
* Implements SkGpuFenceSync for Vulkan. It creates a single command buffer with
* USAGE_SIMULTANEOUS with no content . On every insertFence request it submits
* the command buffer with a new fence.
* Implements sk_gpu_test::FenceSync for Vulkan. It creates a single command
* buffer with USAGE_SIMULTANEOUS with no content . On every insertFence request
* it submits the command buffer with a new fence.
*/
class VkFenceSync : public SkGpuFenceSync {
class VkFenceSync : public sk_gpu_test::FenceSync {
public:
VkFenceSync(sk_sp<const GrVkInterface> vk, VkDevice device, VkQueue queue,
uint32_t queueFamilyIndex)
@ -58,7 +58,7 @@ public:
GR_VK_CALL(fVk, DestroyCommandPool(fDevice, fCommandPool, nullptr));
}
SkPlatformGpuFence SK_WARN_UNUSED_RESULT insertFence() const override {
sk_gpu_test::PlatformFence SK_WARN_UNUSED_RESULT insertFence() const override {
VkFence fence;
VkFenceCreateInfo info;
info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
@ -77,17 +77,17 @@ public:
submitInfo.pSignalSemaphores = nullptr;
GR_VK_CALL_ERRCHECK(fVk, QueueSubmit(fQueue, 1, &submitInfo, fence));
SkDEBUGCODE(++fUnfinishedSyncs;)
return reinterpret_cast<SkPlatformGpuFence>(fence);
return reinterpret_cast<sk_gpu_test::PlatformFence>(fence);
}
bool waitFence(SkPlatformGpuFence opaqueFence) const override {
bool waitFence(sk_gpu_test::PlatformFence opaqueFence) const override {
VkFence fence = reinterpret_cast<VkFence>(opaqueFence);
static constexpr uint64_t kForever = ~((uint64_t)0);
auto result = GR_VK_CALL(fVk, WaitForFences(fDevice, 1, &fence, true, kForever));
return result != VK_TIMEOUT;
}
void deleteFence(SkPlatformGpuFence opaqueFence) const override {
void deleteFence(sk_gpu_test::PlatformFence opaqueFence) const override {
VkFence fence = reinterpret_cast<VkFence>(opaqueFence);
GR_VK_CALL(fVk, DestroyFence(fDevice, fence, nullptr));
SkDEBUGCODE(--fUnfinishedSyncs;)
@ -100,7 +100,7 @@ private:
VkCommandPool fCommandPool;
VkCommandBuffer fCommandBuffer;
SkDEBUGCODE(mutable int fUnfinishedSyncs;)
typedef SkGpuFenceSync INHERITED;
typedef sk_gpu_test::FenceSync INHERITED;
};
// TODO: Implement swap buffers and finish
@ -141,7 +141,7 @@ private:
typedef sk_gpu_test::VkTestContext INHERITED;
};
}
} // anonymous namespace
namespace sk_gpu_test {
VkTestContext* CreatePlatformVkTestContext() { return VkTestContextImpl::Create(); }

View File

@ -33,6 +33,10 @@
* Currently, only GPU configs are supported.
*/
using sk_gpu_test::PlatformFence;
using sk_gpu_test::kInvalidPlatformFence;
using sk_gpu_test::FenceSync;
DEFINE_int32(duration, 5000, "number of milliseconds to run the benchmark");
DEFINE_int32(sampleMs, 50, "minimum duration of a sample");
DEFINE_bool(fps, false, "use fps instead of ms");
@ -62,7 +66,7 @@ struct Sample {
class GpuSync {
public:
GpuSync(const SkGpuFenceSync* fenceSync);
GpuSync(const FenceSync* fenceSync);
~GpuSync();
void syncToPreviousFrame();
@ -70,8 +74,8 @@ public:
private:
void updateFence();
const SkGpuFenceSync* const fFenceSync;
SkPlatformGpuFence fFence;
const FenceSync* const fFenceSync;
PlatformFence fFence;
};
enum class ExitErr {
@ -88,7 +92,7 @@ static bool mkdir_p(const SkString& name);
static SkString join(const SkCommandLineFlags::StringArray&);
static void exitf(ExitErr, const char* format, ...);
static void run_benchmark(const SkGpuFenceSync* fenceSync, SkCanvas* canvas, const SkPicture* skp,
static void run_benchmark(const FenceSync* fenceSync, SkCanvas* canvas, const SkPicture* skp,
std::vector<Sample>* samples) {
using clock = Sample::clock;
const clock::duration sampleDuration = std::chrono::milliseconds(FLAGS_sampleMs);
@ -296,7 +300,7 @@ static void exitf(ExitErr err, const char* format, ...) {
exit((int)err);
}
GpuSync::GpuSync(const SkGpuFenceSync* fenceSync)
GpuSync::GpuSync(const FenceSync* fenceSync)
: fFenceSync(fenceSync) {
this->updateFence();
}
@ -306,7 +310,7 @@ GpuSync::~GpuSync() {
}
void GpuSync::syncToPreviousFrame() {
if (kInvalidPlatformGpuFence == fFence) {
if (kInvalidPlatformFence == fFence) {
exitf(ExitErr::kSoftware, "attempted to sync with invalid fence");
}
if (!fFenceSync->waitFence(fFence)) {
@ -318,7 +322,7 @@ void GpuSync::syncToPreviousFrame() {
void GpuSync::updateFence() {
fFence = fFenceSync->insertFence();
if (kInvalidPlatformGpuFence == fFence) {
if (kInvalidPlatformFence == fFence) {
exitf(ExitErr::kUnavailable, "failed to insert fence");
}
}