Add APIs and plumbing for external rendertaret-textures w/ and w/out MSAA.

Review URL: http://codereview.appspot.com/4388049/



git-svn-id: http://skia.googlecode.com/svn/trunk@1102 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
bsalomon@google.com 2011-04-11 17:58:48 +00:00
parent afac88855a
commit 5877ffd5ea
12 changed files with 494 additions and 106 deletions

View File

@ -158,6 +158,43 @@ public:
// Render targets
/**
* Sets the render target.
* @param target the render target to set. (should not be NULL.)
*/
void setRenderTarget(GrRenderTarget* target);
/**
* Gets the current render target.
* @return the currently bound render target. Should never be NULL.
*/
const GrRenderTarget* getRenderTarget() const;
GrRenderTarget* getRenderTarget();
///////////////////////////////////////////////////////////////////////////
// Platform Surfaces
// GrContext provides an interface for wrapping externally created textures
// and rendertargets in their Gr-equivalents.
/**
* 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
* are set the render target object is accessible by
* GrTexture::asRenderTarget().
*
* GL: if the object is a texture Gr may change its GL texture parameters
* when it is drawn.
*
* @param desc description of the object to create.
* @return either a GrTexture* or GrRenderTarget* depending on desc. NULL
* on failure.
*/
GrResource* createPlatformSurface(const GrPlatformSurfaceDesc& desc);
/**
* DEPRECATED, WILL BE REMOVED SOON. USE createPlatformSurface.
*
* Wraps an externally-created rendertarget in a GrRenderTarget.
* @param platformRenderTarget 3D API-specific render target identifier
* e.g. in GL platforamRenderTarget is an FBO
@ -172,9 +209,18 @@ public:
GrRenderTarget* createPlatformRenderTarget(intptr_t platformRenderTarget,
int stencilBits,
bool isMultisampled,
int width, int height);
int width, int height) {
#if GR_DEBUG
GrPrintf("Using deprecated createPlatformRenderTarget API.");
#endif
return fGpu->createPlatformRenderTarget(platformRenderTarget,
stencilBits, isMultisampled,
width, height);
}
/**
* DEPRECATED, WILL BE REMOVED SOON. USE createPlatformSurface.
*
* Reads the current target object (e.g. FBO or IDirect3DSurface9*) and
* viewport state from the underlying 3D API and wraps it in a
* GrRenderTarget. The GrRenderTarget will not attempt to delete/destroy the
@ -184,22 +230,12 @@ public:
* @return the newly created GrRenderTarget
*/
GrRenderTarget* createRenderTargetFrom3DApiState() {
#if GR_DEBUG
GrPrintf("Using deprecated createRenderTargetFrom3DApiState API.");
#endif
return fGpu->createRenderTargetFrom3DApiState();
}
/**
* Sets the render target.
* @param target the render target to set. (should not be NULL.)
*/
void setRenderTarget(GrRenderTarget* target);
/**
* Gets the current render target.
* @return the currently bound render target. Should never be NULL.
*/
const GrRenderTarget* getRenderTarget() const;
GrRenderTarget* getRenderTarget();
///////////////////////////////////////////////////////////////////////////
// Matrix state

View File

@ -14,7 +14,6 @@
limitations under the License.
*/
#ifndef GrGLTexture_DEFINED
#define GrGLTexture_DEFINED
@ -31,10 +30,10 @@ class GrGLTexture;
class GrGLTexID : public GrRefCnt {
public:
GrGLTexID(GrGLuint texID) : fTexID(texID) {}
GrGLTexID(GrGLuint texID, bool ownsID) : fTexID(texID), fOwnsID(ownsID) {}
virtual ~GrGLTexID() {
if (0 != fTexID) {
if (0 != fTexID && fOwnsID) {
GR_GL(DeleteTextures(1, &fTexID));
}
}
@ -44,27 +43,25 @@ public:
private:
GrGLuint fTexID;
bool fOwnsID;
};
////////////////////////////////////////////////////////////////////////////////
class GrGLRenderTarget : public GrRenderTarget {
public:
virtual ~GrGLRenderTarget() { this->release(); }
// set fTexFBOID to this value to indicate that it is multisampled but
// Gr doesn't know how to resolve it.
enum { kUnresolvableFBOID = 0 };
bool resolveable() const { return fRTFBOID != fTexFBOID; }
bool needsResolve() const { return fNeedsResolve; }
void setDirty(bool dirty) { fNeedsResolve = resolveable() && dirty; }
GrGLuint renderFBOID() const { return fRTFBOID; }
GrGLuint textureFBOID() const { return fTexFBOID; }
protected:
struct GLRenderTargetIDs {
GrGLuint fRTFBOID;
GrGLuint fTexFBOID;
GrGLuint fStencilRenderbufferID;
GrGLuint fMSColorRenderbufferID;
bool fOwnIDs;
void reset() { memset(this, 0, sizeof(GLRenderTargetIDs)); }
};
GrGLRenderTarget(GrGpuGL* gpu,
@ -75,10 +72,33 @@ protected:
const GrGLIRect& fViewport,
GrGLTexture* texture);
virtual ~GrGLRenderTarget() { this->release(); }
void setViewport(const GrGLIRect& rect) { fViewport = rect; }
const GrGLIRect& getViewport() const { return fViewport; }
// overloads of GrResource
// The following two functions return the same ID when a
// texture-rendertarget is multisampled, and different IDs when
// it is.
// FBO ID used to render into
GrGLuint renderFBOID() const { return fRTFBOID; }
// FBO ID that has texture ID attached.
GrGLuint textureFBOID() const { return fTexFBOID; }
// override of GrRenderTarget
virtual ResolveType getResolveType() const {
if (fRTFBOID == fTexFBOID) {
// catches FBO 0 and non MSAA case
return kAutoResolves_ResolveType;
} else if (kUnresolvableFBOID == fTexFBOID) {
return kCantResolve_ResolveType;
} else {
return kCanResolve_ResolveType;
}
}
protected:
// override of GrResource
virtual void onAbandon();
virtual void onRelease();
@ -92,10 +112,6 @@ private:
// else own them.
bool fOwnIDs;
// If there separate Texture and RenderTarget FBO IDs then the rendertarget
// must be resolved to the texture FBO before it is used as a texture.
bool fNeedsResolve;
// when we switch to this rendertarget we want to set the viewport to
// only render to to content area (as opposed to the whole allocation) and
// we want the rendering to be at top left (GL has origin in bottom left)
@ -104,12 +120,11 @@ private:
// non-NULL if this RT was created by Gr with an associated GrGLTexture.
GrGLTexID* fTexIDObj;
friend class GrGpuGL;
friend class GrGLTexture;
typedef GrRenderTarget INHERITED;
};
////////////////////////////////////////////////////////////////////////////////
class GrGLTexture : public GrTexture {
public:
@ -122,8 +137,31 @@ public:
GrGLenum fFilter;
GrGLenum fWrapS;
GrGLenum fWrapT;
void invalidate() { memset(this, 0xff, sizeof(TexParams)); }
};
struct GLTextureDesc {
uint32_t fContentWidth;
uint32_t fContentHeight;
uint32_t fAllocWidth;
uint32_t fAllocHeight;
GrPixelConfig fFormat;
GrGLuint fTextureID;
bool fOwnsID;
GrGLenum fUploadFormat;
GrGLenum fUploadByteCount;
GrGLenum fUploadType;
GrGLuint fStencilBits;
Orientation fOrientation;
};
typedef GrGLRenderTarget::GLRenderTargetIDs GLRenderTargetIDs;
GrGLTexture(GrGpuGL* gpu,
const GLTextureDesc& textureDesc,
const GLRenderTargetIDs& rtIDs,
const TexParams& initialTexParams);
virtual ~GrGLTexture() { this->release(); }
// overrides of GrTexture
@ -176,26 +214,9 @@ public:
// and it is up to the GrGpuGL derivative to handle y-mirroing.
Orientation orientation() const { return fOrientation; }
protected:
static const GrGLenum* WrapMode2GLWrap();
struct GLTextureDesc {
uint32_t fContentWidth;
uint32_t fContentHeight;
uint32_t fAllocWidth;
uint32_t fAllocHeight;
GrPixelConfig fFormat;
GrGLuint fTextureID;
GrGLenum fUploadFormat;
GrGLenum fUploadByteCount;
GrGLenum fUploadType;
GrGLuint fStencilBits;
Orientation fOrientation;
};
typedef GrGLRenderTarget::GLRenderTargetIDs GLRenderTargetIDs;
GrGLTexture(GrGpuGL* gpu,
const GLTextureDesc& textureDesc,
const GLRenderTargetIDs& rtIDs,
const TexParams& initialTexParams);
protected:
// overrides of GrTexture
virtual void onAbandon();
@ -215,10 +236,6 @@ private:
Orientation fOrientation;
GrGpuGL* fGpuGL;
static const GrGLenum* WrapMode2GLWrap();
friend class GrGpuGL;
typedef GrTexture INHERITED;
};

View File

@ -192,12 +192,13 @@ public:
* @param width width of the render target
* @param height height of the render target
*/
virtual GrRenderTarget* createPlatformRenderTarget(
intptr_t platformRenderTarget,
GrRenderTarget* createPlatformRenderTarget(intptr_t platformRenderTarget,
int stencilBits,
bool isMultisampled,
int width, int height);
GrResource* createPlatformSurface(const GrPlatformSurfaceDesc& desc);
/**
* Reads the current target object (e.g. FBO or IDirect3DSurface9*) and
* viewport state from the underlying 3D API and wraps it in a
@ -485,6 +486,7 @@ protected:
virtual GrTexture* createTextureHelper(const TextureDesc& desc,
const void* srcData,
size_t rowBytes) = 0;
virtual GrResource* onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc) = 0;
virtual GrRenderTarget* createPlatformRenderTargetHelper(
intptr_t platformRenderTarget,
int stencilBits,
@ -514,8 +516,9 @@ protected:
virtual void forceRenderTargetFlushHelper() = 0;
// overridden by API-specific derived class to perform the read pixels.
virtual bool readPixelsHelper(int left, int top, int width, int height,
GrPixelConfig, void* buffer) = 0;
virtual bool onReadPixels(GrRenderTarget* target,
int left, int top, int width, int height,
GrPixelConfig, void* buffer) = 0;
// called to program the vertex data, indexCount will be 0 if drawing non-
// indexed geometry. The subclass may adjust the startVertex and/or

View File

@ -58,6 +58,29 @@ public:
*/
bool isMultisampled() { return fIsMultisampled; }
/**
* Call to indicate the multisample contents were modified such that the
* render target needs to be resolved before it can be used as texture. Gr
* tracks this for its own drawing and thus this only needs to be called
* when the render target has been modified outside of Gr. Only meaningful
* for Gr-created RT/Textures and Platform RT/Textures created with the
* kGrCanResolve flag.
*/
void flagAsNeedingResolve() {
fNeedsResolve = kCanResolve_ResolveType == getResolveType();
}
/**
* Call to indicate that GrRenderTarget was externally resolved. This may
* allow Gr to skip a redundant resolve step.
*/
void flagAsResolved() { fNeedsResolve = false; }
/**
* @return true if the GrRenderTarget requires MSAA resolving
*/
bool needsResolve() { return fNeedsResolve; }
/**
* Reads a rectangle of pixels from the render target.
* @param left left edge of the rectangle to read (inclusive)
@ -73,6 +96,16 @@ public:
bool readPixels(int left, int top, int width, int height,
GrPixelConfig config, void* buffer);
// a MSAA RT may require explicit resolving , it may auto-resolve (e.g. FBO
// 0 in GL), or be unresolvable because the client didn't give us the
// resolve destination.
enum ResolveType {
kCanResolve_ResolveType,
kAutoResolves_ResolveType,
kCantResolve_ResolveType,
};
virtual ResolveType getResolveType() const = 0;
protected:
GrRenderTarget(GrGpu* gpu,
GrTexture* texture,
@ -86,6 +119,7 @@ protected:
, fHeight(height)
, fStencilBits(stencilBits)
, fIsMultisampled(isMultisampled)
, fNeedsResolve(false)
{}
friend class GrTexture;
@ -104,6 +138,7 @@ protected:
int fHeight;
int fStencilBits;
bool fIsMultisampled;
bool fNeedsResolve;
private:
// GrGpu keeps a cached clip in the render target to avoid redundantly

View File

@ -154,6 +154,50 @@ template <typename Dst, typename Src> Dst GrTCast(Src src) {
///////////////////////////////////////////////////////////////////////////////
// saves value of T* in and restores in destructor
// e.g.:
// {
// GrAutoTPtrValueRestore<int*> autoCountRestore;
// if (useExtra) {
// autoCountRestore.save(&fCount);
// fCount += fExtraCount;
// }
// ...
// } // fCount is restored
//
template <typename T>
class GrAutoTPtrValueRestore {
public:
GrAutoTPtrValueRestore() : fPtr(NULL), fVal() {}
GrAutoTPtrValueRestore(T* ptr) {
fPtr = ptr;
if (NULL != ptr) {
fVal = *ptr;
}
}
~GrAutoTPtrValueRestore() {
if (NULL != fPtr) {
*fPtr = fVal;
}
}
// restores previously saved value (if any) and saves value for passed T*
void save(T* ptr) {
if (NULL != fPtr) {
*fPtr = fVal;
}
fPtr = ptr;
fVal = *ptr;
}
private:
T* fPtr;
T fVal;
};
///////////////////////////////////////////////////////////////////////////////
/**
* Type used to describe format of vertices in arrays
* Values are defined in GrDrawTarget
@ -388,6 +432,139 @@ enum GrConvexHint {
// concave
};
///////////////////////////////////////////////////////////////////////////////
enum GrPlatformSurfaceType {
/**
* Specifies that the object being created is a render target.
*/
kRenderTarget_GrPlatformSurfaceType,
/**
* Specifies that the object being created is a texture.
*/
kTexture_GrPlatformSurfaceType,
/**
* Specifies that the object being created is a texture and a render
* target.
*/
kTextureRenderTarget_GrPlatformSurfaceType,
};
enum GrPlatformRenderTargetFlags {
kNone_GrPlatformRenderTargetFlagBit = 0x0,
/**
* Specifies that the object being created is multisampled.
*/
kIsMultisampled_GrPlatformRenderTargetFlagBit = 0x1,
/**
* Gives permission to Gr to perform the downsample-resolve of a
* multisampled render target. If this is not set then read pixel
* operations may fail. If the object is both a texture and render target
* then this *must* be set. Otherwise, if the client wants do its own
* resolves it must create separate GrRenderTarget and GrTexture objects
* and insert appropriate flushes and resolves betweeen data hazards.
* GrRenderTarget has a flagForResolve()
*/
kGrCanResolve_GrPlatformRenderTargetFlagBit = 0x2,
};
static inline GrPlatformRenderTargetFlags operator | (GrPlatformRenderTargetFlags a, GrPlatformRenderTargetFlags b) {
return (GrPlatformRenderTargetFlags) (+a | +b);
}
static inline GrPlatformRenderTargetFlags operator & (GrPlatformRenderTargetFlags a, GrPlatformRenderTargetFlags b) {
return (GrPlatformRenderTargetFlags) (+a & +b);
}
// opaque type for 3D API object handles
typedef intptr_t GrPlatform3DObject;
/**
* Description of platform surface to create. See below for GL example.
*/
struct GrPlatformSurfaceDesc {
GrPlatformSurfaceType fSurfaceType; // type of surface to create
/**
* Flags for kRenderTarget and kTextureRenderTarget surface types
*/
GrPlatformRenderTargetFlags fRenderTargetFlags;
int fWidth; // width in pixels
int fHeight; // height in pixels
GrPixelConfig fConfig; // color format
/**
* Number of per sample stencil buffer. Only relevant if kIsRenderTarget is
* set in fFlags.
*/
int fStencilBits;
/**
* Texture object in 3D API. Only relevant if fSurfaceType is kTexture or
* kTextureRenderTarget.
* GL: this is a texture object (glGenTextures)
*/
GrPlatform3DObject fPlatformTexture;
/**
* Render target object in 3D API. Only relevant if fSurfaceType is
* kRenderTarget or kTextureRenderTarget
* GL: this is a FBO object (glGenFramebuffers)
*/
GrPlatform3DObject fPlatformRenderTarget;
/**
* 3D API object used as destination of resolve. Only relevant if
* fSurfaceType is kRenderTarget or kTextureRenderTarget and
* kGrCanResolve is set in fRenderTargetFlags.
* fFlags.
* GL: this is a FBO object (glGenFramebuffers)
*/
GrPlatform3DObject fPlatformResolveDestination;
void reset() { memset(this, 0, sizeof(GrPlatformSurfaceDesc)); }
};
/**
* Example of how to wrap render-to-texture-with-MSAA GL objects with a GrPlatformSurace
*
* GLint colorBufferID;
* glGenRenderbuffers(1, &colorID);
* glBindRenderbuffer(GL_RENDERBUFFER, colorBufferID);
* glRenderbufferStorageMultisample(GL_RENDERBUFFER, S, GL_RGBA, W, H);
*
* GLint stencilBufferID;
* glGenRenderBuffers(1, &stencilBufferID);
* glBindRenderbuffer(GL_RENDERBUFFER, stencilBufferID);
* glRenderbufferStorageMultisample(GL_RENDERBUFFER, S, GL_STENCIL_INDEX8, W, H);
*
* GLint drawFBOID;
* glGenFramebuffers(1, &drawFBOID);
* glBindFramebuffer(GL_FRAMEBUFFER, drawFBOID);
* glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBufferID);
* glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencilBufferID);
*
* GLint textureID;
* glGenTextures(1, &textureID);
* glBindTexture(GL_TEXTURE_2D, textureID);
* glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, W, H, ...);
*
* GLint readFBOID;
* glGenFramebuffers(1, &readFBOID);
* glBindFramebuffer(GL_FRAMEBUFFER, readFBOID);
* glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureID, 0);
*
* GrPlatformSurfaceDesc renderTargetTextureDesc;
* renderTargetTextureDesc.fSurfaceType = kTextureRenderTarget_GrPlatformSurfaceType;
* renderTargetTextureDesc.fRenderTargetFlags = (kIsMultisampled_GrPlatformRenderTargetFlagBit | kGrCanResolve_GrPlatformRenderTargetFlagBit);
* renderTargetTextureDesc.fWidth = W;
* renderTargetTextureDesc.fHeight = H;
* renderTargetTextureDesc.fConfig = kRGBA_8888_GrPixelConfig
* renderTargetTextureDesc.fStencilBits = 8;
* renderTargetTextureDesc.fPlatformTexture = textureID;
* renderTargetTextureDesc.fPlatformRenderTarget = drawFBOID;
* renderTargetTextureDesc.fPlatformResolveDestination = readFBOID;
*
* GrTexture* texture = static_cast<GrTexture*>(grContext->createPlatrformSurface(renderTargetTextureDesc));
*/
///////////////////////////////////////////////////////////////////////////////
// this is included only to make it easy to use this debugging facility

View File

@ -267,16 +267,26 @@ int GrContext::getMaxTextureDimension() {
///////////////////////////////////////////////////////////////////////////////
GrRenderTarget* GrContext::createPlatformRenderTarget(
intptr_t platformRenderTarget,
int stencilBits,
bool isMultisampled,
int width, int height) {
return fGpu->createPlatformRenderTarget(platformRenderTarget, stencilBits,
isMultisampled,
width, height);
GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
// validate flags here so that GrGpu subclasses don't have to check
if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType &&
0 != desc.fRenderTargetFlags) {
return NULL;
}
if (!(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
return NULL;
}
if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType &&
(kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) &&
!(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) {
return NULL;
}
return fGpu->createPlatformSurface(desc);
}
///////////////////////////////////////////////////////////////////////////////
bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler,
int width, int height) {
if (!fGpu->supports8BitPalette()) {

View File

@ -108,7 +108,8 @@ GrGLTexture::GrGLTexture(GrGpuGL* gpu,
textureDesc.fFormat) {
fTexParams = initialTexParams;
fTexIDObj = new GrGLTexID(textureDesc.fTextureID);
fTexIDObj = new GrGLTexID(textureDesc.fTextureID,
textureDesc.fOwnsID);
fUploadFormat = textureDesc.fUploadFormat;
fUploadByteCount = textureDesc.fUploadByteCount;
fUploadType = textureDesc.fUploadType;

View File

@ -158,6 +158,11 @@ GrRenderTarget* GrGpu::createRenderTargetFrom3DApiState() {
return this->createRenderTargetFrom3DApiStateHelper();
}
GrResource* GrGpu::createPlatformSurface(const GrPlatformSurfaceDesc& desc) {
this->handleDirtyContext();
return this->onCreatePlatformSurface(desc);
}
GrVertexBuffer* GrGpu::createVertexBuffer(uint32_t size, bool dynamic) {
this->handleDirtyContext();
return this->createVertexBufferHelper(size, dynamic);
@ -183,12 +188,7 @@ bool GrGpu::readPixels(GrRenderTarget* target,
GrPixelConfig config, void* buffer) {
this->handleDirtyContext();
GrRenderTarget* prevTarget = fCurrDrawState.fRenderTarget;
if (NULL != target) {
fCurrDrawState.fRenderTarget = target;
}
return this->readPixelsHelper(left, top, width, height, config, buffer);
fCurrDrawState.fRenderTarget = prevTarget;
return this->onReadPixels(target, left, top, width, height, config, buffer);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -533,6 +533,73 @@ void GrGpuGL::resetContext() {
fHWDrawState.fRenderTarget = NULL;
}
GrResource* GrGpuGL::onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc) {
bool isTexture = kTexture_GrPlatformSurfaceType == desc.fSurfaceType ||
kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType;
bool isRenderTarget = kRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType ||
kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType;
GrGLRenderTarget::GLRenderTargetIDs rtIDs;
if (isRenderTarget) {
rtIDs.fRTFBOID = desc.fPlatformRenderTarget;
if (kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) {
if (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags) {
rtIDs.fTexFBOID = desc.fPlatformResolveDestination;
} else {
GrAssert(!isTexture); // this should have been filtered by GrContext
rtIDs.fTexFBOID = GrGLRenderTarget::kUnresolvableFBOID;
}
} else {
rtIDs.fTexFBOID = desc.fPlatformRenderTarget;
}
// we don't know what the RB ids are without glGets and we don't care
// since we aren't responsible for deleting them.
rtIDs.fStencilRenderbufferID = 0;
rtIDs.fMSColorRenderbufferID = 0;
rtIDs.fOwnIDs = false;
} else {
rtIDs.reset();
}
if (isTexture) {
GrGLTexture::GLTextureDesc texDesc;
GrGLenum dontCare;
if (!canBeTexture(desc.fConfig, &dontCare,
&texDesc.fUploadFormat,
&texDesc.fUploadType)) {
return NULL;
}
GrGLTexture::TexParams params;
texDesc.fAllocWidth = texDesc.fContentWidth = desc.fWidth;
texDesc.fAllocHeight = texDesc.fContentHeight = desc.fHeight;
texDesc.fFormat = texDesc.fFormat;
texDesc.fOrientation = GrGLTexture::kBottomUp_Orientation;
texDesc.fStencilBits = desc.fStencilBits;
texDesc.fTextureID = desc.fPlatformTexture;
texDesc.fUploadByteCount = GrBytesPerPixel(desc.fConfig);
texDesc.fOwnsID = false;
params.invalidate(); // rather than do glGets.
return new GrGLTexture(this, texDesc, rtIDs, params);
} else {
GrGLIRect viewport;
viewport.fLeft = 0;
viewport.fBottom = 0;
viewport.fWidth = desc.fWidth;
viewport.fHeight = desc.fHeight;
return new GrGLRenderTarget(this, rtIDs, NULL, desc.fStencilBits,
kIsMultisampled_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags,
viewport, NULL);
}
}
GrRenderTarget* GrGpuGL::createPlatformRenderTargetHelper(
intptr_t platformRenderTarget,
int stencilBits,
@ -655,6 +722,7 @@ GrTexture* GrGpuGL::createTextureHelper(const TextureDesc& desc,
glDesc.fAllocHeight = desc.fHeight;
glDesc.fStencilBits = 0;
glDesc.fFormat = desc.fFormat;
glDesc.fOwnsID = true;
bool renderTarget = 0 != (desc.fFlags & kRenderTarget_TextureFlag);
if (!canBeTexture(desc.fFormat,
@ -1154,21 +1222,35 @@ void GrGpuGL::forceRenderTargetFlushHelper() {
flushRenderTarget();
}
bool GrGpuGL::readPixelsHelper(int left, int top, int width, int height,
GrPixelConfig config, void* buffer) {
bool GrGpuGL::onReadPixels(GrRenderTarget* target,
int left, int top, int width, int height,
GrPixelConfig config, void* buffer) {
GrGLenum internalFormat; // we don't use this for glReadPixels
GrGLenum format;
GrGLenum type;
if (!this->canBeTexture(config, &internalFormat, &format, &type)) {
return false;
}
GrGLRenderTarget* tgt = static_cast<GrGLRenderTarget*>(target);
GrAutoTPtrValueRestore<GrRenderTarget*> autoTargetRestore;
switch (tgt->getResolveType()) {
case GrGLRenderTarget::kCantResolve_ResolveType:
return false;
case GrGLRenderTarget::kAutoResolves_ResolveType:
autoTargetRestore.save(&fCurrDrawState.fRenderTarget);
fCurrDrawState.fRenderTarget = target;
flushRenderTarget();
break;
case GrGLRenderTarget::kCanResolve_ResolveType:
resolveRenderTarget(tgt);
// we don't track the state of the READ FBO ID.
GR_GL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, tgt->textureFBOID()));
break;
default:
GrCrash("Unknown resolve type");
}
if (NULL == fCurrDrawState.fRenderTarget) {
return false;
}
flushRenderTarget();
const GrGLIRect& glvp = ((GrGLRenderTarget*)fCurrDrawState.fRenderTarget)->getViewport();
const GrGLIRect& glvp = tgt->getViewport();
// the read rect is viewport-relative
GrGLIRect readRect;
@ -1208,7 +1290,7 @@ void GrGpuGL::flushRenderTarget() {
#if GR_COLLECT_STATS
++fStats.fRenderTargetChngCnt;
#endif
rt->setDirty(true);
rt->flagAsNeedingResolve();
#if GR_DEBUG
GrGLenum status = GR_GL(CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
@ -1316,10 +1398,9 @@ void GrGpuGL::drawNonIndexedHelper(GrPrimitiveType type,
#endif
}
void GrGpuGL::resolveTextureRenderTarget(GrGLTexture* texture) {
GrGLRenderTarget* rt = (GrGLRenderTarget*) texture->asRenderTarget();
void GrGpuGL::resolveRenderTarget(GrGLRenderTarget* rt) {
if (NULL != rt && rt->needsResolve()) {
if (rt->needsResolve()) {
GrAssert(kNone_MSFBO != fMSFBOType);
GrAssert(rt->textureFBOID() != rt->renderFBOID());
GR_GL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER,
@ -1329,32 +1410,32 @@ void GrGpuGL::resolveTextureRenderTarget(GrGLTexture* texture) {
#if GR_COLLECT_STATS
++fStats.fRenderTargetChngCnt;
#endif
// make sure we go through set render target
// make sure we go through flushRenderTarget() since we've modified
// the bound DRAW FBO ID.
fHWDrawState.fRenderTarget = NULL;
const GrGLIRect& vp = rt->getViewport();
GrGLint left = 0;
GrGLint right = texture->width();
// we will have rendered to the top of the FBO.
GrGLint top = texture->allocHeight();
GrGLint bottom = texture->allocHeight() - texture->height();
if (kAppleES_MSFBO == fMSFBOType) {
// Apple's extension uses the scissor as the blit bounds.
GR_GL(Enable(GR_GL_SCISSOR_TEST));
GR_GL(Scissor(left, bottom, right-left, top-bottom));
GR_GL(Scissor(vp.fLeft, vp.fBottom,
vp.fWidth, vp.fHeight));
GR_GL(ResolveMultisampleFramebuffer());
fHWBounds.fScissorRect.invalidate();
fHWBounds.fScissorEnabled = true;
} else {
if (kDesktopARB_MSFBO != fMSFBOType) {
// these respect the scissor during the blit, so disable it.
// this respects the scissor during the blit, so disable it.
GrAssert(kDesktopEXT_MSFBO == fMSFBOType);
flushScissor(NULL);
}
GR_GL(BlitFramebuffer(left, bottom, right, top,
left, bottom, right, top,
GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
int right = vp.fLeft + vp.fWidth;
int top = vp.fBottom + vp.fHeight;
GR_GL(BlitFramebuffer(vp.fLeft, vp.fBottom, right, top,
vp.fLeft, vp.fBottom, right, top,
GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
}
rt->setDirty(false);
rt->flagAsResolved();
}
}
@ -1631,7 +1712,11 @@ bool GrGpuGL::flushGLStateCommon(GrPrimitiveType type) {
// texture and now we're texuring from the rt it will still be
// the last bound texture, but it needs resolving. So keep this
// out of the "last != next" check.
resolveTextureRenderTarget(nextTexture);
GrGLRenderTarget* texRT =
static_cast<GrGLRenderTarget*>(nextTexture->asRenderTarget());
if (NULL != texRT) {
resolveRenderTarget(texRT);
}
if (fHWDrawState.fTextures[s] != nextTexture) {
setTextureUnit(s);

View File

@ -79,21 +79,21 @@ protected:
bool dynamic);
virtual GrIndexBuffer* createIndexBufferHelper(uint32_t size,
bool dynamic);
virtual GrResource* onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc);
virtual GrRenderTarget* createPlatformRenderTargetHelper(
intptr_t platformRenderTarget,
int stencilBits,
bool isMultisampled,
int width, int height);
virtual GrRenderTarget* createRenderTargetFrom3DApiStateHelper();
virtual void eraseColorHelper(GrColor color);
virtual void forceRenderTargetFlushHelper();
virtual bool readPixelsHelper(int left, int top, int width, int height,
GrPixelConfig, void* buffer);
virtual bool onReadPixels(GrRenderTarget* target,
int left, int top, int width, int height,
GrPixelConfig, void* buffer);
virtual void drawIndexedHelper(GrPrimitiveType type,
uint32_t startVertex,
@ -158,7 +158,7 @@ private:
void flushAAState(GrPrimitiveType type);
void flushBlend(GrPrimitiveType type);
void resolveTextureRenderTarget(GrGLTexture* texture);
void resolveRenderTarget(GrGLRenderTarget* texture);
bool canBeTexture(GrPixelConfig config,
GrGLenum* internalFormat,

View File

@ -34,6 +34,14 @@ public:
* construction.
*/
SkGpuDeviceFactory(GrContext*, GrRenderTarget* rootRenderTarget);
/**
* When the root layer is both a GrRenderTarget and a GrTexture it
* is handy to have the factory hang on to a ref to the GrTexture object.
* This is because the GrTexture has a ref to the GrRenderTarget but not
* vice-versa.
*/
SkGpuDeviceFactory(GrContext*, GrTexture* rootRenderTargetTexture);
virtual ~SkGpuDeviceFactory();
@ -43,6 +51,7 @@ public:
private:
GrContext* fContext;
GrRenderTarget* fRootRenderTarget;
GrTexture* fRootTexture;
};
#endif

View File

@ -1453,12 +1453,27 @@ SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context,
rootRenderTarget->ref();
}
context->ref();
fRootTexture = NULL;
}
SkGpuDeviceFactory::SkGpuDeviceFactory(GrContext* context, GrTexture* rootRenderTargetTexture) {
GrAssert(NULL != context);
GrAssert(NULL != rootRenderTargetTexture);
GrAssert(NULL != rootRenderTargetTexture->asRenderTarget());
fRootTexture = rootRenderTargetTexture;
rootRenderTargetTexture->ref();
fRootRenderTarget = rootRenderTargetTexture->asRenderTarget();
fRootRenderTarget->ref();
context->ref();
}
SkGpuDeviceFactory::~SkGpuDeviceFactory() {
fContext->unref();
fRootRenderTarget->unref();
GrSafeUnref(fRootTexture);
}
SkDevice* SkGpuDeviceFactory::newDevice(SkCanvas*, SkBitmap::Config config,