Attempt to somewhat simplify GrContext::readSurfacePixels interaction with GrGpu.
Review URL: https://codereview.chromium.org/1255483005
This commit is contained in:
parent
6d600af80a
commit
398260262f
@ -450,16 +450,6 @@ bool GrContext::writeSurfacePixels(GrSurface* surface,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// toggles between RGBA and BGRA
|
|
||||||
static SkColorType toggle_colortype32(SkColorType ct) {
|
|
||||||
if (kRGBA_8888_SkColorType == ct) {
|
|
||||||
return kBGRA_8888_SkColorType;
|
|
||||||
} else {
|
|
||||||
SkASSERT(kBGRA_8888_SkColorType == ct);
|
|
||||||
return kRGBA_8888_SkColorType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GrContext::readSurfacePixels(GrSurface* src,
|
bool GrContext::readSurfacePixels(GrSurface* src,
|
||||||
int left, int top, int width, int height,
|
int left, int top, int width, int height,
|
||||||
GrPixelConfig dstConfig, void* buffer, size_t rowBytes,
|
GrPixelConfig dstConfig, void* buffer, size_t rowBytes,
|
||||||
@ -480,126 +470,87 @@ bool GrContext::readSurfacePixels(GrSurface* src,
|
|||||||
this->flush();
|
this->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine which conversions have to be applied: flipY, swapRAnd, and/or unpremul.
|
|
||||||
|
|
||||||
// We ignore the preferred config if it is different than our config unless it is an R/B swap.
|
|
||||||
// In that case we'll perform an R and B swap while drawing to a scratch texture of the swapped
|
|
||||||
// config. Then we will call readPixels on the scratch with the swapped config. The swaps during
|
|
||||||
// the draw cancels out the fact that we call readPixels with a config that is R/B swapped from
|
|
||||||
// dstConfig.
|
|
||||||
GrPixelConfig readConfig = dstConfig;
|
|
||||||
bool swapRAndB = false;
|
|
||||||
if (GrPixelConfigSwapRAndB(dstConfig) ==
|
|
||||||
fGpu->preferredReadPixelsConfig(dstConfig, src->config())) {
|
|
||||||
readConfig = GrPixelConfigSwapRAndB(readConfig);
|
|
||||||
swapRAndB = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool flipY = false;
|
|
||||||
GrRenderTarget* srcAsRT = src->asRenderTarget();
|
|
||||||
if (srcAsRT) {
|
|
||||||
// If fGpu->readPixels would incur a y-flip cost then we will read the pixels upside down.
|
|
||||||
// We'll either do the flipY by drawing into a scratch with a matrix or on the cpu after the
|
|
||||||
// read.
|
|
||||||
flipY = fGpu->readPixelsWillPayForYFlip(srcAsRT, left, top,
|
|
||||||
width, height, dstConfig,
|
|
||||||
rowBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
|
bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
|
||||||
if (unpremul && !GrPixelConfigIs8888(dstConfig)) {
|
if (unpremul && !GrPixelConfigIs8888(dstConfig)) {
|
||||||
// The unpremul flag is only allowed for these two configs.
|
// The unpremul flag is only allowed for 8888 configs.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkAutoTUnref<GrTexture> tempTexture;
|
GrGpu::DrawPreference drawPreference = unpremul ? GrGpu::kCallerPrefersDraw_DrawPreference :
|
||||||
|
GrGpu::kNoDraw_DrawPreference;
|
||||||
|
GrGpu::ReadPixelTempDrawInfo tempDrawInfo;
|
||||||
|
if (!fGpu->getReadPixelsInfo(src, width, height, rowBytes, dstConfig, &drawPreference,
|
||||||
|
&tempDrawInfo)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// If the src is a texture and we would have to do conversions after read pixels, we instead
|
GrRenderTarget* rtToRead = src->asRenderTarget();
|
||||||
// do the conversions by drawing the src to a scratch texture. If we handle any of the
|
bool didTempDraw = false;
|
||||||
// conversions in the draw we set the corresponding bool to false so that we don't reapply it
|
if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
|
||||||
// on the read back pixels. We also do an intermediate draw if the src is not a render target as
|
|
||||||
// GrGpu currently supports reading from render targets but not textures.
|
|
||||||
GrTexture* srcAsTex = src->asTexture();
|
|
||||||
GrRenderTarget* rtToRead = srcAsRT;
|
|
||||||
if (srcAsTex && (swapRAndB || unpremul || flipY || !srcAsRT)) {
|
|
||||||
// Make the scratch a render so we can read its pixels.
|
|
||||||
GrSurfaceDesc desc;
|
|
||||||
desc.fFlags = kRenderTarget_GrSurfaceFlag;
|
|
||||||
desc.fWidth = width;
|
|
||||||
desc.fHeight = height;
|
|
||||||
desc.fConfig = readConfig;
|
|
||||||
desc.fOrigin = kTopLeft_GrSurfaceOrigin;
|
|
||||||
|
|
||||||
// When a full read back is faster than a partial we could always make the scratch exactly
|
|
||||||
// match the passed rect. However, if we see many different size rectangles we will trash
|
|
||||||
// our texture cache and pay the cost of creating and destroying many textures. So, we only
|
|
||||||
// request an exact match when the caller is reading an entire RT.
|
|
||||||
GrTextureProvider::ScratchTexMatch match = GrTextureProvider::kApprox_ScratchTexMatch;
|
GrTextureProvider::ScratchTexMatch match = GrTextureProvider::kApprox_ScratchTexMatch;
|
||||||
if (0 == left &&
|
if (tempDrawInfo.fUseExactScratch) {
|
||||||
0 == top &&
|
// We only respect this when the entire src is being read. Otherwise we can trigger too
|
||||||
src->width() == width &&
|
// many odd ball texture sizes and trash the cache.
|
||||||
src->height() == height &&
|
if (width == src->width() && height == src->height()) {
|
||||||
fGpu->fullReadPixelsIsFasterThanPartial()) {
|
|
||||||
match = GrTextureProvider::kExact_ScratchTexMatch;
|
match = GrTextureProvider::kExact_ScratchTexMatch;
|
||||||
}
|
}
|
||||||
tempTexture.reset(this->textureProvider()->refScratchTexture(desc, match));
|
}
|
||||||
if (tempTexture) {
|
SkAutoTUnref<GrTexture> temp;
|
||||||
// compute a matrix to perform the draw
|
temp.reset(this->textureProvider()->refScratchTexture(tempDrawInfo.fTempSurfaceDesc, match));
|
||||||
|
if (temp) {
|
||||||
SkMatrix textureMatrix;
|
SkMatrix textureMatrix;
|
||||||
textureMatrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
|
textureMatrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
|
||||||
textureMatrix.postIDiv(src->width(), src->height());
|
textureMatrix.postIDiv(src->width(), src->height());
|
||||||
|
|
||||||
GrPaint paint;
|
GrPaint paint;
|
||||||
SkAutoTUnref<const GrFragmentProcessor> fp;
|
SkAutoTUnref<const GrFragmentProcessor> fp;
|
||||||
if (unpremul) {
|
if (unpremul) {
|
||||||
fp.reset(this->createPMToUPMEffect(paint.getProcessorDataManager(), srcAsTex,
|
fp.reset(this->createPMToUPMEffect(
|
||||||
swapRAndB, textureMatrix));
|
paint.getProcessorDataManager(), src->asTexture(), tempDrawInfo.fSwapRAndB,
|
||||||
|
textureMatrix));
|
||||||
if (fp) {
|
if (fp) {
|
||||||
unpremul = false; // we no longer need to do this on CPU after the read back.
|
unpremul = false; // we no longer need to do this on CPU after the read back.
|
||||||
|
} else if (GrGpu::kCallerPrefersDraw_DrawPreference == drawPreference) {
|
||||||
|
// We only wanted to do the draw in order to perform the unpremul so don't
|
||||||
|
// bother.
|
||||||
|
temp.reset(NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If we failed to create a PM->UPM effect and have no other conversions to perform then
|
if (!fp && temp) {
|
||||||
// there is no longer any point to using the scratch.
|
fp.reset(GrConfigConversionEffect::Create(
|
||||||
if (fp || flipY || swapRAndB || !srcAsRT) {
|
paint.getProcessorDataManager(), src->asTexture(), tempDrawInfo.fSwapRAndB,
|
||||||
if (!fp) {
|
GrConfigConversionEffect::kNone_PMConversion, textureMatrix));
|
||||||
fp.reset(GrConfigConversionEffect::Create(paint.getProcessorDataManager(),
|
|
||||||
srcAsTex, swapRAndB, GrConfigConversionEffect::kNone_PMConversion,
|
|
||||||
textureMatrix));
|
|
||||||
}
|
}
|
||||||
swapRAndB = false; // we will handle the swap in the draw.
|
if (fp) {
|
||||||
|
|
||||||
// We protect the existing geometry here since it may not be
|
|
||||||
// clear to the caller that a draw operation (i.e., drawSimpleRect)
|
|
||||||
// can be invoked in this method
|
|
||||||
{
|
|
||||||
GrDrawContext* drawContext = this->drawContext();
|
|
||||||
if (!drawContext) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
paint.addColorProcessor(fp);
|
paint.addColorProcessor(fp);
|
||||||
|
|
||||||
SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
|
SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
|
||||||
|
GrDrawContext* drawContext = this->drawContext();
|
||||||
drawContext->drawRect(tempTexture->asRenderTarget(), GrClip::WideOpen(), paint,
|
drawContext->drawRect(temp->asRenderTarget(), GrClip::WideOpen(), paint,
|
||||||
SkMatrix::I(), rect, NULL);
|
SkMatrix::I(), rect, NULL);
|
||||||
|
rtToRead = temp->asRenderTarget();
|
||||||
// we want to read back from the scratch's origin
|
|
||||||
left = 0;
|
left = 0;
|
||||||
top = 0;
|
top = 0;
|
||||||
rtToRead = tempTexture->asRenderTarget();
|
didTempDraw = true;
|
||||||
}
|
|
||||||
this->flushSurfaceWrites(tempTexture);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rtToRead ||
|
if (GrGpu::kRequireDraw_DrawPreference == drawPreference && !didTempDraw) {
|
||||||
!fGpu->readPixels(rtToRead, left, top, width, height, readConfig, buffer, rowBytes)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Perform any conversions we weren't able to perform using a scratch texture.
|
GrPixelConfig configToRead = dstConfig;
|
||||||
if (unpremul || swapRAndB) {
|
if (didTempDraw) {
|
||||||
|
this->flushSurfaceWrites(rtToRead);
|
||||||
|
// We swapped R and B while doing the temp draw. Swap back on the read.
|
||||||
|
if (tempDrawInfo.fSwapRAndB) {
|
||||||
|
configToRead = GrPixelConfigSwapRAndB(dstConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!fGpu->readPixels(rtToRead, left, top, width, height, configToRead, buffer, rowBytes)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform umpremul conversion if we weren't able to perform it as a draw.
|
||||||
|
if (unpremul) {
|
||||||
SkDstPixelInfo dstPI;
|
SkDstPixelInfo dstPI;
|
||||||
if (!GrPixelConfig2ColorAndProfileType(dstConfig, &dstPI.fColorType, NULL)) {
|
if (!GrPixelConfig2ColorAndProfileType(dstConfig, &dstPI.fColorType, NULL)) {
|
||||||
return false;
|
return false;
|
||||||
@ -609,7 +560,7 @@ bool GrContext::readSurfacePixels(GrSurface* src,
|
|||||||
dstPI.fRowBytes = rowBytes;
|
dstPI.fRowBytes = rowBytes;
|
||||||
|
|
||||||
SkSrcPixelInfo srcPI;
|
SkSrcPixelInfo srcPI;
|
||||||
srcPI.fColorType = swapRAndB ? toggle_colortype32(dstPI.fColorType) : dstPI.fColorType;
|
srcPI.fColorType = dstPI.fColorType;
|
||||||
srcPI.fAlphaType = kPremul_SkAlphaType;
|
srcPI.fAlphaType = kPremul_SkAlphaType;
|
||||||
srcPI.fPixels = buffer;
|
srcPI.fPixels = buffer;
|
||||||
srcPI.fRowBytes = rowBytes;
|
srcPI.fRowBytes = rowBytes;
|
||||||
|
@ -133,15 +133,58 @@ public:
|
|||||||
*/
|
*/
|
||||||
void resolveRenderTarget(GrRenderTarget* target);
|
void resolveRenderTarget(GrRenderTarget* target);
|
||||||
|
|
||||||
/**
|
/** Info struct returned by getReadPixelsInfo about performing intermediate draws before
|
||||||
* Gets a preferred 8888 config to use for writing/reading pixel data to/from a surface with
|
reading pixels for performance or correctness. */
|
||||||
* config surfaceConfig. The returned config must have at least as many bits per channel as the
|
struct ReadPixelTempDrawInfo {
|
||||||
* readConfig or writeConfig param.
|
/** If the GrGpu is requesting that the caller do a draw to an intermediate surface then
|
||||||
|
this is descriptor for the temp surface. The draw should always be a rect with
|
||||||
|
dst 0,0,w,h. */
|
||||||
|
GrSurfaceDesc fTempSurfaceDesc;
|
||||||
|
/** Indicates whether there is a performance advantage to using an exact match texture
|
||||||
|
(in terms of width and height) for the intermediate texture instead of approximate. */
|
||||||
|
bool fUseExactScratch;
|
||||||
|
/** The caller should swap the R and B channel in the temp draw and then instead of reading
|
||||||
|
the desired config back it should read GrPixelConfigSwapRAndB(readConfig). The swap
|
||||||
|
during the draw and the swap at readback time cancel and the client gets the correct
|
||||||
|
data. The swapped read back is either faster for or required by the underlying backend
|
||||||
|
3D API. */
|
||||||
|
bool fSwapRAndB;
|
||||||
|
};
|
||||||
|
/** Describes why an intermediate draw must/should be performed before readPixels. */
|
||||||
|
enum DrawPreference {
|
||||||
|
/** On input means that the caller would proceed without draw if the GrGpu doesn't request
|
||||||
|
one.
|
||||||
|
On output means that the GrGpu is not requesting a draw. */
|
||||||
|
kNoDraw_DrawPreference,
|
||||||
|
/** Means that the client would prefer a draw for performance of the readback but
|
||||||
|
can satisfy a straight readPixels call on the inputs without an intermediate draw.
|
||||||
|
getReadPixelsInfo will never set the draw preference to this value but may leave
|
||||||
|
it set. */
|
||||||
|
kCallerPrefersDraw_DrawPreference,
|
||||||
|
/** On output means that GrGpu would prefer a draw for performance of the readback but
|
||||||
|
can satisfy a straight readPixels call on the inputs without an intermediate draw. The
|
||||||
|
caller of getReadPixelsInfo should never specify this on intput. */
|
||||||
|
kGpuPrefersDraw_DrawPreference,
|
||||||
|
/** On input means that the caller requires a draw to do a transformation and there is no
|
||||||
|
CPU fallback.
|
||||||
|
On output means that GrGpu can only satisfy the readPixels request if the intermediate
|
||||||
|
draw is performed.
|
||||||
|
*/
|
||||||
|
kRequireDraw_DrawPreference
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Used to negotiates whether and how an intermediate draw should or must be performed before
|
||||||
|
a readPixels call. If this returns false then GrGpu could not deduce an intermediate draw
|
||||||
|
that would allow a successful readPixels call. */
|
||||||
|
virtual bool getReadPixelsInfo(GrSurface* srcSurface, int readWidth, int readHeight,
|
||||||
|
size_t rowBytes, GrPixelConfig readConfig, DrawPreference*,
|
||||||
|
ReadPixelTempDrawInfo *) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a preferred 8888 config to use for writing pixel data to a surface with
|
||||||
|
* config surfaceConfig. The returned config must have at least as many bits per channel as the
|
||||||
|
* writeConfig param.
|
||||||
*/
|
*/
|
||||||
virtual GrPixelConfig preferredReadPixelsConfig(GrPixelConfig readConfig,
|
|
||||||
GrPixelConfig surfaceConfig) const {
|
|
||||||
return readConfig;
|
|
||||||
}
|
|
||||||
virtual GrPixelConfig preferredWritePixelsConfig(GrPixelConfig writeConfig,
|
virtual GrPixelConfig preferredWritePixelsConfig(GrPixelConfig writeConfig,
|
||||||
GrPixelConfig surfaceConfig) const {
|
GrPixelConfig surfaceConfig) const {
|
||||||
return writeConfig;
|
return writeConfig;
|
||||||
@ -153,35 +196,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual bool canWriteTexturePixels(const GrTexture*, GrPixelConfig srcConfig) const = 0;
|
virtual bool canWriteTexturePixels(const GrTexture*, GrPixelConfig srcConfig) const = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* OpenGL's readPixels returns the result bottom-to-top while the skia
|
|
||||||
* API is top-to-bottom. Thus we have to do a y-axis flip. The obvious
|
|
||||||
* solution is to have the subclass do the flip using either the CPU or GPU.
|
|
||||||
* However, the caller (GrContext) may have transformations to apply and can
|
|
||||||
* simply fold in the y-flip for free. On the other hand, the subclass may
|
|
||||||
* be able to do it for free itself. For example, the subclass may have to
|
|
||||||
* do memcpys to handle rowBytes that aren't tight. It could do the y-flip
|
|
||||||
* concurrently.
|
|
||||||
*
|
|
||||||
* This function returns true if a y-flip is required to put the pixels in
|
|
||||||
* top-to-bottom order and the subclass cannot do it for free.
|
|
||||||
*
|
|
||||||
* See read pixels for the params
|
|
||||||
* @return true if calling readPixels with the same set of params will
|
|
||||||
* produce bottom-to-top data
|
|
||||||
*/
|
|
||||||
virtual bool readPixelsWillPayForYFlip(GrRenderTarget* renderTarget,
|
|
||||||
int left, int top,
|
|
||||||
int width, int height,
|
|
||||||
GrPixelConfig config,
|
|
||||||
size_t rowBytes) const = 0;
|
|
||||||
/**
|
|
||||||
* This should return true if reading a NxM rectangle of pixels from a
|
|
||||||
* render target is faster if the target has dimensons N and M and the read
|
|
||||||
* rectangle has its top-left at 0,0.
|
|
||||||
*/
|
|
||||||
virtual bool fullReadPixelsIsFasterThanPartial() const { return false; };
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a rectangle of pixels from a render target.
|
* Reads a rectangle of pixels from a render target.
|
||||||
*
|
*
|
||||||
|
@ -150,11 +150,10 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool readPixelsWillPayForYFlip(GrRenderTarget* renderTarget,
|
bool getReadPixelsInfo(GrSurface* srcSurface, int readWidth, int readHeight, size_t rowBytes,
|
||||||
int left, int top,
|
GrPixelConfig readConfig, DrawPreference*,
|
||||||
int width, int height,
|
ReadPixelTempDrawInfo*) override { return false; }
|
||||||
GrPixelConfig config,
|
|
||||||
size_t rowBytes) const override { return false; }
|
|
||||||
void buildProgramDesc(GrProgramDesc*,const GrPrimitiveProcessor&,
|
void buildProgramDesc(GrProgramDesc*,const GrPrimitiveProcessor&,
|
||||||
const GrPipeline&,
|
const GrPipeline&,
|
||||||
const GrBatchTracker&) const override {}
|
const GrBatchTracker&) const override {}
|
||||||
|
@ -267,28 +267,6 @@ void GrGLGpu::contextAbandoned() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
GrPixelConfig GrGLGpu::preferredReadPixelsConfig(GrPixelConfig readConfig,
|
|
||||||
GrPixelConfig surfaceConfig) const {
|
|
||||||
if (GR_GL_RGBA_8888_PIXEL_OPS_SLOW && kRGBA_8888_GrPixelConfig == readConfig) {
|
|
||||||
return kBGRA_8888_GrPixelConfig;
|
|
||||||
} else if (kMesa_GrGLDriver == this->glContext().driver() &&
|
|
||||||
GrBytesPerPixel(readConfig) == 4 &&
|
|
||||||
GrPixelConfigSwapRAndB(readConfig) == surfaceConfig) {
|
|
||||||
// Mesa 3D takes a slow path on when reading back BGRA from an RGBA surface and vice-versa.
|
|
||||||
// Perhaps this should be guarded by some compiletime or runtime check.
|
|
||||||
return surfaceConfig;
|
|
||||||
} else if (readConfig == kBGRA_8888_GrPixelConfig
|
|
||||||
&& !this->glCaps().readPixelsSupported(
|
|
||||||
this->glInterface(),
|
|
||||||
GR_GL_BGRA,
|
|
||||||
GR_GL_UNSIGNED_BYTE,
|
|
||||||
surfaceConfig
|
|
||||||
)) {
|
|
||||||
return kRGBA_8888_GrPixelConfig;
|
|
||||||
} else {
|
|
||||||
return readConfig;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GrPixelConfig GrGLGpu::preferredWritePixelsConfig(GrPixelConfig writeConfig,
|
GrPixelConfig GrGLGpu::preferredWritePixelsConfig(GrPixelConfig writeConfig,
|
||||||
GrPixelConfig surfaceConfig) const {
|
GrPixelConfig surfaceConfig) const {
|
||||||
@ -322,10 +300,6 @@ bool GrGLGpu::canWriteTexturePixels(const GrTexture* texture, GrPixelConfig srcC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GrGLGpu::fullReadPixelsIsFasterThanPartial() const {
|
|
||||||
return SkToBool(GR_GL_FULL_READPIXELS_FASTER_THAN_PARTIAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GrGLGpu::onResetContext(uint32_t resetBits) {
|
void GrGLGpu::onResetContext(uint32_t resetBits) {
|
||||||
// we don't use the zb at all
|
// we don't use the zb at all
|
||||||
if (resetBits & kMisc_GrGLBackendState) {
|
if (resetBits & kMisc_GrGLBackendState) {
|
||||||
@ -1651,7 +1625,6 @@ void GrGLGpu::discard(GrRenderTarget* renderTarget) {
|
|||||||
renderTarget->flagAsResolved();
|
renderTarget->flagAsResolved();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void GrGLGpu::clearStencil(GrRenderTarget* target) {
|
void GrGLGpu::clearStencil(GrRenderTarget* target) {
|
||||||
if (NULL == target) {
|
if (NULL == target) {
|
||||||
return;
|
return;
|
||||||
@ -1705,35 +1678,91 @@ void GrGLGpu::onClearStencilClip(GrRenderTarget* target, const SkIRect& rect, bo
|
|||||||
fHWStencilSettings.invalidate();
|
fHWStencilSettings.invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GrGLGpu::readPixelsWillPayForYFlip(GrRenderTarget* renderTarget,
|
static bool read_pixels_pays_for_y_flip(GrRenderTarget* renderTarget, const GrGLCaps& caps,
|
||||||
int left, int top,
|
int width, int height, GrPixelConfig config,
|
||||||
int width, int height,
|
size_t rowBytes) {
|
||||||
GrPixelConfig config,
|
// If this render target is already TopLeft, we don't need to flip.
|
||||||
size_t rowBytes) const {
|
|
||||||
// If this rendertarget is aready TopLeft, we don't need to flip.
|
|
||||||
if (kTopLeft_GrSurfaceOrigin == renderTarget->origin()) {
|
if (kTopLeft_GrSurfaceOrigin == renderTarget->origin()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if GL can do the flip then we'll never pay for it.
|
// if GL can do the flip then we'll never pay for it.
|
||||||
if (this->glCaps().packFlipYSupport()) {
|
if (caps.packFlipYSupport()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have to do memcpy to handle non-trim rowBytes then we
|
// If we have to do memcpy to handle non-trim rowBytes then we
|
||||||
// get the flip for free. Otherwise it costs.
|
// get the flip for free. Otherwise it costs.
|
||||||
if (this->glCaps().packRowLengthSupport()) {
|
// Note that we're assuming that 0 rowBytes has already been handled and that the width has been
|
||||||
return true;
|
// clipped.
|
||||||
}
|
return caps.packRowLengthSupport() || GrBytesPerPixel(config) * width == rowBytes;
|
||||||
// If we have to do memcpys to handle rowBytes then y-flip is free
|
}
|
||||||
// Note the rowBytes might be tight to the passed in data, but if data
|
|
||||||
// gets clipped in x to the target the rowBytes will no longer be tight.
|
void elevate_draw_preference(GrGpu::DrawPreference* preference, GrGpu::DrawPreference elevation) {
|
||||||
if (left >= 0 && (left + width) < renderTarget->width()) {
|
GR_STATIC_ASSERT(GrGpu::kCallerPrefersDraw_DrawPreference > GrGpu::kNoDraw_DrawPreference);
|
||||||
return 0 == rowBytes ||
|
GR_STATIC_ASSERT(GrGpu::kGpuPrefersDraw_DrawPreference >
|
||||||
GrBytesPerPixel(config) * width == rowBytes;
|
GrGpu::kCallerPrefersDraw_DrawPreference);
|
||||||
} else {
|
GR_STATIC_ASSERT(GrGpu::kRequireDraw_DrawPreference > GrGpu::kGpuPrefersDraw_DrawPreference);
|
||||||
|
*preference = SkTMax(*preference, elevation);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GrGLGpu::getReadPixelsInfo(GrSurface* srcSurface, int width, int height, size_t rowBytes,
|
||||||
|
GrPixelConfig readConfig, DrawPreference* drawPreference,
|
||||||
|
ReadPixelTempDrawInfo* tempDrawInfo) {
|
||||||
|
SkASSERT(drawPreference);
|
||||||
|
SkASSERT(tempDrawInfo);
|
||||||
|
SkASSERT(kGpuPrefersDraw_DrawPreference != *drawPreference);
|
||||||
|
|
||||||
|
if (GrPixelConfigIsCompressed(readConfig)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tempDrawInfo->fSwapRAndB = false;
|
||||||
|
|
||||||
|
// These settings we will always want if a temp draw is performed. The config is set below
|
||||||
|
// depending on whether we want to do a R/B swap or not.
|
||||||
|
tempDrawInfo->fTempSurfaceDesc.fFlags = kRenderTarget_GrSurfaceFlag;
|
||||||
|
tempDrawInfo->fTempSurfaceDesc.fWidth = width;
|
||||||
|
tempDrawInfo->fTempSurfaceDesc.fHeight = height;
|
||||||
|
tempDrawInfo->fTempSurfaceDesc.fSampleCnt = 0;
|
||||||
|
tempDrawInfo->fTempSurfaceDesc.fOrigin = kTopLeft_GrSurfaceOrigin; // no CPU y-flip for TL.
|
||||||
|
tempDrawInfo->fUseExactScratch = SkToBool(GR_GL_FULL_READPIXELS_FASTER_THAN_PARTIAL);
|
||||||
|
|
||||||
|
// Start off assuming that any temp draw should be to the readConfig, then check if that will
|
||||||
|
// be inefficient.
|
||||||
|
GrPixelConfig srcConfig = srcSurface->config();
|
||||||
|
tempDrawInfo->fTempSurfaceDesc.fConfig = readConfig;
|
||||||
|
|
||||||
|
if (GR_GL_RGBA_8888_PIXEL_OPS_SLOW && kRGBA_8888_GrPixelConfig == readConfig) {
|
||||||
|
tempDrawInfo->fTempSurfaceDesc.fConfig = kBGRA_8888_GrPixelConfig;
|
||||||
|
} else if (kMesa_GrGLDriver == this->glContext().driver() &&
|
||||||
|
GrBytesPerPixel(readConfig) == 4 &&
|
||||||
|
GrPixelConfigSwapRAndB(readConfig) == 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.
|
||||||
|
tempDrawInfo->fTempSurfaceDesc.fConfig = srcConfig;
|
||||||
|
tempDrawInfo->fSwapRAndB = true;
|
||||||
|
elevate_draw_preference(drawPreference, kGpuPrefersDraw_DrawPreference);
|
||||||
|
} else if (readConfig == kBGRA_8888_GrPixelConfig &&
|
||||||
|
!this->glCaps().readPixelsSupported(this->glInterface(), GR_GL_BGRA,
|
||||||
|
GR_GL_UNSIGNED_BYTE, srcConfig)) {
|
||||||
|
tempDrawInfo->fTempSurfaceDesc.fConfig = kRGBA_8888_GrPixelConfig;
|
||||||
|
tempDrawInfo->fSwapRAndB = true;
|
||||||
|
elevate_draw_preference(drawPreference, kRequireDraw_DrawPreference);
|
||||||
|
}
|
||||||
|
|
||||||
|
GrRenderTarget* srcAsRT = srcSurface->asRenderTarget();
|
||||||
|
if (!srcAsRT) {
|
||||||
|
elevate_draw_preference(drawPreference, kRequireDraw_DrawPreference);
|
||||||
|
} else if (read_pixels_pays_for_y_flip(srcAsRT, this->glCaps(), width, height, readConfig,
|
||||||
|
rowBytes)) {
|
||||||
|
elevate_draw_preference(drawPreference, kGpuPrefersDraw_DrawPreference);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kRequireDraw_DrawPreference == *drawPreference && !srcSurface->asTexture()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GrGLGpu::onReadPixels(GrRenderTarget* target,
|
bool GrGLGpu::onReadPixels(GrRenderTarget* target,
|
||||||
@ -1742,6 +1771,8 @@ bool GrGLGpu::onReadPixels(GrRenderTarget* target,
|
|||||||
GrPixelConfig config,
|
GrPixelConfig config,
|
||||||
void* buffer,
|
void* buffer,
|
||||||
size_t rowBytes) {
|
size_t rowBytes) {
|
||||||
|
SkASSERT(target);
|
||||||
|
|
||||||
// We cannot read pixels into a compressed buffer
|
// We cannot read pixels into a compressed buffer
|
||||||
if (GrPixelConfigIsCompressed(config)) {
|
if (GrPixelConfigIsCompressed(config)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -57,18 +57,15 @@ public:
|
|||||||
// Used by GrGLProgram to configure OpenGL state.
|
// Used by GrGLProgram to configure OpenGL state.
|
||||||
void bindTexture(int unitIdx, const GrTextureParams& params, GrGLTexture* texture);
|
void bindTexture(int unitIdx, const GrTextureParams& params, GrGLTexture* texture);
|
||||||
|
|
||||||
|
bool getReadPixelsInfo(GrSurface* srcSurface, int readWidth, int readHeight, size_t rowBytes,
|
||||||
|
GrPixelConfig readConfig, DrawPreference*,
|
||||||
|
ReadPixelTempDrawInfo*) override;
|
||||||
|
|
||||||
|
|
||||||
// GrGpu overrides
|
// GrGpu overrides
|
||||||
GrPixelConfig preferredReadPixelsConfig(GrPixelConfig readConfig,
|
|
||||||
GrPixelConfig surfaceConfig) const override;
|
|
||||||
GrPixelConfig preferredWritePixelsConfig(GrPixelConfig writeConfig,
|
GrPixelConfig preferredWritePixelsConfig(GrPixelConfig writeConfig,
|
||||||
GrPixelConfig surfaceConfig) const override;
|
GrPixelConfig surfaceConfig) const override;
|
||||||
bool canWriteTexturePixels(const GrTexture*, GrPixelConfig srcConfig) const override;
|
bool canWriteTexturePixels(const GrTexture*, GrPixelConfig srcConfig) const override;
|
||||||
bool readPixelsWillPayForYFlip(GrRenderTarget* renderTarget,
|
|
||||||
int left, int top,
|
|
||||||
int width, int height,
|
|
||||||
GrPixelConfig config,
|
|
||||||
size_t rowBytes) const override;
|
|
||||||
bool fullReadPixelsIsFasterThanPartial() const override;
|
|
||||||
|
|
||||||
bool initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc) const override;
|
bool initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc) const override;
|
||||||
|
|
||||||
|
@ -198,15 +198,17 @@ static bool check_read(skiatest::Reporter* reporter,
|
|||||||
SkPMColor canvasPixel = get_src_color(devx, devy);
|
SkPMColor canvasPixel = get_src_color(devx, devy);
|
||||||
bool didPremul;
|
bool didPremul;
|
||||||
SkPMColor pmPixel = convert_to_pmcolor(ct, at, pixel, &didPremul);
|
SkPMColor pmPixel = convert_to_pmcolor(ct, at, pixel, &didPremul);
|
||||||
bool check = check_read_pixel(pmPixel, canvasPixel, didPremul);
|
if (!check_read_pixel(pmPixel, canvasPixel, didPremul)) {
|
||||||
REPORTER_ASSERT(reporter, check);
|
ERRORF(reporter, "Expected readback pixel value 0x%08x, got 0x%08x. "
|
||||||
if (!check) {
|
"Readback was unpremul: %d", canvasPixel, pmPixel, didPremul);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (checkBitmapPixels) {
|
} else if (checkBitmapPixels) {
|
||||||
REPORTER_ASSERT(reporter, get_dst_bmp_init_color(bx, by, bw) == *pixel);
|
uint32_t origDstPixel = get_dst_bmp_init_color(bx, by, bw);
|
||||||
if (get_dst_bmp_init_color(bx, by, bw) != *pixel) {
|
if (origDstPixel != *pixel) {
|
||||||
|
ERRORF(reporter, "Expected clipped out area of readback to be unchanged. "
|
||||||
|
"Expected 0x%08x, got 0x%08x", origDstPixel, *pixel);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user