diff options
author | bsalomon <bsalomon@google.com> | 2015-11-20 19:34:37 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-11-20 19:34:37 -0800 |
commit | 27a048700778d4cebfc23301d1780649791b0e03 (patch) | |
tree | 93c88e37327c6519baaabb1faff0acef4bbb15c3 | |
parent | ac8cabd729c75fdf774c0701b6ea7fd3ea5b9382 (diff) |
Initial version of external_oes texture support and unit test
Review URL: https://codereview.chromium.org/1451683002
26 files changed, 615 insertions, 149 deletions
diff --git a/include/gpu/GrTypesPriv.h b/include/gpu/GrTypesPriv.h index 9202742df9..6135c14c12 100644 --- a/include/gpu/GrTypesPriv.h +++ b/include/gpu/GrTypesPriv.h @@ -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); } ////////////////////////////////////////////////////////////////////////////// diff --git a/include/gpu/gl/GrGLFunctions.h b/include/gpu/gl/GrGLFunctions.h index a8a721e7e6..1086186df8 100644 --- a/include/gpu/gl/GrGLFunctions.h +++ b/include/gpu/gl/GrGLFunctions.h @@ -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 diff --git a/include/gpu/gl/GrGLInterface.h b/include/gpu/gl/GrGLInterface.h index ec27ace81f..31429a8ebc 100644 --- a/include/gpu/gl/GrGLInterface.h +++ b/include/gpu/gl/GrGLInterface.h @@ -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 diff --git a/include/gpu/gl/GrGLTypes.h b/include/gpu/gl/GrGLTypes.h index 275eba556d..248ce8886d 100644 --- a/include/gpu/gl/GrGLTypes.h +++ b/include/gpu/gl/GrGLTypes.h @@ -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; diff --git a/include/gpu/gl/SkGLContext.h b/include/gpu/gl/SkGLContext.h index 75cfcfee04..3420a47973 100644 --- a/include/gpu/gl/SkGLContext.h +++ b/include/gpu/gl/SkGLContext.h @@ -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: diff --git a/include/gpu/gl/angle/SkANGLEGLContext.h b/include/gpu/gl/angle/SkANGLEGLContext.h index 8d5f83041a..7858fff964 100644 --- a/include/gpu/gl/angle/SkANGLEGLContext.h +++ b/include/gpu/gl/angle/SkANGLEGLContext.h @@ -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 diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp index 31568144a2..38213e6266 100644 --- a/src/gpu/GrResourceProvider.cpp +++ b/src/gpu/GrResourceProvider.cpp @@ -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. diff --git a/src/gpu/gl/GrGLAssembleInterface.cpp b/src/gpu/gl/GrGLAssembleInterface.cpp index e606f4a29e..dbc54adbe4 100644 --- a/src/gpu/gl/GrGLAssembleInterface.cpp +++ b/src/gpu/gl/GrGLAssembleInterface.cpp @@ -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); diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index 28401fe9e6..a768b37105 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -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; diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h index 5f1ca3e340..0ec6c85b47 100644 --- a/src/gpu/gl/GrGLCaps.h +++ b/src/gpu/gl/GrGLCaps.h @@ -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; diff --git a/src/gpu/gl/GrGLDefines.h b/src/gpu/gl/GrGLDefines.h index 603a319ca0..dfab5e7e13 100644 --- a/src/gpu/gl/GrGLDefines.h +++ b/src/gpu/gl/GrGLDefines.h @@ -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 diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index 2bd36b6404..51145c8988 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -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() { +void GrGLGpu::createCopyPrograms() { + for (size_t i = 0; i < SK_ARRAY_COUNT(fCopyPrograms); ++i) { + fCopyPrograms[i].fProgram = 0; + } const char* version = this->glCaps().glslCaps()->versionDeclString(); - - GrGLSLShaderVar aVertex("a_vertex", kVec2f_GrSLType, GrShaderVar::kAttribute_TypeModifier); - GrGLSLShaderVar uTexCoordXform("u_texCoordXform", kVec4f_GrSLType, + 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 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); + 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(";"); + 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); + 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); + 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(";"); - 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()) - ); + 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(fCopyProgram.fProgram, CreateProgram()); - const char* str; - GrGLint length; + GL_CALL_RET(fCopyPrograms[i].fProgram, CreateProgram()); + const char* str; + GrGLint length; - str = vshaderTxt.c_str(); - length = SkToInt(vshaderTxt.size()); - GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fCopyProgram.fProgram, - GR_GL_VERTEX_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); - str = fshaderTxt.c_str(); - length = SkToInt(fshaderTxt.size()); - GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fCopyProgram.fProgram, - GR_GL_FRAGMENT_SHADER, &str, &length, 1, &fStats); + 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(LinkProgram(fCopyProgram.fProgram)); + GL_CALL(LinkProgram(fCopyPrograms[i].fProgram)); - 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_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(BindAttribLocation(fCopyProgram.fProgram, 0, "a_vertex")); + GL_CALL(BindAttribLocation(fCopyPrograms[i].fProgram, 0, "a_vertex")); - GL_CALL(DeleteShader(vshader)); - GL_CALL(DeleteShader(fshader)); + GL_CALL(DeleteShader(vshader)); + GL_CALL(DeleteShader(fshader)); + } - GL_CALL(GenBuffers(1, &fCopyProgram.fArrayBuffer)); - fHWGeometryState.setVertexBufferID(this, fCopyProgram.fArrayBuffer); + 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(); diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h index c8da150a0d..637a1cf161 100644 --- a/src/gpu/gl/GrGLGpu.h +++ b/src/gpu/gl/GrGLGpu.h @@ -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; diff --git a/src/gpu/gl/GrGLInterface.cpp b/src/gpu/gl/GrGLInterface.cpp index c6c846abf8..da3c656c18 100644 --- a/src/gpu/gl/GrGLInterface.cpp +++ b/src/gpu/gl/GrGLInterface.cpp @@ -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 } } diff --git a/src/gpu/gl/GrGLProgramDataManager.cpp b/src/gpu/gl/GrGLProgramDataManager.cpp index a61e6974b6..f0aba49720 100644 --- a/src/gpu/gl/GrGLProgramDataManager.cpp +++ b/src/gpu/gl/GrGLProgramDataManager.cpp @@ -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 diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp index 172aca77ab..a1646618e8 100644 --- a/src/gpu/gl/GrGLProgramDesc.cpp +++ b/src/gpu/gl/GrGLProgramDesc.cpp @@ -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; } diff --git a/src/gpu/gl/angle/GrGLCreateANGLEInterface.cpp b/src/gpu/gl/angle/GrGLCreateANGLEInterface.cpp index 834e122f57..05afb2cb1c 100644 --- a/src/gpu/gl/angle/GrGLCreateANGLEInterface.cpp +++ b/src/gpu/gl/angle/GrGLCreateANGLEInterface.cpp @@ -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); } diff --git a/src/gpu/gl/angle/SkANGLEGLContext.cpp b/src/gpu/gl/angle/SkANGLEGLContext.cpp index 64a3bdec74..54ef02d492 100644 --- a/src/gpu/gl/angle/SkANGLEGLContext.cpp +++ b/src/gpu/gl/angle/SkANGLEGLContext.cpp @@ -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); diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp index 0ae4f96101..b5108a74d0 100644 --- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp +++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp @@ -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); + } } } diff --git a/src/gpu/gl/egl/GrGLCreateNativeInterface_egl.cpp b/src/gpu/gl/egl/GrGLCreateNativeInterface_egl.cpp index 703e39d097..fef4f0276f 100644 --- a/src/gpu/gl/egl/GrGLCreateNativeInterface_egl.cpp +++ b/src/gpu/gl/egl/GrGLCreateNativeInterface_egl.cpp @@ -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() { diff --git a/src/gpu/gl/egl/SkCreatePlatformGLContext_egl.cpp b/src/gpu/gl/egl/SkCreatePlatformGLContext_egl.cpp index d1335d355f..591cae349c 100644 --- a/src/gpu/gl/egl/SkCreatePlatformGLContext_egl.cpp +++ b/src/gpu/gl/egl/SkCreatePlatformGLContext_egl.cpp @@ -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)) { diff --git a/src/gpu/glsl/GrGLSL.h b/src/gpu/glsl/GrGLSL.h index a39f104fab..ac38522ca1 100644 --- a/src/gpu/glsl/GrGLSL.h +++ b/src/gpu/glsl/GrGLSL.h @@ -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 diff --git a/src/gpu/glsl/GrGLSLCaps.cpp b/src/gpu/glsl/GrGLSLCaps.cpp index aed98880f5..191fb567e6 100755 --- a/src/gpu/glsl/GrGLSLCaps.cpp +++ b/src/gpu/glsl/GrGLSLCaps.cpp @@ -28,6 +28,7 @@ GrGLSLCaps::GrGLSLCaps(const GrContextOptions& options) { fShaderDerivativeExtensionString = nullptr; fFragCoordConventionsExtensionString = nullptr; fSecondaryOutputExtensionString = nullptr; + fExternalTextureExtensionString = nullptr; fFBFetchColorName = nullptr; fFBFetchExtensionString = nullptr; fAdvBlendEqInteraction = kNotSupported_AdvBlendEqInteraction; diff --git a/src/gpu/glsl/GrGLSLCaps.h b/src/gpu/glsl/GrGLSLCaps.h index 68e91b6666..9924773139 100755 --- a/src/gpu/glsl/GrGLSLCaps.h +++ b/src/gpu/glsl/GrGLSLCaps.h @@ -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; diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h index 924e3110df..a55fdd2860 100644 --- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h +++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h @@ -172,6 +172,7 @@ private: kFragCoordConventions_GLSLPrivateFeature = kLastGLSLFeature + 1, kBlendEquationAdvanced_GLSLPrivateFeature, kBlendFuncExtended_GLSLPrivateFeature, + kExternalTexture_GLSLPrivateFeature, kLastGLSLPrivateFeature = kBlendFuncExtended_GLSLPrivateFeature }; diff --git a/tests/EGLImageTest.cpp b/tests/EGLImageTest.cpp new file mode 100644 index 0000000000..088049ee1f --- /dev/null +++ b/tests/EGLImageTest.cpp @@ -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 |