diff --git a/bench/benchmain.cpp b/bench/benchmain.cpp index c58d5b1e5f..b809c99cd8 100644 --- a/bench/benchmain.cpp +++ b/bench/benchmain.cpp @@ -464,15 +464,13 @@ int main (int argc, char * const argv[]) { reinterpret_cast(glctx.get()->gl()); context = GrContext::Create(kOpenGL_Shaders_GrEngine, ctx); if (NULL != context) { - GrPlatformSurfaceDesc desc; - desc.reset(); + GrPlatformRenderTargetDesc desc; desc.fConfig = kRGBA_8888_GrPixelConfig; desc.fWidth = contextWidth; desc.fHeight = contextHeight; desc.fStencilBits = 8; - desc.fPlatformRenderTarget = glctx.get()->getFBOID(); - desc.fSurfaceType = kRenderTarget_GrPlatformSurfaceType; - rt = static_cast(context->createPlatformSurface(desc)); + desc.fRenderTargetHandle = glctx.get()->getFBOID(); + rt = context->createPlatformRenderTarget(desc); if (NULL == rt) { context->unref(); context = NULL; diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp index f2ab7033fc..f437906068 100644 --- a/gm/gmmain.cpp +++ b/gm/gmmain.cpp @@ -647,15 +647,13 @@ int main(int argc, char * const argv[]) { reinterpret_cast(glContext.get()->gl()); gGrContext = GrContext::Create(kOpenGL_Shaders_GrEngine, ctx); if (NULL != gGrContext) { - GrPlatformSurfaceDesc desc; - desc.reset(); + GrPlatformRenderTargetDesc desc; desc.fConfig = kRGBA_8888_GrPixelConfig; desc.fWidth = maxW; desc.fHeight = maxH; desc.fStencilBits = 8; - desc.fPlatformRenderTarget = glContext.get()->getFBOID(); - desc.fSurfaceType = kRenderTarget_GrPlatformSurfaceType; - rt = static_cast(gGrContext->createPlatformSurface(desc)); + desc.fRenderTargetHandle = glContext.get()->getFBOID(); + rt = gGrContext->createPlatformRenderTarget(desc); if (NULL == rt) { gGrContext->unref(); gGrContext = NULL; diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h index d61b8bb5a0..5e132a2d4c 100644 --- a/include/gpu/GrContext.h +++ b/include/gpu/GrContext.h @@ -238,6 +238,35 @@ public: // Platform Surfaces /** + * Wraps an existing texture with a GrTexture object. + * + * OpenGL: if the object is a texture Gr may change its GL texture params + * when it is drawn. + * + * @param desc description of the object to create. + * + * @return GrTexture object or NULL on failure. + */ + GrTexture* createPlatformTexture(const GrPlatformTextureDesc& desc); + + /** + * Wraps an existing render target with a GrRenderTarget object. It is + * similar to createPlatformTexture but can be used to draw into surfaces + * that are not also textures (e.g. FBO 0 in OpenGL, or an MSAA buffer that + * the client will resolve to a texture). + * + * @param desc description of the object to create. + * + * @return GrTexture object or NULL on failure. + */ + GrRenderTarget* createPlatformRenderTarget( + const GrPlatformRenderTargetDesc& desc); + + /** + * This interface is depracted and will be removed in a future revision. + * Callers should use createPlatformTexture or createPlatformRenderTarget + * instead. + * * Wraps an existing 3D API surface in a GrObject. desc.fFlags determines * the type of object returned. If kIsTexture is set the returned object * will be a GrTexture*. Otherwise, it will be a GrRenderTarget*. If both diff --git a/include/gpu/GrTypes.h b/include/gpu/GrTypes.h index 5e9cdb2bcb..bb19c35c35 100644 --- a/include/gpu/GrTypes.h +++ b/include/gpu/GrTypes.h @@ -504,6 +504,99 @@ enum GrConvexHint { /////////////////////////////////////////////////////////////////////////////// +// opaque type for 3D API object handles +typedef intptr_t GrPlatform3DObject; + +/** + * Gr can wrap an existing texture created by the client with a GrTexture + * object. The client is responsible for ensuring that the texture lives at + * least as long as the GrTexture object wrapping it. We require the client to + * explicitly provide information about the texture, such as width, height, + * and pixel config, rather than querying the 3D APIfor these values. We expect + * these to be immutable even if the 3D API doesn't require this (OpenGL). + * + * Textures that are also render targets are supported as well. Gr will manage + * any ancillary 3D API (stencil buffer, FBO id, etc) objects necessary for + * Gr to draw into the render target. To access the render target object + * call GrTexture::asRenderTarget(). + * + * If in addition to the render target flag, the caller also specifies a sample + * count Gr will create an MSAA buffer that resolves into the texture. Gr auto- + * resolves when it reads from the texture. The client can explictly resolve + * using the GrRenderTarget interface. + */ + +enum GrPlatformTextureFlags { + /** + * No flags enabled + */ + kNone_GrPlatformTextureFlag = 0x0, + /** + * Indicates that the texture is also a render target, and thus should have + * a GrRenderTarget object. + * + * D3D (future): client must have created the texture with flags that allow + * it to be used as a render target. + */ + kRenderTarget_GrPlatformTextureFlag = 0x1, +}; +GR_MAKE_BITFIELD_OPS(GrPlatformTextureFlags) + +struct GrPlatformTextureDesc { + GrPlatformTextureDesc() { memset(this, 0, sizeof(*this)); } + GrPlatformTextureFlags fFlags; + int fWidth; //attachGL(); - GrPlatformSurfaceDesc desc; - desc.reset(); - desc.fSurfaceType = kRenderTarget_GrPlatformSurfaceType; + GrPlatformRenderTargetDesc desc; desc.fWidth = SkScalarRound(win->width()); desc.fHeight = SkScalarRound(win->height()); desc.fConfig = kRGBA_8888_GrPixelConfig; - GR_GL_GetIntegerv(fGL, GR_GL_STENCIL_BITS, &desc.fStencilBits); GR_GL_GetIntegerv(fGL, GR_GL_SAMPLES, &desc.fSampleCnt); + GR_GL_GetIntegerv(fGL, GR_GL_STENCIL_BITS, &desc.fStencilBits); GrGLint buffer; GR_GL_GetIntegerv(fGL, GR_GL_FRAMEBUFFER_BINDING, &buffer); - desc.fPlatformRenderTarget = buffer; + desc.fRenderTargetHandle = buffer; SkSafeUnref(fGrRenderTarget); - fGrRenderTarget = static_cast( - fGrContext->createPlatformSurface(desc)); + fGrRenderTarget = fGrContext->createPlatformRenderTarget(desc); } if (NULL != fNullGrContext) { - GrPlatformSurfaceDesc desc; - desc.reset(); - desc.fSurfaceType = kRenderTarget_GrPlatformSurfaceType; + GrPlatformRenderTargetDesc desc; desc.fWidth = SkScalarRound(win->width()); desc.fHeight = SkScalarRound(win->height()); desc.fConfig = kRGBA_8888_GrPixelConfig; desc.fStencilBits = 8; desc.fSampleCnt = 0; - desc.fPlatformRenderTarget = 0; - fNullGrRenderTarget = static_cast( - fNullGrContext->createPlatformSurface(desc)); + desc.fRenderTargetHandle = 0; + fGrRenderTarget = fNullGrContext->createPlatformRenderTarget(desc); } } diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 231cf23573..f4e5e9b621 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -525,6 +525,14 @@ int GrContext::getMaxRenderTargetSize() const { /////////////////////////////////////////////////////////////////////////////// +GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) { + return fGpu->createPlatformTexture(desc); +} + +GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) { + return fGpu->createPlatformRenderTarget(desc); +} + GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) { // validate flags here so that GrGpu subclasses don't have to check if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType && diff --git a/src/gpu/GrGLRenderTarget.h b/src/gpu/GrGLRenderTarget.h index 5aeb36dc65..eb817df6f0 100644 --- a/src/gpu/GrGLRenderTarget.h +++ b/src/gpu/GrGLRenderTarget.h @@ -67,7 +67,9 @@ public: return this->textureFBOID(); } virtual ResolveType getResolveType() const { - if (fRTFBOID == fTexFBOID) { + + if (!this->isMultisampled() || + fRTFBOID == fTexFBOID) { // catches FBO 0 and non MSAA case return kAutoResolves_ResolveType; } else if (kUnresolvableFBOID == fTexFBOID) { diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp index c5a8bfb927..b7d1395098 100644 --- a/src/gpu/GrGpu.cpp +++ b/src/gpu/GrGpu.cpp @@ -195,6 +195,25 @@ bool GrGpu::attachStencilBufferToRenderTarget(GrRenderTarget* rt) { } } +GrTexture* GrGpu::createPlatformTexture(const GrPlatformTextureDesc& desc) { + this->handleDirtyContext(); + GrTexture* tex = this->onCreatePlatformTexture(desc); + // TODO: defer this and attach dynamically + GrRenderTarget* tgt = tex->asRenderTarget(); + if (NULL != tgt && + !this->attachStencilBufferToRenderTarget(tgt)) { + tex->unref(); + return NULL; + } else { + return tex; + } +} + +GrRenderTarget* GrGpu::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) { + this->handleDirtyContext(); + return this->onCreatePlatformRenderTarget(desc); +} + GrResource* GrGpu::createPlatformSurface(const GrPlatformSurfaceDesc& desc) { this->handleDirtyContext(); return this->onCreatePlatformSurface(desc); diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h index 5d9cf4fd48..b0aaa185dd 100644 --- a/src/gpu/GrGpu.h +++ b/src/gpu/GrGpu.h @@ -121,6 +121,19 @@ public: GrTexture* createTexture(const GrTextureDesc& desc, const void* srcData, size_t rowBytes); + /** + * Implements GrContext::createPlatformTexture + */ + GrTexture* createPlatformTexture(const GrPlatformTextureDesc& desc); + + /** + * Implements GrContext::createPlatformTexture + */ + GrRenderTarget* createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc); + + /** + * DEPRECATED. This will be removed. + */ GrResource* createPlatformSurface(const GrPlatformSurfaceDesc& desc); /** @@ -314,6 +327,8 @@ protected: virtual GrTexture* onCreateTexture(const GrTextureDesc& desc, const void* srcData, size_t rowBytes) = 0; + virtual GrTexture* onCreatePlatformTexture(const GrPlatformTextureDesc& desc) = 0; + virtual GrRenderTarget* onCreatePlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) = 0; virtual GrResource* onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc) = 0; virtual GrVertexBuffer* onCreateVertexBuffer(uint32_t size, bool dynamic) = 0; diff --git a/src/gpu/GrGpuGL.cpp b/src/gpu/GrGpuGL.cpp index 10c0fa6157..bae4f7762a 100644 --- a/src/gpu/GrGpuGL.cpp +++ b/src/gpu/GrGpuGL.cpp @@ -634,6 +634,81 @@ void GrGpuGL::onResetContext() { fHWDrawState.fRenderTarget = NULL; } +GrTexture* GrGpuGL::onCreatePlatformTexture(const GrPlatformTextureDesc& desc) { + GrGLenum internalFormat; // we don't need this value + GrGLTexture::Desc glTexDesc; + if (!this->canBeTexture(desc.fConfig, &internalFormat, + &glTexDesc.fUploadFormat, &glTexDesc.fUploadType)) { + return NULL; + } + + glTexDesc.fContentWidth = glTexDesc.fAllocWidth = desc.fWidth; + glTexDesc.fContentHeight = glTexDesc.fAllocHeight = desc.fHeight; + glTexDesc.fConfig = desc.fConfig; + glTexDesc.fTextureID = static_cast(desc.fTextureHandle); + glTexDesc.fOwnsID = false; + glTexDesc.fOrientation = GrGLTexture::kBottomUp_Orientation; + + GrGLTexture* texture = NULL; + if (desc.fFlags & kRenderTarget_GrPlatformTextureFlag) { + GrGLRenderTarget::Desc glRTDesc; + glRTDesc.fRTFBOID = 0; + glRTDesc.fTexFBOID = 0; + glRTDesc.fMSColorRenderbufferID = 0; + glRTDesc.fOwnIDs = true; + glRTDesc.fConfig = desc.fConfig; + glRTDesc.fSampleCnt = desc.fSampleCnt; + if (!this->createRenderTargetObjects(glTexDesc.fAllocWidth, + glTexDesc.fAllocHeight, + glTexDesc.fTextureID, + &glRTDesc)) { + return NULL; + } + texture = new GrGLTexture(this, glTexDesc, glRTDesc); + } else { + texture = new GrGLTexture(this, glTexDesc); + } + if (NULL == texture) { + return NULL; + } + + this->setSpareTextureUnit(); + return texture; +} + +GrRenderTarget* GrGpuGL::onCreatePlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) { + GrGLRenderTarget::Desc glDesc; + glDesc.fConfig = desc.fConfig; + glDesc.fRTFBOID = static_cast(desc.fRenderTargetHandle); + glDesc.fMSColorRenderbufferID = 0; + glDesc.fTexFBOID = GrGLRenderTarget::kUnresolvableFBOID; + glDesc.fSampleCnt = desc.fSampleCnt; + glDesc.fOwnIDs = false; + GrGLIRect viewport; + viewport.fLeft = 0; + viewport.fBottom = 0; + viewport.fWidth = desc.fWidth; + viewport.fHeight = desc.fHeight; + + GrRenderTarget* tgt = new GrGLRenderTarget(this, glDesc, viewport); + if (desc.fStencilBits) { + GrGLStencilBuffer::Format format; + format.fInternalFormat = GrGLStencilBuffer::kUnknownInternalFormat; + format.fPacked = false; + format.fStencilBits = desc.fStencilBits; + format.fTotalBits = desc.fStencilBits; + GrGLStencilBuffer* sb = new GrGLStencilBuffer(this, + 0, + desc.fWidth, + desc.fHeight, + desc.fSampleCnt, + format); + tgt->setStencilBuffer(sb); + sb->unref(); + } + return tgt; +} + GrResource* GrGpuGL::onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc) { bool isTexture = kTexture_GrPlatformSurfaceType == desc.fSurfaceType || @@ -868,7 +943,10 @@ bool GrGpuGL::createRenderTargetObjects(int width, int height, // If we are using multisampling we will create two FBOS. We render // to one and then resolve to the texture bound to the other. - if (desc->fSampleCnt > 1 && GLCaps::kNone_MSFBO != fGLCaps.fMSFBOType) { + if (desc->fSampleCnt > 0) { + if (GLCaps::kNone_MSFBO == fGLCaps.fMSFBOType) { + goto FAILED; + } GL_CALL(GenFramebuffers(1, &desc->fRTFBOID)); GL_CALL(GenRenderbuffers(1, &desc->fMSColorRenderbufferID)); if (!desc->fRTFBOID || @@ -949,12 +1027,6 @@ GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc, ++fStats.fTextureCreateCnt; #endif - static const GrGLTexture::TexParams DEFAULT_PARAMS = { - GR_GL_NEAREST, - GR_GL_CLAMP_TO_EDGE, - GR_GL_CLAMP_TO_EDGE - }; - GrGLTexture::Desc glTexDesc; GrGLRenderTarget::Desc glRTDesc; GrGLenum internalFormat; @@ -1025,24 +1097,32 @@ GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc, this->setSpareTextureUnit(); GL_CALL(BindTexture(GR_GL_TEXTURE_2D, glTexDesc.fTextureID)); + + // Some drivers like to know these before seeing glTexImage2D. Some drivers + // have a bug where an FBO won't be complete if it includes a texture that + // is not complete (i.e. has mip levels or non-mip min filter). + static const GrGLTexture::TexParams DEFAULT_TEX_PARAMS = { + GR_GL_NEAREST, + GR_GL_CLAMP_TO_EDGE, + GR_GL_CLAMP_TO_EDGE + }; GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MAG_FILTER, - DEFAULT_PARAMS.fFilter)); + DEFAULT_TEX_PARAMS.fFilter)); GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MIN_FILTER, - DEFAULT_PARAMS.fFilter)); + DEFAULT_TEX_PARAMS.fFilter)); GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_S, - DEFAULT_PARAMS.fWrapS)); + DEFAULT_TEX_PARAMS.fWrapS)); GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_WRAP_T, - DEFAULT_PARAMS.fWrapT)); + DEFAULT_TEX_PARAMS.fWrapT)); this->allocateAndUploadTexData(glTexDesc, internalFormat,srcData, rowBytes); GrGLTexture* tex; if (renderTarget) { - GrGLenum msColorRenderbufferFormat = -1; #if GR_COLLECT_STATS ++fStats.fRenderTargetCreateCnt; #endif @@ -1057,7 +1137,7 @@ GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc, } else { tex = new GrGLTexture(this, glTexDesc); } - tex->setCachedTexParams(DEFAULT_PARAMS, this->getResetTimestamp()); + tex->setCachedTexParams(DEFAULT_TEX_PARAMS, this->getResetTimestamp()); #ifdef TRACE_TEXTURE_CREATION GrPrintf("--- new texture [%d] size=(%d %d) config=%d\n", glTexDesc.fTextureID, desc.fWidth, desc.fHeight, desc.fConfig); diff --git a/src/gpu/GrGpuGL.h b/src/gpu/GrGpuGL.h index f28f578a96..0addf4a2ad 100644 --- a/src/gpu/GrGpuGL.h +++ b/src/gpu/GrGpuGL.h @@ -80,6 +80,8 @@ protected: virtual GrIndexBuffer* onCreateIndexBuffer(uint32_t size, bool dynamic); virtual GrResource* onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc); + virtual GrTexture* onCreatePlatformTexture(const GrPlatformTextureDesc& desc) SK_OVERRIDE; + virtual GrRenderTarget* onCreatePlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) SK_OVERRIDE; virtual bool createStencilBufferForRenderTarget(GrRenderTarget* rt, int width, int height); virtual bool attachStencilBufferToRenderTarget(GrStencilBuffer* sb,