Update nanobench and skpbench to use flush API for gpu syncing.
This also allows us to remove all the one off Fence code that we implemented in all the backend TestContexts Change-Id: I9ff7ba4690cf3f19a180f51fc510991a112bb62c Reviewed-on: https://skia-review.googlesource.com/c/skia/+/272456 Reviewed-by: Chris Dalton <csmartdalton@google.com> Commit-Queue: Greg Daniel <egdaniel@google.com>
This commit is contained in:
parent
9279798022
commit
02497d4016
@ -218,7 +218,7 @@ struct GPUTarget : public Target {
|
||||
}
|
||||
void endTiming() override {
|
||||
if (this->contextInfo.testContext()) {
|
||||
this->contextInfo.testContext()->waitOnSyncOrSwap();
|
||||
this->contextInfo.testContext()->flushAndWaitOnSync(contextInfo.grContext());
|
||||
}
|
||||
}
|
||||
void fence() override { this->contextInfo.testContext()->finish(); }
|
||||
@ -286,9 +286,6 @@ static double time(int loops, Benchmark* bench, Target* target) {
|
||||
double start = now_ms();
|
||||
canvas = target->beginTiming(canvas);
|
||||
bench->draw(loops, canvas);
|
||||
if (canvas) {
|
||||
canvas->flush();
|
||||
}
|
||||
target->endTiming();
|
||||
double elapsed = now_ms() - start;
|
||||
bench->postDraw(canvas);
|
||||
|
@ -2104,7 +2104,7 @@ Result ViaDDL::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkStrin
|
||||
// Fourth, synchronously render the display lists into the dest tiles
|
||||
// TODO: it would be cool to not wait until all the tiles are drawn to begin
|
||||
// drawing to the GPU and composing to the final surface
|
||||
tiles.drawAllTilesAndFlush(context, false);
|
||||
tiles.drawAllTiles(context);
|
||||
|
||||
// Finally, compose the drawn tiles into the result
|
||||
// Note: the separation between the tiles and the final composition better
|
||||
|
@ -33,7 +33,7 @@
|
||||
#define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
|
||||
#define EGL_PROTECTED_CONTENT_EXT 0x32C0
|
||||
|
||||
#define VK_CALL(X) gpu->vkInterface()->fFunctions.f##X;
|
||||
#define VK_CALL(X) gpu->vkInterface()->fFunctions.f##X
|
||||
|
||||
namespace GrAHardwareBufferUtils {
|
||||
|
||||
|
@ -358,29 +358,32 @@ bool EGLTestHelper::importAndWaitOnSemaphore(skiatest::Reporter* reporter, int f
|
||||
}
|
||||
|
||||
void EGLTestHelper::doClientSync() {
|
||||
sk_gpu_test::FenceSync* fenceSync = fGLCtx->fenceSync();
|
||||
sk_gpu_test::PlatformFence fence = fenceSync->insertFence();
|
||||
fenceSync->waitFence(fence);
|
||||
fenceSync->deleteFence(fence);
|
||||
GrFlushInfo flushInfo;
|
||||
flushInfo.fFlags = kSyncCpu_GrFlushFlag;
|
||||
this->grContext()->flush(flushInfo);
|
||||
}
|
||||
#endif // SK_GL
|
||||
|
||||
#define DECLARE_VK_PROC(name) PFN_vk##name fVk##name
|
||||
|
||||
#define ACQUIRE_INST_VK_PROC(name) \
|
||||
do { \
|
||||
fVk##name = reinterpret_cast<PFN_vk##name>(getProc("vk" #name, fBackendContext.fInstance,\
|
||||
VK_NULL_HANDLE)); \
|
||||
if (fVk##name == nullptr) { \
|
||||
ERRORF(reporter, "Function ptr for vk%s could not be acquired\n", #name); \
|
||||
return false; \
|
||||
}
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
#define ACQUIRE_DEVICE_VK_PROC(name) \
|
||||
do { \
|
||||
fVk##name = reinterpret_cast<PFN_vk##name>(getProc("vk" #name, VK_NULL_HANDLE, fDevice)); \
|
||||
if (fVk##name == nullptr) { \
|
||||
ERRORF(reporter, "Function ptr for vk%s could not be acquired\n", #name); \
|
||||
return false; \
|
||||
}
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
class VulkanTestHelper : public BaseTestHelper {
|
||||
public:
|
||||
|
@ -202,13 +202,10 @@ void DDLTileHelper::kickOffThreadedWork(SkTaskGroup* recordingTaskGroup,
|
||||
}
|
||||
}
|
||||
|
||||
void DDLTileHelper::drawAllTilesAndFlush(GrContext* context, bool flush) {
|
||||
void DDLTileHelper::drawAllTiles(GrContext* context) {
|
||||
for (int i = 0; i < this->numTiles(); ++i) {
|
||||
fTiles[i].draw(context);
|
||||
}
|
||||
if (flush) {
|
||||
context->flush();
|
||||
}
|
||||
}
|
||||
|
||||
void DDLTileHelper::composeAllTiles() {
|
||||
|
@ -80,7 +80,7 @@ public:
|
||||
|
||||
void createDDLsInParallel();
|
||||
|
||||
void drawAllTilesAndFlush(GrContext*, bool flush);
|
||||
void drawAllTiles(GrContext*);
|
||||
|
||||
void composeAllTiles();
|
||||
|
||||
|
56
tools/gpu/FlushFinishTracker.h
Normal file
56
tools/gpu/FlushFinishTracker.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef FlushFinishTracker_DEFINED
|
||||
#define FlushFinishTracker_DEFINED
|
||||
|
||||
#include "include/core/SkRefCnt.h"
|
||||
#include "include/gpu/GrContext.h"
|
||||
#include "src/core/SkTraceEvent.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace sk_gpu_test {
|
||||
|
||||
class FlushFinishTracker : public SkRefCnt {
|
||||
public:
|
||||
static void FlushFinished(void* finishedContext) {
|
||||
auto tracker = static_cast<FlushFinishTracker*>(finishedContext);
|
||||
tracker->setFinished();
|
||||
tracker->unref();
|
||||
}
|
||||
|
||||
FlushFinishTracker(GrContext* context) : fContext(context) {}
|
||||
|
||||
void setFinished() { fIsFinished = true; }
|
||||
|
||||
void waitTillFinished() {
|
||||
TRACE_EVENT0("skia.gpu", TRACE_FUNC);
|
||||
auto begin = std::chrono::steady_clock::now();
|
||||
auto end = begin;
|
||||
while (!fIsFinished && (end - begin) < std::chrono::seconds(2)) {
|
||||
fContext->checkAsyncWorkCompletion();
|
||||
end = std::chrono::steady_clock::now();
|
||||
}
|
||||
if (!fIsFinished) {
|
||||
SkDebugf("WARNING: Wait failed for flush sync. Timings might not be accurate.\n");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
GrContext* fContext;
|
||||
|
||||
// Currently we don't have the this bool be atomic cause all current uses of this class happen
|
||||
// on a single thread. In other words we call flush, checkAsyncWorkCompletion, and
|
||||
// waitTillFinished all on the same thread. If we ever want to support the flushing and waiting
|
||||
// to happen on different threads then we should make this atomic.
|
||||
bool fIsFinished = false;
|
||||
};
|
||||
|
||||
} //namespace sk_gpu_test
|
||||
|
||||
#endif
|
@ -8,26 +8,17 @@
|
||||
|
||||
#include "tools/gpu/TestContext.h"
|
||||
|
||||
#include "include/gpu/GrContext.h"
|
||||
#include "src/core/SkTraceEvent.h"
|
||||
#include "src/gpu/GrContextPriv.h"
|
||||
#include "tools/gpu/FlushFinishTracker.h"
|
||||
#include "tools/gpu/GpuTimer.h"
|
||||
|
||||
#include "include/gpu/GrContext.h"
|
||||
|
||||
namespace sk_gpu_test {
|
||||
TestContext::TestContext()
|
||||
: fFenceSync(nullptr)
|
||||
, fGpuTimer(nullptr)
|
||||
, fCurrentFenceIdx(0) {
|
||||
memset(fFrameFences, 0, sizeof(fFrameFences));
|
||||
}
|
||||
TestContext::TestContext() : fGpuTimer(nullptr) {}
|
||||
|
||||
TestContext::~TestContext() {
|
||||
// Subclass should call teardown.
|
||||
#ifdef SK_DEBUG
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(fFrameFences); i++) {
|
||||
SkASSERT(0 == fFrameFences[i]);
|
||||
}
|
||||
#endif
|
||||
SkASSERT(!fFenceSync);
|
||||
SkASSERT(!fGpuTimer);
|
||||
}
|
||||
|
||||
@ -44,44 +35,33 @@ SkScopeExit TestContext::makeCurrentAndAutoRestore() const {
|
||||
return asr;
|
||||
}
|
||||
|
||||
void TestContext::swapBuffers() { this->onPlatformSwapBuffers(); }
|
||||
void TestContext::flushAndWaitOnSync(GrContext* context) {
|
||||
TRACE_EVENT0("skia.gpu", TRACE_FUNC);
|
||||
SkASSERT(context);
|
||||
|
||||
|
||||
void TestContext::waitOnSyncOrSwap() {
|
||||
if (!fFenceSync) {
|
||||
// Fallback on the platform SwapBuffers method for synchronization. This may have no effect.
|
||||
this->swapBuffers();
|
||||
return;
|
||||
if (fFinishTrackers[fCurrentFlushIdx]) {
|
||||
fFinishTrackers[fCurrentFlushIdx]->waitTillFinished();
|
||||
}
|
||||
|
||||
this->submit();
|
||||
if (fFrameFences[fCurrentFenceIdx]) {
|
||||
if (!fFenceSync->waitFence(fFrameFences[fCurrentFenceIdx])) {
|
||||
SkDebugf("WARNING: Wait failed for fence sync. Timings might not be accurate.\n");
|
||||
}
|
||||
fFenceSync->deleteFence(fFrameFences[fCurrentFenceIdx]);
|
||||
}
|
||||
fFinishTrackers[fCurrentFlushIdx].reset(new FlushFinishTracker(context));
|
||||
|
||||
fFrameFences[fCurrentFenceIdx] = fFenceSync->insertFence();
|
||||
fCurrentFenceIdx = (fCurrentFenceIdx + 1) % SK_ARRAY_COUNT(fFrameFences);
|
||||
// We add an additional ref to the current flush tracker here. This ref is owned by the finish
|
||||
// callback on the flush call. The finish callback will unref the tracker when called.
|
||||
fFinishTrackers[fCurrentFlushIdx]->ref();
|
||||
|
||||
GrFlushInfo flushInfo;
|
||||
flushInfo.fFinishedProc = FlushFinishTracker::FlushFinished;
|
||||
flushInfo.fFinishedContext = fFinishTrackers[fCurrentFlushIdx].get();
|
||||
|
||||
context->flush(flushInfo);
|
||||
|
||||
fCurrentFlushIdx = (fCurrentFlushIdx + 1) % SK_ARRAY_COUNT(fFinishTrackers);
|
||||
}
|
||||
|
||||
void TestContext::testAbandon() {
|
||||
if (fFenceSync) {
|
||||
memset(fFrameFences, 0, sizeof(fFrameFences));
|
||||
}
|
||||
}
|
||||
|
||||
void TestContext::teardown() {
|
||||
if (fFenceSync) {
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(fFrameFences); i++) {
|
||||
if (fFrameFences[i]) {
|
||||
fFenceSync->deleteFence(fFrameFences[i]);
|
||||
fFrameFences[i] = 0;
|
||||
}
|
||||
}
|
||||
fFenceSync.reset();
|
||||
}
|
||||
fGpuTimer.reset();
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ struct GrContextOptions;
|
||||
namespace sk_gpu_test {
|
||||
|
||||
class GpuTimer;
|
||||
class FlushFinishTracker;
|
||||
|
||||
/**
|
||||
* An offscreen 3D context. This class is intended for Skia's internal testing needs and not
|
||||
@ -31,14 +32,13 @@ class TestContext : public SkNoncopyable {
|
||||
public:
|
||||
virtual ~TestContext();
|
||||
|
||||
bool fenceSyncSupport() const { return fFenceSync != nullptr; }
|
||||
FenceSync* fenceSync() { SkASSERT(fFenceSync); return fFenceSync.get(); }
|
||||
bool fenceSyncSupport() const { return fFenceSupport; }
|
||||
|
||||
bool gpuTimingSupport() const { return fGpuTimer != nullptr; }
|
||||
GpuTimer* gpuTimer() const { SkASSERT(fGpuTimer); return fGpuTimer.get(); }
|
||||
|
||||
bool getMaxGpuFrameLag(int *maxFrameLag) const {
|
||||
if (!fFenceSync) {
|
||||
if (!this->fenceSyncSupport()) {
|
||||
return false;
|
||||
}
|
||||
*maxFrameLag = kMaxFrameLag;
|
||||
@ -64,25 +64,13 @@ public:
|
||||
|
||||
virtual sk_sp<GrContext> makeGrContext(const GrContextOptions&);
|
||||
|
||||
/** Swaps front and back buffer (if the context has such buffers) */
|
||||
void swapBuffers();
|
||||
|
||||
/**
|
||||
* The only purpose of this function it to provide a means of scheduling
|
||||
* work on the GPU (since all of the subclasses create primary buffers for
|
||||
* testing that are small and not meant to be rendered to the screen).
|
||||
*
|
||||
* If the platform supports fence syncs (OpenGL 3.2+ or EGL_KHR_fence_sync),
|
||||
* this will not swap any buffers, but rather emulate triple buffer synchronization
|
||||
* using fences.
|
||||
*
|
||||
* Otherwise it will call the platform SwapBuffers method. This may or may
|
||||
* not perform some sort of synchronization, depending on whether the
|
||||
* drawing surface provided by the platform is double buffered.
|
||||
*
|
||||
* Implicitly performs a submit().
|
||||
* This will flush work to the GPU. Additionally, if the platform supports fence syncs, we will
|
||||
* add a finished callback to our flush call. We allow ourselves to have kMaxFrameLag number of
|
||||
* unfinished flushes active on the GPU at a time. If we have 2 outstanding flushes then we will
|
||||
* wait on the CPU until one has finished.
|
||||
*/
|
||||
void waitOnSyncOrSwap();
|
||||
void flushAndWaitOnSync(GrContext* context);
|
||||
|
||||
/**
|
||||
* This notifies the context that we are deliberately testing abandoning
|
||||
@ -92,14 +80,12 @@ public:
|
||||
*/
|
||||
virtual void testAbandon();
|
||||
|
||||
/** Ensures all work is submitted to the GPU for execution. */
|
||||
virtual void submit() = 0;
|
||||
|
||||
/** Wait until all GPU work is finished. */
|
||||
virtual void finish() = 0;
|
||||
|
||||
protected:
|
||||
std::unique_ptr<FenceSync> fFenceSync;
|
||||
bool fFenceSupport = false;
|
||||
|
||||
std::unique_ptr<GpuTimer> fGpuTimer;
|
||||
|
||||
TestContext();
|
||||
@ -117,15 +103,14 @@ protected:
|
||||
* should remain current.
|
||||
*/
|
||||
virtual std::function<void()> onPlatformGetAutoContextRestore() const = 0;
|
||||
virtual void onPlatformSwapBuffers() const = 0;
|
||||
|
||||
private:
|
||||
enum {
|
||||
kMaxFrameLag = 3
|
||||
};
|
||||
|
||||
PlatformFence fFrameFences[kMaxFrameLag - 1];
|
||||
int fCurrentFenceIdx;
|
||||
sk_sp<FlushFinishTracker> fFinishTrackers[kMaxFrameLag - 1];
|
||||
int fCurrentFlushIdx = 0;
|
||||
|
||||
typedef SkNoncopyable INHERITED;
|
||||
};
|
||||
|
@ -78,81 +78,6 @@ private:
|
||||
ProcGetter* ProcGetter::fInstance;
|
||||
#endif
|
||||
|
||||
class DawnFence {
|
||||
public:
|
||||
DawnFence(const wgpu::Device& device, const wgpu::Buffer& buffer)
|
||||
: fDevice(device), fBuffer(buffer), fCalled(false) {
|
||||
fBuffer.MapReadAsync(callback, this);
|
||||
}
|
||||
|
||||
bool wait() {
|
||||
while (!fCalled) {
|
||||
fDevice.Tick();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
~DawnFence() {
|
||||
}
|
||||
|
||||
static void callback(WGPUBufferMapAsyncStatus status, const void* data, uint64_t dataLength,
|
||||
void* userData) {
|
||||
DawnFence* fence = static_cast<DawnFence*>(userData);
|
||||
fence->fCalled = true;
|
||||
}
|
||||
wgpu::Buffer buffer() { return fBuffer; }
|
||||
|
||||
private:
|
||||
wgpu::Device fDevice;
|
||||
wgpu::Buffer fBuffer;
|
||||
bool fCalled;
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements sk_gpu_test::FenceSync for Dawn.
|
||||
*/
|
||||
class DawnFenceSync : public sk_gpu_test::FenceSync {
|
||||
public:
|
||||
DawnFenceSync(wgpu::Device device) : fDevice(device) {
|
||||
}
|
||||
|
||||
~DawnFenceSync() override {
|
||||
}
|
||||
|
||||
sk_gpu_test::PlatformFence SK_WARN_UNUSED_RESULT insertFence() const override {
|
||||
wgpu::Buffer buffer;
|
||||
if (fBuffers.empty()) {
|
||||
wgpu::BufferDescriptor desc;
|
||||
desc.usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst;
|
||||
desc.size = 1;
|
||||
buffer = fDevice.CreateBuffer(&desc);
|
||||
} else {
|
||||
buffer = fBuffers.back();
|
||||
fBuffers.pop_back();
|
||||
}
|
||||
DawnFence* fence = new DawnFence(fDevice, buffer);
|
||||
return reinterpret_cast<sk_gpu_test::PlatformFence>(fence);
|
||||
}
|
||||
|
||||
bool waitFence(sk_gpu_test::PlatformFence opaqueFence) const override {
|
||||
fAutoreleasePool.drain();
|
||||
DawnFence* fence = reinterpret_cast<DawnFence*>(opaqueFence);
|
||||
return fence->wait();
|
||||
}
|
||||
|
||||
void deleteFence(sk_gpu_test::PlatformFence opaqueFence) const override {
|
||||
DawnFence* fence = reinterpret_cast<DawnFence*>(opaqueFence);
|
||||
fBuffers.push_back(fence->buffer());
|
||||
delete fence;
|
||||
}
|
||||
|
||||
private:
|
||||
wgpu::Device fDevice;
|
||||
mutable std::vector<wgpu::Buffer> fBuffers;
|
||||
mutable AutoreleasePool fAutoreleasePool;
|
||||
typedef sk_gpu_test::FenceSync INHERITED;
|
||||
};
|
||||
|
||||
class DawnTestContextImpl : public sk_gpu_test::DawnTestContext {
|
||||
public:
|
||||
static wgpu::Device createDevice(const dawn_native::Instance& instance,
|
||||
@ -211,9 +136,6 @@ public:
|
||||
|
||||
void testAbandon() override {}
|
||||
|
||||
// There is really nothing to here since we don't own any unqueued command buffers here.
|
||||
void submit() override {}
|
||||
|
||||
void finish() override {}
|
||||
|
||||
sk_sp<GrContext> makeGrContext(const GrContextOptions& options) override {
|
||||
@ -230,7 +152,7 @@ private:
|
||||
const wgpu::Device& device)
|
||||
: DawnTestContext(device)
|
||||
, fInstance(std::move(instance)) {
|
||||
fFenceSync.reset(new DawnFenceSync(fDevice));
|
||||
fFenceSupport = true;
|
||||
}
|
||||
|
||||
void onPlatformMakeNotCurrent() const override {}
|
||||
|
@ -13,135 +13,6 @@
|
||||
|
||||
namespace {
|
||||
|
||||
class GLFenceSync : public sk_gpu_test::FenceSync {
|
||||
public:
|
||||
static std::unique_ptr<FenceSync> MakeIfSupported(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(const sk_gpu_test::GLTestContext*, const char* ext = "");
|
||||
|
||||
bool validate() const override { 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;
|
||||
static_assert(sizeof(GLsync) <= sizeof(sk_gpu_test::PlatformFence));
|
||||
|
||||
typedef GLsync (GR_GL_FUNCTION_TYPE* GLFenceSyncProc) (GrGLenum, GrGLbitfield);
|
||||
typedef GrGLenum (GR_GL_FUNCTION_TYPE* GLClientWaitSyncProc) (GLsync, GrGLbitfield, GrGLuint64);
|
||||
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GLDeleteSyncProc) (GLsync);
|
||||
|
||||
GLFenceSyncProc fGLFenceSync;
|
||||
GLClientWaitSyncProc fGLClientWaitSync;
|
||||
GLDeleteSyncProc fGLDeleteSync;
|
||||
|
||||
typedef FenceSync INHERITED;
|
||||
};
|
||||
|
||||
class GLNVFenceSync : public sk_gpu_test::FenceSync {
|
||||
public:
|
||||
GLNVFenceSync(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:
|
||||
bool validate() const override {
|
||||
return fGLGenFencesNV && fGLDeleteFencesNV && fGLSetFenceNV && fGLFinishFenceNV;
|
||||
}
|
||||
|
||||
static constexpr GrGLenum GL_ALL_COMPLETED_NV = 0x84F2;
|
||||
|
||||
typedef GrGLvoid(GR_GL_FUNCTION_TYPE* GLGenFencesNVProc) (GrGLsizei, GrGLuint*);
|
||||
typedef GrGLvoid(GR_GL_FUNCTION_TYPE* GLDeleteFencesNVProc) (GrGLsizei, const GrGLuint*);
|
||||
typedef GrGLvoid(GR_GL_FUNCTION_TYPE* GLSetFenceNVProc) (GrGLuint, GrGLenum);
|
||||
typedef GrGLvoid(GR_GL_FUNCTION_TYPE* GLFinishFenceNVProc) (GrGLuint);
|
||||
|
||||
GLGenFencesNVProc fGLGenFencesNV;
|
||||
GLDeleteFencesNVProc fGLDeleteFencesNV;
|
||||
GLSetFenceNVProc fGLSetFenceNV;
|
||||
GLFinishFenceNVProc fGLFinishFenceNV;
|
||||
|
||||
typedef FenceSync INHERITED;
|
||||
};
|
||||
|
||||
std::unique_ptr<sk_gpu_test::FenceSync> GLFenceSync::MakeIfSupported(
|
||||
const sk_gpu_test::GLTestContext* ctx) {
|
||||
std::unique_ptr<FenceSync> 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")) {
|
||||
ret.reset(new GLFenceSync(ctx, "APPLE"));
|
||||
} else if (ctx->gl()->hasExtension("GL_NV_fence")) {
|
||||
ret.reset(new GLNVFenceSync(ctx));
|
||||
} else if (GrGLGetVersion(ctx->gl()) >= GR_GL_VER(3, 0)) {
|
||||
ret.reset(new GLFenceSync(ctx));
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
if (!ret->validate()) {
|
||||
ret = nullptr;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
GLFenceSync::GLFenceSync(const sk_gpu_test::GLTestContext* ctx, const char* ext) {
|
||||
ctx->getGLProcAddress(&fGLFenceSync, "glFenceSync", ext);
|
||||
ctx->getGLProcAddress(&fGLClientWaitSync, "glClientWaitSync", ext);
|
||||
ctx->getGLProcAddress(&fGLDeleteSync, "glDeleteSync", ext);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
GLNVFenceSync::GLNVFenceSync(const sk_gpu_test::GLTestContext* ctx) {
|
||||
ctx->getGLProcAddress(&fGLGenFencesNV, "glGenFencesNV");
|
||||
ctx->getGLProcAddress(&fGLDeleteFencesNV, "glDeleteFencesNV");
|
||||
ctx->getGLProcAddress(&fGLSetFenceNV, "glSetFenceNV");
|
||||
ctx->getGLProcAddress(&fGLFinishFenceNV, "glFinishFenceNV");
|
||||
}
|
||||
|
||||
sk_gpu_test::PlatformFence GLNVFenceSync::insertFence() const {
|
||||
GrGLuint fence;
|
||||
fGLGenFencesNV(1, &fence);
|
||||
fGLSetFenceNV(fence, GL_ALL_COMPLETED_NV);
|
||||
return fence;
|
||||
}
|
||||
|
||||
bool GLNVFenceSync::waitFence(sk_gpu_test::PlatformFence fence) const {
|
||||
fGLFinishFenceNV(fence);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLNVFenceSync::deleteFence(sk_gpu_test::PlatformFence fence) const {
|
||||
GrGLuint glFence = static_cast<GrGLuint>(fence);
|
||||
fGLDeleteFencesNV(1, &glFence);
|
||||
}
|
||||
|
||||
class GLGpuTimer : public sk_gpu_test::GpuTimer {
|
||||
public:
|
||||
static std::unique_ptr<GLGpuTimer> MakeIfSupported(const sk_gpu_test::GLTestContext*);
|
||||
@ -284,9 +155,29 @@ GLTestContext::~GLTestContext() {
|
||||
SkASSERT(nullptr == fGL.get());
|
||||
}
|
||||
|
||||
void GLTestContext::init(sk_sp<const GrGLInterface> gl, std::unique_ptr<FenceSync> fenceSync) {
|
||||
static bool fence_is_supported(const GLTestContext* ctx) {
|
||||
if (kGL_GrGLStandard == ctx->gl()->fStandard) {
|
||||
if (GrGLGetVersion(ctx->gl()) < GR_GL_VER(3, 2) &&
|
||||
!ctx->gl()->hasExtension("GL_ARB_sync")) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
if (ctx->gl()->hasExtension("GL_APPLE_sync")) {
|
||||
return true;
|
||||
} else if (ctx->gl()->hasExtension("GL_NV_fence")) {
|
||||
return true;
|
||||
} else if (GrGLGetVersion(ctx->gl()) >= GR_GL_VER(3, 0)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLTestContext::init(sk_sp<const GrGLInterface> gl) {
|
||||
fGL = std::move(gl);
|
||||
fFenceSync = fenceSync ? std::move(fenceSync) : GLFenceSync::MakeIfSupported(this);
|
||||
fFenceSupport = fence_is_supported(this);
|
||||
fGpuTimer = GLGpuTimer::MakeIfSupported(this);
|
||||
}
|
||||
|
||||
@ -302,12 +193,6 @@ void GLTestContext::testAbandon() {
|
||||
}
|
||||
}
|
||||
|
||||
void GLTestContext::submit() {
|
||||
if (fGL) {
|
||||
GR_GL_CALL(fGL.get(), Flush());
|
||||
}
|
||||
}
|
||||
|
||||
void GLTestContext::finish() {
|
||||
if (fGL) {
|
||||
GR_GL_CALL(fGL.get(), Finish());
|
||||
|
@ -43,9 +43,6 @@ public:
|
||||
|
||||
void testAbandon() override;
|
||||
|
||||
/** Ensures all work is submitted to the GPU for execution. */
|
||||
void submit() override;
|
||||
|
||||
/** Wait until all GPU work is finished. */
|
||||
void finish() override;
|
||||
|
||||
@ -77,9 +74,9 @@ protected:
|
||||
GLTestContext();
|
||||
|
||||
/*
|
||||
* Methods that sublcasses must call from their constructors and destructors.
|
||||
* Methods that subclasses must call from their constructors and destructors.
|
||||
*/
|
||||
void init(sk_sp<const GrGLInterface>, std::unique_ptr<FenceSync> = nullptr);
|
||||
void init(sk_sp<const GrGLInterface>);
|
||||
|
||||
void teardown() override;
|
||||
|
||||
|
@ -104,7 +104,6 @@ private:
|
||||
void onPlatformMakeNotCurrent() const override;
|
||||
void onPlatformMakeCurrent() const override;
|
||||
std::function<void()> onPlatformGetAutoContextRestore() const override;
|
||||
void onPlatformSwapBuffers() const override;
|
||||
GrGLFuncPtr onPlatformGetProcAddress(const char* name) const override;
|
||||
|
||||
void* fContext;
|
||||
@ -468,12 +467,6 @@ std::function<void()> ANGLEGLContext::onPlatformGetAutoContextRestore() const {
|
||||
return context_restorer();
|
||||
}
|
||||
|
||||
void ANGLEGLContext::onPlatformSwapBuffers() const {
|
||||
if (!eglSwapBuffers(fDisplay, fSurface)) {
|
||||
SkDebugf("Could not complete eglSwapBuffers.\n");
|
||||
}
|
||||
}
|
||||
|
||||
GrGLFuncPtr ANGLEGLContext::onPlatformGetProcAddress(const char* name) const {
|
||||
return eglGetProcAddress(name);
|
||||
}
|
||||
|
@ -362,15 +362,6 @@ std::function<void()> CommandBufferGLTestContext::onPlatformGetAutoContextRestor
|
||||
return context_restorer();
|
||||
}
|
||||
|
||||
void CommandBufferGLTestContext::onPlatformSwapBuffers() const {
|
||||
if (!gfFunctionsLoadedSuccessfully) {
|
||||
return;
|
||||
}
|
||||
if (!gfSwapBuffers(fDisplay, fSurface)) {
|
||||
SkDebugf("Command Buffer: Could not complete gfSwapBuffers.\n");
|
||||
}
|
||||
}
|
||||
|
||||
GrGLFuncPtr CommandBufferGLTestContext::onPlatformGetProcAddress(const char *name) const {
|
||||
if (!gfFunctionsLoadedSuccessfully) {
|
||||
return nullptr;
|
||||
@ -383,7 +374,12 @@ void CommandBufferGLTestContext::presentCommandBuffer() {
|
||||
this->gl()->fFunctions.fFlush();
|
||||
}
|
||||
|
||||
this->onPlatformSwapBuffers();
|
||||
if (!gfFunctionsLoadedSuccessfully) {
|
||||
return;
|
||||
}
|
||||
if (!gfSwapBuffers(fDisplay, fSurface)) {
|
||||
SkDebugf("Command Buffer: Could not complete gfSwapBuffers.\n");
|
||||
}
|
||||
}
|
||||
|
||||
bool CommandBufferGLTestContext::makeCurrent() {
|
||||
|
@ -45,8 +45,6 @@ private:
|
||||
|
||||
std::function<void()> onPlatformGetAutoContextRestore() const override;
|
||||
|
||||
void onPlatformSwapBuffers() const override;
|
||||
|
||||
GrGLFuncPtr onPlatformGetProcAddress(const char *name) const override;
|
||||
|
||||
void *fContext;
|
||||
|
@ -19,27 +19,6 @@
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO: Share this class with ANGLE if/when it gets support for EGL_KHR_fence_sync.
|
||||
class EGLFenceSync : public sk_gpu_test::FenceSync {
|
||||
public:
|
||||
static std::unique_ptr<EGLFenceSync> MakeIfSupported(EGLDisplay);
|
||||
|
||||
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);
|
||||
|
||||
PFNEGLCREATESYNCKHRPROC fEGLCreateSyncKHR;
|
||||
PFNEGLCLIENTWAITSYNCKHRPROC fEGLClientWaitSyncKHR;
|
||||
PFNEGLDESTROYSYNCKHRPROC fEGLDestroySyncKHR;
|
||||
|
||||
EGLDisplay fDisplay;
|
||||
|
||||
typedef sk_gpu_test::FenceSync INHERITED;
|
||||
};
|
||||
|
||||
std::function<void()> context_restorer() {
|
||||
auto display = eglGetCurrentDisplay();
|
||||
auto dsurface = eglGetCurrentSurface(EGL_DRAW);
|
||||
@ -66,7 +45,6 @@ private:
|
||||
void onPlatformMakeNotCurrent() const override;
|
||||
void onPlatformMakeCurrent() const override;
|
||||
std::function<void()> onPlatformGetAutoContextRestore() const override;
|
||||
void onPlatformSwapBuffers() const override;
|
||||
GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
|
||||
|
||||
void setupFenceSync(sk_sp<const GrGLInterface>);
|
||||
@ -223,7 +201,7 @@ EGLGLTestContext::EGLGLTestContext(GrGLStandard forcedGpuAPI, EGLGLTestContext*
|
||||
(PFNEGLDESTROYIMAGEKHRPROC)eglGetProcAddress("eglDestroyImageKHR");
|
||||
}
|
||||
|
||||
this->init(std::move(gl), EGLFenceSync::MakeIfSupported(fDisplay));
|
||||
this->init(std::move(gl));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -445,52 +423,10 @@ std::function<void()> EGLGLTestContext::onPlatformGetAutoContextRestore() const
|
||||
return context_restorer();
|
||||
}
|
||||
|
||||
void EGLGLTestContext::onPlatformSwapBuffers() const {
|
||||
if (!eglSwapBuffers(fDisplay, fSurface)) {
|
||||
SkDebugf("Could not complete eglSwapBuffers.\n");
|
||||
}
|
||||
}
|
||||
|
||||
GrGLFuncPtr EGLGLTestContext::onPlatformGetProcAddress(const char* procName) const {
|
||||
return eglGetProcAddress(procName);
|
||||
}
|
||||
|
||||
std::unique_ptr<EGLFenceSync> EGLFenceSync::MakeIfSupported(EGLDisplay display) {
|
||||
if (!display || !supports_egl_extension(display, "EGL_KHR_fence_sync")) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::unique_ptr<EGLFenceSync>(new EGLFenceSync(display));
|
||||
}
|
||||
|
||||
EGLFenceSync::EGLFenceSync(EGLDisplay display)
|
||||
: fDisplay(display) {
|
||||
fEGLCreateSyncKHR = (PFNEGLCREATESYNCKHRPROC) eglGetProcAddress("eglCreateSyncKHR");
|
||||
fEGLClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC) eglGetProcAddress("eglClientWaitSyncKHR");
|
||||
fEGLDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC) eglGetProcAddress("eglDestroySyncKHR");
|
||||
SkASSERT(fEGLCreateSyncKHR && fEGLClientWaitSyncKHR && fEGLDestroySyncKHR);
|
||||
}
|
||||
|
||||
sk_gpu_test::PlatformFence EGLFenceSync::insertFence() const {
|
||||
EGLSyncKHR eglsync = fEGLCreateSyncKHR(fDisplay, EGL_SYNC_FENCE_KHR, nullptr);
|
||||
return reinterpret_cast<sk_gpu_test::PlatformFence>(eglsync);
|
||||
}
|
||||
|
||||
bool EGLFenceSync::waitFence(sk_gpu_test::PlatformFence platformFence) const {
|
||||
EGLSyncKHR eglsync = reinterpret_cast<EGLSyncKHR>(platformFence);
|
||||
return EGL_CONDITION_SATISFIED_KHR ==
|
||||
fEGLClientWaitSyncKHR(fDisplay,
|
||||
eglsync,
|
||||
EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
|
||||
EGL_FOREVER_KHR);
|
||||
}
|
||||
|
||||
void EGLFenceSync::deleteFence(sk_gpu_test::PlatformFence platformFence) const {
|
||||
EGLSyncKHR eglsync = reinterpret_cast<EGLSyncKHR>(platformFence);
|
||||
fEGLDestroySyncKHR(fDisplay, eglsync);
|
||||
}
|
||||
|
||||
static_assert(sizeof(EGLSyncKHR) <= sizeof(sk_gpu_test::PlatformFence));
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace sk_gpu_test {
|
||||
|
@ -64,7 +64,6 @@ private:
|
||||
void onPlatformMakeNotCurrent() const override;
|
||||
void onPlatformMakeCurrent() const override;
|
||||
std::function<void()> onPlatformGetAutoContextRestore() const override;
|
||||
void onPlatformSwapBuffers() const override;
|
||||
GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
|
||||
|
||||
GLXContext fContext;
|
||||
@ -368,10 +367,6 @@ std::function<void()> GLXGLTestContext::onPlatformGetAutoContextRestore() const
|
||||
return context_restorer();
|
||||
}
|
||||
|
||||
void GLXGLTestContext::onPlatformSwapBuffers() const {
|
||||
glXSwapBuffers(fDisplay, fGlxPixmap);
|
||||
}
|
||||
|
||||
GrGLFuncPtr GLXGLTestContext::onPlatformGetProcAddress(const char* procName) const {
|
||||
return glXGetProcAddress(reinterpret_cast<const GLubyte*>(procName));
|
||||
}
|
||||
|
@ -30,7 +30,6 @@ private:
|
||||
void onPlatformMakeNotCurrent() const override;
|
||||
void onPlatformMakeCurrent() const override;
|
||||
std::function<void()> onPlatformGetAutoContextRestore() const override;
|
||||
void onPlatformSwapBuffers() const override;
|
||||
GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
|
||||
|
||||
EAGLContext* fEAGLContext;
|
||||
@ -114,8 +113,6 @@ std::function<void()> IOSGLTestContext::onPlatformGetAutoContextRestore() const
|
||||
return context_restorer();
|
||||
}
|
||||
|
||||
void IOSGLTestContext::onPlatformSwapBuffers() const { }
|
||||
|
||||
GrGLFuncPtr IOSGLTestContext::onPlatformGetProcAddress(const char* procName) const {
|
||||
void* handle = (nullptr == fGLLibrary) ? RTLD_DEFAULT : fGLLibrary;
|
||||
return reinterpret_cast<GrGLFuncPtr>(dlsym(handle, procName));
|
||||
|
@ -31,7 +31,6 @@ private:
|
||||
void onPlatformMakeNotCurrent() const override;
|
||||
void onPlatformMakeCurrent() const override;
|
||||
std::function<void()> onPlatformGetAutoContextRestore() const override;
|
||||
void onPlatformSwapBuffers() const override;
|
||||
GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
|
||||
|
||||
CGLContextObj fContext;
|
||||
@ -122,10 +121,6 @@ std::function<void()> MacGLTestContext::onPlatformGetAutoContextRestore() const
|
||||
return context_restorer();
|
||||
}
|
||||
|
||||
void MacGLTestContext::onPlatformSwapBuffers() const {
|
||||
CGLFlushDrawable(fContext);
|
||||
}
|
||||
|
||||
GrGLFuncPtr MacGLTestContext::onPlatformGetProcAddress(const char* procName) const {
|
||||
void* handle = (nullptr == fGLLibrary) ? RTLD_DEFAULT : fGLLibrary;
|
||||
return reinterpret_cast<GrGLFuncPtr>(dlsym(handle, procName));
|
||||
|
@ -43,7 +43,6 @@ private:
|
||||
void onPlatformMakeNotCurrent() const override;
|
||||
void onPlatformMakeCurrent() const override;
|
||||
std::function<void()> onPlatformGetAutoContextRestore() const override;
|
||||
void onPlatformSwapBuffers() const override;
|
||||
GrGLFuncPtr onPlatformGetProcAddress(const char* name) const override;
|
||||
|
||||
HWND fWindow;
|
||||
@ -205,19 +204,6 @@ std::function<void()> WinGLTestContext::onPlatformGetAutoContextRestore() const
|
||||
return context_restorer();
|
||||
}
|
||||
|
||||
void WinGLTestContext::onPlatformSwapBuffers() const {
|
||||
HDC dc;
|
||||
|
||||
if (nullptr == fPbufferContext) {
|
||||
dc = fDeviceContext;
|
||||
} else {
|
||||
dc = fPbufferContext->getDC();
|
||||
}
|
||||
if (!SwapBuffers(dc)) {
|
||||
SkDebugf("Could not complete SwapBuffers.\n");
|
||||
}
|
||||
}
|
||||
|
||||
GrGLFuncPtr WinGLTestContext::onPlatformGetProcAddress(const char* name) const {
|
||||
return reinterpret_cast<GrGLFuncPtr>(wglGetProcAddress(name));
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ public:
|
||||
virtual GrBackendApi backend() override { return GrBackendApi::kMock; }
|
||||
|
||||
void testAbandon() override {}
|
||||
void submit() override {}
|
||||
void finish() override {}
|
||||
|
||||
sk_sp<GrContext> makeGrContext(const GrContextOptions& options) override {
|
||||
@ -34,7 +33,6 @@ protected:
|
||||
void onPlatformMakeNotCurrent() const override {}
|
||||
void onPlatformMakeCurrent() const override {}
|
||||
std::function<void()> onPlatformGetAutoContextRestore() const override { return nullptr; }
|
||||
void onPlatformSwapBuffers() const override {}
|
||||
|
||||
private:
|
||||
typedef sk_gpu_test::TestContext INHERITED;
|
||||
|
@ -17,56 +17,6 @@
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* Implements sk_gpu_test::FenceSync for Metal.
|
||||
*
|
||||
* Fences as MTLSharedEvents are not supported across all Metal platforms, so we do
|
||||
* the next best thing and submit an empty MTLCommandBuffer and track when it's complete.
|
||||
*/
|
||||
class MtlFenceSync : public sk_gpu_test::FenceSync {
|
||||
public:
|
||||
MtlFenceSync(id<MTLCommandQueue> queue)
|
||||
: fQueue(queue) {
|
||||
SkDEBUGCODE(fUnfinishedSyncs = 0;)
|
||||
}
|
||||
|
||||
~MtlFenceSync() override {
|
||||
SkASSERT(!fUnfinishedSyncs);
|
||||
}
|
||||
|
||||
sk_gpu_test::PlatformFence SK_WARN_UNUSED_RESULT insertFence() const override {
|
||||
id<MTLCommandBuffer> cmdBuffer = [fQueue commandBuffer];
|
||||
cmdBuffer.label = @"Fence";
|
||||
[cmdBuffer commit];
|
||||
|
||||
SkDEBUGCODE(++fUnfinishedSyncs;)
|
||||
|
||||
void* cfCmdBuffer = (__bridge_retained void*)cmdBuffer;
|
||||
return (sk_gpu_test::PlatformFence)cfCmdBuffer;
|
||||
}
|
||||
|
||||
bool waitFence(sk_gpu_test::PlatformFence opaqueFence) const override {
|
||||
void* cfCmdBuffer = (void*) opaqueFence;
|
||||
id<MTLCommandBuffer> cmdBuffer = (__bridge id<MTLCommandBuffer>) cfCmdBuffer;
|
||||
|
||||
[cmdBuffer waitUntilCompleted];
|
||||
|
||||
return (MTLCommandBufferStatusError != cmdBuffer.status);
|
||||
}
|
||||
|
||||
void deleteFence(sk_gpu_test::PlatformFence opaqueFence) const override {
|
||||
CFRelease((void*) opaqueFence);
|
||||
SkDEBUGCODE(--fUnfinishedSyncs;)
|
||||
}
|
||||
|
||||
private:
|
||||
id<MTLCommandQueue> fQueue;
|
||||
SkDEBUGCODE(mutable int fUnfinishedSyncs;)
|
||||
typedef sk_gpu_test::FenceSync INHERITED;
|
||||
};
|
||||
|
||||
static_assert(sizeof(uint64_t) <= sizeof(sk_gpu_test::PlatformFence));
|
||||
|
||||
class MtlTestContextImpl : public sk_gpu_test::MtlTestContext {
|
||||
public:
|
||||
static MtlTestContext* Create(MtlTestContext* sharedContext) {
|
||||
@ -88,9 +38,6 @@ public:
|
||||
|
||||
void testAbandon() override {}
|
||||
|
||||
// There is really nothing to do here since we don't own any unqueued command buffers here.
|
||||
void submit() override {}
|
||||
|
||||
void finish() override {}
|
||||
|
||||
sk_sp<GrContext> makeGrContext(const GrContextOptions& options) override {
|
||||
@ -105,13 +52,12 @@ public:
|
||||
private:
|
||||
MtlTestContextImpl(id<MTLDevice> device, id<MTLCommandQueue> queue)
|
||||
: INHERITED(), fDevice(device), fQueue(queue) {
|
||||
fFenceSync.reset(new MtlFenceSync(queue));
|
||||
fFenceSupport = true;
|
||||
}
|
||||
|
||||
void onPlatformMakeNotCurrent() const override {}
|
||||
void onPlatformMakeCurrent() const override {}
|
||||
std::function<void()> onPlatformGetAutoContextRestore() const override { return nullptr; }
|
||||
void onPlatformSwapBuffers() const override {}
|
||||
|
||||
id<MTLDevice> fDevice;
|
||||
id<MTLCommandQueue> fQueue;
|
||||
|
@ -19,131 +19,6 @@ namespace {
|
||||
f##name = reinterpret_cast<PFN_vk##name>(getProc("vk" #name, nullptr, device)); \
|
||||
SkASSERT(f##name)
|
||||
|
||||
/**
|
||||
* 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 sk_gpu_test::FenceSync {
|
||||
public:
|
||||
VkFenceSync(GrVkGetProc getProc, VkDevice device, VkQueue queue,
|
||||
uint32_t queueFamilyIndex)
|
||||
: fDevice(device)
|
||||
, fQueue(queue) {
|
||||
ACQUIRE_VK_PROC(CreateCommandPool, device);
|
||||
ACQUIRE_VK_PROC(DestroyCommandPool, device);
|
||||
ACQUIRE_VK_PROC(AllocateCommandBuffers, device);
|
||||
ACQUIRE_VK_PROC(FreeCommandBuffers, device);
|
||||
ACQUIRE_VK_PROC(BeginCommandBuffer, device);
|
||||
ACQUIRE_VK_PROC(EndCommandBuffer, device);
|
||||
ACQUIRE_VK_PROC(CreateFence, device);
|
||||
ACQUIRE_VK_PROC(DestroyFence, device);
|
||||
ACQUIRE_VK_PROC(WaitForFences, device);
|
||||
ACQUIRE_VK_PROC(QueueSubmit, device);
|
||||
|
||||
VkResult result;
|
||||
SkDEBUGCODE(fUnfinishedSyncs = 0;)
|
||||
VkCommandPoolCreateInfo createInfo;
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
createInfo.pNext = nullptr;
|
||||
createInfo.flags = 0;
|
||||
createInfo.queueFamilyIndex = queueFamilyIndex;
|
||||
result = fCreateCommandPool(fDevice, &createInfo, nullptr, &fCommandPool);
|
||||
SkASSERT(VK_SUCCESS == result);
|
||||
|
||||
VkCommandBufferAllocateInfo allocateInfo;
|
||||
allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
allocateInfo.pNext = nullptr;
|
||||
allocateInfo.commandBufferCount = 1;
|
||||
allocateInfo.commandPool = fCommandPool;
|
||||
allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
result = fAllocateCommandBuffers(fDevice, &allocateInfo, &fCommandBuffer);
|
||||
SkASSERT(VK_SUCCESS == result);
|
||||
|
||||
VkCommandBufferBeginInfo beginInfo;
|
||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
beginInfo.pNext = nullptr;
|
||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
|
||||
beginInfo.pInheritanceInfo = nullptr;
|
||||
result = fBeginCommandBuffer(fCommandBuffer, &beginInfo);
|
||||
SkASSERT(VK_SUCCESS == result);
|
||||
result = fEndCommandBuffer(fCommandBuffer);
|
||||
SkASSERT(VK_SUCCESS == result);
|
||||
|
||||
}
|
||||
|
||||
~VkFenceSync() override {
|
||||
SkASSERT(!fUnfinishedSyncs);
|
||||
// If the above assertion is true then the command buffer should not be in flight.
|
||||
fFreeCommandBuffers(fDevice, fCommandPool, 1, &fCommandBuffer);
|
||||
fDestroyCommandPool(fDevice, fCommandPool, nullptr);
|
||||
}
|
||||
|
||||
sk_gpu_test::PlatformFence SK_WARN_UNUSED_RESULT insertFence() const override {
|
||||
VkResult result;
|
||||
|
||||
VkFence fence;
|
||||
VkFenceCreateInfo info;
|
||||
info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.flags = 0;
|
||||
result = fCreateFence(fDevice, &info, nullptr, &fence);
|
||||
SkASSERT(VK_SUCCESS == result);
|
||||
|
||||
VkSubmitInfo submitInfo;
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.pNext = nullptr;
|
||||
submitInfo.waitSemaphoreCount = 0;
|
||||
submitInfo.pWaitSemaphores = nullptr;
|
||||
submitInfo.pWaitDstStageMask = nullptr;
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &fCommandBuffer;
|
||||
submitInfo.signalSemaphoreCount = 0;
|
||||
submitInfo.pSignalSemaphores = nullptr;
|
||||
result = fQueueSubmit(fQueue, 1, &submitInfo, fence);
|
||||
SkASSERT(VK_SUCCESS == result);
|
||||
|
||||
SkDEBUGCODE(++fUnfinishedSyncs;)
|
||||
return (sk_gpu_test::PlatformFence)fence;
|
||||
}
|
||||
|
||||
bool waitFence(sk_gpu_test::PlatformFence opaqueFence) const override {
|
||||
VkFence fence = (VkFence)opaqueFence;
|
||||
static constexpr uint64_t kForever = ~((uint64_t)0);
|
||||
auto result = fWaitForFences(fDevice, 1, &fence, true, kForever);
|
||||
return result != VK_TIMEOUT;
|
||||
}
|
||||
|
||||
void deleteFence(sk_gpu_test::PlatformFence opaqueFence) const override {
|
||||
VkFence fence = (VkFence)opaqueFence;
|
||||
fDestroyFence(fDevice, fence, nullptr);
|
||||
SkDEBUGCODE(--fUnfinishedSyncs;)
|
||||
}
|
||||
|
||||
private:
|
||||
VkDevice fDevice;
|
||||
VkQueue fQueue;
|
||||
VkCommandPool fCommandPool;
|
||||
VkCommandBuffer fCommandBuffer;
|
||||
|
||||
PFN_vkCreateCommandPool fCreateCommandPool = nullptr;
|
||||
PFN_vkDestroyCommandPool fDestroyCommandPool = nullptr;
|
||||
PFN_vkAllocateCommandBuffers fAllocateCommandBuffers = nullptr;
|
||||
PFN_vkFreeCommandBuffers fFreeCommandBuffers = nullptr;
|
||||
PFN_vkBeginCommandBuffer fBeginCommandBuffer = nullptr;
|
||||
PFN_vkEndCommandBuffer fEndCommandBuffer = nullptr;
|
||||
PFN_vkCreateFence fCreateFence = nullptr;
|
||||
PFN_vkDestroyFence fDestroyFence = nullptr;
|
||||
PFN_vkWaitForFences fWaitForFences = nullptr;
|
||||
PFN_vkQueueSubmit fQueueSubmit = nullptr;
|
||||
|
||||
SkDEBUGCODE(mutable int fUnfinishedSyncs;)
|
||||
typedef sk_gpu_test::FenceSync INHERITED;
|
||||
};
|
||||
|
||||
static_assert(sizeof(VkFence) <= sizeof(sk_gpu_test::PlatformFence));
|
||||
|
||||
// TODO: Implement swap buffers and finish
|
||||
class VkTestContextImpl : public sk_gpu_test::VkTestContext {
|
||||
public:
|
||||
static VkTestContext* Create(VkTestContext* sharedContext) {
|
||||
@ -196,9 +71,6 @@ public:
|
||||
|
||||
void testAbandon() override {}
|
||||
|
||||
// There is really nothing to here since we don't own any unqueued command buffers here.
|
||||
void submit() override {}
|
||||
|
||||
void finish() override {}
|
||||
|
||||
sk_sp<GrContext> makeGrContext(const GrContextOptions& options) override {
|
||||
@ -245,14 +117,12 @@ private:
|
||||
PFN_vkDestroyDebugReportCallbackEXT destroyCallback)
|
||||
: VkTestContext(backendContext, extensions, features, ownsContext, debugCallback,
|
||||
destroyCallback) {
|
||||
fFenceSync.reset(new VkFenceSync(fVk.fGetProc, fVk.fDevice, fVk.fQueue,
|
||||
fVk.fGraphicsQueueIndex));
|
||||
fFenceSupport = true;
|
||||
}
|
||||
|
||||
void onPlatformMakeNotCurrent() const override {}
|
||||
void onPlatformMakeCurrent() const override {}
|
||||
std::function<void()> onPlatformGetAutoContextRestore() const override { return nullptr; }
|
||||
void onPlatformSwapBuffers() const override {}
|
||||
|
||||
typedef sk_gpu_test::VkTestContext INHERITED;
|
||||
};
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "tools/flags/CommandLineFlags.h"
|
||||
#include "tools/flags/CommonFlags.h"
|
||||
#include "tools/flags/CommonFlagsConfig.h"
|
||||
#include "tools/gpu/FlushFinishTracker.h"
|
||||
#include "tools/gpu/GpuTimer.h"
|
||||
#include "tools/gpu/GrContextFactory.h"
|
||||
|
||||
@ -98,16 +99,17 @@ struct Sample {
|
||||
|
||||
class GpuSync {
|
||||
public:
|
||||
GpuSync(const sk_gpu_test::FenceSync* fenceSync);
|
||||
~GpuSync();
|
||||
GpuSync() {}
|
||||
~GpuSync() {}
|
||||
|
||||
void syncToPreviousFrame();
|
||||
void waitIfNeeded();
|
||||
|
||||
sk_gpu_test::FlushFinishTracker* newFlushTracker(GrContext* context);
|
||||
|
||||
private:
|
||||
void updateFence();
|
||||
|
||||
const sk_gpu_test::FenceSync* const fFenceSync;
|
||||
sk_gpu_test::PlatformFence fFence;
|
||||
enum { kMaxFrameLag = 3 };
|
||||
sk_sp<sk_gpu_test::FlushFinishTracker> fFinishTrackers[kMaxFrameLag - 1];
|
||||
int fCurrentFlushIdx = 0;
|
||||
};
|
||||
|
||||
enum class ExitErr {
|
||||
@ -119,7 +121,8 @@ enum class ExitErr {
|
||||
kSoftware = 70
|
||||
};
|
||||
|
||||
static void draw_skp_and_flush(SkSurface*, const SkPicture*);
|
||||
static void flush_with_sync(GrContext*, GpuSync&);
|
||||
static void draw_skp_and_flush_with_sync(GrContext*, SkSurface*, const SkPicture*, GpuSync&);
|
||||
static sk_sp<SkPicture> create_warmup_skp();
|
||||
static sk_sp<SkPicture> create_skp_from_svg(SkStream*, const char* filename);
|
||||
static bool mkdir_p(const SkString& name);
|
||||
@ -128,25 +131,25 @@ static void exitf(ExitErr, const char* format, ...);
|
||||
|
||||
// An interface used by both static SKPs and animated SKPs
|
||||
class SkpProducer {
|
||||
public:
|
||||
virtual ~SkpProducer() {}
|
||||
// Draw an SkPicture to the provided surface, flush the surface, and sync the GPU.
|
||||
// You may use the static draw_skp_and_flush declared above.
|
||||
// returned int tells how many draw/flush/sync were done.
|
||||
virtual int drawAndFlushAndSync(SkSurface* surface, GpuSync& gpuSync) = 0;
|
||||
public:
|
||||
virtual ~SkpProducer() {}
|
||||
// Draw an SkPicture to the provided surface, flush the surface, and sync the GPU.
|
||||
// You may use the static draw_skp_and_flush_with_sync declared above.
|
||||
// returned int tells how many draw/flush/sync were done.
|
||||
virtual int drawAndFlushAndSync(GrContext*, SkSurface* surface, GpuSync& gpuSync) = 0;
|
||||
};
|
||||
|
||||
class StaticSkp : public SkpProducer {
|
||||
public:
|
||||
StaticSkp(sk_sp<SkPicture> skp) : fSkp(skp) {}
|
||||
public:
|
||||
StaticSkp(sk_sp<SkPicture> skp) : fSkp(skp) {}
|
||||
|
||||
int drawAndFlushAndSync(SkSurface* surface, GpuSync& gpuSync) override {
|
||||
draw_skp_and_flush(surface, fSkp.get());
|
||||
gpuSync.syncToPreviousFrame();
|
||||
int drawAndFlushAndSync(GrContext* context, SkSurface* surface, GpuSync& gpuSync) override {
|
||||
draw_skp_and_flush_with_sync(context, surface, fSkp.get(), gpuSync);
|
||||
return 1;
|
||||
}
|
||||
private:
|
||||
sk_sp<SkPicture> fSkp;
|
||||
|
||||
private:
|
||||
sk_sp<SkPicture> fSkp;
|
||||
};
|
||||
|
||||
// A class for playing/benchmarking a multi frame SKP file.
|
||||
@ -182,10 +185,9 @@ public:
|
||||
}
|
||||
|
||||
// Draw the whole animation once.
|
||||
int drawAndFlushAndSync(SkSurface* surface, GpuSync& gpuSync) override {
|
||||
int drawAndFlushAndSync(GrContext* context, SkSurface* surface, GpuSync& gpuSync) override {
|
||||
for (int i=0; i<this->count(); i++){
|
||||
draw_skp_and_flush(surface, this->frame(i).get());
|
||||
gpuSync.syncToPreviousFrame();
|
||||
draw_skp_and_flush_with_sync(context, surface, this->frame(i).get(), gpuSync);
|
||||
}
|
||||
return this->count();
|
||||
}
|
||||
@ -197,7 +199,7 @@ private:
|
||||
std::vector<SkDocumentPage> fFrames;
|
||||
};
|
||||
|
||||
static void ddl_sample(GrContext* context, DDLTileHelper* tiles, GpuSync* gpuSync, Sample* sample,
|
||||
static void ddl_sample(GrContext* context, DDLTileHelper* tiles, GpuSync& gpuSync, Sample* sample,
|
||||
std::chrono::high_resolution_clock::time_point* startStopTime) {
|
||||
using clock = std::chrono::high_resolution_clock;
|
||||
|
||||
@ -206,10 +208,8 @@ static void ddl_sample(GrContext* context, DDLTileHelper* tiles, GpuSync* gpuSyn
|
||||
tiles->createDDLsInParallel();
|
||||
|
||||
if (!FLAGS_ddlRecordTime) {
|
||||
tiles->drawAllTilesAndFlush(context, true);
|
||||
if (gpuSync) {
|
||||
gpuSync->syncToPreviousFrame();
|
||||
}
|
||||
tiles->drawAllTiles(context);
|
||||
flush_with_sync(context, gpuSync);
|
||||
}
|
||||
|
||||
*startStopTime = clock::now();
|
||||
@ -217,14 +217,12 @@ static void ddl_sample(GrContext* context, DDLTileHelper* tiles, GpuSync* gpuSyn
|
||||
tiles->resetAllTiles();
|
||||
|
||||
if (sample) {
|
||||
SkASSERT(gpuSync);
|
||||
sample->fDuration += *startStopTime - start;
|
||||
sample->fFrames++;
|
||||
}
|
||||
}
|
||||
|
||||
static void run_ddl_benchmark(const sk_gpu_test::FenceSync* fenceSync,
|
||||
GrContext* context, sk_sp<SkSurface> surface,
|
||||
static void run_ddl_benchmark(GrContext* context, sk_sp<SkSurface> surface,
|
||||
SkPicture* inputPicture, std::vector<Sample>* samples) {
|
||||
using clock = std::chrono::high_resolution_clock;
|
||||
const Sample::duration sampleDuration = std::chrono::milliseconds(FLAGS_sampleMs);
|
||||
@ -250,9 +248,8 @@ static void run_ddl_benchmark(const sk_gpu_test::FenceSync* fenceSync,
|
||||
|
||||
clock::time_point startStopTime = clock::now();
|
||||
|
||||
ddl_sample(context, &tiles, nullptr, nullptr, &startStopTime);
|
||||
GpuSync gpuSync(fenceSync);
|
||||
ddl_sample(context, &tiles, &gpuSync, nullptr, &startStopTime);
|
||||
GpuSync gpuSync;
|
||||
ddl_sample(context, &tiles, gpuSync, nullptr, &startStopTime);
|
||||
|
||||
clock::duration cumulativeDuration = std::chrono::milliseconds(0);
|
||||
|
||||
@ -261,7 +258,7 @@ static void run_ddl_benchmark(const sk_gpu_test::FenceSync* fenceSync,
|
||||
Sample& sample = samples->back();
|
||||
|
||||
do {
|
||||
ddl_sample(context, &tiles, &gpuSync, &sample, &startStopTime);
|
||||
ddl_sample(context, &tiles, gpuSync, &sample, &startStopTime);
|
||||
} while (sample.fDuration < sampleDuration);
|
||||
|
||||
cumulativeDuration += sample.fDuration;
|
||||
@ -279,16 +276,16 @@ static void run_ddl_benchmark(const sk_gpu_test::FenceSync* fenceSync,
|
||||
context->flush(flushInfo);
|
||||
}
|
||||
|
||||
static void run_benchmark(const sk_gpu_test::FenceSync* fenceSync, SkSurface* surface,
|
||||
SkpProducer* skpp, std::vector<Sample>* samples) {
|
||||
static void run_benchmark(GrContext* context, SkSurface* surface, SkpProducer* skpp,
|
||||
std::vector<Sample>* samples) {
|
||||
using clock = std::chrono::high_resolution_clock;
|
||||
const Sample::duration sampleDuration = std::chrono::milliseconds(FLAGS_sampleMs);
|
||||
const clock::duration benchDuration = std::chrono::milliseconds(FLAGS_duration);
|
||||
|
||||
GpuSync gpuSync(fenceSync);
|
||||
GpuSync gpuSync;
|
||||
int i = 0;
|
||||
do {
|
||||
i += skpp->drawAndFlushAndSync(surface, gpuSync);
|
||||
i += skpp->drawAndFlushAndSync(context, surface, gpuSync);
|
||||
} while(i < kNumFlushesToPrimeCache);
|
||||
|
||||
clock::time_point now = clock::now();
|
||||
@ -300,9 +297,9 @@ static void run_benchmark(const sk_gpu_test::FenceSync* fenceSync, SkSurface* su
|
||||
Sample& sample = samples->back();
|
||||
|
||||
do {
|
||||
sample.fFrames += skpp->drawAndFlushAndSync(surface, gpuSync);
|
||||
now = clock::now();
|
||||
sample.fDuration = now - sampleStart;
|
||||
sample.fFrames += skpp->drawAndFlushAndSync(context, surface, gpuSync);
|
||||
now = clock::now();
|
||||
sample.fDuration = now - sampleStart;
|
||||
} while (sample.fDuration < sampleDuration);
|
||||
} while (now < endTime || 0 == samples->size() % 2);
|
||||
|
||||
@ -313,9 +310,9 @@ static void run_benchmark(const sk_gpu_test::FenceSync* fenceSync, SkSurface* su
|
||||
surface->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo);
|
||||
}
|
||||
|
||||
static void run_gpu_time_benchmark(sk_gpu_test::GpuTimer* gpuTimer,
|
||||
const sk_gpu_test::FenceSync* fenceSync, SkSurface* surface,
|
||||
const SkPicture* skp, std::vector<Sample>* samples) {
|
||||
static void run_gpu_time_benchmark(sk_gpu_test::GpuTimer* gpuTimer, GrContext* context,
|
||||
SkSurface* surface, const SkPicture* skp,
|
||||
std::vector<Sample>* samples) {
|
||||
using sk_gpu_test::PlatformTimerQuery;
|
||||
using clock = std::chrono::steady_clock;
|
||||
const clock::duration sampleDuration = std::chrono::milliseconds(FLAGS_sampleMs);
|
||||
@ -326,15 +323,14 @@ static void run_gpu_time_benchmark(sk_gpu_test::GpuTimer* gpuTimer,
|
||||
"results may be unreliable\n");
|
||||
}
|
||||
|
||||
draw_skp_and_flush(surface, skp);
|
||||
GpuSync gpuSync(fenceSync);
|
||||
GpuSync gpuSync;
|
||||
draw_skp_and_flush_with_sync(context, surface, skp, gpuSync);
|
||||
|
||||
PlatformTimerQuery previousTime = 0;
|
||||
for (int i = 1; i < kNumFlushesToPrimeCache; ++i) {
|
||||
gpuTimer->queueStart();
|
||||
draw_skp_and_flush(surface, skp);
|
||||
draw_skp_and_flush_with_sync(context, surface, skp, gpuSync);
|
||||
previousTime = gpuTimer->queueStop();
|
||||
gpuSync.syncToPreviousFrame();
|
||||
}
|
||||
|
||||
clock::time_point now = clock::now();
|
||||
@ -347,9 +343,8 @@ static void run_gpu_time_benchmark(sk_gpu_test::GpuTimer* gpuTimer,
|
||||
|
||||
do {
|
||||
gpuTimer->queueStart();
|
||||
draw_skp_and_flush(surface, skp);
|
||||
draw_skp_and_flush_with_sync(context, surface, skp, gpuSync);
|
||||
PlatformTimerQuery time = gpuTimer->queueStop();
|
||||
gpuSync.syncToPreviousFrame();
|
||||
|
||||
switch (gpuTimer->checkQueryStatus(previousTime)) {
|
||||
using QueryStatus = sk_gpu_test::GpuTimer::QueryStatus;
|
||||
@ -555,12 +550,12 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
if (!FLAGS_gpuClock) {
|
||||
if (FLAGS_ddl) {
|
||||
run_ddl_benchmark(testCtx->fenceSync(), ctx, surface, skp.get(), &samples);
|
||||
run_ddl_benchmark(ctx, surface, skp.get(), &samples);
|
||||
} else if (!mskp) {
|
||||
auto s = std::make_unique<StaticSkp>(skp);
|
||||
run_benchmark(testCtx->fenceSync(), surface.get(), s.get(), &samples);
|
||||
run_benchmark(ctx, surface.get(), s.get(), &samples);
|
||||
} else {
|
||||
run_benchmark(testCtx->fenceSync(), surface.get(), mskp.get(), &samples);
|
||||
run_benchmark(ctx, surface.get(), mskp.get(), &samples);
|
||||
}
|
||||
} else {
|
||||
if (FLAGS_ddl) {
|
||||
@ -569,8 +564,7 @@ int main(int argc, char** argv) {
|
||||
if (!testCtx->gpuTimingSupport()) {
|
||||
exitf(ExitErr::kUnavailable, "GPU does not support timing");
|
||||
}
|
||||
run_gpu_time_benchmark(testCtx->gpuTimer(), testCtx->fenceSync(), surface.get(),
|
||||
skp.get(), &samples);
|
||||
run_gpu_time_benchmark(testCtx->gpuTimer(), ctx, surface.get(), skp.get(), &samples);
|
||||
}
|
||||
print_result(samples, config->getTag().c_str(), srcname.c_str());
|
||||
|
||||
@ -592,10 +586,22 @@ int main(int argc, char** argv) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void draw_skp_and_flush(SkSurface* surface, const SkPicture* skp) {
|
||||
static void flush_with_sync(GrContext* context, GpuSync& gpuSync) {
|
||||
gpuSync.waitIfNeeded();
|
||||
|
||||
GrFlushInfo flushInfo;
|
||||
flushInfo.fFinishedProc = sk_gpu_test::FlushFinishTracker::FlushFinished;
|
||||
flushInfo.fFinishedContext = gpuSync.newFlushTracker(context);
|
||||
|
||||
context->flush(flushInfo);
|
||||
}
|
||||
|
||||
static void draw_skp_and_flush_with_sync(GrContext* context, SkSurface* surface,
|
||||
const SkPicture* skp, GpuSync& gpuSync) {
|
||||
auto canvas = surface->getCanvas();
|
||||
canvas->drawPicture(skp);
|
||||
surface->flush();
|
||||
|
||||
flush_with_sync(context, gpuSync);
|
||||
}
|
||||
|
||||
static sk_sp<SkPicture> create_warmup_skp() {
|
||||
@ -671,29 +677,20 @@ static void exitf(ExitErr err, const char* format, ...) {
|
||||
exit((int)err);
|
||||
}
|
||||
|
||||
GpuSync::GpuSync(const sk_gpu_test::FenceSync* fenceSync)
|
||||
: fFenceSync(fenceSync) {
|
||||
this->updateFence();
|
||||
}
|
||||
|
||||
GpuSync::~GpuSync() {
|
||||
fFenceSync->deleteFence(fFence);
|
||||
}
|
||||
|
||||
void GpuSync::syncToPreviousFrame() {
|
||||
if (sk_gpu_test::kInvalidFence == fFence) {
|
||||
exitf(ExitErr::kSoftware, "attempted to sync with invalid fence");
|
||||
}
|
||||
if (!fFenceSync->waitFence(fFence)) {
|
||||
exitf(ExitErr::kUnavailable, "failed to wait for fence");
|
||||
}
|
||||
fFenceSync->deleteFence(fFence);
|
||||
this->updateFence();
|
||||
}
|
||||
|
||||
void GpuSync::updateFence() {
|
||||
fFence = fFenceSync->insertFence();
|
||||
if (sk_gpu_test::kInvalidFence == fFence) {
|
||||
exitf(ExitErr::kUnavailable, "failed to insert fence");
|
||||
void GpuSync::waitIfNeeded() {
|
||||
if (fFinishTrackers[fCurrentFlushIdx]) {
|
||||
fFinishTrackers[fCurrentFlushIdx]->waitTillFinished();
|
||||
}
|
||||
}
|
||||
|
||||
sk_gpu_test::FlushFinishTracker* GpuSync::newFlushTracker(GrContext* context) {
|
||||
fFinishTrackers[fCurrentFlushIdx].reset(new sk_gpu_test::FlushFinishTracker(context));
|
||||
|
||||
sk_gpu_test::FlushFinishTracker* tracker = fFinishTrackers[fCurrentFlushIdx].get();
|
||||
// We add an additional ref to the current flush tracker here. This ref is owned by the finish
|
||||
// callback on the flush call. The finish callback will unref the tracker when called.
|
||||
tracker->ref();
|
||||
|
||||
fCurrentFlushIdx = (fCurrentFlushIdx + 1) % SK_ARRAY_COUNT(fFinishTrackers);
|
||||
return tracker;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user