Add ability to query read pixels support without a render target.

Add more checks to onGetReadPixelsInfo.
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1615023003

Review URL: https://codereview.chromium.org/1615023003
This commit is contained in:
bsalomon 2016-01-22 08:16:09 -08:00 committed by Commit bot
parent 6a377e629d
commit 1aa202935f
4 changed files with 106 additions and 30 deletions

View File

@ -10,6 +10,7 @@
#include "GrContextOptions.h" #include "GrContextOptions.h"
#include "GrGLContext.h" #include "GrGLContext.h"
#include "GrGLRenderTarget.h"
#include "glsl/GrGLSLCaps.h" #include "glsl/GrGLSLCaps.h"
#include "SkTSearch.h" #include "SkTSearch.h"
#include "SkTSort.h" #include "SkTSort.h"
@ -17,6 +18,8 @@
GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions, GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions,
const GrGLContextInfo& ctxInfo, const GrGLContextInfo& ctxInfo,
const GrGLInterface* glInterface) : INHERITED(contextOptions) { const GrGLInterface* glInterface) : INHERITED(contextOptions) {
fStandard = ctxInfo.standard();
fStencilFormats.reset(); fStencilFormats.reset();
fMSFBOType = kNone_MSFBOType; fMSFBOType = kNone_MSFBOType;
fInvalidateFBType = kNone_InvalidateFBType; fInvalidateFBType = kNone_InvalidateFBType;
@ -648,47 +651,52 @@ bool GrGLCaps::hasPathRenderingSupport(const GrGLContextInfo& ctxInfo, const GrG
} }
return true; return true;
} }
bool GrGLCaps::readPixelsSupported(const GrGLInterface* intf,
bool GrGLCaps::readPixelsSupported(GrPixelConfig rtConfig,
GrPixelConfig readConfig, GrPixelConfig readConfig,
GrPixelConfig currFBOConfig) const { std::function<void (GrGLenum, GrGLint*)> getIntegerv,
SkASSERT(this->isConfigRenderable(currFBOConfig, false)); std::function<bool ()> bindRenderTarget) const {
SkASSERT(this->isConfigRenderable(rtConfig, false));
GrGLenum readFormat; GrGLenum readFormat;
GrGLenum readType; GrGLenum readType;
if (!this->getReadPixelsFormat(currFBOConfig, readConfig, &readFormat, &readType)) { if (!this->getReadPixelsFormat(rtConfig, readConfig, &readFormat, &readType)) {
return false; return false;
} }
if (kGL_GrGLStandard == intf->fStandard) { if (kGL_GrGLStandard == fStandard) {
// All of our renderable configs can be converted to each other by glReadPixels in OpenGL. // All of our renderable configs can be converted to each other by glReadPixels in OpenGL.
return true; return true;
} }
// See Section 16.1.2 in the ES 3.2 specification. // See Section 16.1.2 in the ES 3.2 specification.
if (kNormalizedFixedPoint_FormatType == fConfigTable[currFBOConfig].fFormatType) { if (kNormalizedFixedPoint_FormatType == fConfigTable[rtConfig].fFormatType) {
if (GR_GL_RGBA == readFormat && GR_GL_UNSIGNED_BYTE == readType) { if (GR_GL_RGBA == readFormat && GR_GL_UNSIGNED_BYTE == readType) {
return true; return true;
} }
} else { } else {
SkASSERT(kFloat_FormatType == fConfigTable[currFBOConfig].fFormatType); SkASSERT(kFloat_FormatType == fConfigTable[rtConfig].fFormatType);
if (GR_GL_RGBA == readFormat && GR_GL_FLOAT == readType) { if (GR_GL_RGBA == readFormat && GR_GL_FLOAT == readType) {
return true; return true;
} }
} }
if (0 == fConfigTable[currFBOConfig].fSecondReadPixelsFormat.fFormat) { if (0 == fConfigTable[rtConfig].fSecondReadPixelsFormat.fFormat) {
ReadPixelsFormat* rpFormat = ReadPixelsFormat* rpFormat =
const_cast<ReadPixelsFormat*>(&fConfigTable[currFBOConfig].fSecondReadPixelsFormat); const_cast<ReadPixelsFormat*>(&fConfigTable[rtConfig].fSecondReadPixelsFormat);
GrGLint format = 0, type = 0; GrGLint format = 0, type = 0;
GR_GL_GetIntegerv(intf, GR_GL_IMPLEMENTATION_COLOR_READ_FORMAT, &format); if (!bindRenderTarget()) {
GR_GL_GetIntegerv(intf, GR_GL_IMPLEMENTATION_COLOR_READ_TYPE, &type); return false;
}
getIntegerv(GR_GL_IMPLEMENTATION_COLOR_READ_FORMAT, &format);
getIntegerv(GR_GL_IMPLEMENTATION_COLOR_READ_TYPE, &type);
rpFormat->fFormat = format; rpFormat->fFormat = format;
rpFormat->fType = type; rpFormat->fType = type;
} }
return fConfigTable[currFBOConfig].fSecondReadPixelsFormat.fFormat == readFormat && return fConfigTable[rtConfig].fSecondReadPixelsFormat.fFormat == readFormat &&
fConfigTable[currFBOConfig].fSecondReadPixelsFormat.fType == readType; fConfigTable[rtConfig].fSecondReadPixelsFormat.fType == readType;
} }
void GrGLCaps::initFSAASupport(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) { void GrGLCaps::initFSAASupport(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {

View File

@ -9,6 +9,8 @@
#ifndef GrGLCaps_DEFINED #ifndef GrGLCaps_DEFINED
#define GrGLCaps_DEFINED #define GrGLCaps_DEFINED
#include <functional>
#include "glsl/GrGLSL.h" #include "glsl/GrGLSL.h"
#include "GrCaps.h" #include "GrCaps.h"
#include "GrGLStencilAttachment.h" #include "GrGLStencilAttachment.h"
@ -19,6 +21,7 @@
class GrGLContextInfo; class GrGLContextInfo;
class GrGLSLCaps; class GrGLSLCaps;
class GrGLRenderTarget;
/** /**
* Stores some capabilities of a GL context. Most are determined by the GL * Stores some capabilities of a GL context. Most are determined by the GL
@ -283,10 +286,11 @@ public:
/// Use indices or vertices in CPU arrays rather than VBOs for dynamic content. /// Use indices or vertices in CPU arrays rather than VBOs for dynamic content.
bool useNonVBOVertexAndIndexDynamicData() const { return fUseNonVBOVertexAndIndexDynamicData; } bool useNonVBOVertexAndIndexDynamicData() const { return fUseNonVBOVertexAndIndexDynamicData; }
/// Does ReadPixels support the provided format/type combo? /// Does ReadPixels support reading readConfig pixels from a FBO that is renderTargetConfig?
bool readPixelsSupported(const GrGLInterface* intf, bool readPixelsSupported(GrPixelConfig renderTargetConfig,
GrPixelConfig readConfig, GrPixelConfig readConfig,
GrPixelConfig currFBOConfig) const; std::function<void (GrGLenum, GrGLint*)> getIntegerv,
std::function<bool ()> bindRenderTarget) const;
bool isCoreProfile() const { return fIsCoreProfile; } bool isCoreProfile() const { return fIsCoreProfile; }
@ -348,6 +352,8 @@ private:
const GrGLInterface* intf, const GrGLInterface* intf,
GrGLSLCaps* glslCaps); GrGLSLCaps* glslCaps);
GrGLStandard fStandard;
SkTArray<StencilFormat, true> fStencilFormats; SkTArray<StencilFormat, true> fStencilFormats;
int fMaxFragmentUniformVectors; int fMaxFragmentUniformVectors;

View File

@ -2069,12 +2069,55 @@ static bool read_pixels_pays_for_y_flip(GrRenderTarget* renderTarget, const GrGL
return caps.packRowLengthSupport() || GrBytesPerPixel(config) * width == rowBytes; return caps.packRowLengthSupport() || GrBytesPerPixel(config) * width == rowBytes;
} }
bool GrGLGpu::readPixelsSupported(GrRenderTarget* target, GrPixelConfig readConfig) {
auto bindRenderTarget = [this, target]() -> bool {
this->flushRenderTarget(static_cast<GrGLRenderTarget*>(target), &SkIRect::EmptyIRect());
return true;
};
auto getIntegerv = [this](GrGLenum query, GrGLint* value) {
GR_GL_GetIntegerv(this->glInterface(), query, value);
};
GrPixelConfig rtConfig = target->config();
return this->glCaps().readPixelsSupported(rtConfig, readConfig, getIntegerv, bindRenderTarget);
}
bool GrGLGpu::readPixelsSupported(GrPixelConfig rtConfig, GrPixelConfig readConfig) {
auto bindRenderTarget = [this, rtConfig]() -> bool {
GrTextureDesc desc;
desc.fConfig = rtConfig;
desc.fWidth = desc.fHeight = 16;
desc.fFlags = kRenderTarget_GrSurfaceFlag;
SkAutoTUnref<GrTexture> temp(this->createTexture(desc, false, nullptr, 0));
if (!temp) {
return false;
}
GrGLRenderTarget* glrt = static_cast<GrGLRenderTarget*>(temp->asRenderTarget());
this->flushRenderTarget(glrt, &SkIRect::EmptyIRect());
return true;
};
auto getIntegerv = [this](GrGLenum query, GrGLint* value) {
GR_GL_GetIntegerv(this->glInterface(), query, value);
};
return this->glCaps().readPixelsSupported(rtConfig, readConfig, getIntegerv, bindRenderTarget);
}
bool GrGLGpu::readPixelsSupported(GrSurface* surfaceForConfig, GrPixelConfig readConfig) {
if (GrRenderTarget* rt = surfaceForConfig->asRenderTarget()) {
return this->readPixelsSupported(rt, readConfig);
} else {
GrPixelConfig config = surfaceForConfig->config();
return this->readPixelsSupported(config, readConfig);
}
}
bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height, size_t rowBytes, bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height, size_t rowBytes,
GrPixelConfig readConfig, DrawPreference* drawPreference, GrPixelConfig readConfig, DrawPreference* drawPreference,
ReadPixelTempDrawInfo* tempDrawInfo) { ReadPixelTempDrawInfo* tempDrawInfo) {
GrRenderTarget* srcAsRT = srcSurface->asRenderTarget();
// This subclass can only read pixels from a render target. We could use glTexSubImage2D on // This subclass can only read pixels from a render target. We could use glTexSubImage2D on
// GL versions that support it but we don't today. // GL versions that support it but we don't today.
if (!srcSurface->asRenderTarget()) { if (!srcAsRT) {
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference); ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
} }
@ -2099,33 +2142,38 @@ bool GrGLGpu::onGetReadPixelsInfo(GrSurface* srcSurface, int width, int height,
GrPixelConfig srcConfig = srcSurface->config(); GrPixelConfig srcConfig = srcSurface->config();
tempDrawInfo->fTempSurfaceDesc.fConfig = readConfig; tempDrawInfo->fTempSurfaceDesc.fConfig = readConfig;
if (this->glCaps().rgba8888PixelsOpsAreSlow() && kRGBA_8888_GrPixelConfig == readConfig) { if (this->glCaps().rgba8888PixelsOpsAreSlow() && kRGBA_8888_GrPixelConfig == readConfig &&
this->readPixelsSupported(kBGRA_8888_GrPixelConfig, kBGRA_8888_GrPixelConfig)) {
tempDrawInfo->fTempSurfaceDesc.fConfig = kBGRA_8888_GrPixelConfig; tempDrawInfo->fTempSurfaceDesc.fConfig = kBGRA_8888_GrPixelConfig;
tempDrawInfo->fSwizzle = GrSwizzle::BGRA(); tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
tempDrawInfo->fReadConfig = kBGRA_8888_GrPixelConfig; tempDrawInfo->fReadConfig = kBGRA_8888_GrPixelConfig;
ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference); ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference);
} else if (kMesa_GrGLDriver == this->glContext().driver() && } else if (kMesa_GrGLDriver == this->glContext().driver() &&
GrBytesPerPixel(readConfig) == 4 && GrBytesPerPixel(readConfig) == 4 &&
GrPixelConfigSwapRAndB(readConfig) == srcConfig) { GrPixelConfigSwapRAndB(readConfig) == srcConfig &&
this->readPixelsSupported(srcSurface, srcConfig)) {
// Mesa 3D takes a slow path on when reading back BGRA from an RGBA surface and vice-versa. // 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. // Better to do a draw with a R/B swap and then read as the original config.
tempDrawInfo->fTempSurfaceDesc.fConfig = srcConfig; tempDrawInfo->fTempSurfaceDesc.fConfig = srcConfig;
tempDrawInfo->fSwizzle = GrSwizzle::BGRA(); tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
tempDrawInfo->fReadConfig = srcConfig; tempDrawInfo->fReadConfig = srcConfig;
ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference); ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference);
} else if (readConfig == kBGRA_8888_GrPixelConfig && } else if (!this->readPixelsSupported(srcSurface, readConfig)) {
!this->glCaps().readPixelsSupported(this->glInterface(), readConfig, srcConfig)) { if (readConfig == kBGRA_8888_GrPixelConfig &&
tempDrawInfo->fTempSurfaceDesc.fConfig = kRGBA_8888_GrPixelConfig; this->glCaps().isConfigRenderable(kRGBA_8888_GrPixelConfig, false) &&
tempDrawInfo->fSwizzle = GrSwizzle::BGRA(); this->readPixelsSupported(kRGBA_8888_GrPixelConfig, kRGBA_8888_GrPixelConfig)) {
tempDrawInfo->fReadConfig = kRGBA_8888_GrPixelConfig;
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference); tempDrawInfo->fTempSurfaceDesc.fConfig = kRGBA_8888_GrPixelConfig;
tempDrawInfo->fSwizzle = GrSwizzle::BGRA();
tempDrawInfo->fReadConfig = kRGBA_8888_GrPixelConfig;
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
} else {
return false;
}
} }
GrRenderTarget* srcAsRT = srcSurface->asRenderTarget(); if (srcAsRT &&
if (!srcAsRT) { read_pixels_pays_for_y_flip(srcAsRT, this->glCaps(), width, height, readConfig, rowBytes)) {
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
} else if (read_pixels_pays_for_y_flip(srcAsRT, this->glCaps(), width, height, readConfig,
rowBytes)) {
ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference); ElevateDrawPreference(drawPreference, kGpuPrefersDraw_DrawPreference);
} }

View File

@ -166,6 +166,20 @@ private:
bool onMakeCopyForTextureParams(GrTexture*, const GrTextureParams&, bool onMakeCopyForTextureParams(GrTexture*, const GrTextureParams&,
GrTextureProducer::CopyParams*) const override; GrTextureProducer::CopyParams*) const override;
// Checks whether glReadPixels can be called to get pixel values in readConfig from the
// render target.
bool readPixelsSupported(GrRenderTarget* target, GrPixelConfig readConfig);
// Checks whether glReadPixels can be called to get pixel values in readConfig from a
// render target that has renderTargetConfig. This may have to create a temporary
// render target and thus is less preferable than the variant that takes a render target.
bool readPixelsSupported(GrPixelConfig renderTargetConfig, GrPixelConfig readConfig);
// Checks whether glReadPixels can be called to get pixel values in readConfig from a
// render target that has the same config as surfaceForConfig. Calls one of the the two
// variations above, depending on whether the surface is a render target or not.
bool readPixelsSupported(GrSurface* surfaceForConfig, GrPixelConfig readConfig);
bool onReadPixels(GrSurface*, bool onReadPixels(GrSurface*,
int left, int top, int left, int top,
int width, int height, int width, int height,