Revert "Separate texture creation from uploading in GrGpu subclasses."
This reverts commit a7398246cb80746994df430261ed72822a1f60ba.
Reason for revert: breaking bots
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>
TBR=egdaniel@google.com,bsalomon@google.com
Change-Id: Icc6860053242ff1a55784a0f38938968f9e5e5b0
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/240556
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrCaps.h b/src/gpu/GrCaps.h
index 112ba43..b7229bc 100644
--- a/src/gpu/GrCaps.h
+++ b/src/gpu/GrCaps.h
@@ -289,6 +289,17 @@
*/
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.
@@ -393,6 +404,17 @@
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.
*/
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index a7a3bb1..07c035d 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -99,8 +99,8 @@
return false;
}
-static bool validate_texel_levels(int w, int h, const GrMipLevel* texels, int mipLevelCount,
- int bpp, const GrCaps* caps) {
+static bool validate_levels(int w, int h, const GrMipLevel texels[], int mipLevelCount, int bpp,
+ const GrCaps* caps, bool mustHaveDataForAllLevels = false) {
SkASSERT(mipLevelCount > 0);
bool hasBasePixels = texels[0].fPixels;
int levelsWithPixelsCnt = 0;
@@ -138,7 +138,10 @@
if (!hasBasePixels) {
return levelsWithPixelsCnt == 0;
}
- return levelsWithPixelsCnt == 1 || levelsWithPixelsCnt == mipLevelCount;
+ if (levelsWithPixelsCnt == 1 && !mustHaveDataForAllLevels) {
+ return true;
+ }
+ return levelsWithPixelsCnt == mipLevelCount;
}
sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& desc,
@@ -148,14 +151,14 @@
SkBudgeted budgeted,
GrProtected isProtected,
const GrMipLevel texels[],
- int texelLevelCount) {
+ int mipLevelCount) {
TRACE_EVENT0("skia.gpu", TRACE_FUNC);
if (this->caps()->isFormatCompressed(format)) {
// Call GrGpu::createCompressedTexture.
return nullptr;
}
- GrMipMapped mipMapped = texelLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo;
+ GrMipMapped mipMapped = mipLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo;
if (!this->caps()->validateSurfaceParams({desc.fWidth, desc.fHeight}, format, desc.fConfig,
renderable, renderTargetSampleCnt, mipMapped)) {
return nullptr;
@@ -167,26 +170,16 @@
}
// Attempt to catch un- or wrongly initialized sample counts.
SkASSERT(renderTargetSampleCnt > 0 && renderTargetSampleCnt <= 64);
- if (texelLevelCount) {
+
+ bool mustHaveDataForAllLevels = this->caps()->createTextureMustSpecifyAllLevels();
+ if (mipLevelCount) {
int bpp = GrBytesPerPixel(desc.fConfig);
- if (!validate_texel_levels(desc.fWidth, desc.fHeight, texels, texelLevelCount, bpp,
- this->caps())) {
+ if (!validate_levels(desc.fWidth, desc.fHeight, texels, mipLevelCount, bpp, this->caps(),
+ 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);
- }
+ } else if (mustHaveDataForAllLevels) {
+ return nullptr;
}
this->handleDirtyContext();
@@ -196,36 +189,20 @@
renderTargetSampleCnt,
budgeted,
isProtected,
- mipLevelCount,
- levelClearMask);
-
+ texels,
+ mipLevelCount);
if (tex) {
- SkASSERT(tex->backendFormat() == format);
- SkASSERT(GrRenderable::kNo == renderable || tex->asRenderTarget());
if (!this->caps()->reuseScratchTextures() && renderable == GrRenderable::kNo) {
tex->resourcePriv().removeScratchKey();
}
fStats.incTextureCreates();
- 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;
+ if (mipLevelCount) {
+ if (texels[0].fPixels) {
+ fStats.incTextureUploads();
}
- // 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();
@@ -455,7 +432,7 @@
}
size_t bpp = GrColorTypeBytesPerPixel(srcColorType);
- if (!validate_texel_levels(width, height, texels, mipLevelCount, bpp, this->caps())) {
+ if (!validate_levels(width, height, texels, mipLevelCount, bpp, this->caps())) {
return false;
}
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 80677b9..6b8a45e 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -103,7 +103,7 @@
* 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 texelLevelCount the number of levels in 'texels'. May be 0, 1, or
+ * @param mipLevelCount 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 @@
sk_sp<GrTexture> createTexture(const GrSurfaceDesc& desc, const GrBackendFormat& format,
GrRenderable renderable, int renderTargetSampleCnt, SkBudgeted,
GrProtected isProtected, const GrMipLevel texels[],
- int texelLevelCount);
+ int mipLevelCount);
/**
* Simplified createTexture() interface for when there is no initial texel data to upload.
@@ -546,17 +546,15 @@
virtual void xferBarrier(GrRenderTarget*, GrXferBarrierType) = 0;
// overridden by backend-specific derived class to create objects.
- // 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.
+ // Texture size and sample size will have already been validated in base class before
+ // onCreateTexture is called.
virtual sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc&,
const GrBackendFormat&,
GrRenderable,
int renderTargetSampleCnt,
- SkBudgeted,
- GrProtected,
- int mipLevelCoont,
- uint32_t levelClearMask) = 0;
+ SkBudgeted, GrProtected,
+ const GrMipLevel[],
+ int mipLevelCount) = 0;
virtual sk_sp<GrTexture> onCreateCompressedTexture(int width, int height,
const GrBackendFormat&,
SkImage::CompressionType, SkBudgeted,
diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp
index 29a616f..214b24d 100644
--- a/src/gpu/GrResourceProvider.cpp
+++ b/src/gpu/GrResourceProvider.cpp
@@ -45,11 +45,18 @@
// 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,
- GrMipLevel* outLevel, std::unique_ptr<char[]>* data) {
+ bool mustInitializeAllLevels, GrMipLevel* outLevel,
+ std::unique_ptr<char[]>* data) {
size_t minRB = w * bpp;
if (!inLevel.fPixels) {
- outLevel->fPixels = nullptr;
- outLevel->fRowBytes = 0;
+ if (mustInitializeAllLevels) {
+ data->reset(new char[minRB * h]());
+ outLevel->fPixels = data->get();
+ outLevel->fRowBytes = minRB;
+ } else {
+ outLevel->fPixels = nullptr;
+ outLevel->fRowBytes = 0;
+ }
return true;
}
size_t actualRB = inLevel.fRowBytes ? inLevel.fRowBytes : minRB;
@@ -90,6 +97,7 @@
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;
@@ -100,8 +108,8 @@
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, &tmpTexels[i],
- &tmpDatas[i])) {
+ if (!prepare_level(texels[i], bpp, w, h, rowBytesSupport, mustInitializeAllLevels,
+ &tmpTexels[i], &tmpDatas[i])) {
return nullptr;
}
w = std::max(w / 2, 1);
@@ -154,13 +162,14 @@
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, &tmpLevel,
- &tmpData)) {
+ if (!prepare_level(mipLevel, bpp, desc.fWidth, desc.fHeight, rowBytesSupport, mustInitialize,
+ &tmpLevel, &tmpData)) {
return nullptr;
}
@@ -230,6 +239,17 @@
}
}
+ 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);
}
@@ -300,6 +320,16 @@
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);
}
diff --git a/src/gpu/dawn/GrDawnCaps.cpp b/src/gpu/dawn/GrDawnCaps.cpp
index b53feca..106068b 100644
--- a/src/gpu/dawn/GrDawnCaps.cpp
+++ b/src/gpu/dawn/GrDawnCaps.cpp
@@ -175,6 +175,10 @@
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);
diff --git a/src/gpu/dawn/GrDawnCaps.h b/src/gpu/dawn/GrDawnCaps.h
index 123bc3b..41ca2a2 100644
--- a/src/gpu/dawn/GrDawnCaps.h
+++ b/src/gpu/dawn/GrDawnCaps.h
@@ -48,6 +48,8 @@
GrBackendFormat getBackendFormatFromCompressionType(SkImage::CompressionType) const override;
+ bool canClearTextureOnCreation() const override;
+
GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override;
GrSwizzle getOutputSwizzle(const GrBackendFormat&, GrColorType) const override;
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 403202b..447d10d 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -1195,12 +1195,12 @@
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].fInternalFormatForTexImageOrStorage);
+ writer->appendHexU32("i_for_teximage", fFormatTable[i].fInternalFormatForTexImage);
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,28 +1233,12 @@
void GrGLCaps::onDumpJSON(SkJSONWriter* writer) const { }
#endif
-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 {
+void GrGLCaps::getTexImageFormats(GrGLFormat surfaceFormat, GrColorType surfaceColorType,
+ GrColorType memoryColorType, GrGLenum* internalFormat,
+ 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,
@@ -1433,10 +1417,12 @@
{
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;
@@ -1450,11 +1436,7 @@
}
if (texStorageSupported) {
- info.fFlags |= FormatInfo::kUseTexStorage_Flag;
- info.fInternalFormatForTexImageOrStorage = GR_GL_RGBA8;
- } else {
- info.fInternalFormatForTexImageOrStorage =
- texImageSupportsSizedInternalFormat ? GR_GL_RGBA8 : GR_GL_RGBA;
+ info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
}
bool supportsBGRAColorType = GR_IS_GR_GL(standard) &&
@@ -1542,21 +1524,19 @@
{
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::kUseTexStorage_Flag;
- info.fInternalFormatForTexImageOrStorage = GR_GL_R8;
- } else {
- info.fInternalFormatForTexImageOrStorage =
- texImageSupportsSizedInternalFormat ? GR_GL_R8 : GR_GL_RED;
+ info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
}
if (textureRedSupport) {
@@ -1639,6 +1619,8 @@
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.
@@ -1646,6 +1628,14 @@
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) {
@@ -1657,9 +1647,8 @@
}
}
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;
}
@@ -1669,17 +1658,7 @@
info.fFlags |= msaaRenderFlags;
}
if (alpha8TexStorageSupported) {
- 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;
- }
+ info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
}
if (alpha8IsValidForGL || alpha8IsValidForGLES || alpha8IsValidForWebGL) {
@@ -1730,10 +1709,12 @@
{
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));
@@ -1743,11 +1724,7 @@
if (texStorageSupported &&
!formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2 &&
!formatWorkarounds.fDisableNonRedSingleChannelTexStorageForANGLEGL) {
- info.fFlags |= FormatInfo::kUseTexStorage_Flag;
- info.fInternalFormatForTexImageOrStorage = GR_GL_LUMINANCE8;
- } else {
- info.fInternalFormatForTexImageOrStorage =
- texImageSupportsSizedInternalFormat ? GR_GL_LUMINANCE8 : GR_GL_LUMINANCE;
+ info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
}
// 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
@@ -1803,6 +1780,23 @@
{
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
@@ -1825,28 +1819,7 @@
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.
@@ -1856,8 +1829,7 @@
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. However, ES3 supports glTexStorage but
- // without GL_EXT_texture_storage it does not allow the BGRA8 sized internal format.
+ // GL_EXT_texture_format_BGRA8888.
if (ctxInfo.hasExtension("GL_EXT_texture_storage") &&
!formatWorkarounds.fDisableBGRATextureStorageForIntelWindowsES) {
supportsBGRATexStorage = true;
@@ -1880,10 +1852,7 @@
}
}
if (texStorageSupported && supportsBGRATexStorage) {
- info.fFlags |= FormatInfo::kUseTexStorage_Flag;
- info.fInternalFormatForTexImageOrStorage = GR_GL_BGRA8;
- } else {
- info.fInternalFormatForTexImageOrStorage = bgraTexImageFormat;
+ info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
}
if (SkToBool(info.fFlags &FormatInfo::kTexturable_Flag)) {
@@ -1927,10 +1896,12 @@
{
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;
@@ -1948,11 +1919,7 @@
// 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::kUseTexStorage_Flag;
- info.fInternalFormatForTexImageOrStorage = GR_GL_RGB565;
- } else {
- info.fInternalFormatForTexImageOrStorage =
- texImageSupportsSizedInternalFormat ? GR_GL_RGB565 : GR_GL_RGB;
+ info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
}
if (SkToBool(info.fFlags &FormatInfo::kTexturable_Flag)) {
@@ -1996,10 +1963,12 @@
{
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.
@@ -2009,11 +1978,7 @@
}
if (texStorageSupported &&
!formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2) {
- info.fFlags |= FormatInfo::kUseTexStorage_Flag;
- info.fInternalFormatForTexImageOrStorage = GR_GL_RGBA16F;
- } else {
- info.fInternalFormatForTexImageOrStorage =
- texImageSupportsSizedInternalFormat ? GR_GL_RGBA16F : GR_GL_RGBA;
+ info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
}
if (hasFP16Textures) {
@@ -2090,10 +2055,12 @@
{
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) {
@@ -2102,11 +2069,7 @@
}
if (texStorageSupported &&
!formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2) {
- info.fFlags |= FormatInfo::kUseTexStorage_Flag;
- info.fInternalFormatForTexImageOrStorage = GR_GL_R16F;
- } else {
- info.fInternalFormatForTexImageOrStorage =
- texImageSupportsSizedInternalFormat ? GR_GL_R16F : GR_GL_RED;
+ info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
}
if (textureRedSupport && hasFP16Textures) {
@@ -2174,21 +2137,19 @@
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::kUseTexStorage_Flag;
- info.fInternalFormatForTexImageOrStorage = GR_GL_LUMINANCE16F;
- } else {
- info.fInternalFormatForTexImageOrStorage =
- texImageSupportsSizedInternalFormat ? GR_GL_LUMINANCE16F : GR_GL_LUMINANCE;
+ info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
}
info.fColorTypeInfoCount = 1;
@@ -2237,10 +2198,12 @@
{
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
@@ -2261,11 +2224,7 @@
info.fFlags |= msaaRenderFlags;
}
if (texStorageSupported) {
- info.fFlags |= FormatInfo::kUseTexStorage_Flag;
- info.fInternalFormatForTexImageOrStorage = GR_GL_RGB8;
- } else {
- info.fInternalFormatForTexImageOrStorage =
- texImageSupportsSizedInternalFormat ? GR_GL_RGB8 : GR_GL_RGB;
+ info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
}
if (formatWorkarounds.fDisableRGB8ForMali400) {
info.fFlags = 0;
@@ -2316,22 +2275,20 @@
{
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::kUseTexStorage_Flag;
- info.fInternalFormatForTexImageOrStorage = GR_GL_RG8;
+ info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
}
}
- 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]());
@@ -2373,10 +2330,12 @@
{
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;
@@ -2385,11 +2344,7 @@
info.fFlags = FormatInfo::kTexturable_Flag;
} // No WebGL support
if (texStorageSupported) {
- info.fFlags |= FormatInfo::kUseTexStorage_Flag;
- info.fInternalFormatForTexImageOrStorage = GR_GL_RGB10_A2;
- } else {
- info.fInternalFormatForTexImageOrStorage =
- texImageSupportsSizedInternalFormat ? GR_GL_RGB10_A2 : GR_GL_RGBA;
+ info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
}
if (SkToBool(info.fFlags &FormatInfo::kTexturable_Flag)) {
@@ -2433,10 +2388,12 @@
{
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)) {
@@ -2448,11 +2405,7 @@
info.fFlags |= msaaRenderFlags;
}
if (texStorageSupported) {
- info.fFlags |= FormatInfo::kUseTexStorage_Flag;
- info.fInternalFormatForTexImageOrStorage = GR_GL_RGBA4;
- } else {
- info.fInternalFormatForTexImageOrStorage =
- texImageSupportsSizedInternalFormat ? GR_GL_RGBA4 : GR_GL_RGBA;
+ info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
}
info.fColorTypeInfoCount = 1;
@@ -2494,7 +2447,9 @@
{
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA32F);
info.fFormatType = FormatType::kFloat;
- info.fInternalFormatForTexImageOrStorage =
+ info.fBaseInternalFormat = GR_GL_RGBA;
+ info.fSizedInternalFormat = GR_GL_RGBA32F;
+ info.fInternalFormatForTexImage =
texImageSupportsSizedInternalFormat ? GR_GL_RGBA32F : GR_GL_RGBA;
info.fInternalFormatForRenderbuffer = GR_GL_RGBA32F;
// We don't allow texturing or rendering to this format
@@ -2504,10 +2459,12 @@
{
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
@@ -2517,11 +2474,7 @@
}
if (texStorageSupported &&
!formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2) {
- info.fFlags |= FormatInfo::kUseTexStorage_Flag;
- info.fInternalFormatForTexImageOrStorage = GR_GL_SRGB8_ALPHA8;
- } else {
- info.fInternalFormatForTexImageOrStorage =
- texImageSupportsSizedInternalFormat ? GR_GL_SRGB8_ALPHA8 : GR_GL_SRGB_ALPHA;
+ info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
}
if (fSRGBSupport) {
@@ -2570,7 +2523,8 @@
{
FormatInfo& info = this->getFormatInfo(GrGLFormat::kCOMPRESSED_RGB8_ETC2);
info.fFormatType = FormatType::kNormalizedFixedPoint;
- info.fInternalFormatForTexImageOrStorage = GR_GL_COMPRESSED_RGB8_ETC2;
+ info.fBaseInternalFormat = GR_GL_RGB;
+ info.fInternalFormatForTexImage = 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;
@@ -2589,7 +2543,8 @@
{
FormatInfo& info = this->getFormatInfo(GrGLFormat::kCOMPRESSED_ETC1_RGB8);
info.fFormatType = FormatType::kNormalizedFixedPoint;
- info.fInternalFormatForTexImageOrStorage = GR_GL_COMPRESSED_ETC1_RGB8;
+ info.fBaseInternalFormat = GR_GL_RGB;
+ info.fInternalFormatForTexImage = 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;
@@ -2603,12 +2558,12 @@
{
FormatInfo& info = this->getFormatInfo(GrGLFormat::kR16);
info.fFormatType = FormatType::kNormalizedFixedPoint;
- info.fInternalFormatForTexImageOrStorage =
+ info.fBaseInternalFormat = GR_GL_RED;
+ info.fSizedInternalFormat = GR_GL_R16;
+ info.fInternalFormatForTexImage =
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;
}
@@ -2654,12 +2609,12 @@
{
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRG16);
info.fFormatType = FormatType::kNormalizedFixedPoint;
- info.fInternalFormatForTexImageOrStorage =
+ info.fBaseInternalFormat = GR_GL_RG;
+ info.fSizedInternalFormat = GR_GL_RG16;
+ info.fInternalFormatForTexImage =
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;
}
@@ -2724,12 +2679,12 @@
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA16);
info.fFormatType = FormatType::kNormalizedFixedPoint;
- info.fInternalFormatForTexImageOrStorage =
+ info.fBaseInternalFormat = GR_GL_RGBA;
+ info.fSizedInternalFormat = GR_GL_RGBA16;
+ info.fInternalFormatForTexImage =
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;
}
@@ -2798,12 +2753,12 @@
FormatInfo& info = this->getFormatInfo(GrGLFormat::kRG16F);
info.fFormatType = FormatType::kFloat;
- info.fInternalFormatForTexImageOrStorage =
+ info.fBaseInternalFormat = GR_GL_RG;
+ info.fSizedInternalFormat = GR_GL_RG16F;
+ info.fInternalFormatForTexImage =
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;
}
@@ -3661,8 +3616,7 @@
return false;
}
}
- }
- if (auto rt = surface->asRenderTarget()) {
+ } if (auto rt = surface->asRenderTarget()) {
if (fUseDrawInsteadOfAllRenderTargetWrites) {
return false;
}
@@ -3883,7 +3837,7 @@
}
bool GrGLCaps::formatSupportsTexStorage(GrGLFormat format) const {
- return SkToBool(this->getFormatInfo(format).fFlags & FormatInfo::kUseTexStorage_Flag);
+ return SkToBool(this->getFormatInfo(format).fFlags & FormatInfo::kCanUseTexStorage_Flag);
}
static GrPixelConfig validate_sized_format(GrGLFormat format,
@@ -4056,12 +4010,12 @@
GrBackendFormat GrGLCaps::onGetDefaultBackendFormat(GrColorType ct,
GrRenderable renderable) const {
- // TODO: make use of renderable.
auto format = this->getFormatFromColorType(ct);
if (format == GrGLFormat::kUnknown) {
return GrBackendFormat();
}
- return GrBackendFormat::MakeGL(GrGLFormatToEnum(format), GR_GL_TEXTURE_2D);
+ // TODO: plumb 'renderable' into getSizedInternalFormat (or, at least, make use of it)
+ return GrBackendFormat::MakeGL(this->getSizedInternalFormat(format), GR_GL_TEXTURE_2D);
}
GrBackendFormat GrGLCaps::getBackendFormatFromCompressionType(
@@ -4073,6 +4027,8 @@
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) {
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index d936cc2..24f9f63 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -142,36 +142,13 @@
return fColorTypeToFormatTable[idx];
}
- /**
- * 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;
+ GrGLenum formatSizedInternalFormat(GrGLFormat format) const {
+ return this->getFormatInfo(format).fSizedInternalFormat;
}
- /**
- * 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 getTexImageFormats(GrGLFormat surfaceFormat, GrColorType surfaceColorType,
+ GrColorType memoryColorType, GrGLenum* internalFormat,
+ GrGLenum* externalFormat, GrGLenum* externalType) const;
void getReadPixelsFormat(GrGLFormat surfaceFormat, GrColorType surfaceColorType,
GrColorType memoryColorType, GrGLenum* externalFormat,
@@ -189,6 +166,14 @@
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.
*/
@@ -196,6 +181,14 @@
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.
*/
@@ -411,6 +404,8 @@
GrBackendFormat getBackendFormatFromCompressionType(SkImage::CompressionType) const override;
+ bool canClearTextureOnCreation() const override;
+
GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override;
GrSwizzle getOutputSwizzle(const GrBackendFormat&, GrColorType) const override;
@@ -623,30 +618,34 @@
still attach it to a FBO for blitting or reading pixels. */
kFBOColorAttachment_Flag = 0x2,
kFBOColorAttachmentWithMSAA_Flag = 0x4,
- kUseTexStorage_Flag = 0x8,
+ kCanUseTexStorage_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 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 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 glRenderbufferStorageMultisample...
+ // Usually one of fBaseInternalFormat or fSizedInternalFormat but may vary depending on the
+ // particular format, GL version, extensions.
GrGLenum fInternalFormatForRenderbuffer = 0;
- // 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;
+ // Default value to use along with fBaseInternalFormat for functions such as glTexImage2D
+ // when not input providing data (passing nullptr). Not defined for compressed formats.
GrGLenum fDefaultExternalType = 0;
- GrGLenum fTexSubImageZeroDataBpp = 0;
enum {
// This indicates that a stencil format has not yet been determined for the config.
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 0917e79..8cbf08b 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -719,20 +719,22 @@
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 {
@@ -844,8 +846,8 @@
SkASSERT(!GrGLFormatIsCompressed(glTex->format()));
return this->uploadTexData(glTex->format(), surfaceColorType, glTex->width(), glTex->height(),
- glTex->target(), left, top, width, height, srcColorType, texels,
- mipLevelCount);
+ glTex->target(), kWrite_UploadType, left, top,width,
+ height, srcColorType, texels, mipLevelCount);
}
bool GrGLGpu::onTransferPixelsTo(GrTexture* texture, int left, int top, int width, int height,
@@ -894,11 +896,13 @@
}
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().getTexSubImageExternalFormatAndType(
- textureFormat, textureColorType, bufferColorType, &externalFormat, &externalType);
+ this->glCaps().getTexImageFormats(textureFormat, textureColorType, bufferColorType,
+ &internalFormat, &externalFormat, &externalType);
if (!externalFormat || !externalType) {
return false;
}
@@ -929,6 +933,178 @@
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()) {
@@ -937,10 +1113,11 @@
}
}
-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) {
+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) {
// If we're uploading compressed data then we should be using uploadCompressedTexData
SkASSERT(!GrGLFormatIsCompressed(textureFormat));
@@ -964,15 +1141,19 @@
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().getTexSubImageExternalFormatAndType(
- textureFormat, textureColorType, srcColorType, &externalFormat, &externalType);
+ this->glCaps().getTexImageFormats(textureFormat, textureColorType, srcColorType,
+ &internalFormat, &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
@@ -981,40 +1162,61 @@
*/
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;
}
- GR_GL_CALL(interface, PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1));
+ if (mipLevelCount) {
+ GR_GL_CALL(interface, PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1));
+ }
- for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
- if (!texels[currentMipLevel].fPixels) {
- if (mipMapsStatus) {
- *mipMapsStatus = GrMipMapsStatus::kDirty;
+ 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;
}
- 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;
+ 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;
- }
+ 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));
+ GL_CALL(TexSubImage2D(target,
+ currentMipLevel,
+ left, top,
+ currentWidth,
+ currentHeight,
+ externalFormat, externalType,
+ texels[currentMipLevel].fPixels));
+ }
}
- if (restoreGLRowLength) {
- SkASSERT(caps.writePixelsRowBytesSupport());
- GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
- }
- return true;
+
+ restore_pixelstore_state(*interface, caps, restoreGLRowLength);
+
+ return succeeded;
}
bool GrGLGpu::uploadCompressedTexData(GrGLFormat format,
@@ -1026,7 +1228,7 @@
const GrGLCaps& caps = this->glCaps();
// We only need the internal format for compressed 2D textures.
- GrGLenum internalFormat = caps.getTexImageOrStorageInternalFormat(format);
+ GrGLenum internalFormat = caps.getTexImageInternalFormat(format);
if (!internalFormat) {
return 0;
}
@@ -1225,17 +1427,16 @@
int renderTargetSampleCnt,
SkBudgeted budgeted,
GrProtected isProtected,
- int mipLevelCount,
- uint32_t levelClearMask) {
+ const GrMipLevel texels[],
+ int mipLevelCount) {
// We don't support protected textures in GL.
if (isProtected == GrProtected::kYes) {
return nullptr;
}
SkASSERT(GrGLCaps::kNone_MSFBOType != this->glCaps().msFBOType() || renderTargetSampleCnt == 1);
- SkASSERT(mipLevelCount > 0);
- GrMipMapsStatus mipMapsStatus =
- mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
+
+ GrMipMapsStatus mipMapsStatus;
GrGLTextureParameters::SamplerOverriddenState initialState;
GrGLTexture::Desc texDesc;
texDesc.fSize = {desc.fWidth, desc.fHeight};
@@ -1246,8 +1447,18 @@
SkASSERT(texDesc.fFormat != GrGLFormat::kUnknown);
SkASSERT(!GrGLFormatIsCompressed(texDesc.fFormat));
- texDesc.fID = this->createTexture2D({desc.fWidth, desc.fHeight}, texDesc.fFormat, renderable,
- &initialState, mipLevelCount);
+ // 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);
if (!texDesc.fID) {
return return_null_texture();
@@ -1272,49 +1483,16 @@
// The non-sampler params are still at their default values.
tex->parameters()->set(&initialState, GrGLTextureParameters::NonsamplerState(),
fResetTimestampForTextureParameters);
- 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()));
- }
+ 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));
}
}
}
@@ -1378,11 +1556,46 @@
// Default to unsupported, set this if we find a stencil format that works.
int firstWorkingStencilFormatIndex = -1;
- GrGLuint colorID =
- this->createTexture2D({kSize, kSize}, format, GrRenderable::kYes, nullptr, 1);
- if (!colorID) {
+ // 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) {
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));
@@ -1478,7 +1691,11 @@
GrGLFormat format,
GrRenderable renderable,
GrGLTextureParameters::SamplerOverriddenState* initialState,
- int mipLevelCount) {
+ GrColorType textureColorType,
+ GrColorType srcColorType,
+ const GrMipLevel texels[],
+ int mipLevelCount,
+ GrMipMapsStatus* mipMapsStatus) {
SkASSERT(format != GrGLFormat::kUnknown);
SkASSERT(!GrGLFormatIsCompressed(format));
@@ -1496,46 +1713,25 @@
GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_USAGE, GR_GL_FRAMEBUFFER_ATTACHMENT));
}
- if (initialState) {
- *initialState = set_initial_texture_params(this->glInterface(), GR_GL_TEXTURE_2D);
- } else {
- set_initial_texture_params(this->glInterface(), GR_GL_TEXTURE_2D);
- }
+ *initialState = set_initial_texture_params(this->glInterface(), GR_GL_TEXTURE_2D);
- 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 (!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 (success) {
- return id;
- }
- GL_CALL(DeleteTextures(1, &id));
- return 0;
+ return id;
}
GrStencilAttachment* GrGLGpu::createStencilAttachmentForRenderTarget(
@@ -1965,7 +2161,7 @@
}
} else {
// Use a temporary FBO.
- this->bindSurfaceFBOForPixelOps(surface, 0, GR_GL_FRAMEBUFFER, kSrc_TempFBOTarget);
+ this->bindSurfaceFBOForPixelOps(surface, GR_GL_FRAMEBUFFER, kSrc_TempFBOTarget);
fHWBoundRenderTargetUniqueID.makeInvalid();
}
@@ -2006,7 +2202,7 @@
}
if (!renderTarget) {
- this->unbindSurfaceFBOForPixelOps(surface, 0, GR_GL_FRAMEBUFFER);
+ this->unbindTextureFBOForPixelOps(GR_GL_FRAMEBUFFER, surface);
}
return true;
}
@@ -2819,10 +3015,10 @@
}
// If a temporary FBO was created, its non-zero ID is returned.
-void GrGLGpu::bindSurfaceFBOForPixelOps(GrSurface* surface, int mipLevel, GrGLenum fboTarget,
+void GrGLGpu::bindSurfaceFBOForPixelOps(GrSurface* surface, GrGLenum fboTarget,
TempFBOTarget tempFBOTarget) {
GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(surface->asRenderTarget());
- if (!rt || mipLevel > 0) {
+ if (!rt) {
SkASSERT(surface->asTexture());
GrGLTexture* texture = static_cast<GrGLTexture*>(surface->asTexture());
GrGLuint texID = texture->textureID();
@@ -2835,20 +3031,20 @@
}
this->bindFramebuffer(fboTarget, *tempFBOID);
- GR_GL_CALL(
- this->glInterface(),
- FramebufferTexture2D(fboTarget, GR_GL_COLOR_ATTACHMENT0, target, texID, mipLevel));
- if (mipLevel == 0) {
- texture->baseLevelWasBoundToFBO();
- }
+ GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget,
+ GR_GL_COLOR_ATTACHMENT0,
+ target,
+ texID,
+ 0));
+ texture->baseLevelWasBoundToFBO();
} else {
this->bindFramebuffer(fboTarget, rt->renderFBOID());
}
}
-void GrGLGpu::unbindSurfaceFBOForPixelOps(GrSurface* surface, int mipLevel, GrGLenum fboTarget) {
+void GrGLGpu::unbindTextureFBOForPixelOps(GrGLenum fboTarget, GrSurface* surface) {
// bindSurfaceFBOForPixelOps temporarily binds textures that are not render targets to
- if (mipLevel > 0 || !surface->asRenderTarget()) {
+ if (!surface->asRenderTarget()) {
SkASSERT(surface->asTexture());
GrGLenum textureTarget = static_cast<GrGLTexture*>(surface->asTexture())->target();
GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget,
@@ -3230,7 +3426,7 @@
int h = srcRect.height();
// We don't swizzle at all in our copies.
this->bindTexture(0, GrSamplerState::ClampNearest(), GrSwizzle::RGBA(), srcTex);
- this->bindSurfaceFBOForPixelOps(dst, 0, GR_GL_FRAMEBUFFER, kDst_TempFBOTarget);
+ this->bindSurfaceFBOForPixelOps(dst, GR_GL_FRAMEBUFFER, kDst_TempFBOTarget);
this->flushViewport(dst->width(), dst->height());
fHWBoundRenderTargetUniqueID.makeInvalid();
SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, w, h);
@@ -3273,7 +3469,7 @@
this->flushFramebufferSRGB(true);
}
GL_CALL(DrawArrays(GR_GL_TRIANGLE_STRIP, 0, 4));
- this->unbindSurfaceFBOForPixelOps(dst, 0, GR_GL_FRAMEBUFFER);
+ this->unbindTextureFBOForPixelOps(GR_GL_FRAMEBUFFER, dst);
// 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;
@@ -3282,7 +3478,7 @@
void GrGLGpu::copySurfaceAsCopyTexSubImage(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
const SkIPoint& dstPoint) {
SkASSERT(can_copy_texsubimage(dst, src, this->glCaps()));
- this->bindSurfaceFBOForPixelOps(src, 0, GR_GL_FRAMEBUFFER, kSrc_TempFBOTarget);
+ this->bindSurfaceFBOForPixelOps(src, GR_GL_FRAMEBUFFER, kSrc_TempFBOTarget);
GrGLTexture* dstTex = static_cast<GrGLTexture *>(dst->asTexture());
SkASSERT(dstTex);
// We modified the bound FBO
@@ -3293,7 +3489,7 @@
dstPoint.fX, dstPoint.fY,
srcRect.fLeft, srcRect.fTop,
srcRect.width(), srcRect.height()));
- this->unbindSurfaceFBOForPixelOps(src, 0, GR_GL_FRAMEBUFFER);
+ this->unbindTextureFBOForPixelOps(GR_GL_FRAMEBUFFER, src);
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.
@@ -3311,8 +3507,8 @@
}
}
- this->bindSurfaceFBOForPixelOps(dst, 0, GR_GL_DRAW_FRAMEBUFFER, kDst_TempFBOTarget);
- this->bindSurfaceFBOForPixelOps(src, 0, GR_GL_READ_FRAMEBUFFER, kSrc_TempFBOTarget);
+ this->bindSurfaceFBOForPixelOps(dst, GR_GL_DRAW_FRAMEBUFFER, kDst_TempFBOTarget);
+ this->bindSurfaceFBOForPixelOps(src, GR_GL_READ_FRAMEBUFFER, kSrc_TempFBOTarget);
// We modified the bound FBO
fHWBoundRenderTargetUniqueID.makeInvalid();
@@ -3329,8 +3525,8 @@
dstRect.fRight,
dstRect.fBottom,
GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
- this->unbindSurfaceFBOForPixelOps(dst, 0, GR_GL_DRAW_FRAMEBUFFER);
- this->unbindSurfaceFBOForPixelOps(src, 0, GR_GL_READ_FRAMEBUFFER);
+ this->unbindTextureFBOForPixelOps(GR_GL_DRAW_FRAMEBUFFER, dst);
+ this->unbindTextureFBOForPixelOps(GR_GL_READ_FRAMEBUFFER, src);
// The rect is already in device space so we pass in kTopLeft so no flip is done.
this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
@@ -3568,7 +3764,8 @@
GrGLTextureInfo info;
GrGLTextureParameters::SamplerOverriddenState initialState;
- SkTDArray<GrMipLevel> texels;
+ int mipLevelCount = 0;
+ SkAutoTMalloc<GrMipLevel> texels;
SkAutoMalloc pixelStorage;
SkImage::CompressionType compressionType;
if (GrGLFormatToCompressionType(glFormat, &compressionType)) {
@@ -3594,15 +3791,16 @@
info.fTarget = GR_GL_TEXTURE_2D;
} else {
if (srcPixels) {
- texels.append(1);
- texels[0] = {srcPixels, rowBytes};
+ mipLevelCount = 1;
+ texels.reset(mipLevelCount);
+ texels.get()[0] = {srcPixels, rowBytes};
} else if (color) {
- int mipLevelCount = 1;
+ mipLevelCount = 1;
if (GrMipMapped::kYes == mipMapped) {
mipLevelCount = SkMipMap::ComputeLevelCount(w, h) + 1;
}
- texels.append(mipLevelCount);
+ texels.reset(mipLevelCount);
SkTArray<size_t> individualMipOffsets(mipLevelCount);
size_t bytesPerPixel = GrBytesPerPixel(config);
@@ -3619,7 +3817,7 @@
int twoToTheMipLevel = 1 << i;
int currentWidth = SkTMax(1, w / twoToTheMipLevel);
- texels[i] = {&(tmpPixels[offset]), currentWidth * bytesPerPixel};
+ texels.get()[i] = {&(tmpPixels[offset]), currentWidth * bytesPerPixel};
}
}
GrSurfaceDesc desc;
@@ -3629,19 +3827,20 @@
info.fTarget = GR_GL_TEXTURE_2D;
info.fFormat = GrGLFormatToEnum(glFormat);
- info.fID = this->createTexture2D({desc.fWidth, desc.fHeight}, glFormat, renderable,
- &initialState, SkTMax(1, texels.count()));
+ // 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);
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
@@ -3689,7 +3888,17 @@
if (!this->glCaps().isFormatRenderable(format, 1)) {
return {};
}
- bool useTexture = format == GrGLFormat::kBGRA8;
+ 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);
+ }
int sFormatIdx = this->getCompatibleStencilIndex(format);
if (sFormatIdx < 0) {
return {};
@@ -3722,7 +3931,7 @@
GrGLFramebufferInfo info;
info.fFBOID = 0;
- info.fFormat = GrGLFormatToEnum(format);
+ info.fFormat = this->glCaps().formatSizedInternalFormat(format);
GL_CALL(GenFramebuffers(1, &info.fFBOID));
if (!info.fFBOID) {
deleteIDs();
@@ -3733,19 +3942,15 @@
this->bindFramebuffer(GR_GL_FRAMEBUFFER, info.fFBOID);
if (useTexture) {
- GrGLTextureParameters::SamplerOverriddenState initialState;
- colorID = this->createTexture2D({w, h}, format, GrRenderable::kYes, &initialState, 1);
- if (!colorID) {
- deleteIDs();
- return {};
- }
+ this->bindTextureToScratchUnit(GR_GL_TEXTURE_2D, colorID);
+ GL_CALL(TexImage2D(GR_GL_TEXTURE_2D, 0, colorBufferFormat, w, h, 0, externalFormat,
+ externalType, nullptr));
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, renderBufferFormat, w, h));
+ RenderbufferStorage(GR_GL_RENDERBUFFER, colorBufferFormat, w, h));
GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0,
GR_GL_RENDERBUFFER, colorID));
}
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 908ba5d..efacc32 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -195,8 +195,8 @@
int renderTargetSampleCnt,
SkBudgeted,
GrProtected,
- int mipLevelCount,
- uint32_t levelClearMask) override;
+ const GrMipLevel[],
+ int mipLevelCount) override;
sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, const GrBackendFormat&,
SkImage::CompressionType compression, SkBudgeted,
const void* data) override;
@@ -228,7 +228,11 @@
GrGLFormat format,
GrRenderable,
GrGLTextureParameters::SamplerOverriddenState* initialState,
- int mipLevelCount);
+ GrColorType textureColorType,
+ GrColorType srcColorType,
+ const GrMipLevel texels[],
+ int mipLevelCount,
+ GrMipMapsStatus* mipMapsStatus);
GrGLuint createCompressedTexture2D(const SkISize& size, GrGLFormat format,
SkImage::CompressionType compression,
@@ -373,9 +377,15 @@
void flushFramebufferSRGB(bool enable);
- 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,
+ // 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,
GrMipMapsStatus* mipMapsStatus = nullptr);
// Helper for onCreateCompressedTexture. Compressed textures are read-only so we only use this
@@ -398,11 +408,11 @@
// 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, int mipLevel, GrGLenum fboTarget,
+ void bindSurfaceFBOForPixelOps(GrSurface* surface, GrGLenum fboTarget,
TempFBOTarget tempFBOTarget);
// Must be called if bindSurfaceFBOForPixelOps was used to bind a surface for copying.
- void unbindSurfaceFBOForPixelOps(GrSurface* surface, int mipLevel, GrGLenum fboTarget);
+ void unbindTextureFBOForPixelOps(GrGLenum fboTarget, GrSurface* surface);
#ifdef SK_ENABLE_DUMP_GPU
void onDumpJSON(SkJSONWriter*) const override;
diff --git a/src/gpu/mock/GrMockCaps.h b/src/gpu/mock/GrMockCaps.h
index 9a6148cc..911f571 100644
--- a/src/gpu/mock/GrMockCaps.h
+++ b/src/gpu/mock/GrMockCaps.h
@@ -132,6 +132,8 @@
return {};
}
+ bool canClearTextureOnCreation() const override { return true; }
+
GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override {
return GrSwizzle();
}
diff --git a/src/gpu/mock/GrMockGpu.cpp b/src/gpu/mock/GrMockGpu.cpp
index bc91c75..817bb08 100644
--- a/src/gpu/mock/GrMockGpu.cpp
+++ b/src/gpu/mock/GrMockGpu.cpp
@@ -137,8 +137,8 @@
int renderTargetSampleCnt,
SkBudgeted budgeted,
GrProtected isProtected,
- int mipLevelCount,
- uint32_t levelClearMask) {
+ const GrMipLevel texels[],
+ int mipLevelCount) {
if (fMockOptions.fFailTextureAllocations) {
return nullptr;
}
@@ -146,8 +146,14 @@
GrColorType ct = format.asMockColorType();
SkASSERT(ct != GrColorType::kUnknown);
- GrMipMapsStatus mipMapsStatus =
- mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
+ GrMipMapsStatus mipMapsStatus = mipLevelCount > 1 ? GrMipMapsStatus::kValid
+ : GrMipMapsStatus::kNotAllocated;
+ for (int i = 0; i < mipLevelCount; ++i) {
+ if (!texels[i].fPixels) {
+ mipMapsStatus = GrMipMapsStatus::kDirty;
+ break;
+ }
+ }
GrMockTextureInfo texInfo(ct, NextInternalTextureID());
if (renderable == GrRenderable::kYes) {
GrMockRenderTargetInfo rtInfo(ct, NextInternalRenderTargetID());
diff --git a/src/gpu/mock/GrMockGpu.h b/src/gpu/mock/GrMockGpu.h
index 7fec665..7334591 100644
--- a/src/gpu/mock/GrMockGpu.h
+++ b/src/gpu/mock/GrMockGpu.h
@@ -63,8 +63,8 @@
int renderTargetSampleCnt,
SkBudgeted,
GrProtected,
- int mipLevelCount,
- uint32_t levelClearMask) override;
+ const GrMipLevel[],
+ int mipLevelCount) override;
sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, const GrBackendFormat&,
SkImage::CompressionType, SkBudgeted,
diff --git a/src/gpu/mtl/GrMtlCaps.h b/src/gpu/mtl/GrMtlCaps.h
index d56f3a2..b557008 100644
--- a/src/gpu/mtl/GrMtlCaps.h
+++ b/src/gpu/mtl/GrMtlCaps.h
@@ -78,6 +78,8 @@
return fColorTypeToFormatTable[idx];
}
+ bool canClearTextureOnCreation() const override { return true; }
+
GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override;
GrSwizzle getOutputSwizzle(const GrBackendFormat&, GrColorType) const override;
diff --git a/src/gpu/mtl/GrMtlGpu.h b/src/gpu/mtl/GrMtlGpu.h
index 0027956..a944349 100644
--- a/src/gpu/mtl/GrMtlGpu.h
+++ b/src/gpu/mtl/GrMtlGpu.h
@@ -139,8 +139,8 @@
int renderTargetSampleCnt,
SkBudgeted budgeted,
GrProtected,
- int mipLevelCount,
- uint32_t levelClearMask) override;
+ const GrMipLevel texels[],
+ int mipLevelCount) override;
sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, const GrBackendFormat&,
SkImage::CompressionType, SkBudgeted,
const void* data) override {
diff --git a/src/gpu/mtl/GrMtlGpu.mm b/src/gpu/mtl/GrMtlGpu.mm
index 37bd80a..37fd1a8 100644
--- a/src/gpu/mtl/GrMtlGpu.mm
+++ b/src/gpu/mtl/GrMtlGpu.mm
@@ -400,13 +400,13 @@
int renderTargetSampleCnt,
SkBudgeted budgeted,
GrProtected isProtected,
- int mipLevelCount,
- uint32_t levelClearMask) {
+ const GrMipLevel texels[],
+ int mipLevelCount) {
// We don't support protected textures in Metal.
if (isProtected == GrProtected::kYes) {
return nullptr;
}
- SkASSERT(mipLevelCount > 0);
+ int mipLevels = !mipLevelCount ? 1 : mipLevelCount;
MTLPixelFormat mtlPixelFormat = GrBackendFormatAsMTLPixelFormat(format);
SkASSERT(mtlPixelFormat != MTLPixelFormatInvalid);
@@ -422,7 +422,7 @@
texDesc.width = desc.fWidth;
texDesc.height = desc.fHeight;
texDesc.depth = 1;
- texDesc.mipmapLevelCount = mipLevelCount;
+ texDesc.mipmapLevelCount = mipLevels;
texDesc.sampleCount = 1;
texDesc.arrayLength = 1;
// Make all textures have private gpu only access. We can use transfer buffers or textures
@@ -431,8 +431,17 @@
texDesc.usage = MTLTextureUsageShaderRead;
texDesc.usage |= (renderable == GrRenderable::kYes) ? MTLTextureUsageRenderTarget : 0;
- GrMipMapsStatus mipMapsStatus =
- mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
+ 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;
+ }
+ }
+ }
+
if (renderable == GrRenderable::kYes) {
tex = GrMtlTextureRenderTarget::MakeNewTextureRenderTarget(this, budgeted,
desc, renderTargetSampleCnt,
@@ -445,9 +454,24 @@
return nullptr;
}
- if (levelClearMask) {
- auto colorType = GrPixelConfigToColorType(desc.fConfig);
- this->clearTexture(tex.get(), colorType, levelClearMask);
+ 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);
}
return tex;
diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp
index 8881ed8..f15ee7d 100644
--- a/src/gpu/vk/GrVkCaps.cpp
+++ b/src/gpu/vk/GrVkCaps.cpp
@@ -1610,6 +1610,8 @@
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));
diff --git a/src/gpu/vk/GrVkCaps.h b/src/gpu/vk/GrVkCaps.h
index 7141aaa..c781d51 100644
--- a/src/gpu/vk/GrVkCaps.h
+++ b/src/gpu/vk/GrVkCaps.h
@@ -171,6 +171,8 @@
return fColorTypeToFormatTable[idx];
}
+ bool canClearTextureOnCreation() const override;
+
GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override;
GrSwizzle getOutputSwizzle(const GrBackendFormat&, GrColorType) const override;
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 7b68e4d..a0d49ff 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -953,8 +953,8 @@
int renderTargetSampleCnt,
SkBudgeted budgeted,
GrProtected isProtected,
- int mipLevelCount,
- uint32_t levelClearMask) {
+ const GrMipLevel texels[],
+ int mipLevelCount) {
VkFormat pixelFormat;
SkAssertResult(format.asVkFormat(&pixelFormat));
SkASSERT(!GrVkFormatIsCompressed(pixelFormat));
@@ -975,20 +975,28 @@
// 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.
- SkASSERT(mipLevelCount > 0);
+ int mipLevels = !mipLevelCount ? 1 : mipLevelCount;
GrVkImage::ImageDesc imageDesc;
imageDesc.fImageType = VK_IMAGE_TYPE_2D;
imageDesc.fFormat = pixelFormat;
imageDesc.fWidth = desc.fWidth;
imageDesc.fHeight = desc.fHeight;
- imageDesc.fLevels = mipLevelCount;
+ imageDesc.fLevels = mipLevels;
imageDesc.fSamples = 1;
imageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
imageDesc.fUsageFlags = usageFlags;
imageDesc.fIsProtected = isProtected;
- GrMipMapsStatus mipMapsStatus =
- mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
+ 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;
+ }
+ }
+ }
sk_sp<GrVkTexture> tex;
if (renderable == GrRenderable::kYes) {
@@ -1002,11 +1010,20 @@
return nullptr;
}
- if (levelClearMask) {
+ 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()) {
SkSTArray<1, VkImageSubresourceRange> ranges;
bool inRange = false;
for (uint32_t i = 0; i < tex->mipLevels(); ++i) {
- if (levelClearMask & (1U << i)) {
+ if (i >= static_cast<uint32_t>(mipLevelCount) || !texels[i].fPixels) {
if (inRange) {
ranges.back().levelCount++;
} else {
@@ -1022,12 +1039,15 @@
inRange = false;
}
}
- 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());
+
+ 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());
+ }
}
return tex;
}
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index 4863445..f7af80f 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -196,8 +196,8 @@
int renderTargetSampleCnt,
SkBudgeted,
GrProtected,
- int mipLevelCount,
- uint32_t levelClearMask) override;
+ const GrMipLevel[],
+ int mipLevelCount) override;
sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, const GrBackendFormat&,
SkImage::CompressionType, SkBudgeted,
const void* data) override;
diff --git a/tools/gpu/gl/angle/GLTestContext_angle.cpp b/tools/gpu/gl/angle/GLTestContext_angle.cpp
index c7c9149..59430ca 100644
--- a/tools/gpu/gl/angle/GLTestContext_angle.cpp
+++ b/tools/gpu/gl/angle/GLTestContext_angle.cpp
@@ -499,7 +499,7 @@
}
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.