Add GrStencilBuffer as a separate resource type from render target
This is a resubmission of the changes in r2026 with fixes for FBO completeness issues. Review URL: http://codereview.appspot.com/4837046/ git-svn-id: http://skia.googlecode.com/svn/trunk@2035 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
c49d66b04e
commit
81c3f8de1c
@ -19,6 +19,7 @@
|
||||
class GrContext;
|
||||
class GrIndexBufferAllocPool;
|
||||
class GrResource;
|
||||
class GrStencilBuffer;
|
||||
class GrVertexBufferAllocPool;
|
||||
|
||||
/**
|
||||
@ -313,12 +314,13 @@ public:
|
||||
|
||||
/**
|
||||
* Called to tell Gpu object that all GrResources have been lost and should
|
||||
* be abandoned.
|
||||
* be abandoned. Overrides must call INHERITED::abandonResources().
|
||||
*/
|
||||
virtual void abandonResources();
|
||||
|
||||
/**
|
||||
* Called to tell Gpu object to release all GrResources.
|
||||
* Called to tell Gpu object to release all GrResources. Overrides must call
|
||||
* INHERITED::releaseResources().
|
||||
*/
|
||||
void releaseResources();
|
||||
|
||||
@ -469,6 +471,16 @@ protected:
|
||||
int vertexCount,
|
||||
int indexCount) = 0;
|
||||
|
||||
// width and height may be larger than rt (if underlying API allows it).
|
||||
// Should attach the SB to the RT. Returns false if compatible sb could
|
||||
// not be created.
|
||||
virtual bool createStencilBufferForRenderTarget(GrRenderTarget* rt,
|
||||
int width,
|
||||
int height) = 0;
|
||||
|
||||
// attaches an existing SB to an existing RT.
|
||||
virtual bool attachStencilBufferToRenderTarget(GrStencilBuffer* sb,
|
||||
GrRenderTarget* rt) = 0;
|
||||
|
||||
// The GrGpu typically records the clients requested state and then flushes
|
||||
// deltas from previous state at draw time. This function does the
|
||||
@ -513,6 +525,9 @@ private:
|
||||
|
||||
GrResource* fResourceHead;
|
||||
|
||||
// Given a rt, find or create a stencil buffer and attach it
|
||||
bool attachStencilBufferToRenderTarget(GrRenderTarget* target);
|
||||
|
||||
// GrDrawTarget overrides
|
||||
virtual void onDrawIndexed(GrPrimitiveType type,
|
||||
int startVertex,
|
||||
|
@ -18,10 +18,10 @@
|
||||
#ifndef GrRenderTarget_DEFINED
|
||||
#define GrRenderTarget_DEFINED
|
||||
|
||||
#include "GrClip.h"
|
||||
#include "GrRect.h"
|
||||
#include "GrResource.h"
|
||||
|
||||
class GrStencilBuffer;
|
||||
class GrTexture;
|
||||
|
||||
/**
|
||||
@ -50,11 +50,6 @@ public:
|
||||
*/
|
||||
int config() const { return fConfig; }
|
||||
|
||||
/**
|
||||
* @return the number of stencil bits in the rendertarget
|
||||
*/
|
||||
int stencilBits() const { return fStencilBits; }
|
||||
|
||||
/**
|
||||
* @return the texture associated with the rendertarget, may be NULL.
|
||||
*/
|
||||
@ -145,20 +140,25 @@ public:
|
||||
};
|
||||
virtual ResolveType getResolveType() const = 0;
|
||||
|
||||
/**
|
||||
* GrStencilBuffer is not part of the public API.
|
||||
*/
|
||||
GrStencilBuffer* getStencilBuffer() const { return fStencilBuffer; }
|
||||
void setStencilBuffer(GrStencilBuffer* stencilBuffer);
|
||||
|
||||
protected:
|
||||
GrRenderTarget(GrGpu* gpu,
|
||||
GrTexture* texture,
|
||||
int width,
|
||||
int height,
|
||||
GrPixelConfig config,
|
||||
int stencilBits,
|
||||
int sampleCnt)
|
||||
: INHERITED(gpu)
|
||||
, fStencilBuffer(NULL)
|
||||
, fTexture(texture)
|
||||
, fWidth(width)
|
||||
, fHeight(height)
|
||||
, fConfig(config)
|
||||
, fStencilBits(stencilBits)
|
||||
, fSampleCnt(sampleCnt)
|
||||
{
|
||||
fResolveRect.setLargestInverted();
|
||||
@ -175,20 +175,16 @@ protected:
|
||||
fTexture = NULL;
|
||||
}
|
||||
|
||||
GrStencilBuffer* fStencilBuffer;
|
||||
|
||||
private:
|
||||
GrTexture* fTexture; // not ref'ed
|
||||
GrTexture* fTexture; // not ref'ed
|
||||
int fWidth;
|
||||
int fHeight;
|
||||
GrPixelConfig fConfig;
|
||||
int fStencilBits;
|
||||
int fSampleCnt;
|
||||
GrIRect fResolveRect;
|
||||
|
||||
// GrGpu keeps a cached clip in the render target to avoid redundantly
|
||||
// rendering the clip into the same stencil buffer.
|
||||
friend class GrGpu;
|
||||
GrClip fLastStencilClip;
|
||||
|
||||
typedef GrResource INHERITED;
|
||||
};
|
||||
|
||||
|
@ -19,7 +19,6 @@ void GrGLRenderTarget::init(const Desc& desc,
|
||||
fRTFBOID = desc.fRTFBOID;
|
||||
fTexFBOID = desc.fTexFBOID;
|
||||
fMSColorRenderbufferID = desc.fMSColorRenderbufferID;
|
||||
fStencilRenderbufferID = desc.fStencilRenderbufferID;
|
||||
fViewport = viewport;
|
||||
fOwnIDs = desc.fOwnIDs;
|
||||
fTexIDObj = texID;
|
||||
@ -32,8 +31,7 @@ GrGLRenderTarget::GrGLRenderTarget(GrGpuGL* gpu,
|
||||
GrGLTexID* texID,
|
||||
GrGLTexture* texture)
|
||||
: INHERITED(gpu, texture, viewport.fWidth,
|
||||
viewport.fHeight, desc.fConfig,
|
||||
desc.fStencilBits, desc.fSampleCnt) {
|
||||
viewport.fHeight, desc.fConfig, desc.fSampleCnt) {
|
||||
GrAssert(NULL != texID);
|
||||
GrAssert(NULL != texture);
|
||||
// FBO 0 can't also be a texture, right?
|
||||
@ -46,8 +44,7 @@ GrGLRenderTarget::GrGLRenderTarget(GrGpuGL* gpu,
|
||||
const Desc& desc,
|
||||
const GrGLIRect& viewport)
|
||||
: INHERITED(gpu, NULL, viewport.fWidth,
|
||||
viewport.fHeight, desc.fConfig,
|
||||
desc.fStencilBits, desc.fSampleCnt) {
|
||||
viewport.fHeight, desc.fConfig, desc.fSampleCnt) {
|
||||
this->init(desc, viewport, NULL);
|
||||
}
|
||||
|
||||
@ -60,29 +57,26 @@ void GrGLRenderTarget::onRelease() {
|
||||
if (fRTFBOID && fRTFBOID != fTexFBOID) {
|
||||
GR_GL(DeleteFramebuffers(1, &fRTFBOID));
|
||||
}
|
||||
if (fStencilRenderbufferID) {
|
||||
GR_GL(DeleteRenderbuffers(1, &fStencilRenderbufferID));
|
||||
}
|
||||
if (fMSColorRenderbufferID) {
|
||||
GR_GL(DeleteRenderbuffers(1, &fMSColorRenderbufferID));
|
||||
}
|
||||
}
|
||||
fRTFBOID = 0;
|
||||
fTexFBOID = 0;
|
||||
fStencilRenderbufferID = 0;
|
||||
fMSColorRenderbufferID = 0;
|
||||
GrSafeUnref(fTexIDObj);
|
||||
fTexIDObj = NULL;
|
||||
GrSafeSetNull(fStencilBuffer);
|
||||
}
|
||||
|
||||
void GrGLRenderTarget::onAbandon() {
|
||||
fRTFBOID = 0;
|
||||
fTexFBOID = 0;
|
||||
fStencilRenderbufferID = 0;
|
||||
fMSColorRenderbufferID = 0;
|
||||
if (NULL != fTexIDObj) {
|
||||
fTexIDObj->abandon();
|
||||
fTexIDObj = NULL;
|
||||
}
|
||||
GrSafeSetNull(fStencilBuffer);
|
||||
}
|
||||
|
||||
|
@ -28,11 +28,9 @@ public:
|
||||
struct Desc {
|
||||
GrGLuint fRTFBOID;
|
||||
GrGLuint fTexFBOID;
|
||||
GrGLuint fStencilRenderbufferID;
|
||||
GrGLuint fMSColorRenderbufferID;
|
||||
bool fOwnIDs;
|
||||
GrPixelConfig fConfig;
|
||||
int fStencilBits;
|
||||
int fSampleCnt;
|
||||
};
|
||||
|
||||
@ -87,7 +85,7 @@ protected:
|
||||
private:
|
||||
GrGLuint fRTFBOID;
|
||||
GrGLuint fTexFBOID;
|
||||
GrGLuint fStencilRenderbufferID;
|
||||
|
||||
GrGLuint fMSColorRenderbufferID;
|
||||
|
||||
// Should this object delete IDs when it is destroyed or does someone
|
||||
|
72
gpu/src/GrGLStencilBuffer.h
Normal file
72
gpu/src/GrGLStencilBuffer.h
Normal file
@ -0,0 +1,72 @@
|
||||
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GrGLStencilBuffer_DEFINED
|
||||
#define GrGLStencilBuffer_DEFINED
|
||||
|
||||
#include "GrGLInterface.h"
|
||||
#include "GrStencilBuffer.h"
|
||||
|
||||
class GrGLStencilBuffer : public GrStencilBuffer {
|
||||
public:
|
||||
static const GrGLenum kUnknownInternalFormat = ~0;
|
||||
struct Format {
|
||||
GrGLenum fInternalFormat;
|
||||
GrGLuint fStencilBits;
|
||||
GrGLuint fTotalBits;
|
||||
bool fPacked;
|
||||
};
|
||||
|
||||
GrGLStencilBuffer(GrGpu* gpu, GrGLint rbid,
|
||||
int width, int height,
|
||||
const Format& format)
|
||||
: GrStencilBuffer(gpu, width, height, format.fStencilBits)
|
||||
, fFormat(format)
|
||||
, fRenderbufferID(rbid) {
|
||||
}
|
||||
|
||||
virtual ~GrGLStencilBuffer() {
|
||||
this->release();
|
||||
}
|
||||
|
||||
virtual size_t sizeInBytes() const {
|
||||
return this->width() * this->height() * fFormat.fTotalBits;
|
||||
}
|
||||
|
||||
GrGLuint renderbufferID() const {
|
||||
return fRenderbufferID;
|
||||
}
|
||||
|
||||
const Format& format() const {
|
||||
return fFormat;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void onRelease() {
|
||||
if (0 != fRenderbufferID) {
|
||||
GR_GL(DeleteRenderbuffers(1, &fRenderbufferID));
|
||||
fRenderbufferID = 0;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void onAbandon() {
|
||||
fRenderbufferID = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
Format fFormat;
|
||||
// may be zero for external SBs associated with external RTs
|
||||
// (we don't require the client to give us the id, just tell
|
||||
// us how many bits of stencil there are).
|
||||
GrGLuint fRenderbufferID;
|
||||
|
||||
typedef GrStencilBuffer INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
@ -8,12 +8,12 @@
|
||||
|
||||
|
||||
#include "GrGpu.h"
|
||||
#include "GrTextStrike.h"
|
||||
#include "GrBufferAllocPool.h"
|
||||
#include "GrClipIterator.h"
|
||||
#include "GrIndexBuffer.h"
|
||||
#include "GrVertexBuffer.h"
|
||||
#include "GrBufferAllocPool.h"
|
||||
#include "GrPathRenderer.h"
|
||||
#include "GrGLStencilBuffer.h"
|
||||
#include "GrVertexBuffer.h"
|
||||
|
||||
// probably makes no sense for this to be less than a page
|
||||
static const size_t VERTEX_POOL_VB_SIZE = 1 << 18;
|
||||
@ -140,7 +140,24 @@ void GrGpu::unimpl(const char msg[]) {
|
||||
GrTexture* GrGpu::createTexture(const GrTextureDesc& desc,
|
||||
const void* srcData, size_t rowBytes) {
|
||||
this->handleDirtyContext();
|
||||
return this->onCreateTexture(desc, srcData, rowBytes);
|
||||
GrTexture* tex = this->onCreateTexture(desc, srcData, rowBytes);
|
||||
if (NULL != tex &&
|
||||
(kRenderTarget_GrTextureFlagBit & desc.fFlags) &&
|
||||
!(kNoStencil_GrTextureFlagBit & desc.fFlags)) {
|
||||
GrAssert(NULL != tex->asRenderTarget());
|
||||
// TODO: defer this and attach dynamically
|
||||
if (!this->attachStencilBufferToRenderTarget(tex->asRenderTarget())) {
|
||||
tex->unref();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return tex;
|
||||
}
|
||||
|
||||
bool GrGpu::attachStencilBufferToRenderTarget(GrRenderTarget* rt) {
|
||||
// TODO: use a cache of stencil buffers rather than create per-rt.
|
||||
return this->createStencilBufferForRenderTarget(rt, rt->width(),
|
||||
rt->height());
|
||||
}
|
||||
|
||||
GrRenderTarget* GrGpu::createRenderTargetFrom3DApiState() {
|
||||
@ -398,14 +415,22 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
|
||||
fClipInStencil = !fClip.isRect() && !fClip.isEmpty() &&
|
||||
!bounds.isEmpty();
|
||||
|
||||
if (fClipInStencil &&
|
||||
fClip != rt.fLastStencilClip) {
|
||||
// TODO: dynamically attach a SB when needed.
|
||||
GrStencilBuffer* stencilBuffer = rt.getStencilBuffer();
|
||||
if (fClipInStencil && NULL == stencilBuffer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fClipInStencil &&
|
||||
stencilBuffer->mustRenderClip(fClip, rt.width(), rt.height())) {
|
||||
|
||||
stencilBuffer->setLastClip(fClip, rt.width(), rt.height());
|
||||
|
||||
rt.fLastStencilClip = fClip;
|
||||
// we set the current clip to the bounds so that our recursive
|
||||
// draws are scissored to them. We use the copy of the complex clip
|
||||
// in the rt to render
|
||||
const GrClip& clip = rt.fLastStencilClip;
|
||||
// we just stashed on the SB to render from. We set it back after
|
||||
// we finish drawing it into the stencil.
|
||||
const GrClip& clip = stencilBuffer->getLastClip();
|
||||
fClip.setFromRect(bounds);
|
||||
|
||||
AutoStateRestore asr(this);
|
||||
@ -420,7 +445,7 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
|
||||
this->disableState(kNoColorWrites_StateBit);
|
||||
#endif
|
||||
int count = clip.getElementCount();
|
||||
int clipBit = rt.stencilBits();
|
||||
int clipBit = stencilBuffer->bits();
|
||||
clipBit = (1 << (clipBit-1));
|
||||
|
||||
// often we'll see the first two elements of the clip are
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
|
||||
#include "GrGpuGL.h"
|
||||
#include "GrGLStencilBuffer.h"
|
||||
#include "GrTypes.h"
|
||||
#include "SkTemplates.h"
|
||||
|
||||
@ -515,9 +516,14 @@ GrGpuGL::GrGpuGL()
|
||||
}
|
||||
|
||||
fLastSuccessfulStencilFmtIdx = 0;
|
||||
|
||||
fStencilClearFBO = 0;
|
||||
}
|
||||
|
||||
GrGpuGL::~GrGpuGL() {
|
||||
if (fStencilClearFBO) {
|
||||
GR_GL(DeleteFramebuffers(1, &fStencilClearFBO));
|
||||
}
|
||||
}
|
||||
|
||||
void GrGpuGL::resetContext() {
|
||||
@ -589,6 +595,21 @@ void GrGpuGL::resetContext() {
|
||||
fHWDrawState.fRenderTarget = NULL;
|
||||
}
|
||||
|
||||
void GrGpuGL::abandonResources() {
|
||||
INHERITED::abandonResources();
|
||||
|
||||
fStencilClearFBO = 0;
|
||||
}
|
||||
|
||||
void GrGpuGL::releaseResources() {
|
||||
INHERITED::releaseResources();
|
||||
|
||||
if (fStencilClearFBO) {
|
||||
GR_GL(DeleteFramebuffers(1, &fStencilClearFBO));
|
||||
fStencilClearFBO = 0;
|
||||
}
|
||||
}
|
||||
|
||||
GrResource* GrGpuGL::onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc) {
|
||||
|
||||
bool isTexture = kTexture_GrPlatformSurfaceType == desc.fSurfaceType ||
|
||||
@ -597,6 +618,8 @@ GrResource* GrGpuGL::onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc)
|
||||
kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType;
|
||||
|
||||
GrGLRenderTarget::Desc rtDesc;
|
||||
GrGLStencilBuffer* sb = NULL;
|
||||
|
||||
if (isRenderTarget) {
|
||||
rtDesc.fRTFBOID = desc.fPlatformRenderTarget;
|
||||
#if GR_USE_PLATFORM_CREATE_SAMPLE_COUNT
|
||||
@ -615,7 +638,6 @@ GrResource* GrGpuGL::onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc)
|
||||
}
|
||||
// we don't know what the RB ids are without glGets and we don't care
|
||||
// since we aren't responsible for deleting them.
|
||||
rtDesc.fStencilRenderbufferID = 0;
|
||||
rtDesc.fMSColorRenderbufferID = 0;
|
||||
#if GR_USE_PLATFORM_CREATE_SAMPLE_COUNT
|
||||
rtDesc.fSampleCnt = desc.fSampleCnt;
|
||||
@ -629,7 +651,15 @@ GrResource* GrGpuGL::onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc)
|
||||
rtDesc.fSampleCnt = 0;
|
||||
}
|
||||
#endif
|
||||
rtDesc.fStencilBits = desc.fStencilBits;
|
||||
if (desc.fStencilBits) {
|
||||
GrGLStencilBuffer::Format format;
|
||||
format.fInternalFormat = GrGLStencilBuffer::kUnknownInternalFormat;
|
||||
format.fPacked = false;
|
||||
format.fStencilBits = desc.fStencilBits;
|
||||
format.fTotalBits = desc.fStencilBits;
|
||||
sb = new GrGLStencilBuffer(this, 0, desc.fWidth,
|
||||
desc.fHeight, format);
|
||||
}
|
||||
rtDesc.fOwnIDs = false;
|
||||
}
|
||||
|
||||
@ -655,7 +685,9 @@ GrResource* GrGpuGL::onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc)
|
||||
|
||||
params.invalidate(); // rather than do glGets.
|
||||
if (isRenderTarget) {
|
||||
return new GrGLTexture(this, texDesc, rtDesc, params);
|
||||
GrTexture* tex = new GrGLTexture(this, texDesc, rtDesc, params);
|
||||
tex->asRenderTarget()->setStencilBuffer(sb);
|
||||
return tex;
|
||||
} else {
|
||||
return new GrGLTexture(this, texDesc, params);
|
||||
}
|
||||
@ -666,7 +698,9 @@ GrResource* GrGpuGL::onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc)
|
||||
viewport.fWidth = desc.fWidth;
|
||||
viewport.fHeight = desc.fHeight;
|
||||
|
||||
return new GrGLRenderTarget(this, rtDesc, viewport);
|
||||
GrGLRenderTarget* rt = new GrGLRenderTarget(this, rtDesc, viewport);
|
||||
rt->setStencilBuffer(sb);
|
||||
return rt;
|
||||
}
|
||||
}
|
||||
|
||||
@ -815,14 +849,25 @@ GrRenderTarget* GrGpuGL::onCreateRenderTargetFrom3DApiState() {
|
||||
GR_GL_GetIntegerv(GR_GL_FRAMEBUFFER_BINDING, (GrGLint*)&rtDesc.fRTFBOID);
|
||||
rtDesc.fTexFBOID = rtDesc.fRTFBOID;
|
||||
rtDesc.fMSColorRenderbufferID = 0;
|
||||
rtDesc.fStencilRenderbufferID = 0;
|
||||
|
||||
bool arbFBO = (GR_GL_SUPPORT_DESKTOP && (fGLVersion > 3.0 ||
|
||||
this->hasExtension("GL_ARB_framebuffer_object")));
|
||||
|
||||
GrGLIRect viewport;
|
||||
viewport.setFromGLViewport();
|
||||
rtDesc.fStencilBits = get_fbo_stencil_bits(arbFBO);
|
||||
int stencilBits = get_fbo_stencil_bits(arbFBO);
|
||||
|
||||
GrGLStencilBuffer* sb = NULL;
|
||||
if (stencilBits) {
|
||||
GrGLStencilBuffer::Format format;
|
||||
// we could query this but we don't really need it
|
||||
format.fInternalFormat = GrGLStencilBuffer::kUnknownInternalFormat;
|
||||
format.fPacked = false;
|
||||
format.fStencilBits = stencilBits;
|
||||
format.fTotalBits = stencilBits;
|
||||
sb = new GrGLStencilBuffer(this, 0, viewport.fWidth,
|
||||
viewport.fHeight, format);
|
||||
}
|
||||
|
||||
GR_GL_GetIntegerv(GR_GL_SAMPLES, &rtDesc.fSampleCnt);
|
||||
GrGLenum fmat = get_fbo_color_format();
|
||||
@ -837,10 +882,13 @@ GrRenderTarget* GrGpuGL::onCreateRenderTargetFrom3DApiState() {
|
||||
|
||||
rtDesc.fOwnIDs = false;
|
||||
|
||||
return new GrGLRenderTarget(this, rtDesc, viewport);
|
||||
GrGLRenderTarget* target = new GrGLRenderTarget(this, rtDesc, viewport);
|
||||
target->setStencilBuffer(sb);
|
||||
return target;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
static const GrGLuint kUnknownBitCount = ~0;
|
||||
|
||||
void GrGpuGL::setupStencilFormats() {
|
||||
|
||||
@ -849,12 +897,14 @@ void GrGpuGL::setupStencilFormats() {
|
||||
|
||||
// these consts are in order of most preferred to least preferred
|
||||
// we don't bother with GL_STENCIL_INDEX1 or GL_DEPTH32F_STENCIL8
|
||||
static const StencilFormat gS8 = {GR_GL_STENCIL_INDEX8, 8, false};
|
||||
static const StencilFormat gS16 = {GR_GL_STENCIL_INDEX16, 16, false};
|
||||
static const StencilFormat gD24S8 = {GR_GL_DEPTH24_STENCIL8, 8, true };
|
||||
static const StencilFormat gS4 = {GR_GL_STENCIL_INDEX4, 4, false};
|
||||
static const StencilFormat gS = {GR_GL_STENCIL_INDEX, gUNKNOWN_BITCOUNT, false};
|
||||
static const StencilFormat gDS = {GR_GL_DEPTH_STENCIL, gUNKNOWN_BITCOUNT, true };
|
||||
static const GrGLStencilBuffer::Format
|
||||
// internal Format stencil bits total bits packed?
|
||||
gS8 = {GR_GL_STENCIL_INDEX8, 8, 8, false},
|
||||
gS16 = {GR_GL_STENCIL_INDEX16, 16, 16, false},
|
||||
gD24S8 = {GR_GL_DEPTH24_STENCIL8, 8, 32, true },
|
||||
gS4 = {GR_GL_STENCIL_INDEX4, 4, 4, false},
|
||||
gS = {GR_GL_STENCIL_INDEX, kUnknownBitCount, kUnknownBitCount, false},
|
||||
gDS = {GR_GL_DEPTH_STENCIL, kUnknownBitCount, kUnknownBitCount, true };
|
||||
|
||||
if (GR_GL_SUPPORT_DESKTOP) {
|
||||
bool supportsPackedDS = fGLVersion >= 3.0f ||
|
||||
@ -1036,6 +1086,86 @@ void GrGpuGL::allocateAndUploadTexData(const GrGLTexture::Desc& desc,
|
||||
}
|
||||
}
|
||||
|
||||
bool GrGpuGL::createRenderTargetObjects(int width, int height,
|
||||
GrGLuint texID,
|
||||
GrGLRenderTarget::Desc* desc) {
|
||||
desc->fMSColorRenderbufferID = 0;
|
||||
desc->fRTFBOID = 0;
|
||||
desc->fTexFBOID = 0;
|
||||
desc->fOwnIDs = true;
|
||||
|
||||
GrGLenum status;
|
||||
GrGLint err;
|
||||
|
||||
GR_GL(GenFramebuffers(1, &desc->fTexFBOID));
|
||||
if (!desc->fTexFBOID) {
|
||||
goto FAILED;
|
||||
}
|
||||
|
||||
GrGLenum msColorFormat;
|
||||
|
||||
// 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 && kNone_MSFBO != fMSFBOType) {
|
||||
GR_GL(GenFramebuffers(1, &desc->fRTFBOID));
|
||||
GR_GL(GenRenderbuffers(1, &desc->fMSColorRenderbufferID));
|
||||
if (!desc->fRTFBOID ||
|
||||
!desc->fMSColorRenderbufferID ||
|
||||
!this->fboInternalFormat(desc->fConfig, &msColorFormat)) {
|
||||
goto FAILED;
|
||||
}
|
||||
} else {
|
||||
desc->fRTFBOID = desc->fTexFBOID;
|
||||
}
|
||||
|
||||
if (desc->fRTFBOID != desc->fTexFBOID) {
|
||||
GrAssert(desc->fSampleCnt > 1);
|
||||
GR_GL(BindRenderbuffer(GR_GL_RENDERBUFFER,
|
||||
desc->fMSColorRenderbufferID));
|
||||
GR_GL_NO_ERR(RenderbufferStorageMultisample(GR_GL_RENDERBUFFER,
|
||||
desc->fSampleCnt,
|
||||
msColorFormat,
|
||||
width, height));
|
||||
err = GrGLGetGLInterface()->fGetError();
|
||||
if (err != GR_GL_NO_ERROR) {
|
||||
goto FAILED;
|
||||
}
|
||||
GR_GL(BindFramebuffer(GR_GL_FRAMEBUFFER, desc->fRTFBOID));
|
||||
GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
||||
GR_GL_COLOR_ATTACHMENT0,
|
||||
GR_GL_RENDERBUFFER,
|
||||
desc->fMSColorRenderbufferID));
|
||||
GrGLenum status = GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
|
||||
if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
|
||||
goto FAILED;
|
||||
}
|
||||
}
|
||||
GR_GL(BindFramebuffer(GR_GL_FRAMEBUFFER, desc->fTexFBOID));
|
||||
|
||||
GR_GL(FramebufferTexture2D(GR_GL_FRAMEBUFFER,
|
||||
GR_GL_COLOR_ATTACHMENT0,
|
||||
GR_GL_TEXTURE_2D,
|
||||
texID, 0));
|
||||
status = GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
|
||||
if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
|
||||
goto FAILED;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
FAILED:
|
||||
if (desc->fMSColorRenderbufferID) {
|
||||
GR_GL(DeleteRenderbuffers(1, &desc->fMSColorRenderbufferID));
|
||||
}
|
||||
if (desc->fRTFBOID != desc->fTexFBOID) {
|
||||
GR_GL(DeleteFramebuffers(1, &desc->fRTFBOID));
|
||||
}
|
||||
if (desc->fTexFBOID) {
|
||||
GR_GL(DeleteFramebuffers(1, &desc->fTexFBOID));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// good to set a break-point here to know when createTexture fails
|
||||
static GrTexture* return_null_texture() {
|
||||
// GrAssert(!"null texture");
|
||||
@ -1073,7 +1203,6 @@ GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc,
|
||||
glTexDesc.fFormat = desc.fFormat;
|
||||
glTexDesc.fOwnsID = true;
|
||||
|
||||
glRTDesc.fStencilRenderbufferID = 0;
|
||||
glRTDesc.fMSColorRenderbufferID = 0;
|
||||
glRTDesc.fRTFBOID = 0;
|
||||
glRTDesc.fTexFBOID = 0;
|
||||
@ -1092,7 +1221,7 @@ GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc,
|
||||
// can be drawn to by the outside world without the client having
|
||||
// to render upside down.
|
||||
glTexDesc.fOrientation = renderTarget ? GrGLTexture::kBottomUp_Orientation :
|
||||
GrGLTexture::kTopDown_Orientation;
|
||||
GrGLTexture::kTopDown_Orientation;
|
||||
|
||||
GrAssert(as_size_t(desc.fAALevel) < GR_ARRAY_COUNT(fAASamples));
|
||||
glRTDesc.fSampleCnt = fAASamples[desc.fAALevel];
|
||||
@ -1109,9 +1238,9 @@ GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc,
|
||||
}
|
||||
|
||||
glTexDesc.fAllocWidth = GrMax(fMinRenderTargetWidth,
|
||||
glTexDesc.fAllocWidth);
|
||||
glTexDesc.fAllocWidth);
|
||||
glTexDesc.fAllocHeight = GrMax(fMinRenderTargetHeight,
|
||||
glTexDesc.fAllocHeight);
|
||||
glTexDesc.fAllocHeight);
|
||||
if (glTexDesc.fAllocWidth > fMaxRenderTargetSize ||
|
||||
glTexDesc.fAllocHeight > fMaxRenderTargetSize) {
|
||||
return return_null_texture();
|
||||
@ -1147,198 +1276,220 @@ GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc,
|
||||
|
||||
this->allocateAndUploadTexData(glTexDesc, internalFormat,srcData, rowBytes);
|
||||
|
||||
GrGLTexture* tex;
|
||||
if (renderTarget) {
|
||||
GrGLenum msColorRenderbufferFormat = -1;
|
||||
#if GR_COLLECT_STATS
|
||||
++fStats.fRenderTargetCreateCnt;
|
||||
#endif
|
||||
bool failed = true;
|
||||
GrGLenum status;
|
||||
GrGLint err;
|
||||
|
||||
GR_GL(GenFramebuffers(1, &glRTDesc.fTexFBOID));
|
||||
GrAssert(glRTDesc.fTexFBOID);
|
||||
|
||||
// If we are using multisampling and we will create two FBOS We render
|
||||
// to one and then resolve to the texture bound to the other.
|
||||
if (glRTDesc.fSampleCnt > 0 && kNone_MSFBO != fMSFBOType) {
|
||||
GR_GL(GenFramebuffers(1, &glRTDesc.fRTFBOID));
|
||||
GrAssert(0 != glRTDesc.fRTFBOID);
|
||||
GR_GL(GenRenderbuffers(1, &glRTDesc.fMSColorRenderbufferID));
|
||||
GrAssert(0 != glRTDesc.fMSColorRenderbufferID);
|
||||
if (!fboInternalFormat(desc.fFormat, &msColorRenderbufferFormat)) {
|
||||
GR_GL(DeleteRenderbuffers(1, &glRTDesc.fMSColorRenderbufferID));
|
||||
GR_GL(DeleteTextures(1, &glTexDesc.fTextureID));
|
||||
GR_GL(DeleteFramebuffers(1, &glRTDesc.fTexFBOID));
|
||||
GR_GL(DeleteFramebuffers(1, &glRTDesc.fRTFBOID));
|
||||
return return_null_texture();
|
||||
}
|
||||
} else {
|
||||
glRTDesc.fRTFBOID = glRTDesc.fTexFBOID;
|
||||
}
|
||||
if (!(kNoStencil_GrTextureFlagBit & desc.fFlags)) {
|
||||
GR_GL(GenRenderbuffers(1, &glRTDesc.fStencilRenderbufferID));
|
||||
GrAssert(0 != glRTDesc.fStencilRenderbufferID);
|
||||
}
|
||||
|
||||
// someone suggested that some systems might require
|
||||
// unbinding the texture before we call FramebufferTexture2D
|
||||
// (seems unlikely)
|
||||
GR_GL(BindTexture(GR_GL_TEXTURE_2D, 0));
|
||||
|
||||
err = ~GR_GL_NO_ERROR;
|
||||
|
||||
int stencilFmtCnt;
|
||||
if (glRTDesc.fStencilRenderbufferID) {
|
||||
stencilFmtCnt = fStencilFormats.count();
|
||||
} else {
|
||||
stencilFmtCnt = 1; // only 1 attempt when we don't need a stencil
|
||||
}
|
||||
|
||||
for (int i = 0; i < stencilFmtCnt; ++i) {
|
||||
// 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;
|
||||
|
||||
if (glRTDesc.fStencilRenderbufferID) {
|
||||
GR_GL(BindRenderbuffer(GR_GL_RENDERBUFFER,
|
||||
glRTDesc.fStencilRenderbufferID));
|
||||
if (glRTDesc.fSampleCnt > 0) {
|
||||
GR_GL_NO_ERR(RenderbufferStorageMultisample(
|
||||
GR_GL_RENDERBUFFER,
|
||||
glRTDesc.fSampleCnt,
|
||||
fStencilFormats[sIdx].fEnum,
|
||||
glTexDesc.fAllocWidth,
|
||||
glTexDesc.fAllocHeight));
|
||||
} else {
|
||||
GR_GL_NO_ERR(RenderbufferStorage(GR_GL_RENDERBUFFER,
|
||||
fStencilFormats[sIdx].fEnum,
|
||||
glTexDesc.fAllocWidth,
|
||||
glTexDesc.fAllocHeight));
|
||||
}
|
||||
err = GrGLGetGLInterface()->fGetError();
|
||||
if (err != GR_GL_NO_ERROR) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (glRTDesc.fRTFBOID != glRTDesc.fTexFBOID) {
|
||||
GrAssert(glRTDesc.fSampleCnt > 0);
|
||||
GR_GL(BindRenderbuffer(GR_GL_RENDERBUFFER,
|
||||
glRTDesc.fMSColorRenderbufferID));
|
||||
GR_GL_NO_ERR(RenderbufferStorageMultisample(
|
||||
GR_GL_RENDERBUFFER,
|
||||
glRTDesc.fSampleCnt,
|
||||
msColorRenderbufferFormat,
|
||||
glTexDesc.fAllocWidth,
|
||||
glTexDesc.fAllocHeight));
|
||||
err = GrGLGetGLInterface()->fGetError();
|
||||
if (err != GR_GL_NO_ERROR) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
GR_GL(BindFramebuffer(GR_GL_FRAMEBUFFER, glRTDesc.fTexFBOID));
|
||||
|
||||
#if GR_COLLECT_STATS
|
||||
++fStats.fRenderTargetChngCnt;
|
||||
#endif
|
||||
GR_GL(FramebufferTexture2D(GR_GL_FRAMEBUFFER,
|
||||
GR_GL_COLOR_ATTACHMENT0,
|
||||
GR_GL_TEXTURE_2D,
|
||||
glTexDesc.fTextureID, 0));
|
||||
if (glRTDesc.fRTFBOID != glRTDesc.fTexFBOID) {
|
||||
GrGLenum status = GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
|
||||
if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
|
||||
continue;
|
||||
}
|
||||
GR_GL(BindFramebuffer(GR_GL_FRAMEBUFFER, glRTDesc.fRTFBOID));
|
||||
#if GR_COLLECT_STATS
|
||||
++fStats.fRenderTargetChngCnt;
|
||||
#endif
|
||||
GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
||||
GR_GL_COLOR_ATTACHMENT0,
|
||||
GR_GL_RENDERBUFFER,
|
||||
glRTDesc.fMSColorRenderbufferID));
|
||||
|
||||
}
|
||||
if (glRTDesc.fStencilRenderbufferID) {
|
||||
// bind the stencil to rt fbo if present, othewise the tex fbo
|
||||
GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
||||
GR_GL_STENCIL_ATTACHMENT,
|
||||
GR_GL_RENDERBUFFER,
|
||||
glRTDesc.fStencilRenderbufferID));
|
||||
// if it is a packed format bind to depth also, otherwise
|
||||
// we may get an unsupported fbo completeness result
|
||||
if (fStencilFormats[sIdx].fPacked) {
|
||||
GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
||||
GR_GL_DEPTH_ATTACHMENT,
|
||||
GR_GL_RENDERBUFFER,
|
||||
glRTDesc.fStencilRenderbufferID));
|
||||
}
|
||||
}
|
||||
status = GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
|
||||
|
||||
if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
|
||||
// undo the depth bind
|
||||
if (glRTDesc.fStencilRenderbufferID &&
|
||||
fStencilFormats[sIdx].fPacked) {
|
||||
GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
||||
GR_GL_DEPTH_ATTACHMENT,
|
||||
GR_GL_RENDERBUFFER, 0));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// we're successful!
|
||||
failed = false;
|
||||
if (glRTDesc.fStencilRenderbufferID) {
|
||||
fLastSuccessfulStencilFmtIdx = sIdx;
|
||||
if (gUNKNOWN_BITCOUNT == fStencilFormats[sIdx].fBits) {
|
||||
GR_GL_GetIntegerv(GR_GL_STENCIL_BITS, (GrGLint*)&glRTDesc.fStencilBits);
|
||||
} else {
|
||||
glRTDesc.fStencilBits = fStencilFormats[sIdx].fBits;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (failed) {
|
||||
if (glRTDesc.fStencilRenderbufferID) {
|
||||
GR_GL(DeleteRenderbuffers(1, &glRTDesc.fStencilRenderbufferID));
|
||||
}
|
||||
if (glRTDesc.fMSColorRenderbufferID) {
|
||||
GR_GL(DeleteRenderbuffers(1, &glRTDesc.fMSColorRenderbufferID));
|
||||
}
|
||||
if (glRTDesc.fRTFBOID != glRTDesc.fTexFBOID) {
|
||||
GR_GL(DeleteFramebuffers(1, &glRTDesc.fRTFBOID));
|
||||
}
|
||||
if (glRTDesc.fTexFBOID) {
|
||||
GR_GL(DeleteFramebuffers(1, &glRTDesc.fTexFBOID));
|
||||
}
|
||||
if (!this->createRenderTargetObjects(glTexDesc.fAllocWidth,
|
||||
glTexDesc.fAllocHeight,
|
||||
glTexDesc.fTextureID,
|
||||
&glRTDesc)) {
|
||||
GR_GL(DeleteTextures(1, &glTexDesc.fTextureID));
|
||||
return return_null_texture();
|
||||
}
|
||||
tex = new GrGLTexture(this, glTexDesc, glRTDesc, DEFAULT_PARAMS);
|
||||
} else {
|
||||
tex = new GrGLTexture(this, glTexDesc, DEFAULT_PARAMS);
|
||||
}
|
||||
#ifdef TRACE_TEXTURE_CREATION
|
||||
GrPrintf("--- new texture [%d] size=(%d %d) bpp=%d\n",
|
||||
tex->fTextureID, width, height, tex->fUploadByteCount);
|
||||
#endif
|
||||
if (renderTarget) {
|
||||
GrGLTexture* tex = new GrGLTexture(this, glTexDesc,
|
||||
glRTDesc, DEFAULT_PARAMS);
|
||||
GrRenderTarget* rt = tex->asRenderTarget();
|
||||
// We've messed with FBO state but may not have set the correct viewport
|
||||
// so just dirty the rendertarget state to force a resend.
|
||||
return tex;
|
||||
}
|
||||
|
||||
namespace {
|
||||
void inline get_stencil_rb_sizes(GrGLuint rb, GrGLStencilBuffer::Format* format) {
|
||||
// we shouldn't ever know one size and not the other
|
||||
GrAssert((kUnknownBitCount == format->fStencilBits) ==
|
||||
(kUnknownBitCount == format->fTotalBits));
|
||||
if (kUnknownBitCount == format->fStencilBits) {
|
||||
GR_GL_GetRenderbufferParameteriv(GR_GL_RENDERBUFFER,
|
||||
GR_GL_RENDERBUFFER_STENCIL_SIZE,
|
||||
(GrGLint*)&format->fStencilBits);
|
||||
if (format->fPacked) {
|
||||
GR_GL_GetRenderbufferParameteriv(GR_GL_RENDERBUFFER,
|
||||
GR_GL_RENDERBUFFER_DEPTH_SIZE,
|
||||
(GrGLint*)&format->fTotalBits);
|
||||
format->fTotalBits += format->fStencilBits;
|
||||
} else {
|
||||
format->fTotalBits = format->fStencilBits;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GrGpuGL::createStencilBufferForRenderTarget(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 RT that isnt also a texture).
|
||||
GrAssert(rt->asTexture());
|
||||
// if this thing is bloated for NPOT reasons we'll have to bloat the SB
|
||||
// as well.
|
||||
GrGLTexture* tex = (GrGLTexture*) rt->asTexture();
|
||||
width = GrMax(width, tex->allocWidth());
|
||||
height = GrMax(height, tex->allocWidth());
|
||||
|
||||
int samples = rt->numSamples();
|
||||
GrGLuint sbID;
|
||||
GR_GL(GenRenderbuffers(1, &sbID));
|
||||
if (!sbID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GrGLStencilBuffer* sb = NULL;
|
||||
|
||||
int stencilFmtCnt = fStencilFormats.count();
|
||||
for (int i = 0; i < stencilFmtCnt; ++i) {
|
||||
GR_GL(BindRenderbuffer(GR_GL_RENDERBUFFER, sbID));
|
||||
// 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;
|
||||
// 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 > 1) {
|
||||
GR_GL_NO_ERR(RenderbufferStorageMultisample(
|
||||
GR_GL_RENDERBUFFER,
|
||||
samples,
|
||||
fStencilFormats[sIdx].fInternalFormat,
|
||||
width,
|
||||
height));
|
||||
} else {
|
||||
GR_GL_NO_ERR(RenderbufferStorage(GR_GL_RENDERBUFFER,
|
||||
fStencilFormats[sIdx].fInternalFormat,
|
||||
width, height));
|
||||
}
|
||||
|
||||
GrGLenum err = GrGLGetGLInterface()->fGetError();
|
||||
if (err == GR_GL_NO_ERROR) {
|
||||
// After sized formats we attempt an unsized format and take whatever
|
||||
// sizes GL gives us. In that case we query for the size.
|
||||
GrGLStencilBuffer::Format format = fStencilFormats[sIdx];
|
||||
get_stencil_rb_sizes(sbID, &format);
|
||||
sb = new GrGLStencilBuffer(this, sbID, width, height, format);
|
||||
if (this->attachStencilBufferToRenderTarget(sb, rt)) {
|
||||
fLastSuccessfulStencilFmtIdx = sIdx;
|
||||
sb->unref();
|
||||
fHWDrawState.fRenderTarget = NULL;
|
||||
// initial clear zeros the entire sb by attaching it alone
|
||||
// to an fbo (that we create here on demand).
|
||||
if (!fStencilClearFBO) {
|
||||
GR_GL(GenFramebuffers(1, &fStencilClearFBO));
|
||||
if (0 == fStencilClearFBO) {
|
||||
rt->setStencilBuffer(NULL);
|
||||
return false;
|
||||
}
|
||||
GR_GL(BindFramebuffer(GR_GL_FRAMEBUFFER, fStencilClearFBO));
|
||||
if (GR_GL_SUPPORT_DESKTOP) {
|
||||
// We won't be binding a color buffer, set the draw
|
||||
// buffer to NONE to avoid
|
||||
// FRAMEBUFFER_INCOMPLETE_READ_BUFFER.
|
||||
GR_GL(DrawBuffer(GR_GL_NONE));
|
||||
// We bind to FRAMEBUFFER not DRAW_FRAMEBUFFER or
|
||||
// READ_FRAMEBUFFER because earlier versions of desktop
|
||||
// GL and unextended ES only have FRAMEBUFFER. But this
|
||||
// means we're binding both READ and DRAW when
|
||||
// FramebufferBlit is supported. So to avoid
|
||||
// FRAMEBUFFER_INCOMPLETE_READ_BUFFER status we also set
|
||||
// the read buffer to none.
|
||||
GR_GL(ReadBuffer(GR_GL_NONE));
|
||||
// DrawBuffer and ReadBuffer are framebuffer state so
|
||||
// we only have to set these the first time.
|
||||
}
|
||||
} else {
|
||||
GR_GL(BindFramebuffer(GR_GL_FRAMEBUFFER, fStencilClearFBO));
|
||||
}
|
||||
GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
||||
GR_GL_STENCIL_ATTACHMENT,
|
||||
GR_GL_RENDERBUFFER, sbID));
|
||||
if (fStencilFormats[sIdx].fPacked) {
|
||||
GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
||||
GR_GL_DEPTH_ATTACHMENT,
|
||||
GR_GL_RENDERBUFFER, sbID));
|
||||
} else {
|
||||
GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
||||
GR_GL_DEPTH_ATTACHMENT,
|
||||
GR_GL_RENDERBUFFER, 0));
|
||||
}
|
||||
#if GR_DEBUG
|
||||
GrGLenum status =
|
||||
GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
|
||||
GrAssert(GR_GL_FRAMEBUFFER_COMPLETE == status);
|
||||
#endif
|
||||
|
||||
this->flushScissor(NULL);
|
||||
GR_GL(ClearStencil(0));
|
||||
GR_GL(Clear(GR_GL_STENCIL_BUFFER_BIT));
|
||||
return true;
|
||||
}
|
||||
sb->abandon(); // otherwise we lose sbID
|
||||
sb->unref();
|
||||
}
|
||||
}
|
||||
GR_GL(DeleteRenderbuffers(1, &sbID));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool GrGpuGL::attachStencilBufferToRenderTarget(GrStencilBuffer* sb,
|
||||
GrRenderTarget* rt) {
|
||||
GrGLRenderTarget* glrt = (GrGLRenderTarget*) rt;
|
||||
|
||||
GrGLuint fbo = glrt->renderFBOID();
|
||||
|
||||
if (NULL == sb) {
|
||||
if (NULL != rt->getStencilBuffer()) {
|
||||
GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
||||
GR_GL_STENCIL_ATTACHMENT,
|
||||
GR_GL_RENDERBUFFER, 0));
|
||||
GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
||||
GR_GL_DEPTH_ATTACHMENT,
|
||||
GR_GL_RENDERBUFFER, 0));
|
||||
#if GR_DEBUG
|
||||
GrGLenum status =
|
||||
GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
|
||||
GrAssert(GR_GL_FRAMEBUFFER_COMPLETE == status);
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
GrGLStencilBuffer* glsb = (GrGLStencilBuffer*) sb;
|
||||
GrGLuint rb = glsb->renderbufferID();
|
||||
|
||||
fHWDrawState.fRenderTarget = NULL;
|
||||
|
||||
// clear the new stencil buffer if we have one
|
||||
if (!(desc.fFlags & kNoStencil_GrTextureFlagBit)) {
|
||||
GrRenderTarget* rtSave = fCurrDrawState.fRenderTarget;
|
||||
fCurrDrawState.fRenderTarget = rt;
|
||||
this->clearStencil(0, ~0);
|
||||
fCurrDrawState.fRenderTarget = rtSave;
|
||||
GR_GL(BindFramebuffer(GR_GL_FRAMEBUFFER, fbo));
|
||||
GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
||||
GR_GL_STENCIL_ATTACHMENT,
|
||||
GR_GL_RENDERBUFFER, rb));
|
||||
if (glsb->format().fPacked) {
|
||||
GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
||||
GR_GL_DEPTH_ATTACHMENT,
|
||||
GR_GL_RENDERBUFFER, rb));
|
||||
} else {
|
||||
GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
||||
GR_GL_DEPTH_ATTACHMENT,
|
||||
GR_GL_RENDERBUFFER, 0));
|
||||
}
|
||||
|
||||
GrGLenum status = GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
|
||||
if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
|
||||
GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
||||
GR_GL_STENCIL_ATTACHMENT,
|
||||
GR_GL_RENDERBUFFER, 0));
|
||||
if (glsb->format().fPacked) {
|
||||
GR_GL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
|
||||
GR_GL_DEPTH_ATTACHMENT,
|
||||
GR_GL_RENDERBUFFER, 0));
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
rt->setStencilBuffer(sb);
|
||||
return true;
|
||||
}
|
||||
return tex;
|
||||
} else {
|
||||
return new GrGLTexture(this, glTexDesc, DEFAULT_PARAMS);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1468,20 +1619,25 @@ void GrGpuGL::clearStencil(uint32_t value, uint32_t mask) {
|
||||
|
||||
void GrGpuGL::clearStencilClip(const GrIRect& rect) {
|
||||
GrAssert(NULL != fCurrDrawState.fRenderTarget);
|
||||
|
||||
// this should only be called internally when we know we have a
|
||||
// stencil buffer.
|
||||
GrAssert(NULL != fCurrDrawState.fRenderTarget->getStencilBuffer());
|
||||
#if 0
|
||||
GrGLint stencilBitCount = fCurrDrawState.fRenderTarget->stencilBits();
|
||||
GrGLint stencilBitCount =
|
||||
fCurrDrawState.fRenderTarget->getStencilBuffer()->bits();
|
||||
GrAssert(stencilBitCount > 0);
|
||||
GrGLint clipStencilMask = (1 << (stencilBitCount - 1));
|
||||
#else
|
||||
// we could just clear the clip bit but when we go through
|
||||
// angle a partial stencil mask will cause clears to be
|
||||
// ANGLE a partial stencil mask will cause clears to be
|
||||
// turned into draws. Our contract on GrDrawTarget says that
|
||||
// changing the clip between stencil passes may or may not
|
||||
// zero the client's clip bits. So we just clear the whole thing.
|
||||
static const GrGLint clipStencilMask = ~0;
|
||||
#endif
|
||||
this->flushRenderTarget(&GrIRect::EmptyIRect());
|
||||
flushScissor(&rect);
|
||||
this->flushScissor(&rect);
|
||||
GR_GL(StencilMask(clipStencilMask));
|
||||
GR_GL(ClearStencil(0));
|
||||
GR_GL(Clear(GR_GL_STENCIL_BUFFER_BIT));
|
||||
@ -1794,7 +1950,13 @@ void GrGpuGL::flushStencil() {
|
||||
GrAssert(settings->fFrontFailOp != kDecWrap_StencilOp);
|
||||
}
|
||||
#endif
|
||||
int stencilBits = fCurrDrawState.fRenderTarget->stencilBits();
|
||||
int stencilBits = 0;
|
||||
GrStencilBuffer* stencilBuffer =
|
||||
fCurrDrawState.fRenderTarget->getStencilBuffer();
|
||||
if (NULL != stencilBuffer) {
|
||||
stencilBits = stencilBuffer->bits();
|
||||
}
|
||||
// TODO: dynamically attach a stencil buffer
|
||||
GrAssert(stencilBits ||
|
||||
(GrStencilSettings::gDisabled ==
|
||||
fCurrDrawState.fStencilSettings));
|
||||
|
@ -12,11 +12,11 @@
|
||||
#define GrGpuGL_DEFINED
|
||||
|
||||
#include "GrGpu.h"
|
||||
#include "GrGLIRect.h"
|
||||
#include "GrGLTexture.h"
|
||||
|
||||
#include "GrGLVertexBuffer.h"
|
||||
#include "GrGLIndexBuffer.h"
|
||||
#include "GrGLIRect.h"
|
||||
#include "GrGLStencilBuffer.h"
|
||||
#include "GrGLTexture.h"
|
||||
#include "GrGLVertexBuffer.h"
|
||||
|
||||
#include "SkString.h"
|
||||
|
||||
@ -69,8 +69,9 @@ protected:
|
||||
} fHWBounds;
|
||||
|
||||
// GrGpu overrides
|
||||
// overrides from GrGpu
|
||||
virtual void resetContext();
|
||||
virtual void abandonResources();
|
||||
virtual void releaseResources();
|
||||
|
||||
virtual GrTexture* onCreateTexture(const GrTextureDesc& desc,
|
||||
const void* srcData,
|
||||
@ -81,6 +82,10 @@ protected:
|
||||
bool dynamic);
|
||||
virtual GrResource* onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc);
|
||||
virtual GrRenderTarget* onCreateRenderTargetFrom3DApiState();
|
||||
virtual bool createStencilBufferForRenderTarget(GrRenderTarget* rt,
|
||||
int width, int height);
|
||||
virtual bool attachStencilBufferToRenderTarget(GrStencilBuffer* sb,
|
||||
GrRenderTarget* rt);
|
||||
|
||||
virtual void onClear(const GrIRect* rect, GrColor color);
|
||||
|
||||
@ -173,12 +178,16 @@ private:
|
||||
GrGLenum* internalFormat,
|
||||
GrGLenum* format,
|
||||
GrGLenum* type);
|
||||
// helper for onCreateTexture
|
||||
// helpers for onCreateTexture
|
||||
void allocateAndUploadTexData(const GrGLTexture::Desc& desc,
|
||||
GrGLenum internalFormat,
|
||||
const void* data,
|
||||
size_t rowBytes);
|
||||
|
||||
bool createRenderTargetObjects(int width, int height,
|
||||
GrGLuint texID,
|
||||
GrGLRenderTarget::Desc* desc);
|
||||
|
||||
bool fboInternalFormat(GrPixelConfig config, GrGLenum* format);
|
||||
|
||||
friend class GrGLVertexBuffer;
|
||||
@ -186,16 +195,13 @@ private:
|
||||
friend class GrGLTexture;
|
||||
friend class GrGLRenderTarget;
|
||||
|
||||
static const GrGLuint gUNKNOWN_BITCOUNT = ~0;
|
||||
|
||||
struct StencilFormat {
|
||||
GrGLenum fEnum;
|
||||
GrGLuint fBits;
|
||||
bool fPacked;
|
||||
};
|
||||
|
||||
GrTArray<StencilFormat, true> fStencilFormats;
|
||||
|
||||
GrTArray<GrGLStencilBuffer::Format, true> fStencilFormats;
|
||||
// we want to clear stencil buffers when they are created. We want to clear
|
||||
// the entire buffer even if it is larger than the color attachment. We
|
||||
// attach it to this fbo with no color attachment to do the initial clear.
|
||||
GrGLuint fStencilClearFBO;
|
||||
|
||||
bool fHWBlendDisabled;
|
||||
|
||||
GrGLuint fAASamples[4];
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include "GrContext.h"
|
||||
#include "GrGpu.h"
|
||||
#include "GrStencilBuffer.h"
|
||||
|
||||
bool GrRenderTarget::readPixels(int left, int top, int width, int height,
|
||||
GrPixelConfig config, void* buffer) {
|
||||
@ -30,7 +31,7 @@ size_t GrRenderTarget::sizeInBytes() const {
|
||||
} else {
|
||||
colorBits = GrBytesPerPixel(fConfig);
|
||||
}
|
||||
return fWidth * fHeight * (fStencilBits + colorBits);
|
||||
return fWidth * fHeight * colorBits;
|
||||
}
|
||||
|
||||
void GrRenderTarget::flagAsNeedingResolve(const GrIRect* rect) {
|
||||
@ -55,4 +56,8 @@ void GrRenderTarget::overrideResolveRect(const GrIRect rect) {
|
||||
fResolveRect.setLargestInverted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GrRenderTarget::setStencilBuffer(GrStencilBuffer* stencilBuffer) {
|
||||
GrSafeAssign(fStencilBuffer, stencilBuffer);
|
||||
}
|
69
gpu/src/GrStencilBuffer.h
Normal file
69
gpu/src/GrStencilBuffer.h
Normal file
@ -0,0 +1,69 @@
|
||||
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GrStencilBuffer_DEFINED
|
||||
#define GrStencilBuffer_DEFINED
|
||||
|
||||
#include "GrClip.h"
|
||||
#include "GrResource.h"
|
||||
|
||||
class GrStencilBuffer : public GrResource {
|
||||
public:
|
||||
int width() const { return fWidth; }
|
||||
int height() const { return fHeight; }
|
||||
int bits() const { return fBits; }
|
||||
|
||||
// called to note the last clip drawn to this buffer.
|
||||
void setLastClip(const GrClip& clip, int width, int height) {
|
||||
fLastClip = clip;
|
||||
fLastClipWidth = width;
|
||||
fLastClipHeight = height;
|
||||
GrAssert(width <= fWidth);
|
||||
GrAssert(height <= fHeight);
|
||||
}
|
||||
|
||||
// called to determine if we have to render the clip into SB.
|
||||
bool mustRenderClip(const GrClip& clip, int width, int height) const {
|
||||
// The clip is in device space. That is it doesn't scale to fit a
|
||||
// smaller RT. It is just truncated on the right / bottom edges.
|
||||
// Note that this assumes that the viewport origin never moves within
|
||||
// the stencil buffer. This is valid today.
|
||||
return width > fLastClipWidth ||
|
||||
height > fLastClipHeight ||
|
||||
clip != fLastClip;
|
||||
}
|
||||
|
||||
const GrClip& getLastClip() const {
|
||||
return fLastClip;
|
||||
}
|
||||
|
||||
protected:
|
||||
GrStencilBuffer(GrGpu* gpu, int width, int height, int bits)
|
||||
: GrResource(gpu)
|
||||
, fWidth(width)
|
||||
, fHeight(height)
|
||||
, fBits(bits)
|
||||
, fLastClip()
|
||||
, fLastClipWidth(-1)
|
||||
, fLastClipHeight(-1) {
|
||||
}
|
||||
|
||||
private:
|
||||
int fWidth;
|
||||
int fHeight;
|
||||
int fBits;
|
||||
|
||||
GrClip fLastClip;
|
||||
int fLastClipWidth;
|
||||
int fLastClipHeight;
|
||||
|
||||
typedef GrResource INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
@ -153,6 +153,7 @@
|
||||
'../gpu/src/GrGLProgram.h',
|
||||
'../gpu/src/GrGLRenderTarget.cpp',
|
||||
'../gpu/src/GrGLRenderTarget.h',
|
||||
'../gpu/src/GrGLStencilBuffer.h',
|
||||
'../gpu/src/GrGLTexture.cpp',
|
||||
'../gpu/src/GrGLTexture.h',
|
||||
'../gpu/src/GrGLUtil.cpp',
|
||||
@ -179,6 +180,7 @@
|
||||
'../gpu/src/GrResourceCache.cpp',
|
||||
'../gpu/src/GrResourceCache.h',
|
||||
'../gpu/src/GrStencil.cpp',
|
||||
'../gpu/src/GrStencilBuffer.h',
|
||||
'../gpu/src/GrTesselatedPathRenderer.cpp',
|
||||
'../gpu/src/GrTextContext.cpp',
|
||||
'../gpu/src/GrTextStrike.cpp',
|
||||
|
Loading…
Reference in New Issue
Block a user