Prepare sRGB encoding conversion for the removal of GrPixelConfig

Standardizes that GrGpu subclass's onRead/WritePixels never do sRGB<->linear conversion. This means that they can eventually take a color type rather than config. It also means direct callers of GrGpu::read/writePixels can never expect conversion (which in practice is no change).

Consolidate logic about whether to do sRGB<->linear encoding conversions in GrContext::read/writeSurfacePixels helpers. No change in when conversions are done (yet). This prepares this logic to operate on SkColorSpace and color type rather than config WRT the CPU data.

Bug: skia:6718
Change-Id: I346d669624861578f1bb9ea465a7ab4b549117fa
Reviewed-on: https://skia-review.googlesource.com/105286
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2018-02-14 13:53:55 -05:00 committed by Skia Commit-Bot
parent 95edb43251
commit 9b009bb069
10 changed files with 310 additions and 210 deletions

View File

@ -791,13 +791,27 @@ static inline bool GrPixelConfigIs8888Unorm(GrPixelConfig config) {
return false;
}
// Returns true if the color (non-alpha) components represent sRGB values. It does NOT indicate that
// all three color components are present in the config or anything about their order.
static inline bool GrPixelConfigIsSRGB(GrPixelConfig config) {
/**
* Refers to the encoding of a GPU buffer as it will be interpreted by the GPU when sampling and
* blending.
*/
enum class GrSRGBEncoded : bool { kNo = false, kYes = true };
/**
* Describes whether pixel data encoding should be converted to/from linear/sRGB encoding.
*/
enum class GrSRGBConversion {
kNone,
kSRGBToLinear,
kLinearToSRGB,
};
// Returns whether the config's color channels are sRGB encoded.
static inline GrSRGBEncoded GrPixelConfigIsSRGBEncoded(GrPixelConfig config) {
switch (config) {
case kSRGBA_8888_GrPixelConfig:
case kSBGRA_8888_GrPixelConfig:
return true;
return GrSRGBEncoded::kYes;
case kUnknown_GrPixelConfig:
case kAlpha_8_GrPixelConfig:
case kAlpha_8_as_Alpha_GrPixelConfig:
@ -814,12 +828,15 @@ static inline bool GrPixelConfigIsSRGB(GrPixelConfig config) {
case kAlpha_half_GrPixelConfig:
case kAlpha_half_as_Red_GrPixelConfig:
case kRGBA_half_GrPixelConfig:
return false;
return GrSRGBEncoded::kNo;
}
SK_ABORT("Invalid pixel config");
return false;
return GrSRGBEncoded::kNo;
}
static inline bool GrPixelConfigIsSRGB(GrPixelConfig config) {
return GrSRGBEncoded::kYes == GrPixelConfigIsSRGBEncoded(config);
}
// Takes a config and returns the equivalent config with the R and B order
// swapped if such a config exists. Otherwise, kUnknown_GrPixelConfig
static inline GrPixelConfig GrPixelConfigSwapRAndB(GrPixelConfig config) {

View File

@ -542,6 +542,63 @@ static bool pm_upm_must_round_trip(GrPixelConfig config, SkColorSpace* colorSpac
(kRGBA_8888_GrPixelConfig == config || kBGRA_8888_GrPixelConfig == config);
}
static GrSRGBConversion determine_write_pixels_srgb_conversion(
GrPixelConfig srcConfig,
const SkColorSpace* srcColorSpace,
GrSRGBEncoded dstSRGBEncoded,
const SkColorSpace* dstColorSpace) {
// No support for sRGB-encoded alpha.
if (GrPixelConfigIsAlphaOnly(srcConfig)) {
return GrSRGBConversion::kNone;
}
// When the destination has no color space or it has a ~sRGB gamma but isn't sRGB encoded
// (because of caps) then we act in "legacy" mode where no conversions are performed.
if (!dstColorSpace ||
(dstColorSpace->gammaCloseToSRGB() && GrSRGBEncoded::kNo == dstSRGBEncoded)) {
return GrSRGBConversion::kNone;
}
// Similarly, if the src was sRGB gamma and 8888 but we didn't choose a sRGB config we must be
// in legacy mode. For now, anyway.
if (srcColorSpace && srcColorSpace->gammaCloseToSRGB() &&
GrSRGBEncoded::kNo == GrPixelConfigIsSRGBEncoded(srcConfig) &&
GrPixelConfigIs8888Unorm(srcConfig)) {
return GrSRGBConversion::kNone;
}
bool srcColorSpaceIsSRGB = srcColorSpace && srcColorSpace->gammaCloseToSRGB();
bool dstColorSpaceIsSRGB = dstColorSpace->gammaCloseToSRGB();
// For now we are assuming that if color space of the dst does not have sRGB gamma then the
// texture format is not sRGB encoded and vice versa. Note that we already checked for "legacy"
// mode being forced on by caps above. This may change in the future.
SkASSERT(dstColorSpaceIsSRGB == (GrSRGBEncoded::kYes == dstSRGBEncoded));
// Similarly we are assuming that if the color space of the src does not have sRGB gamma then
// the CPU pixels don't have a sRGB pixel config. This will become moot soon as we will not
// be using GrPixelConfig to describe CPU pixel allocations.
SkASSERT(srcColorSpaceIsSRGB == GrPixelConfigIsSRGB(srcConfig));
if (srcColorSpaceIsSRGB == dstColorSpaceIsSRGB) {
return GrSRGBConversion::kNone;
}
return srcColorSpaceIsSRGB ? GrSRGBConversion::kSRGBToLinear : GrSRGBConversion::kLinearToSRGB;
}
static GrSRGBConversion determine_read_pixels_srgb_conversion(
GrSRGBEncoded srcSRGBEncoded,
const SkColorSpace* srcColorSpace,
GrPixelConfig dstConfig,
const SkColorSpace* dstColorSpace) {
// This is symmetrical with the write version.
switch (determine_write_pixels_srgb_conversion(dstConfig, dstColorSpace, srcSRGBEncoded,
srcColorSpace)) {
case GrSRGBConversion::kNone: return GrSRGBConversion::kNone;
case GrSRGBConversion::kLinearToSRGB: return GrSRGBConversion::kSRGBToLinear;
case GrSRGBConversion::kSRGBToLinear: return GrSRGBConversion::kLinearToSRGB;
}
return GrSRGBConversion::kNone;
}
bool GrContextPriv::writeSurfacePixels(GrSurfaceContext* dst,
int left, int top, int width, int height,
GrPixelConfig srcConfig, SkColorSpace* srcColorSpace,
@ -590,8 +647,12 @@ bool GrContextPriv::writeSurfacePixels(GrSurfaceContext* dst,
GrGpu::DrawPreference drawPreference = premulOnGpu ? GrGpu::kCallerPrefersDraw_DrawPreference
: GrGpu::kNoDraw_DrawPreference;
GrGpu::WritePixelTempDrawInfo tempDrawInfo;
GrSRGBConversion srgbConversion = determine_write_pixels_srgb_conversion(
srcConfig, srcColorSpace, GrPixelConfigIsSRGBEncoded(dstProxy->config()),
dst->colorSpaceInfo().colorSpace());
if (!fContext->fGpu->getWritePixelsInfo(dstSurface, dstProxy->origin(), width, height,
srcConfig, &drawPreference, &tempDrawInfo)) {
srcConfig, srgbConversion, &drawPreference,
&tempDrawInfo)) {
return false;
}
@ -723,8 +784,12 @@ bool GrContextPriv::readSurfacePixels(GrSurfaceContext* src,
GrGpu::DrawPreference drawPreference = unpremulOnGpu ? GrGpu::kCallerPrefersDraw_DrawPreference
: GrGpu::kNoDraw_DrawPreference;
GrGpu::ReadPixelTempDrawInfo tempDrawInfo;
GrSRGBConversion srgbConversion = determine_read_pixels_srgb_conversion(
GrPixelConfigIsSRGBEncoded(srcProxy->config()), src->colorSpaceInfo().colorSpace(),
dstConfig, dstColorSpace);
if (!fContext->fGpu->getReadPixelsInfo(srcSurface, srcProxy->origin(), width, height, rowBytes,
dstConfig, &drawPreference, &tempDrawInfo)) {
dstConfig, srgbConversion, &drawPreference,
&tempDrawInfo)) {
return false;
}

View File

@ -193,35 +193,65 @@ bool GrGpu::copySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin,
return this->onCopySurface(dst, dstOrigin, src, srcOrigin, srcRect, dstPoint);
}
bool GrGpu::getReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrigin,
int width, int height, size_t rowBytes,
GrPixelConfig readConfig, DrawPreference* drawPreference,
bool GrGpu::getReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrigin, int width,
int height, size_t rowBytes, GrPixelConfig dstConfig,
GrSRGBConversion srgbConversion, DrawPreference* drawPreference,
ReadPixelTempDrawInfo* tempDrawInfo) {
SkASSERT(drawPreference);
SkASSERT(tempDrawInfo);
SkASSERT(srcSurface);
SkASSERT(kGpuPrefersDraw_DrawPreference != *drawPreference);
// Default values for intermediate draws. The intermediate texture config matches the src's
// Default values for intermediate draws. The intermediate texture config matches the dst's
// config, is approx sized to the read rect, no swizzling or spoofing of the dst config.
tempDrawInfo->fTempSurfaceDesc.fFlags = kRenderTarget_GrSurfaceFlag;
tempDrawInfo->fTempSurfaceDesc.fWidth = width;
tempDrawInfo->fTempSurfaceDesc.fHeight = height;
tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 1;
tempDrawInfo->fTempSurfaceDesc.fOrigin = kTopLeft_GrSurfaceOrigin; // no CPU y-flip for TL.
tempDrawInfo->fTempSurfaceDesc.fConfig = srcSurface->config();
tempDrawInfo->fTempSurfaceDesc.fConfig = dstConfig;
tempDrawInfo->fTempSurfaceFit = SkBackingFit::kApprox;
tempDrawInfo->fSwizzle = GrSwizzle::RGBA();
tempDrawInfo->fReadConfig = readConfig;
tempDrawInfo->fReadConfig = dstConfig;
// 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) {
if (kRGB_565_GrPixelConfig == dstConfig || kRGBA_4444_GrPixelConfig == dstConfig) {
return false;
}
if (!this->onGetReadPixelsInfo(srcSurface, srcOrigin, width, height, rowBytes, readConfig,
drawPreference, tempDrawInfo)) {
// GrGpu::readPixels doesn't do any sRGB conversions, so we must draw if there is one.
switch (srgbConversion) {
case GrSRGBConversion::kNone:
break;
case GrSRGBConversion::kLinearToSRGB:
SkASSERT(this->caps()->srgbSupport());
// This check goes away when we start referring to CPU data using color type.
SkASSERT(GrSRGBEncoded::kYes == GrPixelConfigIsSRGBEncoded(dstConfig));
// Currently we don't expect to make a SRGB encoded surface and then read data from it
// such that we treat it as though it were linear and is then converted to sRGB.
if (GrSRGBEncoded::kYes == GrPixelConfigIsSRGBEncoded(srcSurface->config())) {
return false;
}
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
break;
case GrSRGBConversion::kSRGBToLinear:
SkASSERT(this->caps()->srgbSupport());
// This assert goes away when we start referring to CPU data using color type.
SkASSERT(GrSRGBEncoded::kNo == GrPixelConfigIsSRGBEncoded(dstConfig));
// We don't currently support reading sRGB encoded data into linear from a surface
// unless it is an sRGB-encoded config. That is likely to change when we need to store
// sRGB encoded data in 101010102 and F16 textures. We'll have to provoke the caller to
// do the conversion in a shader.
if (GrSRGBEncoded::kNo == GrPixelConfigIsSRGBEncoded(srcSurface->config())) {
return false;
}
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
break;
}
if (!this->onGetReadPixelsInfo(srcSurface, srcOrigin, width, height, rowBytes, dstConfig,
drawPreference, tempDrawInfo)) {
return false;
}
@ -237,9 +267,9 @@ bool GrGpu::getReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrigin,
return true;
}
bool GrGpu::getWritePixelsInfo(GrSurface* dstSurface, GrSurfaceOrigin dstOrigin,
int width, int height,
GrPixelConfig srcConfig, DrawPreference* drawPreference,
bool GrGpu::getWritePixelsInfo(GrSurface* dstSurface, GrSurfaceOrigin dstOrigin, int width,
int height, GrPixelConfig srcConfig, GrSRGBConversion srgbConversion,
DrawPreference* drawPreference,
WritePixelTempDrawInfo* tempDrawInfo) {
SkASSERT(drawPreference);
SkASSERT(tempDrawInfo);
@ -257,6 +287,36 @@ bool GrGpu::getWritePixelsInfo(GrSurface* dstSurface, GrSurfaceOrigin dstOrigin,
tempDrawInfo->fSwizzle = GrSwizzle::RGBA();
tempDrawInfo->fWriteConfig = srcConfig;
// GrGpu::writePixels doesn't do any sRGB conversions, so we must draw if there is one.
switch (srgbConversion) {
case GrSRGBConversion::kNone:
break;
case GrSRGBConversion::kLinearToSRGB:
SkASSERT(this->caps()->srgbSupport());
// This assert goes away when we start referring to CPU data using color type.
SkASSERT(GrSRGBEncoded::kNo == GrPixelConfigIsSRGBEncoded(srcConfig));
// We don't currently support storing sRGB encoded data in a surface unless it is
// an SRGB-encoded config. That is likely to change when we need to store sRGB encoded
// data in 101010102 and F16 textures. We'll have to provoke the caller to do the
// conversion in a shader.
if (GrSRGBEncoded::kNo == GrPixelConfigIsSRGBEncoded(dstSurface->config())) {
return false;
}
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
break;
case GrSRGBConversion::kSRGBToLinear:
SkASSERT(this->caps()->srgbSupport());
// This assert goes away when we start referring to CPU data using color type.
SkASSERT(GrSRGBEncoded::kYes == GrPixelConfigIsSRGBEncoded(srcConfig));
// Currently we don't expect to make a SRGB encoded surface and then succeed at
// treating it as though it were linear and then convert to sRGB.
if (GrSRGBEncoded::kYes == GrPixelConfigIsSRGBEncoded(dstSurface->config())) {
return false;
}
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
break;
}
if (!this->onGetWritePixelsInfo(dstSurface, dstOrigin, width, height, srcConfig, drawPreference,
tempDrawInfo)) {
return false;

View File

@ -199,9 +199,9 @@ public:
* that would allow a successful readPixels call. The passed width, height, and rowBytes,
* must be non-zero and already reflect clipping to the src bounds.
*/
bool getReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrigin,
int readWidth, int readHeight, size_t rowBytes,
GrPixelConfig readConfig, DrawPreference*, ReadPixelTempDrawInfo*);
bool getReadPixelsInfo(GrSurface*, GrSurfaceOrigin, int width,
int height, size_t rowBytes, GrPixelConfig,
GrSRGBConversion, DrawPreference*, ReadPixelTempDrawInfo*);
/** Info struct returned by getWritePixelsInfo about performing an intermediate draw in order
to write pixels to a GrSurface for either performance or correctness reasons. */
@ -226,18 +226,19 @@ public:
* that would allow a successful transfer of the src pixels to the dst. The passed width,
* height, and rowBytes, must be non-zero and already reflect clipping to the dst bounds.
*/
bool getWritePixelsInfo(GrSurface* dstSurface, GrSurfaceOrigin dstOrigin, int width, int height,
GrPixelConfig srcConfig, DrawPreference*, WritePixelTempDrawInfo*);
bool getWritePixelsInfo(GrSurface*, GrSurfaceOrigin, int width, int height,
GrPixelConfig, GrSRGBConversion, DrawPreference*,
WritePixelTempDrawInfo*);
/**
* Reads a rectangle of pixels from a render target.
* Reads a rectangle of pixels from a render target. No sRGB/linear conversions are performed.
*
* @param surface The surface to read from
* @param left left edge of the rectangle to read (inclusive)
* @param top top edge of the rectangle to read (inclusive)
* @param width width of rectangle to read in pixels.
* @param height height of rectangle to read in pixels.
* @param config the pixel config of the destination buffer
* @param dstConfig the pixel config of the destination buffer
* @param buffer memory to read the rectangle into.
* @param rowBytes the number of bytes between consecutive rows. Zero
* means rows are tightly packed.
@ -248,39 +249,32 @@ public:
* because of a unsupported pixel config or because no render
* target is currently set.
*/
bool readPixels(GrSurface* surface, GrSurfaceOrigin,
int left, int top, int width, int height,
GrPixelConfig config, void* buffer, size_t rowBytes);
bool readPixels(GrSurface* surface, GrSurfaceOrigin, int left, int top, int width, int height,
GrPixelConfig dstConfig, void* buffer, size_t rowBytes);
/**
* Updates the pixels in a rectangle of a surface.
* Updates the pixels in a rectangle of a surface. No sRGB/linear conversions are performed.
*
* @param surface The surface to write to.
* @param left left edge of the rectangle to write (inclusive)
* @param top top edge of the rectangle to write (inclusive)
* @param width width of rectangle to write in pixels.
* @param height height of rectangle to write in pixels.
* @param config the pixel config of the source buffer
* @param srcConfig the pixel config of the source buffer
* @param texels array of mipmap levels containing texture data
* @param mipLevelCount number of levels in 'texels'
*/
bool writePixels(GrSurface* surface, GrSurfaceOrigin origin,
int left, int top, int width, int height,
GrPixelConfig config,
GrPixelConfig srcConfig,
const GrMipLevel texels[], int mipLevelCount);
/**
* This function is a shim which creates a SkTArray<GrMipLevel> of size 1.
* It then calls writePixels with that SkTArray.
*
* @param buffer memory to read pixels from.
* @param rowBytes number of bytes between consecutive rows. Zero
* means rows are tightly packed.
*/
bool writePixels(GrSurface* surface, GrSurfaceOrigin origin,
int left, int top, int width, int height,
GrPixelConfig config, const void* buffer,
size_t rowBytes);
bool writePixels(GrSurface*, GrSurfaceOrigin, int left, int top, int width,
int height, GrPixelConfig, const void* buffer, size_t rowBytes);
/**
* Updates the pixels in a rectangle of a texture using a buffer
@ -293,16 +287,15 @@ public:
* @param top top edge of the rectangle to write (inclusive)
* @param width width of rectangle to write in pixels.
* @param height height of rectangle to write in pixels.
* @param config the pixel config of the source buffer
* @param bufferConfig the pixel config of the source buffer
* @param transferBuffer GrBuffer to read pixels from (type must be "kXferCpuToGpu")
* @param offset offset from the start of the buffer
* @param rowBytes number of bytes between consecutive rows in the buffer. Zero
* means rows are tightly packed.
*/
bool transferPixels(GrTexture* texture,
int left, int top, int width, int height,
GrPixelConfig config, GrBuffer* transferBuffer,
size_t offset, size_t rowBytes);
bool transferPixels(GrTexture* texture, int left, int top, int width, int height,
GrPixelConfig bufferConfig, GrBuffer* transferBuffer, size_t offset,
size_t rowBytes);
// After the client interacts directly with the 3D context state the GrGpu
// must resync its internal state and assumptions about 3D context state.
@ -567,14 +560,11 @@ private:
return false;
}
virtual bool onGetReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrigin,
int readWidth, int readHeight,
size_t rowBytes, GrPixelConfig readConfig, DrawPreference*,
virtual bool onGetReadPixelsInfo(GrSurface*, GrSurfaceOrigin, int width, int height,
size_t rowBytes, GrPixelConfig, DrawPreference*,
ReadPixelTempDrawInfo*) = 0;
virtual bool onGetWritePixelsInfo(GrSurface* dstSurface, GrSurfaceOrigin dstOrigin,
int width, int height,
GrPixelConfig srcConfig, DrawPreference*,
WritePixelTempDrawInfo*) = 0;
virtual bool onGetWritePixelsInfo(GrSurface*, GrSurfaceOrigin, int width, int height,
GrPixelConfig, DrawPreference*, WritePixelTempDrawInfo*) = 0;
// overridden by backend-specific derived class to perform the surface read
virtual bool onReadPixels(GrSurface*, GrSurfaceOrigin,

View File

@ -81,12 +81,13 @@ void GrOpFlushState::doUpload(GrDeferredTextureUploadFn& upload) {
GrDeferredTextureUploadWritePixelsFn wp = [this](GrTextureProxy* dstProxy, int left, int top,
int width, int height, GrPixelConfig srcConfig,
const void* buffer, size_t rowBytes) {
// We don't allow srgb conversions via op flush state uploads.
static constexpr auto kSRGBConversion = GrSRGBConversion::kNone;
GrSurface* dstSurface = dstProxy->priv().peekSurface();
GrGpu::DrawPreference drawPreference = GrGpu::kNoDraw_DrawPreference;
GrGpu::WritePixelTempDrawInfo tempInfo;
if (!fGpu->getWritePixelsInfo(dstSurface, dstProxy->origin(),
width, height, srcConfig,
&drawPreference, &tempInfo)) {
if (!fGpu->getWritePixelsInfo(dstSurface, dstProxy->origin(), width, height, srcConfig,
kSRGBConversion, &drawPreference, &tempInfo)) {
return false;
}
if (GrGpu::kNoDraw_DrawPreference == drawPreference) {

View File

@ -665,6 +665,14 @@ bool GrGLGpu::onGetWritePixelsInfo(GrSurface* dstSurface, GrSurfaceOrigin dstOri
GrPixelConfig srcConfig,
DrawPreference* drawPreference,
WritePixelTempDrawInfo* tempDrawInfo) {
if (*drawPreference != kNoDraw_DrawPreference) {
// We assume the base class has only inserted a draw for sRGB reasons. So the temp surface
// has the config of the original src data. There is no swizzling nor src config spoofing.
SkASSERT(tempDrawInfo->fWriteConfig == srcConfig);
SkASSERT(tempDrawInfo->fTempSurfaceDesc.fConfig == srcConfig);
SkASSERT(tempDrawInfo->fSwizzle == GrSwizzle::RGBA());
}
if (SkToBool(dstSurface->asRenderTarget())) {
if (this->glCaps().useDrawInsteadOfAllRenderTargetWrites()) {
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
@ -694,10 +702,6 @@ bool GrGLGpu::onGetWritePixelsInfo(GrSurface* dstSurface, GrSurfaceOrigin dstOri
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
}
if (GrPixelConfigIsSRGB(dstSurface->config()) != GrPixelConfigIsSRGB(srcConfig)) {
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
}
bool configsAreRBSwaps = GrPixelConfigSwapRAndB(srcConfig) == dstSurface->config();
if (configsAreRBSwaps) {
@ -731,16 +735,11 @@ bool GrGLGpu::onGetWritePixelsInfo(GrSurface* dstSurface, GrSurfaceOrigin dstOri
}
static bool check_write_and_transfer_input(GrGLTexture* glTex, GrSurface* surface,
GrPixelConfig config) {
GrPixelConfig config) {
if (!glTex) {
return false;
}
// OpenGL doesn't do sRGB <-> linear conversions when reading and writing pixels.
if (GrPixelConfigIsSRGB(surface->config()) != GrPixelConfigIsSRGB(config)) {
return false;
}
// Write or transfer of pixels is not implemented for TEXTURE_EXTERNAL textures
if (GR_GL_TEXTURE_EXTERNAL == glTex->target()) {
return false;
@ -749,23 +748,21 @@ static bool check_write_and_transfer_input(GrGLTexture* glTex, GrSurface* surfac
return true;
}
bool GrGLGpu::onWritePixels(GrSurface* surface, GrSurfaceOrigin origin,
int left, int top, int width, int height,
GrPixelConfig config,
const GrMipLevel texels[],
int mipLevelCount) {
bool GrGLGpu::onWritePixels(GrSurface* surface, GrSurfaceOrigin origin, int left, int top,
int width, int height, GrPixelConfig dstConfig,
const GrMipLevel texels[], int mipLevelCount) {
GrGLTexture* glTex = static_cast<GrGLTexture*>(surface->asTexture());
if (!check_write_and_transfer_input(glTex, surface, config)) {
if (!check_write_and_transfer_input(glTex, surface, dstConfig)) {
return false;
}
this->setScratchTextureUnit();
GL_CALL(BindTexture(glTex->target(), glTex->textureID()));
return this->uploadTexData(glTex->config(), glTex->width(), glTex->height(),
origin, glTex->target(), kWrite_UploadType,
left, top, width, height, config, texels, mipLevelCount);
return this->uploadTexData(glTex->config(), glTex->width(), glTex->height(), origin,
glTex->target(), kWrite_UploadType, left, top, width, height,
dstConfig, texels, mipLevelCount);
}
// For GL_[UN]PACK_ALIGNMENT.
@ -798,10 +795,9 @@ static inline GrGLint config_alignment(GrPixelConfig config) {
return 0;
}
bool GrGLGpu::onTransferPixels(GrTexture* texture,
int left, int top, int width, int height,
GrPixelConfig config, GrBuffer* transferBuffer,
size_t offset, size_t rowBytes) {
bool GrGLGpu::onTransferPixels(GrTexture* texture, int left, int top, int width, int height,
GrPixelConfig config, GrBuffer* transferBuffer, size_t offset,
size_t rowBytes) {
GrGLTexture* glTex = static_cast<GrGLTexture*>(texture);
GrPixelConfig texConfig = glTex->config();
SkASSERT(this->caps()->isConfigTexturable(texConfig));
@ -2163,44 +2159,31 @@ bool GrGLGpu::readPixelsSupported(GrSurface* surfaceForConfig, GrPixelConfig rea
}
}
static bool requires_srgb_conversion(GrPixelConfig a, GrPixelConfig b) {
if (GrPixelConfigIsSRGB(a)) {
return !GrPixelConfigIsSRGB(b) && !GrPixelConfigIsAlphaOnly(b);
} else if (GrPixelConfigIsSRGB(b)) {
return !GrPixelConfigIsSRGB(a) && !GrPixelConfigIsAlphaOnly(a);
}
return false;
}
bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrigin,
int width, int height, size_t rowBytes,
GrPixelConfig readConfig, DrawPreference* drawPreference,
bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrigin, int width,
int height, size_t rowBytes, GrPixelConfig dstConfig,
DrawPreference* drawPreference,
ReadPixelTempDrawInfo* tempDrawInfo) {
if (*drawPreference != kNoDraw_DrawPreference) {
// We assume the base class has only inserted a draw for sRGB reasons. So the
// the temp surface has the config of the dst data. There is no swizzling, nor dst config
// spoofing.
SkASSERT(tempDrawInfo->fReadConfig == dstConfig);
SkASSERT(tempDrawInfo->fTempSurfaceDesc.fConfig == dstConfig);
SkASSERT(tempDrawInfo->fSwizzle == GrSwizzle::RGBA());
}
GrPixelConfig srcConfig = srcSurface->config();
tempDrawInfo->fTempSurfaceFit = this->glCaps().partialFBOReadIsSlow() ? SkBackingFit::kExact
: SkBackingFit::kApprox;
if (requires_srgb_conversion(srcConfig, readConfig)) {
if (!this->readPixelsSupported(readConfig, readConfig)) {
return false;
}
// Draw to do srgb to linear conversion or vice versa.
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
tempDrawInfo->fTempSurfaceDesc.fConfig = readConfig;
tempDrawInfo->fReadConfig = readConfig;
return true;
}
if (this->glCaps().rgba8888PixelsOpsAreSlow() && kRGBA_8888_GrPixelConfig == readConfig &&
if (this->glCaps().rgba8888PixelsOpsAreSlow() && kRGBA_8888_GrPixelConfig == dstConfig &&
this->readPixelsSupported(kBGRA_8888_GrPixelConfig, kBGRA_8888_GrPixelConfig)) {
tempDrawInfo->fTempSurfaceDesc.fConfig = kBGRA_8888_GrPixelConfig;
tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
tempDrawInfo->fReadConfig = kBGRA_8888_GrPixelConfig;
ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference);
} else if (this->glCaps().rgbaToBgraReadbackConversionsAreSlow() &&
GrBytesPerPixel(readConfig) == 4 &&
GrPixelConfigSwapRAndB(readConfig) == srcConfig &&
GrBytesPerPixel(dstConfig) == 4 && GrPixelConfigSwapRAndB(dstConfig) == srcConfig &&
this->readPixelsSupported(srcSurface, srcConfig)) {
// Mesa 3D takes a slow path on when reading back BGRA from an RGBA surface and vice-versa.
// Better to do a draw with a R/B swap and then read as the original config.
@ -2208,8 +2191,8 @@ bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrig
tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
tempDrawInfo->fReadConfig = srcConfig;
ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference);
} else if (!this->readPixelsSupported(srcSurface, readConfig)) {
if (readConfig == kBGRA_8888_GrPixelConfig &&
} else if (!this->readPixelsSupported(srcSurface, dstConfig)) {
if (dstConfig == kBGRA_8888_GrPixelConfig &&
this->glCaps().canConfigBeFBOColorAttachment(kRGBA_8888_GrPixelConfig) &&
this->readPixelsSupported(kRGBA_8888_GrPixelConfig, kRGBA_8888_GrPixelConfig)) {
// We're trying to read BGRA but it's not supported. If RGBA is renderable and
@ -2219,9 +2202,10 @@ bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrig
tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
tempDrawInfo->fReadConfig = kRGBA_8888_GrPixelConfig;
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
} else if (readConfig == kSBGRA_8888_GrPixelConfig &&
this->glCaps().canConfigBeFBOColorAttachment(kSRGBA_8888_GrPixelConfig) &&
this->readPixelsSupported(kSRGBA_8888_GrPixelConfig, kSRGBA_8888_GrPixelConfig)) {
} else if (dstConfig == kSBGRA_8888_GrPixelConfig &&
this->glCaps().canConfigBeFBOColorAttachment(kSRGBA_8888_GrPixelConfig) &&
this->readPixelsSupported(kSRGBA_8888_GrPixelConfig,
kSRGBA_8888_GrPixelConfig)) {
// We're trying to read sBGRA but it's not supported. If sRGBA is renderable and
// we can read it back, then do a swizzling draw to a sRGBA and read it back (which
// will effectively be sBGRA).
@ -2229,45 +2213,40 @@ bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrig
tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
tempDrawInfo->fReadConfig = kSRGBA_8888_GrPixelConfig;
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
} else if (readConfig == kAlpha_8_GrPixelConfig) {
// onReadPixels implements a fallback for cases where we are want to read kAlpha_8,
} else if (dstConfig == kAlpha_8_GrPixelConfig) {
// onReadPixels implements a fallback for cases where we want to read kAlpha_8,
// it's unsupported, but 32bit RGBA reads are supported.
// Don't attempt to do any srgb conversions since we only care about alpha.
GrPixelConfig cpuTempConfig = kRGBA_8888_GrPixelConfig;
if (GrPixelConfigIsSRGB(srcSurface->config())) {
cpuTempConfig = kSRGBA_8888_GrPixelConfig;
}
if (!this->readPixelsSupported(srcSurface, cpuTempConfig)) {
if (!this->readPixelsSupported(srcSurface, kRGBA_8888_GrPixelConfig)) {
// If we can't read RGBA from the src try to draw to a kRGBA_8888 (or kSRGBA_8888)
// first and then onReadPixels will read that to a 32bit temporary buffer.
if (this->glCaps().canConfigBeFBOColorAttachment(cpuTempConfig)) {
if (this->glCaps().canConfigBeFBOColorAttachment(kRGBA_8888_GrPixelConfig)) {
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
tempDrawInfo->fTempSurfaceDesc.fConfig = cpuTempConfig;
tempDrawInfo->fTempSurfaceDesc.fConfig = kRGBA_8888_GrPixelConfig;
tempDrawInfo->fReadConfig = kAlpha_8_GrPixelConfig;
} else {
return false;
}
} else {
SkASSERT(tempDrawInfo->fTempSurfaceDesc.fConfig == srcConfig);
tempDrawInfo->fTempSurfaceDesc.fConfig = srcConfig;
SkASSERT(tempDrawInfo->fReadConfig == kAlpha_8_GrPixelConfig);
}
} else if (readConfig == kRGBA_half_GrPixelConfig &&
} else if (dstConfig == kRGBA_half_GrPixelConfig &&
this->readPixelsSupported(srcSurface, kRGBA_float_GrPixelConfig)) {
// If reading in half float format is not supported, then read in float format.
return true;
} else if (this->glCaps().canConfigBeFBOColorAttachment(readConfig) &&
this->readPixelsSupported(readConfig, readConfig)) {
} else if (this->glCaps().canConfigBeFBOColorAttachment(dstConfig) &&
this->readPixelsSupported(dstConfig, dstConfig)) {
// Do a draw to convert from the src config to the read config.
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
tempDrawInfo->fTempSurfaceDesc.fConfig = readConfig;
tempDrawInfo->fReadConfig = readConfig;
tempDrawInfo->fTempSurfaceDesc.fConfig = dstConfig;
tempDrawInfo->fReadConfig = dstConfig;
} else {
return false;
}
}
if ((srcSurface->asRenderTarget() || this->glCaps().canConfigBeFBOColorAttachment(srcConfig)) &&
read_pixels_pays_for_y_flip(srcOrigin, this->glCaps(), width, height, readConfig,
read_pixels_pays_for_y_flip(srcOrigin, this->glCaps(), width, height, dstConfig,
rowBytes)) {
ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference);
}
@ -2288,19 +2267,10 @@ bool GrGLGpu::onReadPixels(GrSurface* surface, GrSurfaceOrigin origin,
return false;
}
// OpenGL doesn't do sRGB <-> linear conversions when reading and writing pixels.
if (requires_srgb_conversion(surface->config(), config)) {
return false;
}
// We have a special case fallback for reading eight bit alpha. We will read back all four 8
// bit channels as RGBA and then extract A.
if (!this->readPixelsSupported(surface, config)) {
// Don't attempt to do any srgb conversions since we only care about alpha.
GrPixelConfig tempConfig = kRGBA_8888_GrPixelConfig;
if (GrPixelConfigIsSRGB(surface->config())) {
tempConfig = kSRGBA_8888_GrPixelConfig;
}
if (kAlpha_8_GrPixelConfig == config &&
this->readPixelsSupported(surface, tempConfig)) {
std::unique_ptr<uint32_t[]> temp(new uint32_t[width * height * 4]);

View File

@ -63,16 +63,6 @@ public:
void generateMipmaps(const GrSamplerState& params, bool allowSRGBInputs, GrGLTexture* texture,
GrSurfaceOrigin textureOrigin);
bool onGetReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrigin,
int readWidth, int readHeight, size_t rowBytes,
GrPixelConfig readConfig, DrawPreference*,
ReadPixelTempDrawInfo*) override;
bool onGetWritePixelsInfo(GrSurface* dstSurface, GrSurfaceOrigin dstOrigin,
int width, int height,
GrPixelConfig srcConfig, DrawPreference*,
WritePixelTempDrawInfo*) override;
// These functions should be used to bind GL objects. They track the GL state and skip redundant
// bindings. Making the equivalent glBind calls directly will confuse the state tracking.
void bindVertexArray(GrGLuint id) {
@ -240,6 +230,12 @@ private:
// variations above, depending on whether the surface is a render target or not.
bool readPixelsSupported(GrSurface* surfaceForConfig, GrPixelConfig readConfig);
bool onGetReadPixelsInfo(GrSurface*, GrSurfaceOrigin, int width, int height, size_t rowBytes,
GrPixelConfig, DrawPreference*, ReadPixelTempDrawInfo*) override;
bool onGetWritePixelsInfo(GrSurface*, GrSurfaceOrigin, int width, int height, GrPixelConfig,
DrawPreference*, WritePixelTempDrawInfo*) override;
bool onReadPixels(GrSurface*, GrSurfaceOrigin,
int left, int top,
int width, int height,

View File

@ -25,25 +25,6 @@ public:
~GrMockGpu() override {}
bool onGetReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrigin,
int readWidth, int readHeight, size_t rowBytes,
GrPixelConfig readConfig, DrawPreference*,
ReadPixelTempDrawInfo*) override { return true; }
bool onGetWritePixelsInfo(GrSurface* dstSurface, GrSurfaceOrigin dstOrigin,
int width, int height,
GrPixelConfig srcConfig, DrawPreference*,
WritePixelTempDrawInfo*) override { return true; }
bool onCopySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin,
GrSurface* src, GrSurfaceOrigin srcOrigin,
const SkIRect& srcRect, const SkIPoint& dstPoint) override { return true; }
void onQueryMultisampleSpecs(GrRenderTarget* rt, GrSurfaceOrigin, const GrStencilSettings&,
int* effectiveSampleCnt, SamplePattern*) override {
*effectiveSampleCnt = rt->numStencilSamples();
}
GrGpuRTCommandBuffer* createCommandBuffer(
GrRenderTarget*, GrSurfaceOrigin,
const GrGpuRTCommandBuffer::LoadAndStoreInfo&,
@ -99,6 +80,18 @@ private:
GrBuffer* onCreateBuffer(size_t sizeInBytes, GrBufferType, GrAccessPattern,
const void*) override;
bool onGetReadPixelsInfo(GrSurface*, GrSurfaceOrigin, int width, int height,
size_t rowBytes, GrPixelConfig, DrawPreference*,
ReadPixelTempDrawInfo*) override {
return true;
}
bool onGetWritePixelsInfo(GrSurface* dstSurface, GrSurfaceOrigin, int width,
int height, GrPixelConfig, DrawPreference*,
WritePixelTempDrawInfo*) override {
return true;
}
bool onReadPixels(GrSurface* surface, GrSurfaceOrigin,
int left, int top, int width, int height,
GrPixelConfig,
@ -121,6 +114,17 @@ private:
return true;
}
bool onCopySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin, GrSurface* src,
GrSurfaceOrigin srcOrigin, const SkIRect& srcRect,
const SkIPoint& dstPoint) override {
return true;
}
void onQueryMultisampleSpecs(GrRenderTarget* rt, GrSurfaceOrigin, const GrStencilSettings&,
int* effectiveSampleCnt, SamplePattern*) override {
*effectiveSampleCnt = rt->numStencilSamples();
}
void onResolveRenderTarget(GrRenderTarget* target) override { return; }
void onFinishFlush(bool insertedSemaphores) override {}

View File

@ -340,6 +340,14 @@ bool GrVkGpu::onGetWritePixelsInfo(GrSurface* dstSurface, GrSurfaceOrigin dstOri
int width, int height,
GrPixelConfig srcConfig, DrawPreference* drawPreference,
WritePixelTempDrawInfo* tempDrawInfo) {
if (*drawPreference != kNoDraw_DrawPreference) {
// We assume the base class has only inserted a draw for sRGB reasons. So the temp surface
// has the config of the original src data. There is no swizzling nor src config spoofing.
SkASSERT(tempDrawInfo->fWriteConfig == srcConfig);
SkASSERT(tempDrawInfo->fTempSurfaceDesc.fConfig == srcConfig);
SkASSERT(tempDrawInfo->fSwizzle == GrSwizzle::RGBA());
}
GrRenderTarget* renderTarget = dstSurface->asRenderTarget();
if (dstSurface->config() == srcConfig) {
@ -381,11 +389,6 @@ bool GrVkGpu::onWritePixels(GrSurface* surface, GrSurfaceOrigin origin,
return false;
}
// We assume Vulkan doesn't do sRGB <-> linear conversions when reading and writing pixels.
if (GrPixelConfigIsSRGB(surface->config()) != GrPixelConfigIsSRGB(config)) {
return false;
}
bool success = false;
bool linearTiling = vkTex->isLinearTiled();
if (linearTiling) {
@ -435,11 +438,6 @@ bool GrVkGpu::onTransferPixels(GrTexture* texture,
return false;
}
// We assume Vulkan doesn't do sRGB <-> linear conversions when reading and writing pixels.
if (GrPixelConfigIsSRGB(texture->config()) != GrPixelConfigIsSRGB(config)) {
return false;
}
SkDEBUGCODE(
SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height);
SkIRect bounds = SkIRect::MakeWH(texture->width(), texture->height());
@ -1859,29 +1857,35 @@ void GrVkGpu::onQueryMultisampleSpecs(GrRenderTarget* rt, GrSurfaceOrigin, const
*effectiveSampleCnt = rt->numStencilSamples();
}
bool GrVkGpu::onGetReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrigin,
int width, int height, size_t rowBytes,
GrPixelConfig readConfig, DrawPreference* drawPreference,
bool GrVkGpu::onGetReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrigin, int width,
int height, size_t rowBytes, GrPixelConfig dstConfig,
DrawPreference* drawPreference,
ReadPixelTempDrawInfo* tempDrawInfo) {
if (srcSurface->config() == readConfig) {
if (*drawPreference != kNoDraw_DrawPreference) {
// We assume the base class has only inserted a draw for sRGB reasons. So the
// the temp surface has the config of the dst data. There is no swizzling nor dst config.
// spoofing.
SkASSERT(tempDrawInfo->fReadConfig == dstConfig);
SkASSERT(tempDrawInfo->fTempSurfaceDesc.fConfig == dstConfig);
SkASSERT(tempDrawInfo->fSwizzle == GrSwizzle::RGBA());
}
if (srcSurface->config() == dstConfig) {
return true;
}
// Any config change requires a draw
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
tempDrawInfo->fTempSurfaceDesc.fConfig = readConfig;
tempDrawInfo->fReadConfig = readConfig;
tempDrawInfo->fTempSurfaceDesc.fConfig = dstConfig;
tempDrawInfo->fReadConfig = dstConfig;
return true;
}
bool GrVkGpu::onReadPixels(GrSurface* surface, GrSurfaceOrigin origin,
int left, int top, int width, int height,
GrPixelConfig config,
void* buffer,
size_t rowBytes) {
bool GrVkGpu::onReadPixels(GrSurface* surface, GrSurfaceOrigin origin, int left, int top, int width,
int height, GrPixelConfig dstConfig, void* buffer, size_t rowBytes) {
VkFormat pixelFormat;
if (!GrPixelConfigToVkFormat(config, &pixelFormat)) {
if (!GrPixelConfigToVkFormat(dstConfig, &pixelFormat)) {
return false;
}
@ -1916,7 +1920,7 @@ bool GrVkGpu::onReadPixels(GrSurface* surface, GrSurfaceOrigin origin,
VK_PIPELINE_STAGE_TRANSFER_BIT,
false);
size_t bpp = GrBytesPerPixel(config);
size_t bpp = GrBytesPerPixel(dstConfig);
size_t tightRowBytes = bpp * width;
bool flipY = kBottomLeft_GrSurfaceOrigin == origin;

View File

@ -64,23 +64,6 @@ public:
kSkip_SyncQueue
};
bool onGetReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrigin,
int readWidth, int readHeight, size_t rowBytes,
GrPixelConfig readConfig, DrawPreference*,
ReadPixelTempDrawInfo*) override;
bool onGetWritePixelsInfo(GrSurface* dstSurface, GrSurfaceOrigin dstOrigin,
int width, int height,
GrPixelConfig srcConfig, DrawPreference*,
WritePixelTempDrawInfo*) override;
bool onCopySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin,
GrSurface* src, GrSurfaceOrigin srcOrigin,
const SkIRect& srcRect, const SkIPoint& dstPoint) override;
void onQueryMultisampleSpecs(GrRenderTarget*, GrSurfaceOrigin, const GrStencilSettings&,
int* effectiveSampleCnt, SamplePattern*) override;
void xferBarrier(GrRenderTarget*, GrXferBarrierType) override {}
GrBackendTexture createTestingOnlyBackendTexture(void* pixels, int w, int h,
@ -193,11 +176,14 @@ private:
GrBuffer* onCreateBuffer(size_t size, GrBufferType type, GrAccessPattern,
const void* data) override;
bool onReadPixels(GrSurface* surface, GrSurfaceOrigin,
int left, int top, int width, int height,
GrPixelConfig,
void* buffer,
size_t rowBytes) override;
bool onGetReadPixelsInfo(GrSurface*, GrSurfaceOrigin, int width, int height, size_t rowBytes,
GrPixelConfig, DrawPreference*, ReadPixelTempDrawInfo*) override;
bool onGetWritePixelsInfo(GrSurface*, GrSurfaceOrigin, int width, int height, GrPixelConfig,
DrawPreference*, WritePixelTempDrawInfo*) override;
bool onReadPixels(GrSurface* surface, GrSurfaceOrigin, int left, int top, int width, int height,
GrPixelConfig, void* buffer, size_t rowBytes) override;
bool onWritePixels(GrSurface* surface, GrSurfaceOrigin,
int left, int top, int width, int height,
@ -208,6 +194,13 @@ private:
GrPixelConfig config, GrBuffer* transferBuffer,
size_t offset, size_t rowBytes) override;
bool onCopySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin, GrSurface* src,
GrSurfaceOrigin srcOrigin, const SkIRect& srcRect,
const SkIPoint& dstPoint) override;
void onQueryMultisampleSpecs(GrRenderTarget*, GrSurfaceOrigin, const GrStencilSettings&,
int* effectiveSampleCnt, SamplePattern*) override;
void onFinishFlush(bool insertedSemaphores) override;
// Ends and submits the current command buffer to the queue and then creates a new command