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; }
/**
* 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,10 @@ 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;
info.fDefaultExternalFormat = GR_GL_RGBA;
info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
info.fTexSubImageZeroDataBpp = 4;
if (fSRGBSupport) {
uint32_t srgbRenderFlags =
formatWorkarounds.fDisableSRGBRenderWithMSAAForMacAMD ? nonMSAARenderFlags
@ -2474,7 +2517,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) {
@ -2523,8 +2570,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 +2589,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 +2603,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 +2654,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 +2724,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 +2798,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 +3661,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 +3883,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 +4056,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 +4073,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

@ -400,13 +400,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);
@ -422,7 +422,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
@ -431,17 +431,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,
@ -454,24 +445,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.