diff options
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/GrCaps.cpp | 3 | ||||
-rw-r--r-- | src/gpu/GrDrawOpAtlas.cpp | 3 | ||||
-rw-r--r-- | src/gpu/GrGpu.cpp | 37 | ||||
-rw-r--r-- | src/gpu/GrGpu.h | 8 | ||||
-rw-r--r-- | src/gpu/GrResourceProvider.cpp | 36 | ||||
-rw-r--r-- | src/gpu/GrShaderCaps.cpp | 3 | ||||
-rw-r--r-- | src/gpu/GrSurface.cpp | 15 | ||||
-rw-r--r-- | src/gpu/GrSurfaceProxy.cpp | 12 | ||||
-rw-r--r-- | src/gpu/GrTexture.cpp | 16 | ||||
-rw-r--r-- | src/gpu/GrTextureProducer.cpp | 4 | ||||
-rw-r--r-- | src/gpu/SkGr.h | 2 | ||||
-rw-r--r-- | src/gpu/gl/GrGLCaps.cpp | 48 | ||||
-rw-r--r-- | src/gpu/gl/GrGLCaps.h | 2 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.cpp | 265 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.h | 15 | ||||
-rw-r--r-- | src/gpu/ops/GrCopySurfaceOp.cpp | 3 | ||||
-rw-r--r-- | src/gpu/vk/GrVkCaps.cpp | 6 | ||||
-rw-r--r-- | src/gpu/vk/GrVkGpu.cpp | 65 | ||||
-rw-r--r-- | src/gpu/vk/GrVkGpu.h | 3 | ||||
-rw-r--r-- | src/gpu/vk/GrVkUtil.cpp | 6 |
20 files changed, 485 insertions, 67 deletions
diff --git a/src/gpu/GrCaps.cpp b/src/gpu/GrCaps.cpp index 5c04d190c5..4acf90ea13 100644 --- a/src/gpu/GrCaps.cpp +++ b/src/gpu/GrCaps.cpp @@ -21,6 +21,7 @@ static const char* pixel_config_name(GrPixelConfig config) { case kSRGBA_8888_GrPixelConfig: return "SRGBA8888"; case kSBGRA_8888_GrPixelConfig: return "SBGRA8888"; case kRGBA_8888_sint_GrPixelConfig: return "RGBA8888_sint"; + case kETC1_GrPixelConfig: return "ETC1"; case kRGBA_float_GrPixelConfig: return "RGBAFloat"; case kRG_float_GrPixelConfig: return "RGFloat"; case kAlpha_half_GrPixelConfig: return "AlphaHalf"; @@ -39,6 +40,7 @@ GrCaps::GrCaps(const GrContextOptions& options) { fReuseScratchTextures = true; fReuseScratchBuffers = true; fGpuTracingSupport = false; + fCompressedTexSubImageSupport = false; fOversizedStencilSupport = false; fTextureBarrierSupport = false; fSampleLocationsSupport = false; @@ -128,6 +130,7 @@ SkString GrCaps::dump() const { r.appendf("Reuse Scratch Textures : %s\n", gNY[fReuseScratchTextures]); r.appendf("Reuse Scratch Buffers : %s\n", gNY[fReuseScratchBuffers]); r.appendf("Gpu Tracing Support : %s\n", gNY[fGpuTracingSupport]); + r.appendf("Compressed Update Support : %s\n", gNY[fCompressedTexSubImageSupport]); r.appendf("Oversized Stencil Support : %s\n", gNY[fOversizedStencilSupport]); r.appendf("Texture Barrier Support : %s\n", gNY[fTextureBarrierSupport]); r.appendf("Sample Locations Support : %s\n", gNY[fSampleLocationsSupport]); diff --git a/src/gpu/GrDrawOpAtlas.cpp b/src/gpu/GrDrawOpAtlas.cpp index be8258ab51..0e8de3c578 100644 --- a/src/gpu/GrDrawOpAtlas.cpp +++ b/src/gpu/GrDrawOpAtlas.cpp @@ -172,6 +172,9 @@ GrDrawOpAtlas::GrDrawOpAtlas(GrContext* context, sk_sp<GrTextureProxy> proxy, SkDEBUGCODE(fNumPlots = numPlotsX * numPlotsY;) + // We currently do not support compressed atlases... + SkASSERT(!GrPixelConfigIsCompressed(fProxy->config())); + // set up allocated plots fPlotArray.reset(new sk_sp<Plot>[ numPlotsX * numPlotsY ]); diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp index 14ce050933..c1970afbe1 100644 --- a/src/gpu/GrGpu.cpp +++ b/src/gpu/GrGpu.cpp @@ -143,8 +143,24 @@ GrTexture* GrGpu::createTexture(const GrSurfaceDesc& origDesc, SkBudgeted budget desc.fOrigin = resolve_origin(desc.fOrigin, isRT); - this->handleDirtyContext(); - GrTexture* tex = this->onCreateTexture(desc, budgeted, texels); + GrTexture* tex = nullptr; + + if (GrPixelConfigIsCompressed(desc.fConfig)) { + // We shouldn't be rendering into this + SkASSERT(!isRT); + SkASSERT(0 == desc.fSampleCnt); + + if (!caps->npotTextureTileSupport() && + (!SkIsPow2(desc.fWidth) || !SkIsPow2(desc.fHeight))) { + return nullptr; + } + + this->handleDirtyContext(); + tex = this->onCreateCompressedTexture(desc, budgeted, texels); + } else { + this->handleDirtyContext(); + tex = this->onCreateTexture(desc, budgeted, texels); + } if (tex) { if (!caps->reuseScratchTextures() && !isRT) { tex->resourcePriv().removeScratchKey(); @@ -245,6 +261,9 @@ bool GrGpu::copySurface(GrSurface* dst, if (GrPixelConfigIsSint(dst->config()) != GrPixelConfigIsSint(src->config())) { return false; } + if (GrPixelConfigIsCompressed(dst->config())) { + return false; + } return this->onCopySurface(dst, src, srcRect, dstPoint); } @@ -256,6 +275,11 @@ bool GrGpu::getReadPixelsInfo(GrSurface* srcSurface, int width, int height, size SkASSERT(srcSurface); SkASSERT(kGpuPrefersDraw_DrawPreference != *drawPreference); + // We currently do not support reading into a compressed buffer + if (GrPixelConfigIsCompressed(readConfig)) { + return false; + } + // We currently do not support reading into the packed formats 565 or 4444 as they are not // required to have read back support on all devices and backends. if (kRGB_565_GrPixelConfig == readConfig || kRGBA_4444_GrPixelConfig == readConfig) { @@ -287,6 +311,10 @@ bool GrGpu::getWritePixelsInfo(GrSurface* dstSurface, int width, int height, SkASSERT(dstSurface); SkASSERT(kGpuPrefersDraw_DrawPreference != *drawPreference); + if (GrPixelConfigIsCompressed(dstSurface->config()) && dstSurface->config() != srcConfig) { + return false; + } + if (SkToBool(dstSurface->asRenderTarget())) { if (this->caps()->useDrawInsteadOfAllRenderTargetWrites()) { ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference); @@ -325,6 +353,11 @@ bool GrGpu::readPixels(GrSurface* surface, return false; } + // We cannot read pixels into a compressed buffer + if (GrPixelConfigIsCompressed(config)) { + return false; + } + size_t bpp = GrBytesPerPixel(config); if (!GrSurfacePriv::AdjustReadPixelParams(surface->width(), surface->height(), bpp, &left, &top, &width, &height, diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h index 897f2b8737..259c573757 100644 --- a/src/gpu/GrGpu.h +++ b/src/gpu/GrGpu.h @@ -100,7 +100,8 @@ public: * @param budgeted does this texture count against the resource cache budget? * @param texels array of mipmap levels containing texel data to load. * Each level begins with full-size palette data for paletted textures. - * It contains width*height texels. If there is only one + * For compressed formats the level contains the compressed pixel data. + * Otherwise, it contains width*height texels. If there is only one * element and it contains nullptr fPixels, texture data is * uninitialized. * @return The texture object if successful, otherwise nullptr. @@ -545,10 +546,13 @@ private: // 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. + // onCreateTexture/CompressedTexture are called. virtual GrTexture* onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted, const SkTArray<GrMipLevel>& texels) = 0; + virtual GrTexture* onCreateCompressedTexture(const GrSurfaceDesc& desc, + SkBudgeted budgeted, + const SkTArray<GrMipLevel>& texels) = 0; virtual sk_sp<GrTexture> onWrapBackendTexture(const GrBackendTexture&, GrSurfaceOrigin, diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp index 84e274eee2..2eb82714a2 100644 --- a/src/gpu/GrResourceProvider.cpp +++ b/src/gpu/GrResourceProvider.cpp @@ -157,15 +157,17 @@ sk_sp<GrTextureProxy> GrResourceProvider::createTextureProxy(const GrSurfaceDesc GrContext* context = fGpu->getContext(); - SkImageInfo srcInfo; - - if (make_info(desc.fWidth, desc.fHeight, desc.fConfig, &srcInfo)) { - sk_sp<GrTexture> tex = this->getExactScratch(desc, budgeted, 0); - sk_sp<GrSurfaceContext> sContext = - context->contextPriv().makeWrappedSurfaceContext(std::move(tex)); - if (sContext) { - if (sContext->writePixels(srcInfo, mipLevel.fPixels, mipLevel.fRowBytes, 0, 0)) { - return sContext->asTextureProxyRef(); + if (!GrPixelConfigIsCompressed(desc.fConfig)) { + SkImageInfo srcInfo; + + if (make_info(desc.fWidth, desc.fHeight, desc.fConfig, &srcInfo)) { + sk_sp<GrTexture> tex = this->getExactScratch(desc, budgeted, 0); + sk_sp<GrSurfaceContext> sContext = + context->contextPriv().makeWrappedSurfaceContext(std::move(tex)); + if (sContext) { + if (sContext->writePixels(srcInfo, mipLevel.fPixels, mipLevel.fRowBytes, 0, 0)) { + return sContext->asTextureProxyRef(); + } } } } @@ -190,12 +192,14 @@ sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, Sk return nullptr; } - sk_sp<GrTexture> tex = this->getExactScratch(desc, budgeted, flags); - if (tex) { - return tex; + if (!GrPixelConfigIsCompressed(desc.fConfig)) { + sk_sp<GrTexture> tex = this->getExactScratch(desc, budgeted, flags); + if (tex) { + return tex; + } } - tex.reset(fGpu->createTexture(desc, budgeted)); + sk_sp<GrTexture> tex(fGpu->createTexture(desc, budgeted)); return tex; } @@ -207,6 +211,11 @@ GrTexture* GrResourceProvider::createApproxTexture(const GrSurfaceDesc& desc, ui return nullptr; } + // Currently we don't recycle compressed textures as scratch. + if (GrPixelConfigIsCompressed(desc.fConfig)) { + return nullptr; + } + if (!validate_desc(desc, *fCaps)) { return nullptr; } @@ -217,6 +226,7 @@ GrTexture* GrResourceProvider::createApproxTexture(const GrSurfaceDesc& desc, ui GrTexture* GrResourceProvider::refScratchTexture(const GrSurfaceDesc& inDesc, uint32_t flags) { ASSERT_SINGLE_OWNER SkASSERT(!this->isAbandoned()); + SkASSERT(!GrPixelConfigIsCompressed(inDesc.fConfig)); SkASSERT(validate_desc(inDesc, *fCaps)); SkTCopyOnFirstWrite<GrSurfaceDesc> desc(inDesc); diff --git a/src/gpu/GrShaderCaps.cpp b/src/gpu/GrShaderCaps.cpp index 9a429bb0de..636b955ab7 100644 --- a/src/gpu/GrShaderCaps.cpp +++ b/src/gpu/GrShaderCaps.cpp @@ -213,12 +213,13 @@ void GrShaderCaps::initSamplerPrecisionTable() { table[kSRGBA_8888_GrPixelConfig] = lowp; table[kSBGRA_8888_GrPixelConfig] = lowp; table[kRGBA_8888_sint_GrPixelConfig] = lowp; + table[kETC1_GrPixelConfig] = lowp; table[kRGBA_float_GrPixelConfig] = kHigh_GrSLPrecision; table[kRG_float_GrPixelConfig] = kHigh_GrSLPrecision; table[kAlpha_half_GrPixelConfig] = mediump; table[kRGBA_half_GrPixelConfig] = mediump; - GR_STATIC_ASSERT(14 == kGrPixelConfigCnt); + GR_STATIC_ASSERT(15 == kGrPixelConfigCnt); } } diff --git a/src/gpu/GrSurface.cpp b/src/gpu/GrSurface.cpp index 635e74e49c..26584285b8 100644 --- a/src/gpu/GrSurface.cpp +++ b/src/gpu/GrSurface.cpp @@ -29,6 +29,7 @@ size_t GrSurface::WorstCaseSize(const GrSurfaceDesc& desc, bool useNextPow2) { colorValuesPerPixel += 1; } SkASSERT(kUnknown_GrPixelConfig != desc.fConfig); + SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig)); size_t colorBytes = (size_t) width * height * GrBytesPerPixel(desc.fConfig); // This would be a nice assert to have (i.e., we aren't creating 0 width/height surfaces). @@ -38,7 +39,11 @@ size_t GrSurface::WorstCaseSize(const GrSurfaceDesc& desc, bool useNextPow2) { size = colorValuesPerPixel * colorBytes; size += colorBytes/3; // in case we have to mipmap } else { - size = (size_t) width * height * GrBytesPerPixel(desc.fConfig); + if (GrPixelConfigIsCompressed(desc.fConfig)) { + size = GrCompressedFormatDataSize(desc.fConfig, width, height); + } else { + size = (size_t) width * height * GrBytesPerPixel(desc.fConfig); + } size += size/3; // in case we have to mipmap } @@ -52,11 +57,17 @@ size_t GrSurface::ComputeSize(GrPixelConfig config, int colorSamplesPerPixel, bool hasMIPMaps, bool useNextPow2) { + size_t colorSize; + width = useNextPow2 ? GrNextPow2(width) : width; height = useNextPow2 ? GrNextPow2(height) : height; SkASSERT(kUnknown_GrPixelConfig != config); - size_t colorSize = (size_t)width * height * GrBytesPerPixel(config); + if (GrPixelConfigIsCompressed(config)) { + colorSize = GrCompressedFormatDataSize(config, width, height); + } else { + colorSize = (size_t)width * height * GrBytesPerPixel(config); + } SkASSERT(colorSize > 0); size_t finalSize = colorSamplesPerPixel * colorSize; diff --git a/src/gpu/GrSurfaceProxy.cpp b/src/gpu/GrSurfaceProxy.cpp index 3ced81b150..b22d0aaa4c 100644 --- a/src/gpu/GrSurfaceProxy.cpp +++ b/src/gpu/GrSurfaceProxy.cpp @@ -136,6 +136,18 @@ sk_sp<GrTextureProxy> GrSurfaceProxy::MakeDeferred(GrResourceProvider* resourceP // TODO: move this logic into GrResourceProvider! // TODO: share this testing code with check_texture_creation_params + if (GrPixelConfigIsCompressed(desc.fConfig)) { + if (SkBackingFit::kApprox == fit || kBottomLeft_GrSurfaceOrigin == desc.fOrigin) { + // We don't allow scratch compressed textures and, apparently can't Y-flip compressed + // textures + return nullptr; + } + + if (!caps->npotTextureTileSupport() && (!SkIsPow2(desc.fWidth) || !SkIsPow2(desc.fHeight))) { + return nullptr; + } + } + if (!caps->isConfigTexturable(desc.fConfig)) { return nullptr; } diff --git a/src/gpu/GrTexture.cpp b/src/gpu/GrTexture.cpp index 064cc0a22b..cbab5f0f60 100644 --- a/src/gpu/GrTexture.cpp +++ b/src/gpu/GrTexture.cpp @@ -76,14 +76,16 @@ GrTexture::GrTexture(GrGpu* gpu, const GrSurfaceDesc& desc, GrSLType samplerType } void GrTexture::computeScratchKey(GrScratchKey* key) const { - const GrRenderTarget* rt = this->asRenderTarget(); - int sampleCount = 0; - if (rt) { - sampleCount = rt->numStencilSamples(); + if (!GrPixelConfigIsCompressed(this->config())) { + const GrRenderTarget* rt = this->asRenderTarget(); + int sampleCount = 0; + if (rt) { + sampleCount = rt->numStencilSamples(); + } + GrTexturePriv::ComputeScratchKey(this->config(), this->width(), this->height(), + this->origin(), SkToBool(rt), sampleCount, + this->texturePriv().hasMipMaps(), key); } - GrTexturePriv::ComputeScratchKey(this->config(), this->width(), this->height(), - this->origin(), SkToBool(rt), sampleCount, - this->texturePriv().hasMipMaps(), key); } void GrTexturePriv::ComputeScratchKey(GrPixelConfig config, int width, int height, diff --git a/src/gpu/GrTextureProducer.cpp b/src/gpu/GrTextureProducer.cpp index b9e7dfc9b6..75796b1aa4 100644 --- a/src/gpu/GrTextureProducer.cpp +++ b/src/gpu/GrTextureProducer.cpp @@ -23,10 +23,12 @@ sk_sp<GrTextureProxy> GrTextureProducer::CopyOnGpu(GrContext* context, SkASSERT(!subset || !subset->isEmpty()); SkASSERT(context); + GrPixelConfig config = GrMakePixelConfigUncompressed(inputProxy->config()); + const SkRect dstRect = SkRect::MakeIWH(copyParams.fWidth, copyParams.fHeight); sk_sp<GrRenderTargetContext> copyRTC = context->makeDeferredRenderTargetContextWithFallback( - SkBackingFit::kExact, dstRect.width(), dstRect.height(), inputProxy->config(), nullptr); + SkBackingFit::kExact, dstRect.width(), dstRect.height(), config, nullptr); if (!copyRTC) { return nullptr; } diff --git a/src/gpu/SkGr.h b/src/gpu/SkGr.h index 0145513139..7784c53845 100644 --- a/src/gpu/SkGr.h +++ b/src/gpu/SkGr.h @@ -209,7 +209,7 @@ sk_sp<GrTextureProxy> GrRefCachedBitmapTextureProxy(GrContext*, /** * Creates a new texture for the bitmap. Does not concern itself with cache keys or texture params. * The bitmap must have CPU-accessible pixels. Attempts to take advantage of faster paths for - * yuv planes. + * compressed textures and yuv planes. */ sk_sp<GrTextureProxy> GrUploadBitmapToTextureProxy(GrResourceProvider*, const SkBitmap&, SkColorSpace* dstColorSpace); diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index b9eee088e0..f4e50628d0 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -1344,6 +1344,15 @@ bool GrGLCaps::getTexImageFormats(GrPixelConfig surfaceConfig, GrPixelConfig ext return true; } +bool GrGLCaps::getCompressedTexImageFormats(GrPixelConfig surfaceConfig, + GrGLenum* internalFormat) const { + if (!GrPixelConfigIsCompressed(surfaceConfig)) { + return false; + } + *internalFormat = fConfigTable[surfaceConfig].fFormats.fInternalFormatTexImage; + return true; +} + bool GrGLCaps::getReadPixelsFormat(GrPixelConfig surfaceConfig, GrPixelConfig externalConfig, GrGLenum* externalFormat, GrGLenum* externalType) const { if (!this->getExternalFormat(surfaceConfig, externalConfig, kOther_ExternalFormatUsage, @@ -1354,6 +1363,9 @@ bool GrGLCaps::getReadPixelsFormat(GrPixelConfig surfaceConfig, GrPixelConfig ex } bool GrGLCaps::getRenderbufferFormat(GrPixelConfig config, GrGLenum* internalFormat) const { + if (GrPixelConfigIsCompressed(config)) { + return false; + } *internalFormat = fConfigTable[config].fFormats.fInternalFormatRenderbuffer; return true; } @@ -1362,6 +1374,9 @@ bool GrGLCaps::getExternalFormat(GrPixelConfig surfaceConfig, GrPixelConfig memo ExternalFormatUsage usage, GrGLenum* externalFormat, GrGLenum* externalType) const { SkASSERT(externalFormat && externalType); + if (GrPixelConfigIsCompressed(memoryConfig)) { + return false; + } bool surfaceIsAlphaOnly = GrPixelConfigIsAlphaOnly(surfaceConfig); bool memoryIsAlphaOnly = GrPixelConfigIsAlphaOnly(memoryConfig); @@ -1911,6 +1926,39 @@ void GrGLCaps::initConfigTable(const GrContextOptions& contextOptions, } fConfigTable[kRGBA_half_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); + // Compressed texture support + + // glCompressedTexImage2D is available on all OpenGL ES devices. It is available on standard + // OpenGL after version 1.3. We'll assume at least that level of OpenGL support. + + // TODO: Fix command buffer bindings and remove this. + fCompressedTexSubImageSupport = SkToBool(gli->fFunctions.fCompressedTexSubImage2D); + + // No sized/unsized internal format distinction for compressed formats, no external format. + // Below we set the external formats and types to 0. + { + fConfigTable[kETC1_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_COMPRESSED_ETC1_RGB8; + fConfigTable[kETC1_GrPixelConfig].fFormats.fSizedInternalFormat = + GR_GL_COMPRESSED_ETC1_RGB8; + fConfigTable[kETC1_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = 0; + fConfigTable[kETC1_GrPixelConfig].fFormats.fExternalType = 0; + fConfigTable[kETC1_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType; + if (kGL_GrGLStandard == standard) { + if (version >= GR_GL_VER(4, 3) || ctxInfo.hasExtension("GL_ARB_ES3_compatibility")) { + fConfigTable[kETC1_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; + } + } else { + if (version >= GR_GL_VER(3, 0) || + ctxInfo.hasExtension("GL_OES_compressed_ETC1_RGB8_texture") || + // ETC2 is a superset of ETC1, so we can just check for that, too. + (ctxInfo.hasExtension("GL_OES_compressed_ETC2_RGB8_texture") && + ctxInfo.hasExtension("GL_OES_compressed_ETC2_RGBA8_texture"))) { + fConfigTable[kETC1_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag; + } + } + fConfigTable[kETC1_GrPixelConfig].fSwizzle = GrSwizzle::RGBA(); + } + // Bulk populate the texture internal/external formats here and then deal with exceptions below. // ES 2.0 requires that the internal/external formats match. diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h index 3059ea7149..de3d8472f7 100644 --- a/src/gpu/gl/GrGLCaps.h +++ b/src/gpu/gl/GrGLCaps.h @@ -153,6 +153,8 @@ public: GrGLenum* internalFormat, GrGLenum* externalFormat, GrGLenum* externalType) const; + bool getCompressedTexImageFormats(GrPixelConfig surfaceConfig, GrGLenum* internalFormat) const; + bool getReadPixelsFormat(GrPixelConfig surfaceConfig, GrPixelConfig externalConfig, GrGLenum* externalFormat, GrGLenum* externalType) const; diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index 565e60a220..b324280895 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -662,6 +662,10 @@ bool GrGLGpu::onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height, GrPixelConfig srcConfig, DrawPreference* drawPreference, WritePixelTempDrawInfo* tempDrawInfo) { + if (GrPixelConfigIsCompressed(dstSurface->config())) { + return false; + } + // This subclass only allows writes to textures. If the dst is not a texture we have to draw // into it. We could use glDrawPixels on GLs that have it, but we don't today. if (!dstSurface->asTexture()) { @@ -761,9 +765,20 @@ bool GrGLGpu::onWritePixels(GrSurface* surface, this->setScratchTextureUnit(); GL_CALL(BindTexture(glTex->target(), glTex->textureID())); - return this->uploadTexData(glTex->config(), glTex->width(), glTex->height(), - glTex->origin(), glTex->target(), kWrite_UploadType, - left, top, width, height, config, texels); + bool success = false; + if (GrPixelConfigIsCompressed(glTex->config())) { + // We check that config == desc.fConfig in GrGLGpu::canWriteTexturePixels() + SkASSERT(config == glTex->config()); + success = this->uploadCompressedTexData(glTex->config(), glTex->width(), glTex->height(), + glTex->origin(), glTex->target(), texels, + kWrite_UploadType, left, top, width, height); + } else { + success = this->uploadTexData(glTex->config(), glTex->width(), glTex->height(), + glTex->origin(), glTex->target(), kWrite_UploadType, + left, top, width, height, config, texels); + } + + return success; } bool GrGLGpu::onTransferPixels(GrSurface* surface, @@ -776,6 +791,11 @@ bool GrGLGpu::onTransferPixels(GrSurface* surface, return false; } + // For the moment, can't transfer compressed data + if (GrPixelConfigIsCompressed(glTex->config())) { + return false; + } + this->setScratchTextureUnit(); GL_CALL(BindTexture(glTex->target(), glTex->textureID())); @@ -798,6 +818,7 @@ bool GrGLGpu::onTransferPixels(GrSurface* surface, // For GL_[UN]PACK_ALIGNMENT. static inline GrGLint config_alignment(GrPixelConfig config) { + SkASSERT(!GrPixelConfigIsCompressed(config)); switch (config) { case kAlpha_8_GrPixelConfig: case kGray_8_GrPixelConfig: @@ -816,6 +837,7 @@ static inline GrGLint config_alignment(GrPixelConfig config) { case kRG_float_GrPixelConfig: return 4; case kUnknown_GrPixelConfig: + case kETC1_GrPixelConfig: return 0; } SkFAIL("Invalid pixel config"); @@ -836,16 +858,16 @@ static inline GrGLint config_alignment(GrPixelConfig config) { * @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(GrPixelConfig config, - const GrGLInterface& interface, - const GrGLCaps& caps, - GrGLenum target, - GrGLenum internalFormat, - GrGLenum internalFormatForTexStorage, - GrGLenum externalFormat, - GrGLenum externalType, - const SkTArray<GrMipLevel>& texels, - int baseWidth, int baseHeight) { +static bool allocate_and_populate_uncompressed_texture(GrPixelConfig config, + const GrGLInterface& interface, + const GrGLCaps& caps, + GrGLenum target, + GrGLenum internalFormat, + GrGLenum internalFormatForTexStorage, + GrGLenum externalFormat, + GrGLenum externalType, + const SkTArray<GrMipLevel>& texels, + int baseWidth, int baseHeight) { CLEAR_ERROR_BEFORE_ALLOC(&interface); bool useTexStorage = caps.isConfigTexSupportEnabled(config); @@ -929,6 +951,97 @@ static bool allocate_and_populate_texture(GrPixelConfig config, } /** + * Creates storage space for the texture and fills it with texels. + * + * @param config Compressed pixel config of the texture. + * @param desc The surface descriptor for the texture being created. + * @param interface The GL interface in use. + * @param caps The capabilities of the GL device. + * @param internalFormat The data format used for the internal storage of the texture. + * @param texels The texel data of the texture being created. + */ +static bool allocate_and_populate_compressed_texture(GrPixelConfig config, + const GrGLInterface& interface, + const GrGLCaps& caps, + GrGLenum target, GrGLenum internalFormat, + const SkTArray<GrMipLevel>& texels, + int baseWidth, int baseHeight) { + CLEAR_ERROR_BEFORE_ALLOC(&interface); + + bool useTexStorage = caps.isConfigTexSupportEnabled(config); + // We can only use TexStorage if we know we will not later change the storage requirements. + // This means if we may later want to add mipmaps, we cannot use TexStorage. + // Right now, we cannot know if we will later add mipmaps or not. + // The only time we can use TexStorage is when we already have the + // mipmaps. + useTexStorage &= texels.count() > 1; + + if (useTexStorage) { + // We never resize or change formats of textures. + GL_ALLOC_CALL(&interface, + TexStorage2D(target, + texels.count(), + internalFormat, + baseWidth, baseHeight)); + GrGLenum error = CHECK_ALLOC_ERROR(&interface); + if (error != GR_GL_NO_ERROR) { + return false; + } else { + for (int currentMipLevel = 0; currentMipLevel < texels.count(); currentMipLevel++) { + const void* currentMipData = texels[currentMipLevel].fPixels; + if (currentMipData == nullptr) { + continue; + } + + int twoToTheMipLevel = 1 << currentMipLevel; + int currentWidth = SkTMax(1, baseWidth / twoToTheMipLevel); + int currentHeight = SkTMax(1, baseHeight / twoToTheMipLevel); + + // Make sure that the width and height that we pass to OpenGL + // is a multiple of the block size. + size_t dataSize = GrCompressedFormatDataSize(config, currentWidth, currentHeight); + GR_GL_CALL(&interface, CompressedTexSubImage2D(target, + currentMipLevel, + 0, // left + 0, // top + currentWidth, + currentHeight, + internalFormat, + SkToInt(dataSize), + currentMipData)); + } + } + } else { + for (int currentMipLevel = 0; currentMipLevel < texels.count(); currentMipLevel++) { + int twoToTheMipLevel = 1 << currentMipLevel; + int currentWidth = SkTMax(1, baseWidth / twoToTheMipLevel); + int currentHeight = SkTMax(1, baseHeight / twoToTheMipLevel); + + // Make sure that the width and height that we pass to OpenGL + // is a multiple of the block size. + size_t dataSize = GrCompressedFormatDataSize(config, baseWidth, baseHeight); + + GL_ALLOC_CALL(&interface, + CompressedTexImage2D(target, + currentMipLevel, + internalFormat, + currentWidth, + currentHeight, + 0, // border + SkToInt(dataSize), + texels[currentMipLevel].fPixels)); + + 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. * @@ -952,6 +1065,9 @@ bool GrGLGpu::uploadTexData(GrPixelConfig texConfig, int texWidth, int texHeight GrSurfaceOrigin texOrigin, GrGLenum target, UploadType uploadType, int left, int top, int width, int height, GrPixelConfig dataConfig, const SkTArray<GrMipLevel>& texels) { + // If we're uploading compressed data then we should be using uploadCompressedTexData + SkASSERT(!GrPixelConfigIsCompressed(dataConfig)); + SkASSERT(this->caps()->isConfigTexturable(texConfig)); // texels is const. @@ -1106,7 +1222,7 @@ bool GrGLGpu::uploadTexData(GrPixelConfig texConfig, int texWidth, int texHeight bool succeeded = true; if (kNewTexture_UploadType == uploadType) { if (0 == left && 0 == top && texWidth == width && texHeight == height) { - succeeded = allocate_and_populate_texture( + succeeded = allocate_and_populate_uncompressed_texture( texConfig, *interface, caps, target, internalFormat, internalFormatForTexStorage, externalFormat, externalType, texelsShallowCopy, width, height); @@ -1138,6 +1254,75 @@ bool GrGLGpu::uploadTexData(GrPixelConfig texConfig, int texWidth, int texHeight return succeeded; } +// TODO: This function is using a lot of wonky semantics like, if width == -1 +// then set width = desc.fWdith ... blah. A better way to do it might be to +// create a CompressedTexData struct that takes a desc/ptr and figures out +// the proper upload semantics. Then users can construct this function how they +// see fit if they want to go against the "standard" way to do it. +bool GrGLGpu::uploadCompressedTexData(GrPixelConfig config, int texWidth, int texHeight, + GrSurfaceOrigin texOrigin, GrGLenum target, + const SkTArray<GrMipLevel>& texels, UploadType uploadType, + int left, int top, int width, int height) { + SkASSERT(this->caps()->isConfigTexturable(config)); + + // No support for software flip y, yet... + SkASSERT(kBottomLeft_GrSurfaceOrigin != texOrigin); + + const GrGLInterface* interface = this->glInterface(); + const GrGLCaps& caps = this->glCaps(); + + if (-1 == width) { + width = texWidth; + } +#ifdef SK_DEBUG + else { + SkASSERT(width <= texWidth); + } +#endif + + if (-1 == height) { + height = texHeight; + } +#ifdef SK_DEBUG + else { + SkASSERT(height <= texHeight); + } +#endif + + // We only need the internal format for compressed 2D textures. + GrGLenum internalFormat; + if (!caps.getCompressedTexImageFormats(config, &internalFormat)) { + return false; + } + + if (kNewTexture_UploadType == uploadType) { + return allocate_and_populate_compressed_texture(config, *interface, caps, target, + internalFormat, texels, width, height); + } else { + for (int currentMipLevel = 0; currentMipLevel < texels.count(); currentMipLevel++) { + SkASSERT(texels[currentMipLevel].fPixels || kTransfer_UploadType == uploadType); + + int twoToTheMipLevel = 1 << currentMipLevel; + int currentWidth = SkTMax(1, width / twoToTheMipLevel); + int currentHeight = SkTMax(1, height / twoToTheMipLevel); + + // Make sure that the width and height that we pass to OpenGL + // is a multiple of the block size. + size_t dataSize = GrCompressedFormatDataSize(config, currentWidth, currentHeight); + GL_CALL(CompressedTexSubImage2D(target, + currentMipLevel, + left, top, + currentWidth, + currentHeight, + internalFormat, + SkToInt(dataSize), + texels[currentMipLevel].fPixels)); + } + } + + return true; +} + static bool renderbuffer_storage_msaa(const GrGLContext& ctx, int sampleCount, GrGLenum format, @@ -1292,6 +1477,18 @@ static size_t as_size_t(int x) { } #endif +static GrGLTexture::IDDesc generate_gl_texture(const GrGLInterface* interface) { + GrGLTexture::IDDesc idDesc; + idDesc.fInfo.fID = 0; + GR_GL_CALL(interface, GenTextures(1, &idDesc.fInfo.fID)); + idDesc.fOwnership = GrBackendObjectOwnership::kOwned; + // When we create the texture, we only + // create GL_TEXTURE_2D at the moment. + // External clients can do something different. + idDesc.fInfo.fTarget = GR_GL_TEXTURE_2D; + return idDesc; +} + static void set_initial_texture_params(const GrGLInterface* interface, const GrGLTextureInfo& info, GrGLTexture::TexParams* initialTexParams) { @@ -1364,6 +1561,41 @@ GrTexture* GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc, return tex; } +GrTexture* GrGLGpu::onCreateCompressedTexture(const GrSurfaceDesc& desc, + SkBudgeted budgeted, + const SkTArray<GrMipLevel>& texels) { + // Make sure that we're not flipping Y. + if (kBottomLeft_GrSurfaceOrigin == desc.fOrigin) { + return return_null_texture(); + } + + GrGLTexture::IDDesc idDesc = generate_gl_texture(this->glInterface()); + if (!idDesc.fInfo.fID) { + return return_null_texture(); + } + + this->setScratchTextureUnit(); + GL_CALL(BindTexture(idDesc.fInfo.fTarget, idDesc.fInfo.fID)); + + GrGLTexture::TexParams initialTexParams; + set_initial_texture_params(this->glInterface(), idDesc.fInfo, &initialTexParams); + + if (!this->uploadCompressedTexData(desc.fConfig, desc.fWidth, desc.fHeight, desc.fOrigin, + idDesc.fInfo.fTarget, texels)) { + GL_CALL(DeleteTextures(1, &idDesc.fInfo.fID)); + return return_null_texture(); + } + + GrGLTexture* tex; + tex = new GrGLTexture(this, budgeted, desc, idDesc); + tex->setCachedTexParams(initialTexParams, this->getResetTimestamp()); +#ifdef TRACE_TEXTURE_CREATION + SkDebugf("--- new compressed texture [%d] size=(%d %d) config=%d\n", + idDesc.fInfo.fID, desc.fWidth, desc.fHeight, desc.fConfig); +#endif + return tex; +} + namespace { const GrGLuint kUnknownBitCount = GrGLStencilAttachment::kUnknownBitCount; @@ -2795,7 +3027,7 @@ void GrGLGpu::bindTexture(int unitIdx, const GrSamplerParams& params, bool allow GrSamplerParams::FilterMode filterMode = params.filterMode(); if (GrSamplerParams::kMipMap_FilterMode == filterMode) { - if (!this->caps()->mipMapSupport()) { + if (!this->caps()->mipMapSupport() || GrPixelConfigIsCompressed(texture->config())) { filterMode = GrSamplerParams::kBilerp_FilterMode; } } @@ -2941,7 +3173,7 @@ void GrGLGpu::generateMipmaps(const GrSamplerParams& params, bool allowSRGBInput GrSamplerParams::FilterMode filterMode = params.filterMode(); if (GrSamplerParams::kMipMap_FilterMode == filterMode) { - if (!this->caps()->mipMapSupport()) { + if (!this->caps()->mipMapSupport() || GrPixelConfigIsCompressed(texture->config())) { filterMode = GrSamplerParams::kBilerp_FilterMode; } } @@ -3163,6 +3395,7 @@ static inline bool can_copy_texsubimage(const GrSurface* dst, // Check that we could wrap the source in an FBO, that the dst is TEXTURE_2D, that no mirroring // is required. if (gpu->glCaps().canConfigBeFBOColorAttachment(src->config()) && + !GrPixelConfigIsCompressed(src->config()) && (!srcTex || srcTex->target() == GR_GL_TEXTURE_2D) && dstTex->target() == GR_GL_TEXTURE_2D && dst->origin() == src->origin()) { return true; diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h index a4706c79ed..cf3d38fa6b 100644 --- a/src/gpu/gl/GrGLGpu.h +++ b/src/gpu/gl/GrGLGpu.h @@ -163,6 +163,9 @@ private: GrTexture* onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted, const SkTArray<GrMipLevel>& texels) override; + GrTexture* onCreateCompressedTexture(const GrSurfaceDesc& desc, + SkBudgeted budgeted, + const SkTArray<GrMipLevel>& texels) override; GrBuffer* onCreateBuffer(size_t size, GrBufferType intendedType, GrAccessPattern, const void* data) override; @@ -363,6 +366,18 @@ private: int top, int width, int height, GrPixelConfig dataConfig, const SkTArray<GrMipLevel>& texels); + // helper for onCreateCompressedTexture. If width and height are + // set to -1, then this function will use desc.fWidth and desc.fHeight + // for the size of the data. The isNewTexture flag should be set to true + // whenever a new texture needs to be created. Otherwise, we assume that + // the texture is already in GPU memory and that it's going to be updated + // with new data. + bool uploadCompressedTexData(GrPixelConfig texAndDataConfig, int texWidth, int texHeight, + GrSurfaceOrigin texOrigin, GrGLenum target, + const SkTArray<GrMipLevel>& texels, + UploadType uploadType = kNewTexture_UploadType, int left = 0, + int top = 0, int width = -1, int height = -1); + bool createRenderTargetObjects(const GrSurfaceDesc&, const GrGLTextureInfo& texInfo, GrGLRenderTarget::IDDesc*); diff --git a/src/gpu/ops/GrCopySurfaceOp.cpp b/src/gpu/ops/GrCopySurfaceOp.cpp index 9cbde0e53b..5feed18f76 100644 --- a/src/gpu/ops/GrCopySurfaceOp.cpp +++ b/src/gpu/ops/GrCopySurfaceOp.cpp @@ -67,6 +67,9 @@ std::unique_ptr<GrOp> GrCopySurfaceOp::Make(GrResourceProvider* resourceProvider if (GrPixelConfigIsSint(dstProxy->config()) != GrPixelConfigIsSint(srcProxy->config())) { return nullptr; } + if (GrPixelConfigIsCompressed(dstProxy->config())) { + return nullptr; + } SkIRect clippedSrcRect; SkIPoint clippedDstPoint; // If the rect is outside the srcProxy or dstProxy then we've already succeeded. diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp index ef0004be04..0e5ccf07bd 100644 --- a/src/gpu/vk/GrVkCaps.cpp +++ b/src/gpu/vk/GrVkCaps.cpp @@ -31,6 +31,7 @@ GrVkCaps::GrVkCaps(const GrContextOptions& contextOptions, const GrVkInterface* fDiscardRenderTargetSupport = true; fReuseScratchTextures = true; //TODO: figure this out fGpuTracingSupport = false; //TODO: figure this out + fCompressedTexSubImageSupport = false; //TODO: figure this out fOversizedStencilSupport = false; //TODO: figure this out fUseDrawInsteadOfClear = false; @@ -306,6 +307,11 @@ void GrVkCaps::initConfigTable(const GrVkInterface* interface, VkPhysicalDevice fConfigTable[i].init(interface, physDev, format); } } + + // We currently do not support compressed textures in Vulkan + const uint16_t kFlagsToRemove = ConfigInfo::kTextureable_Flag|ConfigInfo::kRenderable_Flag; + fConfigTable[kETC1_GrPixelConfig].fOptimalFlags &= ~kFlagsToRemove; + fConfigTable[kETC1_GrPixelConfig].fLinearFlags &= ~kFlagsToRemove; } void GrVkCaps::ConfigInfo::InitConfigFlags(VkFormatFeatureFlags vkFlags, uint16_t* flags) { diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp index 7fbca9f9da..6969e06252 100644 --- a/src/gpu/vk/GrVkGpu.cpp +++ b/src/gpu/vk/GrVkGpu.cpp @@ -315,6 +315,10 @@ GrBuffer* GrVkGpu::onCreateBuffer(size_t size, GrBufferType type, GrAccessPatter bool GrVkGpu::onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height, GrPixelConfig srcConfig, DrawPreference* drawPreference, WritePixelTempDrawInfo* tempDrawInfo) { + if (GrPixelConfigIsCompressed(dstSurface->config())) { + return false; + } + GrRenderTarget* renderTarget = dstSurface->asRenderTarget(); // Start off assuming no swizzling @@ -375,32 +379,43 @@ bool GrVkGpu::onWritePixels(GrSurface* surface, } bool success = false; - bool linearTiling = vkTex->isLinearTiled(); - if (linearTiling) { - if (texels.count() > 1) { - SkDebugf("Can't upload mipmap data to linear tiled texture"); - return false; - } - if (VK_IMAGE_LAYOUT_PREINITIALIZED != vkTex->currentLayout()) { - // Need to change the layout to general in order to perform a host write - vkTex->setImageLayout(this, - VK_IMAGE_LAYOUT_GENERAL, - VK_ACCESS_HOST_WRITE_BIT, - VK_PIPELINE_STAGE_HOST_BIT, - false); - this->submitCommandBuffer(kForce_SyncQueue); - } - success = this->uploadTexDataLinear(vkTex, left, top, width, height, config, - texels.begin()->fPixels, texels.begin()->fRowBytes); + if (GrPixelConfigIsCompressed(vkTex->config())) { + // We check that config == desc.fConfig in GrGpu::getWritePixelsInfo() + SkASSERT(config == vkTex->config()); + // TODO: add compressed texture support + // delete the following two lines and uncomment the two after that when ready + vkTex->unref(); + return false; + //success = this->uploadCompressedTexData(vkTex->desc(), buffer, false, left, top, width, + // height); } else { - int newMipLevels = texels.count(); - int currentMipLevels = vkTex->texturePriv().maxMipMapLevel() + 1; - if (newMipLevels > currentMipLevels) { - if (!vkTex->reallocForMipmap(this, newMipLevels)) { + bool linearTiling = vkTex->isLinearTiled(); + if (linearTiling) { + if (texels.count() > 1) { + SkDebugf("Can't upload mipmap data to linear tiled texture"); return false; } + if (VK_IMAGE_LAYOUT_PREINITIALIZED != vkTex->currentLayout()) { + // Need to change the layout to general in order to perform a host write + vkTex->setImageLayout(this, + VK_IMAGE_LAYOUT_GENERAL, + VK_ACCESS_HOST_WRITE_BIT, + VK_PIPELINE_STAGE_HOST_BIT, + false); + this->submitCommandBuffer(kForce_SyncQueue); + } + success = this->uploadTexDataLinear(vkTex, left, top, width, height, config, + texels.begin()->fPixels, texels.begin()->fRowBytes); + } else { + int newMipLevels = texels.count(); + int currentMipLevels = vkTex->texturePriv().maxMipMapLevel() + 1; + if (newMipLevels > currentMipLevels) { + if (!vkTex->reallocForMipmap(this, newMipLevels)) { + return false; + } + } + success = this->uploadTexDataOptimal(vkTex, left, top, width, height, config, texels); } - success = this->uploadTexDataOptimal(vkTex, left, top, width, height, config, texels); } return success; @@ -483,6 +498,9 @@ bool GrVkGpu::uploadTexDataLinear(GrVkTexture* tex, SkASSERT(data); SkASSERT(tex->isLinearTiled()); + // If we're uploading compressed data then we should be using uploadCompressedTexData + SkASSERT(!GrPixelConfigIsCompressed(dataConfig)); + size_t bpp = GrBytesPerPixel(dataConfig); if (!GrSurfacePriv::AdjustWritePixelParams(tex->width(), tex->height(), bpp, &left, &top, @@ -551,6 +569,9 @@ bool GrVkGpu::uploadTexDataOptimal(GrVkTexture* tex, // first. SkASSERT(1 == texels.count() || texels.count() == (tex->texturePriv().maxMipMapLevel() + 1)); + // If we're uploading compressed data then we should be using uploadCompressedTexData + SkASSERT(!GrPixelConfigIsCompressed(dataConfig)); + if (width == 0 || height == 0) { return false; } diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h index 913662dcd1..9442d3f979 100644 --- a/src/gpu/vk/GrVkGpu.h +++ b/src/gpu/vk/GrVkGpu.h @@ -176,6 +176,9 @@ private: GrTexture* onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted, const SkTArray<GrMipLevel>&) override; + GrTexture* onCreateCompressedTexture(const GrSurfaceDesc& desc, SkBudgeted, + const SkTArray<GrMipLevel>&) override { return NULL; } + sk_sp<GrTexture> onWrapBackendTexture(const GrBackendTexture&, GrSurfaceOrigin, GrBackendTextureFlags, diff --git a/src/gpu/vk/GrVkUtil.cpp b/src/gpu/vk/GrVkUtil.cpp index c56a4fb6fb..ec71fb0ed1 100644 --- a/src/gpu/vk/GrVkUtil.cpp +++ b/src/gpu/vk/GrVkUtil.cpp @@ -48,6 +48,10 @@ bool GrPixelConfigToVkFormat(GrPixelConfig config, VkFormat* format) { case kGray_8_GrPixelConfig: *format = VK_FORMAT_R8_UNORM; return true; + case kETC1_GrPixelConfig: + // converting to ETC2 which is a superset of ETC1 + *format = VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; + return true; case kRGBA_float_GrPixelConfig: *format = VK_FORMAT_R32G32B32A32_SFLOAT; return true; @@ -86,6 +90,8 @@ GrPixelConfig GrVkFormatToPixelConfig(VkFormat format) { return kRGBA_4444_GrPixelConfig; case VK_FORMAT_R8_UNORM: return kAlpha_8_GrPixelConfig; + case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: + return kETC1_GrPixelConfig; // this conversion seems a bit sketchy case VK_FORMAT_R32G32B32A32_SFLOAT: return kRGBA_float_GrPixelConfig; case VK_FORMAT_R32G32_SFLOAT: |