Separate texture creation from uploading in GrGpu subclasses.

GrGpu base class still allows creation with initial data, but separated
at subclass level into create and then write pixels.

GrGpu handles determining which levels need clearing and GrGpu
subclasses take a mask and clear levels with mask bit set.

GrGLGpu uses three pronged clear strategy:
glClearTexImage() if supported, glClear() if format is FBO bindable, and
lastly glTexSubImage2D with zero'ed buffer.

Change-Id: I65fb1e60eed8f9d0896d686d3baeb10b57ff8f39
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/236676
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
This commit is contained in:
Brian Salomon 2019-09-10 09:17:38 -04:00 committed by Skia Commit-Bot
parent 66d8006c2b
commit a7398246cb
21 changed files with 490 additions and 751 deletions

View File

@ -289,17 +289,6 @@ public:
*/ */
bool shouldInitializeTextures() const { return fShouldInitializeTextures; } bool shouldInitializeTextures() const { return fShouldInitializeTextures; }
/**
* When this is true it is required that all textures are initially cleared. However, the
* clearing must be implemented by passing level data to GrGpu::createTexture() rather than
* be implemeted by GrGpu::createTexture().
*
* TODO: Make this take GrBacknedFormat when canClearTextureOnCreation() does as well.
*/
bool createTextureMustSpecifyAllLevels() const {
return this->shouldInitializeTextures() && !this->canClearTextureOnCreation();
}
/** Returns true if the given backend supports importing AHardwareBuffers via the /** Returns true if the given backend supports importing AHardwareBuffers via the
* GrAHardwarebufferImageGenerator. This will only ever be supported on Android devices with API * GrAHardwarebufferImageGenerator. This will only ever be supported on Android devices with API
* level >= 26. * level >= 26.
@ -403,17 +392,6 @@ public:
virtual GrBackendFormat getBackendFormatFromCompressionType(SkImage::CompressionType) const = 0; virtual GrBackendFormat getBackendFormatFromCompressionType(SkImage::CompressionType) const = 0;
/**
* Used by implementation of shouldInitializeTextures(). Indicates whether GrGpu implements the
* clear in GrGpu::createTexture() or if false then the caller must provide cleared MIP level
* data or GrGpu::createTexture() will fail.
*
* TODO: Make this take a GrBackendFormat so that GL can make this faster for cases
* when the format is renderable and glTexClearImage is not available. Doing this
* is overly complicated until the GrPixelConfig/format mess is straightened out..
*/
virtual bool canClearTextureOnCreation() const = 0;
/** /**
* The CLAMP_TO_BORDER wrap mode for texture coordinates was added to desktop GL in 1.3, and * The CLAMP_TO_BORDER wrap mode for texture coordinates was added to desktop GL in 1.3, and
* GLES 3.2, but is also available in extensions. Vulkan and Metal always have support. * GLES 3.2, but is also available in extensions. Vulkan and Metal always have support.

View File

@ -99,8 +99,8 @@ bool GrGpu::IsACopyNeededForMips(const GrCaps* caps, const GrTextureProxy* texPr
return false; return false;
} }
static bool validate_levels(int w, int h, const GrMipLevel texels[], int mipLevelCount, int bpp, static bool validate_texel_levels(int w, int h, const GrMipLevel* texels, int mipLevelCount,
const GrCaps* caps, bool mustHaveDataForAllLevels = false) { int bpp, const GrCaps* caps) {
SkASSERT(mipLevelCount > 0); SkASSERT(mipLevelCount > 0);
bool hasBasePixels = texels[0].fPixels; bool hasBasePixels = texels[0].fPixels;
int levelsWithPixelsCnt = 0; int levelsWithPixelsCnt = 0;
@ -138,10 +138,7 @@ static bool validate_levels(int w, int h, const GrMipLevel texels[], int mipLeve
if (!hasBasePixels) { if (!hasBasePixels) {
return levelsWithPixelsCnt == 0; return levelsWithPixelsCnt == 0;
} }
if (levelsWithPixelsCnt == 1 && !mustHaveDataForAllLevels) { return levelsWithPixelsCnt == 1 || levelsWithPixelsCnt == mipLevelCount;
return true;
}
return levelsWithPixelsCnt == mipLevelCount;
} }
sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& desc, sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& desc,
@ -151,14 +148,14 @@ sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& desc,
SkBudgeted budgeted, SkBudgeted budgeted,
GrProtected isProtected, GrProtected isProtected,
const GrMipLevel texels[], const GrMipLevel texels[],
int mipLevelCount) { int texelLevelCount) {
TRACE_EVENT0("skia.gpu", TRACE_FUNC); TRACE_EVENT0("skia.gpu", TRACE_FUNC);
if (this->caps()->isFormatCompressed(format)) { if (this->caps()->isFormatCompressed(format)) {
// Call GrGpu::createCompressedTexture. // Call GrGpu::createCompressedTexture.
return nullptr; return nullptr;
} }
GrMipMapped mipMapped = mipLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo; GrMipMapped mipMapped = texelLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo;
if (!this->caps()->validateSurfaceParams({desc.fWidth, desc.fHeight}, format, desc.fConfig, if (!this->caps()->validateSurfaceParams({desc.fWidth, desc.fHeight}, format, desc.fConfig,
renderable, renderTargetSampleCnt, mipMapped)) { renderable, renderTargetSampleCnt, mipMapped)) {
return nullptr; return nullptr;
@ -170,16 +167,26 @@ sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& desc,
} }
// Attempt to catch un- or wrongly initialized sample counts. // Attempt to catch un- or wrongly initialized sample counts.
SkASSERT(renderTargetSampleCnt > 0 && renderTargetSampleCnt <= 64); SkASSERT(renderTargetSampleCnt > 0 && renderTargetSampleCnt <= 64);
if (texelLevelCount) {
bool mustHaveDataForAllLevels = this->caps()->createTextureMustSpecifyAllLevels();
if (mipLevelCount) {
int bpp = GrBytesPerPixel(desc.fConfig); int bpp = GrBytesPerPixel(desc.fConfig);
if (!validate_levels(desc.fWidth, desc.fHeight, texels, mipLevelCount, bpp, this->caps(), if (!validate_texel_levels(desc.fWidth, desc.fHeight, texels, texelLevelCount, bpp,
mustHaveDataForAllLevels)) { this->caps())) {
return nullptr; return nullptr;
} }
} else if (mustHaveDataForAllLevels) { }
return nullptr;
int mipLevelCount = SkTMax(1, texelLevelCount);
uint32_t levelClearMask = 0;
if (this->caps()->shouldInitializeTextures()) {
if (texelLevelCount) {
for (int i = 0; i < mipLevelCount; ++i) {
if (!texels->fPixels) {
levelClearMask |= static_cast<uint32_t>(1 << i);
}
}
} else {
levelClearMask = static_cast<uint32_t>((1 << mipLevelCount) - 1);
}
} }
this->handleDirtyContext(); this->handleDirtyContext();
@ -189,20 +196,36 @@ sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& desc,
renderTargetSampleCnt, renderTargetSampleCnt,
budgeted, budgeted,
isProtected, isProtected,
texels, mipLevelCount,
mipLevelCount); levelClearMask);
if (tex) { if (tex) {
SkASSERT(tex->backendFormat() == format);
SkASSERT(GrRenderable::kNo == renderable || tex->asRenderTarget());
if (!this->caps()->reuseScratchTextures() && renderable == GrRenderable::kNo) { if (!this->caps()->reuseScratchTextures() && renderable == GrRenderable::kNo) {
tex->resourcePriv().removeScratchKey(); tex->resourcePriv().removeScratchKey();
} }
fStats.incTextureCreates(); fStats.incTextureCreates();
if (mipLevelCount) { bool markMipLevelsClean = false;
if (texels[0].fPixels) { // Currently if level 0 does not have pixels then no other level may, as enforced by
fStats.incTextureUploads(); // validate_texel_levels.
if (texelLevelCount && texels[0].fPixels) {
auto textureColorType = GrPixelConfigToColorType(desc.fConfig);
auto dataColorType = textureColorType;
if (!this->writePixels(tex.get(), 0, 0, desc.fWidth, desc.fHeight, textureColorType,
dataColorType, texels, texelLevelCount)) {
return nullptr;
} }
// Currently if level[1] of mip map has pixel data then so must all other levels.
// as enforced by validate_texel_levels.
markMipLevelsClean = (texelLevelCount > 1 && !levelClearMask && texels[1].fPixels);
fStats.incTextureUploads();
} else if (levelClearMask && mipLevelCount > 1) {
markMipLevelsClean = true;
}
if (markMipLevelsClean) {
tex->texturePriv().markMipMapsClean();
} }
SkASSERT(tex->backendFormat() == format);
SkASSERT(!tex || GrRenderable::kNo == renderable || tex->asRenderTarget());
if (renderTargetSampleCnt > 1 && !this->caps()->msaaResolvesAutomatically()) { if (renderTargetSampleCnt > 1 && !this->caps()->msaaResolvesAutomatically()) {
SkASSERT(GrRenderable::kYes == renderable); SkASSERT(GrRenderable::kYes == renderable);
tex->asRenderTarget()->setRequiresManualMSAAResolve(); tex->asRenderTarget()->setRequiresManualMSAAResolve();
@ -432,7 +455,7 @@ bool GrGpu::writePixels(GrSurface* surface, int left, int top, int width, int he
} }
size_t bpp = GrColorTypeBytesPerPixel(srcColorType); size_t bpp = GrColorTypeBytesPerPixel(srcColorType);
if (!validate_levels(width, height, texels, mipLevelCount, bpp, this->caps())) { if (!validate_texel_levels(width, height, texels, mipLevelCount, bpp, this->caps())) {
return false; return false;
} }

View File

@ -103,7 +103,7 @@ public:
* If mipLevelCount > 1 and texels[i].fPixels != nullptr for any i > 0 * If mipLevelCount > 1 and texels[i].fPixels != nullptr for any i > 0
* then all levels must have non-null pixels. All levels must have * then all levels must have non-null pixels. All levels must have
* non-null pixels if GrCaps::createTextureMustSpecifyAllLevels() is true. * non-null pixels if GrCaps::createTextureMustSpecifyAllLevels() is true.
* @param mipLevelCount the number of levels in 'texels'. May be 0, 1, or * @param texelLevelCount the number of levels in 'texels'. May be 0, 1, or
* floor(max((log2(desc.fWidth), log2(desc.fHeight)))). It must be the * floor(max((log2(desc.fWidth), log2(desc.fHeight)))). It must be the
* latter if GrCaps::createTextureMustSpecifyAllLevels() is true. * latter if GrCaps::createTextureMustSpecifyAllLevels() is true.
* @return The texture object if successful, otherwise nullptr. * @return The texture object if successful, otherwise nullptr.
@ -111,7 +111,7 @@ public:
sk_sp<GrTexture> createTexture(const GrSurfaceDesc& desc, const GrBackendFormat& format, sk_sp<GrTexture> createTexture(const GrSurfaceDesc& desc, const GrBackendFormat& format,
GrRenderable renderable, int renderTargetSampleCnt, SkBudgeted, GrRenderable renderable, int renderTargetSampleCnt, SkBudgeted,
GrProtected isProtected, const GrMipLevel texels[], GrProtected isProtected, const GrMipLevel texels[],
int mipLevelCount); int texelLevelCount);
/** /**
* Simplified createTexture() interface for when there is no initial texel data to upload. * Simplified createTexture() interface for when there is no initial texel data to upload.
@ -546,15 +546,17 @@ private:
virtual void xferBarrier(GrRenderTarget*, GrXferBarrierType) = 0; virtual void xferBarrier(GrRenderTarget*, GrXferBarrierType) = 0;
// overridden by backend-specific derived class to create objects. // overridden by backend-specific derived class to create objects.
// Texture size and sample size will have already been validated in base class before // Texture size, renderablility, format support, sample count will have already been validated
// onCreateTexture is called. // in base class before onCreateTexture is called.
// If the ith bit is set in levelClearMask then the ith MIP level should be cleared.
virtual sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc&, virtual sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc&,
const GrBackendFormat&, const GrBackendFormat&,
GrRenderable, GrRenderable,
int renderTargetSampleCnt, int renderTargetSampleCnt,
SkBudgeted, GrProtected, SkBudgeted,
const GrMipLevel[], GrProtected,
int mipLevelCount) = 0; int mipLevelCoont,
uint32_t levelClearMask) = 0;
virtual sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, virtual sk_sp<GrTexture> onCreateCompressedTexture(int width, int height,
const GrBackendFormat&, const GrBackendFormat&,
SkImage::CompressionType, SkBudgeted, SkImage::CompressionType, SkBudgeted,

View File

@ -45,18 +45,11 @@ GrResourceProvider::GrResourceProvider(GrGpu* gpu, GrResourceCache* cache, GrSin
// Ensures the row bytes are populated (not 0) and makes a copy to a temporary // Ensures the row bytes are populated (not 0) and makes a copy to a temporary
// to make the row bytes tight if necessary. Returns false if the input row bytes are invalid. // to make the row bytes tight if necessary. Returns false if the input row bytes are invalid.
static bool prepare_level(const GrMipLevel& inLevel, size_t bpp, int w, int h, bool rowBytesSupport, static bool prepare_level(const GrMipLevel& inLevel, size_t bpp, int w, int h, bool rowBytesSupport,
bool mustInitializeAllLevels, GrMipLevel* outLevel, GrMipLevel* outLevel, std::unique_ptr<char[]>* data) {
std::unique_ptr<char[]>* data) {
size_t minRB = w * bpp; size_t minRB = w * bpp;
if (!inLevel.fPixels) { if (!inLevel.fPixels) {
if (mustInitializeAllLevels) { outLevel->fPixels = nullptr;
data->reset(new char[minRB * h]()); outLevel->fRowBytes = 0;
outLevel->fPixels = data->get();
outLevel->fRowBytes = minRB;
} else {
outLevel->fPixels = nullptr;
outLevel->fRowBytes = 0;
}
return true; return true;
} }
size_t actualRB = inLevel.fRowBytes ? inLevel.fRowBytes : minRB; size_t actualRB = inLevel.fRowBytes ? inLevel.fRowBytes : minRB;
@ -97,7 +90,6 @@ sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc,
renderTargetSampleCnt, mipMapped)) { renderTargetSampleCnt, mipMapped)) {
return nullptr; return nullptr;
} }
bool mustInitializeAllLevels = this->caps()->createTextureMustSpecifyAllLevels();
bool rowBytesSupport = this->caps()->writePixelsRowBytesSupport(); bool rowBytesSupport = this->caps()->writePixelsRowBytesSupport();
SkAutoSTMalloc<14, GrMipLevel> tmpTexels; SkAutoSTMalloc<14, GrMipLevel> tmpTexels;
SkAutoSTArray<14, std::unique_ptr<char[]>> tmpDatas; SkAutoSTArray<14, std::unique_ptr<char[]>> tmpDatas;
@ -108,8 +100,8 @@ sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc,
int h = desc.fHeight; int h = desc.fHeight;
size_t bpp = GrBytesPerPixel(desc.fConfig); size_t bpp = GrBytesPerPixel(desc.fConfig);
for (int i = 0; i < mipLevelCount; ++i) { for (int i = 0; i < mipLevelCount; ++i) {
if (!prepare_level(texels[i], bpp, w, h, rowBytesSupport, mustInitializeAllLevels, if (!prepare_level(texels[i], bpp, w, h, rowBytesSupport, &tmpTexels[i],
&tmpTexels[i], &tmpDatas[i])) { &tmpDatas[i])) {
return nullptr; return nullptr;
} }
w = std::max(w / 2, 1); w = std::max(w / 2, 1);
@ -162,14 +154,13 @@ sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc,
GrContext* context = fGpu->getContext(); GrContext* context = fGpu->getContext();
GrProxyProvider* proxyProvider = context->priv().proxyProvider(); GrProxyProvider* proxyProvider = context->priv().proxyProvider();
bool mustInitialize = this->caps()->createTextureMustSpecifyAllLevels();
bool rowBytesSupport = this->caps()->writePixelsRowBytesSupport(); bool rowBytesSupport = this->caps()->writePixelsRowBytesSupport();
size_t bpp = GrBytesPerPixel(desc.fConfig); size_t bpp = GrBytesPerPixel(desc.fConfig);
std::unique_ptr<char[]> tmpData; std::unique_ptr<char[]> tmpData;
GrMipLevel tmpLevel; GrMipLevel tmpLevel;
if (!prepare_level(mipLevel, bpp, desc.fWidth, desc.fHeight, rowBytesSupport, mustInitialize, if (!prepare_level(mipLevel, bpp, desc.fWidth, desc.fHeight, rowBytesSupport, &tmpLevel,
&tmpLevel, &tmpData)) { &tmpData)) {
return nullptr; return nullptr;
} }
@ -239,17 +230,6 @@ sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc,
} }
} }
if (fCaps->createTextureMustSpecifyAllLevels()) {
size_t rowBytes = GrBytesPerPixel(desc.fConfig) * desc.fWidth;
size_t size = rowBytes * desc.fHeight;
std::unique_ptr<char[]> zeros(new char[size]());
GrMipLevel level;
level.fRowBytes = rowBytes;
level.fPixels = zeros.get();
return fGpu->createTexture(desc, format, renderable, renderTargetSampleCnt, budgeted,
isProtected, &level, 1);
}
return fGpu->createTexture(desc, format, renderable, renderTargetSampleCnt, budgeted, return fGpu->createTexture(desc, format, renderable, renderTargetSampleCnt, budgeted,
isProtected); isProtected);
} }
@ -320,16 +300,6 @@ sk_sp<GrTexture> GrResourceProvider::createApproxTexture(const GrSurfaceDesc& de
return tex; return tex;
} }
if (this->caps()->createTextureMustSpecifyAllLevels()) {
size_t rowBytes = GrBytesPerPixel(copyDesc->fConfig) * copyDesc->fWidth;
size_t size = rowBytes * copyDesc->fHeight;
std::unique_ptr<char[]> zeros(new char[size]());
GrMipLevel level;
level.fRowBytes = rowBytes;
level.fPixels = zeros.get();
return fGpu->createTexture(*copyDesc, format, renderable, renderTargetSampleCnt,
SkBudgeted::kYes, isProtected, &level, 1);
}
return fGpu->createTexture(*copyDesc, format, renderable, renderTargetSampleCnt, return fGpu->createTexture(*copyDesc, format, renderable, renderTargetSampleCnt,
SkBudgeted::kYes, isProtected); SkBudgeted::kYes, isProtected);
} }

View File

@ -175,10 +175,6 @@ GrSwizzle GrDawnCaps::getTextureSwizzle(const GrBackendFormat& format, GrColorTy
return get_swizzle(format, colorType, false); return get_swizzle(format, colorType, false);
} }
bool GrDawnCaps::canClearTextureOnCreation() const {
return true;
}
GrSwizzle GrDawnCaps::getOutputSwizzle(const GrBackendFormat& format, GrColorType colorType) const GrSwizzle GrDawnCaps::getOutputSwizzle(const GrBackendFormat& format, GrColorType colorType) const
{ {
return get_swizzle(format, colorType, true); return get_swizzle(format, colorType, true);

View File

@ -48,8 +48,6 @@ public:
GrBackendFormat getBackendFormatFromCompressionType(SkImage::CompressionType) const override; GrBackendFormat getBackendFormatFromCompressionType(SkImage::CompressionType) const override;
bool canClearTextureOnCreation() const override;
GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override; GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override;
GrSwizzle getOutputSwizzle(const GrBackendFormat&, GrColorType) const override; GrSwizzle getOutputSwizzle(const GrBackendFormat&, GrColorType) const override;

View File

@ -1195,12 +1195,12 @@ void GrGLCaps::onDumpJSON(SkJSONWriter* writer) const {
writer->beginObject(nullptr, false); writer->beginObject(nullptr, false);
writer->appendHexU32("flags", fFormatTable[i].fFlags); writer->appendHexU32("flags", fFormatTable[i].fFlags);
writer->appendHexU32("f_type", (uint32_t)fFormatTable[i].fFormatType); writer->appendHexU32("f_type", (uint32_t)fFormatTable[i].fFormatType);
writer->appendHexU32("b_internal", fFormatTable[i].fBaseInternalFormat);
writer->appendHexU32("s_internal", fFormatTable[i].fSizedInternalFormat);
writer->appendHexU32("c_internal", fFormatTable[i].fCompressedInternalFormat); writer->appendHexU32("c_internal", fFormatTable[i].fCompressedInternalFormat);
writer->appendHexU32("i_for_teximage", fFormatTable[i].fInternalFormatForTexImage); writer->appendHexU32("i_for_teximage", fFormatTable[i].fInternalFormatForTexImageOrStorage);
writer->appendHexU32("i_for_renderbuffer", fFormatTable[i].fInternalFormatForRenderbuffer); writer->appendHexU32("i_for_renderbuffer", fFormatTable[i].fInternalFormatForRenderbuffer);
writer->appendHexU32("default_ex_format", fFormatTable[i].fDefaultExternalFormat);
writer->appendHexU32("default_ex_type", fFormatTable[i].fDefaultExternalType); writer->appendHexU32("default_ex_type", fFormatTable[i].fDefaultExternalType);
writer->appendHexU64("z_bpp", fFormatTable[i].fTexSubImageZeroDataBpp);
writer->beginArray("surface color types"); writer->beginArray("surface color types");
for (int j = 0; j < fFormatTable[i].fColorTypeInfoCount; ++j) { for (int j = 0; j < fFormatTable[i].fColorTypeInfoCount; ++j) {
@ -1233,12 +1233,28 @@ void GrGLCaps::onDumpJSON(SkJSONWriter* writer) const {
void GrGLCaps::onDumpJSON(SkJSONWriter* writer) const { } void GrGLCaps::onDumpJSON(SkJSONWriter* writer) const { }
#endif #endif
void GrGLCaps::getTexImageFormats(GrGLFormat surfaceFormat, GrColorType surfaceColorType, void GrGLCaps::getTexImageExternalFormatAndType(GrGLFormat surfaceFormat, GrGLenum* externalFormat,
GrColorType memoryColorType, GrGLenum* internalFormat, GrGLenum* externalType) const {
GrGLenum* externalFormat, GrGLenum* externalType) const { const auto& info = this->getFormatInfo(surfaceFormat);
*externalType = info.fDefaultExternalType;
*externalFormat = info.fDefaultExternalFormat;
}
void GrGLCaps::getTexSubImageZeroFormatTypeAndBpp(GrGLFormat format, GrGLenum* externalFormat,
GrGLenum* externalType, size_t* bpp) const {
const auto& info = this->getFormatInfo(format);
*externalType = info.fDefaultExternalType;
*externalFormat = info.fDefaultExternalFormat;
*bpp = info.fTexSubImageZeroDataBpp;
}
void GrGLCaps::getTexSubImageExternalFormatAndType(GrGLFormat surfaceFormat,
GrColorType surfaceColorType,
GrColorType memoryColorType,
GrGLenum* externalFormat,
GrGLenum* externalType) const {
this->getExternalFormat(surfaceFormat, surfaceColorType, memoryColorType, this->getExternalFormat(surfaceFormat, surfaceColorType, memoryColorType,
kTexImage_ExternalFormatUsage, externalFormat, externalType); kTexImage_ExternalFormatUsage, externalFormat, externalType);
*internalFormat = this->getTexImageInternalFormat(surfaceFormat);
} }
void GrGLCaps::getReadPixelsFormat(GrGLFormat surfaceFormat, GrColorType surfaceColorType, void GrGLCaps::getReadPixelsFormat(GrGLFormat surfaceFormat, GrColorType surfaceColorType,
@ -1417,12 +1433,10 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{ {
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA8); FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA8);
info.fFormatType = FormatType::kNormalizedFixedPoint; info.fFormatType = FormatType::kNormalizedFixedPoint;
info.fBaseInternalFormat = GR_GL_RGBA;
info.fSizedInternalFormat = GR_GL_RGBA8;
info.fInternalFormatForTexImage =
texImageSupportsSizedInternalFormat ? GR_GL_RGBA8 : GR_GL_RGBA;
info.fInternalFormatForRenderbuffer = GR_GL_RGBA8; info.fInternalFormatForRenderbuffer = GR_GL_RGBA8;
info.fDefaultExternalFormat = GR_GL_RGBA;
info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE; info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
info.fTexSubImageZeroDataBpp = 4;
info.fFlags = FormatInfo::kTexturable_Flag; info.fFlags = FormatInfo::kTexturable_Flag;
if (GR_IS_GR_GL(standard)) { if (GR_IS_GR_GL(standard)) {
info.fFlags |= msaaRenderFlags; info.fFlags |= msaaRenderFlags;
@ -1436,7 +1450,11 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
} }
if (texStorageSupported) { if (texStorageSupported) {
info.fFlags |= FormatInfo::kCanUseTexStorage_Flag; info.fFlags |= FormatInfo::kUseTexStorage_Flag;
info.fInternalFormatForTexImageOrStorage = GR_GL_RGBA8;
} else {
info.fInternalFormatForTexImageOrStorage =
texImageSupportsSizedInternalFormat ? GR_GL_RGBA8 : GR_GL_RGBA;
} }
bool supportsBGRAColorType = GR_IS_GR_GL(standard) && bool supportsBGRAColorType = GR_IS_GR_GL(standard) &&
@ -1524,19 +1542,21 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{ {
FormatInfo& info = this->getFormatInfo(GrGLFormat::kR8); FormatInfo& info = this->getFormatInfo(GrGLFormat::kR8);
info.fFormatType = FormatType::kNormalizedFixedPoint; info.fFormatType = FormatType::kNormalizedFixedPoint;
info.fBaseInternalFormat = GR_GL_RED;
info.fSizedInternalFormat = GR_GL_R8;
info.fInternalFormatForTexImage =
texImageSupportsSizedInternalFormat ? GR_GL_R8 : GR_GL_RED;
info.fInternalFormatForRenderbuffer = GR_GL_R8; info.fInternalFormatForRenderbuffer = GR_GL_R8;
info.fDefaultExternalFormat = GR_GL_RED;
info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE; info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
info.fTexSubImageZeroDataBpp = 1;
if (textureRedSupport) { if (textureRedSupport) {
info.fFlags |= FormatInfo::kTexturable_Flag | msaaRenderFlags; info.fFlags |= FormatInfo::kTexturable_Flag | msaaRenderFlags;
} }
if (texStorageSupported && if (texStorageSupported &&
!formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2) { !formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2) {
info.fFlags |= FormatInfo::kCanUseTexStorage_Flag; info.fFlags |= FormatInfo::kUseTexStorage_Flag;
info.fInternalFormatForTexImageOrStorage = GR_GL_R8;
} else {
info.fInternalFormatForTexImageOrStorage =
texImageSupportsSizedInternalFormat ? GR_GL_R8 : GR_GL_RED;
} }
if (textureRedSupport) { if (textureRedSupport) {
@ -1619,8 +1639,6 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
FormatInfo& info = this->getFormatInfo(GrGLFormat::kALPHA8); FormatInfo& info = this->getFormatInfo(GrGLFormat::kALPHA8);
info.fFormatType = FormatType::kNormalizedFixedPoint; info.fFormatType = FormatType::kNormalizedFixedPoint;
info.fBaseInternalFormat = GR_GL_ALPHA;
info.fSizedInternalFormat = GR_GL_ALPHA8;
// GL_EXT_texture_storage adds GL_ALPHA8 for texture storage. However, ES3 has glTexStorage // GL_EXT_texture_storage adds GL_ALPHA8 for texture storage. However, ES3 has glTexStorage
// but does not have GL_ALPHA8 (and requires a sized internal format for glTexStorage). // but does not have GL_ALPHA8 (and requires a sized internal format for glTexStorage).
// WebGL never has GL_ALPHA8. // WebGL never has GL_ALPHA8.
@ -1628,14 +1646,6 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
alpha8IsValidForGL || alpha8IsValidForGL ||
(alpha8IsValidForGLES && ctxInfo.hasExtension("GL_EXT_texture_storage")); (alpha8IsValidForGLES && ctxInfo.hasExtension("GL_EXT_texture_storage"));
bool alpha8TexStorageSupported = alpha8SizedEnumSupported && texStorageSupported; bool alpha8TexStorageSupported = alpha8SizedEnumSupported && texStorageSupported;
// Even if GL_ALPHA8 is added by GL_EXT_texture_storage it doesn't become legal for
// glTexImage2D.
if (!GR_IS_GR_GL_ES(standard) && texImageSupportsSizedInternalFormat &&
alpha8SizedEnumSupported) {
info.fInternalFormatForTexImage = GR_GL_ALPHA8;
} else {
info.fInternalFormatForTexImage = GR_GL_ALPHA;
}
bool alpha8IsRenderable = false; bool alpha8IsRenderable = false;
if (!formatWorkarounds.fDisableAlpha8Renderable) { if (!formatWorkarounds.fDisableAlpha8Renderable) {
@ -1647,8 +1657,9 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
} }
} }
info.fInternalFormatForRenderbuffer = GR_GL_ALPHA8; info.fInternalFormatForRenderbuffer = GR_GL_ALPHA8;
info.fDefaultExternalFormat = GR_GL_ALPHA;
info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE; info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
info.fTexSubImageZeroDataBpp = 1;
if (alpha8IsValidForGL || alpha8IsValidForGLES || alpha8IsValidForWebGL) { if (alpha8IsValidForGL || alpha8IsValidForGLES || alpha8IsValidForWebGL) {
info.fFlags = FormatInfo::kTexturable_Flag; info.fFlags = FormatInfo::kTexturable_Flag;
} }
@ -1658,7 +1669,17 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
info.fFlags |= msaaRenderFlags; info.fFlags |= msaaRenderFlags;
} }
if (alpha8TexStorageSupported) { if (alpha8TexStorageSupported) {
info.fFlags |= FormatInfo::kCanUseTexStorage_Flag; info.fFlags |= FormatInfo::kUseTexStorage_Flag;
info.fInternalFormatForTexImageOrStorage = GR_GL_ALPHA8;
} else {
// Even if GL_ALPHA8 is added to ES by GL_EXT_texture_storage it doesn't become legal
// for glTexImage2D.
if (!GR_IS_GR_GL_ES(standard) && texImageSupportsSizedInternalFormat &&
alpha8SizedEnumSupported) {
info.fInternalFormatForTexImageOrStorage = GR_GL_ALPHA8;
} else {
info.fInternalFormatForTexImageOrStorage = GR_GL_ALPHA;
}
} }
if (alpha8IsValidForGL || alpha8IsValidForGLES || alpha8IsValidForWebGL) { if (alpha8IsValidForGL || alpha8IsValidForGLES || alpha8IsValidForWebGL) {
@ -1709,12 +1730,10 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{ {
FormatInfo& info = this->getFormatInfo(GrGLFormat::kLUMINANCE8); FormatInfo& info = this->getFormatInfo(GrGLFormat::kLUMINANCE8);
info.fFormatType = FormatType::kNormalizedFixedPoint; info.fFormatType = FormatType::kNormalizedFixedPoint;
info.fBaseInternalFormat = GR_GL_LUMINANCE;
info.fSizedInternalFormat = GR_GL_LUMINANCE8;
info.fInternalFormatForTexImage =
texImageSupportsSizedInternalFormat ? GR_GL_LUMINANCE8 : GR_GL_LUMINANCE;
info.fInternalFormatForRenderbuffer = GR_GL_LUMINANCE8; info.fInternalFormatForRenderbuffer = GR_GL_LUMINANCE8;
info.fDefaultExternalFormat = GR_GL_LUMINANCE;
info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE; info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
info.fTexSubImageZeroDataBpp = 1;
bool supportsLum = (GR_IS_GR_GL(standard) && version <= GR_GL_VER(3, 0)) || bool supportsLum = (GR_IS_GR_GL(standard) && version <= GR_GL_VER(3, 0)) ||
(GR_IS_GR_GL_ES(standard) && version < GR_GL_VER(3, 0)) || (GR_IS_GR_GL_ES(standard) && version < GR_GL_VER(3, 0)) ||
(GR_IS_GR_WEBGL(standard)); (GR_IS_GR_WEBGL(standard));
@ -1724,7 +1743,11 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
if (texStorageSupported && if (texStorageSupported &&
!formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2 && !formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2 &&
!formatWorkarounds.fDisableNonRedSingleChannelTexStorageForANGLEGL) { !formatWorkarounds.fDisableNonRedSingleChannelTexStorageForANGLEGL) {
info.fFlags |= FormatInfo::kCanUseTexStorage_Flag; info.fFlags |= FormatInfo::kUseTexStorage_Flag;
info.fInternalFormatForTexImageOrStorage = GR_GL_LUMINANCE8;
} else {
info.fInternalFormatForTexImageOrStorage =
texImageSupportsSizedInternalFormat ? GR_GL_LUMINANCE8 : GR_GL_LUMINANCE;
} }
// We are not enabling attaching to an FBO for LUMINANCE8 mostly because of confusion in the // We are not enabling attaching to an FBO for LUMINANCE8 mostly because of confusion in the
// spec. For GLES it does not seem to ever support LUMINANCE8 being color-renderable. For GL // spec. For GLES it does not seem to ever support LUMINANCE8 being color-renderable. For GL
@ -1780,23 +1803,6 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{ {
FormatInfo& info = this->getFormatInfo(GrGLFormat::kBGRA8); FormatInfo& info = this->getFormatInfo(GrGLFormat::kBGRA8);
info.fFormatType = FormatType::kNormalizedFixedPoint; info.fFormatType = FormatType::kNormalizedFixedPoint;
info.fBaseInternalFormat = GR_GL_BGRA;
info.fSizedInternalFormat = GR_GL_BGRA8;
// If BGRA is supported as an internal format it must always be specified to glTex[Sub]Image
// as a base format. Which base format depends on which extension is used.
if (ctxInfo.hasExtension("GL_APPLE_texture_format_BGRA8888")) {
// GL_APPLE_texture_format_BGRA8888:
// ES 2.0: the extension makes BGRA an external format but not an internal format.
// ES 3.0: the extension explicitly states GL_BGRA8 is not a valid internal format
// for glTexImage (just for glTexStorage).
info.fInternalFormatForTexImage = GR_GL_RGBA;
} else {
// GL_EXT_texture_format_BGRA8888:
// This extension adds GL_BGRA as an unsized internal format. However, it is
// written against ES 2.0 and therefore doesn't define a GL_BGRA8 as ES 2.0 doesn't
// have sized internal formats.
info.fInternalFormatForTexImage = GR_GL_BGRA;
}
// We currently only use the renderbuffer format when allocating msaa renderbuffers, so we // We currently only use the renderbuffer format when allocating msaa renderbuffers, so we
// are making decisions here based on that use case. The GL_EXT_texture_format_BGRA8888 // are making decisions here based on that use case. The GL_EXT_texture_format_BGRA8888
@ -1819,7 +1825,28 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
info.fInternalFormatForRenderbuffer = GR_GL_BGRA8; info.fInternalFormatForRenderbuffer = GR_GL_BGRA8;
} }
info.fDefaultExternalFormat = GR_GL_BGRA;
info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE; info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
info.fTexSubImageZeroDataBpp = 4;
GrGLenum bgraTexImageFormat;
// If BGRA is supported as an internal format it must always be specified to glTex[Sub]Image
// as a base format. Which base format depends on which extension is used.
if (ctxInfo.hasExtension("GL_APPLE_texture_format_BGRA8888")) {
// GL_APPLE_texture_format_BGRA8888:
// ES 2.0: the extension makes BGRA an external format but not an internal format.
// ES 3.0: the extension explicitly states GL_BGRA8 is not a valid internal format
// for glTexImage (just for glTexStorage).
bgraTexImageFormat = GR_GL_RGBA;
} else {
// GL_EXT_texture_format_BGRA8888:
// This extension adds GL_BGRA as an unsized internal format. However, it is
// written against ES 2.0 and therefore doesn't define a GL_BGRA8 as ES 2.0 doesn't
// have sized internal formats. See later where we check for tex storage BGRA8
// support.
bgraTexImageFormat = GR_GL_BGRA;
}
// TexStorage requires using a sized internal format and BGRA8 is only supported if we have // TexStorage requires using a sized internal format and BGRA8 is only supported if we have
// the GL_APPLE_texture_format_BGRA8888 extension or if we have GL_EXT_texture_storage and // the GL_APPLE_texture_format_BGRA8888 extension or if we have GL_EXT_texture_storage and
// GL_EXT_texture_format_BGRA8888. // GL_EXT_texture_format_BGRA8888.
@ -1829,7 +1856,8 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
if (ctxInfo.hasExtension("GL_EXT_texture_format_BGRA8888")) { if (ctxInfo.hasExtension("GL_EXT_texture_format_BGRA8888")) {
info.fFlags = FormatInfo::kTexturable_Flag | nonMSAARenderFlags; info.fFlags = FormatInfo::kTexturable_Flag | nonMSAARenderFlags;
// GL_EXT_texture storage has defined interactions with // GL_EXT_texture storage has defined interactions with
// GL_EXT_texture_format_BGRA8888. // GL_EXT_texture_format_BGRA8888. However, ES3 supports glTexStorage but
// without GL_EXT_texture_storage it does not allow the BGRA8 sized internal format.
if (ctxInfo.hasExtension("GL_EXT_texture_storage") && if (ctxInfo.hasExtension("GL_EXT_texture_storage") &&
!formatWorkarounds.fDisableBGRATextureStorageForIntelWindowsES) { !formatWorkarounds.fDisableBGRATextureStorageForIntelWindowsES) {
supportsBGRATexStorage = true; supportsBGRATexStorage = true;
@ -1852,7 +1880,10 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
} }
} }
if (texStorageSupported && supportsBGRATexStorage) { if (texStorageSupported && supportsBGRATexStorage) {
info.fFlags |= FormatInfo::kCanUseTexStorage_Flag; info.fFlags |= FormatInfo::kUseTexStorage_Flag;
info.fInternalFormatForTexImageOrStorage = GR_GL_BGRA8;
} else {
info.fInternalFormatForTexImageOrStorage = bgraTexImageFormat;
} }
if (SkToBool(info.fFlags &FormatInfo::kTexturable_Flag)) { if (SkToBool(info.fFlags &FormatInfo::kTexturable_Flag)) {
@ -1896,12 +1927,10 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{ {
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGB565); FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGB565);
info.fFormatType = FormatType::kNormalizedFixedPoint; info.fFormatType = FormatType::kNormalizedFixedPoint;
info.fBaseInternalFormat = GR_GL_RGB;
info.fSizedInternalFormat = GR_GL_RGB565;
info.fInternalFormatForTexImage =
texImageSupportsSizedInternalFormat ? GR_GL_RGB565 : GR_GL_RGB;
info.fInternalFormatForRenderbuffer = GR_GL_RGB565; info.fInternalFormatForRenderbuffer = GR_GL_RGB565;
info.fDefaultExternalFormat = GR_GL_RGB;
info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT_5_6_5; info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT_5_6_5;
info.fTexSubImageZeroDataBpp = 2;
if (GR_IS_GR_GL(standard)) { if (GR_IS_GR_GL(standard)) {
if (version >= GR_GL_VER(4, 2) || ctxInfo.hasExtension("GL_ARB_ES2_compatibility")) { if (version >= GR_GL_VER(4, 2) || ctxInfo.hasExtension("GL_ARB_ES2_compatibility")) {
info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags; info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
@ -1919,7 +1948,11 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
// TODO: As of 4.2, regular GL supports 565. This logic is due for an // TODO: As of 4.2, regular GL supports 565. This logic is due for an
// update. // update.
if (texStorageSupported && GR_IS_GR_GL_ES(standard)) { if (texStorageSupported && GR_IS_GR_GL_ES(standard)) {
info.fFlags |= FormatInfo::kCanUseTexStorage_Flag; info.fFlags |= FormatInfo::kUseTexStorage_Flag;
info.fInternalFormatForTexImageOrStorage = GR_GL_RGB565;
} else {
info.fInternalFormatForTexImageOrStorage =
texImageSupportsSizedInternalFormat ? GR_GL_RGB565 : GR_GL_RGB;
} }
if (SkToBool(info.fFlags &FormatInfo::kTexturable_Flag)) { if (SkToBool(info.fFlags &FormatInfo::kTexturable_Flag)) {
@ -1963,12 +1996,10 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{ {
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA16F); FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA16F);
info.fFormatType = FormatType::kFloat; info.fFormatType = FormatType::kFloat;
info.fBaseInternalFormat = GR_GL_RGBA;
info.fSizedInternalFormat = GR_GL_RGBA16F;
info.fInternalFormatForTexImage =
texImageSupportsSizedInternalFormat ? GR_GL_RGBA16F : GR_GL_RGBA;
info.fInternalFormatForRenderbuffer = GR_GL_RGBA16F; info.fInternalFormatForRenderbuffer = GR_GL_RGBA16F;
info.fDefaultExternalFormat = GR_GL_RGBA;
info.fDefaultExternalType = halfFloatType; info.fDefaultExternalType = halfFloatType;
info.fTexSubImageZeroDataBpp = 8;
if (hasFP16Textures) { if (hasFP16Textures) {
info.fFlags = FormatInfo::kTexturable_Flag; info.fFlags = FormatInfo::kTexturable_Flag;
// ES requires 3.2 or EXT_color_buffer_half_float. // ES requires 3.2 or EXT_color_buffer_half_float.
@ -1978,7 +2009,11 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
} }
if (texStorageSupported && if (texStorageSupported &&
!formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2) { !formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2) {
info.fFlags |= FormatInfo::kCanUseTexStorage_Flag; info.fFlags |= FormatInfo::kUseTexStorage_Flag;
info.fInternalFormatForTexImageOrStorage = GR_GL_RGBA16F;
} else {
info.fInternalFormatForTexImageOrStorage =
texImageSupportsSizedInternalFormat ? GR_GL_RGBA16F : GR_GL_RGBA;
} }
if (hasFP16Textures) { if (hasFP16Textures) {
@ -2055,12 +2090,10 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{ {
FormatInfo& info = this->getFormatInfo(GrGLFormat::kR16F); FormatInfo& info = this->getFormatInfo(GrGLFormat::kR16F);
info.fFormatType = FormatType::kFloat; info.fFormatType = FormatType::kFloat;
info.fBaseInternalFormat = GR_GL_RED;
info.fSizedInternalFormat = GR_GL_R16F;
info.fInternalFormatForTexImage =
texImageSupportsSizedInternalFormat ? GR_GL_R16F : GR_GL_RED;
info.fInternalFormatForRenderbuffer = GR_GL_R16F; info.fInternalFormatForRenderbuffer = GR_GL_R16F;
info.fDefaultExternalFormat = GR_GL_RED;
info.fDefaultExternalType = halfFloatType; info.fDefaultExternalType = halfFloatType;
info.fTexSubImageZeroDataBpp = 2;
if (textureRedSupport && hasFP16Textures) { if (textureRedSupport && hasFP16Textures) {
info.fFlags = FormatInfo::kTexturable_Flag; info.fFlags = FormatInfo::kTexturable_Flag;
if (halfFPRenderTargetSupport == HalfFPRenderTargetSupport::kAll) { if (halfFPRenderTargetSupport == HalfFPRenderTargetSupport::kAll) {
@ -2069,7 +2102,11 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
} }
if (texStorageSupported && if (texStorageSupported &&
!formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2) { !formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2) {
info.fFlags |= FormatInfo::kCanUseTexStorage_Flag; info.fFlags |= FormatInfo::kUseTexStorage_Flag;
info.fInternalFormatForTexImageOrStorage = GR_GL_R16F;
} else {
info.fInternalFormatForTexImageOrStorage =
texImageSupportsSizedInternalFormat ? GR_GL_R16F : GR_GL_RED;
} }
if (textureRedSupport && hasFP16Textures) { if (textureRedSupport && hasFP16Textures) {
@ -2137,19 +2174,21 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
FormatInfo& info = this->getFormatInfo(GrGLFormat::kLUMINANCE16F); FormatInfo& info = this->getFormatInfo(GrGLFormat::kLUMINANCE16F);
info.fFormatType = FormatType::kFloat; info.fFormatType = FormatType::kFloat;
info.fBaseInternalFormat = GR_GL_LUMINANCE;
info.fSizedInternalFormat = GR_GL_LUMINANCE16F;
info.fInternalFormatForTexImage =
texImageSupportsSizedInternalFormat ? GR_GL_LUMINANCE16F : GR_GL_LUMINANCE;
info.fInternalFormatForRenderbuffer = GR_GL_LUMINANCE16F; info.fInternalFormatForRenderbuffer = GR_GL_LUMINANCE16F;
info.fDefaultExternalFormat = GR_GL_LUMINANCE;
info.fDefaultExternalType = halfFloatType; info.fDefaultExternalType = halfFloatType;
info.fTexSubImageZeroDataBpp = 2;
if (lum16FSupported) { if (lum16FSupported) {
info.fFlags = FormatInfo::kTexturable_Flag; info.fFlags = FormatInfo::kTexturable_Flag;
if (texStorageSupported && if (texStorageSupported &&
!formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2) { !formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2) {
info.fFlags |= FormatInfo::kCanUseTexStorage_Flag; info.fFlags |= FormatInfo::kUseTexStorage_Flag;
info.fInternalFormatForTexImageOrStorage = GR_GL_LUMINANCE16F;
} else {
info.fInternalFormatForTexImageOrStorage =
texImageSupportsSizedInternalFormat ? GR_GL_LUMINANCE16F : GR_GL_LUMINANCE;
} }
info.fColorTypeInfoCount = 1; info.fColorTypeInfoCount = 1;
@ -2198,12 +2237,10 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{ {
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGB8); FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGB8);
info.fFormatType = FormatType::kNormalizedFixedPoint; info.fFormatType = FormatType::kNormalizedFixedPoint;
info.fBaseInternalFormat = GR_GL_RGB;
info.fSizedInternalFormat = GR_GL_RGB8;
info.fInternalFormatForTexImage =
texImageSupportsSizedInternalFormat ? GR_GL_RGB8 : GR_GL_RGB;
info.fInternalFormatForRenderbuffer = GR_GL_RGB8; info.fInternalFormatForRenderbuffer = GR_GL_RGB8;
info.fDefaultExternalFormat = GR_GL_RGB;
info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE; info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
info.fTexSubImageZeroDataBpp = 3;
info.fFlags = FormatInfo::kTexturable_Flag; info.fFlags = FormatInfo::kTexturable_Flag;
if (GR_IS_GR_GL(standard)) { if (GR_IS_GR_GL(standard)) {
// Even in OpenGL 4.6 GL_RGB8 is required to be color renderable but not required to be // Even in OpenGL 4.6 GL_RGB8 is required to be color renderable but not required to be
@ -2224,7 +2261,11 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
info.fFlags |= msaaRenderFlags; info.fFlags |= msaaRenderFlags;
} }
if (texStorageSupported) { if (texStorageSupported) {
info.fFlags |= FormatInfo::kCanUseTexStorage_Flag; info.fFlags |= FormatInfo::kUseTexStorage_Flag;
info.fInternalFormatForTexImageOrStorage = GR_GL_RGB8;
} else {
info.fInternalFormatForTexImageOrStorage =
texImageSupportsSizedInternalFormat ? GR_GL_RGB8 : GR_GL_RGB;
} }
if (formatWorkarounds.fDisableRGB8ForMali400) { if (formatWorkarounds.fDisableRGB8ForMali400) {
info.fFlags = 0; info.fFlags = 0;
@ -2275,20 +2316,22 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{ {
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRG8); FormatInfo& info = this->getFormatInfo(GrGLFormat::kRG8);
info.fFormatType = FormatType::kNormalizedFixedPoint; info.fFormatType = FormatType::kNormalizedFixedPoint;
info.fBaseInternalFormat = GR_GL_RG;
info.fSizedInternalFormat = GR_GL_RG8;
info.fInternalFormatForTexImage =
texImageSupportsSizedInternalFormat ? GR_GL_RG8 : GR_GL_RG;
info.fInternalFormatForRenderbuffer = GR_GL_RG8; info.fInternalFormatForRenderbuffer = GR_GL_RG8;
info.fDefaultExternalFormat = GR_GL_RG;
info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE; info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
info.fTexSubImageZeroDataBpp = 2;
if (textureRedSupport) { if (textureRedSupport) {
info.fFlags |= FormatInfo::kTexturable_Flag | msaaRenderFlags; info.fFlags |= FormatInfo::kTexturable_Flag | msaaRenderFlags;
if (texStorageSupported && if (texStorageSupported &&
!formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2) { !formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2) {
info.fFlags |= FormatInfo::kCanUseTexStorage_Flag; info.fFlags |= FormatInfo::kUseTexStorage_Flag;
info.fInternalFormatForTexImageOrStorage = GR_GL_RG8;
} }
} }
if (!(info.fFlags & FormatInfo::kUseTexStorage_Flag)) {
info.fInternalFormatForTexImageOrStorage =
texImageSupportsSizedInternalFormat ? GR_GL_RG8 : GR_GL_RG;
}
if (textureRedSupport) { if (textureRedSupport) {
info.fColorTypeInfoCount = 1; info.fColorTypeInfoCount = 1;
info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]()); info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]());
@ -2330,12 +2373,10 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{ {
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGB10_A2); FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGB10_A2);
info.fFormatType = FormatType::kNormalizedFixedPoint; info.fFormatType = FormatType::kNormalizedFixedPoint;
info.fBaseInternalFormat = GR_GL_RGBA;
info.fSizedInternalFormat = GR_GL_RGB10_A2;
info.fInternalFormatForTexImage =
texImageSupportsSizedInternalFormat ? GR_GL_RGB10_A2 : GR_GL_RGBA;
info.fInternalFormatForRenderbuffer = GR_GL_RGB10_A2; info.fInternalFormatForRenderbuffer = GR_GL_RGB10_A2;
info.fDefaultExternalFormat = GR_GL_RGBA;
info.fDefaultExternalType = GR_GL_UNSIGNED_INT_2_10_10_10_REV; info.fDefaultExternalType = GR_GL_UNSIGNED_INT_2_10_10_10_REV;
info.fTexSubImageZeroDataBpp = 4;
if (GR_IS_GR_GL(standard) || if (GR_IS_GR_GL(standard) ||
(GR_IS_GR_GL_ES(standard) && version >= GR_GL_VER(3, 0))) { (GR_IS_GR_GL_ES(standard) && version >= GR_GL_VER(3, 0))) {
info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags; info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
@ -2344,7 +2385,11 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
info.fFlags = FormatInfo::kTexturable_Flag; info.fFlags = FormatInfo::kTexturable_Flag;
} // No WebGL support } // No WebGL support
if (texStorageSupported) { if (texStorageSupported) {
info.fFlags |= FormatInfo::kCanUseTexStorage_Flag; info.fFlags |= FormatInfo::kUseTexStorage_Flag;
info.fInternalFormatForTexImageOrStorage = GR_GL_RGB10_A2;
} else {
info.fInternalFormatForTexImageOrStorage =
texImageSupportsSizedInternalFormat ? GR_GL_RGB10_A2 : GR_GL_RGBA;
} }
if (SkToBool(info.fFlags &FormatInfo::kTexturable_Flag)) { if (SkToBool(info.fFlags &FormatInfo::kTexturable_Flag)) {
@ -2388,12 +2433,10 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{ {
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA4); FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA4);
info.fFormatType = FormatType::kNormalizedFixedPoint; info.fFormatType = FormatType::kNormalizedFixedPoint;
info.fBaseInternalFormat = GR_GL_RGBA;
info.fSizedInternalFormat = GR_GL_RGBA4;
info.fInternalFormatForTexImage =
texImageSupportsSizedInternalFormat ? GR_GL_RGBA4 : GR_GL_RGBA;
info.fInternalFormatForRenderbuffer = GR_GL_RGBA4; info.fInternalFormatForRenderbuffer = GR_GL_RGBA4;
info.fDefaultExternalFormat = GR_GL_RGBA;
info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT_4_4_4_4; info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT_4_4_4_4;
info.fTexSubImageZeroDataBpp = 2;
info.fFlags = FormatInfo::kTexturable_Flag; info.fFlags = FormatInfo::kTexturable_Flag;
if (GR_IS_GR_GL(standard)) { if (GR_IS_GR_GL(standard)) {
if (version >= GR_GL_VER(4, 2)) { if (version >= GR_GL_VER(4, 2)) {
@ -2405,7 +2448,11 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
info.fFlags |= msaaRenderFlags; info.fFlags |= msaaRenderFlags;
} }
if (texStorageSupported) { if (texStorageSupported) {
info.fFlags |= FormatInfo::kCanUseTexStorage_Flag; info.fFlags |= FormatInfo::kUseTexStorage_Flag;
info.fInternalFormatForTexImageOrStorage = GR_GL_RGBA4;
} else {
info.fInternalFormatForTexImageOrStorage =
texImageSupportsSizedInternalFormat ? GR_GL_RGBA4 : GR_GL_RGBA;
} }
info.fColorTypeInfoCount = 1; info.fColorTypeInfoCount = 1;
@ -2447,9 +2494,7 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{ {
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA32F); FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA32F);
info.fFormatType = FormatType::kFloat; info.fFormatType = FormatType::kFloat;
info.fBaseInternalFormat = GR_GL_RGBA; info.fInternalFormatForTexImageOrStorage =
info.fSizedInternalFormat = GR_GL_RGBA32F;
info.fInternalFormatForTexImage =
texImageSupportsSizedInternalFormat ? GR_GL_RGBA32F : GR_GL_RGBA; texImageSupportsSizedInternalFormat ? GR_GL_RGBA32F : GR_GL_RGBA;
info.fInternalFormatForRenderbuffer = GR_GL_RGBA32F; info.fInternalFormatForRenderbuffer = GR_GL_RGBA32F;
// We don't allow texturing or rendering to this format // We don't allow texturing or rendering to this format
@ -2459,12 +2504,10 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{ {
FormatInfo& info = this->getFormatInfo(GrGLFormat::kSRGB8_ALPHA8); FormatInfo& info = this->getFormatInfo(GrGLFormat::kSRGB8_ALPHA8);
info.fFormatType = FormatType::kNormalizedFixedPoint; info.fFormatType = FormatType::kNormalizedFixedPoint;
info.fBaseInternalFormat = GR_GL_RGBA;
info.fSizedInternalFormat = GR_GL_SRGB8_ALPHA8;
info.fInternalFormatForTexImage =
texImageSupportsSizedInternalFormat ? GR_GL_SRGB8_ALPHA8 : GR_GL_SRGB_ALPHA;
info.fInternalFormatForRenderbuffer = GR_GL_SRGB8_ALPHA8; info.fInternalFormatForRenderbuffer = GR_GL_SRGB8_ALPHA8;
info.fDefaultExternalFormat = GR_GL_RGBA;
info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE; info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
info.fTexSubImageZeroDataBpp = 4;
if (fSRGBSupport) { if (fSRGBSupport) {
uint32_t srgbRenderFlags = uint32_t srgbRenderFlags =
formatWorkarounds.fDisableSRGBRenderWithMSAAForMacAMD ? nonMSAARenderFlags formatWorkarounds.fDisableSRGBRenderWithMSAAForMacAMD ? nonMSAARenderFlags
@ -2474,7 +2517,11 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
} }
if (texStorageSupported && if (texStorageSupported &&
!formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2) { !formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2) {
info.fFlags |= FormatInfo::kCanUseTexStorage_Flag; info.fFlags |= FormatInfo::kUseTexStorage_Flag;
info.fInternalFormatForTexImageOrStorage = GR_GL_SRGB8_ALPHA8;
} else {
info.fInternalFormatForTexImageOrStorage =
texImageSupportsSizedInternalFormat ? GR_GL_SRGB8_ALPHA8 : GR_GL_SRGB_ALPHA;
} }
if (fSRGBSupport) { if (fSRGBSupport) {
@ -2523,8 +2570,7 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{ {
FormatInfo& info = this->getFormatInfo(GrGLFormat::kCOMPRESSED_RGB8_ETC2); FormatInfo& info = this->getFormatInfo(GrGLFormat::kCOMPRESSED_RGB8_ETC2);
info.fFormatType = FormatType::kNormalizedFixedPoint; info.fFormatType = FormatType::kNormalizedFixedPoint;
info.fBaseInternalFormat = GR_GL_RGB; info.fInternalFormatForTexImageOrStorage = GR_GL_COMPRESSED_RGB8_ETC2;
info.fInternalFormatForTexImage = GR_GL_COMPRESSED_RGB8_ETC2;
if (GR_IS_GR_GL(standard)) { if (GR_IS_GR_GL(standard)) {
if (version >= GR_GL_VER(4, 3) || ctxInfo.hasExtension("GL_ARB_ES3_compatibility")) { if (version >= GR_GL_VER(4, 3) || ctxInfo.hasExtension("GL_ARB_ES3_compatibility")) {
info.fFlags = FormatInfo::kTexturable_Flag; info.fFlags = FormatInfo::kTexturable_Flag;
@ -2543,8 +2589,7 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{ {
FormatInfo& info = this->getFormatInfo(GrGLFormat::kCOMPRESSED_ETC1_RGB8); FormatInfo& info = this->getFormatInfo(GrGLFormat::kCOMPRESSED_ETC1_RGB8);
info.fFormatType = FormatType::kNormalizedFixedPoint; info.fFormatType = FormatType::kNormalizedFixedPoint;
info.fBaseInternalFormat = GR_GL_RGB; info.fInternalFormatForTexImageOrStorage = GR_GL_COMPRESSED_ETC1_RGB8;
info.fInternalFormatForTexImage = GR_GL_COMPRESSED_ETC1_RGB8;
if (GR_IS_GR_GL_ES(standard)) { if (GR_IS_GR_GL_ES(standard)) {
if (ctxInfo.hasExtension("GL_OES_compressed_ETC1_RGB8_texture")) { if (ctxInfo.hasExtension("GL_OES_compressed_ETC1_RGB8_texture")) {
info.fFlags = FormatInfo::kTexturable_Flag; info.fFlags = FormatInfo::kTexturable_Flag;
@ -2558,12 +2603,12 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{ {
FormatInfo& info = this->getFormatInfo(GrGLFormat::kR16); FormatInfo& info = this->getFormatInfo(GrGLFormat::kR16);
info.fFormatType = FormatType::kNormalizedFixedPoint; info.fFormatType = FormatType::kNormalizedFixedPoint;
info.fBaseInternalFormat = GR_GL_RED; info.fInternalFormatForTexImageOrStorage =
info.fSizedInternalFormat = GR_GL_R16;
info.fInternalFormatForTexImage =
texImageSupportsSizedInternalFormat ? GR_GL_R16 : GR_GL_RED; texImageSupportsSizedInternalFormat ? GR_GL_R16 : GR_GL_RED;
info.fInternalFormatForRenderbuffer = GR_GL_R16; info.fInternalFormatForRenderbuffer = GR_GL_R16;
info.fDefaultExternalFormat = GR_GL_RED;
info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT; info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT;
info.fTexSubImageZeroDataBpp = 2;
if (r16AndRG1616Supported) { if (r16AndRG1616Supported) {
info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags; info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
} }
@ -2609,12 +2654,12 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{ {
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRG16); FormatInfo& info = this->getFormatInfo(GrGLFormat::kRG16);
info.fFormatType = FormatType::kNormalizedFixedPoint; info.fFormatType = FormatType::kNormalizedFixedPoint;
info.fBaseInternalFormat = GR_GL_RG; info.fInternalFormatForTexImageOrStorage =
info.fSizedInternalFormat = GR_GL_RG16;
info.fInternalFormatForTexImage =
texImageSupportsSizedInternalFormat ? GR_GL_RG16 : GR_GL_RG; texImageSupportsSizedInternalFormat ? GR_GL_RG16 : GR_GL_RG;
info.fInternalFormatForRenderbuffer = GR_GL_RG16; info.fInternalFormatForRenderbuffer = GR_GL_RG16;
info.fDefaultExternalFormat = GR_GL_RG;
info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT; info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT;
info.fTexSubImageZeroDataBpp = 4;
if (r16AndRG1616Supported) { if (r16AndRG1616Supported) {
info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags; info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
} }
@ -2679,12 +2724,12 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA16); FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA16);
info.fFormatType = FormatType::kNormalizedFixedPoint; info.fFormatType = FormatType::kNormalizedFixedPoint;
info.fBaseInternalFormat = GR_GL_RGBA; info.fInternalFormatForTexImageOrStorage =
info.fSizedInternalFormat = GR_GL_RGBA16;
info.fInternalFormatForTexImage =
texImageSupportsSizedInternalFormat ? GR_GL_RGBA16 : GR_GL_RGBA; texImageSupportsSizedInternalFormat ? GR_GL_RGBA16 : GR_GL_RGBA;
info.fInternalFormatForRenderbuffer = GR_GL_RGBA16; info.fInternalFormatForRenderbuffer = GR_GL_RGBA16;
info.fDefaultExternalFormat = GR_GL_RGBA;
info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT; info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT;
info.fTexSubImageZeroDataBpp = 8;
if (rgba16161616Supported) { if (rgba16161616Supported) {
info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags; info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
} }
@ -2753,12 +2798,12 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRG16F); FormatInfo& info = this->getFormatInfo(GrGLFormat::kRG16F);
info.fFormatType = FormatType::kFloat; info.fFormatType = FormatType::kFloat;
info.fBaseInternalFormat = GR_GL_RG; info.fInternalFormatForTexImageOrStorage =
info.fSizedInternalFormat = GR_GL_RG16F;
info.fInternalFormatForTexImage =
texImageSupportsSizedInternalFormat ? GR_GL_RG16F : GR_GL_RG; texImageSupportsSizedInternalFormat ? GR_GL_RG16F : GR_GL_RG;
info.fInternalFormatForRenderbuffer = GR_GL_RG16F; info.fInternalFormatForRenderbuffer = GR_GL_RG16F;
info.fDefaultExternalFormat = GR_GL_RG;
info.fDefaultExternalType = halfFloatType; info.fDefaultExternalType = halfFloatType;
info.fTexSubImageZeroDataBpp = 4;
if (rg16fTexturesSupported) { if (rg16fTexturesSupported) {
info.fFlags |= FormatInfo::kTexturable_Flag; info.fFlags |= FormatInfo::kTexturable_Flag;
} }
@ -3616,7 +3661,8 @@ bool GrGLCaps::onSurfaceSupportsWritePixels(const GrSurface* surface) const {
return false; return false;
} }
} }
} if (auto rt = surface->asRenderTarget()) { }
if (auto rt = surface->asRenderTarget()) {
if (fUseDrawInsteadOfAllRenderTargetWrites) { if (fUseDrawInsteadOfAllRenderTargetWrites) {
return false; return false;
} }
@ -3837,7 +3883,7 @@ bool GrGLCaps::isFormatCopyable(const GrBackendFormat& format) const {
} }
bool GrGLCaps::formatSupportsTexStorage(GrGLFormat format) const { bool GrGLCaps::formatSupportsTexStorage(GrGLFormat format) const {
return SkToBool(this->getFormatInfo(format).fFlags & FormatInfo::kCanUseTexStorage_Flag); return SkToBool(this->getFormatInfo(format).fFlags & FormatInfo::kUseTexStorage_Flag);
} }
static GrPixelConfig validate_sized_format(GrGLFormat format, static GrPixelConfig validate_sized_format(GrGLFormat format,
@ -4010,12 +4056,12 @@ GrColorType GrGLCaps::getYUVAColorTypeFromBackendFormat(const GrBackendFormat& f
GrBackendFormat GrGLCaps::onGetDefaultBackendFormat(GrColorType ct, GrBackendFormat GrGLCaps::onGetDefaultBackendFormat(GrColorType ct,
GrRenderable renderable) const { GrRenderable renderable) const {
// TODO: make use of renderable.
auto format = this->getFormatFromColorType(ct); auto format = this->getFormatFromColorType(ct);
if (format == GrGLFormat::kUnknown) { if (format == GrGLFormat::kUnknown) {
return GrBackendFormat(); return GrBackendFormat();
} }
// TODO: plumb 'renderable' into getSizedInternalFormat (or, at least, make use of it) return GrBackendFormat::MakeGL(GrGLFormatToEnum(format), GR_GL_TEXTURE_2D);
return GrBackendFormat::MakeGL(this->getSizedInternalFormat(format), GR_GL_TEXTURE_2D);
} }
GrBackendFormat GrGLCaps::getBackendFormatFromCompressionType( GrBackendFormat GrGLCaps::getBackendFormatFromCompressionType(
@ -4027,8 +4073,6 @@ GrBackendFormat GrGLCaps::getBackendFormatFromCompressionType(
SK_ABORT("Invalid compression type"); SK_ABORT("Invalid compression type");
} }
bool GrGLCaps::canClearTextureOnCreation() const { return fClearTextureSupport; }
GrSwizzle GrGLCaps::getTextureSwizzle(const GrBackendFormat& format, GrColorType colorType) const { GrSwizzle GrGLCaps::getTextureSwizzle(const GrBackendFormat& format, GrColorType colorType) const {
const auto& info = this->getFormatInfo(format.asGLFormat()); const auto& info = this->getFormatInfo(format.asGLFormat());
for (int i = 0; i < info.fColorTypeInfoCount; ++i) { for (int i = 0; i < info.fColorTypeInfoCount; ++i) {

View File

@ -142,13 +142,36 @@ public:
return fColorTypeToFormatTable[idx]; return fColorTypeToFormatTable[idx];
} }
GrGLenum formatSizedInternalFormat(GrGLFormat format) const { /**
return this->getFormatInfo(format).fSizedInternalFormat; * Gets the internal format to use with glTexImage...() and glTexStorage...(). May be sized or
* base depending upon the GL. Not applicable to compressed textures.
*/
GrGLenum getTexImageOrStorageInternalFormat(GrGLFormat format) const {
return this->getFormatInfo(format).fInternalFormatForTexImageOrStorage;
} }
void getTexImageFormats(GrGLFormat surfaceFormat, GrColorType surfaceColorType, /**
GrColorType memoryColorType, GrGLenum* internalFormat, * Gets the external format and type to pass to glTexImage2D with nullptr to create an
GrGLenum* externalFormat, GrGLenum* externalType) const; * uninitialized texture. See getTexImageOrStorageInternalFormat() for the internal format.
*/
void getTexImageExternalFormatAndType(GrGLFormat surfaceFormat, GrGLenum* externalFormat,
GrGLenum* externalType) const;
/**
* Given a src data color type and a color type interpretation for a texture of a given format
* this provides the external GL format and type to use with glTexSubImage2d. The color types
* should originate from supportedWritePixelsColorType().
*/
void getTexSubImageExternalFormatAndType(GrGLFormat surfaceFormat, GrColorType surfaceColorType,
GrColorType memoryColorType, GrGLenum* externalFormat,
GrGLenum* externalType) const;
/**
* Gets the external format, type, and bytes per pixel to use when uploading zeros via
* glTexSubImage...() to clear the texture at creation.
*/
void getTexSubImageZeroFormatTypeAndBpp(GrGLFormat format, GrGLenum* externalFormat,
GrGLenum* externalType, size_t* bpp) const;
void getReadPixelsFormat(GrGLFormat surfaceFormat, GrColorType surfaceColorType, void getReadPixelsFormat(GrGLFormat surfaceFormat, GrColorType surfaceColorType,
GrColorType memoryColorType, GrGLenum* externalFormat, GrColorType memoryColorType, GrGLenum* externalFormat,
@ -165,14 +188,6 @@ public:
bool formatSupportsTexStorage(GrGLFormat) const; bool formatSupportsTexStorage(GrGLFormat) const;
/**
* Gets the internal format to use with glTexImage...() and glTexStorage...(). May be sized or
* base depending upon the GL. Not applicable to compressed textures.
*/
GrGLenum getTexImageInternalFormat(GrGLFormat format) const {
return this->getFormatInfo(format).fInternalFormatForTexImage;
}
/** /**
* Gets the internal format to use with glRenderbufferStorageMultisample...(). May be sized or * Gets the internal format to use with glRenderbufferStorageMultisample...(). May be sized or
* base depending upon the GL. Not applicable to compressed textures. * base depending upon the GL. Not applicable to compressed textures.
@ -181,14 +196,6 @@ public:
return this->getFormatInfo(format).fInternalFormatForRenderbuffer; return this->getFormatInfo(format).fInternalFormatForRenderbuffer;
} }
GrGLenum getSizedInternalFormat(GrGLFormat format) const {
return this->getFormatInfo(format).fSizedInternalFormat;
}
GrGLenum getBaseInternalFormat(GrGLFormat format) const {
return this->getFormatInfo(format).fBaseInternalFormat;
}
/** /**
* Gets the default external type to use with glTex[Sub]Image... when the data pointer is null. * Gets the default external type to use with glTex[Sub]Image... when the data pointer is null.
*/ */
@ -404,8 +411,6 @@ public:
GrBackendFormat getBackendFormatFromCompressionType(SkImage::CompressionType) const override; GrBackendFormat getBackendFormatFromCompressionType(SkImage::CompressionType) const override;
bool canClearTextureOnCreation() const override;
GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override; GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override;
GrSwizzle getOutputSwizzle(const GrBackendFormat&, GrColorType) const override; GrSwizzle getOutputSwizzle(const GrBackendFormat&, GrColorType) const override;
@ -618,34 +623,30 @@ private:
still attach it to a FBO for blitting or reading pixels. */ still attach it to a FBO for blitting or reading pixels. */
kFBOColorAttachment_Flag = 0x2, kFBOColorAttachment_Flag = 0x2,
kFBOColorAttachmentWithMSAA_Flag = 0x4, kFBOColorAttachmentWithMSAA_Flag = 0x4,
kCanUseTexStorage_Flag = 0x8, kUseTexStorage_Flag = 0x8,
}; };
uint32_t fFlags = 0; uint32_t fFlags = 0;
FormatType fFormatType = FormatType::kUnknown; FormatType fFormatType = FormatType::kUnknown;
// Both compressed and uncompressed formats have base internal formats.
GrGLenum fBaseInternalFormat = 0;
// Not defined for compressed formats.
GrGLenum fSizedInternalFormat = 0;
// Not defined for uncompressed formats. Passed to glCompressedTexImage... // Not defined for uncompressed formats. Passed to glCompressedTexImage...
GrGLenum fCompressedInternalFormat = 0; GrGLenum fCompressedInternalFormat = 0;
// Value to uses as the "internalformat" argument to glTexImage and glCompressedTexImage... // Value to uses as the "internalformat" argument to glTexImage or glTexStorage. It is
// Usually one of fBaseInternalFormat or fSizedInternalFormat but may vary depending on the // initialized in coordination with the presence/absence of the kUseTexStorage flag. In
// particular format, GL version, extensions. // other words, it is only guaranteed to be compatible with glTexImage if the flag is not
GrGLenum fInternalFormatForTexImage = 0; // set and or with glTexStorage if the flag is set.
GrGLenum fInternalFormatForTexImageOrStorage = 0;
// Value to uses as the "internalformat" argument to glRenderbufferStorageMultisample... // Value to uses as the "internalformat" argument to glRenderbufferStorageMultisample...
// Usually one of fBaseInternalFormat or fSizedInternalFormat but may vary depending on the
// particular format, GL version, extensions.
GrGLenum fInternalFormatForRenderbuffer = 0; GrGLenum fInternalFormatForRenderbuffer = 0;
// Default value to use along with fBaseInternalFormat for functions such as glTexImage2D // Default values to use along with fInternalFormatForTexImageOrStorage for function
// when not input providing data (passing nullptr). Not defined for compressed formats. // glTexImage2D when not input providing data (passing nullptr). Not defined for compressed
// formats. Also used to upload zeros to initially clear a texture.
GrGLenum fDefaultExternalFormat = 0;
GrGLenum fDefaultExternalType = 0; GrGLenum fDefaultExternalType = 0;
GrGLenum fTexSubImageZeroDataBpp = 0;
enum { enum {
// This indicates that a stencil format has not yet been determined for the config. // This indicates that a stencil format has not yet been determined for the config.

View File

@ -719,22 +719,20 @@ sk_sp<GrTexture> GrGLGpu::onWrapRenderableBackendTexture(const GrBackendTexture&
GrColorType colorType, GrColorType colorType,
GrWrapOwnership ownership, GrWrapOwnership ownership,
GrWrapCacheable cacheable) { GrWrapCacheable cacheable) {
const GrGLCaps& caps = this->glCaps();
GrGLTexture::Desc desc; GrGLTexture::Desc desc;
if (!check_backend_texture(backendTex, colorType, this->glCaps(), &desc)) { if (!check_backend_texture(backendTex, colorType, this->glCaps(), &desc)) {
return nullptr; return nullptr;
} }
SkASSERT(caps.isFormatRenderable(desc.fFormat, sampleCnt));
SkASSERT(caps.isFormatTexturable(desc.fFormat));
// We don't support rendering to a EXTERNAL texture. // We don't support rendering to a EXTERNAL texture.
if (GR_GL_TEXTURE_EXTERNAL == desc.fTarget) { if (GR_GL_TEXTURE_EXTERNAL == desc.fTarget) {
return nullptr; return nullptr;
} }
const GrGLCaps& caps = this->glCaps();
if (!caps.isFormatRenderable(desc.fFormat, sampleCnt)) {
return nullptr;
}
if (kBorrow_GrWrapOwnership == ownership) { if (kBorrow_GrWrapOwnership == ownership) {
desc.fOwnership = GrBackendObjectOwnership::kBorrowed; desc.fOwnership = GrBackendObjectOwnership::kBorrowed;
} else { } else {
@ -846,8 +844,8 @@ bool GrGLGpu::onWritePixels(GrSurface* surface, int left, int top, int width, in
SkASSERT(!GrGLFormatIsCompressed(glTex->format())); SkASSERT(!GrGLFormatIsCompressed(glTex->format()));
return this->uploadTexData(glTex->format(), surfaceColorType, glTex->width(), glTex->height(), return this->uploadTexData(glTex->format(), surfaceColorType, glTex->width(), glTex->height(),
glTex->target(), kWrite_UploadType, left, top,width, glTex->target(), left, top, width, height, srcColorType, texels,
height, srcColorType, texels, mipLevelCount); mipLevelCount);
} }
bool GrGLGpu::onTransferPixelsTo(GrTexture* texture, int left, int top, int width, int height, bool GrGLGpu::onTransferPixelsTo(GrTexture* texture, int left, int top, int width, int height,
@ -896,13 +894,11 @@ bool GrGLGpu::onTransferPixelsTo(GrTexture* texture, int left, int top, int widt
} }
GrGLFormat textureFormat = glTex->format(); GrGLFormat textureFormat = glTex->format();
// Internal format comes from the texture desc.
GrGLenum internalFormat;
// External format and type come from the upload data. // External format and type come from the upload data.
GrGLenum externalFormat = 0; GrGLenum externalFormat = 0;
GrGLenum externalType = 0; GrGLenum externalType = 0;
this->glCaps().getTexImageFormats(textureFormat, textureColorType, bufferColorType, this->glCaps().getTexSubImageExternalFormatAndType(
&internalFormat, &externalFormat, &externalType); textureFormat, textureColorType, bufferColorType, &externalFormat, &externalType);
if (!externalFormat || !externalType) { if (!externalFormat || !externalType) {
return false; return false;
} }
@ -933,178 +929,6 @@ bool GrGLGpu::onTransferPixelsFrom(GrSurface* surface, int left, int top, int wi
dstColorType, offsetAsPtr, width); dstColorType, offsetAsPtr, width);
} }
/**
* Creates storage space for the texture and fills it with texels.
*
* @param format The format of the texture.
* @param interface The GL interface in use.
* @param caps The capabilities of the GL device.
* @param target Which bound texture to target (GR_GL_TEXTURE_2D, e.g.)
* @param internalFormat The data format used for the internal storage of the texture. May be sized.
* @param internalFormatForTexStorage The data format used for the TexStorage API. Must be sized.
* @param externalFormat The data format used for the external storage of the texture.
* @param externalType The type of the data used for the external storage of the texture.
* @param dataBpp The bytes per pixel of the data in texels.
* @param texels The texel data of the texture being created.
* @param mipLevelCount Number of mipmap levels
* @param baseWidth The width of the texture's base mipmap level
* @param baseHeight The height of the texture's base mipmap level
*/
static bool allocate_and_populate_texture(GrGLFormat format,
const GrGLInterface& interface,
const GrGLCaps& caps,
GrGLenum target,
GrGLenum internalFormat,
GrGLenum internalFormatForTexStorage,
GrGLenum externalFormat,
GrGLenum externalType,
size_t dataBpp,
const GrMipLevel texels[],
int mipLevelCount,
int baseWidth,
int baseHeight,
bool* changedUnpackRowLength,
GrMipMapsStatus* mipMapsStatus) {
CLEAR_ERROR_BEFORE_ALLOC(&interface);
if (caps.formatSupportsTexStorage(format)) {
// We never resize or change formats of textures.
GL_ALLOC_CALL(&interface,
TexStorage2D(target, SkTMax(mipLevelCount, 1), internalFormatForTexStorage,
baseWidth, baseHeight));
GrGLenum error = CHECK_ALLOC_ERROR(&interface);
if (error != GR_GL_NO_ERROR) {
return false;
} else {
for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
const void* currentMipData = texels[currentMipLevel].fPixels;
if (currentMipData == nullptr) {
if (mipMapsStatus) {
*mipMapsStatus = GrMipMapsStatus::kDirty;
}
continue;
}
int twoToTheMipLevel = 1 << currentMipLevel;
const int currentWidth = SkTMax(1, baseWidth / twoToTheMipLevel);
const int currentHeight = SkTMax(1, baseHeight / twoToTheMipLevel);
if (texels[currentMipLevel].fPixels) {
const size_t trimRowBytes = currentWidth * dataBpp;
const size_t rowBytes = texels[currentMipLevel].fRowBytes;
if (rowBytes != trimRowBytes) {
SkASSERT(caps.writePixelsRowBytesSupport());
GrGLint rowLength = static_cast<GrGLint>(rowBytes / dataBpp);
GR_GL_CALL(&interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength));
*changedUnpackRowLength = true;
} else if (*changedUnpackRowLength) {
SkASSERT(caps.writePixelsRowBytesSupport());
GR_GL_CALL(&interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
*changedUnpackRowLength = false;
}
}
GR_GL_CALL(&interface,
TexSubImage2D(target,
currentMipLevel,
0, // left
0, // top
currentWidth,
currentHeight,
externalFormat, externalType,
currentMipData));
}
return true;
}
} else {
if (!mipLevelCount) {
GL_ALLOC_CALL(&interface,
TexImage2D(target,
0,
internalFormat,
baseWidth,
baseHeight,
0, // border
externalFormat, externalType,
nullptr));
GrGLenum error = CHECK_ALLOC_ERROR(&interface);
if (error != GR_GL_NO_ERROR) {
return false;
}
} else {
for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
int twoToTheMipLevel = 1 << currentMipLevel;
const int currentWidth = SkTMax(1, baseWidth / twoToTheMipLevel);
const int currentHeight = SkTMax(1, baseHeight / twoToTheMipLevel);
const void* currentMipData = texels[currentMipLevel].fPixels;
if (currentMipData) {
const size_t trimRowBytes = currentWidth * dataBpp;
const size_t rowBytes = texels[currentMipLevel].fRowBytes;
if (rowBytes != trimRowBytes) {
SkASSERT(caps.writePixelsRowBytesSupport());
GrGLint rowLength = static_cast<GrGLint>(rowBytes / dataBpp);
GR_GL_CALL(&interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength));
*changedUnpackRowLength = true;
} else if (*changedUnpackRowLength) {
SkASSERT(caps.writePixelsRowBytesSupport());
GR_GL_CALL(&interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
*changedUnpackRowLength = false;
}
} else if (mipMapsStatus) {
*mipMapsStatus = GrMipMapsStatus::kDirty;
}
// We are considering modifying the interface to GrGpu to no longer allow data to
// be provided when creating a texture. To test whether that is feasible for
// performance on ES2 GPUs without tex storage we're calling glTexImage2D and then
// glTexSubImage2D and hoping we don't get any performance regressions.
GL_ALLOC_CALL(&interface,
TexImage2D(target,
currentMipLevel,
internalFormat,
currentWidth,
currentHeight,
0, // border
externalFormat, externalType,
nullptr));
if (currentMipData) {
GR_GL_CALL(&interface,
TexSubImage2D(target,
currentMipLevel,
0, 0,
currentWidth,
currentHeight,
externalFormat,
externalType,
currentMipData));
}
GrGLenum error = CHECK_ALLOC_ERROR(&interface);
if (error != GR_GL_NO_ERROR) {
return false;
}
}
}
}
return true;
}
/**
* After a texture is created, any state which was altered during its creation
* needs to be restored.
*
* @param interface The GL interface to use.
* @param caps The capabilities of the GL device.
* @param restoreGLRowLength Should the row length unpacking be restored?
* @param glFlipY Did GL flip the texture vertically?
*/
static void restore_pixelstore_state(const GrGLInterface& interface, const GrGLCaps& caps,
bool restoreGLRowLength) {
if (restoreGLRowLength) {
SkASSERT(caps.writePixelsRowBytesSupport());
GR_GL_CALL(&interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
}
}
void GrGLGpu::unbindCpuToGpuXferBuffer() { void GrGLGpu::unbindCpuToGpuXferBuffer() {
auto* xferBufferState = this->hwBufferState(GrGpuBufferType::kXferCpuToGpu); auto* xferBufferState = this->hwBufferState(GrGpuBufferType::kXferCpuToGpu);
if (!xferBufferState->fBoundBufferUniqueID.isInvalid()) { if (!xferBufferState->fBoundBufferUniqueID.isInvalid()) {
@ -1113,11 +937,10 @@ void GrGLGpu::unbindCpuToGpuXferBuffer() {
} }
} }
bool GrGLGpu::uploadTexData(GrGLFormat textureFormat, GrColorType textureColorType, bool GrGLGpu::uploadTexData(GrGLFormat textureFormat, GrColorType textureColorType, int texWidth,
int texWidth, int texHeight, GrGLenum target, UploadType uploadType, int texHeight, GrGLenum target, int left, int top, int width,
int left, int top, int width, int height, GrColorType srcColorType, int height, GrColorType srcColorType, const GrMipLevel texels[],
const GrMipLevel texels[],int mipLevelCount, int mipLevelCount, GrMipMapsStatus* mipMapsStatus) {
GrMipMapsStatus* mipMapsStatus) {
// If we're uploading compressed data then we should be using uploadCompressedTexData // If we're uploading compressed data then we should be using uploadCompressedTexData
SkASSERT(!GrGLFormatIsCompressed(textureFormat)); SkASSERT(!GrGLFormatIsCompressed(textureFormat));
@ -1141,19 +964,15 @@ bool GrGLGpu::uploadTexData(GrGLFormat textureFormat, GrColorType textureColorTy
return false; return false;
} }
// Internal format comes from the texture desc.
GrGLenum internalFormat;
// External format and type come from the upload data. // External format and type come from the upload data.
GrGLenum externalFormat; GrGLenum externalFormat;
GrGLenum externalType; GrGLenum externalType;
this->glCaps().getTexImageFormats(textureFormat, textureColorType, srcColorType, this->glCaps().getTexSubImageExternalFormatAndType(
&internalFormat, &externalFormat, &externalType); textureFormat, textureColorType, srcColorType, &externalFormat, &externalType);
if (!externalFormat || !externalType) { if (!externalFormat || !externalType) {
return false; return false;
} }
GrGLenum internalFormatForTexStorage = this->glCaps().getSizedInternalFormat(textureFormat);
/* /*
* Check whether to allocate a temporary buffer for flipping y or * Check whether to allocate a temporary buffer for flipping y or
* because our srcData has extra bytes past each row. If so, we need * because our srcData has extra bytes past each row. If so, we need
@ -1162,61 +981,40 @@ bool GrGLGpu::uploadTexData(GrGLFormat textureFormat, GrColorType textureColorTy
*/ */
bool restoreGLRowLength = false; bool restoreGLRowLength = false;
// in case we need a temporary, trimmed copy of the src pixels
SkAutoSMalloc<128 * 128> tempStorage;
if (mipMapsStatus) { if (mipMapsStatus) {
*mipMapsStatus = (mipLevelCount > 1) ? *mipMapsStatus = (mipLevelCount > 1) ?
GrMipMapsStatus::kValid : GrMipMapsStatus::kNotAllocated; GrMipMapsStatus::kValid : GrMipMapsStatus::kNotAllocated;
} }
if (mipLevelCount) { GR_GL_CALL(interface, PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1));
GR_GL_CALL(interface, PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1));
}
bool succeeded = true; for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
if (kNewTexture_UploadType == uploadType) { if (!texels[currentMipLevel].fPixels) {
if (0 == left && 0 == top && texWidth == width && texHeight == height) { if (mipMapsStatus) {
succeeded = allocate_and_populate_texture( *mipMapsStatus = GrMipMapsStatus::kDirty;
textureFormat, *interface, caps, target, internalFormat,
internalFormatForTexStorage, externalFormat, externalType, bpp, texels,
mipLevelCount, width, height, &restoreGLRowLength, mipMapsStatus);
} else {
succeeded = false;
}
} else {
for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
if (!texels[currentMipLevel].fPixels) {
if (mipMapsStatus) {
*mipMapsStatus = GrMipMapsStatus::kDirty;
}
continue;
} }
int twoToTheMipLevel = 1 << currentMipLevel; continue;
const int currentWidth = SkTMax(1, width / twoToTheMipLevel);
const int currentHeight = SkTMax(1, height / twoToTheMipLevel);
const size_t trimRowBytes = currentWidth * bpp;
const size_t rowBytes = texels[currentMipLevel].fRowBytes;
if (caps.writePixelsRowBytesSupport() && rowBytes != trimRowBytes) {
GrGLint rowLength = static_cast<GrGLint>(rowBytes / bpp);
GR_GL_CALL(interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength));
restoreGLRowLength = true;
}
GL_CALL(TexSubImage2D(target,
currentMipLevel,
left, top,
currentWidth,
currentHeight,
externalFormat, externalType,
texels[currentMipLevel].fPixels));
} }
int twoToTheMipLevel = 1 << currentMipLevel;
const int currentWidth = SkTMax(1, width / twoToTheMipLevel);
const int currentHeight = SkTMax(1, height / twoToTheMipLevel);
const size_t trimRowBytes = currentWidth * bpp;
const size_t rowBytes = texels[currentMipLevel].fRowBytes;
if (caps.writePixelsRowBytesSupport() && (rowBytes != trimRowBytes || restoreGLRowLength)) {
GrGLint rowLength = static_cast<GrGLint>(rowBytes / bpp);
GR_GL_CALL(interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength));
restoreGLRowLength = true;
}
GL_CALL(TexSubImage2D(target, currentMipLevel, left, top, currentWidth, currentHeight,
externalFormat, externalType, texels[currentMipLevel].fPixels));
} }
if (restoreGLRowLength) {
restore_pixelstore_state(*interface, caps, restoreGLRowLength); SkASSERT(caps.writePixelsRowBytesSupport());
GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
return succeeded; }
return true;
} }
bool GrGLGpu::uploadCompressedTexData(GrGLFormat format, bool GrGLGpu::uploadCompressedTexData(GrGLFormat format,
@ -1228,7 +1026,7 @@ bool GrGLGpu::uploadCompressedTexData(GrGLFormat format,
const GrGLCaps& caps = this->glCaps(); const GrGLCaps& caps = this->glCaps();
// We only need the internal format for compressed 2D textures. // We only need the internal format for compressed 2D textures.
GrGLenum internalFormat = caps.getTexImageInternalFormat(format); GrGLenum internalFormat = caps.getTexImageOrStorageInternalFormat(format);
if (!internalFormat) { if (!internalFormat) {
return 0; return 0;
} }
@ -1427,16 +1225,17 @@ sk_sp<GrTexture> GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc,
int renderTargetSampleCnt, int renderTargetSampleCnt,
SkBudgeted budgeted, SkBudgeted budgeted,
GrProtected isProtected, GrProtected isProtected,
const GrMipLevel texels[], int mipLevelCount,
int mipLevelCount) { uint32_t levelClearMask) {
// We don't support protected textures in GL. // We don't support protected textures in GL.
if (isProtected == GrProtected::kYes) { if (isProtected == GrProtected::kYes) {
return nullptr; return nullptr;
} }
SkASSERT(GrGLCaps::kNone_MSFBOType != this->glCaps().msFBOType() || renderTargetSampleCnt == 1); SkASSERT(GrGLCaps::kNone_MSFBOType != this->glCaps().msFBOType() || renderTargetSampleCnt == 1);
SkASSERT(mipLevelCount > 0);
GrMipMapsStatus mipMapsStatus; GrMipMapsStatus mipMapsStatus =
mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
GrGLTextureParameters::SamplerOverriddenState initialState; GrGLTextureParameters::SamplerOverriddenState initialState;
GrGLTexture::Desc texDesc; GrGLTexture::Desc texDesc;
texDesc.fSize = {desc.fWidth, desc.fHeight}; texDesc.fSize = {desc.fWidth, desc.fHeight};
@ -1447,18 +1246,8 @@ sk_sp<GrTexture> GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc,
SkASSERT(texDesc.fFormat != GrGLFormat::kUnknown); SkASSERT(texDesc.fFormat != GrGLFormat::kUnknown);
SkASSERT(!GrGLFormatIsCompressed(texDesc.fFormat)); SkASSERT(!GrGLFormatIsCompressed(texDesc.fFormat));
// TODO: Take these as parameters. texDesc.fID = this->createTexture2D({desc.fWidth, desc.fHeight}, texDesc.fFormat, renderable,
auto textureColorType = GrPixelConfigToColorType(desc.fConfig); &initialState, mipLevelCount);
auto srcColorType = GrPixelConfigToColorType(desc.fConfig);
texDesc.fID = this->createTexture2D({desc.fWidth, desc.fHeight},
texDesc.fFormat,
renderable,
&initialState,
textureColorType,
srcColorType,
texels,
mipLevelCount,
&mipMapsStatus);
if (!texDesc.fID) { if (!texDesc.fID) {
return return_null_texture(); return return_null_texture();
@ -1483,16 +1272,49 @@ sk_sp<GrTexture> GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc,
// The non-sampler params are still at their default values. // The non-sampler params are still at their default values.
tex->parameters()->set(&initialState, GrGLTextureParameters::NonsamplerState(), tex->parameters()->set(&initialState, GrGLTextureParameters::NonsamplerState(),
fResetTimestampForTextureParameters); fResetTimestampForTextureParameters);
bool clearLevelsWithoutData = if (levelClearMask) {
this->caps()->shouldInitializeTextures() && this->glCaps().clearTextureSupport(); GrGLenum externalFormat, externalType;
size_t bpp;
if (clearLevelsWithoutData) { this->glCaps().getTexSubImageZeroFormatTypeAndBpp(texDesc.fFormat, &externalFormat,
static constexpr uint32_t kZero = 0; &externalType, &bpp);
int levelCnt = SkTMax(1, tex->texturePriv().maxMipMapLevel()); if (this->glCaps().clearTextureSupport()) {
for (int i = 0; i < levelCnt; ++i) { for (int i = 0; i < mipLevelCount; ++i) {
if (i >= mipLevelCount || !texels[i].fPixels) { if (levelClearMask & (1U << i)) {
GL_CALL(ClearTexImage(tex->textureID(), i, GR_GL_RGBA, GR_GL_UNSIGNED_BYTE, GL_CALL(ClearTexImage(tex->textureID(), i, externalFormat, externalType,
&kZero)); nullptr));
}
}
} else if (this->glCaps().canFormatBeFBOColorAttachment(format.asGLFormat()) &&
!this->glCaps().performColorClearsAsDraws()) {
this->disableScissor();
this->disableWindowRectangles();
this->flushColorWrite(true);
this->flushClearColor(0, 0, 0, 0);
for (int i = 0; i < mipLevelCount; ++i) {
if (levelClearMask & (1U << i)) {
this->bindSurfaceFBOForPixelOps(tex.get(), i, GR_GL_FRAMEBUFFER,
kDst_TempFBOTarget);
GL_CALL(Clear(GR_GL_COLOR_BUFFER_BIT));
this->unbindSurfaceFBOForPixelOps(tex.get(), i, GR_GL_FRAMEBUFFER);
}
}
} else {
std::unique_ptr<char[]> zeros;
GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1));
for (int i = 0; i < mipLevelCount; ++i) {
if (levelClearMask & (1U << i)) {
int levelWidth = SkTMax(1, texDesc.fSize.width() >> i);
int levelHeight = SkTMax(1, texDesc.fSize.height() >> i);
// Levels only get smaller as we proceed. Once we create a zeros use it for all
// smaller levels that need clearing.
if (!zeros) {
size_t size = levelWidth * levelHeight * bpp;
zeros.reset(new char[size]());
}
this->bindTextureToScratchUnit(GR_GL_TEXTURE_2D, tex->textureID());
GL_CALL(TexSubImage2D(GR_GL_TEXTURE_2D, i, 0, 0, levelWidth, levelHeight,
externalFormat, externalType, zeros.get()));
}
} }
} }
} }
@ -1556,46 +1378,11 @@ int GrGLGpu::getCompatibleStencilIndex(GrGLFormat format) {
// Default to unsupported, set this if we find a stencil format that works. // Default to unsupported, set this if we find a stencil format that works.
int firstWorkingStencilFormatIndex = -1; int firstWorkingStencilFormatIndex = -1;
// Create color texture GrGLuint colorID =
GrGLuint colorID = 0; this->createTexture2D({kSize, kSize}, format, GrRenderable::kYes, nullptr, 1);
GL_CALL(GenTextures(1, &colorID)); if (!colorID) {
this->bindTextureToScratchUnit(GR_GL_TEXTURE_2D, colorID);
GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
GR_GL_TEXTURE_MAG_FILTER,
GR_GL_NEAREST));
GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
GR_GL_TEXTURE_MIN_FILTER,
GR_GL_NEAREST));
GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
GR_GL_TEXTURE_WRAP_S,
GR_GL_CLAMP_TO_EDGE));
GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
GR_GL_TEXTURE_WRAP_T,
GR_GL_CLAMP_TO_EDGE));
GrGLenum internalFormat = this->glCaps().getTexImageInternalFormat(format);
GrGLenum externalFormat = this->glCaps().getBaseInternalFormat(format);
GrGLenum externalType = this->glCaps().getFormatDefaultExternalType(format);
if (!internalFormat || !externalFormat || !externalType) {
return -1; return -1;
} }
this->unbindCpuToGpuXferBuffer();
CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
GL_ALLOC_CALL(this->glInterface(), TexImage2D(GR_GL_TEXTURE_2D,
0,
internalFormat,
kSize,
kSize,
0,
externalFormat,
externalType,
nullptr));
if (GR_GL_NO_ERROR != CHECK_ALLOC_ERROR(this->glInterface())) {
GL_CALL(DeleteTextures(1, &colorID));
return -1;
}
// unbind the texture from the texture unit before binding it to the frame buffer // unbind the texture from the texture unit before binding it to the frame buffer
GL_CALL(BindTexture(GR_GL_TEXTURE_2D, 0)); GL_CALL(BindTexture(GR_GL_TEXTURE_2D, 0));
@ -1691,11 +1478,7 @@ GrGLuint GrGLGpu::createTexture2D(const SkISize& size,
GrGLFormat format, GrGLFormat format,
GrRenderable renderable, GrRenderable renderable,
GrGLTextureParameters::SamplerOverriddenState* initialState, GrGLTextureParameters::SamplerOverriddenState* initialState,
GrColorType textureColorType, int mipLevelCount) {
GrColorType srcColorType,
const GrMipLevel texels[],
int mipLevelCount,
GrMipMapsStatus* mipMapsStatus) {
SkASSERT(format != GrGLFormat::kUnknown); SkASSERT(format != GrGLFormat::kUnknown);
SkASSERT(!GrGLFormatIsCompressed(format)); SkASSERT(!GrGLFormatIsCompressed(format));
@ -1713,25 +1496,46 @@ GrGLuint GrGLGpu::createTexture2D(const SkISize& size,
GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_USAGE, GR_GL_FRAMEBUFFER_ATTACHMENT)); GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_USAGE, GR_GL_FRAMEBUFFER_ATTACHMENT));
} }
*initialState = set_initial_texture_params(this->glInterface(), GR_GL_TEXTURE_2D); if (initialState) {
*initialState = set_initial_texture_params(this->glInterface(), GR_GL_TEXTURE_2D);
if (!this->uploadTexData(format, } else {
textureColorType, set_initial_texture_params(this->glInterface(), GR_GL_TEXTURE_2D);
size.width(), size.height(),
GR_GL_TEXTURE_2D,
kNewTexture_UploadType,
0,
0,
size.width(),
size.height(),
srcColorType,
texels,
mipLevelCount,
mipMapsStatus)) {
GL_CALL(DeleteTextures(1, &id));
return 0;
} }
return id;
GrGLenum internalFormat = this->glCaps().getTexImageOrStorageInternalFormat(format);
bool success = false;
if (internalFormat) {
CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
if (this->glCaps().formatSupportsTexStorage(format)) {
GL_ALLOC_CALL(this->glInterface(),
TexStorage2D(GR_GL_TEXTURE_2D, SkTMax(mipLevelCount, 1), internalFormat,
size.width(), size.height()));
success = (GR_GL_NO_ERROR == CHECK_ALLOC_ERROR(this->glInterface()));
} else {
GrGLenum externalFormat, externalType;
this->glCaps().getTexImageExternalFormatAndType(format, &externalFormat, &externalType);
GrGLenum error = GR_GL_NO_ERROR;
if (externalFormat && externalType) {
for (int level = 0; level < mipLevelCount && error == GR_GL_NO_ERROR; level++) {
const int twoToTheMipLevel = 1 << level;
const int currentWidth = SkTMax(1, size.width() / twoToTheMipLevel);
const int currentHeight = SkTMax(1, size.height() / twoToTheMipLevel);
GL_ALLOC_CALL(
this->glInterface(),
TexImage2D(GR_GL_TEXTURE_2D, level, internalFormat, currentWidth,
currentHeight, 0, externalFormat, externalType, nullptr));
error = CHECK_ALLOC_ERROR(this->glInterface());
}
success = (GR_GL_NO_ERROR == error);
}
}
}
if (success) {
return id;
}
GL_CALL(DeleteTextures(1, &id));
return 0;
} }
GrStencilAttachment* GrGLGpu::createStencilAttachmentForRenderTarget( GrStencilAttachment* GrGLGpu::createStencilAttachmentForRenderTarget(
@ -2161,7 +1965,7 @@ bool GrGLGpu::readOrTransferPixelsFrom(GrSurface* surface, int left, int top, in
} }
} else { } else {
// Use a temporary FBO. // Use a temporary FBO.
this->bindSurfaceFBOForPixelOps(surface, GR_GL_FRAMEBUFFER, kSrc_TempFBOTarget); this->bindSurfaceFBOForPixelOps(surface, 0, GR_GL_FRAMEBUFFER, kSrc_TempFBOTarget);
fHWBoundRenderTargetUniqueID.makeInvalid(); fHWBoundRenderTargetUniqueID.makeInvalid();
} }
@ -2202,7 +2006,7 @@ bool GrGLGpu::readOrTransferPixelsFrom(GrSurface* surface, int left, int top, in
} }
if (!renderTarget) { if (!renderTarget) {
this->unbindTextureFBOForPixelOps(GR_GL_FRAMEBUFFER, surface); this->unbindSurfaceFBOForPixelOps(surface, 0, GR_GL_FRAMEBUFFER);
} }
return true; return true;
} }
@ -3015,10 +2819,10 @@ static inline bool can_copy_texsubimage(const GrSurface* dst, const GrSurface* s
} }
// If a temporary FBO was created, its non-zero ID is returned. // If a temporary FBO was created, its non-zero ID is returned.
void GrGLGpu::bindSurfaceFBOForPixelOps(GrSurface* surface, GrGLenum fboTarget, void GrGLGpu::bindSurfaceFBOForPixelOps(GrSurface* surface, int mipLevel, GrGLenum fboTarget,
TempFBOTarget tempFBOTarget) { TempFBOTarget tempFBOTarget) {
GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(surface->asRenderTarget()); GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(surface->asRenderTarget());
if (!rt) { if (!rt || mipLevel > 0) {
SkASSERT(surface->asTexture()); SkASSERT(surface->asTexture());
GrGLTexture* texture = static_cast<GrGLTexture*>(surface->asTexture()); GrGLTexture* texture = static_cast<GrGLTexture*>(surface->asTexture());
GrGLuint texID = texture->textureID(); GrGLuint texID = texture->textureID();
@ -3031,20 +2835,20 @@ void GrGLGpu::bindSurfaceFBOForPixelOps(GrSurface* surface, GrGLenum fboTarget,
} }
this->bindFramebuffer(fboTarget, *tempFBOID); this->bindFramebuffer(fboTarget, *tempFBOID);
GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget, GR_GL_CALL(
GR_GL_COLOR_ATTACHMENT0, this->glInterface(),
target, FramebufferTexture2D(fboTarget, GR_GL_COLOR_ATTACHMENT0, target, texID, mipLevel));
texID, if (mipLevel == 0) {
0)); texture->baseLevelWasBoundToFBO();
texture->baseLevelWasBoundToFBO(); }
} else { } else {
this->bindFramebuffer(fboTarget, rt->renderFBOID()); this->bindFramebuffer(fboTarget, rt->renderFBOID());
} }
} }
void GrGLGpu::unbindTextureFBOForPixelOps(GrGLenum fboTarget, GrSurface* surface) { void GrGLGpu::unbindSurfaceFBOForPixelOps(GrSurface* surface, int mipLevel, GrGLenum fboTarget) {
// bindSurfaceFBOForPixelOps temporarily binds textures that are not render targets to // bindSurfaceFBOForPixelOps temporarily binds textures that are not render targets to
if (!surface->asRenderTarget()) { if (mipLevel > 0 || !surface->asRenderTarget()) {
SkASSERT(surface->asTexture()); SkASSERT(surface->asTexture());
GrGLenum textureTarget = static_cast<GrGLTexture*>(surface->asTexture())->target(); GrGLenum textureTarget = static_cast<GrGLTexture*>(surface->asTexture())->target();
GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget, GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget,
@ -3426,7 +3230,7 @@ bool GrGLGpu::copySurfaceAsDraw(GrSurface* dst, GrSurface* src, const SkIRect& s
int h = srcRect.height(); int h = srcRect.height();
// We don't swizzle at all in our copies. // We don't swizzle at all in our copies.
this->bindTexture(0, GrSamplerState::ClampNearest(), GrSwizzle::RGBA(), srcTex); this->bindTexture(0, GrSamplerState::ClampNearest(), GrSwizzle::RGBA(), srcTex);
this->bindSurfaceFBOForPixelOps(dst, GR_GL_FRAMEBUFFER, kDst_TempFBOTarget); this->bindSurfaceFBOForPixelOps(dst, 0, GR_GL_FRAMEBUFFER, kDst_TempFBOTarget);
this->flushViewport(dst->width(), dst->height()); this->flushViewport(dst->width(), dst->height());
fHWBoundRenderTargetUniqueID.makeInvalid(); fHWBoundRenderTargetUniqueID.makeInvalid();
SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, w, h); SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, w, h);
@ -3469,7 +3273,7 @@ bool GrGLGpu::copySurfaceAsDraw(GrSurface* dst, GrSurface* src, const SkIRect& s
this->flushFramebufferSRGB(true); this->flushFramebufferSRGB(true);
} }
GL_CALL(DrawArrays(GR_GL_TRIANGLE_STRIP, 0, 4)); GL_CALL(DrawArrays(GR_GL_TRIANGLE_STRIP, 0, 4));
this->unbindTextureFBOForPixelOps(GR_GL_FRAMEBUFFER, dst); this->unbindSurfaceFBOForPixelOps(dst, 0, GR_GL_FRAMEBUFFER);
// The rect is already in device space so we pass in kTopLeft so no flip is done. // The rect is already in device space so we pass in kTopLeft so no flip is done.
this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect); this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
return true; return true;
@ -3478,7 +3282,7 @@ bool GrGLGpu::copySurfaceAsDraw(GrSurface* dst, GrSurface* src, const SkIRect& s
void GrGLGpu::copySurfaceAsCopyTexSubImage(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, void GrGLGpu::copySurfaceAsCopyTexSubImage(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
const SkIPoint& dstPoint) { const SkIPoint& dstPoint) {
SkASSERT(can_copy_texsubimage(dst, src, this->glCaps())); SkASSERT(can_copy_texsubimage(dst, src, this->glCaps()));
this->bindSurfaceFBOForPixelOps(src, GR_GL_FRAMEBUFFER, kSrc_TempFBOTarget); this->bindSurfaceFBOForPixelOps(src, 0, GR_GL_FRAMEBUFFER, kSrc_TempFBOTarget);
GrGLTexture* dstTex = static_cast<GrGLTexture *>(dst->asTexture()); GrGLTexture* dstTex = static_cast<GrGLTexture *>(dst->asTexture());
SkASSERT(dstTex); SkASSERT(dstTex);
// We modified the bound FBO // We modified the bound FBO
@ -3489,7 +3293,7 @@ void GrGLGpu::copySurfaceAsCopyTexSubImage(GrSurface* dst, GrSurface* src, const
dstPoint.fX, dstPoint.fY, dstPoint.fX, dstPoint.fY,
srcRect.fLeft, srcRect.fTop, srcRect.fLeft, srcRect.fTop,
srcRect.width(), srcRect.height())); srcRect.width(), srcRect.height()));
this->unbindTextureFBOForPixelOps(GR_GL_FRAMEBUFFER, src); this->unbindSurfaceFBOForPixelOps(src, 0, GR_GL_FRAMEBUFFER);
SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
srcRect.width(), srcRect.height()); srcRect.width(), srcRect.height());
// The rect is already in device space so we pass in kTopLeft so no flip is done. // The rect is already in device space so we pass in kTopLeft so no flip is done.
@ -3507,8 +3311,8 @@ bool GrGLGpu::copySurfaceAsBlitFramebuffer(GrSurface* dst, GrSurface* src, const
} }
} }
this->bindSurfaceFBOForPixelOps(dst, GR_GL_DRAW_FRAMEBUFFER, kDst_TempFBOTarget); this->bindSurfaceFBOForPixelOps(dst, 0, GR_GL_DRAW_FRAMEBUFFER, kDst_TempFBOTarget);
this->bindSurfaceFBOForPixelOps(src, GR_GL_READ_FRAMEBUFFER, kSrc_TempFBOTarget); this->bindSurfaceFBOForPixelOps(src, 0, GR_GL_READ_FRAMEBUFFER, kSrc_TempFBOTarget);
// We modified the bound FBO // We modified the bound FBO
fHWBoundRenderTargetUniqueID.makeInvalid(); fHWBoundRenderTargetUniqueID.makeInvalid();
@ -3525,8 +3329,8 @@ bool GrGLGpu::copySurfaceAsBlitFramebuffer(GrSurface* dst, GrSurface* src, const
dstRect.fRight, dstRect.fRight,
dstRect.fBottom, dstRect.fBottom,
GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST)); GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
this->unbindTextureFBOForPixelOps(GR_GL_DRAW_FRAMEBUFFER, dst); this->unbindSurfaceFBOForPixelOps(dst, 0, GR_GL_DRAW_FRAMEBUFFER);
this->unbindTextureFBOForPixelOps(GR_GL_READ_FRAMEBUFFER, src); this->unbindSurfaceFBOForPixelOps(src, 0, GR_GL_READ_FRAMEBUFFER);
// The rect is already in device space so we pass in kTopLeft so no flip is done. // The rect is already in device space so we pass in kTopLeft so no flip is done.
this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect); this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
@ -3764,8 +3568,7 @@ GrBackendTexture GrGLGpu::createBackendTexture(int w, int h,
GrGLTextureInfo info; GrGLTextureInfo info;
GrGLTextureParameters::SamplerOverriddenState initialState; GrGLTextureParameters::SamplerOverriddenState initialState;
int mipLevelCount = 0; SkTDArray<GrMipLevel> texels;
SkAutoTMalloc<GrMipLevel> texels;
SkAutoMalloc pixelStorage; SkAutoMalloc pixelStorage;
SkImage::CompressionType compressionType; SkImage::CompressionType compressionType;
if (GrGLFormatToCompressionType(glFormat, &compressionType)) { if (GrGLFormatToCompressionType(glFormat, &compressionType)) {
@ -3791,16 +3594,15 @@ GrBackendTexture GrGLGpu::createBackendTexture(int w, int h,
info.fTarget = GR_GL_TEXTURE_2D; info.fTarget = GR_GL_TEXTURE_2D;
} else { } else {
if (srcPixels) { if (srcPixels) {
mipLevelCount = 1; texels.append(1);
texels.reset(mipLevelCount); texels[0] = {srcPixels, rowBytes};
texels.get()[0] = {srcPixels, rowBytes};
} else if (color) { } else if (color) {
mipLevelCount = 1; int mipLevelCount = 1;
if (GrMipMapped::kYes == mipMapped) { if (GrMipMapped::kYes == mipMapped) {
mipLevelCount = SkMipMap::ComputeLevelCount(w, h) + 1; mipLevelCount = SkMipMap::ComputeLevelCount(w, h) + 1;
} }
texels.reset(mipLevelCount); texels.append(mipLevelCount);
SkTArray<size_t> individualMipOffsets(mipLevelCount); SkTArray<size_t> individualMipOffsets(mipLevelCount);
size_t bytesPerPixel = GrBytesPerPixel(config); size_t bytesPerPixel = GrBytesPerPixel(config);
@ -3817,7 +3619,7 @@ GrBackendTexture GrGLGpu::createBackendTexture(int w, int h,
int twoToTheMipLevel = 1 << i; int twoToTheMipLevel = 1 << i;
int currentWidth = SkTMax(1, w / twoToTheMipLevel); int currentWidth = SkTMax(1, w / twoToTheMipLevel);
texels.get()[i] = {&(tmpPixels[offset]), currentWidth * bytesPerPixel}; texels[i] = {&(tmpPixels[offset]), currentWidth * bytesPerPixel};
} }
} }
GrSurfaceDesc desc; GrSurfaceDesc desc;
@ -3827,20 +3629,19 @@ GrBackendTexture GrGLGpu::createBackendTexture(int w, int h,
info.fTarget = GR_GL_TEXTURE_2D; info.fTarget = GR_GL_TEXTURE_2D;
info.fFormat = GrGLFormatToEnum(glFormat); info.fFormat = GrGLFormatToEnum(glFormat);
// TODO: Take these as parameters. info.fID = this->createTexture2D({desc.fWidth, desc.fHeight}, glFormat, renderable,
auto srcColorType = GrPixelConfigToColorType(desc.fConfig); &initialState, SkTMax(1, texels.count()));
info.fID = this->createTexture2D({desc.fWidth, desc.fHeight},
glFormat,
renderable,
&initialState,
textureColorType,
srcColorType,
texels,
mipLevelCount,
nullptr);
if (!info.fID) { if (!info.fID) {
return GrBackendTexture(); // invalid return GrBackendTexture(); // invalid
} }
auto srcColorType = GrPixelConfigToColorType(desc.fConfig);
if (!texels.empty() &&
!this->uploadTexData(glFormat, textureColorType, desc.fWidth, desc.fHeight,
GR_GL_TEXTURE_2D, 0, 0, desc.fWidth, desc.fHeight, srcColorType,
texels.begin(), texels.count())) {
GL_CALL(DeleteTextures(1, &info.fID));
return GrBackendTexture();
}
} }
// unbind the texture from the texture unit to avoid asserts // unbind the texture from the texture unit to avoid asserts
@ -3888,17 +3689,7 @@ GrBackendRenderTarget GrGLGpu::createTestingOnlyBackendRenderTarget(int w, int h
if (!this->glCaps().isFormatRenderable(format, 1)) { if (!this->glCaps().isFormatRenderable(format, 1)) {
return {}; return {};
} }
bool useTexture = false; bool useTexture = format == GrGLFormat::kBGRA8;
GrGLenum colorBufferFormat;
GrGLenum externalFormat = 0, externalType = 0;
if (format == GrGLFormat::kBGRA8) {
// BGRA render buffers are not supported.
this->glCaps().getTexImageFormats(format, colorType, colorType, &colorBufferFormat,
&externalFormat, &externalType);
useTexture = true;
} else {
colorBufferFormat = this->glCaps().getRenderbufferInternalFormat(format);
}
int sFormatIdx = this->getCompatibleStencilIndex(format); int sFormatIdx = this->getCompatibleStencilIndex(format);
if (sFormatIdx < 0) { if (sFormatIdx < 0) {
return {}; return {};
@ -3931,7 +3722,7 @@ GrBackendRenderTarget GrGLGpu::createTestingOnlyBackendRenderTarget(int w, int h
GrGLFramebufferInfo info; GrGLFramebufferInfo info;
info.fFBOID = 0; info.fFBOID = 0;
info.fFormat = this->glCaps().formatSizedInternalFormat(format); info.fFormat = GrGLFormatToEnum(format);
GL_CALL(GenFramebuffers(1, &info.fFBOID)); GL_CALL(GenFramebuffers(1, &info.fFBOID));
if (!info.fFBOID) { if (!info.fFBOID) {
deleteIDs(); deleteIDs();
@ -3942,15 +3733,19 @@ GrBackendRenderTarget GrGLGpu::createTestingOnlyBackendRenderTarget(int w, int h
this->bindFramebuffer(GR_GL_FRAMEBUFFER, info.fFBOID); this->bindFramebuffer(GR_GL_FRAMEBUFFER, info.fFBOID);
if (useTexture) { if (useTexture) {
this->bindTextureToScratchUnit(GR_GL_TEXTURE_2D, colorID); GrGLTextureParameters::SamplerOverriddenState initialState;
GL_CALL(TexImage2D(GR_GL_TEXTURE_2D, 0, colorBufferFormat, w, h, 0, externalFormat, colorID = this->createTexture2D({w, h}, format, GrRenderable::kYes, &initialState, 1);
externalType, nullptr)); if (!colorID) {
deleteIDs();
return {};
}
GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0, GR_GL_TEXTURE_2D, GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0, GR_GL_TEXTURE_2D,
colorID, 0)); colorID, 0));
} else { } else {
GrGLenum renderBufferFormat = this->glCaps().getRenderbufferInternalFormat(format);
GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, colorID)); GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, colorID));
GL_ALLOC_CALL(this->glInterface(), GL_ALLOC_CALL(this->glInterface(),
RenderbufferStorage(GR_GL_RENDERBUFFER, colorBufferFormat, w, h)); RenderbufferStorage(GR_GL_RENDERBUFFER, renderBufferFormat, w, h));
GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0, GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0,
GR_GL_RENDERBUFFER, colorID)); GR_GL_RENDERBUFFER, colorID));
} }

View File

@ -195,8 +195,8 @@ private:
int renderTargetSampleCnt, int renderTargetSampleCnt,
SkBudgeted, SkBudgeted,
GrProtected, GrProtected,
const GrMipLevel[], int mipLevelCount,
int mipLevelCount) override; uint32_t levelClearMask) override;
sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, const GrBackendFormat&, sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, const GrBackendFormat&,
SkImage::CompressionType compression, SkBudgeted, SkImage::CompressionType compression, SkBudgeted,
const void* data) override; const void* data) override;
@ -228,11 +228,7 @@ private:
GrGLFormat format, GrGLFormat format,
GrRenderable, GrRenderable,
GrGLTextureParameters::SamplerOverriddenState* initialState, GrGLTextureParameters::SamplerOverriddenState* initialState,
GrColorType textureColorType, int mipLevelCount);
GrColorType srcColorType,
const GrMipLevel texels[],
int mipLevelCount,
GrMipMapsStatus* mipMapsStatus);
GrGLuint createCompressedTexture2D(const SkISize& size, GrGLFormat format, GrGLuint createCompressedTexture2D(const SkISize& size, GrGLFormat format,
SkImage::CompressionType compression, SkImage::CompressionType compression,
@ -377,15 +373,9 @@ private:
void flushFramebufferSRGB(bool enable); void flushFramebufferSRGB(bool enable);
// helper for onCreateTexture and writeTexturePixels bool uploadTexData(GrGLFormat textureFormat, GrColorType textureColorType, int texWidth,
enum UploadType { int texHeight, GrGLenum target, int left, int top, int width, int height,
kNewTexture_UploadType, // we are creating a new texture GrColorType srcColorType, const GrMipLevel texels[], int mipLevelCount,
kWrite_UploadType, // we are using TexSubImage2D to copy data to an existing texture
};
bool uploadTexData(GrGLFormat textureFormat, GrColorType textureColorType,
int texWidth, int texHeight, GrGLenum target, UploadType uploadType,
int left, int top, int width, int height, GrColorType srcColorType,
const GrMipLevel texels[], int mipLevelCount,
GrMipMapsStatus* mipMapsStatus = nullptr); GrMipMapsStatus* mipMapsStatus = nullptr);
// Helper for onCreateCompressedTexture. Compressed textures are read-only so we only use this // Helper for onCreateCompressedTexture. Compressed textures are read-only so we only use this
@ -408,11 +398,11 @@ private:
// Binds a surface as a FBO for copying, reading, or clearing. If the surface already owns an // 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 // 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(). // is bound. This must be paired with a call to unbindSurfaceFBOForPixelOps().
void bindSurfaceFBOForPixelOps(GrSurface* surface, GrGLenum fboTarget, void bindSurfaceFBOForPixelOps(GrSurface* surface, int mipLevel, GrGLenum fboTarget,
TempFBOTarget tempFBOTarget); TempFBOTarget tempFBOTarget);
// Must be called if bindSurfaceFBOForPixelOps was used to bind a surface for copying. // Must be called if bindSurfaceFBOForPixelOps was used to bind a surface for copying.
void unbindTextureFBOForPixelOps(GrGLenum fboTarget, GrSurface* surface); void unbindSurfaceFBOForPixelOps(GrSurface* surface, int mipLevel, GrGLenum fboTarget);
#ifdef SK_ENABLE_DUMP_GPU #ifdef SK_ENABLE_DUMP_GPU
void onDumpJSON(SkJSONWriter*) const override; void onDumpJSON(SkJSONWriter*) const override;

View File

@ -132,8 +132,6 @@ public:
return {}; return {};
} }
bool canClearTextureOnCreation() const override { return true; }
GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override { GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override {
return GrSwizzle(); return GrSwizzle();
} }

View File

@ -137,8 +137,8 @@ sk_sp<GrTexture> GrMockGpu::onCreateTexture(const GrSurfaceDesc& desc,
int renderTargetSampleCnt, int renderTargetSampleCnt,
SkBudgeted budgeted, SkBudgeted budgeted,
GrProtected isProtected, GrProtected isProtected,
const GrMipLevel texels[], int mipLevelCount,
int mipLevelCount) { uint32_t levelClearMask) {
if (fMockOptions.fFailTextureAllocations) { if (fMockOptions.fFailTextureAllocations) {
return nullptr; return nullptr;
} }
@ -146,14 +146,8 @@ sk_sp<GrTexture> GrMockGpu::onCreateTexture(const GrSurfaceDesc& desc,
GrColorType ct = format.asMockColorType(); GrColorType ct = format.asMockColorType();
SkASSERT(ct != GrColorType::kUnknown); SkASSERT(ct != GrColorType::kUnknown);
GrMipMapsStatus mipMapsStatus = mipLevelCount > 1 ? GrMipMapsStatus::kValid GrMipMapsStatus mipMapsStatus =
: GrMipMapsStatus::kNotAllocated; mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
for (int i = 0; i < mipLevelCount; ++i) {
if (!texels[i].fPixels) {
mipMapsStatus = GrMipMapsStatus::kDirty;
break;
}
}
GrMockTextureInfo texInfo(ct, NextInternalTextureID()); GrMockTextureInfo texInfo(ct, NextInternalTextureID());
if (renderable == GrRenderable::kYes) { if (renderable == GrRenderable::kYes) {
GrMockRenderTargetInfo rtInfo(ct, NextInternalRenderTargetID()); GrMockRenderTargetInfo rtInfo(ct, NextInternalRenderTargetID());

View File

@ -63,8 +63,8 @@ private:
int renderTargetSampleCnt, int renderTargetSampleCnt,
SkBudgeted, SkBudgeted,
GrProtected, GrProtected,
const GrMipLevel[], int mipLevelCount,
int mipLevelCount) override; uint32_t levelClearMask) override;
sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, const GrBackendFormat&, sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, const GrBackendFormat&,
SkImage::CompressionType, SkBudgeted, SkImage::CompressionType, SkBudgeted,

View File

@ -78,8 +78,6 @@ public:
return fColorTypeToFormatTable[idx]; return fColorTypeToFormatTable[idx];
} }
bool canClearTextureOnCreation() const override { return true; }
GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override; GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override;
GrSwizzle getOutputSwizzle(const GrBackendFormat&, GrColorType) const override; GrSwizzle getOutputSwizzle(const GrBackendFormat&, GrColorType) const override;

View File

@ -139,8 +139,8 @@ private:
int renderTargetSampleCnt, int renderTargetSampleCnt,
SkBudgeted budgeted, SkBudgeted budgeted,
GrProtected, GrProtected,
const GrMipLevel texels[], int mipLevelCount,
int mipLevelCount) override; uint32_t levelClearMask) override;
sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, const GrBackendFormat&, sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, const GrBackendFormat&,
SkImage::CompressionType, SkBudgeted, SkImage::CompressionType, SkBudgeted,
const void* data) override { const void* data) override {

View File

@ -400,13 +400,13 @@ sk_sp<GrTexture> GrMtlGpu::onCreateTexture(const GrSurfaceDesc& desc,
int renderTargetSampleCnt, int renderTargetSampleCnt,
SkBudgeted budgeted, SkBudgeted budgeted,
GrProtected isProtected, GrProtected isProtected,
const GrMipLevel texels[], int mipLevelCount,
int mipLevelCount) { uint32_t levelClearMask) {
// We don't support protected textures in Metal. // We don't support protected textures in Metal.
if (isProtected == GrProtected::kYes) { if (isProtected == GrProtected::kYes) {
return nullptr; return nullptr;
} }
int mipLevels = !mipLevelCount ? 1 : mipLevelCount; SkASSERT(mipLevelCount > 0);
MTLPixelFormat mtlPixelFormat = GrBackendFormatAsMTLPixelFormat(format); MTLPixelFormat mtlPixelFormat = GrBackendFormatAsMTLPixelFormat(format);
SkASSERT(mtlPixelFormat != MTLPixelFormatInvalid); SkASSERT(mtlPixelFormat != MTLPixelFormatInvalid);
@ -422,7 +422,7 @@ sk_sp<GrTexture> GrMtlGpu::onCreateTexture(const GrSurfaceDesc& desc,
texDesc.width = desc.fWidth; texDesc.width = desc.fWidth;
texDesc.height = desc.fHeight; texDesc.height = desc.fHeight;
texDesc.depth = 1; texDesc.depth = 1;
texDesc.mipmapLevelCount = mipLevels; texDesc.mipmapLevelCount = mipLevelCount;
texDesc.sampleCount = 1; texDesc.sampleCount = 1;
texDesc.arrayLength = 1; texDesc.arrayLength = 1;
// Make all textures have private gpu only access. We can use transfer buffers or textures // Make all textures have private gpu only access. We can use transfer buffers or textures
@ -431,17 +431,8 @@ sk_sp<GrTexture> GrMtlGpu::onCreateTexture(const GrSurfaceDesc& desc,
texDesc.usage = MTLTextureUsageShaderRead; texDesc.usage = MTLTextureUsageShaderRead;
texDesc.usage |= (renderable == GrRenderable::kYes) ? MTLTextureUsageRenderTarget : 0; texDesc.usage |= (renderable == GrRenderable::kYes) ? MTLTextureUsageRenderTarget : 0;
GrMipMapsStatus mipMapsStatus = GrMipMapsStatus::kNotAllocated; GrMipMapsStatus mipMapsStatus =
if (mipLevels > 1) { mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
mipMapsStatus = GrMipMapsStatus::kValid;
for (int i = 0; i < mipLevels; ++i) {
if (!texels[i].fPixels) {
mipMapsStatus = GrMipMapsStatus::kDirty;
break;
}
}
}
if (renderable == GrRenderable::kYes) { if (renderable == GrRenderable::kYes) {
tex = GrMtlTextureRenderTarget::MakeNewTextureRenderTarget(this, budgeted, tex = GrMtlTextureRenderTarget::MakeNewTextureRenderTarget(this, budgeted,
desc, renderTargetSampleCnt, desc, renderTargetSampleCnt,
@ -454,24 +445,9 @@ sk_sp<GrTexture> GrMtlGpu::onCreateTexture(const GrSurfaceDesc& desc,
return nullptr; return nullptr;
} }
auto colorType = GrPixelConfigToColorType(desc.fConfig); if (levelClearMask) {
if (mipLevelCount && texels[0].fPixels) { auto colorType = GrPixelConfigToColorType(desc.fConfig);
if (!this->uploadToTexture(tex.get(), 0, 0, desc.fWidth, desc.fHeight, colorType, texels, this->clearTexture(tex.get(), colorType, levelClearMask);
mipLevelCount)) {
tex->unref();
return nullptr;
}
}
if (this->caps()->shouldInitializeTextures()) {
uint32_t levelMask = ~0;
SkASSERT(mipLevelCount < 32);
for (int i = 0; i < mipLevelCount; ++i) {
if (!texels[i].fPixels) {
levelMask &= ~(1 << i);
}
}
this->clearTexture(tex.get(), colorType, levelMask);
} }
return tex; return tex;

View File

@ -1610,8 +1610,6 @@ GrBackendFormat GrVkCaps::getBackendFormatFromCompressionType(
SK_ABORT("Invalid compression type"); SK_ABORT("Invalid compression type");
} }
bool GrVkCaps::canClearTextureOnCreation() const { return true; }
GrSwizzle GrVkCaps::getTextureSwizzle(const GrBackendFormat& format, GrColorType colorType) const { GrSwizzle GrVkCaps::getTextureSwizzle(const GrBackendFormat& format, GrColorType colorType) const {
VkFormat vkFormat; VkFormat vkFormat;
SkAssertResult(format.asVkFormat(&vkFormat)); SkAssertResult(format.asVkFormat(&vkFormat));

View File

@ -171,8 +171,6 @@ public:
return fColorTypeToFormatTable[idx]; return fColorTypeToFormatTable[idx];
} }
bool canClearTextureOnCreation() const override;
GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override; GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override;
GrSwizzle getOutputSwizzle(const GrBackendFormat&, GrColorType) const override; GrSwizzle getOutputSwizzle(const GrBackendFormat&, GrColorType) const override;

View File

@ -953,8 +953,8 @@ sk_sp<GrTexture> GrVkGpu::onCreateTexture(const GrSurfaceDesc& desc,
int renderTargetSampleCnt, int renderTargetSampleCnt,
SkBudgeted budgeted, SkBudgeted budgeted,
GrProtected isProtected, GrProtected isProtected,
const GrMipLevel texels[], int mipLevelCount,
int mipLevelCount) { uint32_t levelClearMask) {
VkFormat pixelFormat; VkFormat pixelFormat;
SkAssertResult(format.asVkFormat(&pixelFormat)); SkAssertResult(format.asVkFormat(&pixelFormat));
SkASSERT(!GrVkFormatIsCompressed(pixelFormat)); SkASSERT(!GrVkFormatIsCompressed(pixelFormat));
@ -975,28 +975,20 @@ sk_sp<GrTexture> GrVkGpu::onCreateTexture(const GrSurfaceDesc& desc,
// This ImageDesc refers to the texture that will be read by the client. Thus even if msaa is // This ImageDesc refers to the texture that will be read by the client. Thus even if msaa is
// requested, this ImageDesc describes the resolved texture. Therefore we always have samples set // requested, this ImageDesc describes the resolved texture. Therefore we always have samples set
// to 1. // to 1.
int mipLevels = !mipLevelCount ? 1 : mipLevelCount; SkASSERT(mipLevelCount > 0);
GrVkImage::ImageDesc imageDesc; GrVkImage::ImageDesc imageDesc;
imageDesc.fImageType = VK_IMAGE_TYPE_2D; imageDesc.fImageType = VK_IMAGE_TYPE_2D;
imageDesc.fFormat = pixelFormat; imageDesc.fFormat = pixelFormat;
imageDesc.fWidth = desc.fWidth; imageDesc.fWidth = desc.fWidth;
imageDesc.fHeight = desc.fHeight; imageDesc.fHeight = desc.fHeight;
imageDesc.fLevels = mipLevels; imageDesc.fLevels = mipLevelCount;
imageDesc.fSamples = 1; imageDesc.fSamples = 1;
imageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL; imageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
imageDesc.fUsageFlags = usageFlags; imageDesc.fUsageFlags = usageFlags;
imageDesc.fIsProtected = isProtected; imageDesc.fIsProtected = isProtected;
GrMipMapsStatus mipMapsStatus = GrMipMapsStatus::kNotAllocated; GrMipMapsStatus mipMapsStatus =
if (mipLevels > 1) { mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
mipMapsStatus = GrMipMapsStatus::kValid;
for (int i = 0; i < mipLevels; ++i) {
if (!texels[i].fPixels) {
mipMapsStatus = GrMipMapsStatus::kDirty;
break;
}
}
}
sk_sp<GrVkTexture> tex; sk_sp<GrVkTexture> tex;
if (renderable == GrRenderable::kYes) { if (renderable == GrRenderable::kYes) {
@ -1010,20 +1002,11 @@ sk_sp<GrTexture> GrVkGpu::onCreateTexture(const GrSurfaceDesc& desc,
return nullptr; return nullptr;
} }
auto colorType = GrPixelConfigToColorType(desc.fConfig); if (levelClearMask) {
if (mipLevelCount) {
if (!this->uploadTexDataOptimal(tex.get(), 0, 0, desc.fWidth, desc.fHeight, colorType,
texels, mipLevelCount)) {
tex->unref();
return nullptr;
}
}
if (this->caps()->shouldInitializeTextures()) {
SkSTArray<1, VkImageSubresourceRange> ranges; SkSTArray<1, VkImageSubresourceRange> ranges;
bool inRange = false; bool inRange = false;
for (uint32_t i = 0; i < tex->mipLevels(); ++i) { for (uint32_t i = 0; i < tex->mipLevels(); ++i) {
if (i >= static_cast<uint32_t>(mipLevelCount) || !texels[i].fPixels) { if (levelClearMask & (1U << i)) {
if (inRange) { if (inRange) {
ranges.back().levelCount++; ranges.back().levelCount++;
} else { } else {
@ -1039,15 +1022,12 @@ sk_sp<GrTexture> GrVkGpu::onCreateTexture(const GrSurfaceDesc& desc,
inRange = false; inRange = false;
} }
} }
SkASSERT(!ranges.empty());
if (!ranges.empty()) { static constexpr VkClearColorValue kZeroClearColor = {};
static constexpr VkClearColorValue kZeroClearColor = {}; tex->setImageLayout(this, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
tex->setImageLayout(this, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, false);
VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, this->currentCommandBuffer()->clearColorImage(this, tex.get(), &kZeroClearColor,
false); ranges.count(), ranges.begin());
this->currentCommandBuffer()->clearColorImage(this, tex.get(), &kZeroClearColor,
ranges.count(), ranges.begin());
}
} }
return tex; return tex;
} }

View File

@ -196,8 +196,8 @@ private:
int renderTargetSampleCnt, int renderTargetSampleCnt,
SkBudgeted, SkBudgeted,
GrProtected, GrProtected,
const GrMipLevel[], int mipLevelCount,
int mipLevelCount) override; uint32_t levelClearMask) override;
sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, const GrBackendFormat&, sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, const GrBackendFormat&,
SkImage::CompressionType, SkBudgeted, SkImage::CompressionType, SkBudgeted,
const void* data) override; const void* data) override;

View File

@ -499,7 +499,7 @@ sk_sp<const GrGLInterface> CreateANGLEGLInterface() {
} }
std::unique_ptr<GLTestContext> MakeANGLETestContext(ANGLEBackend type, ANGLEContextVersion version, std::unique_ptr<GLTestContext> MakeANGLETestContext(ANGLEBackend type, ANGLEContextVersion version,
GLTestContext* shareContext, void* display){ GLTestContext* shareContext, void* display) {
#if defined(SK_BUILD_FOR_WIN) && defined(_M_ARM64) #if defined(SK_BUILD_FOR_WIN) && defined(_M_ARM64)
// Windows-on-ARM only has D3D11. This will fail correctly, but it produces huge amounts of // Windows-on-ARM only has D3D11. This will fail correctly, but it produces huge amounts of
// debug output for every unit test from both ANGLE and our context factory. // debug output for every unit test from both ANGLE and our context factory.