Revert "Revert "Add a flag to GrSurfaceFlags that requires the texture to be cleared upon creation. ""

This reverts commit a9e795eab5.

Bug: skia:
Change-Id: Ibfc51497ae99f332f8f72a799393a1b2996f7f3f
Reviewed-on: https://skia-review.googlesource.com/17767
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2017-05-23 16:53:47 -04:00 committed by Skia Commit-Bot
parent 0610a462ad
commit d17b4a678b
14 changed files with 214 additions and 13 deletions

View File

@ -443,6 +443,7 @@ static inline bool GrPixelConfigIsOpaque(GrPixelConfig config) {
switch (config) {
case kRGB_565_GrPixelConfig:
case kGray_8_GrPixelConfig:
case kRG_float_GrPixelConfig:
return true;
case kAlpha_8_GrPixelConfig:
case kRGBA_4444_GrPixelConfig:
@ -454,7 +455,6 @@ static inline bool GrPixelConfigIsOpaque(GrPixelConfig config) {
case kRGBA_8888_sint_GrPixelConfig:
case kRGBA_half_GrPixelConfig:
case kRGBA_float_GrPixelConfig:
case kRG_float_GrPixelConfig:
case kUnknown_GrPixelConfig:
return false;
}
@ -516,12 +516,17 @@ static inline bool GrPixelConfigIsSint(GrPixelConfig config) {
* Optional bitfield flags that can be set on GrSurfaceDesc (below).
*/
enum GrSurfaceFlags {
kNone_GrSurfaceFlags = 0x0,
kNone_GrSurfaceFlags = 0x0,
/**
* Creates a texture that can be rendered to as a GrRenderTarget. Use
* GrTexture::asRenderTarget() to access.
*/
kRenderTarget_GrSurfaceFlag = 0x1,
kRenderTarget_GrSurfaceFlag = 0x1,
/**
* Clears to zero on creation. It will cause creation failure if initial data is supplied to the
* texture. This only affects the base level if the texture is created with MIP levels.
*/
kPerformInitialClear_GrSurfaceFlag = 0x2
};
GR_MAKE_BITFIELD_OPS(GrSurfaceFlags)

View File

@ -40,6 +40,8 @@ typedef GrGLenum (GR_GL_FUNCTION_TYPE* GrGLCheckFramebufferStatusProc)(GrGLenum
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLClearProc)(GrGLbitfield mask);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLClearColorProc)(GrGLclampf red, GrGLclampf green, GrGLclampf blue, GrGLclampf alpha);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLClearStencilProc)(GrGLint s);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLClearTexImageProc)(GrGLuint texture, GrGLint level, GrGLenum format, GrGLenum type,const GrGLvoid * data);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLClearTexSubImageProc)(GrGLuint texture, GrGLint level, GrGLint xoffset, GrGLint yoffset, GrGLint zoffset, GrGLsizei width, GrGLsizei height, GrGLsizei depth, GrGLenum format, GrGLenum type,const GrGLvoid * data);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLColorMaskProc)(GrGLboolean red, GrGLboolean green, GrGLboolean blue, GrGLboolean alpha);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLCompileShaderProc)(GrGLuint shader);
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLCompressedTexImage2DProc)(GrGLenum target, GrGLint level, GrGLenum internalformat, GrGLsizei width, GrGLsizei height, GrGLint border, GrGLsizei imageSize, const GrGLvoid* data);

View File

@ -125,6 +125,8 @@ public:
GrGLFunction<GrGLClearProc> fClear;
GrGLFunction<GrGLClearColorProc> fClearColor;
GrGLFunction<GrGLClearStencilProc> fClearStencil;
GrGLFunction<GrGLClearTexImageProc> fClearTexImage;
GrGLFunction<GrGLClearTexSubImageProc> fClearTexSubImage;
GrGLFunction<GrGLColorMaskProc> fColorMask;
GrGLFunction<GrGLCompileShaderProc> fCompileShader;
GrGLFunction<GrGLCompressedTexImage2DProc> fCompressedTexImage2D;

View File

@ -323,6 +323,7 @@ protected:
, fFit(fit)
, fBudgeted(budgeted)
, fFlags(flags)
, fNeedsClear(SkToBool(desc.fFlags & kPerformInitialClear_GrSurfaceFlag))
, fGpuMemorySize(kInvalidGpuMemorySize)
, fLastOpList(nullptr) {
// Note: this ctor pulls a new uniqueID from the same pool at the GrGpuResources
@ -359,7 +360,6 @@ protected:
// mutable bc of SkSurface/SkImage wishy-washiness
const uint32_t fFlags;
const UniqueID fUniqueID; // set from the backing resource for wrapped resources
static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
@ -368,6 +368,8 @@ protected:
private:
virtual size_t onUninstantiatedGpuMemorySize() const = 0;
bool fNeedsClear;
// This entry is lazily evaluated so, when the proxy wraps a resource, the resource
// will be called but, when the proxy is deferred, it will compute the answer itself.
// If the proxy computes its own answer that answer is checked (in debug mode) in

View File

@ -138,11 +138,15 @@ GrTexture* GrGpu::createTexture(const GrSurfaceDesc& origDesc, SkBudgeted budget
}
desc.fSampleCnt = SkTMin(desc.fSampleCnt, caps->maxSampleCount());
// Attempt to catch un- or wrongly intialized sample counts;
// Attempt to catch un- or wrongly initialized sample counts.
SkASSERT(desc.fSampleCnt >= 0 && desc.fSampleCnt <= 64);
desc.fOrigin = resolve_origin(desc.fOrigin, isRT);
if (texels.count() && (desc.fFlags & kPerformInitialClear_GrSurfaceFlag)) {
return nullptr;
}
this->handleDirtyContext();
GrTexture* tex = this->onCreateTexture(desc, budgeted, texels);
if (tex) {
@ -262,7 +266,7 @@ bool GrGpu::getReadPixelsInfo(GrSurface* srcSurface, int width, int height, size
return false;
}
if (!this->onGetReadPixelsInfo(srcSurface, width, height, rowBytes, readConfig, drawPreference,
if (!this->onGetReadPixelsInfo(srcSurface, width, height, rowBytes, readConfig, drawPreference,
tempDrawInfo)) {
return false;
}

View File

@ -221,7 +221,10 @@ GrTexture* GrResourceProvider::refScratchTexture(const GrSurfaceDesc& inDesc, ui
SkTCopyOnFirstWrite<GrSurfaceDesc> desc(inDesc);
if (fGpu->caps()->reuseScratchTextures() || (desc->fFlags & kRenderTarget_GrSurfaceFlag)) {
// We could make initial clears work with scratch textures but it is a rare case so we just opt
// to fall back to making a new texture.
if (!SkToBool(inDesc.fFlags & kPerformInitialClear_GrSurfaceFlag) &&
(fGpu->caps()->reuseScratchTextures() || (desc->fFlags & kRenderTarget_GrSurfaceFlag))) {
if (!(kExact_Flag & flags)) {
// bin by pow2 with a reasonable min
GrSurfaceDesc* wdesc = desc.writable();

View File

@ -30,6 +30,7 @@ GrSurfaceProxy::GrSurfaceProxy(sk_sp<GrSurface> surface, SkBackingFit fit)
, fBudgeted(fTarget->resourcePriv().isBudgeted())
, fFlags(0)
, fUniqueID(fTarget->uniqueID()) // Note: converting from unique resource ID to a proxy ID!
, fNeedsClear(false)
, fGpuMemorySize(kInvalidGpuMemorySize)
, fLastOpList(nullptr) {}
@ -53,6 +54,9 @@ GrSurface* GrSurfaceProxy::instantiateImpl(GrResourceProvider* resourceProvider,
desc.fSampleCnt = sampleCnt;
desc.fIsMipMapped = isMipMapped;
desc.fFlags = flags;
if (fNeedsClear) {
desc.fFlags |= kPerformInitialClear_GrSurfaceFlag;
}
if (SkBackingFit::kApprox == fFit) {
fTarget = resourceProvider->createApproxTexture(desc, fFlags);

View File

@ -105,6 +105,10 @@ const GrGLInterface* GrGLAssembleGLInterface(void* ctx, GrGLGetProc get) {
GET_PROC(Clear);
GET_PROC(ClearColor);
GET_PROC(ClearStencil);
if (glVer >= GR_GL_VER(4,4) || extensions.has("GL_ARB_clear_texture")) {
GET_PROC(ClearTexImage);
GET_PROC(ClearTexSubImage);
}
GET_PROC(ColorMask);
GET_PROC(CompileShader);
GET_PROC(CompressedTexImage2D);
@ -584,6 +588,10 @@ const GrGLInterface* GrGLAssembleGLESInterface(void* ctx, GrGLGetProc get) {
GET_PROC(Clear);
GET_PROC(ClearColor);
GET_PROC(ClearStencil);
if (extensions.has("GL_EXT_clear_texture")) {
GET_PROC_SUFFIX(ClearTexImage, EXT);
GET_PROC_SUFFIX(ClearTexSubImage, EXT);
}
GET_PROC(ColorMask);
GET_PROC(CompileShader);
GET_PROC(CompressedTexImage2D);

View File

@ -54,6 +54,7 @@ GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions,
fSRGBDecodeDisableSupport = false;
fSRGBDecodeDisableAffectsMipmaps = false;
fClearToBoundaryValuesIsBroken = false;
fClearTextureSupport = false;
fDrawArraysBaseVertexIsBroken = false;
fBlitFramebufferFlags = kNoSupport_BlitFramebufferFlag;
@ -252,6 +253,22 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
// vis-versa.
fRGBAToBGRAReadbackConversionsAreSlow = isMESA || isMAC;
if (kGL_GrGLStandard == standard) {
if (version >= GR_GL_VER(4,4) || ctxInfo.hasExtension("GL_ARB_clear_texture")) {
// glClearTexImage seems to have a bug in NVIDIA drivers that was fixed sometime between
// 340.96 and 367.57.
if (ctxInfo.driver() != kNVIDIA_GrGLDriver ||
ctxInfo.driverVersion() >= GR_GL_DRIVER_VER(367, 57)) {
fClearTextureSupport = true;
}
}
} else if (ctxInfo.hasExtension("GL_EXT_clear_texture")) {
// Calling glClearTexImage crashes on the NexusPlayer.
if (kPowerVRRogue_GrGLRenderer != ctxInfo.renderer()) {
fClearTextureSupport = true;
}
}
/**************************************************************************
* GrShaderCaps fields
**************************************************************************/

View File

@ -360,6 +360,9 @@ public:
// Certain Intel GPUs on Mac fail to clear if the glClearColor is made up of only 1s and 0s.
bool clearToBoundaryValuesIsBroken() const { return fClearToBoundaryValuesIsBroken; }
/// glClearTex(Sub)Image support
bool clearTextureSupport() const { return fClearTextureSupport; }
// Adreno/MSAA drops a draw on the imagefiltersbase GM if the base vertex param to
// glDrawArrays is nonzero.
// https://bugs.chromium.org/p/skia/issues/detail?id=6650
@ -437,6 +440,7 @@ private:
bool fSRGBDecodeDisableSupport : 1;
bool fSRGBDecodeDisableAffectsMipmaps : 1;
bool fClearToBoundaryValuesIsBroken : 1;
bool fClearTextureSupport : 1;
bool fDrawArraysBaseVertexIsBroken : 1;
uint32_t fBlitFramebufferFlags;

View File

@ -1320,24 +1320,44 @@ static void set_initial_texture_params(const GrGLInterface* interface,
GrTexture* GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc,
SkBudgeted budgeted,
const SkTArray<GrMipLevel>& texels) {
const SkTArray<GrMipLevel>& origTexels) {
// We fail if the MSAA was requested and is not available.
if (GrGLCaps::kNone_MSFBOType == this->glCaps().msFBOType() && desc.fSampleCnt) {
//SkDebugf("MSAA RT requested but not supported on this platform.");
return return_null_texture();
}
bool performClear = (desc.fFlags & kPerformInitialClear_GrSurfaceFlag);
const SkTArray<GrMipLevel>* texels = &origTexels;
SkTArray<GrMipLevel> zeroLevels;
std::unique_ptr<uint8_t[]> zeros;
// TODO: remove the GrPixelConfigIsSint test. This is here because we have yet to add support
// for glClearBuffer* which must be used instead of glClearColor/glClear for integer FBO
// attachments.
if (performClear && !this->glCaps().clearTextureSupport() &&
(!this->glCaps().canConfigBeFBOColorAttachment(desc.fConfig) ||
GrPixelConfigIsSint(desc.fConfig))) {
size_t rowSize = GrBytesPerPixel(desc.fConfig) * desc.fWidth;
size_t size = rowSize * desc.fHeight;
zeros.reset(new uint8_t[size]);
memset(zeros.get(), 0, size);
zeroLevels.push_back(GrMipLevel{zeros.get(), 0});
texels = &zeroLevels;
performClear = false;
}
bool isRenderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
GrGLTexture::IDDesc idDesc;
idDesc.fOwnership = GrBackendObjectOwnership::kOwned;
GrGLTexture::TexParams initialTexParams;
if (!this->createTextureImpl(desc, &idDesc.fInfo, isRenderTarget, &initialTexParams, texels)) {
if (!this->createTextureImpl(desc, &idDesc.fInfo, isRenderTarget, &initialTexParams, *texels)) {
return return_null_texture();
}
bool wasMipMapDataProvided = false;
if (texels.count() > 1) {
if (texels->count() > 1) {
wasMipMapDataProvided = true;
}
@ -1361,6 +1381,25 @@ GrTexture* GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc,
SkDebugf("--- new texture [%d] size=(%d %d) config=%d\n",
idDesc.fInfo.fID, desc.fWidth, desc.fHeight, desc.fConfig);
#endif
if (tex && performClear) {
if (this->glCaps().clearTextureSupport()) {
GrGLenum format = GrPixelConfigIsSint(tex->config()) ? GR_GL_RGBA_INTEGER : GR_GL_RGBA;
static constexpr uint32_t kZero = 0;
GL_CALL(ClearTexImage(tex->textureID(), 0, format, GR_GL_UNSIGNED_BYTE, &kZero));
} else {
SkASSERT(!GrPixelConfigIsSint(desc.fConfig));
GrGLIRect viewport;
this->bindSurfaceFBOForPixelOps(tex, GR_GL_FRAMEBUFFER, &viewport, kDst_TempFBOTarget);
this->disableScissor();
this->disableWindowRectangles();
GL_CALL(ColorMask(GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE, GR_GL_TRUE));
fHWWriteToColor = kYes_TriState;
GL_CALL(ClearColor(0, 0, 0, 0));
GL_CALL(Clear(GR_GL_COLOR_BUFFER_BIT));
this->unbindTextureFBOForPixelOps(GR_GL_FRAMEBUFFER, tex);
fHWBoundRenderTargetUniqueID.makeInvalid();
}
}
return tex;
}

View File

@ -371,9 +371,9 @@ private:
kDst_TempFBOTarget
};
// Binds a surface as a FBO for copying or reading. If the surface already owns an FBO ID then
// that ID is bound. If not the surface is temporarily bound to a FBO and that FBO is bound.
// This must be paired with a call to unbindSurfaceFBOForPixelOps().
// Binds a surface as a FBO for copying, reading, or clearing. If the surface already owns an
// FBO ID then that ID is bound. If not the surface is temporarily bound to a FBO and that FBO
// is bound. This must be paired with a call to unbindSurfaceFBOForPixelOps().
void bindSurfaceFBOForPixelOps(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport,
TempFBOTarget tempFBOTarget);

View File

@ -745,6 +745,19 @@ GrTexture* GrVkGpu::onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budget
}
}
if (desc.fFlags & kPerformInitialClear_GrSurfaceFlag) {
VkClearColorValue zeroClearColor;
memset(&zeroClearColor, 0, sizeof(zeroClearColor));
VkImageSubresourceRange range;
range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
range.baseArrayLayer = 0;
range.baseMipLevel = 0;
range.layerCount = 1;
range.levelCount = 1;
tex->setImageLayout(this, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, false);
this->currentCommandBuffer()->clearColorImage(this, tex, &zeroClearColor, 1, &range);
}
return tex;
}

View File

@ -123,4 +123,102 @@ DEF_GPUTEST_FOR_ALL_CONTEXTS(GrSurfaceRenderability, reporter, ctxInfo) {
}
#endif
#include "GrDrawingManager.h"
#include "GrSurfaceProxy.h"
#include "GrTextureContext.h"
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(InitialTextureClear, reporter, context_info) {
static constexpr int kSize = 100;
GrSurfaceDesc desc;
desc.fWidth = desc.fHeight = kSize;
std::unique_ptr<uint32_t[]> data(new uint32_t[kSize * kSize]);
GrContext* context = context_info.grContext();
for (int c = 0; c <= kLast_GrPixelConfig; ++c) {
desc.fConfig = static_cast<GrPixelConfig>(c);
if (!context_info.grContext()->caps()->isConfigTexturable(desc.fConfig)) {
continue;
}
desc.fFlags = kPerformInitialClear_GrSurfaceFlag;
for (bool rt : {false, true}) {
if (rt && !context->caps()->isConfigRenderable(desc.fConfig, false)) {
continue;
}
desc.fFlags |= rt ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags;
for (bool mipped : {false, true}) {
desc.fIsMipMapped = mipped;
for (GrSurfaceOrigin origin :
{kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin}) {
desc.fOrigin = origin;
for (bool approx : {false, true}) {
auto resourceProvider = context->resourceProvider();
// Try directly creating the texture.
// Do this twice in an attempt to hit the cache on the second time through.
for (int i = 0; i < 2; ++i) {
sk_sp<GrTexture> tex;
if (approx) {
tex = sk_sp<GrTexture>(
resourceProvider->createApproxTexture(desc, 0));
} else {
tex = resourceProvider->createTexture(desc, SkBudgeted::kYes);
}
if (!tex) {
continue;
}
auto proxy = GrSurfaceProxy::MakeWrapped(std::move(tex));
auto texCtx = context->contextPriv().makeWrappedSurfaceContext(
std::move(proxy), nullptr);
SkImageInfo info = SkImageInfo::Make(
kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
memset(data.get(), 0xAB, kSize * kSize * sizeof(uint32_t));
if (texCtx->readPixels(info, data.get(), 0, 0, 0)) {
uint32_t cmp = GrPixelConfigIsOpaque(desc.fConfig) ? 0xFF000000 : 0;
for (int i = 0; i < kSize * kSize; ++i) {
if (cmp != data.get()[i]) {
ERRORF(reporter, "Failed on config %d", desc.fConfig);
break;
}
}
}
memset(data.get(), 0xBC, kSize * kSize * sizeof(uint32_t));
// Here we overwrite the texture so that the second time through we
// test against recycling without reclearing.
if (0 == i) {
texCtx->writePixels(info, data.get(), 0, 0, 0);
}
}
context->purgeAllUnlockedResources();
// Try creating the texture as a deferred proxy.
for (int i = 0; i < 2; ++i) {
auto surfCtx = context->contextPriv().makeDeferredSurfaceContext(
desc, approx ? SkBackingFit::kApprox : SkBackingFit::kExact,
SkBudgeted::kYes);
if (!surfCtx) {
continue;
}
SkImageInfo info = SkImageInfo::Make(
kSize, kSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
memset(data.get(), 0xAB, kSize * kSize * sizeof(uint32_t));
if (surfCtx->readPixels(info, data.get(), 0, 0, 0)) {
uint32_t cmp = GrPixelConfigIsOpaque(desc.fConfig) ? 0xFF000000 : 0;
for (int i = 0; i < kSize * kSize; ++i) {
if (cmp != data.get()[i]) {
ERRORF(reporter, "Failed on config %d", desc.fConfig);
break;
}
}
}
// Here we overwrite the texture so that the second time through we
// test against recycling without reclearing.
if (0 == i) {
surfCtx->writePixels(info, data.get(), 0, 0, 0);
}
}
context->purgeAllUnlockedResources();
}
}
}
}
}
}
#endif