Start removal of tool usage of SkSurface::MakeFromBackendTextureAsRenderTarget.

Adds a new helper that creates a GrBackendRenderTarget using
GrGpu and then wraps it in a SkSurface. Uses the SkSurface
release proc to delete the BERT using GrGpu.

Upgrades GrGpu::createTestingOnlyBackendRenderTarget to create MSAA
buffers.

Updates many tests/tool to call sites to use the helper instead of
SkSurface::MakeFromBackendTextureAsRenderTarget.

Adds syncToCpu bool to SkSurface:: and GrContext::flushAndSubmit.

Bug: skia:9832

Change-Id: I73a8f0ce09dc6523729af0814464c6b6657fda06
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/293683
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
This commit is contained in:
Brian Salomon 2020-10-06 10:07:38 -04:00 committed by Skia Commit-Bot
parent 2e09693964
commit 72c7b98ae3
50 changed files with 754 additions and 459 deletions

View File

@ -1605,6 +1605,8 @@ if (skia_enable_tools) {
deps = []
public_deps = []
sources = [
"tools/gpu/BackendSurfaceFactory.cpp",
"tools/gpu/BackendSurfaceFactory.h",
"tools/gpu/BackendTextureImageFactory.cpp",
"tools/gpu/BackendTextureImageFactory.h",
"tools/gpu/FlushFinishTracker.cpp",

View File

@ -9,6 +9,8 @@ Milestone 88
* <insert new release notes here>
* CPU sync bool added to SkSurface::flushAndSubmit() and GrContext::flushAndSubmit()
* Removed legacy variant of SkImage::MakeFromYUVAPixmaps. Use the version that
takes SkYUVAPixmaps instead. It has a more structured description of the
planar configuration.

View File

@ -51,6 +51,7 @@
#include "tools/DDLTileHelper.h"
#include "tools/Resources.h"
#include "tools/debugger/DebugCanvas.h"
#include "tools/gpu/BackendSurfaceFactory.h"
#include "tools/gpu/MemoryCache.h"
#if defined(SK_BUILD_FOR_WIN)
#include "include/docs/SkXPSDocument.h"
@ -1467,9 +1468,9 @@ Result GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream* dstStream, SkStri
return this->onDraw(src, dst, dstStream, log, fBaseContextOptions);
}
sk_sp<SkSurface> GPUSink::createDstSurface(GrDirectContext* context, SkISize size,
GrBackendTexture* backendTexture,
GrBackendRenderTarget* backendRT) const {
sk_sp<SkSurface> GPUSink::createDstSurface(GrDirectContext* context,
SkISize size,
GrBackendTexture* backendTexture) const {
sk_sp<SkSurface> surface;
SkImageInfo info = SkImageInfo::Make(size, fColorType, fAlphaType, fColorSpace);
@ -1490,14 +1491,13 @@ sk_sp<SkSurface> GPUSink::createDstSurface(GrDirectContext* context, SkISize siz
fColorType, info.refColorSpace(), &props);
break;
case SkCommandLineConfigGpu::SurfType::kBackendRenderTarget:
if (1 == fSampleCount) {
auto colorType = SkColorTypeToGrColorType(info.colorType());
*backendRT = context->priv().getGpu()->createTestingOnlyBackendRenderTarget(
info.width(), info.height(), colorType);
surface = SkSurface::MakeFromBackendRenderTarget(
context, *backendRT, kBottomLeft_GrSurfaceOrigin, info.colorType(),
info.refColorSpace(), &props);
}
surface = MakeBackendRenderTargetSurface(context,
info.dimensions(),
fSampleCount,
kBottomLeft_GrSurfaceOrigin,
info.colorType(),
info.refColorSpace(),
&props);
break;
}
@ -1537,9 +1537,7 @@ Result GPUSink::onDraw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log,
}
GrBackendTexture backendTexture;
GrBackendRenderTarget backendRT;
sk_sp<SkSurface> surface = this->createDstSurface(direct, src.size(),
&backendTexture, &backendRT);
sk_sp<SkSurface> surface = this->createDstSurface(direct, src.size(), &backendTexture);
if (!surface) {
return Result::Fatal("Could not create a surface.");
}
@ -1570,9 +1568,6 @@ Result GPUSink::onDraw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log,
if (backendTexture.isValid()) {
direct->deleteBackendTexture(backendTexture);
}
if (backendRT.isValid()) {
direct->priv().getGpu()->deleteTestingOnlyBackendRenderTarget(backendRT);
}
}
if (grOptions.fPersistentCache) {
direct->storeVkPipelineCacheData();
@ -1749,9 +1744,7 @@ Result GPUOOPRSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* lo
SkASSERT(context->priv().getGpu());
GrBackendTexture backendTexture;
GrBackendRenderTarget backendRT;
sk_sp<SkSurface> surface = this->createDstSurface(context, src.size(),
&backendTexture, &backendRT);
sk_sp<SkSurface> surface = this->createDstSurface(context, src.size(), &backendTexture);
if (!surface) {
return Result::Fatal("Could not create a surface.");
}
@ -1775,9 +1768,6 @@ Result GPUOOPRSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* lo
if (backendTexture.isValid()) {
context->deleteBackendTexture(backendTexture);
}
if (backendRT.isValid()) {
context->priv().getGpu()->deleteTestingOnlyBackendRenderTarget(backendRT);
}
return Result::Ok();
}
@ -1929,9 +1919,7 @@ Result GPUDDLSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log
mainTestCtx->makeCurrent();
GrBackendTexture backendTexture;
GrBackendRenderTarget backendRT;
sk_sp<SkSurface> surface = this->createDstSurface(mainCtx, src.size(),
&backendTexture, &backendRT);
sk_sp<SkSurface> surface = this->createDstSurface(mainCtx, src.size(), &backendTexture);
if (!surface) {
return Result::Fatal("Could not create a surface.");
}
@ -1965,9 +1953,6 @@ Result GPUDDLSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log
if (backendTexture.isValid()) {
mainCtx->deleteBackendTexture(backendTexture);
}
if (backendRT.isValid()) {
mainCtx->priv().getGpu()->deleteTestingOnlyBackendRenderTarget(backendRT);
}
return Result::Ok();
}

View File

@ -407,8 +407,7 @@ public:
}
protected:
sk_sp<SkSurface> createDstSurface(GrDirectContext*, SkISize size, GrBackendTexture*,
GrBackendRenderTarget*) const;
sk_sp<SkSurface> createDstSurface(GrDirectContext*, SkISize size, GrBackendTexture*) const;
bool readBack(SkSurface*, SkBitmap* dst) const;
private:

View File

@ -900,9 +900,9 @@ public:
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. This is equivalent to calling
SkSurface::flush with a default GrFlushInfo followed by GrContext::submit.
SkSurface::flush with a default GrFlushInfo followed by GrContext::submit(syncCpu).
*/
void flushAndSubmit();
void flushAndSubmit(bool syncCpu = false);
enum class BackendSurfaceAccess {
kNoAccess, //!< back-end object will not be used by client

View File

@ -332,11 +332,11 @@ public:
/**
* 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.
* GrContext::submit(syncCpu).
*/
void flushAndSubmit() {
void flushAndSubmit(bool syncCpu = false) {
this->flush(GrFlushInfo());
this->submit();
this->submit(syncCpu);
}
/**

View File

@ -1647,7 +1647,9 @@ EMSCRIPTEN_BINDINGS(Skia) {
class_<SkSurface>("SkSurface")
.smart_ptr<sk_sp<SkSurface>>("sk_sp<SkSurface>")
.function("_flush", select_overload<void()>(&SkSurface::flushAndSubmit))
.function("_flush", optional_override([](SkSurface& self) {
self.flushAndSubmit(false);
}))
.function("getCanvas", &SkSurface::getCanvas, allow_raw_pointers())
.function("imageInfo", optional_override([](SkSurface& self)->SimpleImageInfo {
const auto& ii = self.imageInfo();

View File

@ -666,9 +666,22 @@ public:
/** Check a handle represents an actual texture in the backend API that has not been freed. */
virtual bool isTestingOnlyBackendTexture(const GrBackendTexture&) const = 0;
virtual GrBackendRenderTarget createTestingOnlyBackendRenderTarget(int w, int h,
GrColorType) = 0;
/**
* Creates a GrBackendRenderTarget that can be wrapped using
* SkSurface::MakeFromBackendRenderTarget. Ideally this is a non-textureable allocation to
* differentiate from testing with SkSurface::MakeFromBackendTexture. When sampleCnt > 1 this
* is used to test client wrapped allocations with MSAA where Skia does not allocate a separate
* buffer for resolving. If the color is non-null the backing store should be cleared to the
* passed in color.
*/
virtual GrBackendRenderTarget createTestingOnlyBackendRenderTarget(SkISize,
GrColorType,
int sampleCount = 1) = 0;
/**
* Deletes a GrBackendRenderTarget allocated with the above. Synchronization to make this safe
* is up to the caller.
*/
virtual void deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget&) = 0;
// This is only to be used in GL-specific tests.

View File

@ -207,45 +207,75 @@ bool GrSurfaceContext::readPixels(GrDirectContext* dContext, const GrImageInfo&
}
if (readFlag == GrCaps::SurfaceReadPixelsSupport::kCopyToTexture2D || canvas2DFastPath) {
GrColorType colorType = (canvas2DFastPath || srcIsCompressed)
? GrColorType::kRGBA_8888 : this->colorInfo().colorType();
sk_sp<SkColorSpace> cs = canvas2DFastPath ? nullptr : this->colorInfo().refColorSpace();
std::unique_ptr<GrSurfaceContext> tempCtx;
if (this->asTextureProxy()) {
GrColorType colorType = (canvas2DFastPath || srcIsCompressed)
? GrColorType::kRGBA_8888
: this->colorInfo().colorType();
sk_sp<SkColorSpace> cs = canvas2DFastPath ? nullptr : this->colorInfo().refColorSpace();
auto tempCtx = GrRenderTargetContext::Make(
dContext, colorType, std::move(cs), SkBackingFit::kApprox, dstInfo.dimensions(),
1, GrMipmapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
if (!tempCtx) {
return false;
}
std::unique_ptr<GrFragmentProcessor> fp;
if (canvas2DFastPath) {
fp = dContext->priv().createPMToUPMEffect(
GrTextureEffect::Make(this->readSurfaceView(), this->colorInfo().alphaType()));
if (dstInfo.colorType() == GrColorType::kBGRA_8888) {
fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), GrSwizzle::BGRA());
dstInfo = dstInfo.makeColorType(GrColorType::kRGBA_8888);
tempCtx = GrRenderTargetContext::Make(
dContext, colorType, std::move(cs), SkBackingFit::kApprox, dstInfo.dimensions(),
1, GrMipMapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
if (!tempCtx) {
return false;
}
// The render target context is incorrectly tagged as kPremul even though we're writing
// unpremul data thanks to the PMToUPM effect. Fake out the dst alpha type so we don't
// double unpremul.
dstInfo = dstInfo.makeAlphaType(kPremul_SkAlphaType);
std::unique_ptr<GrFragmentProcessor> fp;
if (canvas2DFastPath) {
fp = dContext->priv().createPMToUPMEffect(GrTextureEffect::Make(
this->readSurfaceView(), this->colorInfo().alphaType()));
if (dstInfo.colorType() == GrColorType::kBGRA_8888) {
fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), GrSwizzle::BGRA());
dstInfo = dstInfo.makeColorType(GrColorType::kRGBA_8888);
}
// The render target context is incorrectly tagged as kPremul even though we're
// writing unpremul data thanks to the PMToUPM effect. Fake out the dst alpha type
// so we don't double unpremul.
dstInfo = dstInfo.makeAlphaType(kPremul_SkAlphaType);
} else {
fp = GrTextureEffect::Make(this->readSurfaceView(), this->colorInfo().alphaType());
}
if (!fp) {
return false;
}
GrPaint paint;
paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
paint.setColorFragmentProcessor(std::move(fp));
tempCtx->asRenderTargetContext()->fillRectToRect(
nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(),
SkRect::MakeWH(dstInfo.width(), dstInfo.height()),
SkRect::MakeXYWH(pt.fX, pt.fY, dstInfo.width(), dstInfo.height()));
pt = {0, 0};
} else {
fp = GrTextureEffect::Make(this->readSurfaceView(), this->colorInfo().alphaType());
auto restrictions = this->caps()->getDstCopyRestrictions(this->asRenderTargetProxy(),
this->colorInfo().colorType());
sk_sp<GrSurfaceProxy> copy;
static constexpr auto kFit = SkBackingFit::kExact;
static constexpr auto kBudgeted = SkBudgeted::kYes;
static constexpr auto kMipMapped = GrMipMapped::kNo;
if (restrictions.fMustCopyWholeSrc) {
copy = GrSurfaceProxy::Copy(fContext, srcProxy, this->origin(), kMipMapped, kFit,
kBudgeted);
} else {
auto srcRect = SkIRect::MakeXYWH(pt.fX, pt.fY, dstInfo.width(), dstInfo.height());
copy = GrSurfaceProxy::Copy(fContext, srcProxy, this->origin(), kMipMapped, srcRect,
kFit, kBudgeted, restrictions.fRectsMustMatch);
pt = {0, 0};
}
if (!copy) {
return false;
}
GrSurfaceProxyView view{std::move(copy), this->origin(), this->readSwizzle()};
tempCtx = GrSurfaceContext::Make(dContext,
std::move(view),
this->colorInfo().colorType(),
this->colorInfo().alphaType(),
this->colorInfo().refColorSpace());
SkASSERT(tempCtx);
}
if (!fp) {
return false;
}
GrPaint paint;
paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
paint.setColorFragmentProcessor(std::move(fp));
tempCtx->asRenderTargetContext()->fillRectToRect(
nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(),
SkRect::MakeWH(dstInfo.width(), dstInfo.height()),
SkRect::MakeXYWH(pt.fX, pt.fY, dstInfo.width(), dstInfo.height()));
return tempCtx->readPixels(dContext, dstInfo, dst, rowBytes, {0, 0});
return tempCtx->readPixels(dContext, dstInfo, dst, rowBytes, pt);
}
bool flip = this->origin() == kBottomLeft_GrSurfaceOrigin;

View File

@ -911,8 +911,14 @@ GrCaps::SurfaceReadPixelsSupport GrD3DCaps::surfaceSupportsReadPixels(
if (GrDxgiFormatIsCompressed(tex->dxgiFormat())) {
return SurfaceReadPixelsSupport::kCopyToTexture2D;
}
return SurfaceReadPixelsSupport::kSupported;
} else if (auto rt = static_cast<const GrD3DRenderTarget*>(surface->asRenderTarget())) {
if (rt->numSamples() > 1) {
return SurfaceReadPixelsSupport::kCopyToTexture2D;
}
return SurfaceReadPixelsSupport::kSupported;
}
return SurfaceReadPixelsSupport::kSupported;
return SurfaceReadPixelsSupport::kUnsupported;
}
bool GrD3DCaps::onSurfaceSupportsWritePixels(const GrSurface* surface) const {

View File

@ -395,8 +395,9 @@ void GrD3DDirectCommandList::clearRenderTargetView(const GrD3DRenderTarget* rend
const D3D12_RECT* rect) {
this->addingWork();
this->addResource(renderTarget->resource());
if (renderTarget->numSamples() > 1) {
this->addResource(renderTarget->msaaTextureResource()->resource());
const GrD3DTextureResource* msaaTextureResource = renderTarget->msaaTextureResource();
if (msaaTextureResource && msaaTextureResource != renderTarget) {
this->addResource(msaaTextureResource->resource());
}
unsigned int numRects = rect ? 1 : 0;
fCommandList->ClearRenderTargetView(renderTarget->colorRenderTargetView(),
@ -416,8 +417,9 @@ void GrD3DDirectCommandList::clearDepthStencilView(const GrD3DStencilAttachment*
void GrD3DDirectCommandList::setRenderTarget(const GrD3DRenderTarget* renderTarget) {
this->addingWork();
this->addResource(renderTarget->resource());
if (renderTarget->numSamples() > 1) {
this->addResource(renderTarget->msaaTextureResource()->resource());
const GrD3DTextureResource* msaaTextureResource = renderTarget->msaaTextureResource();
if (msaaTextureResource && msaaTextureResource != renderTarget) {
this->addResource(msaaTextureResource->resource());
}
D3D12_CPU_DESCRIPTOR_HANDLE rtvDescriptor = renderTarget->colorRenderTargetView();

View File

@ -583,7 +583,7 @@ void GrD3DGpu::resolveTexture(GrSurface* dst, int32_t dstX, int32_t dstY,
void GrD3DGpu::onResolveRenderTarget(GrRenderTarget* target, const SkIRect& resolveRect) {
SkASSERT(target->numSamples() > 1);
GrD3DRenderTarget* rt = static_cast<GrD3DRenderTarget*>(target);
SkASSERT(rt->msaaTextureResource());
SkASSERT(rt->msaaTextureResource() && rt != rt->msaaTextureResource());
this->resolveTexture(target, resolveRect.fLeft, resolveRect.fTop, rt, resolveRect);
}
@ -884,14 +884,6 @@ sk_sp<GrTexture> GrD3DGpu::onWrapRenderableBackendTexture(const GrBackendTexture
}
sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& rt) {
// Currently the Direct3D backend does not support wrapping of msaa render targets directly. In
// general this is not an issue since swapchain images in D3D are never multisampled. Thus if
// you want a multisampled RT it is best to wrap the swapchain images and then let Skia handle
// creating and owning the MSAA images.
if (rt.sampleCnt() > 1) {
return nullptr;
}
GrD3DTextureResourceInfo info;
if (!rt.getD3DTextureResourceInfo(&info)) {
return nullptr;
@ -913,7 +905,7 @@ sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendRenderTarget(const GrBackendRenderT
sk_sp<GrD3DResourceState> state = rt.getGrD3DResourceState();
sk_sp<GrD3DRenderTarget> tgt = GrD3DRenderTarget::MakeWrappedRenderTarget(
this, rt.dimensions(), 1, info, std::move(state));
this, rt.dimensions(), rt.sampleCnt(), info, std::move(state));
// We don't allow the client to supply a premade stencil buffer. We always create one if needed.
SkASSERT(!rt.stencilBits());
@ -993,6 +985,7 @@ bool GrD3DGpu::createTextureResourceForBackendSurface(DXGI_FORMAT dxgiFormat,
GrTexturable texturable,
GrRenderable renderable,
GrMipmapped mipMapped,
int sampleCnt,
GrD3DTextureResourceInfo* info,
GrProtected isProtected) {
SkASSERT(texturable == GrTexturable::kYes || renderable == GrRenderable::kYes);
@ -1028,7 +1021,7 @@ bool GrD3DGpu::createTextureResourceForBackendSurface(DXGI_FORMAT dxgiFormat,
resourceDesc.DepthOrArraySize = 1;
resourceDesc.MipLevels = numMipLevels;
resourceDesc.Format = dxgiFormat;
resourceDesc.SampleDesc.Count = 1;
resourceDesc.SampleDesc.Count = sampleCnt;
resourceDesc.SampleDesc.Quality = DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN;
resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
resourceDesc.Flags = usageFlags;
@ -1082,8 +1075,8 @@ GrBackendTexture GrD3DGpu::onCreateBackendTexture(SkISize dimensions,
GrD3DTextureResourceInfo info;
if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
renderable, mipMapped,
&info, isProtected)) {
renderable, mipMapped, 1, &info,
isProtected)) {
return {};
}
@ -1265,24 +1258,26 @@ bool GrD3DGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
return !(textureResource->GetDesc().Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE);
}
GrBackendRenderTarget GrD3DGpu::createTestingOnlyBackendRenderTarget(int w, int h,
GrColorType colorType) {
GrBackendRenderTarget GrD3DGpu::createTestingOnlyBackendRenderTarget(SkISize dimensions,
GrColorType colorType,
int sampleCnt) {
this->handleDirtyContext();
if (w > this->caps()->maxRenderTargetSize() || h > this->caps()->maxRenderTargetSize()) {
if (dimensions.width() > this->caps()->maxRenderTargetSize() ||
dimensions.height() > this->caps()->maxRenderTargetSize()) {
return {};
}
DXGI_FORMAT dxgiFormat = this->d3dCaps().getFormatFromColorType(colorType);
GrD3DTextureResourceInfo info;
if (!this->createTextureResourceForBackendSurface(dxgiFormat, { w, h }, GrTexturable::kNo,
if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kNo,
GrRenderable::kYes, GrMipmapped::kNo,
&info, GrProtected::kNo)) {
sampleCnt, &info, GrProtected::kNo)) {
return {};
}
return GrBackendRenderTarget(w, h, info);
return GrBackendRenderTarget(dimensions.width(), dimensions.height(), info);
}
void GrD3DGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {

View File

@ -65,7 +65,9 @@ public:
#if GR_TEST_UTILS
bool isTestingOnlyBackendTexture(const GrBackendTexture&) const override;
GrBackendRenderTarget createTestingOnlyBackendRenderTarget(int w, int h, GrColorType) override;
GrBackendRenderTarget createTestingOnlyBackendRenderTarget(SkISize,
GrColorType,
int sampleCnt) override;
void deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget&) override;
void testingOnly_flushGpuAndSync() override;
@ -258,6 +260,7 @@ private:
GrTexturable texturable,
GrRenderable renderable,
GrMipmapped mipMapped,
int sampleCnt,
GrD3DTextureResourceInfo* info,
GrProtected isProtected);

View File

@ -19,7 +19,6 @@
// constructor must be explicitly called.
GrD3DRenderTarget::GrD3DRenderTarget(GrD3DGpu* gpu,
SkISize dimensions,
int sampleCnt,
const GrD3DTextureResourceInfo& info,
sk_sp<GrD3DResourceState> state,
const GrD3DTextureResourceInfo& msaaInfo,
@ -30,12 +29,12 @@ GrD3DRenderTarget::GrD3DRenderTarget(GrD3DGpu* gpu,
: GrSurface(gpu, dimensions, info.fProtected)
, GrD3DTextureResource(info, std::move(state))
// for the moment we only support 1:1 color to stencil
, GrRenderTarget(gpu, dimensions, sampleCnt, info.fProtected)
, GrRenderTarget(gpu, dimensions, msaaInfo.fSampleCount, info.fProtected)
, fMSAATextureResource(new GrD3DTextureResource(msaaInfo, std::move(msaaState)))
, fColorRenderTargetView(colorRenderTargetView)
, fResolveRenderTargetView(resolveRenderTargetView) {
SkASSERT(info.fProtected == msaaInfo.fProtected);
SkASSERT(sampleCnt > 1);
SkASSERT(msaaInfo.fSampleCount > 1);
this->registerWithCacheWrapped(GrWrapCacheable::kNo);
}
@ -43,7 +42,6 @@ GrD3DRenderTarget::GrD3DRenderTarget(GrD3DGpu* gpu,
// constructor must be explicitly called.
GrD3DRenderTarget::GrD3DRenderTarget(GrD3DGpu* gpu,
SkISize dimensions,
int sampleCnt,
const GrD3DTextureResourceInfo& info,
sk_sp<GrD3DResourceState> state,
const GrD3DTextureResourceInfo& msaaInfo,
@ -53,12 +51,12 @@ GrD3DRenderTarget::GrD3DRenderTarget(GrD3DGpu* gpu,
: GrSurface(gpu, dimensions, info.fProtected)
, GrD3DTextureResource(info, std::move(state))
// for the moment we only support 1:1 color to stencil
, GrRenderTarget(gpu, dimensions, sampleCnt, info.fProtected)
, GrRenderTarget(gpu, dimensions, msaaInfo.fSampleCount, info.fProtected)
, fMSAATextureResource(new GrD3DTextureResource(msaaInfo, std::move(msaaState)))
, fColorRenderTargetView(colorRenderTargetView)
, fResolveRenderTargetView(resolveRenderTargetView) {
SkASSERT(info.fProtected == msaaInfo.fProtected);
SkASSERT(sampleCnt > 1);
SkASSERT(msaaInfo.fSampleCount > 1);
}
// We're virtually derived from GrSurface (via GrRenderTarget) so its
@ -71,7 +69,7 @@ GrD3DRenderTarget::GrD3DRenderTarget(GrD3DGpu* gpu,
Wrapped)
: GrSurface(gpu, dimensions, info.fProtected)
, GrD3DTextureResource(info, std::move(state))
, GrRenderTarget(gpu, dimensions, 1, info.fProtected)
, GrRenderTarget(gpu, dimensions, info.fSampleCount, info.fProtected)
, fMSAATextureResource(nullptr)
, fColorRenderTargetView(renderTargetView) {
this->registerWithCacheWrapped(GrWrapCacheable::kNo);
@ -86,7 +84,7 @@ GrD3DRenderTarget::GrD3DRenderTarget(GrD3DGpu* gpu,
const GrD3DDescriptorHeap::CPUHandle& renderTargetView)
: GrSurface(gpu, dimensions, info.fProtected)
, GrD3DTextureResource(info, std::move(state))
, GrRenderTarget(gpu, dimensions, 1, info.fProtected)
, GrRenderTarget(gpu, dimensions, info.fSampleCount, info.fProtected)
, fMSAATextureResource(nullptr)
, fColorRenderTargetView(renderTargetView) {}
@ -94,15 +92,20 @@ sk_sp<GrD3DRenderTarget> GrD3DRenderTarget::MakeWrappedRenderTarget(
GrD3DGpu* gpu, SkISize dimensions, int sampleCnt, const GrD3DTextureResourceInfo& info,
sk_sp<GrD3DResourceState> state) {
SkASSERT(info.fResource.get());
SkASSERT(info.fLevelCount == 1);
SkASSERT(sampleCnt >= 1 && info.fSampleCount >= 1);
SkASSERT(1 == info.fLevelCount);
int wrappedTextureSampleCnt = static_cast<int>(info.fSampleCount);
if (sampleCnt != wrappedTextureSampleCnt && wrappedTextureSampleCnt != 1) {
return nullptr;
}
GrD3DDescriptorHeap::CPUHandle renderTargetView =
gpu->resourceProvider().createRenderTargetView(info.fResource.get());
// create msaa surface if necessary
GrD3DRenderTarget* d3dRT;
if (sampleCnt > 1) {
if (sampleCnt != wrappedTextureSampleCnt) {
GrD3DTextureResourceInfo msInfo;
sk_sp<GrD3DResourceState> msState;
// for wrapped MSAA surface we assume clear to white
@ -113,9 +116,9 @@ sk_sp<GrD3DRenderTarget> GrD3DRenderTarget::MakeWrappedRenderTarget(
GrD3DDescriptorHeap::CPUHandle msaaRenderTargetView =
gpu->resourceProvider().createRenderTargetView(msInfo.fResource.get());
d3dRT = new GrD3DRenderTarget(gpu, dimensions, sampleCnt, info, std::move(state), msInfo,
std::move(msState), msaaRenderTargetView,
renderTargetView, kWrapped);
d3dRT = new GrD3DRenderTarget(gpu, dimensions, info, std::move(state), msInfo,
std::move(msState), msaaRenderTargetView, renderTargetView,
kWrapped);
} else {
d3dRT = new GrD3DRenderTarget(gpu, dimensions, info, std::move(state), renderTargetView,
kWrapped);
@ -129,6 +132,23 @@ GrD3DRenderTarget::~GrD3DRenderTarget() {
SkASSERT(!fMSAATextureResource);
}
const GrD3DTextureResource* GrD3DRenderTarget::msaaTextureResource() const {
if (this->numSamples() == 1) {
SkASSERT(!fMSAATextureResource);
return nullptr;
}
if (fMSAATextureResource) {
return fMSAATextureResource.get();
}
SkASSERT(!fMSAATextureResource);
return this;
}
GrD3DTextureResource* GrD3DRenderTarget::msaaTextureResource() {
auto* constThis = const_cast<const GrD3DRenderTarget*>(this);
return const_cast<GrD3DTextureResource*>(constThis->msaaTextureResource());
}
void GrD3DRenderTarget::releaseInternalObjects() {
GrD3DGpu* gpu = this->getD3DGpu();

View File

@ -31,7 +31,13 @@ public:
GrBackendFormat backendFormat() const override { return this->getBackendFormat(); }
GrD3DTextureResource* msaaTextureResource() const { return fMSAATextureResource.get(); }
/**
* If this render target is multisampled, this returns the MSAA texture for rendering. This
* will be different than *this* when we have separate render/resolve images. If not
* multisampled returns nullptr.
*/
const GrD3DTextureResource* msaaTextureResource() const;
GrD3DTextureResource* msaaTextureResource();
bool canAttemptStencilAttachment() const override {
return true;
@ -51,7 +57,6 @@ public:
protected:
GrD3DRenderTarget(GrD3DGpu* gpu,
SkISize dimensions,
int sampleCnt,
const GrD3DTextureResourceInfo& info,
sk_sp<GrD3DResourceState> state,
const GrD3DTextureResourceInfo& msaaInfo,
@ -84,7 +89,6 @@ private:
enum Wrapped { kWrapped };
GrD3DRenderTarget(GrD3DGpu* gpu,
SkISize dimensions,
int sampleCnt,
const GrD3DTextureResourceInfo& info,
sk_sp<GrD3DResourceState> state,
const GrD3DTextureResourceInfo& msaaInfo,

View File

@ -11,64 +11,88 @@
#include "src/gpu/d3d/GrD3DGpu.h"
GrD3DTextureRenderTarget::GrD3DTextureRenderTarget(
GrD3DGpu* gpu, SkBudgeted budgeted, SkISize dimensions, int sampleCnt,
const GrD3DTextureResourceInfo& info, sk_sp<GrD3DResourceState> state,
GrD3DGpu* gpu,
SkBudgeted budgeted,
SkISize dimensions,
const GrD3DTextureResourceInfo& info,
sk_sp<GrD3DResourceState> state,
const GrD3DDescriptorHeap::CPUHandle& shaderResourceView,
const GrD3DTextureResourceInfo& msaaInfo, sk_sp<GrD3DResourceState> msaaState,
const GrD3DTextureResourceInfo& msaaInfo,
sk_sp<GrD3DResourceState> msaaState,
const GrD3DDescriptorHeap::CPUHandle& colorRenderTargetView,
const GrD3DDescriptorHeap::CPUHandle& resolveRenderTargetView,
GrMipmapStatus mipmapStatus)
: GrSurface(gpu, dimensions, info.fProtected)
, GrD3DTextureResource(info, state)
, GrD3DTexture(gpu, dimensions, info, state, shaderResourceView, mipmapStatus)
, GrD3DRenderTarget(gpu, dimensions, sampleCnt, info, state, msaaInfo,
std::move(msaaState), colorRenderTargetView, resolveRenderTargetView) {
: GrSurface(gpu, dimensions, info.fProtected)
, GrD3DTextureResource(info, state)
, GrD3DTexture(gpu, dimensions, info, state, shaderResourceView, mipmapStatus)
, GrD3DRenderTarget(gpu,
dimensions,
info,
state,
msaaInfo,
std::move(msaaState),
colorRenderTargetView,
resolveRenderTargetView) {
SkASSERT(info.fProtected == msaaInfo.fProtected);
this->registerWithCache(budgeted);
}
GrD3DTextureRenderTarget::GrD3DTextureRenderTarget(
GrD3DGpu* gpu, SkBudgeted budgeted, SkISize dimensions,
const GrD3DTextureResourceInfo& info, sk_sp<GrD3DResourceState> state,
GrD3DGpu* gpu,
SkBudgeted budgeted,
SkISize dimensions,
const GrD3DTextureResourceInfo& info,
sk_sp<GrD3DResourceState> state,
const GrD3DDescriptorHeap::CPUHandle& shaderResourceView,
const GrD3DDescriptorHeap::CPUHandle& renderTargetView,
GrMipmapStatus mipmapStatus)
: GrSurface(gpu, dimensions, info.fProtected)
, GrD3DTextureResource(info, state)
, GrD3DTexture(gpu, dimensions, info, state, shaderResourceView, mipmapStatus)
, GrD3DRenderTarget(gpu, dimensions, info, state, renderTargetView) {
: GrSurface(gpu, dimensions, info.fProtected)
, GrD3DTextureResource(info, state)
, GrD3DTexture(gpu, dimensions, info, state, shaderResourceView, mipmapStatus)
, GrD3DRenderTarget(gpu, dimensions, info, state, renderTargetView) {
this->registerWithCache(budgeted);
}
GrD3DTextureRenderTarget::GrD3DTextureRenderTarget(
GrD3DGpu* gpu, SkISize dimensions, int sampleCnt,
const GrD3DTextureResourceInfo& info, sk_sp<GrD3DResourceState> state,
GrD3DGpu* gpu,
SkISize dimensions,
const GrD3DTextureResourceInfo& info,
sk_sp<GrD3DResourceState> state,
const GrD3DDescriptorHeap::CPUHandle& shaderResourceView,
const GrD3DTextureResourceInfo& msaaInfo, sk_sp<GrD3DResourceState> msaaState,
const GrD3DTextureResourceInfo& msaaInfo,
sk_sp<GrD3DResourceState> msaaState,
const GrD3DDescriptorHeap::CPUHandle& colorRenderTargetView,
const GrD3DDescriptorHeap::CPUHandle& resolveRenderTargetView,
GrMipmapStatus mipmapStatus,
GrWrapCacheable cacheable)
: GrSurface(gpu, dimensions, info.fProtected)
, GrD3DTextureResource(info, state)
, GrD3DTexture(gpu, dimensions, info, state, shaderResourceView, mipmapStatus)
, GrD3DRenderTarget(gpu, dimensions, sampleCnt, info, state, msaaInfo,
std::move(msaaState), colorRenderTargetView, resolveRenderTargetView) {
: GrSurface(gpu, dimensions, info.fProtected)
, GrD3DTextureResource(info, state)
, GrD3DTexture(gpu, dimensions, info, state, shaderResourceView, mipmapStatus)
, GrD3DRenderTarget(gpu,
dimensions,
info,
state,
msaaInfo,
std::move(msaaState),
colorRenderTargetView,
resolveRenderTargetView) {
SkASSERT(info.fProtected == msaaInfo.fProtected);
this->registerWithCacheWrapped(cacheable);
}
GrD3DTextureRenderTarget::GrD3DTextureRenderTarget(
GrD3DGpu* gpu, SkISize dimensions,
const GrD3DTextureResourceInfo& info, sk_sp<GrD3DResourceState> state,
GrD3DGpu* gpu,
SkISize dimensions,
const GrD3DTextureResourceInfo& info,
sk_sp<GrD3DResourceState> state,
const GrD3DDescriptorHeap::CPUHandle& shaderResourceView,
const GrD3DDescriptorHeap::CPUHandle& renderTargetView,
GrMipmapStatus mipmapStatus,
GrWrapCacheable cacheable)
: GrSurface(gpu, dimensions, info.fProtected)
, GrD3DTextureResource(info, state)
, GrD3DTexture(gpu, dimensions, info, state, shaderResourceView, mipmapStatus)
, GrD3DRenderTarget(gpu, dimensions, info, state, renderTargetView) {
: GrSurface(gpu, dimensions, info.fProtected)
, GrD3DTextureResource(info, state)
, GrD3DTexture(gpu, dimensions, info, state, shaderResourceView, mipmapStatus)
, GrD3DRenderTarget(gpu, dimensions, info, state, renderTargetView) {
this->registerWithCacheWrapped(cacheable);
}
@ -117,8 +141,8 @@ sk_sp<GrD3DTextureRenderTarget> GrD3DTextureRenderTarget::MakeNewTextureRenderTa
gpu->resourceProvider().createRenderTargetView(msInfo.fResource.get());
GrD3DTextureRenderTarget* trt = new GrD3DTextureRenderTarget(
gpu, budgeted, dimensions, sampleCnt, info, std::move(state), shaderResourceView,
msInfo, std::move(msState), msaaRenderTargetView, renderTargetView, mipmapStatus);
gpu, budgeted, dimensions, info, std::move(state), shaderResourceView, msInfo,
std::move(msState), msaaRenderTargetView, renderTargetView, mipmapStatus);
return sk_sp<GrD3DTextureRenderTarget>(trt);
} else {
GrD3DTextureRenderTarget* trt = new GrD3DTextureRenderTarget(
@ -161,8 +185,8 @@ sk_sp<GrD3DTextureRenderTarget> GrD3DTextureRenderTarget::MakeWrappedTextureRend
gpu->resourceProvider().createRenderTargetView(msInfo.fResource.get());
GrD3DTextureRenderTarget* trt = new GrD3DTextureRenderTarget(
gpu, dimensions, sampleCnt, info, std::move(state), shaderResourceView,
msInfo, std::move(msState), msaaRenderTargetView, renderTargetView, mipmapStatus,
gpu, dimensions, info, std::move(state), shaderResourceView, msInfo,
std::move(msState), msaaRenderTargetView, renderTargetView, mipmapStatus,
cacheable);
return sk_sp<GrD3DTextureRenderTarget>(trt);
} else {

View File

@ -56,7 +56,6 @@ private:
GrD3DTextureRenderTarget(GrD3DGpu* gpu,
SkBudgeted budgeted,
SkISize dimensions,
int sampleCnt,
const GrD3DTextureResourceInfo& info,
sk_sp<GrD3DResourceState> state,
const GrD3DDescriptorHeap::CPUHandle& shaderResourceView,
@ -79,7 +78,6 @@ private:
// MSAA, wrapped
GrD3DTextureRenderTarget(GrD3DGpu* gpu,
SkISize dimensions,
int sampleCnt,
const GrD3DTextureResourceInfo& info,
sk_sp<GrD3DResourceState> state,
const GrD3DDescriptorHeap::CPUHandle& shaderResourceView,

View File

@ -52,6 +52,7 @@ bool GrD3DTextureResource::InitTextureResourceInfo(GrD3DGpu* gpu, const D3D12_RE
info->fResourceState = initialState;
info->fFormat = desc.Format;
info->fLevelCount = desc.MipLevels;
info->fSampleCount = desc.SampleDesc.Count;
info->fSampleQualityPattern = desc.SampleDesc.Quality;
info->fProtected = isProtected;

View File

@ -431,15 +431,22 @@ bool GrDawnGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
return info.fTexture.Get();
}
GrBackendRenderTarget GrDawnGpu::createTestingOnlyBackendRenderTarget(int width, int height,
GrColorType colorType) {
if (width > this->caps()->maxTextureSize() || height > this->caps()->maxTextureSize()) {
return GrBackendRenderTarget();
GrBackendRenderTarget GrDawnGpu::createTestingOnlyBackendRenderTarget(SkISize dimensions,
GrColorType colorType,
int sampleCnt) {
if (dimensions.width() > this->caps()->maxTextureSize() ||
dimensions.height() > this->caps()->maxTextureSize()) {
return {};
}
// We don't support MSAA in this backend yet.
if (sampleCnt != 1) {
return {};
}
wgpu::TextureFormat format;
if (!GrColorTypeToDawnFormat(colorType, &format)) {
return GrBackendRenderTarget();
return {};
}
wgpu::TextureDescriptor desc;
@ -447,8 +454,8 @@ GrBackendRenderTarget GrDawnGpu::createTestingOnlyBackendRenderTarget(int width,
wgpu::TextureUsage::CopySrc |
wgpu::TextureUsage::OutputAttachment;
desc.size.width = width;
desc.size.height = height;
desc.size.width = dimensions.width();
desc.size.height = dimensions.height();
desc.size.depth = 1;
desc.format = format;
@ -458,7 +465,8 @@ GrBackendRenderTarget GrDawnGpu::createTestingOnlyBackendRenderTarget(int width,
info.fTextureView = tex.CreateView();
info.fFormat = desc.format;
info.fLevelCount = desc.mipLevelCount;
return GrBackendRenderTarget(width, height, 1, 0, info);
return GrBackendRenderTarget(dimensions.width(), dimensions.height(), 1, 0, info);
}
void GrDawnGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {

View File

@ -53,7 +53,9 @@ public:
#if GR_TEST_UTILS
bool isTestingOnlyBackendTexture(const GrBackendTexture&) const override;
GrBackendRenderTarget createTestingOnlyBackendRenderTarget(int w, int h, GrColorType) override;
GrBackendRenderTarget createTestingOnlyBackendRenderTarget(SkISize,
GrColorType,
int sampleCnt) override;
void deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget&) override;
void testingOnly_flushGpuAndSync() override;

View File

@ -1805,13 +1805,10 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
// requires the src and dst be bindable to FBOs. However, we can't do this in the current
// world since some devices (e.g. chromium & angle) require the formats in glBlitFramebuffer
// to match. We don't have a way to really check this during resolve since we only actually
// have GrBackendFormat that is shared by the GrGLRenderTarget.
// have GrBackendFormat that is shared by the GrGLRenderTarget. We always set the
// renderbuffer format to RGBA8 but disable MSAA unless we have the APPLE extension.
// Once we break those up into different surface we can revisit doing this change.
if (ctxInfo.hasExtension("GL_APPLE_texture_format_BGRA8888")) {
info.fInternalFormatForRenderbuffer = GR_GL_RGBA8;
} else {
info.fInternalFormatForRenderbuffer = GR_GL_BGRA8;
}
info.fInternalFormatForRenderbuffer = GR_GL_RGBA8;
info.fDefaultExternalFormat = GR_GL_BGRA;
info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
@ -4086,6 +4083,12 @@ GrCaps::SurfaceReadPixelsSupport GrGLCaps::surfaceSupportsReadPixels(
if (tex->target() == GR_GL_TEXTURE_EXTERNAL || GrGLFormatIsCompressed(tex->format())) {
return SurfaceReadPixelsSupport::kCopyToTexture2D;
}
} else if (auto rt = static_cast<const GrGLRenderTarget*>(surface->asRenderTarget())) {
// glReadPixels does not allow reading back from a MSAA framebuffer. If the underlying
// GrSurface doesn't have a second FBO to resolve to then we must make a copy.
if (rt->numSamples() > 1 && rt->textureFBOID() == GrGLRenderTarget::kUnresolvableFBOID) {
return SurfaceReadPixelsSupport::kCopyToTexture2D;
}
}
return SurfaceReadPixelsSupport::kSupported;
}

View File

@ -3702,24 +3702,46 @@ bool GrGLGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
return (GR_GL_TRUE == result);
}
GrBackendRenderTarget GrGLGpu::createTestingOnlyBackendRenderTarget(int w, int h,
GrColorType colorType) {
if (w > this->caps()->maxRenderTargetSize() || h > this->caps()->maxRenderTargetSize()) {
return GrBackendRenderTarget(); // invalid
GrBackendRenderTarget GrGLGpu::createTestingOnlyBackendRenderTarget(SkISize dimensions,
GrColorType colorType,
int sampleCnt) {
if (dimensions.width() > this->caps()->maxRenderTargetSize() ||
dimensions.height() > this->caps()->maxRenderTargetSize()) {
return {};
}
this->handleDirtyContext();
auto format = this->glCaps().getFormatFromColorType(colorType);
if (!this->glCaps().isFormatRenderable(format, 1)) {
sampleCnt = this->glCaps().getRenderTargetSampleCount(sampleCnt, format);
if (!sampleCnt) {
return {};
}
bool useTexture = format == GrGLFormat::kBGRA8;
// We make a texture instead of a render target if we're using a
// "multisampled_render_to_texture" style extension or have a BGRA format that
// is allowed for textures but not render buffer internal formats.
bool useTexture = false;
if (sampleCnt > 1 && !this->glCaps().usesMSAARenderBuffers()) {
useTexture = true;
} else if (format == GrGLFormat::kBGRA8 &&
this->glCaps().getRenderbufferInternalFormat(GrGLFormat::kBGRA8) != GR_GL_BGRA8) {
// We have a BGRA extension that doesn't support BGRA render buffers. We can use a texture
// unless we've been asked for MSAA. Note we already checked above for render-to-
// multisampled-texture style extensions.
if (sampleCnt > 1) {
return {};
}
useTexture = true;
}
int sFormatIdx = this->getCompatibleStencilIndex(format);
if (sFormatIdx < 0) {
return {};
}
GrGLuint colorID = 0;
GrGLuint stencilID = 0;
auto deleteIDs = [&] {
GrGLFramebufferInfo info;
info.fFBOID = 0;
info.fFormat = GrGLFormatToEnum(format);
auto deleteIDs = [&](bool saveFBO = false) {
if (colorID) {
if (useTexture) {
GL_CALL(DeleteTextures(1, &colorID));
@ -3730,6 +3752,9 @@ GrBackendRenderTarget GrGLGpu::createTestingOnlyBackendRenderTarget(int w, int h
if (stencilID) {
GL_CALL(DeleteRenderbuffers(1, &stencilID));
}
if (!saveFBO && info.fFBOID) {
this->deleteFramebuffer(info.fFBOID);
}
};
if (useTexture) {
@ -3743,9 +3768,6 @@ GrBackendRenderTarget GrGLGpu::createTestingOnlyBackendRenderTarget(int w, int h
return {};
}
GrGLFramebufferInfo info;
info.fFBOID = 0;
info.fFormat = GrGLFormatToEnum(format);
GL_CALL(GenFramebuffers(1, &info.fFBOID));
if (!info.fFBOID) {
deleteIDs();
@ -3757,24 +3779,47 @@ GrBackendRenderTarget GrGLGpu::createTestingOnlyBackendRenderTarget(int w, int h
this->bindFramebuffer(GR_GL_FRAMEBUFFER, info.fFBOID);
if (useTexture) {
GrGLTextureParameters::SamplerOverriddenState initialState;
colorID = this->createTexture({w, h}, format, GR_GL_TEXTURE_2D, GrRenderable::kYes,
colorID = this->createTexture(dimensions, format, GR_GL_TEXTURE_2D, GrRenderable::kYes,
&initialState, 1);
if (!colorID) {
deleteIDs();
return {};
}
GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0, GR_GL_TEXTURE_2D,
colorID, 0));
if (sampleCnt == 1) {
GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0,
GR_GL_TEXTURE_2D, colorID, 0));
} else {
GL_CALL(FramebufferTexture2DMultisample(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0,
GR_GL_TEXTURE_2D, colorID, 0, sampleCnt));
}
} else {
GrGLenum renderBufferFormat = this->glCaps().getRenderbufferInternalFormat(format);
GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, colorID));
GL_CALL(RenderbufferStorage(GR_GL_RENDERBUFFER, renderBufferFormat, w, h));
if (sampleCnt == 1) {
GL_CALL(RenderbufferStorage(GR_GL_RENDERBUFFER, renderBufferFormat, dimensions.width(),
dimensions.height()));
} else {
if (!this->renderbufferStorageMSAA(this->glContext(), sampleCnt, renderBufferFormat,
dimensions.width(), dimensions.height())) {
deleteIDs();
return {};
}
}
GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0,
GR_GL_RENDERBUFFER, colorID));
}
GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, stencilID));
auto stencilBufferFormat = this->glCaps().stencilFormats()[sFormatIdx].fInternalFormat;
GL_CALL(RenderbufferStorage(GR_GL_RENDERBUFFER, stencilBufferFormat, w, h));
if (sampleCnt == 1) {
GL_CALL(RenderbufferStorage(GR_GL_RENDERBUFFER, stencilBufferFormat, dimensions.width(),
dimensions.height()));
} else {
if (!this->renderbufferStorageMSAA(this->glContext(), sampleCnt, stencilBufferFormat,
dimensions.width(), dimensions.height())) {
deleteIDs();
return {};
}
}
GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_STENCIL_ATTACHMENT, GR_GL_RENDERBUFFER,
stencilID));
if (this->glCaps().stencilFormats()[sFormatIdx].fPacked) {
@ -3787,7 +3832,7 @@ GrBackendRenderTarget GrGLGpu::createTestingOnlyBackendRenderTarget(int w, int h
// has the RB attached then deletion is delayed. So we unbind the FBO here and delete the
// renderbuffers/texture.
this->bindFramebuffer(GR_GL_FRAMEBUFFER, 0);
deleteIDs();
deleteIDs(/* saveFBO = */ true);
this->bindFramebuffer(GR_GL_FRAMEBUFFER, info.fFBOID);
GrGLenum status;
@ -3796,9 +3841,11 @@ GrBackendRenderTarget GrGLGpu::createTestingOnlyBackendRenderTarget(int w, int h
this->deleteFramebuffer(info.fFBOID);
return {};
}
auto stencilBits = SkToInt(this->glCaps().stencilFormats()[sFormatIdx].fStencilBits);
GrBackendRenderTarget beRT = GrBackendRenderTarget(w, h, 1, stencilBits, info);
GrBackendRenderTarget beRT = GrBackendRenderTarget(dimensions.width(), dimensions.height(),
sampleCnt, stencilBits, info);
SkASSERT(this->caps()->areColorTypeAndFormatCompatible(colorType, beRT.getBackendFormat()));
return beRT;
}

View File

@ -144,7 +144,9 @@ public:
#if GR_TEST_UTILS
bool isTestingOnlyBackendTexture(const GrBackendTexture&) const override;
GrBackendRenderTarget createTestingOnlyBackendRenderTarget(int w, int h, GrColorType) override;
GrBackendRenderTarget createTestingOnlyBackendRenderTarget(SkISize,
GrColorType,
int sampleCnt) override;
void deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget&) override;
const GrGLContext* glContextForTesting() const override { return &this->glContext(); }

View File

@ -334,12 +334,13 @@ bool GrMockGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
return fOutstandingTestingOnlyTextureIDs.contains(info.id());
}
GrBackendRenderTarget GrMockGpu::createTestingOnlyBackendRenderTarget(int w, int h,
GrColorType colorType) {
GrBackendRenderTarget GrMockGpu::createTestingOnlyBackendRenderTarget(SkISize dimensions,
GrColorType colorType,
int sampleCnt) {
GrMockRenderTargetInfo info(colorType, NextExternalRenderTargetID());
static constexpr int kSampleCnt = 1;
static constexpr int kStencilBits = 8;
return GrBackendRenderTarget(w, h, kSampleCnt, kStencilBits, info);
return GrBackendRenderTarget(dimensions.width(), dimensions.height(), sampleCnt, kStencilBits,
info);
}
void GrMockGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget&) {}

View File

@ -177,7 +177,9 @@ private:
#if GR_TEST_UTILS
bool isTestingOnlyBackendTexture(const GrBackendTexture&) const override;
GrBackendRenderTarget createTestingOnlyBackendRenderTarget(int w, int h, GrColorType) override;
GrBackendRenderTarget createTestingOnlyBackendRenderTarget(SkISize dimensions,
GrColorType,
int sampleCnt) override;
void deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget&) override;
void testingOnly_flushGpuAndSync() override {}

View File

@ -48,9 +48,10 @@ public:
const GrBackendFormat& surfaceFormat,
GrColorType srcColorType) const override;
SurfaceReadPixelsSupport surfaceSupportsReadPixels(const GrSurface*) const override {
return SurfaceReadPixelsSupport::kSupported;
}
SurfaceReadPixelsSupport surfaceSupportsReadPixels(const GrSurface*) const override;
DstCopyRestrictions getDstCopyRestrictions(const GrRenderTargetProxy* src,
GrColorType ct) const override;
/**
* Returns both a supported and most prefered stencil format to use in draws.
@ -59,17 +60,27 @@ public:
return fPreferredStencilFormat;
}
bool canCopyAsBlit(GrSurface* dst, int dstSampleCount, GrSurface* src, int srcSampleCount,
const SkIRect& srcRect, const SkIPoint& dstPoint,
bool areDstSrcSameObj) const;
bool canCopyAsBlit(GrSurface* dst,
GrSurface* src,
const SkIRect& srcRect,
const SkIPoint& dstPoint) const;
bool canCopyAsBlit(MTLPixelFormat dstFormat, int dstSampleCount,
MTLPixelFormat srcFormat, int srcSampleCount,
const SkIRect& srcRect, const SkIPoint& dstPoint,
bool areDstSrcSameObj) const;
bool canCopyAsResolve(GrSurface* dst, int dstSampleCount, GrSurface* src, int srcSampleCount,
const SkIRect& srcRect, const SkIPoint& dstPoint) const;
bool canCopyAsResolve(GrSurface* dst,
GrSurface* src,
const SkIRect& srcRect,
const SkIPoint& dstPoint) const;
bool canCopyAsResolve(MTLPixelFormat dstFormat, int dstSampleCount,
MTLPixelFormat srcFormat, int srcSampleCount,
bool srcIsRenderTarget, const SkISize srcDimensions,
const SkIRect& srcRect,
const SkIPoint& dstPoint,
bool areDstSrcSameObj) const;
GrBackendFormat getBackendFormatFromCompressionType(SkImage::CompressionType) const override;

View File

@ -18,6 +18,7 @@
#include "src/gpu/GrRenderTargetProxy.h"
#include "src/gpu/GrShaderCaps.h"
#include "src/gpu/GrSurfaceProxy.h"
#include "src/gpu/mtl/GrMtlRenderTarget.h"
#include "src/gpu/mtl/GrMtlUtil.h"
#if !__has_feature(objc_arc)
@ -128,10 +129,29 @@ void GrMtlCaps::initFeatureSet(MTLFeatureSet featureSet) {
SK_ABORT("Requested an unsupported feature set");
}
bool GrMtlCaps::canCopyAsBlit(GrSurface* dst, int dstSampleCount,
GrSurface* src, int srcSampleCount,
const SkIRect& srcRect, const SkIPoint& dstPoint,
bool areDstSrcSameObj) const {
static int get_surface_sample_cnt(GrSurface* surf) {
if (const GrRenderTarget* rt = surf->asRenderTarget()) {
return rt->numSamples();
}
return 1;
}
static bool is_resolving_msaa(GrSurface* surf) {
auto rt = static_cast<GrMtlRenderTarget*>(surf->asRenderTarget());
if (rt && rt->mtlResolveTexture()) {
SkASSERT(rt->numSamples() > 1);
return true;
}
return false;
}
bool GrMtlCaps::canCopyAsBlit(GrSurface* dst,
GrSurface* src,
const SkIRect& srcRect,
const SkIPoint& dstPoint) const {
if (is_resolving_msaa(src) || is_resolving_msaa(dst)) {
return false;
}
id<MTLTexture> dstTex = GrGetMTLTextureFromSurface(dst);
id<MTLTexture> srcTex = GrGetMTLTextureFromSurface(src);
if (srcTex.framebufferOnly || dstTex.framebufferOnly) {
@ -140,9 +160,11 @@ bool GrMtlCaps::canCopyAsBlit(GrSurface* dst, int dstSampleCount,
MTLPixelFormat dstFormat = dstTex.pixelFormat;
MTLPixelFormat srcFormat = srcTex.pixelFormat;
int srcSampleCount = get_surface_sample_cnt(src);
int dstSampleCount = get_surface_sample_cnt(dst);
return this->canCopyAsBlit(dstFormat, dstSampleCount, srcFormat, srcSampleCount,
srcRect, dstPoint, areDstSrcSameObj);
return this->canCopyAsBlit(dstFormat, dstSampleCount, srcFormat, srcSampleCount, srcRect,
dstPoint, src == dst);
}
bool GrMtlCaps::canCopyAsBlit(MTLPixelFormat dstFormat, int dstSampleCount,
@ -165,16 +187,35 @@ bool GrMtlCaps::canCopyAsBlit(MTLPixelFormat dstFormat, int dstSampleCount,
return true;
}
bool GrMtlCaps::canCopyAsResolve(GrSurface* dst, int dstSampleCount,
GrSurface* src, int srcSampleCount,
const SkIRect& srcRect, const SkIPoint& dstPoint) const {
if (dst == src) {
bool GrMtlCaps::canCopyAsResolve(GrSurface* dst,
GrSurface* src,
const SkIRect& srcRect,
const SkIPoint& dstPoint) const {
MTLPixelFormat dstFormat = GrBackendFormatAsMTLPixelFormat(dst->backendFormat());
MTLPixelFormat srcFormat = GrBackendFormatAsMTLPixelFormat(src->backendFormat());
int srcSampleCount = get_surface_sample_cnt(src);
int dstSampleCount = get_surface_sample_cnt(dst);
bool srcIsRenderTarget = src->asRenderTarget();
SkISize srcSize = src->dimensions();
return this->canCopyAsResolve(dstFormat, dstSampleCount, srcFormat, srcSampleCount,
srcIsRenderTarget, srcSize, srcRect, dstPoint, src == dst);
}
bool GrMtlCaps::canCopyAsResolve(MTLPixelFormat dstFormat, int dstSampleCount,
MTLPixelFormat srcFormat, int srcSampleCount,
bool srcIsRenderTarget, const SkISize srcDimensions,
const SkIRect& srcRect,
const SkIPoint& dstPoint,
bool areDstSrcSameObj) const {
if (areDstSrcSameObj) {
return false;
}
if (dst->backendFormat() != src->backendFormat()) {
if (dstFormat != srcFormat) {
return false;
}
if (dstSampleCount > 1 || srcSampleCount == 1 || !src->asRenderTarget()) {
if (dstSampleCount > 1 || srcSampleCount == 1 || !srcIsRenderTarget) {
return false;
}
@ -182,7 +223,7 @@ bool GrMtlCaps::canCopyAsResolve(GrSurface* dst, int dstSampleCount,
if (dstPoint != SkIPoint::Make(0, 0)) {
return false;
}
if (srcRect != SkIRect::MakeXYWH(0, 0, src->width(), src->height())) {
if (srcRect != SkIRect::MakeSize(srcDimensions)) {
return false;
}
@ -191,22 +232,30 @@ bool GrMtlCaps::canCopyAsResolve(GrSurface* dst, int dstSampleCount,
bool GrMtlCaps::onCanCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src,
const SkIRect& srcRect, const SkIPoint& dstPoint) const {
int dstSampleCnt = 0;
int srcSampleCnt = 0;
int dstSampleCnt = 1;
int srcSampleCnt = 1;
if (const GrRenderTargetProxy* rtProxy = dst->asRenderTargetProxy()) {
dstSampleCnt = rtProxy->numSamples();
}
if (const GrRenderTargetProxy* rtProxy = src->asRenderTargetProxy()) {
srcSampleCnt = rtProxy->numSamples();
}
SkASSERT((dstSampleCnt > 0) == SkToBool(dst->asRenderTargetProxy()));
SkASSERT((srcSampleCnt > 0) == SkToBool(src->asRenderTargetProxy()));
// TODO: need some way to detect whether the proxy is framebufferOnly
return this->canCopyAsBlit(GrBackendFormatAsMTLPixelFormat(dst->backendFormat()), dstSampleCnt,
GrBackendFormatAsMTLPixelFormat(src->backendFormat()), srcSampleCnt,
srcRect, dstPoint, dst == src);
if (this->canCopyAsBlit(GrBackendFormatAsMTLPixelFormat(dst->backendFormat()), dstSampleCnt,
GrBackendFormatAsMTLPixelFormat(src->backendFormat()), srcSampleCnt,
srcRect, dstPoint, dst == src)) {
return true;
}
bool srcIsRenderTarget = src->asRenderTargetProxy();
MTLPixelFormat dstFormat = GrBackendFormatAsMTLPixelFormat(dst->backendFormat());
MTLPixelFormat srcFormat = GrBackendFormatAsMTLPixelFormat(src->backendFormat());
return this->canCopyAsResolve(dstFormat, dstSampleCnt,
srcFormat, srcSampleCnt,
srcIsRenderTarget, src->backingStoreDimensions(), srcRect,
dstPoint,
dst == src);
}
void GrMtlCaps::initGrCaps(const id<MTLDevice> device) {
@ -853,6 +902,31 @@ bool GrMtlCaps::onSurfaceSupportsWritePixels(const GrSurface* surface) const {
return true;
}
GrCaps::SurfaceReadPixelsSupport GrMtlCaps::surfaceSupportsReadPixels(
const GrSurface* surface) const {
if (auto mtlRT = static_cast<const GrMtlRenderTarget*>(surface->asRenderTarget())) {
if (mtlRT->numSamples() > 1 && !mtlRT->mtlResolveTexture()) {
return SurfaceReadPixelsSupport::kCopyToTexture2D;
}
}
return SurfaceReadPixelsSupport::kSupported;
}
GrCaps::DstCopyRestrictions GrMtlCaps::getDstCopyRestrictions(const GrRenderTargetProxy* src,
GrColorType ct) const {
// If the src is a MSAA RT then the only supported copy action (not considering falling back
// to a draw) is to resolve from the MSAA src to the non-MSAA dst. Currently we only support
// resolving the entire texture to a resolve buffer of the same size.
DstCopyRestrictions restrictions = {};
if (auto rtProxy = src->asRenderTargetProxy()) {
if (rtProxy->numSamples() > 1) {
restrictions.fMustCopyWholeSrc = true;
restrictions.fRectsMustMatch = GrSurfaceProxy::RectsMustMatch::kYes;
}
}
return restrictions;
}
bool GrMtlCaps::onAreColorTypeAndFormatCompatible(GrColorType ct,
const GrBackendFormat& format) const {
MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(format);

View File

@ -65,7 +65,9 @@ public:
#if GR_TEST_UTILS
bool isTestingOnlyBackendTexture(const GrBackendTexture&) const override;
GrBackendRenderTarget createTestingOnlyBackendRenderTarget(int w, int h, GrColorType) override;
GrBackendRenderTarget createTestingOnlyBackendRenderTarget(SkISize,
GrColorType,
int sampleCnt) override;
void deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget&) override;
void testingOnly_flushGpuAndSync() override;
@ -241,6 +243,7 @@ private:
bool createMtlTextureForBackendSurface(MTLPixelFormat,
SkISize dimensions,
int sampleCnt,
GrTexturable,
GrRenderable,
GrMipmapped,

View File

@ -769,10 +769,10 @@ sk_sp<GrTexture> GrMtlGpu::onWrapRenderableBackendTexture(const GrBackendTexture
}
sk_sp<GrRenderTarget> GrMtlGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& backendRT) {
// TODO: Revisit this when the Metal backend is completed. It may support MSAA render targets.
if (backendRT.sampleCnt() > 1) {
if (!this->caps()->isFormatRenderable(backendRT.getBackendFormat(), backendRT.sampleCnt())) {
return nullptr;
}
id<MTLTexture> mtlTexture = get_texture_from_backend(backendRT);
if (!mtlTexture) {
return nullptr;
@ -875,6 +875,7 @@ void copy_src_data(char* dst, size_t bytesPerPixel, const SkTArray<size_t>& indi
bool GrMtlGpu::createMtlTextureForBackendSurface(MTLPixelFormat mtlFormat,
SkISize dimensions,
int sampleCnt,
GrTexturable texturable,
GrRenderable renderable,
GrMipmapped mipMapped,
@ -902,6 +903,10 @@ bool GrMtlGpu::createMtlTextureForBackendSurface(MTLPixelFormat mtlFormat,
desc.usage = texturable == GrTexturable::kYes ? MTLTextureUsageShaderRead : 0;
desc.usage |= renderable == GrRenderable::kYes ? MTLTextureUsageRenderTarget : 0;
}
if (sampleCnt != 1) {
desc.sampleCount = sampleCnt;
desc.textureType = MTLTextureType2DMultisample;
}
id<MTLTexture> testTexture = [fDevice newTextureWithDescriptor: desc];
info->fTexture.reset(GrRetainPtrFromId(testTexture));
return true;
@ -915,7 +920,7 @@ GrBackendTexture GrMtlGpu::onCreateBackendTexture(SkISize dimensions,
const MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(format);
GrMtlTextureInfo info;
if (!this->createMtlTextureForBackendSurface(mtlFormat, dimensions, GrTexturable::kYes,
if (!this->createMtlTextureForBackendSurface(mtlFormat, dimensions, 1, GrTexturable::kYes,
renderable, mipMapped, &info)) {
return {};
}
@ -1056,7 +1061,7 @@ GrBackendTexture GrMtlGpu::onCreateCompressedBackendTexture(
const MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(format);
GrMtlTextureInfo info;
if (!this->createMtlTextureForBackendSurface(mtlFormat, dimensions, GrTexturable::kYes,
if (!this->createMtlTextureForBackendSurface(mtlFormat, dimensions, 1, GrTexturable::kYes,
GrRenderable::kNo, mipMapped, &info)) {
return {};
}
@ -1098,25 +1103,27 @@ bool GrMtlGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
}
}
GrBackendRenderTarget GrMtlGpu::createTestingOnlyBackendRenderTarget(int w, int h, GrColorType ct) {
if (w > this->caps()->maxRenderTargetSize() || h > this->caps()->maxRenderTargetSize()) {
return GrBackendRenderTarget();
}
MTLPixelFormat format = this->mtlCaps().getFormatFromColorType(ct);
if (format == MTLPixelFormatInvalid) {
return GrBackendRenderTarget();
}
GrMtlTextureInfo info;
if (!this->createMtlTextureForBackendSurface(format, {w, h}, GrTexturable::kNo,
GrRenderable::kYes,
GrMipmapped::kNo, &info)) {
GrBackendRenderTarget GrMtlGpu::createTestingOnlyBackendRenderTarget(SkISize dimensions,
GrColorType ct,
int sampleCnt) {
if (dimensions.width() > this->caps()->maxRenderTargetSize() ||
dimensions.height() > this->caps()->maxRenderTargetSize()) {
return {};
}
GrBackendRenderTarget backendRT(w, h, info);
return backendRT;
MTLPixelFormat format = this->mtlCaps().getFormatFromColorType(ct);
sampleCnt = this->mtlCaps().getRenderTargetSampleCount(sampleCnt, format);
if (sampleCnt == 0) {
return {};
}
GrMtlTextureInfo info;
if (!this->createMtlTextureForBackendSurface(format, dimensions, sampleCnt, GrTexturable::kNo,
GrRenderable::kYes, GrMipmapped::kNo, &info)) {
return {};
}
return GrBackendRenderTarget(dimensions.width(), dimensions.height(), info);
}
void GrMtlGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {
@ -1135,13 +1142,6 @@ void GrMtlGpu::testingOnly_flushGpuAndSync() {
}
#endif // GR_TEST_UTILS
static int get_surface_sample_cnt(GrSurface* surf) {
if (const GrRenderTarget* rt = surf->asRenderTarget()) {
return rt->numSamples();
}
return 0;
}
void GrMtlGpu::copySurfaceAsResolve(GrSurface* dst, GrSurface* src) {
// TODO: Add support for subrectangles
GrMtlRenderTarget* srcRT = static_cast<GrMtlRenderTarget*>(src->asRenderTarget());
@ -1161,10 +1161,7 @@ void GrMtlGpu::copySurfaceAsResolve(GrSurface* dst, GrSurface* src) {
void GrMtlGpu::copySurfaceAsBlit(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
const SkIPoint& dstPoint) {
#ifdef SK_DEBUG
int dstSampleCnt = get_surface_sample_cnt(dst);
int srcSampleCnt = get_surface_sample_cnt(src);
SkASSERT(this->mtlCaps().canCopyAsBlit(dst, dstSampleCnt, src, srcSampleCnt,
srcRect, dstPoint, dst == src));
SkASSERT(this->mtlCaps().canCopyAsBlit(dst, src, srcRect, dstPoint));
#endif
id<MTLTexture> dstTex = GrGetMTLTextureFromSurface(dst);
id<MTLTexture> srcTex = GrGetMTLTextureFromSurface(src);
@ -1185,17 +1182,13 @@ bool GrMtlGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcR
const SkIPoint& dstPoint) {
SkASSERT(!src->isProtected() && !dst->isProtected());
int dstSampleCnt = get_surface_sample_cnt(dst);
int srcSampleCnt = get_surface_sample_cnt(src);
bool success = false;
if (this->mtlCaps().canCopyAsResolve(dst, dstSampleCnt, src, srcSampleCnt, srcRect, dstPoint)) {
if (this->mtlCaps().canCopyAsBlit(dst, src, srcRect, dstPoint)) {
this->copySurfaceAsBlit(dst, src, srcRect, dstPoint);
success = true;
} else if (this->mtlCaps().canCopyAsResolve(dst, src, srcRect, dstPoint)) {
this->copySurfaceAsResolve(dst, src);
success = true;
} else if (this->mtlCaps().canCopyAsBlit(dst, dstSampleCnt, src, srcSampleCnt, srcRect,
dstPoint, dst == src)) {
this->copySurfaceAsBlit(dst, src, srcRect, dstPoint);
success = true;
}
if (success) {
SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.x(), dstPoint.y(),

View File

@ -19,6 +19,8 @@ class GrMtlGpu;
class GrMtlRenderTarget: public GrRenderTarget {
public:
// If sampleCnt is greater than 1 and the texture is single sampled, then a MSAA texture
// is created that will resolve to the wrapped single sample texture.
static sk_sp<GrMtlRenderTarget> MakeWrappedRenderTarget(GrMtlGpu*,
SkISize,
int sampleCnt,

View File

@ -71,32 +71,39 @@ sk_sp<GrMtlRenderTarget> GrMtlRenderTarget::MakeWrappedRenderTarget(GrMtlGpu* gp
GrMtlRenderTarget* mtlRT;
if (sampleCnt > 1) {
MTLPixelFormat format = texture.pixelFormat;
if (!gpu->mtlCaps().isFormatRenderable(format, sampleCnt)) {
return nullptr;
}
MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
texDesc.textureType = MTLTextureType2DMultisample;
texDesc.pixelFormat = format;
texDesc.width = dimensions.fWidth;
texDesc.height = dimensions.fHeight;
texDesc.depth = 1;
texDesc.mipmapLevelCount = 1;
texDesc.sampleCount = sampleCnt;
texDesc.arrayLength = 1;
if (@available(macOS 10.11, iOS 9.0, *)) {
texDesc.storageMode = MTLStorageModePrivate;
texDesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget;
}
if ([texture sampleCount] == 1) {
MTLPixelFormat format = texture.pixelFormat;
if (!gpu->mtlCaps().isFormatRenderable(format, sampleCnt)) {
return nullptr;
}
MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
texDesc.textureType = MTLTextureType2DMultisample;
texDesc.pixelFormat = format;
texDesc.width = dimensions.fWidth;
texDesc.height = dimensions.fHeight;
texDesc.depth = 1;
texDesc.mipmapLevelCount = 1;
texDesc.sampleCount = sampleCnt;
texDesc.arrayLength = 1;
if (@available(macOS 10.11, iOS 9.0, *)) {
texDesc.storageMode = MTLStorageModePrivate;
texDesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget;
}
id<MTLTexture> colorTexture = [gpu->device() newTextureWithDescriptor:texDesc];
if (!colorTexture) {
return nullptr;
id<MTLTexture> colorTexture = [gpu->device() newTextureWithDescriptor:texDesc];
if (!colorTexture) {
return nullptr;
}
if (@available(macOS 10.11, iOS 9.0, *)) {
SkASSERT((MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget) &
colorTexture.usage);
}
mtlRT = new GrMtlRenderTarget(
gpu, dimensions, sampleCnt, colorTexture, texture, kWrapped);
} else {
SkASSERT(sampleCnt == static_cast<int>([texture sampleCount]));
mtlRT = new GrMtlRenderTarget(gpu, dimensions, sampleCnt, texture, nil, kWrapped);
}
if (@available(macOS 10.11, iOS 9.0, *)) {
SkASSERT((MTLTextureUsageShaderRead|MTLTextureUsageRenderTarget) & colorTexture.usage);
}
mtlRT = new GrMtlRenderTarget(gpu, dimensions, sampleCnt, colorTexture, texture, kWrapped);
} else {
mtlRT = new GrMtlRenderTarget(gpu, dimensions, texture, kWrapped);
}

View File

@ -212,8 +212,10 @@ id<MTLTexture> GrGetMTLTextureFromSurface(GrSurface* surface) {
GrMtlRenderTarget* renderTarget = static_cast<GrMtlRenderTarget*>(surface->asRenderTarget());
GrMtlTexture* texture;
if (renderTarget) {
// We should not be using this for multisampled rendertargets
if (renderTarget->numSamples() > 1) {
// We should not be using this for multisampled rendertargets with a separate resolve
// texture.
if (renderTarget->mtlResolveTexture()) {
SkASSERT(renderTarget->numSamples() > 1);
SkASSERT(false);
return nil;
}

View File

@ -1489,8 +1489,14 @@ GrCaps::SurfaceReadPixelsSupport GrVkCaps::surfaceSupportsReadPixels(
if (GrVkFormatIsCompressed(tex->imageFormat())) {
return SurfaceReadPixelsSupport::kCopyToTexture2D;
}
return SurfaceReadPixelsSupport::kSupported;
} else if (auto rt = surface->asRenderTarget()) {
if (rt->numSamples() > 1) {
return SurfaceReadPixelsSupport::kCopyToTexture2D;
}
return SurfaceReadPixelsSupport::kSupported;
}
return SurfaceReadPixelsSupport::kSupported;
return SurfaceReadPixelsSupport::kUnsupported;
}
bool GrVkCaps::onSurfaceSupportsWritePixels(const GrSurface* surface) const {

View File

@ -666,6 +666,7 @@ void GrVkGpu::onResolveRenderTarget(GrRenderTarget* target, const SkIRect& resol
SkASSERT(target->numSamples() > 1);
GrVkRenderTarget* rt = static_cast<GrVkRenderTarget*>(target);
SkASSERT(rt->msaaImage());
SkASSERT(rt->colorAttachmentView() && rt->resolveAttachmentView());
this->resolveImage(target, rt, resolveRect,
SkIPoint::Make(resolveRect.x(), resolveRect.y()));
@ -1356,14 +1357,6 @@ sk_sp<GrTexture> GrVkGpu::onWrapRenderableBackendTexture(const GrBackendTexture&
}
sk_sp<GrRenderTarget> GrVkGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& backendRT) {
// Currently the Vulkan backend does not support wrapping of msaa render targets directly. In
// general this is not an issue since swapchain images in vulkan are never multisampled. Thus if
// you want a multisampled RT it is best to wrap the swapchain images and then let Skia handle
// creating and owning the MSAA images.
if (backendRT.sampleCnt() > 1) {
return nullptr;
}
GrVkImageInfo info;
if (!backendRT.getVkImageInfo(&info)) {
return nullptr;
@ -1602,6 +1595,7 @@ bool generate_compressed_data(GrVkGpu* gpu, char* mapPtr,
bool GrVkGpu::createVkImageForBackendSurface(VkFormat vkFormat,
SkISize dimensions,
int sampleCnt,
GrTexturable texturable,
GrRenderable renderable,
GrMipmapped mipMapped,
@ -1617,10 +1611,19 @@ bool GrVkGpu::createVkImageForBackendSurface(VkFormat vkFormat,
return false;
}
if (renderable == GrRenderable::kYes && !fVkCaps->isFormatRenderable(vkFormat, 1)) {
// MSAA images are only currently used by createTestingOnlyBackendRenderTarget.
if (sampleCnt > 1 && (texturable == GrTexturable::kYes || renderable == GrRenderable::kNo)) {
return false;
}
if (renderable == GrRenderable::kYes) {
sampleCnt = fVkCaps->getRenderTargetSampleCount(sampleCnt, vkFormat);
if (!sampleCnt) {
return false;
}
}
int numMipLevels = 1;
if (mipMapped == GrMipmapped::kYes) {
numMipLevels = SkMipmap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
@ -1643,7 +1646,7 @@ bool GrVkGpu::createVkImageForBackendSurface(VkFormat vkFormat,
imageDesc.fWidth = dimensions.width();
imageDesc.fHeight = dimensions.height();
imageDesc.fLevels = numMipLevels;
imageDesc.fSamples = 1;
imageDesc.fSamples = sampleCnt;
imageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
imageDesc.fUsageFlags = usageFlags;
imageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
@ -1777,9 +1780,8 @@ GrBackendTexture GrVkGpu::onCreateBackendTexture(SkISize dimensions,
}
GrVkImageInfo info;
if (!this->createVkImageForBackendSurface(vkFormat, dimensions, GrTexturable::kYes,
renderable, mipMapped,
&info, isProtected)) {
if (!this->createVkImageForBackendSurface(vkFormat, dimensions, 1, GrTexturable::kYes,
renderable, mipMapped, &info, isProtected)) {
return {};
}
@ -2022,23 +2024,25 @@ bool GrVkGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
return false;
}
GrBackendRenderTarget GrVkGpu::createTestingOnlyBackendRenderTarget(int w, int h, GrColorType ct) {
GrBackendRenderTarget GrVkGpu::createTestingOnlyBackendRenderTarget(SkISize dimensions,
GrColorType ct,
int sampleCnt) {
this->handleDirtyContext();
if (w > this->caps()->maxRenderTargetSize() || h > this->caps()->maxRenderTargetSize()) {
return GrBackendRenderTarget();
if (dimensions.width() > this->caps()->maxRenderTargetSize() ||
dimensions.height() > this->caps()->maxRenderTargetSize()) {
return {};
}
VkFormat vkFormat = this->vkCaps().getFormatFromColorType(ct);
GrVkImageInfo info;
if (!this->createVkImageForBackendSurface(vkFormat, {w, h}, GrTexturable::kNo,
GrRenderable::kYes, GrMipmapped::kNo,
&info, GrProtected::kNo)) {
return {};
if (!this->createVkImageForBackendSurface(vkFormat, dimensions, sampleCnt, GrTexturable::kNo,
GrRenderable::kYes, GrMipmapped::kNo, &info,
GrProtected::kNo)) {
return {};
}
return GrBackendRenderTarget(w, h, 1, info);
return GrBackendRenderTarget(dimensions.width(), dimensions.height(), 0, info);
}
void GrVkGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {

View File

@ -94,7 +94,9 @@ public:
#if GR_TEST_UTILS
bool isTestingOnlyBackendTexture(const GrBackendTexture&) const override;
GrBackendRenderTarget createTestingOnlyBackendRenderTarget(int w, int h, GrColorType) override;
GrBackendRenderTarget createTestingOnlyBackendRenderTarget(SkISize,
GrColorType,
int sampleCnt) override;
void deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget&) override;
void testingOnly_flushGpuAndSync() override;
@ -320,6 +322,7 @@ private:
bool createVkImageForBackendSurface(VkFormat,
SkISize dimensions,
int sampleCnt,
GrTexturable,
GrRenderable,
GrMipmapped,

View File

@ -268,6 +268,7 @@ bool GrVkImage::InitImageInfo(GrVkGpu* gpu, const ImageDesc& imageDesc, GrVkImag
info->fImageLayout = initialLayout;
info->fFormat = imageDesc.fFormat;
info->fImageUsageFlags = imageDesc.fUsageFlags;
info->fSampleCount = imageDesc.fSamples;
info->fLevelCount = imageDesc.fLevels;
info->fCurrentQueueFamily = VK_QUEUE_FAMILY_IGNORED;
info->fProtected =

View File

@ -97,7 +97,7 @@ GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
sk_sp<const GrVkImageView> colorAttachmentView)
: GrSurface(gpu, dimensions, info.fProtected)
, GrVkImage(gpu, info, std::move(mutableState), GrBackendObjectOwnership::kBorrowed)
, GrRenderTarget(gpu, dimensions, 1, info.fProtected)
, GrRenderTarget(gpu, dimensions, info.fSampleCount, info.fProtected)
, fColorAttachmentView(std::move(colorAttachmentView))
, fMSAAImage(nullptr)
, fCachedFramebuffers()
@ -117,7 +117,7 @@ GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
GrBackendObjectOwnership ownership)
: GrSurface(gpu, dimensions, info.fProtected)
, GrVkImage(gpu, info, std::move(mutableState), ownership)
, GrRenderTarget(gpu, dimensions, 1, info.fProtected)
, GrRenderTarget(gpu, dimensions, info.fSampleCount, info.fProtected)
, fColorAttachmentView(std::move(colorAttachmentView))
, fMSAAImage(nullptr)
, fCachedFramebuffers()
@ -139,6 +139,7 @@ GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
, fCachedFramebuffers()
, fCachedRenderPasses()
, fSecondaryCommandBuffer(secondaryCommandBuffer) {
SkASSERT(info.fSampleCount == 1);
SkASSERT(fSecondaryCommandBuffer != VK_NULL_HANDLE);
SkASSERT(SkToBool(info.fImageUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT));
this->setFlags(info);
@ -159,8 +160,14 @@ sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeWrappedRenderTarget(
GrVkGpu* gpu, SkISize dimensions, int sampleCnt, const GrVkImageInfo& info,
sk_sp<GrBackendSurfaceMutableStateImpl> mutableState) {
SkASSERT(VK_NULL_HANDLE != info.fImage);
SkASSERT(1 == info.fLevelCount);
SkASSERT(sampleCnt >= 1 && info.fSampleCount >= 1);
int wrappedImageSampleCnt = static_cast<int>(info.fSampleCount);
if (sampleCnt != wrappedImageSampleCnt && wrappedImageSampleCnt != 1) {
return nullptr;
}
VkFormat pixelFormat = info.fFormat;
VkImage colorImage;
@ -169,7 +176,7 @@ sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeWrappedRenderTarget(
GrVkImageInfo msInfo;
sk_sp<GrBackendSurfaceMutableStateImpl> msMutableState;
sk_sp<const GrVkImageView> resolveAttachmentView;
if (sampleCnt > 1) {
if (sampleCnt != wrappedImageSampleCnt) {
GrVkImage::ImageDesc msImageDesc;
msImageDesc.fImageType = VK_IMAGE_TYPE_2D;
msImageDesc.fFormat = pixelFormat;
@ -210,7 +217,7 @@ sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeWrappedRenderTarget(
sk_sp<const GrVkImageView> colorAttachmentView = GrVkImageView::Make(
gpu, colorImage, pixelFormat, GrVkImageView::kColor_Type, 1, GrVkYcbcrConversionInfo());
if (!colorAttachmentView) {
if (sampleCnt > 1) {
if (resolveAttachmentView) {
resolveAttachmentView.reset();
GrVkImage::DestroyImageInfo(gpu, &msInfo);
}
@ -218,7 +225,7 @@ sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeWrappedRenderTarget(
}
GrVkRenderTarget* vkRT;
if (sampleCnt > 1) {
if (resolveAttachmentView) {
vkRT = new GrVkRenderTarget(gpu, dimensions, sampleCnt, info, std::move(mutableState),
msInfo, std::move(msMutableState),
std::move(colorAttachmentView),
@ -531,6 +538,20 @@ GrBackendRenderTarget GrVkRenderTarget::getBackendRenderTarget() const {
return GrBackendRenderTarget(this->width(), this->height(), fInfo, this->getMutableState());
}
GrVkImage* GrVkRenderTarget::msaaImage() {
if (this->numSamples() == 1) {
SkASSERT(fColorAttachmentView && !fResolveAttachmentView);
return nullptr;
}
if (!this->fResolveAttachmentView) {
// In this case *this* object is MSAA (there is not a separate color and resolve buffer)
SkASSERT(!fMSAAImage);
return this;
}
SkASSERT(fMSAAImage);
return fMSAAImage.get();
}
const GrManagedResource* GrVkRenderTarget::stencilImageResource() const {
SkASSERT(!this->wrapsSecondaryCommandBuffer());
const GrStencilAttachment* stencil = this->getStencilAttachment();

View File

@ -47,7 +47,12 @@ public:
}
return nullptr;
}
GrVkImage* msaaImage() { return fMSAAImage.get(); }
/**
* If this render target is multisampled, this returns the MSAA image for rendering. This
* will be different than *this* when we have separate render/resolve images. If not
* multisampled returns nullptr.
*/
GrVkImage* msaaImage();
const GrVkImageView* resolveAttachmentView() const { return fResolveAttachmentView.get(); }
const GrManagedResource* stencilImageResource() const;
const GrVkImageView* stencilAttachmentView() const;
@ -142,7 +147,7 @@ private:
SkISize dimensions,
const GrVkImageInfo& info,
sk_sp<GrBackendSurfaceMutableStateImpl> mutableState,
sk_sp < const GrVkImageView> colorAttachmentView);
sk_sp<const GrVkImageView> colorAttachmentView);
GrVkRenderTarget(GrVkGpu* gpu,
SkISize dimensions,

View File

@ -435,7 +435,7 @@ sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext*,
return nullptr;
}
void SkSurface::flushAndSubmit() {
void SkSurface::flushAndSubmit(bool syncCpu) {
this->flush(BackendSurfaceAccess::kNoAccess, GrFlushInfo());
}

View File

@ -767,12 +767,12 @@ sk_sp<SkSurface> SkSurface::MakeFromAHardwareBuffer(GrContext* context,
}
#endif
void SkSurface::flushAndSubmit() {
void SkSurface::flushAndSubmit(bool syncCpu) {
this->flush(BackendSurfaceAccess::kNoAccess, GrFlushInfo());
auto direct = GrAsDirectContext(this->recordingContext());
if (direct) {
direct->submit();
direct->submit(syncCpu);
}
}

View File

@ -9,7 +9,6 @@
#include "include/core/SkBlendMode.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColor.h"
#include "include/core/SkColorSpace.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkPaint.h"
#include "include/core/SkPoint.h"
@ -17,16 +16,10 @@
#include "include/core/SkRefCnt.h"
#include "include/core/SkSurface.h"
#include "include/core/SkTypes.h"
#include "include/gpu/GrBackendSurface.h"
#include "include/gpu/GrDirectContext.h"
#include "include/gpu/GrTypes.h"
#include "include/private/GrTypesPriv.h"
#include "src/gpu/GrCaps.h"
#include "src/gpu/GrContextPriv.h"
#include "src/gpu/GrResourceProvider.h"
#include "src/gpu/GrTexture.h"
#include "tests/Test.h"
#include "tools/gpu/GrContextFactory.h"
#include "tools/gpu/BackendSurfaceFactory.h"
#include <initializer_list>
#include <vector>
@ -87,32 +80,6 @@ DEF_TEST(Blend_byte_multiply, r) {
for (auto multiply : perfect) { REPORTER_ASSERT(r, test(multiply).diffs == 0); }
}
namespace {
static sk_sp<SkSurface> create_gpu_surface_backend_texture_as_render_target(
GrDirectContext* context, int sampleCnt, SkISize dimensions, SkColorType colorType,
GrSurfaceOrigin origin, sk_sp<GrTexture>* backingSurface) {
auto ct = SkColorTypeToGrColorType(colorType);
auto format = context->priv().caps()->getDefaultBackendFormat(ct, GrRenderable::kYes);
auto resourceProvider = context->priv().resourceProvider();
*backingSurface =
resourceProvider->createTexture(dimensions, format, GrRenderable::kYes, sampleCnt,
GrMipmapped::kNo, SkBudgeted::kNo, GrProtected::kNo);
if (!(*backingSurface)) {
return nullptr;
}
GrBackendTexture backendTex = (*backingSurface)->getBackendTexture();
sk_sp<SkSurface> surface =
SkSurface::MakeFromBackendTextureAsRenderTarget(context, backendTex, origin,
sampleCnt, colorType, nullptr, nullptr);
return surface;
}
} // namespace
// Tests blending to a surface with no texture available.
DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ES2BlendWithNoTexture, reporter, ctxInfo) {
auto context = ctxInfo.directContext();
@ -156,10 +123,9 @@ DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ES2BlendWithNoTexture, reporter, ctxInfo)
SkIPoint inPoint = testCase.fRectAndPoints.inPoint;
GrSurfaceOrigin origin = testCase.fOrigin;
sk_sp<GrTexture> backingSurface;
// BGRA forces a framebuffer blit on ES2.
sk_sp<SkSurface> surface = create_gpu_surface_backend_texture_as_render_target(
context, sampleCnt, kDimensions, kColorType, origin, &backingSurface);
sk_sp<SkSurface> surface =
MakeBackendRenderTargetSurface(context, kDimensions, sampleCnt, origin, kColorType);
if (!surface && sampleCnt > 1) {
// Some platforms don't support MSAA.
@ -194,9 +160,5 @@ DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ES2BlendWithNoTexture, reporter, ctxInfo)
SkColorSetRGB(0xFF, 0xFF, 0x80));
REPORTER_ASSERT(reporter, bitmap.getColor(inPoint.x(), inPoint.y()) ==
SkColorSetRGB(0x80, 0xFF, 0x80));
// Clean up - surface depends on backingSurface and must be released first.
surface.reset();
backingSurface.reset();
}
}

View File

@ -25,8 +25,7 @@ static sk_sp<GrSurfaceProxy> make_wrapped_rt(GrProxyProvider* provider,
skiatest::Reporter* reporter,
const SkISize& size,
GrColorType colorType) {
auto backendRT =
gpu->createTestingOnlyBackendRenderTarget(size.width(), size.height(), colorType);
auto backendRT = gpu->createTestingOnlyBackendRenderTarget(size, colorType);
return provider->wrapBackendRenderTarget(backendRT, nullptr);
}

View File

@ -226,7 +226,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WrappedProxyTest, reporter, ctxInfo) {
// sample counts :(.
if (direct->colorTypeSupportedAsSurface(colorType)) {
GrBackendRenderTarget backendRT = gpu->createTestingOnlyBackendRenderTarget(
kWidthHeight, kWidthHeight, grColorType);
{kWidthHeight, kWidthHeight}, grColorType);
sk_sp<GrSurfaceProxy> sProxy(
proxyProvider->wrapBackendRenderTarget(backendRT, nullptr));
check_surface(reporter, sProxy.get(), kWidthHeight, kWidthHeight, SkBudgeted::kNo);

View File

@ -30,6 +30,7 @@
#include "src/image/SkSurface_Gpu.h"
#include "tests/Test.h"
#include "tests/TestUtils.h"
#include "tools/gpu/BackendSurfaceFactory.h"
#include <functional>
#include <initializer_list>
@ -117,12 +118,6 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrContext_colorTypeSupportedAsSurface, report
REPORTER_ASSERT(reporter, can == SkToBool(surf), "ct: %d, can: %d, surf: %d",
colorType, can, SkToBool(surf));
surf = SkSurface::MakeFromBackendTextureAsRenderTarget(context, backendTex,
kTopLeft_GrSurfaceOrigin, 1,
colorType, nullptr, nullptr);
REPORTER_ASSERT(reporter, can == SkToBool(surf), "ct: %d, can: %d, surf: %d",
colorType, can, SkToBool(surf));
surf.reset();
context->flushAndSubmit();
context->deleteBackendTexture(backendTex);
@ -158,44 +153,38 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GrContext_colorTypeSupportedAsSurface, report
"Should store an allowed sample count (%d vs %d)", allowedCnt,
storedCnt);
}
surf = SkSurface::MakeFromBackendTextureAsRenderTarget(context, backendTex,
kTopLeft_GrSurfaceOrigin,
kSampleCnt, colorType,
nullptr, nullptr);
REPORTER_ASSERT(reporter, can == SkToBool(surf),
"colorTypeSupportedAsSurface:%d, surf:%d, ct:%d", can, SkToBool(surf),
colorType);
if (surf) {
auto rtc = ((SkSurface_Gpu*)(surf.get()))->getDevice()->accessRenderTargetContext();
int storedCnt = rtc->numSamples();
int allowedCnt = context->priv().caps()->getRenderTargetSampleCount(
storedCnt, backendTex.getBackendFormat());
REPORTER_ASSERT(reporter, storedCnt == allowedCnt,
"Should store an allowed sample count (%d vs %d)", allowedCnt,
storedCnt);
}
surf.reset();
context->flushAndSubmit();
context->deleteBackendTexture(backendTex);
}
{
auto* gpu = context->priv().getGpu();
GrBackendRenderTarget backendRenderTarget = gpu->createTestingOnlyBackendRenderTarget(
16, 16, SkColorTypeToGrColorType(colorType));
bool can = context->colorTypeSupportedAsSurface(colorType);
auto surf = SkSurface::MakeFromBackendRenderTarget(context, backendRenderTarget,
kTopLeft_GrSurfaceOrigin, colorType,
nullptr, nullptr);
REPORTER_ASSERT(reporter, can == SkToBool(surf), "ct: %d, can: %d, surf: %d", colorType,
can, SkToBool(surf));
surf.reset();
context->flushAndSubmit();
if (backendRenderTarget.isValid()) {
gpu->deleteTestingOnlyBackendRenderTarget(backendRenderTarget);
for (int sampleCnt : {1, 2}) {
auto surf = MakeBackendRenderTargetSurface(context, {16, 16}, sampleCnt,
kTopLeft_GrSurfaceOrigin, colorType);
bool can = context->colorTypeSupportedAsSurface(colorType) &&
context->maxSurfaceSampleCountForColorType(colorType) >= sampleCnt;
if (!surf && can && colorType == kBGRA_8888_SkColorType && sampleCnt > 1 &&
context->backend() == GrBackendApi::kOpenGL) {
// This is an execeptional case. On iOS GLES we support MSAA BGRA for internally-
// created render targets by using a MSAA RGBA8 renderbuffer that resolves to a
// BGRA8 texture. However, the GL_APPLE_texture_format_BGRA8888 extension does not
// allow creation of BGRA8 renderbuffers and we don't support multisampled textures.
// So this is expected to fail. As of 10/5/2020 it actually seems to work to create
// a MSAA BGRA8 renderbuffer (at least in the simulator) but we don't want to rely
// on this undocumented behavior.
continue;
}
REPORTER_ASSERT(reporter, can == SkToBool(surf), "ct: %d, sc: %d, can: %d, surf: %d",
colorType, sampleCnt, can, SkToBool(surf));
if (surf) {
auto rtc = ((SkSurface_Gpu*)(surf.get()))->getDevice()->accessRenderTargetContext();
auto backendFormat = rtc->asSurfaceProxy()->backendFormat();
int storedCnt = rtc->numSamples();
int allowedCnt = context->priv().caps()->getRenderTargetSampleCount(storedCnt,
backendFormat);
REPORTER_ASSERT(reporter, storedCnt == allowedCnt,
"Should store an allowed sample count (%d vs %d)", allowedCnt,
storedCnt);
}
}
}
@ -744,32 +733,21 @@ static bool supports_readpixels(const GrCaps* caps, SkSurface* surface) {
return caps->surfaceSupportsReadPixels(rt) == GrCaps::SurfaceReadPixelsSupport::kSupported;
}
static sk_sp<SkSurface> create_gpu_surface_backend_texture_as_render_target(
GrDirectContext* dContext,
int sampleCnt,
const SkColor4f& color,
GrBackendTexture* outTexture) {
static sk_sp<SkSurface> create_gpu_surface_backend_render_target(GrDirectContext* dContext,
int sampleCnt,
const SkColor4f& color,
GrBackendTexture* outTexture) {
const int kWidth = 10;
const int kHeight = 10;
SkImageInfo ii = SkImageInfo::Make(kWidth, kHeight, SkColorType::kRGBA_8888_SkColorType,
kPremul_SkAlphaType);
if (!CreateBackendTexture(dContext, outTexture, ii, color,
GrMipmapped::kNo, GrRenderable::kYes)) {
auto surf = MakeBackendRenderTargetSurface(dContext, {kWidth, kHeight}, sampleCnt,
kTopLeft_GrSurfaceOrigin, kRGBA_8888_SkColorType,
nullptr, nullptr);
if (!surf) {
return nullptr;
}
sk_sp<SkSurface> surface = SkSurface::MakeFromBackendTextureAsRenderTarget(
dContext, *outTexture, kTopLeft_GrSurfaceOrigin, sampleCnt, kRGBA_8888_SkColorType,
nullptr, nullptr);
if (!surface) {
DeleteBackendTexture(dContext, *outTexture);
return nullptr;
}
return surface;
surf->getCanvas()->clear(color);
return surf;
}
static void test_surface_context_clear(skiatest::Reporter* reporter,
@ -835,8 +813,8 @@ DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(SurfaceClear_Gpu, reporter, ctxInfo) {
// Wrapped RTs are *not* supposed to clear (to allow client to partially update a surface).
const SkColor4f kOrigColor{.67f, .67f, .67f, 1};
for (auto& surfaceFunc : {&create_gpu_surface_backend_texture,
&create_gpu_surface_backend_texture_as_render_target}) {
for (auto& surfaceFunc :
{&create_gpu_surface_backend_texture, &create_gpu_surface_backend_render_target}) {
GrBackendTexture backendTex;
auto surface = surfaceFunc(dContext, 1, kOrigColor, &backendTex);
if (!surface) {
@ -913,8 +891,8 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfacePartialDraw_Gpu, reporter, ctxInfo) {
static const SkColor4f kOrigColor { 0.667f, 0.733f, 0.8f, 1 };
for (auto& surfaceFunc : {&create_gpu_surface_backend_texture,
&create_gpu_surface_backend_texture_as_render_target}) {
for (auto& surfaceFunc :
{&create_gpu_surface_backend_texture, &create_gpu_surface_backend_render_target}) {
// Validate that we can draw to the canvas and that the original texture color is
// preserved in pixels that aren't rendered to via the surface.
// This works only for non-multisampled case.
@ -970,7 +948,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfaceWrappedWithRelease_Gpu, reporter, ctxI
ReleaseChecker::Release,
&releaseChecker);
} else {
backendRT = gpu->createTestingOnlyBackendRenderTarget(kWidth, kHeight,
backendRT = gpu->createTestingOnlyBackendRenderTarget({kWidth, kHeight},
GrColorType::kRGBA_8888);
if (!backendRT.isValid()) {
continue;
@ -1015,8 +993,8 @@ DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(SurfaceAttachStencil_Gpu, reporter, ctxInf
auto resourceProvider = context->priv().resourceProvider();
for (auto& surfaceFunc : {&create_gpu_surface_backend_texture,
&create_gpu_surface_backend_texture_as_render_target}) {
for (auto& surfaceFunc :
{&create_gpu_surface_backend_texture, &create_gpu_surface_backend_render_target}) {
for (int sampleCnt : {1, 4, 8}) {
GrBackendTexture backendTex;
auto surface = surfaceFunc(context, sampleCnt, kOrigColor, &backendTex);
@ -1031,7 +1009,9 @@ DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(SurfaceAttachStencil_Gpu, reporter, ctxInf
GrRenderTarget* rt = surface->getCanvas()
->internal_private_accessTopLayerRenderTargetContext()->accessRenderTarget();
REPORTER_ASSERT(reporter, resourceProvider->attachStencilAttachment(rt, sampleCnt));
context->deleteBackendTexture(backendTex);
if (backendTex.isValid()) {
context->deleteBackendTexture(backendTex);
}
}
}
}

View File

@ -5,6 +5,9 @@
* found in the LICENSE file.
*/
#ifndef TestUtils_DEFINED
#define TestUtils_DEFINED
#include "include/core/SkBitmap.h"
#include "src/gpu/GrDataUtils.h"
#include "tests/Test.h"
@ -110,3 +113,5 @@ void CheckSingleThreadedProxyRefs(skiatest::Reporter* reporter,
GrSurfaceProxy* proxy,
int32_t expectedProxyRefs,
int32_t expectedBackingRefs);
#endif

View File

@ -134,11 +134,15 @@ void wrap_rt_test(skiatest::Reporter* reporter, GrDirectContext* dContext) {
// Image has MSAA
{
GrVkImageInfo backendCopy = imageInfo;
backendCopy.fSampleCount = 4;
GrBackendRenderTarget backendRT(kW, kH, backendCopy);
rt = gpu->wrapBackendRenderTarget(backendRT);
REPORTER_ASSERT(reporter, !rt);
GrColorType ct = SkColorTypeToGrColorType(kColorType);
GrGpu* gpu = dContext->priv().getGpu();
GrBackendRenderTarget backendRT =
gpu->createTestingOnlyBackendRenderTarget({kW, kW}, ct, 4);
if (backendRT.isValid()) {
rt = gpu->wrapBackendRenderTarget(backendRT);
REPORTER_ASSERT(reporter, rt);
dContext->priv().getGpu()->deleteTestingOnlyBackendRenderTarget(backendRT);
}
}
// When we wrapBackendRenderTarget it is always borrowed, so we must make sure to free the

View File

@ -7,18 +7,16 @@
#include "include/core/SkCanvas.h"
#include "include/core/SkSurface.h"
#include "include/gpu/GrBackendSurface.h"
#include "include/gpu/GrDirectContext.h"
#include "include/private/SkColorData.h"
#include "include/private/SkImageInfoPriv.h"
#include "src/core/SkMathPriv.h"
#include "tests/Test.h"
#include "tests/TestUtils.h"
#include "tools/ToolUtils.h"
#include "include/gpu/GrBackendSurface.h"
#include "include/gpu/GrDirectContext.h"
#include "src/gpu/GrContextPriv.h"
#include "src/gpu/GrGpu.h"
#include "src/gpu/GrProxyProvider.h"
#include "tests/Test.h"
#include "tools/gpu/BackendSurfaceFactory.h"
#include <initializer_list>
@ -462,21 +460,13 @@ static void test_write_pixels_non_texture(skiatest::Reporter* reporter,
return;
}
for (auto& origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin }) {
GrBackendTexture backendTex;
CreateBackendTexture(dContext, &backendTex, DEV_W, DEV_H, kRGBA_8888_SkColorType,
SkColors::kTransparent, GrMipmapped::kNo, GrRenderable::kYes,
GrProtected::kNo);
if (!backendTex.isValid()) {
continue;
}
SkColorType colorType = kN32_SkColorType;
sk_sp<SkSurface> surface(SkSurface::MakeFromBackendTextureAsRenderTarget(
dContext, backendTex, origin, sampleCnt, colorType, nullptr, nullptr));
auto surface = MakeBackendRenderTargetSurface(dContext, {DEV_W, DEV_H}, sampleCnt, origin,
colorType);
if (surface) {
auto ii = SkImageInfo::MakeN32Premul(DEV_W, DEV_H);
test_write_pixels(reporter, surface.get(), ii);
}
dContext->deleteBackendTexture(backendTex);
}
}

View File

@ -26,9 +26,11 @@
#include "tools/ToolUtils.h"
#include "tools/flags/CommandLineFlags.h"
#include "tools/flags/CommonFlags.h"
#include "tools/gpu/BackendSurfaceFactory.h"
#include "tools/gpu/GrContextFactory.h"
#include "tools/gpu/MemoryCache.h"
#include "tools/trace/EventTracingPriv.h"
#include <chrono>
#include <functional>
#include <stdio.h>
@ -338,16 +340,13 @@ static sk_sp<SkImage> draw_with_gpu(std::function<bool(SkCanvas*)> draw,
break;
case SurfaceType::kBackendRenderTarget:
backendRT = context->priv().getGpu()
->createTestingOnlyBackendRenderTarget(info.width(),
info.height(),
SkColorTypeToGrColorType(info.colorType()));
surface = SkSurface::MakeFromBackendRenderTarget(context,
backendRT,
kBottomLeft_GrSurfaceOrigin,
info.colorType(),
info.refColorSpace(),
&props);
surface = MakeBackendRenderTargetSurface(context,
info.dimensions(),
FLAGS_samples,
kBottomLeft_GrSurfaceOrigin,
info.colorType(),
info.refColorSpace(),
&props);
break;
}

View File

@ -0,0 +1,44 @@
/*
* 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 "tools/gpu/BackendSurfaceFactory.h"
#include "include/core/SkSurface.h"
#include "include/gpu/GrContext.h"
#include "src/gpu/GrContextPriv.h"
#include "src/gpu/GrGpu.h"
sk_sp<SkSurface> MakeBackendRenderTargetSurface(GrDirectContext* context,
SkISize dimensions,
int sampleCnt,
GrSurfaceOrigin origin,
SkColorType colorType,
sk_sp<SkColorSpace> colorSpace,
const SkSurfaceProps* props) {
auto ct = SkColorTypeToGrColorType(colorType);
struct ReleaseContext {
GrContext* fContext;
GrBackendRenderTarget fRenderTarget;
};
auto bert = context->priv().getGpu()->createTestingOnlyBackendRenderTarget(
dimensions, ct, sampleCnt);
auto rc = new ReleaseContext{context, bert};
SkASSERT(!bert.isValid() || bert.sampleCnt() >= sampleCnt);
auto proc = [](void* c) {
const auto* rc = static_cast<ReleaseContext*>(c);
if (auto gpu = rc->fContext->priv().getGpu(); gpu && rc->fRenderTarget.isValid()) {
gpu->deleteTestingOnlyBackendRenderTarget(rc->fRenderTarget);
}
delete rc;
};
return SkSurface::MakeFromBackendRenderTarget(
context, bert, origin, colorType, std::move(colorSpace), props, proc, rc);
}

View File

@ -0,0 +1,29 @@
/*
* 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 TestSurface_DEFINED
#define TestSurface_DEFINED
#include "include/core/SkImageInfo.h"
#include "include/core/SkSize.h"
#include "include/gpu/GrTypes.h"
#include "include/private/SkColorData.h"
class GrDirectContext;
class SkSurface;
class SkSurfaceProps;
/** Creates an SkSurface backed by a non-textureable render target. */
sk_sp<SkSurface> MakeBackendRenderTargetSurface(GrDirectContext*,
SkISize,
int sampleCnt,
GrSurfaceOrigin,
SkColorType,
sk_sp<SkColorSpace> = nullptr,
const SkSurfaceProps* = nullptr);
#endif