Reland "Implement submit API to GrContext."

This reverts commit 9ee15d7b57.

Reason for revert: relanding with fixes

Original change's description:
> Revert "Implement submit API to GrContext."
> 
> This reverts commit 40f288c72e.
> 
> Reason for revert: canvaskit breaking for some reason???
> 
> Original change's description:
> > Implement submit API to GrContext.
> > 
> > Change-Id: Ib813d42abb5f63e2ecdbf245d416658143853288
> > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/289033
> > Commit-Queue: Greg Daniel <egdaniel@google.com>
> > Reviewed-by: Brian Salomon <bsalomon@google.com>
> 
> TBR=egdaniel@google.com,bsalomon@google.com,penghuang@chromium.org,vasilyt@chromium.org
> 
> Change-Id: Iee6c8342cccc601edf64ea011f1303e5d72559a9
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/290917
> Reviewed-by: Greg Daniel <egdaniel@google.com>
> Commit-Queue: Greg Daniel <egdaniel@google.com>

TBR=egdaniel@google.com,bsalomon@google.com,penghuang@chromium.org,vasilyt@chromium.org

# Not skipping CQ checks because this is a reland.

Change-Id: I5203676f88893cbbaba685301b8a713b40396b48
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/290960
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
This commit is contained in:
Greg Daniel 2020-05-20 13:16:00 -04:00 committed by Skia Commit-Bot
parent c5eb5c7127
commit 04283f3f6f
14 changed files with 168 additions and 86 deletions

View File

@ -9,6 +9,16 @@ Milestone 85
* <insert new release notes here>
* 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
send commands to the driver. However, clients should still assume the must call
submit which is where any glFlush that is need for sync objects will be called. There,
are flushAndSubmit() functions of GrContext, SkSurface, and SkImage that will act
like the previous flush() functions. This will flush the work and immediately call
submit.
https://review.skia.org/289033
* Remove deprecated version of flush calls on GrContext and SkSurface.
https://review.skia.org/2290540

View File

@ -916,7 +916,8 @@ public:
Skia will correctly order its own draws and pixel operations. This must to be used to ensure
correct ordering when the surface backing store is accessed outside Skia (e.g. direct use of
the 3D API or a windowing system). GrContext has additional flush and submit methods that
apply to all surfaces and images created from a GrContext.
apply to all surfaces and images created from a GrContext. This is equivalent to calling
SkSurface::flush with a default GrFlushInfo followed by GrContext::submit.
*/
void flushAndSubmit();
@ -925,7 +926,16 @@ public:
kPresent, //!< back-end surface will be used for presenting to screen
};
/** Issues pending SkSurface commands to the GPU-backed API and resolves any SkSurface MSAA.
/** Issues pending SkSurface commands to the GPU-backed API objects and resolves any SkSurface
MSAA. A call to GrContext::submit is always required to ensure work is actually sent to the
gpu. Some specific API details:
GL: Commands are actually sent to the driver, but glFlush is never called. Thus some
sync objects from the flush will not be valid until a submission occurs.
Vulkan/Metal/D3D/Dawn: Commands are recorded to the backend APIs corresponding command
buffer or encoder objects. However, these objects are not sent to the gpu until a
submission occurs.
The work that is submitted to the GPU will be dependent on the BackendSurfaceAccess that is
passed in.
@ -941,13 +951,19 @@ public:
The GrFlushInfo describes additional options to flush. Please see documentation at
GrFlushInfo for more info.
If the return is GrSemaphoresSubmitted::kYes, only initialized GrBackendSemaphores will
have been submitted and can be waited on (it is possible Skia failed to create a subset of
the semaphores). If this call returns GrSemaphoresSubmitted::kNo, the GPU backend will not
have submitted any semaphores to be signaled on the GPU. Thus the client should not have
the GPU wait on any of the semaphores passed in with the GrFlushInfo. Regardless of whether
semaphores were submitted to the GPU or not, the client is still responsible for deleting
any initialized semaphores.
If the return is GrSemaphoresSubmitted::kYes, only initialized GrBackendSemaphores will be
submitted to the gpu during the next submit call (it is possible Skia failed to create a
subset of the semaphores). The client should not wait on these semaphores until after submit
has been called, but must keep them alive until then. If a submit flag was passed in with
the flush these valid semaphores can we waited on immediately. If this call returns
GrSemaphoresSubmitted::kNo, the GPU backend will not submit any semaphores to be signaled on
the GPU. Thus the client should not have the GPU wait on any of the semaphores passed in
with the GrFlushInfo. Regardless of whether semaphores were submitted to the GPU or not, the
client is still responsible for deleting any initialized semaphores.
Regardleess of semaphore submission the context will still be flushed. It should be
emphasized that a return value of GrSemaphoresSubmitted::kNo does not mean the flush did not
happen. It simply means there were no semaphores submitted to the GPU. A caller should only
take this as a failure if they passed in semaphores to be submitted.
Pending surface commands are flushed regardless of the return result.

View File

@ -296,7 +296,6 @@ public:
///////////////////////////////////////////////////////////////////////////
// Misc.
/**
* Inserts a list of GPU semaphores that the current GPU-backed API must wait on before
* executing any more commands on the GPU. Skia will take ownership of the underlying semaphores
@ -307,20 +306,35 @@ public:
bool wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores);
/**
* Call to ensure all drawing to the context has been issued to the underlying 3D API.
* Call to ensure all drawing to the context has been flushed and submitted to the underlying 3D
* API. This is equivalent to calling GrContext::flush with a default GrFlushInfo followed by
* GrContext::submit.
*/
void flushAndSubmit() { this->flush(GrFlushInfo(), GrPrepareForExternalIORequests()); }
void flushAndSubmit() {
this->flush(GrFlushInfo(), GrPrepareForExternalIORequests());
this->submit();
}
/**
* Call to ensure all drawing to the context has been issued to the underlying 3D API.
* Call to ensure all drawing to the context has been flushed to underlying 3D API specific
* objects. A call to GrContext::submit is always required to ensure work is actually sent to
* the gpu. Some specific API details:
* GL: Commands are actually sent to the driver, but glFlush is never called. Thus some
* sync objects from the flush will not be valid until a submission occurs.
*
* If the return is GrSemaphoresSubmitted::kYes, only initialized GrBackendSemaphores will have
* been submitted and can be waited on (it is possible Skia failed to create a subset of the
* semaphores). If this call returns GrSemaphoresSubmitted::kNo, the GPU backend will not have
* submitted any semaphores to be signaled on the GPU. Thus the client should not have the GPU
* wait on any of the semaphores passed in with the GrFlushInfo. Regardless of whether
* semaphores were submitted to the GPU or not, the client is still responsible for deleting any
* initialized semaphores.
* Vulkan/Metal/D3D/Dawn: Commands are recorded to the backend APIs corresponding command
* buffer or encoder objects. However, these objects are not sent to the gpu until a
* submission occurs.
*
* If the return is GrSemaphoresSubmitted::kYes, only initialized GrBackendSemaphores will be
* submitted to the gpu during the next submit call (it is possible Skia failed to create a
* subset of the semaphores). The client should not wait on these semaphores until after submit
* has been called, but must keep them alive until then. If a submit flag was passed in with the
* flush these valid semaphores can we waited on immediately. If this call returns
* GrSemaphoresSubmitted::kNo, the GPU backend will not submit any semaphores to be signaled on
* the GPU. Thus the client should not have the GPU wait on any of the semaphores passed in with
* the GrFlushInfo. Regardless of whether semaphores were submitted to the GPU or not, the
* client is still responsible for deleting any initialized semaphores.
* Regardleess of semaphore submission the context will still be flushed. It should be
* emphasized that a return value of GrSemaphoresSubmitted::kNo does not mean the flush did not
* happen. It simply means there were no semaphores submitted to the GPU. A caller should only
@ -331,26 +345,54 @@ public:
}
/**
* Call to ensure all drawing to the context has been issued to the underlying 3D API.
* Call to ensure all drawing to the context has been flushed to underlying 3D API specific
* objects. A call to GrContext::submit is always required to ensure work is actually sent to
* the gpu. Some specific API details:
* GL: Commands are actually sent to the driver, but glFlush is never called. Thus some
* sync objects from the flush will not be valid until submit is called.
*
* If this call returns GrSemaphoresSubmitted::kNo, the GPU backend will not have created or
* added any semaphores to signal on the GPU. Thus the client should not have the GPU wait on
* any of the semaphores passed in with the GrFlushInfo. However, any pending commands to the
* context will still be flushed. It should be emphasized that a return value of
* GrSemaphoresSubmitted::kNo does not mean the flush did not happen. It simply means there were
* no semaphores submitted to the GPU. A caller should only take this as a failure if they
* passed in semaphores to be submitted.
* Vulkan/Metal/D3D/Dawn: Commands are recorded to the backend APIs corresponding command
* buffer or encoder objects. However, these objects are not sent to the gpu until
* submit is called.
*
* Note: The default values for GrFlushInfo will submit the work the gpu.
*
* If the return is GrSemaphoresSubmitted::kYes, only initialized GrBackendSemaphores will be
* submitted to the gpu during the next submit call (it is possible Skia failed to create a
* subset of the semaphores). The client should not wait on these semaphores until after submit
* has been called, but must keep them alive until then. If this call returns
* GrSemaphoresSubmitted::kNo, the GPU backend will not submit any semaphores to be signaled on
* the GPU. Thus the client should not have the GPU wait on any of the semaphores passed in with
* the GrFlushInfo. The client is always responsible for deleting any initialized semaphores.
* Regardleess of semaphore submission the context will still be flushed. It should be
* emphasized that a return value of GrSemaphoresSubmitted::kNo does not mean the flush did not
* happen. It simply means there were no semaphores submitted to the GPU. A caller should only
* take this as a failure if they passed in semaphores to be submitted.
*
* If the GrPrepareForExternalIORequests contains valid gpu backed SkSurfaces or SkImages, Skia
* will put the underlying backend objects into a state that is ready for external uses. See
* declaration of GrPreopareForExternalIORequests for more details.
* declaration of GrPreopareForExternalIORequests for more details. Note that the backend
* objects will not be moved to this state until submit has been called. If subsequent flushes
* are called between this and submit, those objects are no longer guaranteed to be in a state
* that is ready for external use.
*/
GrSemaphoresSubmitted flush(const GrFlushInfo&, const GrPrepareForExternalIORequests&);
/**
* Placeholder no-op submit call.
* Submit outstanding work to the gpu from all previously un-submitted flushes. The return
* value of the submit will indicate whether or not the submission to the GPU was successful.
*
* If the call returns true, all previously passed in semaphores in flush calls will have been
* submitted to the GPU and they can safely be waited on. The caller should wait on those
* semaphores or perform some other global synchronization before deleting the semaphores.
*
* If it returns false, then those same semaphores will not have been submitted and we will not
* try to submit them again. The caller is free to delete the semaphores at any time.
*
* If the syncCpu flag is true this function will return once the gpu has finished with all
* submitted work.
*/
bool submit(bool syncToCpu = false);
bool submit(bool syncCpu = false);
/**
* Checks whether any asynchronous work is complete and if so calls related callbacks.

View File

@ -227,7 +227,7 @@ static const uint32_t kAll_GrBackendState = 0xffffffff;
enum GrFlushFlags {
kNone_GrFlushFlags = 0,
// flush will wait till all submitted GPU work is finished before returning.
// Deprecated: Use syncCpu call on submit instead.
kSyncCpu_GrFlushFlag = 0x1,
};

View File

@ -319,21 +319,26 @@ GrSemaphoresSubmitted GrContext::flush(const GrFlushInfo& info,
return GrSemaphoresSubmitted::kNo;
}
bool submitted = false;
if (this->drawingManager()->flush(nullptr, 0, SkSurface::BackendSurfaceAccess::kNoAccess,
info, externalRequests)) {
bool forceSync = SkToBool(info.fFlags & kSyncCpu_GrFlushFlag);
submitted = this->drawingManager()->submitToGpu(forceSync);
}
bool flushed = this->drawingManager()->flush(
nullptr, 0, SkSurface::BackendSurfaceAccess::kNoAccess, info, externalRequests);
if (!submitted || (!this->priv().caps()->semaphoreSupport() && info.fNumSemaphores)) {
if (!flushed || (!this->priv().caps()->semaphoreSupport() && info.fNumSemaphores)) {
return GrSemaphoresSubmitted::kNo;
}
return GrSemaphoresSubmitted::kYes;
}
bool GrContext::submit(bool syncToCpu) {
return true;
bool GrContext::submit(bool syncCpu) {
ASSERT_SINGLE_OWNER
if (this->abandoned()) {
return false;
}
if (!fGpu) {
return false;
}
return fGpu->submitToGpu(syncCpu);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -570,12 +570,7 @@ GrSemaphoresSubmitted GrDrawingManager::flushSurfaces(GrSurfaceProxy* proxies[],
SkDEBUGCODE(this->validate());
bool submitted = false;
if (didFlush) {
submitted = this->submitToGpu(SkToBool(info.fFlags & kSyncCpu_GrFlushFlag));
}
if (!submitted || (!direct->priv().caps()->semaphoreSupport() && info.fNumSemaphores)) {
if (!didFlush || (!direct->priv().caps()->semaphoreSupport() && info.fNumSemaphores)) {
return GrSemaphoresSubmitted::kNo;
}
return GrSemaphoresSubmitted::kYes;

View File

@ -1901,6 +1901,7 @@ void GrRenderTargetContext::asyncReadPixels(const SkIRect& rect, SkColorType col
flushInfo.fFinishedContext = finishContext;
flushInfo.fFinishedProc = finishCallback;
this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo);
directContext->submit();
}
void GrRenderTargetContext::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace,
@ -2153,6 +2154,7 @@ void GrRenderTargetContext::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvC
flushInfo.fFinishedContext = finishContext;
flushInfo.fFinishedProc = finishCallback;
this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo);
direct->submit();
}
GrSemaphoresSubmitted GrRenderTargetContext::flush(SkSurface::BackendSurfaceAccess access,

View File

@ -275,7 +275,7 @@ bool GrSurfaceContext::readPixels(const GrImageInfo& origDstInfo, void* dst, siz
}
direct->priv().flushSurface(srcProxy);
direct->submit();
if (!direct->priv().getGpu()->readPixels(srcSurface, pt.fX, pt.fY, dstInfo.width(),
dstInfo.height(), this->colorInfo().colorType(),
supportedRead.fColorType, readDst, readRB)) {

View File

@ -1061,6 +1061,7 @@ void SkGpuDevice::drawDrawable(SkDrawable* drawable, const SkMatrix* matrix, SkC
void SkGpuDevice::flush() {
this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, GrFlushInfo());
this->context()->submit();
}
GrSemaphoresSubmitted SkGpuDevice::flush(SkSurface::BackendSurfaceAccess access,

View File

@ -160,7 +160,10 @@ GrSemaphoresSubmitted SkImage::flush(GrContext* context, const GrFlushInfo& flus
return as_IB(this)->onFlush(context, flushInfo);
}
void SkImage::flushAndSubmit(GrContext* context) { this->flush(context, {}); }
void SkImage::flushAndSubmit(GrContext* context) {
this->flush(context, {});
context->submit();
}
#else

View File

@ -444,10 +444,6 @@ bool SkSurface::replaceBackendTexture(const GrBackendTexture& backendTexture,
releaseContext);
}
void SkSurface::flushAndSubmit() {
this->flush(BackendSurfaceAccess::kNoAccess, GrFlushInfo());
}
GrSemaphoresSubmitted SkSurface::flush(BackendSurfaceAccess access, const GrFlushInfo& flushInfo) {
return asSB(this)->onFlush(access, flushInfo);
}
@ -537,4 +533,8 @@ sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext*,
return nullptr;
}
void SkSurface::flushAndSubmit() {
this->flush(BackendSurfaceAccess::kNoAccess, GrFlushInfo());
}
#endif

View File

@ -732,4 +732,11 @@ sk_sp<SkSurface> SkSurface::MakeFromAHardwareBuffer(GrContext* context,
}
#endif
void SkSurface::flushAndSubmit() {
this->flush(BackendSurfaceAccess::kNoAccess, GrFlushInfo());
if (this->getContext()) {
this->getContext()->submit();
}
}
#endif

View File

@ -1379,55 +1379,55 @@ DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFlush, reporter, ctxInfo) {
// Flush all the setup work we did above and then make little lambda that reports the flush
// count delta since the last time it was called.
c->flushAndSubmit();
auto numFlushes = [c, flushCnt = c->priv().getGpu()->stats()->numSubmitToGpus()]() mutable {
auto numSubmits = [c, submitCnt = c->priv().getGpu()->stats()->numSubmitToGpus()]() mutable {
int curr = c->priv().getGpu()->stats()->numSubmitToGpus();
int n = curr - flushCnt;
flushCnt = curr;
int n = curr - submitCnt;
submitCnt = curr;
return n;
};
// Images aren't used therefore flush is ignored.
// Images aren't used therefore flush is ignored, but submit is still called.
i0->flushAndSubmit(c);
i1->flushAndSubmit(c);
i2->flushAndSubmit(c);
REPORTER_ASSERT(reporter, numFlushes() == 0);
REPORTER_ASSERT(reporter, numSubmits() == 3);
// Syncing forces the flush to happen even if the images aren't used.
GrFlushInfo syncInfo;
syncInfo.fFlags = kSyncCpu_GrFlushFlag;
i0->flush(c, syncInfo);
c->submit(true);
REPORTER_ASSERT(reporter, numFlushes() == 1);
REPORTER_ASSERT(reporter, numSubmits() == 1);
i1->flush(c, syncInfo);
c->submit(true);
REPORTER_ASSERT(reporter, numFlushes() == 1);
REPORTER_ASSERT(reporter, numSubmits() == 1);
i2->flush(c, syncInfo);
c->submit(true);
REPORTER_ASSERT(reporter, numFlushes() == 1);
REPORTER_ASSERT(reporter, numSubmits() == 1);
// Use image 1
s->getCanvas()->drawImage(i1, 0, 0);
// Flushing image 0 should do nothing.
// Flushing image 0 should do nothing, but submit is still called.
i0->flushAndSubmit(c);
REPORTER_ASSERT(reporter, numFlushes() == 0);
REPORTER_ASSERT(reporter, numSubmits() == 1);
// Flushing image 1 should flush.
i1->flushAndSubmit(c);
REPORTER_ASSERT(reporter, numFlushes() == 1);
// Flushing image 2 should do nothing.
REPORTER_ASSERT(reporter, numSubmits() == 1);
// Flushing image 2 should do nothing, but submit is still called.
i2->flushAndSubmit(c);
REPORTER_ASSERT(reporter, numFlushes() == 0);
REPORTER_ASSERT(reporter, numSubmits() == 1);
// Use image 2
s->getCanvas()->drawImage(i2, 0, 0);
// Flushing image 0 should do nothing.
// Flushing image 0 should do nothing, but submit is still called.
i0->flushAndSubmit(c);
REPORTER_ASSERT(reporter, numFlushes() == 0);
// Flushing image 1 do nothing.
REPORTER_ASSERT(reporter, numSubmits() == 1);
// Flushing image 1 do nothing, but submit is still called.
i1->flushAndSubmit(c);
REPORTER_ASSERT(reporter, numFlushes() == 0);
REPORTER_ASSERT(reporter, numSubmits() == 1);
// Flushing image 2 should flush.
i2->flushAndSubmit(c);
REPORTER_ASSERT(reporter, numFlushes() == 1);
REPORTER_ASSERT(reporter, numSubmits() == 1);
// Since we just did a simple image draw it should not have been flattened.
REPORTER_ASSERT(reporter,
!static_cast<SkImage_GpuYUVA*>(as_IB(i2.get()))->testingOnly_IsFlattened());
@ -1439,35 +1439,35 @@ DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFlush, reporter, ctxInfo) {
static_cast<SkImage_GpuYUVA*>(as_IB(i2.get()))->testingOnly_IsFlattened());
REPORTER_ASSERT(reporter, static_cast<SkImage_GpuYUVA*>(as_IB(i2.get()))->isTextureBacked());
s->getCanvas()->drawImage(i2, 0, 0);
// Flushing image 0 should do nothing.
// Flushing image 0 should do nothing, but submit is still called.
i0->flushAndSubmit(c);
REPORTER_ASSERT(reporter, numFlushes() == 0);
// Flushing image 1 do nothing.
REPORTER_ASSERT(reporter, numSubmits() == 1);
// Flushing image 1 do nothing, but submit is still called.
i1->flushAndSubmit(c);
REPORTER_ASSERT(reporter, numFlushes() == 0);
REPORTER_ASSERT(reporter, numSubmits() == 1);
// Flushing image 2 should flush.
i2->flushAndSubmit(c);
REPORTER_ASSERT(reporter, numFlushes() == 1);
REPORTER_ASSERT(reporter, numSubmits() == 1);
// Test case where flatten happens before the first flush.
i2 = make_yuva_image(c);
// On some systems where preferVRAMUseOverFlushes is false (ANGLE on Windows) the above may
// actually flush in order to make textures for the YUV planes. TODO: Remove this when we
// make the YUVA planes from backend textures rather than pixmaps that GrContext must upload.
// Calling numFlushes rebases the flush count from here.
numFlushes();
// Calling numSubmits rebases the flush count from here.
numSubmits();
as_IB(i2.get())->view(c);
REPORTER_ASSERT(reporter,
static_cast<SkImage_GpuYUVA*>(as_IB(i2.get()))->testingOnly_IsFlattened());
REPORTER_ASSERT(reporter, static_cast<SkImage_GpuYUVA*>(as_IB(i2.get()))->isTextureBacked());
s->getCanvas()->drawImage(i2, 0, 0);
// Flushing image 0 should do nothing.
// Flushing image 0 should do nothing, but submit is still called.
i0->flushAndSubmit(c);
REPORTER_ASSERT(reporter, numFlushes() == 0);
// Flushing image 1 do nothing.
REPORTER_ASSERT(reporter, numSubmits() == 1);
// Flushing image 1 do nothing, but submit is still called.
i1->flushAndSubmit(c);
REPORTER_ASSERT(reporter, numFlushes() == 0);
// Flushing image 2 should flush.
REPORTER_ASSERT(reporter, numSubmits() == 1);
// Flushing image 2 should flush, but submit is still called.
i2->flushAndSubmit(c);
REPORTER_ASSERT(reporter, numFlushes() == 1);
REPORTER_ASSERT(reporter, numSubmits() == 1);
}

View File

@ -245,9 +245,10 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(EmptySurfaceSemaphoreTest, reporter, ctxInfo)
GrFlushInfo flushInfo;
flushInfo.fNumSemaphores = 1;
flushInfo.fSignalSemaphores = &semaphore;
GrSemaphoresSubmitted submitted = mainSurface->flush(SkSurface::BackendSurfaceAccess::kNoAccess,
flushInfo);
GrSemaphoresSubmitted submitted =
mainSurface->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo);
REPORTER_ASSERT(reporter, GrSemaphoresSubmitted::kYes == submitted);
ctx->submit();
#ifdef SK_GL
if (GrBackendApi::kOpenGL == ctxInfo.backend()) {