Add submittedProc to GrFlushInfo.
Bug: skia:10118 Change-Id: Iad848310d0f2fb22f19e9890209548fda103bd27 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/291078 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Greg Daniel <egdaniel@google.com>
This commit is contained in:
parent
1303a1a15c
commit
55822f17bd
@ -9,6 +9,11 @@ Milestone 85
|
||||
|
||||
* <insert new release notes here>
|
||||
|
||||
* Adds submittedProc callback to GrFlushInfo which will be called when the work
|
||||
from the flush call is submitted to the GPU. This is specifically useful for knowing
|
||||
when semahpores sent with the flush have been submitted and can be waiting on.
|
||||
https://review.skia.org/291078
|
||||
|
||||
* GrContext submit is now required to be called in order to send GPU work to the
|
||||
actual GPU. The flush calls simply produces 3D API specific objects that are ready
|
||||
to be submitted (e.g. command buffers). For the GL backend, the flush will still
|
||||
|
@ -112,6 +112,7 @@ tests_sources = [
|
||||
"$_tests/GrQuadBufferTest.cpp",
|
||||
"$_tests/GrQuadCropTest.cpp",
|
||||
"$_tests/GrStyledShapeTest.cpp",
|
||||
"$_tests/GrSubmittedFlushTest.cpp",
|
||||
"$_tests/GrSurfaceTest.cpp",
|
||||
"$_tests/GrTAllocatorTest.cpp",
|
||||
"$_tests/GrTRecorderTest.cpp",
|
||||
|
@ -234,6 +234,9 @@ enum GrFlushFlags {
|
||||
typedef void* GrGpuFinishedContext;
|
||||
typedef void (*GrGpuFinishedProc)(GrGpuFinishedContext finishedContext);
|
||||
|
||||
typedef void* GrGpuSubmittedContext;
|
||||
typedef void (*GrGpuSubmittedProc)(GrGpuSubmittedContext submittedContext, bool success);
|
||||
|
||||
/**
|
||||
* Struct to supply options to flush calls.
|
||||
*
|
||||
@ -251,13 +254,31 @@ typedef void (*GrGpuFinishedProc)(GrGpuFinishedContext finishedContext);
|
||||
* from this flush call and all previous flush calls has finished on the GPU. If the flush call
|
||||
* fails due to an error and nothing ends up getting sent to the GPU, the finished proc is called
|
||||
* immediately.
|
||||
*
|
||||
* If a submittedProc is provided, the submittedProc will be called when all work from this flush
|
||||
* call is submitted to the GPU. If the flush call fails due to an error and nothing will get sent
|
||||
* to the GPU, the submitted proc is called immediately. It is possibly that when work is finally
|
||||
* submitted, that the submission actual fails. In this case we will not reattempt to do the
|
||||
* submission. Skia notifies the client of these via the success bool passed into the submittedProc.
|
||||
* The submittedProc is useful to the client to know when semaphores that were sent with the flush
|
||||
* have actually been submitted to the GPU so that they can be waited on (or deleted if the submit
|
||||
* fails).
|
||||
* Note about GL: In GL work gets sent to the driver immediately during the flush call, but we don't
|
||||
* really know when the driver sends the work to the GPU. Therefore, we treat the submitted proc as
|
||||
* we do in other backends. It will be called when the next GrContext::submit is called after the
|
||||
* flush (or possibly during the flush if there is no work to be done for the flush). The main use
|
||||
* case for the submittedProc is to know when semaphores have been sent to the GPU and even in GL
|
||||
* it is required to call GrContext::submit to flush them. So a client should be able to treat all
|
||||
* backend APIs the same in terms of how the submitted procs are treated.
|
||||
*/
|
||||
struct GrFlushInfo {
|
||||
GrFlushFlags fFlags = kNone_GrFlushFlags;
|
||||
int fNumSemaphores = 0;
|
||||
GrBackendSemaphore* fSignalSemaphores = nullptr;
|
||||
GrGpuFinishedProc fFinishedProc = nullptr;
|
||||
GrFlushFlags fFlags = kNone_GrFlushFlags;
|
||||
int fNumSemaphores = 0;
|
||||
GrBackendSemaphore* fSignalSemaphores = nullptr;
|
||||
GrGpuFinishedProc fFinishedProc = nullptr;
|
||||
GrGpuFinishedContext fFinishedContext = nullptr;
|
||||
GrGpuSubmittedProc fSubmittedProc = nullptr;
|
||||
GrGpuSubmittedContext fSubmittedContext = nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -316,6 +316,12 @@ GrSemaphoresSubmitted GrContext::flush(const GrFlushInfo& info,
|
||||
const GrPrepareForExternalIORequests& externalRequests) {
|
||||
ASSERT_SINGLE_OWNER
|
||||
if (this->abandoned()) {
|
||||
if (info.fFinishedProc) {
|
||||
info.fFinishedProc(info.fFinishedContext);
|
||||
}
|
||||
if (info.fSubmittedProc) {
|
||||
info.fSubmittedProc(info.fSubmittedContext, false);
|
||||
}
|
||||
return GrSemaphoresSubmitted::kNo;
|
||||
}
|
||||
|
||||
|
@ -229,6 +229,9 @@ bool GrDrawingManager::flush(GrSurfaceProxy* proxies[], int numProxies,
|
||||
GR_CREATE_TRACE_MARKER_CONTEXT("GrDrawingManager", "flush", fContext);
|
||||
|
||||
if (fFlushing || this->wasAbandoned()) {
|
||||
if (info.fSubmittedProc) {
|
||||
info.fSubmittedProc(info.fSubmittedContext, false);
|
||||
}
|
||||
if (info.fFinishedProc) {
|
||||
info.fFinishedProc(info.fFinishedContext);
|
||||
}
|
||||
@ -245,12 +248,18 @@ bool GrDrawingManager::flush(GrSurfaceProxy* proxies[], int numProxies,
|
||||
canSkip = !fDAG.isUsed(proxies[i]) && !this->isDDLTarget(proxies[i]);
|
||||
}
|
||||
if (canSkip) {
|
||||
if (info.fSubmittedProc) {
|
||||
info.fSubmittedProc(info.fSubmittedContext, true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto direct = fContext->priv().asDirectContext();
|
||||
if (!direct) {
|
||||
if (info.fSubmittedProc) {
|
||||
info.fSubmittedProc(info.fSubmittedContext, false);
|
||||
}
|
||||
if (info.fFinishedProc) {
|
||||
info.fFinishedProc(info.fFinishedContext);
|
||||
}
|
||||
@ -259,12 +268,8 @@ bool GrDrawingManager::flush(GrSurfaceProxy* proxies[], int numProxies,
|
||||
direct->priv().clientMappedBufferManager()->process();
|
||||
|
||||
GrGpu* gpu = direct->priv().getGpu();
|
||||
if (!gpu) {
|
||||
if (info.fFinishedProc) {
|
||||
info.fFinishedProc(info.fFinishedContext);
|
||||
}
|
||||
return false; // Can't flush while DDL recording
|
||||
}
|
||||
// We have a non abandoned and direct GrContext. It must have a GrGpu.
|
||||
SkASSERT(gpu);
|
||||
|
||||
fFlushing = true;
|
||||
|
||||
@ -515,6 +520,12 @@ GrSemaphoresSubmitted GrDrawingManager::flushSurfaces(GrSurfaceProxy* proxies[],
|
||||
SkSurface::BackendSurfaceAccess access,
|
||||
const GrFlushInfo& info) {
|
||||
if (this->wasAbandoned()) {
|
||||
if (info.fSubmittedProc) {
|
||||
info.fSubmittedProc(info.fSubmittedContext, false);
|
||||
}
|
||||
if (info.fFinishedProc) {
|
||||
info.fFinishedProc(info.fFinishedContext);
|
||||
}
|
||||
return GrSemaphoresSubmitted::kNo;
|
||||
}
|
||||
SkDEBUGCODE(this->validate());
|
||||
@ -523,13 +534,18 @@ GrSemaphoresSubmitted GrDrawingManager::flushSurfaces(GrSurfaceProxy* proxies[],
|
||||
|
||||
auto direct = fContext->priv().asDirectContext();
|
||||
if (!direct) {
|
||||
if (info.fSubmittedProc) {
|
||||
info.fSubmittedProc(info.fSubmittedContext, false);
|
||||
}
|
||||
if (info.fFinishedProc) {
|
||||
info.fFinishedProc(info.fFinishedContext);
|
||||
}
|
||||
return GrSemaphoresSubmitted::kNo; // Can't flush while DDL recording
|
||||
}
|
||||
|
||||
GrGpu* gpu = direct->priv().getGpu();
|
||||
if (!gpu) {
|
||||
return GrSemaphoresSubmitted::kNo; // Can't flush while DDL recording
|
||||
}
|
||||
// We have a non abandoned and direct GrContext. It must have a GrGpu.
|
||||
SkASSERT(gpu);
|
||||
|
||||
// TODO: It is important to upgrade the drawingmanager to just flushing the
|
||||
// portion of the DAG required by 'proxies' in order to restore some of the
|
||||
|
@ -42,6 +42,7 @@ static const size_t kMinStagingBufferSize = 32 * 1024;
|
||||
GrGpu::GrGpu(GrContext* context) : fResetBits(kAll_GrBackendState), fContext(context) {}
|
||||
|
||||
GrGpu::~GrGpu() {
|
||||
this->callSubmittedProcs(false);
|
||||
SkASSERT(fBusyStagingBuffers.isEmpty());
|
||||
}
|
||||
|
||||
@ -685,6 +686,11 @@ void GrGpu::executeFlushInfo(GrSurfaceProxy* proxies[],
|
||||
if (info.fFinishedProc) {
|
||||
this->addFinishedProc(info.fFinishedProc, info.fFinishedContext);
|
||||
}
|
||||
|
||||
if (info.fSubmittedProc) {
|
||||
fSubmittedProcs.emplace_back(info.fSubmittedProc, info.fSubmittedContext);
|
||||
}
|
||||
|
||||
this->prepareSurfacesForBackendAccessAndExternalIO(proxies, numProxies, access,
|
||||
externalRequests);
|
||||
}
|
||||
@ -699,9 +705,18 @@ bool GrGpu::submitToGpu(bool syncCpu) {
|
||||
|
||||
bool submitted = this->onSubmitToGpu(syncCpu);
|
||||
|
||||
this->callSubmittedProcs(submitted);
|
||||
|
||||
return submitted;
|
||||
}
|
||||
|
||||
void GrGpu::callSubmittedProcs(bool success) {
|
||||
for (int i = 0; i < fSubmittedProcs.count(); ++i) {
|
||||
fSubmittedProcs[i].fProc(fSubmittedProcs[i].fContext, success);
|
||||
}
|
||||
fSubmittedProcs.reset();
|
||||
}
|
||||
|
||||
#ifdef SK_ENABLE_DUMP_GPU
|
||||
void GrGpu::dumpJSON(SkJSONWriter* writer) const {
|
||||
writer->beginObject();
|
||||
|
@ -849,6 +849,8 @@ private:
|
||||
void validateStagingBuffers() const;
|
||||
#endif
|
||||
|
||||
void callSubmittedProcs(bool success);
|
||||
|
||||
uint32_t fResetBits;
|
||||
// The context owns us, not vice-versa, so this ptr is not ref'ed by Gpu.
|
||||
GrContext* fContext;
|
||||
@ -860,6 +862,15 @@ private:
|
||||
StagingBufferList fActiveStagingBuffers;
|
||||
StagingBufferList fBusyStagingBuffers;
|
||||
|
||||
struct SubmittedProc {
|
||||
SubmittedProc(GrGpuSubmittedProc proc, GrGpuSubmittedContext context)
|
||||
: fProc(proc), fContext(context) {}
|
||||
|
||||
GrGpuSubmittedProc fProc;
|
||||
GrGpuSubmittedContext fContext;
|
||||
};
|
||||
SkSTArray<4, SubmittedProc> fSubmittedProcs;
|
||||
|
||||
friend class GrPathRendering;
|
||||
typedef SkRefCnt INHERITED;
|
||||
};
|
||||
|
@ -2166,6 +2166,12 @@ GrSemaphoresSubmitted GrRenderTargetContext::flush(SkSurface::BackendSurfaceAcce
|
||||
const GrFlushInfo& info) {
|
||||
ASSERT_SINGLE_OWNER
|
||||
if (fContext->priv().abandoned()) {
|
||||
if (info.fSubmittedProc) {
|
||||
info.fSubmittedProc(info.fSubmittedContext, false);
|
||||
}
|
||||
if (info.fFinishedProc) {
|
||||
info.fFinishedProc(info.fFinishedContext);
|
||||
}
|
||||
return GrSemaphoresSubmitted::kNo;
|
||||
}
|
||||
SkDEBUGCODE(this->validate();)
|
||||
|
@ -67,6 +67,12 @@ SkImage_Gpu::~SkImage_Gpu() {}
|
||||
|
||||
GrSemaphoresSubmitted SkImage_Gpu::onFlush(GrContext* context, const GrFlushInfo& info) {
|
||||
if (!context || !fContext->priv().matches(context) || fContext->abandoned()) {
|
||||
if (info.fSubmittedProc) {
|
||||
info.fSubmittedProc(info.fSubmittedContext, false);
|
||||
}
|
||||
if (info.fFinishedProc) {
|
||||
info.fFinishedProc(info.fFinishedContext);
|
||||
}
|
||||
return GrSemaphoresSubmitted::kNo;
|
||||
}
|
||||
|
||||
|
@ -117,6 +117,12 @@ bool SkImage_GpuYUVA::setupMipmapsForPlanes(GrRecordingContext* context) const {
|
||||
|
||||
GrSemaphoresSubmitted SkImage_GpuYUVA::onFlush(GrContext* context, const GrFlushInfo& info) {
|
||||
if (!context || !fContext->priv().matches(context) || fContext->abandoned()) {
|
||||
if (info.fSubmittedProc) {
|
||||
info.fSubmittedProc(info.fSubmittedContext, false);
|
||||
}
|
||||
if (info.fFinishedProc) {
|
||||
info.fFinishedProc(info.fFinishedContext);
|
||||
}
|
||||
return GrSemaphoresSubmitted::kNo;
|
||||
}
|
||||
|
||||
|
88
tests/GrSubmittedFlushTest.cpp
Normal file
88
tests/GrSubmittedFlushTest.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "tests/Test.h"
|
||||
|
||||
#include "include/core/SkCanvas.h"
|
||||
#include "include/core/SkSurface.h"
|
||||
#include "include/gpu/GrContext.h"
|
||||
|
||||
using namespace sk_gpu_test;
|
||||
|
||||
namespace {
|
||||
struct SubmittedInfo {
|
||||
int* fCount;
|
||||
bool* fSuccess;
|
||||
};
|
||||
};
|
||||
|
||||
static void testing_submitted_proc(void* ctx, bool success) {
|
||||
SubmittedInfo* info = (SubmittedInfo*)ctx;
|
||||
*info->fCount += 1;
|
||||
*info->fSuccess = success;
|
||||
}
|
||||
|
||||
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(FlushSubmittedProcTest, reporter, ctxInfo) {
|
||||
GrContext* ctx = ctxInfo.grContext();
|
||||
|
||||
SkImageInfo info = SkImageInfo::Make(8, 8, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
|
||||
sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info);
|
||||
SkCanvas* canvas = surface->getCanvas();
|
||||
|
||||
canvas->clear(SK_ColorGREEN);
|
||||
|
||||
int submittedCount = 0;
|
||||
bool submittedSuccess = false;
|
||||
SubmittedInfo submittedInfo = { &submittedCount, &submittedSuccess };
|
||||
|
||||
GrFlushInfo flushInfo;
|
||||
flushInfo.fSubmittedProc = testing_submitted_proc;
|
||||
flushInfo.fSubmittedContext = &submittedInfo;
|
||||
|
||||
ctx->flush(flushInfo);
|
||||
REPORTER_ASSERT(reporter, submittedCount == 0);
|
||||
|
||||
ctx->submit();
|
||||
REPORTER_ASSERT(reporter, submittedCount == 1);
|
||||
REPORTER_ASSERT(reporter, submittedSuccess);
|
||||
|
||||
// There should be no work so if we flush again the submittedProc should be called immediately
|
||||
surface->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo);
|
||||
REPORTER_ASSERT(reporter, submittedCount == 2);
|
||||
REPORTER_ASSERT(reporter, submittedSuccess);
|
||||
|
||||
// However, flushing the context we don't do any checks of work so we still require submit to be
|
||||
// called in order for the callback to trigger.
|
||||
ctx->flush(flushInfo);
|
||||
REPORTER_ASSERT(reporter, submittedCount == 2);
|
||||
|
||||
ctx->submit();
|
||||
REPORTER_ASSERT(reporter, submittedCount == 3);
|
||||
REPORTER_ASSERT(reporter, submittedSuccess);
|
||||
|
||||
// Testing that doing multiple flushes before a submit triggers both submittedProcs to be called
|
||||
canvas->clear(SK_ColorBLUE);
|
||||
surface->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo);
|
||||
REPORTER_ASSERT(reporter, submittedCount == 3);
|
||||
canvas->clear(SK_ColorRED);
|
||||
surface->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo);
|
||||
REPORTER_ASSERT(reporter, submittedCount == 3);
|
||||
ctx->submit();
|
||||
|
||||
REPORTER_ASSERT(reporter, submittedCount == 5);
|
||||
REPORTER_ASSERT(reporter, submittedSuccess);
|
||||
|
||||
// Test an abandoned context to get a failed submit immediately when flush is called
|
||||
canvas->clear(SK_ColorCYAN);
|
||||
ctx->abandonContext();
|
||||
surface->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo);
|
||||
REPORTER_ASSERT(reporter, submittedCount == 6);
|
||||
REPORTER_ASSERT(reporter, !submittedSuccess);
|
||||
ctx->flush(flushInfo);
|
||||
REPORTER_ASSERT(reporter, submittedCount == 7);
|
||||
REPORTER_ASSERT(reporter, !submittedSuccess);
|
||||
}
|
Loading…
Reference in New Issue
Block a user