Initial version of external_oes texture support and unit test
Review URL: https://codereview.chromium.org/1451683002
This commit is contained in:
parent
ac8cabd729
commit
27a0487007
@ -25,8 +25,9 @@ enum GrSLType {
|
||||
kMat33f_GrSLType,
|
||||
kMat44f_GrSLType,
|
||||
kSampler2D_GrSLType,
|
||||
kSamplerExternal_GrSLType,
|
||||
|
||||
kLast_GrSLType = kSampler2D_GrSLType
|
||||
kLast_GrSLType = kSamplerExternal_GrSLType
|
||||
};
|
||||
static const int kGrSLTypeCount = kLast_GrSLType + 1;
|
||||
|
||||
@ -63,7 +64,7 @@ static const int kGrSLPrecisionCount = kLast_GrSLPrecision + 1;
|
||||
*/
|
||||
static inline int GrSLTypeVectorCount(GrSLType type) {
|
||||
SkASSERT(type >= 0 && type < static_cast<GrSLType>(kGrSLTypeCount));
|
||||
static const int kCounts[] = { -1, 1, 2, 3, 4, -1, -1, -1 };
|
||||
static const int kCounts[] = { -1, 1, 2, 3, 4, -1, -1, -1, -1 };
|
||||
return kCounts[type];
|
||||
|
||||
GR_STATIC_ASSERT(0 == kVoid_GrSLType);
|
||||
@ -74,6 +75,7 @@ static inline int GrSLTypeVectorCount(GrSLType type) {
|
||||
GR_STATIC_ASSERT(5 == kMat33f_GrSLType);
|
||||
GR_STATIC_ASSERT(6 == kMat44f_GrSLType);
|
||||
GR_STATIC_ASSERT(7 == kSampler2D_GrSLType);
|
||||
GR_STATIC_ASSERT(8 == kSamplerExternal_GrSLType);
|
||||
GR_STATIC_ASSERT(SK_ARRAY_COUNT(kCounts) == kGrSLTypeCount);
|
||||
}
|
||||
|
||||
@ -102,7 +104,8 @@ static inline bool GrSLTypeIsFloatType(GrSLType type) {
|
||||
GR_STATIC_ASSERT(5 == kMat33f_GrSLType);
|
||||
GR_STATIC_ASSERT(6 == kMat44f_GrSLType);
|
||||
GR_STATIC_ASSERT(7 == kSampler2D_GrSLType);
|
||||
GR_STATIC_ASSERT(8 == kGrSLTypeCount);
|
||||
GR_STATIC_ASSERT(8 == kSamplerExternal_GrSLType);
|
||||
GR_STATIC_ASSERT(9 == kGrSLTypeCount);
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -69,6 +69,7 @@ typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDrawArraysProc)(GrGLenum mode, GrGLin
|
||||
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDrawBufferProc)(GrGLenum mode);
|
||||
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDrawBuffersProc)(GrGLsizei n, const GrGLenum* bufs);
|
||||
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLDrawElementsProc)(GrGLenum mode, GrGLsizei count, GrGLenum type, const GrGLvoid* indices);
|
||||
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLEGLImageTargetTexture2DProc)(GrGLenum target, GrGLeglImage image);
|
||||
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLEnableProc)(GrGLenum cap);
|
||||
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLEnableVertexAttribArrayProc)(GrGLuint index);
|
||||
typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLEndQueryProc)(GrGLenum target);
|
||||
@ -352,8 +353,8 @@ typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLObjectLabelProc)(GrGLenum identifier,
|
||||
/** EGL functions */
|
||||
typedef const char* (GR_GL_FUNCTION_TYPE* GrEGLQueryStringProc)(GrEGLDisplay dpy, GrEGLint name);
|
||||
typedef GrEGLDisplay (GR_GL_FUNCTION_TYPE* GrEGLGetCurrentDisplayProc)();
|
||||
typedef GrEGLImageKHR (GR_GL_FUNCTION_TYPE* GrEGLCreateImageProc)(GrEGLDisplay dpy, GrEGLContext ctx, GrEGLenum target, GrEGLClientBuffer buffer, const GrEGLint *attrib_list);
|
||||
typedef GrEGLBoolean (GR_GL_FUNCTION_TYPE* GrEGLDestroyImageProc)(GrEGLDisplay dpy, GrEGLImageKHR image);
|
||||
typedef GrEGLImage (GR_GL_FUNCTION_TYPE* GrEGLCreateImageProc)(GrEGLDisplay dpy, GrEGLContext ctx, GrEGLenum target, GrEGLClientBuffer buffer, const GrEGLint *attrib_list);
|
||||
typedef GrEGLBoolean (GR_GL_FUNCTION_TYPE* GrEGLDestroyImageProc)(GrEGLDisplay dpy, GrEGLImage image);
|
||||
} // extern "C"
|
||||
|
||||
#endif
|
||||
|
@ -498,8 +498,8 @@ public:
|
||||
GLPtr<GrGLObjectLabelProc> fObjectLabel;
|
||||
|
||||
/* EGL functions */
|
||||
GLPtr<GrEGLCreateImageProc> fCreateImage;
|
||||
GLPtr<GrEGLDestroyImageProc> fDestroyImage;
|
||||
GLPtr<GrEGLCreateImageProc> fEGLCreateImage;
|
||||
GLPtr<GrEGLDestroyImageProc> fEGLDestroyImage;
|
||||
} fFunctions;
|
||||
|
||||
// Per-GL func callback
|
||||
|
@ -57,12 +57,12 @@ typedef signed long int GrGLsizeiptr;
|
||||
typedef signed long int GrGLintptr;
|
||||
typedef signed long int GrGLsizeiptr;
|
||||
#endif
|
||||
|
||||
typedef void* GrGLeglImage;
|
||||
/**
|
||||
* EGL types.
|
||||
*/
|
||||
|
||||
typedef void* GrEGLImageKHR;
|
||||
typedef void* GrEGLImage;
|
||||
typedef void* GrEGLDisplay;
|
||||
typedef void* GrEGLContext;
|
||||
typedef void* GrEGLClientBuffer;
|
||||
|
@ -14,8 +14,9 @@
|
||||
/**
|
||||
* Create an offscreen opengl context with an RGBA8 / 8bit stencil FBO.
|
||||
* Provides a GrGLInterface struct of function pointers for the context.
|
||||
* This class is intended for Skia's testing needs and not for general
|
||||
* use.
|
||||
*/
|
||||
|
||||
class SK_API SkGLContext : public SkRefCnt {
|
||||
public:
|
||||
~SkGLContext() override;
|
||||
@ -36,6 +37,16 @@ public:
|
||||
|
||||
void makeCurrent() const;
|
||||
|
||||
/** Used for testing EGLImage integration. Take a GL_TEXTURE_2D and wraps it in an EGL Image */
|
||||
virtual GrEGLImage texture2DToEGLImage(GrGLuint /*texID*/) const { return 0; }
|
||||
virtual void destroyEGLImage(GrEGLImage) const {}
|
||||
|
||||
/**
|
||||
* Used for testing EGLImage integration. Takes a EGLImage and wraps it in a
|
||||
* GL_TEXTURE_EXTERNAL_OES.
|
||||
*/
|
||||
virtual GrGLuint eglImageToExternalTexture(GrEGLImage) const { return 0; }
|
||||
|
||||
/**
|
||||
* The only purpose of this function it to provide a means of scheduling
|
||||
* work on the GPU (since all of the subclasses create primary buffers for
|
||||
@ -59,6 +70,12 @@ public:
|
||||
*/
|
||||
void testAbandon();
|
||||
|
||||
/**
|
||||
* Creates a new GL context of the same type and makes the returned context current
|
||||
* (if not null).
|
||||
*/
|
||||
virtual SkGLContext* createNew() const { return nullptr; }
|
||||
|
||||
class GLFenceSync; // SkGpuFenceSync implementation that uses the OpenGL functionality.
|
||||
|
||||
protected:
|
||||
|
@ -27,6 +27,10 @@ public:
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
GrEGLImage texture2DToEGLImage(GrGLuint texID) const override;
|
||||
void destroyEGLImage(GrEGLImage) const override;
|
||||
GrGLuint eglImageToExternalTexture(GrEGLImage) const override;
|
||||
SkGLContext* createNew() const override;
|
||||
|
||||
// The param is an EGLNativeDisplayType and the return is an EGLDispay.
|
||||
static void* GetD3DEGLDisplay(void* nativeDisplay, bool useGLBackend);
|
||||
@ -42,6 +46,7 @@ private:
|
||||
void* fContext;
|
||||
void* fDisplay;
|
||||
void* fSurface;
|
||||
bool fIsGLBackend;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -202,7 +202,7 @@ GrStencilAttachment* GrResourceProvider::attachStencilAttachment(GrRenderTarget*
|
||||
if (rt->renderTargetPriv().attachStencilAttachment(stencil)) {
|
||||
if (newStencil) {
|
||||
// Right now we're clearing the stencil attachment here after it is
|
||||
// attached to an RT for the first time. When we start matching
|
||||
// attached to a RT for the first time. When we start matching
|
||||
// stencil buffers with smaller color targets this will no longer
|
||||
// be correct because it won't be guaranteed to clear the entire
|
||||
// sb.
|
||||
|
@ -14,7 +14,7 @@
|
||||
#define GET_PROC_SUFFIX(F, S) functions->f ## F = (GrGL ## F ## Proc) get(ctx, "gl" #F #S)
|
||||
#define GET_PROC_LOCAL(F) GrGL ## F ## Proc F = (GrGL ## F ## Proc) get(ctx, "gl" #F)
|
||||
|
||||
#define GET_EGL_PROC_SUFFIX(F, S) functions->f ## F = (GrEGL ## F ## Proc) get(ctx, "egl" #F #S)
|
||||
#define GET_EGL_PROC_SUFFIX(F, S) functions->fEGL ## F = (GrEGL ## F ## Proc) get(ctx, "egl" #F #S)
|
||||
|
||||
const GrGLInterface* GrGLAssembleInterface(void* ctx, GrGLGetProc get) {
|
||||
GET_PROC_LOCAL(GetString);
|
||||
|
@ -46,6 +46,7 @@ GrGLCaps::GrGLCaps(const GrContextOptions& contextOptions,
|
||||
fUseNonVBOVertexAndIndexDynamicData = false;
|
||||
fIsCoreProfile = false;
|
||||
fBindFragDataLocationSupport = false;
|
||||
fExternalTextureSupport = false;
|
||||
fSRGBWriteControl = false;
|
||||
fRGBA8888PixelsOpsAreSlow = false;
|
||||
fPartialFBOReadIsSlow = false;
|
||||
@ -259,6 +260,16 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
|
||||
fBindUniformLocationSupport = false;
|
||||
#endif
|
||||
|
||||
if (ctxInfo.hasExtension("GL_OES_EGL_image_external")) {
|
||||
if (ctxInfo.glslGeneration() == k110_GrGLSLGeneration) {
|
||||
fExternalTextureSupport = true;
|
||||
} else if (ctxInfo.hasExtension("GL_OES_EGL_image_external_essl3") ||
|
||||
ctxInfo.hasExtension("OES_EGL_image_external_essl3")) {
|
||||
// At least one driver has been found that has this extension without the "GL_" prefix.
|
||||
fExternalTextureSupport = true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SK_BUILD_FOR_WIN
|
||||
// We're assuming that on Windows Chromium we're using ANGLE.
|
||||
bool isANGLE = kANGLE_GrGLDriver == ctxInfo.driver() ||
|
||||
@ -588,13 +599,21 @@ void GrGLCaps::initGLSL(const GrGLContextInfo& ctxInfo) {
|
||||
glslCaps->fSecondaryOutputExtensionString = "GL_EXT_blend_func_extended";
|
||||
}
|
||||
|
||||
if (fExternalTextureSupport) {
|
||||
if (ctxInfo.glslGeneration() == k110_GrGLSLGeneration) {
|
||||
glslCaps->fExternalTextureExtensionString = "GL_OES_EGL_image_external";
|
||||
} else {
|
||||
glslCaps->fExternalTextureExtensionString = "GL_OES_EGL_image_external_essl3";
|
||||
}
|
||||
}
|
||||
|
||||
// The Tegra3 compiler will sometimes never return if we have min(abs(x), 1.0), so we must do
|
||||
// the abs first in a separate expression.
|
||||
if (kTegra3_GrGLRenderer == ctxInfo.renderer()) {
|
||||
glslCaps->fCanUseMinAndAbsTogether = false;
|
||||
}
|
||||
|
||||
// On Intel GPU there is an issue where it reads the second arguement to atan "- %s.x" as an int
|
||||
// On Intel GPU there is an issue where it reads the second argument to atan "- %s.x" as an int
|
||||
// thus must us -1.0 * %s.x to work correctly
|
||||
if (kIntel_GrGLVendor == ctxInfo.vendor()) {
|
||||
glslCaps->fMustForceNegatedAtanParamToFloat = true;
|
||||
|
@ -232,6 +232,9 @@ public:
|
||||
|
||||
bool bindUniformLocationSupport() const { return fBindUniformLocationSupport; }
|
||||
|
||||
/// Are textures with GL_TEXTURE_EXTERNAL_OES type supported.
|
||||
bool externalTextureSupport() const { return fExternalTextureSupport; }
|
||||
|
||||
/**
|
||||
* Is there support for enabling/disabling sRGB writes for sRGB-capable color attachments?
|
||||
* If false this does not mean sRGB is not supported but rather that if it is supported
|
||||
@ -360,6 +363,7 @@ private:
|
||||
bool fRGBA8888PixelsOpsAreSlow : 1;
|
||||
bool fPartialFBOReadIsSlow : 1;
|
||||
bool fBindUniformLocationSupport : 1;
|
||||
bool fExternalTextureSupport : 1;
|
||||
|
||||
struct ReadPixelsSupportedFormat {
|
||||
GrGLenum fFormat;
|
||||
|
@ -928,8 +928,18 @@
|
||||
#define GR_GL_PROGRAM_PIPELINE 0x82E4
|
||||
#define GR_GL_SAMPLER 0x82E6
|
||||
|
||||
/* GL_OES_EGL_image_external */
|
||||
#define GR_GL_TEXTURE_EXTERNAL 0x8D65
|
||||
|
||||
/* EGL Defines */
|
||||
#define GR_EGL_NO_DISPLAY ((GrEGLDisplay)0)
|
||||
#define GR_EGL_EXTENSIONS 0x3055
|
||||
#define GR_EGL_GL_TEXTURE_2D 0x30B1
|
||||
#define GR_EGL_GL_TEXTURE_LEVEL 0x30BC
|
||||
#define GR_EGL_IMAGE_PRESERVED 0x30D2
|
||||
#define GR_EGL_FALSE 0x0
|
||||
#define GR_EGL_TRUE 0x1
|
||||
#define GR_EGL_NONE 0x3038
|
||||
#define GR_EGL_NO_IMAGE ((GrEGLImage)0)
|
||||
|
||||
#endif
|
||||
|
@ -233,7 +233,7 @@ GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context)
|
||||
fPathRendering.reset(new GrGLPathRendering(this));
|
||||
}
|
||||
|
||||
this->createCopyProgram();
|
||||
this->createCopyPrograms();
|
||||
}
|
||||
|
||||
GrGLGpu::~GrGLGpu() {
|
||||
@ -253,12 +253,13 @@ GrGLGpu::~GrGLGpu() {
|
||||
GL_CALL(DeleteFramebuffers(1, &fStencilClearFBOID));
|
||||
}
|
||||
|
||||
if (0 != fCopyProgram.fArrayBuffer) {
|
||||
GL_CALL(DeleteBuffers(1, &fCopyProgram.fArrayBuffer));
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(fCopyPrograms); ++i) {
|
||||
if (0 != fCopyPrograms[i].fProgram) {
|
||||
GL_CALL(DeleteProgram(fCopyPrograms[i].fProgram));
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != fCopyProgram.fProgram) {
|
||||
GL_CALL(DeleteProgram(fCopyProgram.fProgram));
|
||||
if (0 != fCopyProgramArrayBuffer) {
|
||||
GL_CALL(DeleteBuffers(1, &fCopyProgramArrayBuffer));
|
||||
}
|
||||
|
||||
delete fProgramCache;
|
||||
@ -271,8 +272,10 @@ void GrGLGpu::contextAbandoned() {
|
||||
fTempSrcFBOID = 0;
|
||||
fTempDstFBOID = 0;
|
||||
fStencilClearFBOID = 0;
|
||||
fCopyProgram.fArrayBuffer = 0;
|
||||
fCopyProgram.fProgram = 0;
|
||||
fCopyProgramArrayBuffer = 0;
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(fCopyPrograms); ++i) {
|
||||
fCopyPrograms[i].fProgram = 0;
|
||||
}
|
||||
if (this->glCaps().shaderCaps()->pathRenderingSupport()) {
|
||||
this->glPathRendering()->abandonGpuResources();
|
||||
}
|
||||
@ -429,6 +432,9 @@ GrTexture* GrGLGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// next line relies on GrBackendTextureDesc's flags matching GrTexture's
|
||||
bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrBackendTextureFlag);
|
||||
|
||||
GrGLTexture::IDDesc idDesc;
|
||||
GrSurfaceDesc surfDesc;
|
||||
|
||||
@ -439,6 +445,15 @@ GrTexture* GrGLGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc,
|
||||
#else
|
||||
idDesc.fInfo = *info;
|
||||
#endif
|
||||
if (GR_GL_TEXTURE_EXTERNAL == idDesc.fInfo.fTarget) {
|
||||
if (renderTarget) {
|
||||
// This combination is not supported.
|
||||
return nullptr;
|
||||
}
|
||||
if (!this->glCaps().externalTextureSupport()) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
switch (ownership) {
|
||||
case kAdopt_GrWrapOwnership:
|
||||
@ -449,13 +464,11 @@ GrTexture* GrGLGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc,
|
||||
break;
|
||||
}
|
||||
|
||||
// next line relies on GrBackendTextureDesc's flags matching GrTexture's
|
||||
surfDesc.fFlags = (GrSurfaceFlags) desc.fFlags;
|
||||
surfDesc.fWidth = desc.fWidth;
|
||||
surfDesc.fHeight = desc.fHeight;
|
||||
surfDesc.fConfig = desc.fConfig;
|
||||
surfDesc.fSampleCnt = SkTMin(desc.fSampleCnt, this->caps()->maxSampleCount());
|
||||
bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrBackendTextureFlag);
|
||||
// FIXME: this should be calling resolve_origin(), but Chrome code is currently
|
||||
// assuming the old behaviour, which is that backend textures are always
|
||||
// BottomLeft, even for non-RT's. Once Chrome is fixed, change this to:
|
||||
@ -524,6 +537,12 @@ bool GrGLGpu::onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height,
|
||||
// into it. We could use glDrawPixels on GLs that have it, but we don't today.
|
||||
if (!dstSurface->asTexture()) {
|
||||
ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
|
||||
} else {
|
||||
GrGLTexture* texture = static_cast<GrGLTexture*>(dstSurface->asTexture());
|
||||
if (GR_GL_TEXTURE_2D != texture->target()) {
|
||||
// We don't currently support writing pixels to non-TEXTURE_2D textures.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (GrPixelConfigIsSRGB(dstSurface->config()) != GrPixelConfigIsSRGB(srcConfig)) {
|
||||
@ -585,6 +604,11 @@ bool GrGLGpu::onWritePixels(GrSurface* surface,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write pixels is only implemented for TEXTURE_2D textures
|
||||
if (GR_GL_TEXTURE_2D != glTex->target()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this->setScratchTextureUnit();
|
||||
GL_CALL(BindTexture(glTex->target(), glTex->textureID()));
|
||||
|
||||
@ -2752,11 +2776,10 @@ void GrGLGpu::setScratchTextureUnit() {
|
||||
fHWBoundTextureUniqueIDs[lastUnitIdx] = SK_InvalidUniqueID;
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Determines whether glBlitFramebuffer could be used between src and dst.
|
||||
inline bool can_blit_framebuffer(const GrSurface* dst,
|
||||
const GrSurface* src,
|
||||
const GrGLGpu* gpu) {
|
||||
static inline bool can_blit_framebuffer(const GrSurface* dst,
|
||||
const GrSurface* src,
|
||||
const GrGLGpu* gpu) {
|
||||
if (gpu->glCaps().isConfigRenderable(dst->config(), dst->desc().fSampleCnt > 0) &&
|
||||
gpu->glCaps().isConfigRenderable(src->config(), src->desc().fSampleCnt > 0) &&
|
||||
gpu->glCaps().usesMSAARenderBuffers()) {
|
||||
@ -2766,15 +2789,23 @@ inline bool can_blit_framebuffer(const GrSurface* dst,
|
||||
(src->desc().fSampleCnt > 0 || src->config() != dst->config())) {
|
||||
return false;
|
||||
}
|
||||
const GrGLTexture* dstTex = static_cast<const GrGLTexture*>(dst->asTexture());
|
||||
if (dstTex && dstTex->target() != GR_GL_TEXTURE_2D) {
|
||||
return false;
|
||||
}
|
||||
const GrGLTexture* srcTex = static_cast<const GrGLTexture*>(dst->asTexture());
|
||||
if (srcTex && srcTex->target() != GR_GL_TEXTURE_2D) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool can_copy_texsubimage(const GrSurface* dst,
|
||||
const GrSurface* src,
|
||||
const GrGLGpu* gpu) {
|
||||
static inline bool can_copy_texsubimage(const GrSurface* dst,
|
||||
const GrSurface* src,
|
||||
const GrGLGpu* gpu) {
|
||||
// Table 3.9 of the ES2 spec indicates the supported formats with CopyTexSubImage
|
||||
// and BGRA isn't in the spec. There doesn't appear to be any extension that adds it. Perhaps
|
||||
// many drivers would allow it to work, but ANGLE does not.
|
||||
@ -2794,18 +2825,29 @@ inline bool can_copy_texsubimage(const GrSurface* dst,
|
||||
if (srcRT && srcRT->renderFBOID() != srcRT->textureFBOID()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const GrGLTexture* dstTex = static_cast<const GrGLTexture*>(dst->asTexture());
|
||||
// CopyTex(Sub)Image writes to a texture and we have no way of dynamically wrapping a RT in a
|
||||
// texture.
|
||||
if (!dstTex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const GrGLTexture* srcTex = static_cast<const GrGLTexture*>(src->asTexture());
|
||||
|
||||
// Check that we could wrap the source in an FBO, that the dst is TEXTURE_2D, that no mirroring
|
||||
// is required.
|
||||
if (gpu->glCaps().isConfigRenderable(src->config(), src->desc().fSampleCnt > 0) &&
|
||||
dst->asTexture() &&
|
||||
dst->origin() == src->origin() &&
|
||||
!GrPixelConfigIsCompressed(src->config())) {
|
||||
!GrPixelConfigIsCompressed(src->config()) &&
|
||||
(!srcTex || srcTex->target() == GR_GL_TEXTURE_2D) &&
|
||||
dstTex->target() == GR_GL_TEXTURE_2D &&
|
||||
dst->origin() == src->origin()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// If a temporary FBO was created, its non-zero ID is returned. The viewport that the copy rect is
|
||||
// relative to is output.
|
||||
void GrGLGpu::bindSurfaceFBOForCopy(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport,
|
||||
@ -2863,6 +2905,12 @@ bool GrGLGpu::initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc)
|
||||
return true;
|
||||
}
|
||||
|
||||
const GrGLTexture* srcTexture = static_cast<const GrGLTexture*>(src->asTexture());
|
||||
if (srcTexture && srcTexture->target() != GR_GL_TEXTURE_2D) {
|
||||
// Not supported for FBO blit or CopyTexSubImage
|
||||
return false;
|
||||
}
|
||||
|
||||
// We look for opportunities to use CopyTexSubImage, or fbo blit. If neither are
|
||||
// possible and we return false to fallback to creating a render target dst for render-to-
|
||||
// texture. This code prefers CopyTexSubImage to fbo blit and avoids triggering temporary fbo
|
||||
@ -2927,92 +2975,109 @@ bool GrGLGpu::onCopySurface(GrSurface* dst,
|
||||
}
|
||||
|
||||
|
||||
void GrGLGpu::createCopyProgram() {
|
||||
const char* version = this->glCaps().glslCaps()->versionDeclString();
|
||||
|
||||
GrGLSLShaderVar aVertex("a_vertex", kVec2f_GrSLType, GrShaderVar::kAttribute_TypeModifier);
|
||||
GrGLSLShaderVar uTexCoordXform("u_texCoordXform", kVec4f_GrSLType,
|
||||
GrShaderVar::kUniform_TypeModifier);
|
||||
GrGLSLShaderVar uPosXform("u_posXform", kVec4f_GrSLType, GrShaderVar::kUniform_TypeModifier);
|
||||
GrGLSLShaderVar uTexture("u_texture", kSampler2D_GrSLType, GrShaderVar::kUniform_TypeModifier);
|
||||
GrGLSLShaderVar vTexCoord("v_texCoord", kVec2f_GrSLType, GrShaderVar::kVaryingOut_TypeModifier);
|
||||
GrGLSLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_TypeModifier);
|
||||
|
||||
SkString vshaderTxt(version);
|
||||
aVertex.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
|
||||
vshaderTxt.append(";");
|
||||
uTexCoordXform.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
|
||||
vshaderTxt.append(";");
|
||||
uPosXform.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
|
||||
vshaderTxt.append(";");
|
||||
vTexCoord.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
|
||||
vshaderTxt.append(";");
|
||||
|
||||
vshaderTxt.append(
|
||||
"// Copy Program VS\n"
|
||||
"void main() {"
|
||||
" v_texCoord = a_vertex.xy * u_texCoordXform.xy + u_texCoordXform.zw;"
|
||||
" gl_Position.xy = a_vertex * u_posXform.xy + u_posXform.zw;"
|
||||
" gl_Position.zw = vec2(0, 1);"
|
||||
"}"
|
||||
);
|
||||
|
||||
SkString fshaderTxt(version);
|
||||
GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision,
|
||||
*this->glCaps().glslCaps(),
|
||||
&fshaderTxt);
|
||||
vTexCoord.setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier);
|
||||
vTexCoord.appendDecl(this->glCaps().glslCaps(), &fshaderTxt);
|
||||
fshaderTxt.append(";");
|
||||
uTexture.appendDecl(this->glCaps().glslCaps(), &fshaderTxt);
|
||||
fshaderTxt.append(";");
|
||||
const char* fsOutName;
|
||||
if (this->glCaps().glslCaps()->mustDeclareFragmentShaderOutput()) {
|
||||
oFragColor.appendDecl(this->glCaps().glslCaps(), &fshaderTxt);
|
||||
fshaderTxt.append(";");
|
||||
fsOutName = oFragColor.c_str();
|
||||
} else {
|
||||
fsOutName = "gl_FragColor";
|
||||
void GrGLGpu::createCopyPrograms() {
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(fCopyPrograms); ++i) {
|
||||
fCopyPrograms[i].fProgram = 0;
|
||||
}
|
||||
fshaderTxt.appendf(
|
||||
"// Copy Program FS\n"
|
||||
"void main() {"
|
||||
" %s = %s(u_texture, v_texCoord);"
|
||||
"}",
|
||||
fsOutName,
|
||||
GrGLSLTexture2DFunctionName(kVec2f_GrSLType, this->glslGeneration())
|
||||
);
|
||||
const char* version = this->glCaps().glslCaps()->versionDeclString();
|
||||
static const GrSLType kSamplerTypes[2] = { kSampler2D_GrSLType, kSamplerExternal_GrSLType };
|
||||
SkASSERT(2 == SK_ARRAY_COUNT(fCopyPrograms));
|
||||
int programCount = this->glCaps().externalTextureSupport() ? 2 : 1;
|
||||
for (int i = 0; i < programCount; ++i) {
|
||||
GrGLSLShaderVar aVertex("a_vertex", kVec2f_GrSLType, GrShaderVar::kAttribute_TypeModifier);
|
||||
GrGLSLShaderVar uTexCoordXform("u_texCoordXform", kVec4f_GrSLType,
|
||||
GrShaderVar::kUniform_TypeModifier);
|
||||
GrGLSLShaderVar uPosXform("u_posXform", kVec4f_GrSLType,
|
||||
GrShaderVar::kUniform_TypeModifier);
|
||||
GrGLSLShaderVar uTexture("u_texture", kSamplerTypes[i],
|
||||
GrShaderVar::kUniform_TypeModifier);
|
||||
GrGLSLShaderVar vTexCoord("v_texCoord", kVec2f_GrSLType,
|
||||
GrShaderVar::kVaryingOut_TypeModifier);
|
||||
GrGLSLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType,
|
||||
GrShaderVar::kOut_TypeModifier);
|
||||
|
||||
GL_CALL_RET(fCopyProgram.fProgram, CreateProgram());
|
||||
const char* str;
|
||||
GrGLint length;
|
||||
SkString vshaderTxt(version);
|
||||
aVertex.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
|
||||
vshaderTxt.append(";");
|
||||
uTexCoordXform.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
|
||||
vshaderTxt.append(";");
|
||||
uPosXform.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
|
||||
vshaderTxt.append(";");
|
||||
vTexCoord.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
|
||||
vshaderTxt.append(";");
|
||||
|
||||
vshaderTxt.append(
|
||||
"// Copy Program VS\n"
|
||||
"void main() {"
|
||||
" v_texCoord = a_vertex.xy * u_texCoordXform.xy + u_texCoordXform.zw;"
|
||||
" gl_Position.xy = a_vertex * u_posXform.xy + u_posXform.zw;"
|
||||
" gl_Position.zw = vec2(0, 1);"
|
||||
"}"
|
||||
);
|
||||
|
||||
str = vshaderTxt.c_str();
|
||||
length = SkToInt(vshaderTxt.size());
|
||||
GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fCopyProgram.fProgram,
|
||||
GR_GL_VERTEX_SHADER, &str, &length, 1, &fStats);
|
||||
SkString fshaderTxt(version);
|
||||
if (kSamplerTypes[i] == kSamplerExternal_GrSLType) {
|
||||
fshaderTxt.appendf("#extension %s : require\n",
|
||||
this->glCaps().glslCaps()->externalTextureExtensionString());
|
||||
}
|
||||
GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision,
|
||||
*this->glCaps().glslCaps(),
|
||||
&fshaderTxt);
|
||||
vTexCoord.setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier);
|
||||
vTexCoord.appendDecl(this->glCaps().glslCaps(), &fshaderTxt);
|
||||
fshaderTxt.append(";");
|
||||
uTexture.appendDecl(this->glCaps().glslCaps(), &fshaderTxt);
|
||||
fshaderTxt.append(";");
|
||||
const char* fsOutName;
|
||||
if (this->glCaps().glslCaps()->mustDeclareFragmentShaderOutput()) {
|
||||
oFragColor.appendDecl(this->glCaps().glslCaps(), &fshaderTxt);
|
||||
fshaderTxt.append(";");
|
||||
fsOutName = oFragColor.c_str();
|
||||
} else {
|
||||
fsOutName = "gl_FragColor";
|
||||
}
|
||||
fshaderTxt.appendf(
|
||||
"// Copy Program FS\n"
|
||||
"void main() {"
|
||||
" %s = %s(u_texture, v_texCoord);"
|
||||
"}",
|
||||
fsOutName,
|
||||
GrGLSLTexture2DFunctionName(kVec2f_GrSLType, this->glslGeneration())
|
||||
);
|
||||
|
||||
GL_CALL_RET(fCopyPrograms[i].fProgram, CreateProgram());
|
||||
const char* str;
|
||||
GrGLint length;
|
||||
|
||||
str = fshaderTxt.c_str();
|
||||
length = SkToInt(fshaderTxt.size());
|
||||
GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fCopyProgram.fProgram,
|
||||
GR_GL_FRAGMENT_SHADER, &str, &length, 1, &fStats);
|
||||
str = vshaderTxt.c_str();
|
||||
length = SkToInt(vshaderTxt.size());
|
||||
GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fCopyPrograms[i].fProgram,
|
||||
GR_GL_VERTEX_SHADER, &str, &length, 1,
|
||||
&fStats);
|
||||
|
||||
GL_CALL(LinkProgram(fCopyProgram.fProgram));
|
||||
str = fshaderTxt.c_str();
|
||||
length = SkToInt(fshaderTxt.size());
|
||||
GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fCopyPrograms[i].fProgram,
|
||||
GR_GL_FRAGMENT_SHADER, &str, &length, 1,
|
||||
&fStats);
|
||||
|
||||
GL_CALL_RET(fCopyProgram.fTextureUniform, GetUniformLocation(fCopyProgram.fProgram,
|
||||
"u_texture"));
|
||||
GL_CALL_RET(fCopyProgram.fPosXformUniform, GetUniformLocation(fCopyProgram.fProgram,
|
||||
"u_posXform"));
|
||||
GL_CALL_RET(fCopyProgram.fTexCoordXformUniform, GetUniformLocation(fCopyProgram.fProgram,
|
||||
"u_texCoordXform"));
|
||||
GL_CALL(LinkProgram(fCopyPrograms[i].fProgram));
|
||||
|
||||
GL_CALL(BindAttribLocation(fCopyProgram.fProgram, 0, "a_vertex"));
|
||||
GL_CALL_RET(fCopyPrograms[i].fTextureUniform,
|
||||
GetUniformLocation(fCopyPrograms[i].fProgram, "u_texture"));
|
||||
GL_CALL_RET(fCopyPrograms[i].fPosXformUniform,
|
||||
GetUniformLocation(fCopyPrograms[i].fProgram, "u_posXform"));
|
||||
GL_CALL_RET(fCopyPrograms[i].fTexCoordXformUniform,
|
||||
GetUniformLocation(fCopyPrograms[i].fProgram, "u_texCoordXform"));
|
||||
|
||||
GL_CALL(DeleteShader(vshader));
|
||||
GL_CALL(DeleteShader(fshader));
|
||||
GL_CALL(BindAttribLocation(fCopyPrograms[i].fProgram, 0, "a_vertex"));
|
||||
|
||||
GL_CALL(GenBuffers(1, &fCopyProgram.fArrayBuffer));
|
||||
fHWGeometryState.setVertexBufferID(this, fCopyProgram.fArrayBuffer);
|
||||
GL_CALL(DeleteShader(vshader));
|
||||
GL_CALL(DeleteShader(fshader));
|
||||
}
|
||||
|
||||
GL_CALL(GenBuffers(1, &fCopyProgramArrayBuffer));
|
||||
fHWGeometryState.setVertexBufferID(this, fCopyProgramArrayBuffer);
|
||||
static const GrGLfloat vdata[] = {
|
||||
0, 0,
|
||||
0, 1,
|
||||
@ -3041,14 +3106,16 @@ void GrGLGpu::copySurfaceAsDraw(GrSurface* dst,
|
||||
SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, w, h);
|
||||
this->flushRenderTarget(dstRT, &dstRect);
|
||||
|
||||
GL_CALL(UseProgram(fCopyProgram.fProgram));
|
||||
fHWProgramID = fCopyProgram.fProgram;
|
||||
int progIdx = TextureTargetToCopyProgramIdx(srcTex->target());
|
||||
|
||||
GL_CALL(UseProgram(fCopyPrograms[progIdx].fProgram));
|
||||
fHWProgramID = fCopyPrograms[progIdx].fProgram;
|
||||
|
||||
fHWGeometryState.setVertexArrayID(this, 0);
|
||||
|
||||
GrGLAttribArrayState* attribs =
|
||||
fHWGeometryState.bindArrayAndBufferToDraw(this, fCopyProgram.fArrayBuffer);
|
||||
attribs->set(this, 0, fCopyProgram.fArrayBuffer, 2, GR_GL_FLOAT, false,
|
||||
fHWGeometryState.bindArrayAndBufferToDraw(this, fCopyProgramArrayBuffer);
|
||||
attribs->set(this, 0, fCopyProgramArrayBuffer, 2, GR_GL_FLOAT, false,
|
||||
2 * sizeof(GrGLfloat), 0);
|
||||
attribs->disableUnusedArrays(this, 0x1);
|
||||
|
||||
@ -3076,9 +3143,10 @@ void GrGLGpu::copySurfaceAsDraw(GrSurface* dst,
|
||||
sy1 = 1.f - sy1;
|
||||
}
|
||||
|
||||
GL_CALL(Uniform4f(fCopyProgram.fPosXformUniform, dx1 - dx0, dy1 - dy0, dx0, dy0));
|
||||
GL_CALL(Uniform4f(fCopyProgram.fTexCoordXformUniform, sx1 - sx0, sy1 - sy0, sx0, sy0));
|
||||
GL_CALL(Uniform1i(fCopyProgram.fTextureUniform, 0));
|
||||
GL_CALL(Uniform4f(fCopyPrograms[progIdx].fPosXformUniform, dx1 - dx0, dy1 - dy0, dx0, dy0));
|
||||
GL_CALL(Uniform4f(fCopyPrograms[progIdx].fTexCoordXformUniform,
|
||||
sx1 - sx0, sy1 - sy0, sx0, sy0));
|
||||
GL_CALL(Uniform1i(fCopyPrograms[progIdx].fTextureUniform, 0));
|
||||
|
||||
GrXferProcessor::BlendInfo blendInfo;
|
||||
blendInfo.reset();
|
||||
|
@ -322,7 +322,7 @@ private:
|
||||
|
||||
SkAutoTUnref<GrGLContext> fGLContext;
|
||||
|
||||
void createCopyProgram();
|
||||
void createCopyPrograms();
|
||||
|
||||
// GL program-related state
|
||||
ProgramCache* fProgramCache;
|
||||
@ -497,8 +497,17 @@ private:
|
||||
GrGLint fTextureUniform;
|
||||
GrGLint fTexCoordXformUniform;
|
||||
GrGLint fPosXformUniform;
|
||||
GrGLuint fArrayBuffer;
|
||||
} fCopyProgram;
|
||||
} fCopyPrograms[2];
|
||||
GrGLuint fCopyProgramArrayBuffer;
|
||||
|
||||
static int TextureTargetToCopyProgramIdx(GrGLenum target) {
|
||||
if (target == GR_GL_TEXTURE_2D) {
|
||||
return 0;
|
||||
} else {
|
||||
SkASSERT(target == GR_GL_TEXTURE_EXTERNAL);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
TriState fMSAAEnabled;
|
||||
|
||||
|
@ -727,8 +727,8 @@ bool GrGLInterface::validate() const {
|
||||
}
|
||||
|
||||
if (fExtensions.has("EGL_KHR_image") || fExtensions.has("EGL_KHR_image_base")) {
|
||||
if (nullptr == fFunctions.fCreateImage ||
|
||||
nullptr == fFunctions.fDestroyImage) {
|
||||
if (nullptr == fFunctions.fEGLCreateImage ||
|
||||
nullptr == fFunctions.fEGLDestroyImage) {
|
||||
RETURN_FALSE_INTERFACE
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ GrGLProgramDataManager::GrGLProgramDataManager(GrGLGpu* gpu, GrGLuint programID,
|
||||
|
||||
void GrGLProgramDataManager::setSampler(UniformHandle u, int texUnit) const {
|
||||
const Uniform& uni = fUniforms[u.toIndex()];
|
||||
SkASSERT(uni.fType == kSampler2D_GrSLType);
|
||||
SkASSERT(uni.fType == kSampler2D_GrSLType || uni.fType == kSamplerExternal_GrSLType);
|
||||
SkASSERT(GrGLSLShaderVar::kNonArray == uni.fArrayCount);
|
||||
// FIXME: We still insert a single sampler uniform for every stage. If the shader does not
|
||||
// reference the sampler then the compiler may have optimized it out. Uncomment this assert
|
||||
|
@ -31,11 +31,16 @@ static bool swizzle_requires_alpha_remapping(const GrGLSLCaps& caps, GrPixelConf
|
||||
static uint32_t gen_texture_key(const GrProcessor& proc, const GrGLCaps& caps) {
|
||||
uint32_t key = 0;
|
||||
int numTextures = proc.numTextures();
|
||||
int shift = 0;
|
||||
for (int t = 0; t < numTextures; ++t) {
|
||||
const GrTextureAccess& access = proc.textureAccess(t);
|
||||
if (swizzle_requires_alpha_remapping(*caps.glslCaps(), access.getTexture()->config())) {
|
||||
key |= 1 << t;
|
||||
key |= 1 << shift;
|
||||
}
|
||||
if (GR_GL_TEXTURE_EXTERNAL == static_cast<GrGLTexture*>(access.getTexture())->target()) {
|
||||
key |= 2 << shift;
|
||||
}
|
||||
shift += 2;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
@ -48,10 +53,8 @@ static uint32_t gen_texture_key(const GrProcessor& proc, const GrGLCaps& caps) {
|
||||
* which must be different for every GrProcessor subclass. It can fail if an effect uses too many
|
||||
* textures, transforms, etc, for the space allotted in the meta-key. NOTE, both FPs and GPs share
|
||||
* this function because it is hairy, though FPs do not have attribs, and GPs do not have transforms
|
||||
*
|
||||
* TODO: A better name for this function would be "compute" instead of "get".
|
||||
*/
|
||||
static bool get_meta_key(const GrProcessor& proc,
|
||||
static bool gen_meta_key(const GrProcessor& proc,
|
||||
const GrGLCaps& caps,
|
||||
uint32_t transformKey,
|
||||
GrProcessorKeyBuilder* b) {
|
||||
@ -75,15 +78,12 @@ static bool get_meta_key(const GrProcessor& proc,
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: A better name for this function would be "compute" instead of "get".
|
||||
*/
|
||||
static bool get_frag_proc_and_meta_keys(const GrPrimitiveProcessor& primProc,
|
||||
static bool gen_frag_proc_and_meta_keys(const GrPrimitiveProcessor& primProc,
|
||||
const GrFragmentProcessor& fp,
|
||||
const GrGLCaps& caps,
|
||||
GrProcessorKeyBuilder* b) {
|
||||
for (int i = 0; i < fp.numChildProcessors(); ++i) {
|
||||
if (!get_frag_proc_and_meta_keys(primProc, fp.childProcessor(i), caps, b)) {
|
||||
if (!gen_frag_proc_and_meta_keys(primProc, fp.childProcessor(i), caps, b)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -91,7 +91,7 @@ static bool get_frag_proc_and_meta_keys(const GrPrimitiveProcessor& primProc,
|
||||
fp.getGLSLProcessorKey(*caps.glslCaps(), b);
|
||||
|
||||
//**** use glslCaps here?
|
||||
return get_meta_key(fp, caps, primProc.getTransformKey(fp.coordTransforms(),
|
||||
return gen_meta_key(fp, caps, primProc.getTransformKey(fp.coordTransforms(),
|
||||
fp.numTransformsExclChildren()), b);
|
||||
}
|
||||
|
||||
@ -115,14 +115,14 @@ bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc,
|
||||
|
||||
primProc.getGLSLProcessorKey(*gpu->glCaps().glslCaps(), &b);
|
||||
//**** use glslCaps here?
|
||||
if (!get_meta_key(primProc, gpu->glCaps(), 0, &b)) {
|
||||
if (!gen_meta_key(primProc, gpu->glCaps(), 0, &b)) {
|
||||
glDesc->key().reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
|
||||
const GrFragmentProcessor& fp = pipeline.getFragmentProcessor(i);
|
||||
if (!get_frag_proc_and_meta_keys(primProc, fp, gpu->glCaps(), &b)) {
|
||||
if (!gen_frag_proc_and_meta_keys(primProc, fp, gpu->glCaps(), &b)) {
|
||||
glDesc->key().reset();
|
||||
return false;
|
||||
}
|
||||
@ -131,7 +131,7 @@ bool GrGLProgramDescBuilder::Build(GrProgramDesc* desc,
|
||||
const GrXferProcessor& xp = *pipeline.getXferProcessor();
|
||||
xp.getGLSLProcessorKey(*gpu->glCaps().glslCaps(), &b);
|
||||
//**** use glslCaps here?
|
||||
if (!get_meta_key(xp, gpu->glCaps(), 0, &b)) {
|
||||
if (!gen_meta_key(xp, gpu->glCaps(), 0, &b)) {
|
||||
glDesc->key().reset();
|
||||
return false;
|
||||
}
|
||||
|
@ -12,8 +12,20 @@
|
||||
|
||||
#include <EGL/egl.h>
|
||||
|
||||
namespace {
|
||||
struct Libs {
|
||||
void* fGLLib;
|
||||
void* fEGLLib;
|
||||
};
|
||||
}
|
||||
|
||||
static GrGLFuncPtr angle_get_gl_proc(void* ctx, const char name[]) {
|
||||
GrGLFuncPtr proc = (GrGLFuncPtr) GetProcedureAddress(ctx, name);
|
||||
const Libs* libs = reinterpret_cast<const Libs*>(ctx);
|
||||
GrGLFuncPtr proc = (GrGLFuncPtr) GetProcedureAddress(libs->fGLLib, name);
|
||||
if (proc) {
|
||||
return proc;
|
||||
}
|
||||
proc = (GrGLFuncPtr) GetProcedureAddress(libs->fEGLLib, name);
|
||||
if (proc) {
|
||||
return proc;
|
||||
}
|
||||
@ -21,23 +33,26 @@ static GrGLFuncPtr angle_get_gl_proc(void* ctx, const char name[]) {
|
||||
}
|
||||
|
||||
const GrGLInterface* GrGLCreateANGLEInterface() {
|
||||
static void* gANGLELib = nullptr;
|
||||
static Libs gLibs = { nullptr, nullptr };
|
||||
|
||||
if (nullptr == gANGLELib) {
|
||||
if (nullptr == gLibs.fGLLib) {
|
||||
// We load the ANGLE library and never let it go
|
||||
#if defined _WIN32
|
||||
gANGLELib = DynamicLoadLibrary("libGLESv2.dll");
|
||||
gLibs.fGLLib = DynamicLoadLibrary("libGLESv2.dll");
|
||||
gLibs.fEGLLib = DynamicLoadLibrary("libEGL.dll");
|
||||
#elif defined SK_BUILD_FOR_MAC
|
||||
gANGLELib = DynamicLoadLibrary("libGLESv2.dylib");
|
||||
gLibs.fGLLib = DynamicLoadLibrary("libGLESv2.dylib");
|
||||
gLibs.fEGLLib = DynamicLoadLibrary("libEGL.dylib");
|
||||
#else
|
||||
gANGLELib = DynamicLoadLibrary("libGLESv2.so");
|
||||
#endif // defined _WIN32
|
||||
gLibs.fGLLib = DynamicLoadLibrary("libGLESv2.so");
|
||||
gLibs.fGLLib = DynamicLoadLibrary("libEGL.so");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (nullptr == gANGLELib) {
|
||||
if (nullptr == gLibs.fGLLib || nullptr == gLibs.fEGLLib) {
|
||||
// We can't setup the interface correctly w/o the so
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return GrGLAssembleGLESInterface(gANGLELib, angle_get_gl_proc);
|
||||
return GrGLAssembleGLESInterface(&gLibs, angle_get_gl_proc);
|
||||
}
|
||||
|
@ -11,6 +11,9 @@
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
#include "gl/GrGLDefines.h"
|
||||
#include "gl/GrGLUtil.h"
|
||||
|
||||
#define EGL_PLATFORM_ANGLE_ANGLE 0x3202
|
||||
#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203
|
||||
#define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3207
|
||||
@ -34,8 +37,7 @@ void* SkANGLEGLContext::GetD3DEGLDisplay(void* nativeDisplay, bool useGLBackend)
|
||||
EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE,
|
||||
EGL_NONE
|
||||
};
|
||||
display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
|
||||
nativeDisplay, attribs);
|
||||
display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, nativeDisplay, attribs);
|
||||
} else {
|
||||
// Try for an ANGLE D3D11 context, fall back to D3D9, and finally GL.
|
||||
EGLint attribs[3][3] = {
|
||||
@ -56,8 +58,7 @@ void* SkANGLEGLContext::GetD3DEGLDisplay(void* nativeDisplay, bool useGLBackend)
|
||||
}
|
||||
};
|
||||
for (int i = 0; i < 3 && display == EGL_NO_DISPLAY; ++i) {
|
||||
display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,
|
||||
nativeDisplay, attribs[i]);
|
||||
display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,nativeDisplay, attribs[i]);
|
||||
}
|
||||
}
|
||||
return display;
|
||||
@ -79,6 +80,7 @@ SkANGLEGLContext::SkANGLEGLContext(bool useGLBackend)
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
fIsGLBackend = useGLBackend;
|
||||
fDisplay = GetD3DEGLDisplay(EGL_DEFAULT_DISPLAY, useGLBackend);
|
||||
if (EGL_NO_DISPLAY == fDisplay) {
|
||||
SkDebugf("Could not create EGL display!");
|
||||
@ -129,6 +131,62 @@ SkANGLEGLContext::~SkANGLEGLContext() {
|
||||
this->destroyGLContext();
|
||||
}
|
||||
|
||||
GrEGLImage SkANGLEGLContext::texture2DToEGLImage(GrGLuint texID) const {
|
||||
if (!this->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) {
|
||||
return GR_EGL_NO_IMAGE;
|
||||
}
|
||||
GrEGLImage img;
|
||||
GrEGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0,
|
||||
GR_EGL_IMAGE_PRESERVED, GR_EGL_TRUE,
|
||||
GR_EGL_NONE };
|
||||
// 64 bit cast is to shut Visual C++ up about casting 32 bit value to a pointer.
|
||||
GrEGLClientBuffer clientBuffer = reinterpret_cast<GrEGLClientBuffer>((uint64_t)texID);
|
||||
GR_GL_CALL_RET(this->gl(), img,
|
||||
EGLCreateImage(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clientBuffer,
|
||||
attribs));
|
||||
return img;
|
||||
}
|
||||
|
||||
void SkANGLEGLContext::destroyEGLImage(GrEGLImage image) const {
|
||||
GR_GL_CALL(this->gl(), EGLDestroyImage(fDisplay, image));
|
||||
}
|
||||
|
||||
GrGLuint SkANGLEGLContext::eglImageToExternalTexture(GrEGLImage image) const {
|
||||
GrGLClearErr(this->gl());
|
||||
if (!this->gl()->hasExtension("GL_OES_EGL_image_external")) {
|
||||
return 0;
|
||||
}
|
||||
GrGLEGLImageTargetTexture2DProc glEGLImageTargetTexture2D =
|
||||
(GrGLEGLImageTargetTexture2DProc)eglGetProcAddress("glEGLImageTargetTexture2DOES");
|
||||
if (!glEGLImageTargetTexture2D) {
|
||||
return 0;
|
||||
}
|
||||
GrGLuint texID;
|
||||
GR_GL_CALL(this->gl(), GenTextures(1, &texID));
|
||||
if (!texID) {
|
||||
return 0;
|
||||
}
|
||||
GR_GL_CALL(this->gl(), BindTexture(GR_GL_TEXTURE_EXTERNAL, texID));
|
||||
if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
|
||||
GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
|
||||
return 0;
|
||||
}
|
||||
glEGLImageTargetTexture2D(GR_GL_TEXTURE_EXTERNAL, image);
|
||||
if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
|
||||
GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
|
||||
return 0;
|
||||
}
|
||||
return texID;
|
||||
}
|
||||
|
||||
SkGLContext* SkANGLEGLContext::createNew() const {
|
||||
SkGLContext* ctx = SkANGLEGLContext::Create(this->gl()->fStandard, fIsGLBackend);
|
||||
if (ctx) {
|
||||
ctx->makeCurrent();
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void SkANGLEGLContext::destroyGLContext() {
|
||||
if (fDisplay) {
|
||||
eglMakeCurrent(fDisplay, 0, 0, 0);
|
||||
|
@ -319,6 +319,16 @@ void GrGLProgramBuilder::verify(const GrFragmentProcessor& fp) {
|
||||
SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition());
|
||||
}
|
||||
|
||||
static GrSLType get_sampler_type(const GrTextureAccess& access) {
|
||||
GrGLTexture* glTexture = static_cast<GrGLTexture*>(access.getTexture());
|
||||
if (glTexture->target() == GR_GL_TEXTURE_EXTERNAL) {
|
||||
return kSamplerExternal_GrSLType;
|
||||
} else {
|
||||
SkASSERT(glTexture->target() == GR_GL_TEXTURE_2D);
|
||||
return kSampler2D_GrSLType;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Proc>
|
||||
void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor,
|
||||
GrGLSLTextureSampler::TextureSamplerArray* outSamplers,
|
||||
@ -329,11 +339,19 @@ void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor,
|
||||
SkString name;
|
||||
for (int t = 0; t < numTextures; ++t) {
|
||||
name.printf("Sampler%d", t);
|
||||
GrSLType samplerType = get_sampler_type(processor.textureAccess(t));
|
||||
localSamplerUniforms[t] = this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
|
||||
kSampler2D_GrSLType, kDefault_GrSLPrecision,
|
||||
samplerType, kDefault_GrSLPrecision,
|
||||
name.c_str());
|
||||
SkNEW_APPEND_TO_TARRAY(outSamplers, GrGLSLTextureSampler,
|
||||
(localSamplerUniforms[t], processor.textureAccess(t)));
|
||||
if (kSamplerExternal_GrSLType == samplerType) {
|
||||
const char* externalFeatureString = this->glslCaps()->externalTextureExtensionString();
|
||||
// We shouldn't ever create a GrGLTexture that requires external sampler type
|
||||
SkASSERT(externalFeatureString);
|
||||
fFS.addFeature(1 << GrGLSLFragmentShaderBuilder::kExternalTexture_GLSLPrivateFeature,
|
||||
externalFeatureString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,15 @@
|
||||
|
||||
static GrGLFuncPtr egl_get_gl_proc(void* ctx, const char name[]) {
|
||||
SkASSERT(nullptr == ctx);
|
||||
return eglGetProcAddress(name);
|
||||
GrGLFuncPtr ptr = eglGetProcAddress(name);
|
||||
if (!ptr) {
|
||||
if (0 == strcmp("eglQueryString", name)) {
|
||||
return (GrGLFuncPtr)eglQueryString;
|
||||
} else if (0 == strcmp("eglGetCurrentDisplay", name)) {
|
||||
return (GrGLFuncPtr)eglGetCurrentDisplay;
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
const GrGLInterface* GrGLCreateNativeInterface() {
|
||||
|
@ -13,6 +13,9 @@
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
#include "gl/GrGLDefines.h"
|
||||
#include "gl/GrGLUtil.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO: Share this class with ANGLE if/when it gets support for EGL_KHR_fence_sync.
|
||||
@ -37,6 +40,11 @@ public:
|
||||
EGLGLContext(GrGLStandard forcedGpuAPI);
|
||||
~EGLGLContext() override;
|
||||
|
||||
GrEGLImage texture2DToEGLImage(GrGLuint texID) const override;
|
||||
void destroyEGLImage(GrEGLImage) const override;
|
||||
GrGLuint eglImageToExternalTexture(GrEGLImage) const override;
|
||||
SkGLContext* createNew() const override;
|
||||
|
||||
private:
|
||||
void destroyGLContext();
|
||||
|
||||
@ -200,6 +208,57 @@ void EGLGLContext::destroyGLContext() {
|
||||
}
|
||||
}
|
||||
|
||||
GrEGLImage EGLGLContext::texture2DToEGLImage(GrGLuint texID) const {
|
||||
if (!this->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) {
|
||||
return GR_EGL_NO_IMAGE;
|
||||
}
|
||||
GrEGLImage img;
|
||||
GrEGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0, GR_EGL_NONE };
|
||||
GrEGLClientBuffer clientBuffer = reinterpret_cast<GrEGLClientBuffer>(texID);
|
||||
GR_GL_CALL_RET(this->gl(), img,
|
||||
EGLCreateImage(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clientBuffer, attribs));
|
||||
return img;
|
||||
}
|
||||
|
||||
void EGLGLContext::destroyEGLImage(GrEGLImage image) const {
|
||||
GR_GL_CALL(this->gl(), EGLDestroyImage(fDisplay, image));
|
||||
}
|
||||
|
||||
GrGLuint EGLGLContext::eglImageToExternalTexture(GrEGLImage image) const {
|
||||
GrGLClearErr(this->gl());
|
||||
if (!this->gl()->hasExtension("GL_OES_EGL_image_external")) {
|
||||
return 0;
|
||||
}
|
||||
GrGLEGLImageTargetTexture2DProc glEGLImageTargetTexture2D =
|
||||
(GrGLEGLImageTargetTexture2DProc) eglGetProcAddress("glEGLImageTargetTexture2DOES");
|
||||
if (!glEGLImageTargetTexture2D) {
|
||||
return 0;
|
||||
}
|
||||
GrGLuint texID;
|
||||
glGenTextures(1, &texID);
|
||||
if (!texID) {
|
||||
return 0;
|
||||
}
|
||||
glBindTexture(GR_GL_TEXTURE_EXTERNAL, texID);
|
||||
if (glGetError() != GR_GL_NO_ERROR) {
|
||||
glDeleteTextures(1, &texID);
|
||||
return 0;
|
||||
}
|
||||
glEGLImageTargetTexture2D(GR_GL_TEXTURE_EXTERNAL, image);
|
||||
if (glGetError() != GR_GL_NO_ERROR) {
|
||||
glDeleteTextures(1, &texID);
|
||||
return 0;
|
||||
}
|
||||
return texID;
|
||||
}
|
||||
|
||||
SkGLContext* EGLGLContext::createNew() const {
|
||||
SkGLContext* ctx = SkCreatePlatformGLContext(this->gl()->fStandard);
|
||||
if (ctx) {
|
||||
ctx->makeCurrent();
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void EGLGLContext::onPlatformMakeCurrent() const {
|
||||
if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
|
||||
|
@ -85,6 +85,8 @@ static inline const char* GrGLSLTypeString(GrSLType t) {
|
||||
return "mat4";
|
||||
case kSampler2D_GrSLType:
|
||||
return "sampler2D";
|
||||
case kSamplerExternal_GrSLType:
|
||||
return "samplerExternalOES";
|
||||
default:
|
||||
SkFAIL("Unknown shader var type.");
|
||||
return ""; // suppress warning
|
||||
|
@ -28,6 +28,7 @@ GrGLSLCaps::GrGLSLCaps(const GrContextOptions& options) {
|
||||
fShaderDerivativeExtensionString = nullptr;
|
||||
fFragCoordConventionsExtensionString = nullptr;
|
||||
fSecondaryOutputExtensionString = nullptr;
|
||||
fExternalTextureExtensionString = nullptr;
|
||||
fFBFetchColorName = nullptr;
|
||||
fFBFetchExtensionString = nullptr;
|
||||
fAdvBlendEqInteraction = kNotSupported_AdvBlendEqInteraction;
|
||||
|
@ -102,6 +102,10 @@ public:
|
||||
return fSecondaryOutputExtensionString;
|
||||
}
|
||||
|
||||
const char* externalTextureExtensionString() const {
|
||||
return fExternalTextureExtensionString;
|
||||
}
|
||||
|
||||
bool mustSwizzleInShader() const { return fMustSwizzleInShader; }
|
||||
|
||||
/**
|
||||
@ -140,6 +144,7 @@ private:
|
||||
const char* fShaderDerivativeExtensionString;
|
||||
const char* fFragCoordConventionsExtensionString;
|
||||
const char* fSecondaryOutputExtensionString;
|
||||
const char* fExternalTextureExtensionString;
|
||||
|
||||
const char* fFBFetchColorName;
|
||||
const char* fFBFetchExtensionString;
|
||||
|
@ -172,6 +172,7 @@ private:
|
||||
kFragCoordConventions_GLSLPrivateFeature = kLastGLSLFeature + 1,
|
||||
kBlendEquationAdvanced_GLSLPrivateFeature,
|
||||
kBlendFuncExtended_GLSLPrivateFeature,
|
||||
kExternalTexture_GLSLPrivateFeature,
|
||||
kLastGLSLPrivateFeature = kBlendFuncExtended_GLSLPrivateFeature
|
||||
};
|
||||
|
||||
|
163
tests/EGLImageTest.cpp
Normal file
163
tests/EGLImageTest.cpp
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "Test.h"
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "GrContext.h"
|
||||
#include "GrContextFactory.h"
|
||||
#include "gl/GrGLGpu.h"
|
||||
#include "gl/GrGLUtil.h"
|
||||
#include "gl/SkGLContext.h"
|
||||
|
||||
static void cleanup(SkGLContext* glctx0, GrGLuint texID0, SkGLContext* glctx1, GrContext* grctx1,
|
||||
const GrGLTextureInfo* grbackendtex1, GrEGLImage image1) {
|
||||
if (glctx1) {
|
||||
glctx1->makeCurrent();
|
||||
if (grctx1) {
|
||||
if (grbackendtex1) {
|
||||
GrGLGpu* gpu1 = static_cast<GrGLGpu*>(grctx1->getGpu());
|
||||
GrBackendObject handle = reinterpret_cast<GrBackendObject>(grbackendtex1);
|
||||
gpu1->deleteTestingOnlyBackendTexture(handle, false);
|
||||
}
|
||||
grctx1->unref();
|
||||
}
|
||||
if (GR_EGL_NO_IMAGE != image1) {
|
||||
glctx1->destroyEGLImage(image1);
|
||||
}
|
||||
glctx1->unref();
|
||||
}
|
||||
|
||||
glctx0->makeCurrent();
|
||||
if (texID0) {
|
||||
GR_GL_CALL(glctx0->gl(), DeleteTextures(1, &texID0));
|
||||
}
|
||||
}
|
||||
|
||||
DEF_GPUTEST(EGLImageTest, reporter, factory) {
|
||||
for (int glCtxType = 0; glCtxType < GrContextFactory::kGLContextTypeCnt; ++glCtxType) {
|
||||
GrContextFactory::GLContextType type = (GrContextFactory::GLContextType)glCtxType;
|
||||
if (!GrContextFactory::IsRenderingGLContext(type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try to create a second GL context and then check if the contexts have necessary
|
||||
// extensions to run this test.
|
||||
|
||||
GrContext* context0 = factory->get(type);
|
||||
if (!context0) {
|
||||
continue;
|
||||
}
|
||||
SkGLContext* glCtx0 = factory->getGLContext(type);
|
||||
SkGLContext* glCtx1 = glCtx0->createNew();
|
||||
if (!glCtx1) {
|
||||
continue;
|
||||
}
|
||||
GrContext* context1 = GrContext::Create(kOpenGL_GrBackend, (GrBackendContext)glCtx1->gl());
|
||||
const GrGLTextureInfo* backendTexture1 = nullptr;
|
||||
GrEGLImage image = GR_EGL_NO_IMAGE;
|
||||
GrGLTextureInfo externalTexture;
|
||||
externalTexture.fID = 0;
|
||||
|
||||
if (!context1) {
|
||||
cleanup(glCtx0, externalTexture.fID, glCtx1, context1, backendTexture1, image);
|
||||
continue;
|
||||
}
|
||||
|
||||
SkASSERT(glCtx0);
|
||||
if (!glCtx0->gl()->hasExtension("EGL_KHR_image") ||
|
||||
!glCtx0->gl()->hasExtension("GL_OES_EGL_image_external") ||
|
||||
!glCtx1->gl()->hasExtension("EGL_KHR_image") ||
|
||||
!glCtx1->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) {
|
||||
cleanup(glCtx0, externalTexture.fID, glCtx1, context1, backendTexture1, image);
|
||||
continue;
|
||||
}
|
||||
|
||||
///////////////////////////////// CONTEXT 1 ///////////////////////////////////
|
||||
|
||||
// Use GL Context 1 to create a texture unknown to GrContext.
|
||||
context1->flush();
|
||||
GrGpu* gpu1 = context1->getGpu();
|
||||
static const int kSize = 100;
|
||||
backendTexture1 = reinterpret_cast<const GrGLTextureInfo*>(
|
||||
gpu1->createTestingOnlyBackendTexture(nullptr, kSize, kSize, kRGBA_8888_GrPixelConfig));
|
||||
if (!backendTexture1 || !backendTexture1->fID) {
|
||||
ERRORF(reporter, "Error creating texture for EGL Image");
|
||||
cleanup(glCtx0, externalTexture.fID, glCtx1, context1, backendTexture1, image);
|
||||
continue;
|
||||
}
|
||||
if (GR_GL_TEXTURE_2D != backendTexture1->fTarget) {
|
||||
ERRORF(reporter, "Expected backend texture to be 2D");
|
||||
cleanup(glCtx0, externalTexture.fID, glCtx1, context1, backendTexture1, image);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Wrap the texture in an EGLImage
|
||||
image = glCtx1->texture2DToEGLImage(backendTexture1->fID);
|
||||
if (GR_EGL_NO_IMAGE == image) {
|
||||
ERRORF(reporter, "Error creating EGL Image from texture");
|
||||
cleanup(glCtx0, externalTexture.fID, glCtx1, context1, backendTexture1, image);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Populate the texture using GL context 1. Important to use TexSubImage as TexImage orphans
|
||||
// the EGL image. Also, this must be done after creating the EGLImage as the texture
|
||||
// contents may not be preserved when the image is created.
|
||||
SkAutoTMalloc<uint32_t> pixels(kSize * kSize);
|
||||
for (int i = 0; i < kSize*kSize; ++i) {
|
||||
pixels.get()[i] = 0xDDAABBCC;
|
||||
}
|
||||
GR_GL_CALL(glCtx1->gl(), ActiveTexture(GR_GL_TEXTURE0));
|
||||
GR_GL_CALL(glCtx1->gl(), BindTexture(backendTexture1->fTarget, backendTexture1->fID));
|
||||
GR_GL_CALL(glCtx1->gl(), TexSubImage2D(backendTexture1->fTarget, 0, 0, 0, kSize, kSize,
|
||||
GR_GL_RGBA, GR_GL_UNSIGNED_BYTE, pixels.get()));
|
||||
GR_GL_CALL(glCtx1->gl(), Finish());
|
||||
// We've been making direct GL calls in GL context 1, let GrContext 1 know its internal
|
||||
// state is invalid.
|
||||
context1->resetContext();
|
||||
|
||||
///////////////////////////////// CONTEXT 0 ///////////////////////////////////
|
||||
|
||||
// Make a new texture ID in GL Context 0 from the EGL Image
|
||||
glCtx0->makeCurrent();
|
||||
externalTexture.fTarget = GR_GL_TEXTURE_EXTERNAL;
|
||||
externalTexture.fID = glCtx0->eglImageToExternalTexture(image);
|
||||
|
||||
// Wrap this texture ID in a GrTexture
|
||||
GrBackendTextureDesc externalDesc;
|
||||
externalDesc.fConfig = kRGBA_8888_GrPixelConfig;
|
||||
externalDesc.fWidth = kSize;
|
||||
externalDesc.fHeight = kSize;
|
||||
externalDesc.fTextureHandle = reinterpret_cast<GrBackendObject>(&externalTexture);
|
||||
SkAutoTUnref<GrTexture> externalTextureObj(
|
||||
context0->textureProvider()->wrapBackendTexture(externalDesc));
|
||||
if (!externalTextureObj) {
|
||||
ERRORF(reporter, "Error wrapping external texture in GrTexture.");
|
||||
cleanup(glCtx0, externalTexture.fID, glCtx1, context1, backendTexture1, image);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Read the pixels and see if we get the values set in GL context 1
|
||||
memset(pixels.get(), 0, sizeof(uint32_t)*kSize*kSize);
|
||||
bool read = externalTextureObj->readPixels(0, 0, kSize, kSize, kRGBA_8888_GrPixelConfig,
|
||||
pixels.get());
|
||||
if (!read) {
|
||||
ERRORF(reporter, "Error reading external texture.");
|
||||
cleanup(glCtx0, externalTexture.fID, glCtx1, context1, backendTexture1, image);
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < kSize*kSize; ++i) {
|
||||
if (pixels.get()[i] != 0xDDAABBCC) {
|
||||
ERRORF(reporter, "Error, external texture pixel value %d should be 0xDDAABBCC,"
|
||||
" got 0x%08x.", pixels.get()[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
cleanup(glCtx0, externalTexture.fID, glCtx1, context1, backendTexture1, image);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user