Reland "Separate texture creation from uploading in GrGpu subclasses."

This is a reland of a7398246cb

TBR:egdaniel@google.com

Original change's description:
> 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>

Change-Id: I54cda3b6a4b017a94ef1f50bb3748c45a24d8936
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/240558
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2019-09-10 16:03:59 -04:00 committed by Skia Commit-Bot
parent c0c05047c2
commit d2a8ae2b71
21 changed files with 501 additions and 754 deletions

View File

@ -289,17 +289,6 @@ public:
*/
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
* GrAHardwarebufferImageGenerator. This will only ever be supported on Android devices with API
* level >= 26.
@ -403,17 +392,6 @@ public:
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
* 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;
}
static bool validate_levels(int w, int h, const GrMipLevel texels[], int mipLevelCount, int bpp,
const GrCaps* caps, bool mustHaveDataForAllLevels = false) {
static bool validate_texel_levels(int w, int h, const GrMipLevel* texels, int mipLevelCount,
int bpp, const GrCaps* caps) {
SkASSERT(mipLevelCount > 0);
bool hasBasePixels = texels[0].fPixels;
int levelsWithPixelsCnt = 0;
@ -138,10 +138,7 @@ static bool validate_levels(int w, int h, const GrMipLevel texels[], int mipLeve
if (!hasBasePixels) {
return levelsWithPixelsCnt == 0;
}
if (levelsWithPixelsCnt == 1 && !mustHaveDataForAllLevels) {
return true;
}
return levelsWithPixelsCnt == mipLevelCount;
return levelsWithPixelsCnt == 1 || levelsWithPixelsCnt == mipLevelCount;
}
sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& desc,
@ -151,14 +148,14 @@ sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& desc,
SkBudgeted budgeted,
GrProtected isProtected,
const GrMipLevel texels[],
int mipLevelCount) {
int texelLevelCount) {
TRACE_EVENT0("skia.gpu", TRACE_FUNC);
if (this->caps()->isFormatCompressed(format)) {
// Call GrGpu::createCompressedTexture.
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,
renderable, renderTargetSampleCnt, mipMapped)) {
return nullptr;
@ -170,16 +167,26 @@ sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& desc,
}
// Attempt to catch un- or wrongly initialized sample counts.
SkASSERT(renderTargetSampleCnt > 0 && renderTargetSampleCnt <= 64);
bool mustHaveDataForAllLevels = this->caps()->createTextureMustSpecifyAllLevels();
if (mipLevelCount) {
if (texelLevelCount) {
int bpp = GrBytesPerPixel(desc.fConfig);
if (!validate_levels(desc.fWidth, desc.fHeight, texels, mipLevelCount, bpp, this->caps(),
mustHaveDataForAllLevels)) {
if (!validate_texel_levels(desc.fWidth, desc.fHeight, texels, texelLevelCount, bpp,
this->caps())) {
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();
@ -189,20 +196,36 @@ sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& desc,
renderTargetSampleCnt,
budgeted,
isProtected,
texels,
mipLevelCount);
mipLevelCount,
levelClearMask);
if (tex) {
SkASSERT(tex->backendFormat() == format);
SkASSERT(GrRenderable::kNo == renderable || tex->asRenderTarget());
if (!this->caps()->reuseScratchTextures() && renderable == GrRenderable::kNo) {
tex->resourcePriv().removeScratchKey();
}
fStats.incTextureCreates();
if (mipLevelCount) {
if (texels[0].fPixels) {
fStats.incTextureUploads();
bool markMipLevelsClean = false;
// Currently if level 0 does not have pixels then no other level may, as enforced by
// 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()) {
SkASSERT(GrRenderable::kYes == renderable);
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);
if (!validate_levels(width, height, texels, mipLevelCount, bpp, this->caps())) {
if (!validate_texel_levels(width, height, texels, mipLevelCount, bpp, this->caps())) {
return false;
}

View File

@ -103,7 +103,7 @@ public:
* If mipLevelCount > 1 and texels[i].fPixels != nullptr for any i > 0
* then all levels must have non-null pixels. All levels must have
* 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
* latter if GrCaps::createTextureMustSpecifyAllLevels() is true.
* @return The texture object if successful, otherwise nullptr.
@ -111,7 +111,7 @@ public:
sk_sp<GrTexture> createTexture(const GrSurfaceDesc& desc, const GrBackendFormat& format,
GrRenderable renderable, int renderTargetSampleCnt, SkBudgeted,
GrProtected isProtected, const GrMipLevel texels[],
int mipLevelCount);
int texelLevelCount);
/**
* Simplified createTexture() interface for when there is no initial texel data to upload.
@ -546,15 +546,17 @@ private:
virtual void xferBarrier(GrRenderTarget*, GrXferBarrierType) = 0;
// overridden by backend-specific derived class to create objects.
// Texture size and sample size will have already been validated in base class before
// onCreateTexture is called.
// Texture size, renderablility, format support, sample count will have already been validated
// 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&,
const GrBackendFormat&,
GrRenderable,
int renderTargetSampleCnt,
SkBudgeted, GrProtected,
const GrMipLevel[],
int mipLevelCount) = 0;
SkBudgeted,
GrProtected,
int mipLevelCoont,
uint32_t levelClearMask) = 0;
virtual sk_sp<GrTexture> onCreateCompressedTexture(int width, int height,
const GrBackendFormat&,
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
// 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,
bool mustInitializeAllLevels, GrMipLevel* outLevel,
std::unique_ptr<char[]>* data) {
GrMipLevel* outLevel, std::unique_ptr<char[]>* data) {
size_t minRB = w * bpp;
if (!inLevel.fPixels) {
if (mustInitializeAllLevels) {
data->reset(new char[minRB * h]());
outLevel->fPixels = data->get();
outLevel->fRowBytes = minRB;
} else {
outLevel->fPixels = nullptr;
outLevel->fRowBytes = 0;
}
outLevel->fPixels = nullptr;
outLevel->fRowBytes = 0;
return true;
}
size_t actualRB = inLevel.fRowBytes ? inLevel.fRowBytes : minRB;
@ -97,7 +90,6 @@ sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc,
renderTargetSampleCnt, mipMapped)) {
return nullptr;
}
bool mustInitializeAllLevels = this->caps()->createTextureMustSpecifyAllLevels();
bool rowBytesSupport = this->caps()->writePixelsRowBytesSupport();
SkAutoSTMalloc<14, GrMipLevel> tmpTexels;
SkAutoSTArray<14, std::unique_ptr<char[]>> tmpDatas;
@ -108,8 +100,8 @@ sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc,
int h = desc.fHeight;
size_t bpp = GrBytesPerPixel(desc.fConfig);
for (int i = 0; i < mipLevelCount; ++i) {
if (!prepare_level(texels[i], bpp, w, h, rowBytesSupport, mustInitializeAllLevels,
&tmpTexels[i], &tmpDatas[i])) {
if (!prepare_level(texels[i], bpp, w, h, rowBytesSupport, &tmpTexels[i],
&tmpDatas[i])) {
return nullptr;
}
w = std::max(w / 2, 1);
@ -162,14 +154,13 @@ sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc,
GrContext* context = fGpu->getContext();
GrProxyProvider* proxyProvider = context->priv().proxyProvider();
bool mustInitialize = this->caps()->createTextureMustSpecifyAllLevels();
bool rowBytesSupport = this->caps()->writePixelsRowBytesSupport();
size_t bpp = GrBytesPerPixel(desc.fConfig);
std::unique_ptr<char[]> tmpData;
GrMipLevel tmpLevel;
if (!prepare_level(mipLevel, bpp, desc.fWidth, desc.fHeight, rowBytesSupport, mustInitialize,
&tmpLevel, &tmpData)) {
if (!prepare_level(mipLevel, bpp, desc.fWidth, desc.fHeight, rowBytesSupport, &tmpLevel,
&tmpData)) {
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,
isProtected);
}
@ -320,16 +300,6 @@ sk_sp<GrTexture> GrResourceProvider::createApproxTexture(const GrSurfaceDesc& de
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,
SkBudgeted::kYes, isProtected);
}

View File

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

View File

@ -48,8 +48,6 @@ public:
GrBackendFormat getBackendFormatFromCompressionType(SkImage::CompressionType) const override;
bool canClearTextureOnCreation() const override;
GrSwizzle getTextureSwizzle(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->appendHexU32("flags", fFormatTable[i].fFlags);
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("i_for_teximage", fFormatTable[i].fInternalFormatForTexImage);
writer->appendHexU32("i_for_teximage", fFormatTable[i].fInternalFormatForTexImageOrStorage);
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->appendHexU64("z_bpp", fFormatTable[i].fTexSubImageZeroDataBpp);
writer->beginArray("surface color types");
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 { }
#endif
void GrGLCaps::getTexImageFormats(GrGLFormat surfaceFormat, GrColorType surfaceColorType,
GrColorType memoryColorType, GrGLenum* internalFormat,
GrGLenum* externalFormat, GrGLenum* externalType) const {
void GrGLCaps::getTexImageExternalFormatAndType(GrGLFormat surfaceFormat, 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,
kTexImage_ExternalFormatUsage, externalFormat, externalType);
*internalFormat = this->getTexImageInternalFormat(surfaceFormat);
}
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);
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.fDefaultExternalFormat = GR_GL_RGBA;
info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
info.fTexSubImageZeroDataBpp = 4;
info.fFlags = FormatInfo::kTexturable_Flag;
if (GR_IS_GR_GL(standard)) {
info.fFlags |= msaaRenderFlags;
@ -1436,7 +1450,11 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
}
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) &&
@ -1524,19 +1542,21 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{
FormatInfo& info = this->getFormatInfo(GrGLFormat::kR8);
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.fDefaultExternalFormat = GR_GL_RED;
info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
info.fTexSubImageZeroDataBpp = 1;
if (textureRedSupport) {
info.fFlags |= FormatInfo::kTexturable_Flag | msaaRenderFlags;
}
if (texStorageSupported &&
!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) {
@ -1619,8 +1639,6 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
FormatInfo& info = this->getFormatInfo(GrGLFormat::kALPHA8);
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
// but does not have GL_ALPHA8 (and requires a sized internal format for glTexStorage).
// WebGL never has GL_ALPHA8.
@ -1628,14 +1646,6 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
alpha8IsValidForGL ||
(alpha8IsValidForGLES && ctxInfo.hasExtension("GL_EXT_texture_storage"));
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;
if (!formatWorkarounds.fDisableAlpha8Renderable) {
@ -1647,8 +1657,9 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
}
}
info.fInternalFormatForRenderbuffer = GR_GL_ALPHA8;
info.fDefaultExternalFormat = GR_GL_ALPHA;
info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
info.fTexSubImageZeroDataBpp = 1;
if (alpha8IsValidForGL || alpha8IsValidForGLES || alpha8IsValidForWebGL) {
info.fFlags = FormatInfo::kTexturable_Flag;
}
@ -1658,7 +1669,17 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
info.fFlags |= msaaRenderFlags;
}
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) {
@ -1709,12 +1730,10 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{
FormatInfo& info = this->getFormatInfo(GrGLFormat::kLUMINANCE8);
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.fDefaultExternalFormat = GR_GL_LUMINANCE;
info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
info.fTexSubImageZeroDataBpp = 1;
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_WEBGL(standard));
@ -1724,7 +1743,11 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
if (texStorageSupported &&
!formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2 &&
!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
// 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);
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
// 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.fDefaultExternalFormat = GR_GL_BGRA;
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
// the GL_APPLE_texture_format_BGRA8888 extension or if we have GL_EXT_texture_storage and
// 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")) {
info.fFlags = FormatInfo::kTexturable_Flag | nonMSAARenderFlags;
// 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") &&
!formatWorkarounds.fDisableBGRATextureStorageForIntelWindowsES) {
supportsBGRATexStorage = true;
@ -1852,7 +1880,10 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
}
}
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)) {
@ -1896,12 +1927,10 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGB565);
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.fDefaultExternalFormat = GR_GL_RGB;
info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT_5_6_5;
info.fTexSubImageZeroDataBpp = 2;
if (GR_IS_GR_GL(standard)) {
if (version >= GR_GL_VER(4, 2) || ctxInfo.hasExtension("GL_ARB_ES2_compatibility")) {
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
// update.
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)) {
@ -1963,12 +1996,10 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA16F);
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.fDefaultExternalFormat = GR_GL_RGBA;
info.fDefaultExternalType = halfFloatType;
info.fTexSubImageZeroDataBpp = 8;
if (hasFP16Textures) {
info.fFlags = FormatInfo::kTexturable_Flag;
// ES requires 3.2 or EXT_color_buffer_half_float.
@ -1978,7 +2009,11 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
}
if (texStorageSupported &&
!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) {
@ -2055,12 +2090,10 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{
FormatInfo& info = this->getFormatInfo(GrGLFormat::kR16F);
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.fDefaultExternalFormat = GR_GL_RED;
info.fDefaultExternalType = halfFloatType;
info.fTexSubImageZeroDataBpp = 2;
if (textureRedSupport && hasFP16Textures) {
info.fFlags = FormatInfo::kTexturable_Flag;
if (halfFPRenderTargetSupport == HalfFPRenderTargetSupport::kAll) {
@ -2069,7 +2102,11 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
}
if (texStorageSupported &&
!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) {
@ -2137,19 +2174,21 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
FormatInfo& info = this->getFormatInfo(GrGLFormat::kLUMINANCE16F);
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.fDefaultExternalFormat = GR_GL_LUMINANCE;
info.fDefaultExternalType = halfFloatType;
info.fTexSubImageZeroDataBpp = 2;
if (lum16FSupported) {
info.fFlags = FormatInfo::kTexturable_Flag;
if (texStorageSupported &&
!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;
@ -2198,12 +2237,10 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGB8);
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.fDefaultExternalFormat = GR_GL_RGB;
info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
info.fTexSubImageZeroDataBpp = 3;
info.fFlags = FormatInfo::kTexturable_Flag;
if (GR_IS_GR_GL(standard)) {
// 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;
}
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) {
info.fFlags = 0;
@ -2275,20 +2316,22 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRG8);
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.fDefaultExternalFormat = GR_GL_RG;
info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
info.fTexSubImageZeroDataBpp = 2;
if (textureRedSupport) {
info.fFlags |= FormatInfo::kTexturable_Flag | msaaRenderFlags;
if (texStorageSupported &&
!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) {
info.fColorTypeInfoCount = 1;
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);
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.fDefaultExternalFormat = GR_GL_RGBA;
info.fDefaultExternalType = GR_GL_UNSIGNED_INT_2_10_10_10_REV;
info.fTexSubImageZeroDataBpp = 4;
if (GR_IS_GR_GL(standard) ||
(GR_IS_GR_GL_ES(standard) && version >= GR_GL_VER(3, 0))) {
info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
@ -2344,7 +2385,11 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
info.fFlags = FormatInfo::kTexturable_Flag;
} // No WebGL support
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)) {
@ -2388,12 +2433,10 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA4);
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.fDefaultExternalFormat = GR_GL_RGBA;
info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT_4_4_4_4;
info.fTexSubImageZeroDataBpp = 2;
info.fFlags = FormatInfo::kTexturable_Flag;
if (GR_IS_GR_GL(standard)) {
if (version >= GR_GL_VER(4, 2)) {
@ -2405,7 +2448,11 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
info.fFlags |= msaaRenderFlags;
}
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;
@ -2447,9 +2494,7 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA32F);
info.fFormatType = FormatType::kFloat;
info.fBaseInternalFormat = GR_GL_RGBA;
info.fSizedInternalFormat = GR_GL_RGBA32F;
info.fInternalFormatForTexImage =
info.fInternalFormatForTexImageOrStorage =
texImageSupportsSizedInternalFormat ? GR_GL_RGBA32F : GR_GL_RGBA;
info.fInternalFormatForRenderbuffer = GR_GL_RGBA32F;
// We don't allow texturing or rendering to this format
@ -2459,12 +2504,18 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{
FormatInfo& info = this->getFormatInfo(GrGLFormat::kSRGB8_ALPHA8);
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;
// See comment below about ES 2.0 + GL_EXT_sRGB.
if (GR_IS_GR_GL_ES(standard) && version == GR_GL_VER(2,0)) {
// ES 2.0 requires that the external format matches the internal format.
info.fDefaultExternalFormat = GR_GL_SRGB_ALPHA;
} else {
// On other GLs the expected external format is GL_RGBA, assuming this format
// is supported at all.
info.fDefaultExternalFormat = GR_GL_RGBA;
}
info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
info.fTexSubImageZeroDataBpp = 4;
if (fSRGBSupport) {
uint32_t srgbRenderFlags =
formatWorkarounds.fDisableSRGBRenderWithMSAAForMacAMD ? nonMSAARenderFlags
@ -2474,7 +2525,11 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
}
if (texStorageSupported &&
!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) {
@ -2499,7 +2554,7 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
// GL does not do srgb<->rgb conversions when transferring between cpu and gpu.
// Thus, the external format is GL_RGBA. See below for note about ES2.0 and
// glTex[Sub]Image.
GrGLenum texImageFormat = GR_GL_RGBA;
GrGLenum texImageExternalFormat = GR_GL_RGBA;
// OpenGL ES 2.0 + GL_EXT_sRGB allows GL_SRGB_ALPHA to be specified as the
// <format> param to Tex(Sub)Image. ES 2.0 requires the <internalFormat> and
@ -2507,12 +2562,12 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
// <format> param. On OpenGL and ES 3.0+ GL_SRGB_ALPHA does not work for the
// <format> param to glTexImage.
if (GR_IS_GR_GL_ES(standard) && version == GR_GL_VER(2,0)) {
texImageFormat = GR_GL_SRGB_ALPHA;
texImageExternalFormat = GR_GL_SRGB_ALPHA;
}
auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
ioFormat.fColorType = GrColorType::kRGBA_8888_SRGB;
ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
ioFormat.fExternalTexImageFormat = texImageFormat;
ioFormat.fExternalTexImageFormat = texImageExternalFormat;
ioFormat.fExternalReadFormat = GR_GL_RGBA;
}
}
@ -2523,8 +2578,7 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{
FormatInfo& info = this->getFormatInfo(GrGLFormat::kCOMPRESSED_RGB8_ETC2);
info.fFormatType = FormatType::kNormalizedFixedPoint;
info.fBaseInternalFormat = GR_GL_RGB;
info.fInternalFormatForTexImage = GR_GL_COMPRESSED_RGB8_ETC2;
info.fInternalFormatForTexImageOrStorage = GR_GL_COMPRESSED_RGB8_ETC2;
if (GR_IS_GR_GL(standard)) {
if (version >= GR_GL_VER(4, 3) || ctxInfo.hasExtension("GL_ARB_ES3_compatibility")) {
info.fFlags = FormatInfo::kTexturable_Flag;
@ -2543,8 +2597,7 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{
FormatInfo& info = this->getFormatInfo(GrGLFormat::kCOMPRESSED_ETC1_RGB8);
info.fFormatType = FormatType::kNormalizedFixedPoint;
info.fBaseInternalFormat = GR_GL_RGB;
info.fInternalFormatForTexImage = GR_GL_COMPRESSED_ETC1_RGB8;
info.fInternalFormatForTexImageOrStorage = GR_GL_COMPRESSED_ETC1_RGB8;
if (GR_IS_GR_GL_ES(standard)) {
if (ctxInfo.hasExtension("GL_OES_compressed_ETC1_RGB8_texture")) {
info.fFlags = FormatInfo::kTexturable_Flag;
@ -2558,12 +2611,12 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{
FormatInfo& info = this->getFormatInfo(GrGLFormat::kR16);
info.fFormatType = FormatType::kNormalizedFixedPoint;
info.fBaseInternalFormat = GR_GL_RED;
info.fSizedInternalFormat = GR_GL_R16;
info.fInternalFormatForTexImage =
info.fInternalFormatForTexImageOrStorage =
texImageSupportsSizedInternalFormat ? GR_GL_R16 : GR_GL_RED;
info.fInternalFormatForRenderbuffer = GR_GL_R16;
info.fDefaultExternalFormat = GR_GL_RED;
info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT;
info.fTexSubImageZeroDataBpp = 2;
if (r16AndRG1616Supported) {
info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
}
@ -2609,12 +2662,12 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
{
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRG16);
info.fFormatType = FormatType::kNormalizedFixedPoint;
info.fBaseInternalFormat = GR_GL_RG;
info.fSizedInternalFormat = GR_GL_RG16;
info.fInternalFormatForTexImage =
info.fInternalFormatForTexImageOrStorage =
texImageSupportsSizedInternalFormat ? GR_GL_RG16 : GR_GL_RG;
info.fInternalFormatForRenderbuffer = GR_GL_RG16;
info.fDefaultExternalFormat = GR_GL_RG;
info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT;
info.fTexSubImageZeroDataBpp = 4;
if (r16AndRG1616Supported) {
info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
}
@ -2679,12 +2732,12 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA16);
info.fFormatType = FormatType::kNormalizedFixedPoint;
info.fBaseInternalFormat = GR_GL_RGBA;
info.fSizedInternalFormat = GR_GL_RGBA16;
info.fInternalFormatForTexImage =
info.fInternalFormatForTexImageOrStorage =
texImageSupportsSizedInternalFormat ? GR_GL_RGBA16 : GR_GL_RGBA;
info.fInternalFormatForRenderbuffer = GR_GL_RGBA16;
info.fDefaultExternalFormat = GR_GL_RGBA;
info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT;
info.fTexSubImageZeroDataBpp = 8;
if (rgba16161616Supported) {
info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
}
@ -2753,12 +2806,12 @@ void GrGLCaps::initFormatTable(const GrGLContextInfo& ctxInfo, const GrGLInterfa
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRG16F);
info.fFormatType = FormatType::kFloat;
info.fBaseInternalFormat = GR_GL_RG;
info.fSizedInternalFormat = GR_GL_RG16F;
info.fInternalFormatForTexImage =
info.fInternalFormatForTexImageOrStorage =
texImageSupportsSizedInternalFormat ? GR_GL_RG16F : GR_GL_RG;
info.fInternalFormatForRenderbuffer = GR_GL_RG16F;
info.fDefaultExternalFormat = GR_GL_RG;
info.fDefaultExternalType = halfFloatType;
info.fTexSubImageZeroDataBpp = 4;
if (rg16fTexturesSupported) {
info.fFlags |= FormatInfo::kTexturable_Flag;
}
@ -3616,7 +3669,8 @@ bool GrGLCaps::onSurfaceSupportsWritePixels(const GrSurface* surface) const {
return false;
}
}
} if (auto rt = surface->asRenderTarget()) {
}
if (auto rt = surface->asRenderTarget()) {
if (fUseDrawInsteadOfAllRenderTargetWrites) {
return false;
}
@ -3837,7 +3891,7 @@ bool GrGLCaps::isFormatCopyable(const GrBackendFormat& 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,
@ -4010,12 +4064,12 @@ GrColorType GrGLCaps::getYUVAColorTypeFromBackendFormat(const GrBackendFormat& f
GrBackendFormat GrGLCaps::onGetDefaultBackendFormat(GrColorType ct,
GrRenderable renderable) const {
// TODO: make use of renderable.
auto format = this->getFormatFromColorType(ct);
if (format == GrGLFormat::kUnknown) {
return GrBackendFormat();
}
// TODO: plumb 'renderable' into getSizedInternalFormat (or, at least, make use of it)
return GrBackendFormat::MakeGL(this->getSizedInternalFormat(format), GR_GL_TEXTURE_2D);
return GrBackendFormat::MakeGL(GrGLFormatToEnum(format), GR_GL_TEXTURE_2D);
}
GrBackendFormat GrGLCaps::getBackendFormatFromCompressionType(
@ -4027,8 +4081,6 @@ GrBackendFormat GrGLCaps::getBackendFormatFromCompressionType(
SK_ABORT("Invalid compression type");
}
bool GrGLCaps::canClearTextureOnCreation() const { return fClearTextureSupport; }
GrSwizzle GrGLCaps::getTextureSwizzle(const GrBackendFormat& format, GrColorType colorType) const {
const auto& info = this->getFormatInfo(format.asGLFormat());
for (int i = 0; i < info.fColorTypeInfoCount; ++i) {

View File

@ -142,13 +142,36 @@ public:
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,
GrGLenum* externalFormat, GrGLenum* externalType) const;
/**
* Gets the external format and type to pass to glTexImage2D with nullptr to create an
* 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,
GrColorType memoryColorType, GrGLenum* externalFormat,
@ -165,14 +188,6 @@ public:
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
* base depending upon the GL. Not applicable to compressed textures.
@ -181,14 +196,6 @@ public:
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.
*/
@ -404,8 +411,6 @@ public:
GrBackendFormat getBackendFormatFromCompressionType(SkImage::CompressionType) const override;
bool canClearTextureOnCreation() const override;
GrSwizzle getTextureSwizzle(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. */
kFBOColorAttachment_Flag = 0x2,
kFBOColorAttachmentWithMSAA_Flag = 0x4,
kCanUseTexStorage_Flag = 0x8,
kUseTexStorage_Flag = 0x8,
};
uint32_t fFlags = 0;
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...
GrGLenum fCompressedInternalFormat = 0;
// Value to uses as the "internalformat" argument to glTexImage and glCompressedTexImage...
// Usually one of fBaseInternalFormat or fSizedInternalFormat but may vary depending on the
// particular format, GL version, extensions.
GrGLenum fInternalFormatForTexImage = 0;
// Value to uses as the "internalformat" argument to glTexImage or glTexStorage. It is
// initialized in coordination with the presence/absence of the kUseTexStorage flag. In
// other words, it is only guaranteed to be compatible with glTexImage if the flag is not
// set and or with glTexStorage if the flag is set.
GrGLenum fInternalFormatForTexImageOrStorage = 0;
// 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;
// Default value to use along with fBaseInternalFormat for functions such as glTexImage2D
// when not input providing data (passing nullptr). Not defined for compressed formats.
// Default values to use along with fInternalFormatForTexImageOrStorage for function
// 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 fTexSubImageZeroDataBpp = 0;
enum {
// 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,
GrWrapOwnership ownership,
GrWrapCacheable cacheable) {
const GrGLCaps& caps = this->glCaps();
GrGLTexture::Desc desc;
if (!check_backend_texture(backendTex, colorType, this->glCaps(), &desc)) {
return nullptr;
}
SkASSERT(caps.isFormatRenderable(desc.fFormat, sampleCnt));
SkASSERT(caps.isFormatTexturable(desc.fFormat));
// We don't support rendering to a EXTERNAL texture.
if (GR_GL_TEXTURE_EXTERNAL == desc.fTarget) {
return nullptr;
}
const GrGLCaps& caps = this->glCaps();
if (!caps.isFormatRenderable(desc.fFormat, sampleCnt)) {
return nullptr;
}
if (kBorrow_GrWrapOwnership == ownership) {
desc.fOwnership = GrBackendObjectOwnership::kBorrowed;
} else {
@ -846,8 +844,8 @@ bool GrGLGpu::onWritePixels(GrSurface* surface, int left, int top, int width, in
SkASSERT(!GrGLFormatIsCompressed(glTex->format()));
return this->uploadTexData(glTex->format(), surfaceColorType, glTex->width(), glTex->height(),
glTex->target(), kWrite_UploadType, left, top,width,
height, srcColorType, texels, mipLevelCount);
glTex->target(), left, top, width, height, srcColorType, texels,
mipLevelCount);
}
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();
// Internal format comes from the texture desc.
GrGLenum internalFormat;
// External format and type come from the upload data.
GrGLenum externalFormat = 0;
GrGLenum externalType = 0;
this->glCaps().getTexImageFormats(textureFormat, textureColorType, bufferColorType,
&internalFormat, &externalFormat, &externalType);
this->glCaps().getTexSubImageExternalFormatAndType(
textureFormat, textureColorType, bufferColorType, &externalFormat, &externalType);
if (!externalFormat || !externalType) {
return false;
}
@ -933,178 +929,6 @@ bool GrGLGpu::onTransferPixelsFrom(GrSurface* surface, int left, int top, int wi
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() {
auto* xferBufferState = this->hwBufferState(GrGpuBufferType::kXferCpuToGpu);
if (!xferBufferState->fBoundBufferUniqueID.isInvalid()) {
@ -1113,11 +937,10 @@ void GrGLGpu::unbindCpuToGpuXferBuffer() {
}
}
bool GrGLGpu::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) {
bool GrGLGpu::uploadTexData(GrGLFormat textureFormat, GrColorType textureColorType, int texWidth,
int texHeight, GrGLenum target, int left, int top, int width,
int height, GrColorType srcColorType, const GrMipLevel texels[],
int mipLevelCount, GrMipMapsStatus* mipMapsStatus) {
// If we're uploading compressed data then we should be using uploadCompressedTexData
SkASSERT(!GrGLFormatIsCompressed(textureFormat));
@ -1141,19 +964,15 @@ bool GrGLGpu::uploadTexData(GrGLFormat textureFormat, GrColorType textureColorTy
return false;
}
// Internal format comes from the texture desc.
GrGLenum internalFormat;
// External format and type come from the upload data.
GrGLenum externalFormat;
GrGLenum externalType;
this->glCaps().getTexImageFormats(textureFormat, textureColorType, srcColorType,
&internalFormat, &externalFormat, &externalType);
this->glCaps().getTexSubImageExternalFormatAndType(
textureFormat, textureColorType, srcColorType, &externalFormat, &externalType);
if (!externalFormat || !externalType) {
return false;
}
GrGLenum internalFormatForTexStorage = this->glCaps().getSizedInternalFormat(textureFormat);
/*
* Check whether to allocate a temporary buffer for flipping y or
* 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;
// in case we need a temporary, trimmed copy of the src pixels
SkAutoSMalloc<128 * 128> tempStorage;
if (mipMapsStatus) {
*mipMapsStatus = (mipLevelCount > 1) ?
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;
if (kNewTexture_UploadType == uploadType) {
if (0 == left && 0 == top && texWidth == width && texHeight == height) {
succeeded = allocate_and_populate_texture(
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;
for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
if (!texels[currentMipLevel].fPixels) {
if (mipMapsStatus) {
*mipMapsStatus = GrMipMapsStatus::kDirty;
}
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) {
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));
continue;
}
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));
}
restore_pixelstore_state(*interface, caps, restoreGLRowLength);
return succeeded;
if (restoreGLRowLength) {
SkASSERT(caps.writePixelsRowBytesSupport());
GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
}
return true;
}
bool GrGLGpu::uploadCompressedTexData(GrGLFormat format,
@ -1228,7 +1026,7 @@ bool GrGLGpu::uploadCompressedTexData(GrGLFormat format,
const GrGLCaps& caps = this->glCaps();
// We only need the internal format for compressed 2D textures.
GrGLenum internalFormat = caps.getTexImageInternalFormat(format);
GrGLenum internalFormat = caps.getTexImageOrStorageInternalFormat(format);
if (!internalFormat) {
return 0;
}
@ -1427,16 +1225,17 @@ sk_sp<GrTexture> GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc,
int renderTargetSampleCnt,
SkBudgeted budgeted,
GrProtected isProtected,
const GrMipLevel texels[],
int mipLevelCount) {
int mipLevelCount,
uint32_t levelClearMask) {
// We don't support protected textures in GL.
if (isProtected == GrProtected::kYes) {
return nullptr;
}
SkASSERT(GrGLCaps::kNone_MSFBOType != this->glCaps().msFBOType() || renderTargetSampleCnt == 1);
GrMipMapsStatus mipMapsStatus;
SkASSERT(mipLevelCount > 0);
GrMipMapsStatus mipMapsStatus =
mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
GrGLTextureParameters::SamplerOverriddenState initialState;
GrGLTexture::Desc texDesc;
texDesc.fSize = {desc.fWidth, desc.fHeight};
@ -1447,18 +1246,8 @@ sk_sp<GrTexture> GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc,
SkASSERT(texDesc.fFormat != GrGLFormat::kUnknown);
SkASSERT(!GrGLFormatIsCompressed(texDesc.fFormat));
// TODO: Take these as parameters.
auto textureColorType = GrPixelConfigToColorType(desc.fConfig);
auto srcColorType = GrPixelConfigToColorType(desc.fConfig);
texDesc.fID = this->createTexture2D({desc.fWidth, desc.fHeight},
texDesc.fFormat,
renderable,
&initialState,
textureColorType,
srcColorType,
texels,
mipLevelCount,
&mipMapsStatus);
texDesc.fID = this->createTexture2D({desc.fWidth, desc.fHeight}, texDesc.fFormat, renderable,
&initialState, mipLevelCount);
if (!texDesc.fID) {
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.
tex->parameters()->set(&initialState, GrGLTextureParameters::NonsamplerState(),
fResetTimestampForTextureParameters);
bool clearLevelsWithoutData =
this->caps()->shouldInitializeTextures() && this->glCaps().clearTextureSupport();
if (clearLevelsWithoutData) {
static constexpr uint32_t kZero = 0;
int levelCnt = SkTMax(1, tex->texturePriv().maxMipMapLevel());
for (int i = 0; i < levelCnt; ++i) {
if (i >= mipLevelCount || !texels[i].fPixels) {
GL_CALL(ClearTexImage(tex->textureID(), i, GR_GL_RGBA, GR_GL_UNSIGNED_BYTE,
&kZero));
if (levelClearMask) {
GrGLenum externalFormat, externalType;
size_t bpp;
this->glCaps().getTexSubImageZeroFormatTypeAndBpp(texDesc.fFormat, &externalFormat,
&externalType, &bpp);
if (this->glCaps().clearTextureSupport()) {
for (int i = 0; i < mipLevelCount; ++i) {
if (levelClearMask & (1U << i)) {
GL_CALL(ClearTexImage(tex->textureID(), i, externalFormat, externalType,
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.
int firstWorkingStencilFormatIndex = -1;
// Create color texture
GrGLuint colorID = 0;
GL_CALL(GenTextures(1, &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) {
GrGLuint colorID =
this->createTexture2D({kSize, kSize}, format, GrRenderable::kYes, nullptr, 1);
if (!colorID) {
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
GL_CALL(BindTexture(GR_GL_TEXTURE_2D, 0));
@ -1691,11 +1478,7 @@ GrGLuint GrGLGpu::createTexture2D(const SkISize& size,
GrGLFormat format,
GrRenderable renderable,
GrGLTextureParameters::SamplerOverriddenState* initialState,
GrColorType textureColorType,
GrColorType srcColorType,
const GrMipLevel texels[],
int mipLevelCount,
GrMipMapsStatus* mipMapsStatus) {
int mipLevelCount) {
SkASSERT(format != GrGLFormat::kUnknown);
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));
}
*initialState = set_initial_texture_params(this->glInterface(), GR_GL_TEXTURE_2D);
if (!this->uploadTexData(format,
textureColorType,
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;
if (initialState) {
*initialState = set_initial_texture_params(this->glInterface(), GR_GL_TEXTURE_2D);
} else {
set_initial_texture_params(this->glInterface(), GR_GL_TEXTURE_2D);
}
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(
@ -2161,7 +1965,7 @@ bool GrGLGpu::readOrTransferPixelsFrom(GrSurface* surface, int left, int top, in
}
} else {
// Use a temporary FBO.
this->bindSurfaceFBOForPixelOps(surface, GR_GL_FRAMEBUFFER, kSrc_TempFBOTarget);
this->bindSurfaceFBOForPixelOps(surface, 0, GR_GL_FRAMEBUFFER, kSrc_TempFBOTarget);
fHWBoundRenderTargetUniqueID.makeInvalid();
}
@ -2202,7 +2006,7 @@ bool GrGLGpu::readOrTransferPixelsFrom(GrSurface* surface, int left, int top, in
}
if (!renderTarget) {
this->unbindTextureFBOForPixelOps(GR_GL_FRAMEBUFFER, surface);
this->unbindSurfaceFBOForPixelOps(surface, 0, GR_GL_FRAMEBUFFER);
}
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.
void GrGLGpu::bindSurfaceFBOForPixelOps(GrSurface* surface, GrGLenum fboTarget,
void GrGLGpu::bindSurfaceFBOForPixelOps(GrSurface* surface, int mipLevel, GrGLenum fboTarget,
TempFBOTarget tempFBOTarget) {
GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(surface->asRenderTarget());
if (!rt) {
if (!rt || mipLevel > 0) {
SkASSERT(surface->asTexture());
GrGLTexture* texture = static_cast<GrGLTexture*>(surface->asTexture());
GrGLuint texID = texture->textureID();
@ -3031,20 +2835,20 @@ void GrGLGpu::bindSurfaceFBOForPixelOps(GrSurface* surface, GrGLenum fboTarget,
}
this->bindFramebuffer(fboTarget, *tempFBOID);
GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget,
GR_GL_COLOR_ATTACHMENT0,
target,
texID,
0));
texture->baseLevelWasBoundToFBO();
GR_GL_CALL(
this->glInterface(),
FramebufferTexture2D(fboTarget, GR_GL_COLOR_ATTACHMENT0, target, texID, mipLevel));
if (mipLevel == 0) {
texture->baseLevelWasBoundToFBO();
}
} else {
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
if (!surface->asRenderTarget()) {
if (mipLevel > 0 || !surface->asRenderTarget()) {
SkASSERT(surface->asTexture());
GrGLenum textureTarget = static_cast<GrGLTexture*>(surface->asTexture())->target();
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();
// We don't swizzle at all in our copies.
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());
fHWBoundRenderTargetUniqueID.makeInvalid();
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);
}
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.
this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
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,
const SkIPoint& dstPoint) {
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());
SkASSERT(dstTex);
// We modified the bound FBO
@ -3489,7 +3293,7 @@ void GrGLGpu::copySurfaceAsCopyTexSubImage(GrSurface* dst, GrSurface* src, const
dstPoint.fX, dstPoint.fY,
srcRect.fLeft, srcRect.fTop,
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,
srcRect.width(), srcRect.height());
// 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(src, GR_GL_READ_FRAMEBUFFER, kSrc_TempFBOTarget);
this->bindSurfaceFBOForPixelOps(dst, 0, GR_GL_DRAW_FRAMEBUFFER, kDst_TempFBOTarget);
this->bindSurfaceFBOForPixelOps(src, 0, GR_GL_READ_FRAMEBUFFER, kSrc_TempFBOTarget);
// We modified the bound FBO
fHWBoundRenderTargetUniqueID.makeInvalid();
@ -3525,8 +3329,8 @@ bool GrGLGpu::copySurfaceAsBlitFramebuffer(GrSurface* dst, GrSurface* src, const
dstRect.fRight,
dstRect.fBottom,
GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
this->unbindTextureFBOForPixelOps(GR_GL_DRAW_FRAMEBUFFER, dst);
this->unbindTextureFBOForPixelOps(GR_GL_READ_FRAMEBUFFER, src);
this->unbindSurfaceFBOForPixelOps(dst, 0, GR_GL_DRAW_FRAMEBUFFER);
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.
this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
@ -3764,8 +3568,7 @@ GrBackendTexture GrGLGpu::createBackendTexture(int w, int h,
GrGLTextureInfo info;
GrGLTextureParameters::SamplerOverriddenState initialState;
int mipLevelCount = 0;
SkAutoTMalloc<GrMipLevel> texels;
SkTDArray<GrMipLevel> texels;
SkAutoMalloc pixelStorage;
SkImage::CompressionType compressionType;
if (GrGLFormatToCompressionType(glFormat, &compressionType)) {
@ -3791,16 +3594,15 @@ GrBackendTexture GrGLGpu::createBackendTexture(int w, int h,
info.fTarget = GR_GL_TEXTURE_2D;
} else {
if (srcPixels) {
mipLevelCount = 1;
texels.reset(mipLevelCount);
texels.get()[0] = {srcPixels, rowBytes};
texels.append(1);
texels[0] = {srcPixels, rowBytes};
} else if (color) {
mipLevelCount = 1;
int mipLevelCount = 1;
if (GrMipMapped::kYes == mipMapped) {
mipLevelCount = SkMipMap::ComputeLevelCount(w, h) + 1;
}
texels.reset(mipLevelCount);
texels.append(mipLevelCount);
SkTArray<size_t> individualMipOffsets(mipLevelCount);
size_t bytesPerPixel = GrBytesPerPixel(config);
@ -3817,7 +3619,7 @@ GrBackendTexture GrGLGpu::createBackendTexture(int w, int h,
int twoToTheMipLevel = 1 << i;
int currentWidth = SkTMax(1, w / twoToTheMipLevel);
texels.get()[i] = {&(tmpPixels[offset]), currentWidth * bytesPerPixel};
texels[i] = {&(tmpPixels[offset]), currentWidth * bytesPerPixel};
}
}
GrSurfaceDesc desc;
@ -3827,20 +3629,19 @@ GrBackendTexture GrGLGpu::createBackendTexture(int w, int h,
info.fTarget = GR_GL_TEXTURE_2D;
info.fFormat = GrGLFormatToEnum(glFormat);
// TODO: Take these as parameters.
auto srcColorType = GrPixelConfigToColorType(desc.fConfig);
info.fID = this->createTexture2D({desc.fWidth, desc.fHeight},
glFormat,
renderable,
&initialState,
textureColorType,
srcColorType,
texels,
mipLevelCount,
nullptr);
info.fID = this->createTexture2D({desc.fWidth, desc.fHeight}, glFormat, renderable,
&initialState, SkTMax(1, texels.count()));
if (!info.fID) {
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
@ -3888,17 +3689,7 @@ GrBackendRenderTarget GrGLGpu::createTestingOnlyBackendRenderTarget(int w, int h
if (!this->glCaps().isFormatRenderable(format, 1)) {
return {};
}
bool useTexture = false;
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);
}
bool useTexture = format == GrGLFormat::kBGRA8;
int sFormatIdx = this->getCompatibleStencilIndex(format);
if (sFormatIdx < 0) {
return {};
@ -3931,7 +3722,7 @@ GrBackendRenderTarget GrGLGpu::createTestingOnlyBackendRenderTarget(int w, int h
GrGLFramebufferInfo info;
info.fFBOID = 0;
info.fFormat = this->glCaps().formatSizedInternalFormat(format);
info.fFormat = GrGLFormatToEnum(format);
GL_CALL(GenFramebuffers(1, &info.fFBOID));
if (!info.fFBOID) {
deleteIDs();
@ -3942,15 +3733,19 @@ GrBackendRenderTarget GrGLGpu::createTestingOnlyBackendRenderTarget(int w, int h
this->bindFramebuffer(GR_GL_FRAMEBUFFER, info.fFBOID);
if (useTexture) {
this->bindTextureToScratchUnit(GR_GL_TEXTURE_2D, colorID);
GL_CALL(TexImage2D(GR_GL_TEXTURE_2D, 0, colorBufferFormat, w, h, 0, externalFormat,
externalType, nullptr));
GrGLTextureParameters::SamplerOverriddenState initialState;
colorID = this->createTexture2D({w, h}, format, GrRenderable::kYes, &initialState, 1);
if (!colorID) {
deleteIDs();
return {};
}
GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0, GR_GL_TEXTURE_2D,
colorID, 0));
} else {
GrGLenum renderBufferFormat = this->glCaps().getRenderbufferInternalFormat(format);
GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, colorID));
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,
GR_GL_RENDERBUFFER, colorID));
}

View File

@ -195,8 +195,8 @@ private:
int renderTargetSampleCnt,
SkBudgeted,
GrProtected,
const GrMipLevel[],
int mipLevelCount) override;
int mipLevelCount,
uint32_t levelClearMask) override;
sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, const GrBackendFormat&,
SkImage::CompressionType compression, SkBudgeted,
const void* data) override;
@ -228,11 +228,7 @@ private:
GrGLFormat format,
GrRenderable,
GrGLTextureParameters::SamplerOverriddenState* initialState,
GrColorType textureColorType,
GrColorType srcColorType,
const GrMipLevel texels[],
int mipLevelCount,
GrMipMapsStatus* mipMapsStatus);
int mipLevelCount);
GrGLuint createCompressedTexture2D(const SkISize& size, GrGLFormat format,
SkImage::CompressionType compression,
@ -377,15 +373,9 @@ private:
void flushFramebufferSRGB(bool enable);
// helper for onCreateTexture and writeTexturePixels
enum UploadType {
kNewTexture_UploadType, // we are creating a new texture
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,
bool uploadTexData(GrGLFormat textureFormat, GrColorType textureColorType, int texWidth,
int texHeight, GrGLenum target, int left, int top, int width, int height,
GrColorType srcColorType, const GrMipLevel texels[], int mipLevelCount,
GrMipMapsStatus* mipMapsStatus = nullptr);
// 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
// FBO ID then that ID is bound. If not the surface is temporarily bound to a FBO and that FBO
// is bound. This must be paired with a call to unbindSurfaceFBOForPixelOps().
void bindSurfaceFBOForPixelOps(GrSurface* surface, GrGLenum fboTarget,
void bindSurfaceFBOForPixelOps(GrSurface* surface, int mipLevel, GrGLenum fboTarget,
TempFBOTarget tempFBOTarget);
// 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
void onDumpJSON(SkJSONWriter*) const override;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -499,7 +499,7 @@ sk_sp<const GrGLInterface> CreateANGLEGLInterface() {
}
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)
// 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.