| Index: src/gpu/gl/GrGLGpu.cpp
|
| diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
|
| index 602eeca56d60befb09ac79f90f678fe11f9be7b4..0eac373f2e81f1edf8a8ba975e4a937cebe88273 100644
|
| --- a/src/gpu/gl/GrGLGpu.cpp
|
| +++ b/src/gpu/gl/GrGLGpu.cpp
|
| @@ -159,6 +159,15 @@ bool GrGLGpu::BlendCoeffReferencesConstant(GrBlendCoeff coeff) {
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| +// Used in the map of pixel configs to stencil format indices. This value is used to
|
| +// indicate that a stencil format has not yet been set for the given config.
|
| +static const int kUnknownStencilIndex = -1;
|
| +// This value is used as the stencil index when no stencil configs are supported with the
|
| +// given pixel config.
|
| +static const int kUnsupportedStencilIndex = -2;
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +
|
| GrGpu* GrGLGpu::Create(GrBackendContext backendContext, const GrContextOptions& options,
|
| GrContext* context) {
|
| SkAutoTUnref<const GrGLInterface> glInterface(
|
| @@ -211,7 +220,9 @@ GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context)
|
|
|
| SkASSERT(this->glCaps().maxVertexAttributes() >= GrGeometryProcessor::kMaxVertexAttribs);
|
|
|
| - fLastSuccessfulStencilFmtIdx = 0;
|
| + for (int i = 0; i < kGrPixelConfigCnt; ++i) {
|
| + fPixelConfigToStencilIndex[i] = kUnknownStencilIndex;
|
| + }
|
| fHWProgramID = 0;
|
| fTempSrcFBOID = 0;
|
| fTempDstFBOID = 0;
|
| @@ -1169,120 +1180,223 @@ void inline get_stencil_rb_sizes(const GrGLInterface* gl,
|
| }
|
| }
|
|
|
| -bool GrGLGpu::createStencilAttachmentForRenderTarget(GrRenderTarget* rt, int width, int height) {
|
| - // All internally created RTs are also textures. We don't create
|
| - // SBs for a client's standalone RT (that is a RT that isn't also a texture).
|
| - SkASSERT(rt->asTexture());
|
| - SkASSERT(width >= rt->width());
|
| - SkASSERT(height >= rt->height());
|
| -
|
| - int samples = rt->numStencilSamples();
|
| - GrGLStencilAttachment::IDDesc sbDesc;
|
| +int GrGLGpu::getCompatibleStencilIndex(GrPixelConfig config) {
|
| + int size = this->caps()->minTextureSize();
|
| + if (kUnknownStencilIndex == fPixelConfigToStencilIndex[config]) {
|
| + // Default to unsupported
|
| + fPixelConfigToStencilIndex[config] = kUnsupportedStencilIndex;
|
| + // Create color texture
|
| + GrGLuint colorID;
|
| + GL_CALL(GenTextures(1, &colorID));
|
| + this->setScratchTextureUnit();
|
| + GL_CALL(BindTexture(GR_GL_TEXTURE_2D, colorID));
|
| + GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
|
| + GR_GL_TEXTURE_MAG_FILTER,
|
| + GR_GL_NEAREST));
|
| + GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
|
| + GR_GL_TEXTURE_MIN_FILTER,
|
| + GR_GL_NEAREST));
|
| + GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
|
| + GR_GL_TEXTURE_WRAP_S,
|
| + GR_GL_CLAMP_TO_EDGE));
|
| + GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
|
| + GR_GL_TEXTURE_WRAP_T,
|
| + GR_GL_CLAMP_TO_EDGE));
|
|
|
| - int stencilFmtCnt = this->glCaps().stencilFormats().count();
|
| - for (int i = 0; i < stencilFmtCnt; ++i) {
|
| - if (!sbDesc.fRenderbufferID) {
|
| - GL_CALL(GenRenderbuffers(1, &sbDesc.fRenderbufferID));
|
| + GrGLenum internalFormat = 0x0; // suppress warning
|
| + GrGLenum externalFormat = 0x0; // suppress warning
|
| + GrGLenum externalType = 0x0; // suppress warning
|
| + if (!this->configToGLFormats(config, false, &internalFormat,
|
| + &externalFormat, &externalType)) {
|
| + GL_CALL(DeleteTextures(1, &colorID));
|
| + fPixelConfigToStencilIndex[config] = kUnsupportedStencilIndex;
|
| + return kUnsupportedStencilIndex;
|
| }
|
| - if (!sbDesc.fRenderbufferID) {
|
| - return false;
|
| - }
|
| - GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, sbDesc.fRenderbufferID));
|
| - // we start with the last stencil format that succeeded in hopes
|
| - // that we won't go through this loop more than once after the
|
| - // first (painful) stencil creation.
|
| - int sIdx = (i + fLastSuccessfulStencilFmtIdx) % stencilFmtCnt;
|
| - const GrGLCaps::StencilFormat& sFmt = this->glCaps().stencilFormats()[sIdx];
|
| +
|
| CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
|
| - // we do this "if" so that we don't call the multisample
|
| - // version on a GL that doesn't have an MSAA extension.
|
| - bool created;
|
| - if (samples > 0) {
|
| - created = renderbuffer_storage_msaa(*fGLContext,
|
| - samples,
|
| - sFmt.fInternalFormat,
|
| - width, height);
|
| - } else {
|
| + GL_ALLOC_CALL(this->glInterface(), TexImage2D(GR_GL_TEXTURE_2D,
|
| + 0, internalFormat,
|
| + size,
|
| + size,
|
| + 0,
|
| + externalFormat,
|
| + externalType,
|
| + NULL));
|
| + if (GR_GL_NO_ERROR != GR_GL_GET_ERROR(this->glInterface())) {
|
| + GL_CALL(DeleteTextures(1, &colorID));
|
| + fPixelConfigToStencilIndex[config] = kUnsupportedStencilIndex;
|
| + return kUnsupportedStencilIndex;
|
| + }
|
| +
|
| + // unbind the texture from the texture unit before binding it to the frame buffer
|
| + GL_CALL(BindTexture(GR_GL_TEXTURE_2D, 0));
|
| +
|
| + // Create Framebuffer
|
| + GrGLuint fb;
|
| + GL_CALL(GenFramebuffers(1, &fb));
|
| + GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fb));
|
| + fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
|
| + GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER,
|
| + GR_GL_COLOR_ATTACHMENT0,
|
| + GR_GL_TEXTURE_2D,
|
| + colorID,
|
| + 0));
|
| +
|
| + // look over formats till I find a compatible one
|
| + int stencilFmtCnt = this->glCaps().stencilFormats().count();
|
| + GrGLuint sbRBID = 0;
|
| + for (int i = 0; i < stencilFmtCnt; ++i) {
|
| + const GrGLCaps::StencilFormat& sFmt = this->glCaps().stencilFormats()[i];
|
| +
|
| + GL_CALL(GenRenderbuffers(1, &sbRBID));
|
| + if (!sbRBID) {
|
| + break;
|
| + }
|
| + GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, sbRBID));
|
| + CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
|
| GL_ALLOC_CALL(this->glInterface(), RenderbufferStorage(GR_GL_RENDERBUFFER,
|
| sFmt.fInternalFormat,
|
| - width, height));
|
| - created = (GR_GL_NO_ERROR == check_alloc_error(rt->desc(), this->glInterface()));
|
| - }
|
| - if (created) {
|
| - fStats.incStencilAttachmentCreates();
|
| - // After sized formats we attempt an unsized format and take
|
| - // whatever sizes GL gives us. In that case we query for the size.
|
| - GrGLStencilAttachment::Format format = sFmt;
|
| - get_stencil_rb_sizes(this->glInterface(), &format);
|
| - SkAutoTUnref<GrGLStencilAttachment> sb(
|
| - new GrGLStencilAttachment(this, sbDesc, width, height, samples, format));
|
| - if (this->attachStencilAttachmentToRenderTarget(sb, rt)) {
|
| - fLastSuccessfulStencilFmtIdx = sIdx;
|
| - rt->renderTargetPriv().didAttachStencilAttachment(sb);
|
| -// This work around is currently breaking on windows 7 hd2000 bot when we bind a color buffer
|
| -#if 0
|
| - // Clear the stencil buffer. We use a special purpose FBO for this so that the
|
| - // entire stencil buffer is cleared, even if it is attached to an FBO with a
|
| - // smaller color target.
|
| - if (0 == fStencilClearFBOID) {
|
| - GL_CALL(GenFramebuffers(1, &fStencilClearFBOID));
|
| - }
|
| -
|
| - GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fStencilClearFBOID));
|
| - fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
|
| - fStats.incRenderTargetBinds();
|
| + size, size));
|
| + if (GR_GL_NO_ERROR == GR_GL_GET_ERROR(this->glInterface())) {
|
| GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
| GR_GL_STENCIL_ATTACHMENT,
|
| - GR_GL_RENDERBUFFER, sbDesc.fRenderbufferID));
|
| + GR_GL_RENDERBUFFER, sbRBID));
|
| if (sFmt.fPacked) {
|
| GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
| GR_GL_DEPTH_ATTACHMENT,
|
| - GR_GL_RENDERBUFFER, sbDesc.fRenderbufferID));
|
| - }
|
| -
|
| - GL_CALL(ClearStencil(0));
|
| - // Many GL implementations seem to have trouble with clearing an FBO with only
|
| - // a stencil buffer.
|
| - GrGLuint tempRB;
|
| - GL_CALL(GenRenderbuffers(1, &tempRB));
|
| - GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, tempRB));
|
| - if (samples > 0) {
|
| - renderbuffer_storage_msaa(fGLContext, samples, GR_GL_RGBA8, width, height);
|
| + GR_GL_RENDERBUFFER, sbRBID));
|
| } else {
|
| - GL_CALL(RenderbufferStorage(GR_GL_RENDERBUFFER, GR_GL_RGBA8, width, height));
|
| - }
|
| - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
| - GR_GL_COLOR_ATTACHMENT0,
|
| - GR_GL_RENDERBUFFER, tempRB));
|
| -
|
| - GL_CALL(Clear(GR_GL_STENCIL_BUFFER_BIT));
|
| -
|
| - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
| - GR_GL_COLOR_ATTACHMENT0,
|
| - GR_GL_RENDERBUFFER, 0));
|
| - GL_CALL(DeleteRenderbuffers(1, &tempRB));
|
| -
|
| - // Unbind the SB from the FBO so that we don't keep it alive.
|
| - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
| - GR_GL_STENCIL_ATTACHMENT,
|
| - GR_GL_RENDERBUFFER, 0));
|
| - if (sFmt.fPacked) {
|
| GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
| GR_GL_DEPTH_ATTACHMENT,
|
| GR_GL_RENDERBUFFER, 0));
|
| }
|
| -#endif
|
| - return true;
|
| + GrGLenum status;
|
| + GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
|
| + if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
|
| + GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
| + GR_GL_STENCIL_ATTACHMENT,
|
| + GR_GL_RENDERBUFFER, 0));
|
| + if (sFmt.fPacked) {
|
| + GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
| + GR_GL_DEPTH_ATTACHMENT,
|
| + GR_GL_RENDERBUFFER, 0));
|
| + }
|
| + } else {
|
| + fPixelConfigToStencilIndex[config] = i;
|
| + break;
|
| + }
|
| }
|
| - // Remove the scratch key from this resource so we don't grab it from the cache ever
|
| - // again.
|
| - sb->resourcePriv().removeScratchKey();
|
| - // Set this to 0 since we handed the valid ID off to the failed stencil buffer resource.
|
| - sbDesc.fRenderbufferID = 0;
|
| + sbRBID = 0;
|
| }
|
| + GL_CALL(DeleteTextures(1, &colorID));
|
| + GL_CALL(DeleteRenderbuffers(1, &sbRBID));
|
| + GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, 0));
|
| + GL_CALL(DeleteFramebuffers(1, &fb));
|
| }
|
| - GL_CALL(DeleteRenderbuffers(1, &sbDesc.fRenderbufferID));
|
| - return false;
|
| + SkASSERT(kUnknownStencilIndex != fPixelConfigToStencilIndex[config]);
|
| + return fPixelConfigToStencilIndex[config];
|
| +}
|
| +
|
| +bool GrGLGpu::createStencilAttachmentForRenderTarget(GrRenderTarget* rt, int width, int height) {
|
| + // All internally created RTs are also textures. We don't create
|
| + // SBs for a client's standalone RT (that is a RT that isn't also a texture).
|
| + SkASSERT(rt->asTexture());
|
| + SkASSERT(width >= rt->width());
|
| + SkASSERT(height >= rt->height());
|
| +
|
| + int samples = rt->numStencilSamples();
|
| + GrGLStencilAttachment::IDDesc sbDesc;
|
| +
|
| + int sIdx = this->getCompatibleStencilIndex(rt->config());
|
| + if (sIdx == kUnsupportedStencilIndex) {
|
| + return false;
|
| + }
|
| +
|
| + if (!sbDesc.fRenderbufferID) {
|
| + GL_CALL(GenRenderbuffers(1, &sbDesc.fRenderbufferID));
|
| + }
|
| + if (!sbDesc.fRenderbufferID) {
|
| + return false;
|
| + }
|
| + GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, sbDesc.fRenderbufferID));
|
| + const GrGLCaps::StencilFormat& sFmt = this->glCaps().stencilFormats()[sIdx];
|
| + CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
|
| + // we do this "if" so that we don't call the multisample
|
| + // version on a GL that doesn't have an MSAA extension.
|
| + if (samples > 0) {
|
| + SkAssertResult(renderbuffer_storage_msaa(*fGLContext,
|
| + samples,
|
| + sFmt.fInternalFormat,
|
| + width, height));
|
| + } else {
|
| + GL_ALLOC_CALL(this->glInterface(), RenderbufferStorage(GR_GL_RENDERBUFFER,
|
| + sFmt.fInternalFormat,
|
| + width, height));
|
| + SkASSERT(GR_GL_NO_ERROR == check_alloc_error(rt->desc(), this->glInterface()));
|
| + }
|
| + fStats.incStencilAttachmentCreates();
|
| + // After sized formats we attempt an unsized format and take
|
| + // whatever sizes GL gives us. In that case we query for the size.
|
| + GrGLStencilAttachment::Format format = sFmt;
|
| + get_stencil_rb_sizes(this->glInterface(), &format);
|
| + SkAutoTUnref<GrGLStencilAttachment> sb(
|
| + new GrGLStencilAttachment(this, sbDesc, width, height, samples, format));
|
| + SkAssertResult(this->attachStencilAttachmentToRenderTarget(sb, rt));
|
| + rt->renderTargetPriv().didAttachStencilAttachment(sb);
|
| + // This work around is currently breaking on windows 7 hd2000 bot when we bind a color buffer
|
| +#if 0
|
| + // Clear the stencil buffer. We use a special purpose FBO for this so that the
|
| + // entire stencil buffer is cleared, even if it is attached to an FBO with a
|
| + // smaller color target.
|
| + if (0 == fStencilClearFBOID) {
|
| + GL_CALL(GenFramebuffers(1, &fStencilClearFBOID));
|
| + }
|
| +
|
| + GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, fStencilClearFBOID));
|
| + fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
|
| + fStats.incRenderTargetBinds();
|
| + GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
| + GR_GL_STENCIL_ATTACHMENT,
|
| + GR_GL_RENDERBUFFER, sbDesc.fRenderbufferID));
|
| + if (sFmt.fPacked) {
|
| + GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
| + GR_GL_DEPTH_ATTACHMENT,
|
| + GR_GL_RENDERBUFFER, sbDesc.fRenderbufferID));
|
| + }
|
| +
|
| + GL_CALL(ClearStencil(0));
|
| + // Many GL implementations seem to have trouble with clearing an FBO with only
|
| + // a stencil buffer.
|
| + GrGLuint tempRB;
|
| + GL_CALL(GenRenderbuffers(1, &tempRB));
|
| + GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, tempRB));
|
| + if (samples > 0) {
|
| + renderbuffer_storage_msaa(fGLContext, samples, GR_GL_RGBA8, width, height);
|
| + } else {
|
| + GL_CALL(RenderbufferStorage(GR_GL_RENDERBUFFER, GR_GL_RGBA8, width, height));
|
| + }
|
| + GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
| + GR_GL_COLOR_ATTACHMENT0,
|
| + GR_GL_RENDERBUFFER, tempRB));
|
| +
|
| + GL_CALL(Clear(GR_GL_STENCIL_BUFFER_BIT));
|
| +
|
| + GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
| + GR_GL_COLOR_ATTACHMENT0,
|
| + GR_GL_RENDERBUFFER, 0));
|
| + GL_CALL(DeleteRenderbuffers(1, &tempRB));
|
| +
|
| + // Unbind the SB from the FBO so that we don't keep it alive.
|
| + GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
| + GR_GL_STENCIL_ATTACHMENT,
|
| + GR_GL_RENDERBUFFER, 0));
|
| + if (sFmt.fPacked) {
|
| + GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
| + GR_GL_DEPTH_ATTACHMENT,
|
| + GR_GL_RENDERBUFFER, 0));
|
| + }
|
| +#endif
|
| + return true;
|
| }
|
|
|
| bool GrGLGpu::attachStencilAttachmentToRenderTarget(GrStencilAttachment* sb, GrRenderTarget* rt) {
|
| @@ -1325,25 +1439,11 @@ bool GrGLGpu::attachStencilAttachmentToRenderTarget(GrStencilAttachment* sb, GrR
|
| GR_GL_RENDERBUFFER, 0));
|
| }
|
|
|
| +#ifdef SK_DEBUG
|
| GrGLenum status;
|
| - if (!this->glCaps().isColorConfigAndStencilFormatVerified(rt->config(), glsb->format())) {
|
| - GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
|
| - if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
|
| - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
| - GR_GL_STENCIL_ATTACHMENT,
|
| - GR_GL_RENDERBUFFER, 0));
|
| - if (glsb->format().fPacked) {
|
| - GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
| - GR_GL_DEPTH_ATTACHMENT,
|
| - GR_GL_RENDERBUFFER, 0));
|
| - }
|
| - return false;
|
| - } else {
|
| - fGLContext->caps()->markColorConfigAndStencilFormatAsVerified(
|
| - rt->config(),
|
| - glsb->format());
|
| - }
|
| - }
|
| + GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
|
| + SkASSERT(GR_GL_FRAMEBUFFER_COMPLETE == status);
|
| +#endif
|
| return true;
|
| }
|
| }
|
|
|