Add texture-specific flags for External & Rectangle textures

For DDLs, Ganesh needs to know about External & Rectangle textures prior to instantiation (or PromiseImage fulfillment). These new flags allow the client to provide this information when the lazyProxy is created.

The new texture flags work analogously to the render target flags:
   GrSurface and GrSurfaceProxy get a new set of accessors for the new flags
   The new flags are set appropriately on a GrGLTexture when it is created
   For wrapped texture proxies the flags are just copied off of the GrSurface
   For lazy-proxies/promise-images the flags are computed up front and passed to the proxy
   The GrSurfaceProxy/GrSurface flags equivalence is verified in GrSurfaceProxy::assign

Change-Id: Ia8e1998aa0a36ce4481bfd9e56be21f990e83148
Reviewed-on: https://skia-review.googlesource.com/114985
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Robert Phillips 2018-03-21 12:13:37 -04:00 committed by Skia Commit-Bot
parent e65a5cd3fc
commit abf7b763e2
18 changed files with 172 additions and 77 deletions

View File

@ -63,6 +63,20 @@ public:
GrMipMapped, bool useNextPow2 = false);
protected:
void setDoesNotSupportMipMaps() {
SkASSERT(this->asTexture());
fSurfaceFlags |= GrInternalSurfaceFlags::kDoesNotSupportMipMaps;
}
bool doesNotSupportMipMaps() const {
return fSurfaceFlags & GrInternalSurfaceFlags::kDoesNotSupportMipMaps;
}
void setIsClampOnly() {
SkASSERT(this->asTexture());
fSurfaceFlags |= GrInternalSurfaceFlags::kIsClampOnly;
}
bool isClampOnly() const { return fSurfaceFlags & GrInternalSurfaceFlags::kIsClampOnly; }
void setHasMixedSamples() {
SkASSERT(this->asRenderTarget());
fSurfaceFlags |= GrInternalSurfaceFlags::kMixedSampled;

View File

@ -420,6 +420,20 @@ protected:
bool instantiateImpl(GrResourceProvider* resourceProvider, int sampleCnt, bool needsStencil,
GrSurfaceDescFlags descFlags, GrMipMapped, const GrUniqueKey*);
void setDoesNotSupportMipMaps() {
SkASSERT(this->asTextureProxy());
fSurfaceFlags |= GrInternalSurfaceFlags::kDoesNotSupportMipMaps;
}
bool doesNotSupportMipMaps() const {
return fSurfaceFlags & GrInternalSurfaceFlags::kDoesNotSupportMipMaps;
}
void setIsClampOnly() {
SkASSERT(this->asTextureProxy());
fSurfaceFlags |= GrInternalSurfaceFlags::kIsClampOnly;
}
bool isClampOnly() const { return fSurfaceFlags & GrInternalSurfaceFlags::kIsClampOnly; }
void setHasMixedSamples() {
SkASSERT(this->asRenderTargetProxy());
fSurfaceFlags |= GrInternalSurfaceFlags::kMixedSampled;

View File

@ -672,14 +672,24 @@ enum GrAccessPattern {
// Flags shared between the GrSurface & GrSurfaceProxy class hierarchies
enum class GrInternalSurfaceFlags {
kNone = 0,
kNone = 0,
// Surface-level
kNoPendingIO = 1 << 0,
kNoPendingIO = 1 << 0,
// Texture-only
// Texture-only flags
/* coming soon */
// This flag is set when the internal texture target doesn't support mipmaps (e.g.,
// external and rectangle textures). Note that Ganesh does not internally
// create resources with this limitation - this flag will only appear on resources passed
// into Ganesh.
kDoesNotSupportMipMaps = 1 << 1,
// This flag is set when the internal texture target only supports the clamp wrap mode (e.g.,
// external and rectangle textures). Note that Ganesh does not internally
// create resources with this limitation - this flag will only appear on resources passed
// into Ganesh.
kIsClampOnly = 1 << 2,
// RT-only
@ -689,14 +699,14 @@ enum class GrInternalSurfaceFlags {
// this is disabled for FBO0
// but, otherwise, is enabled whenever MSAA is enabled and GrCaps reports mixed samples
// are supported
kMixedSampled = 1 << 3,
kMixedSampled = 1 << 3,
// For internal resources:
// this is enabled whenever GrCaps reports window rect support
// For wrapped resources1
// this is disabled for FBO0
// but, otherwise, is enabled whenever GrCaps reports window rect support
kWindowRectsSupport = 1 << 4
kWindowRectsSupport = 1 << 4
};
GR_MAKE_BITFIELD_CLASS_OPS(GrInternalSurfaceFlags)

View File

@ -93,6 +93,14 @@ bool SkDeferredDisplayListRecorder::init() {
// proxy, when instantiated, will use the GrRenderTarget that backs the SkSurface that the
// DDL is being replayed into.
GrInternalSurfaceFlags surfaceFlags = GrInternalSurfaceFlags::kNone;
if (fContext->caps()->usesMixedSamples() && desc.fSampleCnt > 1) {
surfaceFlags |= GrInternalSurfaceFlags::kMixedSampled;
}
if (fContext->caps()->maxWindowRectangles() > 0) {
surfaceFlags |= GrInternalSurfaceFlags::kWindowRectsSupport;
}
sk_sp<GrRenderTargetProxy> proxy = proxyProvider->createLazyRenderTargetProxy(
[lazyProxyData](GrResourceProvider* resourceProvider) {
if (!resourceProvider) {
@ -106,7 +114,7 @@ bool SkDeferredDisplayListRecorder::init() {
},
desc,
fCharacterization.origin(),
GrInternalSurfaceFlags::kNone,
surfaceFlags,
GrProxyProvider::Textureable(fCharacterization.isTextureable()),
GrMipMapped::kNo,
SkBackingFit::kExact,

View File

@ -26,6 +26,7 @@
#include "GrStencilSettings.h"
#include "GrSurfacePriv.h"
#include "GrTexturePriv.h"
#include "GrTextureProxyPriv.h"
#include "GrTracing.h"
#include "SkJSONWriter.h"
#include "SkMathPriv.h"
@ -44,11 +45,25 @@ void GrGpu::disconnect(DisconnectType) {}
////////////////////////////////////////////////////////////////////////////////
bool GrGpu::IsACopyNeededForTextureParams(const GrCaps* caps,
bool GrGpu::IsACopyNeededForTextureParams(const GrCaps* caps, GrTextureProxy* texProxy,
int width, int height,
const GrSamplerState& textureParams,
GrTextureProducer::CopyParams* copyParams,
SkScalar scaleAdjust[2]) {
if (texProxy) {
// If the texture format itself doesn't support repeat wrap mode or mipmapping (and
// those capabilities are required) force a copy.
if ((textureParams.isRepeated() && texProxy->texPriv().isClampOnly()) ||
(GrSamplerState::Filter::kMipMap == textureParams.filter() &&
texProxy->texPriv().doesNotSupportMipMaps())) {
copyParams->fFilter = GrSamplerState::Filter::kNearest;
copyParams->fWidth = texProxy->width();
copyParams->fHeight = texProxy->height();
return true;
}
}
if (textureParams.isRepeated() && !caps->npotTextureTileSupport() &&
(!SkIsPow2(width) || !SkIsPow2(height))) {
SkASSERT(scaleAdjust);

View File

@ -506,26 +506,12 @@ public:
virtual void clearStencil(GrRenderTarget* target, int clearValue) = 0;
// Determines whether a texture will need to be rescaled in order to be used with the
// GrSamplerState. This variation is called when the caller will create a new texture using the
// resource provider from a non-texture src (cpu-backed image, ...).
static bool IsACopyNeededForTextureParams(const GrCaps*, int width, int height,
// GrSamplerState.
static bool IsACopyNeededForTextureParams(const GrCaps*, GrTextureProxy* texProxy,
int width, int height,
const GrSamplerState&, GrTextureProducer::CopyParams*,
SkScalar scaleAdjust[2]);
// Like the above but this variation should be called when the caller is not creating the
// original texture but rather was handed the original texture. It adds additional checks
// relevant to original textures that were created external to Skia via
// GrResourceProvider::wrap methods.
bool isACopyNeededForTextureParams(GrTextureProxy* proxy, const GrSamplerState& params,
GrTextureProducer::CopyParams* copyParams,
SkScalar scaleAdjust[2]) const {
if (IsACopyNeededForTextureParams(this->caps(), proxy->width(), proxy->height(), params,
copyParams, scaleAdjust)) {
return true;
}
return this->onIsACopyNeededForTextureParams(proxy, params, copyParams, scaleAdjust);
}
void handleDirtyContext() {
if (fResetBits) {
this->resetContext();
@ -578,12 +564,6 @@ private:
virtual GrBuffer* onCreateBuffer(size_t size, GrBufferType intendedType, GrAccessPattern,
const void* data) = 0;
virtual bool onIsACopyNeededForTextureParams(GrTextureProxy* proxy, const GrSamplerState&,
GrTextureProducer::CopyParams*,
SkScalar scaleAdjust[2]) const {
return false;
}
virtual bool onGetReadPixelsInfo(GrSurface*, GrSurfaceOrigin, int width, int height,
size_t rowBytes, GrColorType, DrawPreference*,
ReadPixelTempDrawInfo*) = 0;

View File

@ -40,6 +40,9 @@ public:
GrInternalSurfaceFlags flags() const { return fSurface->fSurfaceFlags; }
bool doesNotSupportMipMaps() const { return fSurface->doesNotSupportMipMaps(); }
bool isClampOnly() const { return fSurface->isClampOnly(); }
private:
explicit GrSurfacePriv(GrSurface* surface) : fSurface(surface) {}
GrSurfacePriv(const GrSurfacePriv&); // unimpl

View File

@ -179,6 +179,11 @@ sk_sp<GrSurface> GrSurfaceProxy::createSurfaceImpl(
void GrSurfaceProxy::assign(sk_sp<GrSurface> surface) {
SkASSERT(!fTarget && surface);
// Check that our a priori computation matched the ultimate reality
SkASSERT((fSurfaceFlags & ~GrInternalSurfaceFlags::kNoPendingIO) ==
surface->surfacePriv().flags());
fTarget = surface.release();
this->INHERITED::transferRefs();
@ -222,10 +227,6 @@ bool GrSurfaceProxy::instantiateImpl(GrResourceProvider* resourceProvider, int s
this->assign(std::move(surface));
// Check that our a priori computation matched the ultimate reality
SkASSERT((fSurfaceFlags & ~GrInternalSurfaceFlags::kNoPendingIO) ==
fTarget->surfacePriv().flags());
return true;
}

View File

@ -75,13 +75,9 @@ sk_sp<GrTextureProxy> GrTextureAdjuster::refTextureProxySafeForParams(const GrSa
return nullptr;
}
// DDL TODO: remove the need for the GrGpu in this method
GrGpu* gpu = fContext->contextPriv().getGpu();
if (!gpu) {
return proxy;
}
if (!gpu->isACopyNeededForTextureParams(proxy.get(), params, &copyParams, scaleAdjust)) {
if (!GrGpu::IsACopyNeededForTextureParams(fContext->caps(),
proxy.get(), proxy->width(), proxy->height(),
params, &copyParams, scaleAdjust)) {
return proxy;
}

View File

@ -31,13 +31,14 @@ sk_sp<GrTextureProxy> GrTextureMaker::refTextureProxyForParams(const GrSamplerSt
sk_sp<GrTextureProxy> original(this->refOriginalTextureProxy(willBeMipped, dstColorSpace,
AllowedTexGenType::kCheap));
if (original) {
GrGpu* gpu = fContext->contextPriv().getGpu();
if (!gpu->isACopyNeededForTextureParams(original.get(), params, &copyParams, scaleAdjust)) {
if (!GrGpu::IsACopyNeededForTextureParams(fContext->caps(), original.get(),
original->width(), original->height(),
params, &copyParams, scaleAdjust)) {
return original;
}
} else {
if (!GrGpu::IsACopyNeededForTextureParams(fContext->caps(), this->width(), this->height(),
if (!GrGpu::IsACopyNeededForTextureParams(fContext->caps(), nullptr,
this->width(), this->height(),
params, &copyParams, scaleAdjust)) {
return this->refOriginalTextureProxy(willBeMipped, dstColorSpace,
AllowedTexGenType::kAny);

View File

@ -31,6 +31,9 @@ public:
// been instantiated or not.
GrMipMapped proxyMipMapped() const { return fTextureProxy->fMipMapped; }
bool doesNotSupportMipMaps() const { return fTextureProxy->doesNotSupportMipMaps(); }
bool isClampOnly() const { return fTextureProxy->isClampOnly(); }
private:
explicit GrTextureProxyPriv(GrTextureProxy* textureProxy) : fTextureProxy(textureProxy) {}
GrTextureProxyPriv(const GrTextureProxyPriv&) {} // unimpl

View File

@ -4553,30 +4553,6 @@ GrGLAttribArrayState* GrGLGpu::HWVertexArrayState::bindInternalVertexArray(GrGLG
return attribState;
}
bool GrGLGpu::onIsACopyNeededForTextureParams(GrTextureProxy* proxy,
const GrSamplerState& textureParams,
GrTextureProducer::CopyParams* copyParams,
SkScalar scaleAdjust[2]) const {
const GrTexture* texture = proxy->priv().peekTexture();
if (!texture) {
// The only way to get and EXTERNAL or RECTANGLE texture in Ganesh is to wrap them.
// In that case the proxy should already be instantiated.
return false;
}
if (textureParams.isRepeated() || GrSamplerState::Filter::kMipMap == textureParams.filter()) {
const GrGLTexture* glTexture = static_cast<const GrGLTexture*>(texture);
if (GR_GL_TEXTURE_EXTERNAL == glTexture->target() ||
GR_GL_TEXTURE_RECTANGLE == glTexture->target()) {
copyParams->fFilter = GrSamplerState::Filter::kNearest;
copyParams->fWidth = texture->width();
copyParams->fHeight = texture->height();
return true;
}
}
return false;
}
void GrGLGpu::onFinishFlush(bool insertedSemaphore) {
// If we inserted semaphores during the flush, we need to call GLFlush.
if (insertedSemaphore) {

View File

@ -215,10 +215,6 @@ private:
GrGLTexture::TexParams* initialTexParams, const GrMipLevel texels[],
int mipLevelCount, GrMipMapsStatus* mipMapsStatus);
bool onIsACopyNeededForTextureParams(GrTextureProxy*, const GrSamplerState&,
GrTextureProducer::CopyParams*,
SkScalar scaleAdjust[2]) const override;
// Checks whether glReadPixels can be called to get pixel values in readConfig from the
// render target.
bool readPixelsSupported(GrRenderTarget* target, GrPixelConfig readConfig);

View File

@ -69,6 +69,11 @@ GrGLTexture::GrGLTexture(GrGLGpu* gpu, const GrSurfaceDesc& desc, const IDDesc&
void GrGLTexture::init(const GrSurfaceDesc& desc, const IDDesc& idDesc) {
SkASSERT(0 != idDesc.fInfo.fID);
SkASSERT(0 != idDesc.fInfo.fFormat);
if (idDesc.fInfo.fTarget == GR_GL_TEXTURE_RECTANGLE ||
idDesc.fInfo.fTarget == GR_GL_TEXTURE_EXTERNAL) {
this->setDoesNotSupportMipMaps();
this->setIsClampOnly();
}
fTexParams.invalidate();
fTexParamsTimestamp = GrGpu::kExpiredTimestamp;
fInfo = idDesc.fInfo;

View File

@ -28,6 +28,7 @@
#include "GrTexture.h"
#include "GrTexturePriv.h"
#include "GrTextureProxy.h"
#include "gl/GrGLDefines.h"
#include "effects/GrNonlinearColorSpaceXformEffect.h"
#include "effects/GrYUVtoRGBEffect.h"
#include "SkCanvas.h"
@ -617,6 +618,17 @@ private:
sk_sp<GrReleaseProcHelper> fDoneHelper;
};
static GrInternalSurfaceFlags get_flags_from_format(const GrBackendFormat& backendFormat) {
if (const GrGLenum* target = backendFormat.getGLTarget()) {
if (GR_GL_TEXTURE_RECTANGLE == *target || GR_GL_TEXTURE_EXTERNAL == *target) {
return GrInternalSurfaceFlags::kDoesNotSupportMipMaps |
GrInternalSurfaceFlags::kIsClampOnly;
}
}
return GrInternalSurfaceFlags::kNone;
}
sk_sp<SkImage> SkImage_Gpu::MakePromiseTexture(GrContext* context,
const GrBackendFormat& backendFormat,
int width,
@ -661,6 +673,8 @@ sk_sp<SkImage> SkImage_Gpu::MakePromiseTexture(GrContext* context,
PromiseImageHelper promiseHelper(textureFulfillProc, textureReleaseProc, promiseDoneProc,
textureContext);
GrInternalSurfaceFlags formatFlags = get_flags_from_format(backendFormat);
sk_sp<GrTextureProxy> proxy = proxyProvider->createLazyProxy(
[promiseHelper, config] (GrResourceProvider* resourceProvider) mutable {
if (!resourceProvider) {
@ -669,7 +683,7 @@ sk_sp<SkImage> SkImage_Gpu::MakePromiseTexture(GrContext* context,
}
return promiseHelper.getTexture(resourceProvider, config);
}, desc, origin, mipMapped, GrInternalSurfaceFlags::kNone, SkBackingFit::kExact,
}, desc, origin, mipMapped, formatFlags, SkBackingFit::kExact,
SkBudgeted::kNo, GrSurfaceProxy::LazyInstantiationType::kUninstantiate);
if (!proxy) {

View File

@ -11,9 +11,12 @@
#include "GrBackendSurface.h"
#include "GrGpu.h"
#include "GrTextureProxyPriv.h"
#include "SkCanvas.h"
#include "SkDeferredDisplayListRecorder.h"
#include "SkGpuDevice.h"
#include "SkImage_Gpu.h"
#include "SkSurface.h"
#include "SkSurface_Gpu.h"
#include "SkSurfaceCharacterization.h"
@ -406,7 +409,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLWrapBackendTest, reporter, ctxInfo) {
static void dummy_fulfill_proc(void*, GrBackendTexture*) { SkASSERT(0); }
static void dummy_release_proc(void*) { SkASSERT(0); }
static void dummy_done_proc(void*) { SkASSERT(0); }
static void dummy_done_proc(void*) { }
// Test out the behavior of an invalid DDLRecorder
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLInvalidRecorder, reporter, ctxInfo) {
@ -433,7 +436,7 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLInvalidRecorder, reporter, ctxInfo) {
REPORTER_ASSERT(reporter, !recorder.getCanvas());
REPORTER_ASSERT(reporter, !recorder.detach());
GrBackendFormat format;
GrBackendFormat format = create_backend_format(context, kRGBA_8888_SkColorType);
sk_sp<SkImage> image = recorder.makePromiseTexture(format, 32, 32, GrMipMapped::kNo,
kTopLeft_GrSurfaceOrigin,
kRGBA_8888_SkColorType,
@ -464,4 +467,42 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DDLFlushWhileRecording, reporter, ctxInfo) {
canvas->getGrContext()->flush();
}
// Check that the texture-specific flags (i.e., for external & rectangle textures) work
// for promise images. As such, this is a GL-only test.
DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(DDLTextureFlagsTest, reporter, ctxInfo) {
GrContext* context = ctxInfo.grContext();
SkImageInfo ii = SkImageInfo::MakeN32Premul(32, 32);
sk_sp<SkSurface> s = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, ii);
SkSurfaceCharacterization characterization;
SkAssertResult(s->characterize(&characterization));
SkDeferredDisplayListRecorder recorder(characterization);
for (GrGLenum target : { GR_GL_TEXTURE_EXTERNAL, GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_2D } ) {
GrBackendFormat format = GrBackendFormat::MakeGL(GR_GL_RGBA8, target);
sk_sp<SkImage> image = recorder.makePromiseTexture(format, 32, 32, GrMipMapped::kNo,
kTopLeft_GrSurfaceOrigin,
kRGBA_8888_SkColorType,
kPremul_SkAlphaType, nullptr,
dummy_fulfill_proc,
dummy_release_proc,
dummy_done_proc,
nullptr);
REPORTER_ASSERT(reporter, image);
GrTextureProxy* backingProxy = ((SkImage_Gpu*) image.get())->peekProxy();
if (GR_GL_TEXTURE_2D == target) {
REPORTER_ASSERT(reporter, !backingProxy->texPriv().doesNotSupportMipMaps());
REPORTER_ASSERT(reporter, !backingProxy->texPriv().isClampOnly());
} else {
REPORTER_ASSERT(reporter, backingProxy->texPriv().doesNotSupportMipMaps());
REPORTER_ASSERT(reporter, backingProxy->texPriv().isClampOnly());
}
}
}
#endif

View File

@ -13,8 +13,11 @@
#include "GrContextPriv.h"
#include "GrRenderTargetContext.h"
#include "GrShaderCaps.h"
#include "GrSurfacePriv.h"
#include "GrTest.h"
#include "GrTexture.h"
#include "GrTextureContext.h"
#include "GrTextureProxyPriv.h"
#include "gl/GLTestContext.h"
#include "gl/GrGLGpu.h"
#include "gl/GrGLUtil.h"
@ -159,6 +162,13 @@ DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(EGLImageTest, reporter, ctxInfo) {
return;
}
GrTextureProxy* proxy = surfaceContext->asTextureProxy();
REPORTER_ASSERT(reporter, proxy->texPriv().doesNotSupportMipMaps());
REPORTER_ASSERT(reporter, proxy->priv().peekTexture()->surfacePriv().doesNotSupportMipMaps());
REPORTER_ASSERT(reporter, proxy->texPriv().isClampOnly());
REPORTER_ASSERT(reporter, proxy->priv().peekTexture()->surfacePriv().isClampOnly());
// Should not be able to wrap as a RT
{
sk_sp<GrRenderTargetContext> temp =

View File

@ -14,7 +14,9 @@
#include "GrContextPriv.h"
#include "GrProxyProvider.h"
#include "GrRenderTargetContext.h"
#include "GrSurfacePriv.h"
#include "GrTest.h"
#include "GrTextureProxyPriv.h"
#include "gl/GLTestContext.h"
#include "gl/GrGLGpu.h"
#include "gl/GrGLUtil.h"
@ -135,6 +137,12 @@ DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(RectangleTexture, reporter, ctxInfo) {
continue;
}
SkASSERT(rectProxy->texPriv().doesNotSupportMipMaps());
SkASSERT(rectProxy->priv().peekTexture()->surfacePriv().doesNotSupportMipMaps());
SkASSERT(rectProxy->texPriv().isClampOnly());
SkASSERT(rectProxy->priv().peekTexture()->surfacePriv().isClampOnly());
test_basic_draw_as_src(reporter, context, rectProxy, refPixels);
// Test copy to both a texture and RT