Adds read pixels to GrTexture and GrRenderTarget
Adds SkGrRenderTargetPixelRef for SkBitmaps that are backed by RTs that aren't textures. Adds onReadPixels implementations for SkGr pixel ref types git-svn-id: http://skia.googlecode.com/svn/trunk@1056 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
62ab7addb0
commit
669fdc4ed8
@ -423,20 +423,49 @@ public:
|
||||
* FlushBits.
|
||||
*/
|
||||
void flush(int flagsBitfield = 0);
|
||||
|
||||
/**
|
||||
* Return true on success, i.e. if we could copy the specified range of
|
||||
* pixels from the current render-target into the buffer, converting into
|
||||
* the specified pixel-config.
|
||||
* Reads a rectangle of pixels from a render target.
|
||||
* @param renderTarget the render target to read from. NULL means the
|
||||
* current render target.
|
||||
* @param left left edge of the rectangle to read (inclusive)
|
||||
* @param top top edge of the rectangle to read (inclusive)
|
||||
* @param width width of rectangle to read in pixels.
|
||||
* @param height height of rectangle to read in pixels.
|
||||
* @param config the pixel config of the destination buffer
|
||||
* @param buffer memory to read the rectangle into.
|
||||
*
|
||||
* @return true if the read succeeded, false if not. The read can fail
|
||||
* because of a unsupported pixel config or because no render
|
||||
* target is currently set.
|
||||
*/
|
||||
bool readPixels(int left, int top, int width, int height,
|
||||
GrTexture::PixelConfig, void* buffer);
|
||||
bool readRenderTargetPixels(GrRenderTarget* target,
|
||||
int left, int top, int width, int height,
|
||||
GrPixelConfig config, void* buffer);
|
||||
|
||||
/**
|
||||
* Reads a rectangle of pixels from a texture.
|
||||
* @param texture the render target to read from.
|
||||
* @param left left edge of the rectangle to read (inclusive)
|
||||
* @param top top edge of the rectangle to read (inclusive)
|
||||
* @param width width of rectangle to read in pixels.
|
||||
* @param height height of rectangle to read in pixels.
|
||||
* @param config the pixel config of the destination buffer
|
||||
* @param buffer memory to read the rectangle into.
|
||||
*
|
||||
* @return true if the read succeeded, false if not. The read can fail
|
||||
* because of a unsupported pixel config.
|
||||
*/
|
||||
bool readTexturePixels(GrTexture* target,
|
||||
int left, int top, int width, int height,
|
||||
GrPixelConfig config, void* buffer);
|
||||
|
||||
/**
|
||||
* Copy the src pixels [buffer, stride, pixelconfig] into the current
|
||||
* render-target at the specified rectangle.
|
||||
*/
|
||||
void writePixels(int left, int top, int width, int height,
|
||||
GrTexture::PixelConfig, const void* buffer, size_t stride);
|
||||
GrPixelConfig, const void* buffer, size_t stride);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -180,17 +180,17 @@ public:
|
||||
protected:
|
||||
|
||||
struct GLTextureDesc {
|
||||
uint32_t fContentWidth;
|
||||
uint32_t fContentHeight;
|
||||
uint32_t fAllocWidth;
|
||||
uint32_t fAllocHeight;
|
||||
PixelConfig fFormat;
|
||||
GrGLuint fTextureID;
|
||||
GrGLenum fUploadFormat;
|
||||
GrGLenum fUploadByteCount;
|
||||
GrGLenum fUploadType;
|
||||
GrGLuint fStencilBits;
|
||||
Orientation fOrientation;
|
||||
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,
|
||||
|
@ -17,15 +17,16 @@
|
||||
#ifndef GrGpu_DEFINED
|
||||
#define GrGpu_DEFINED
|
||||
|
||||
#include "GrDrawTarget.h"
|
||||
#include "GrPathRenderer.h"
|
||||
#include "GrRect.h"
|
||||
#include "GrRefCnt.h"
|
||||
#include "GrDrawTarget.h"
|
||||
#include "GrTexture.h"
|
||||
#include "GrPathRenderer.h"
|
||||
|
||||
class GrVertexBufferAllocPool;
|
||||
class GrContext;
|
||||
class GrIndexBufferAllocPool;
|
||||
class GrResource;
|
||||
class GrVertexBufferAllocPool;
|
||||
|
||||
class GrGpu : public GrDrawTarget {
|
||||
|
||||
@ -104,7 +105,7 @@ public:
|
||||
// kRenderTarget_TextureFlag.
|
||||
uint32_t fWidth; //!< Width of the texture
|
||||
uint32_t fHeight; //!< Height of the texture
|
||||
GrTexture::PixelConfig fFormat; //!< Format of source data of the
|
||||
GrPixelConfig fFormat; //!< Format of source data of the
|
||||
// texture. Not guaraunteed to be the
|
||||
// same as internal format used by
|
||||
// 3D API.
|
||||
@ -143,6 +144,14 @@ public:
|
||||
GrGpu();
|
||||
virtual ~GrGpu();
|
||||
|
||||
// The GrContext sets itself as the owner of this Gpu object
|
||||
void setContext(GrContext* context) {
|
||||
GrAssert(NULL == fContext);
|
||||
fContext = context;
|
||||
}
|
||||
GrContext* getContext() { return fContext; }
|
||||
const GrContext* getContext() const { return fContext; }
|
||||
|
||||
/**
|
||||
* The GrGpu object normally assumes that no outsider is setting state
|
||||
* within the underlying 3D API's context/device/whatever. This call informs
|
||||
@ -340,19 +349,23 @@ public:
|
||||
void forceRenderTargetFlush();
|
||||
|
||||
/**
|
||||
* Reads a rectangle of pixels from the current render target.
|
||||
* @param left left edge of the rectangle to read (inclusive)
|
||||
* @param top top edge of the rectangle to read (inclusive)
|
||||
* @param width width of rectangle to read in pixels.
|
||||
* @param height height of rectangle to read in pixels.
|
||||
* @param buffer memory to read the rectangle into.
|
||||
* Reads a rectangle of pixels from a render target.
|
||||
* @param renderTarget the render target to read from. NULL means the
|
||||
* current render target.
|
||||
* @param left left edge of the rectangle to read (inclusive)
|
||||
* @param top top edge of the rectangle to read (inclusive)
|
||||
* @param width width of rectangle to read in pixels.
|
||||
* @param height height of rectangle to read in pixels.
|
||||
* @param config the pixel config of the destination buffer
|
||||
* @param buffer memory to read the rectangle into.
|
||||
*
|
||||
* @return true if the read succeeded, false if not. The read can fail
|
||||
* because of a unsupported pixel config or because no render
|
||||
* target is currently set.
|
||||
*/
|
||||
bool readPixels(int left, int top, int width, int height,
|
||||
GrTexture::PixelConfig, void* buffer);
|
||||
bool readPixels(GrRenderTarget* renderTarget,
|
||||
int left, int top, int width, int height,
|
||||
GrPixelConfig config, void* buffer);
|
||||
|
||||
const Stats& getStats() const;
|
||||
void resetStats();
|
||||
@ -499,7 +512,7 @@ protected:
|
||||
|
||||
// overridden by API-specific derived class to perform the read pixels.
|
||||
virtual bool readPixelsHelper(int left, int top, int width, int height,
|
||||
GrTexture::PixelConfig, void* buffer) = 0;
|
||||
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
|
||||
@ -523,20 +536,7 @@ protected:
|
||||
virtual void eraseStencilClip(const GrIRect& rect) = 0;
|
||||
|
||||
private:
|
||||
// readies the pools to provide vertex/index data.
|
||||
void prepareVertexPool();
|
||||
void prepareIndexPool();
|
||||
|
||||
// determines the path renderer used to draw a clip path element.
|
||||
GrPathRenderer* getClipPathRenderer(GrPathIter* path,
|
||||
GrPathFill fill);
|
||||
|
||||
void handleDirtyContext() {
|
||||
if (fContextIsDirty) {
|
||||
this->resetContext();
|
||||
fContextIsDirty = false;
|
||||
}
|
||||
}
|
||||
GrContext* fContext; // not reffed (context refs gpu)
|
||||
|
||||
GrVertexBufferAllocPool* fVertexPool;
|
||||
|
||||
@ -561,6 +561,21 @@ private:
|
||||
|
||||
GrResource* fResourceHead;
|
||||
|
||||
// readies the pools to provide vertex/index data.
|
||||
void prepareVertexPool();
|
||||
void prepareIndexPool();
|
||||
|
||||
// determines the path renderer used to draw a clip path element.
|
||||
GrPathRenderer* getClipPathRenderer(GrPathIter* path,
|
||||
GrPathFill fill);
|
||||
|
||||
void handleDirtyContext() {
|
||||
if (fContextIsDirty) {
|
||||
this->resetContext();
|
||||
fContextIsDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
// used to save and restore state when the GrGpu needs
|
||||
// to make its geometry pools available internally
|
||||
class AutoInternalDrawGeomRestore {
|
||||
|
@ -52,6 +52,21 @@ public:
|
||||
*/
|
||||
GrTexture* asTexture() {return fTexture;}
|
||||
|
||||
/**
|
||||
* Reads a rectangle of pixels from the render target.
|
||||
* @param left left edge of the rectangle to read (inclusive)
|
||||
* @param top top edge of the rectangle to read (inclusive)
|
||||
* @param width width of rectangle to read in pixels.
|
||||
* @param height height of rectangle to read in pixels.
|
||||
* @param config the pixel config of the destination buffer
|
||||
* @param buffer memory to read the rectangle into.
|
||||
*
|
||||
* @return true if the read succeeded, false if not. The read can fail
|
||||
* because of a unsupported pixel config.
|
||||
*/
|
||||
bool readPixels(int left, int top, int width, int height,
|
||||
GrPixelConfig config, void* buffer);
|
||||
|
||||
protected:
|
||||
GrRenderTarget(GrGpu* gpu,
|
||||
GrTexture* texture,
|
||||
@ -81,25 +96,11 @@ private:
|
||||
};
|
||||
|
||||
class GrTexture : public GrResource {
|
||||
public:
|
||||
enum PixelConfig {
|
||||
kUnknown_PixelConfig,
|
||||
kAlpha_8_PixelConfig,
|
||||
kIndex_8_PixelConfig,
|
||||
kRGB_565_PixelConfig,
|
||||
kRGBA_4444_PixelConfig, //!< premultiplied
|
||||
kRGBA_8888_PixelConfig, //!< premultiplied
|
||||
kRGBX_8888_PixelConfig, //!< treat the alpha channel as opaque
|
||||
};
|
||||
static size_t BytesPerPixel(PixelConfig);
|
||||
static bool PixelConfigIsOpaque(PixelConfig);
|
||||
static bool PixelConfigIsAlphaOnly(PixelConfig);
|
||||
|
||||
protected:
|
||||
GrTexture(GrGpu* gpu,
|
||||
int width,
|
||||
int height,
|
||||
PixelConfig config)
|
||||
GrPixelConfig config)
|
||||
: INHERITED(gpu)
|
||||
, fWidth(width)
|
||||
, fHeight(height)
|
||||
@ -138,13 +139,13 @@ public:
|
||||
/**
|
||||
* Retrieves the pixel config specified when the texture was created.
|
||||
*/
|
||||
PixelConfig config() const { return fConfig; }
|
||||
GrPixelConfig config() const { return fConfig; }
|
||||
|
||||
/**
|
||||
* Approximate number of bytes used by the texture
|
||||
*/
|
||||
size_t sizeInBytes() const {
|
||||
return fWidth * fHeight * BytesPerPixel(fConfig);
|
||||
return fWidth * fHeight * GrBytesPerPixel(fConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -163,6 +164,21 @@ public:
|
||||
uint32_t height,
|
||||
const void* srcData) = 0;
|
||||
|
||||
/**
|
||||
* Reads a rectangle of pixels from the texture.
|
||||
* @param left left edge of the rectangle to read (inclusive)
|
||||
* @param top top edge of the rectangle to read (inclusive)
|
||||
* @param width width of rectangle to read in pixels.
|
||||
* @param height height of rectangle to read in pixels.
|
||||
* @param config the pixel config of the destination buffer
|
||||
* @param buffer memory to read the rectangle into.
|
||||
*
|
||||
* @return true if the read succeeded, false if not. The read can fail
|
||||
* because of a unsupported pixel config.
|
||||
*/
|
||||
bool readPixels(int left, int top, int width, int height,
|
||||
GrPixelConfig config, void* buffer);
|
||||
|
||||
/**
|
||||
* Retrieves the render target underlying this texture that can be passed to
|
||||
* GrGpu::setRenderTarget().
|
||||
@ -200,7 +216,8 @@ private:
|
||||
// for this texture if the texture is power of two sized.
|
||||
int fShiftFixedX;
|
||||
int fShiftFixedY;
|
||||
PixelConfig fConfig;
|
||||
|
||||
GrPixelConfig fConfig;
|
||||
|
||||
typedef GrResource INHERITED;
|
||||
};
|
||||
|
@ -212,6 +212,54 @@ static inline int GrMaskFormatBytesPerPixel(GrMaskFormat format) {
|
||||
return (int)format + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pixel configurations.
|
||||
*/
|
||||
enum GrPixelConfig {
|
||||
kUnknown_GrPixelConfig,
|
||||
kAlpha_8_GrPixelConfig,
|
||||
kIndex_8_GrPixelConfig,
|
||||
kRGB_565_GrPixelConfig,
|
||||
kRGBA_4444_GrPixelConfig, //!< premultiplied
|
||||
kRGBA_8888_GrPixelConfig, //!< premultiplied
|
||||
kRGBX_8888_GrPixelConfig, //!< treat the alpha channel as opaque
|
||||
};
|
||||
|
||||
static inline size_t GrBytesPerPixel(GrPixelConfig config) {
|
||||
switch (config) {
|
||||
case kAlpha_8_GrPixelConfig:
|
||||
case kIndex_8_GrPixelConfig:
|
||||
return 1;
|
||||
case kRGB_565_GrPixelConfig:
|
||||
case kRGBA_4444_GrPixelConfig:
|
||||
return 2;
|
||||
case kRGBA_8888_GrPixelConfig:
|
||||
case kRGBX_8888_GrPixelConfig:
|
||||
return 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool GrPixelConfigIsOpaque(GrPixelConfig config) {
|
||||
switch (config) {
|
||||
case kRGB_565_GrPixelConfig:
|
||||
case kRGBX_8888_GrPixelConfig:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool GrPixelConfigIsAlphaOnly(GrPixelConfig config) {
|
||||
switch (config) {
|
||||
case kAlpha_8_GrPixelConfig:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Operations used to construct clips.
|
||||
*/
|
||||
|
@ -142,16 +142,16 @@ GrAtlasMgr::~GrAtlasMgr() {
|
||||
fGpu->unref();
|
||||
}
|
||||
|
||||
static GrTexture::PixelConfig maskformat2pixelconfig(GrMaskFormat format) {
|
||||
static GrPixelConfig maskformat2pixelconfig(GrMaskFormat format) {
|
||||
switch (format) {
|
||||
case kA8_GrMaskFormat:
|
||||
return GrTexture::kAlpha_8_PixelConfig;
|
||||
return kAlpha_8_GrPixelConfig;
|
||||
case kA565_GrMaskFormat:
|
||||
return GrTexture::kRGB_565_PixelConfig;
|
||||
return kRGB_565_GrPixelConfig;
|
||||
default:
|
||||
GrAssert(!"unknown maskformat");
|
||||
}
|
||||
return GrTexture::kUnknown_PixelConfig;
|
||||
return kUnknown_GrPixelConfig;
|
||||
}
|
||||
|
||||
GrAtlas* GrAtlasMgr::addToAtlas(GrAtlas* atlas,
|
||||
|
@ -206,7 +206,7 @@ GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key,
|
||||
// no longer need to clamp at min RT size.
|
||||
rtDesc.fWidth = GrNextPow2(desc.fWidth);
|
||||
rtDesc.fHeight = GrNextPow2(desc.fHeight);
|
||||
int bpp = GrTexture::BytesPerPixel(desc.fFormat);
|
||||
int bpp = GrBytesPerPixel(desc.fFormat);
|
||||
GrAutoSMalloc<128*128*4> stretchedPixels(bpp *
|
||||
rtDesc.fWidth *
|
||||
rtDesc.fHeight);
|
||||
@ -609,14 +609,39 @@ void GrContext::flushDrawBuffer() {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool GrContext::readPixels(int left, int top, int width, int height,
|
||||
GrTexture::PixelConfig config, void* buffer) {
|
||||
this->flush(true);
|
||||
return fGpu->readPixels(left, top, width, height, config, buffer);
|
||||
bool GrContext::readTexturePixels(GrTexture* texture,
|
||||
int left, int top, int width, int height,
|
||||
GrPixelConfig config, void* buffer) {
|
||||
|
||||
// TODO: code read pixels for textures that aren't rendertargets
|
||||
|
||||
this->flush();
|
||||
GrRenderTarget* target = texture->asRenderTarget();
|
||||
if (NULL != target) {
|
||||
return fGpu->readPixels(target,
|
||||
left, top, width, height,
|
||||
config, buffer);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
|
||||
int left, int top, int width, int height,
|
||||
GrPixelConfig config, void* buffer) {
|
||||
uint32_t flushFlags = 0;
|
||||
if (NULL == target) {
|
||||
flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit;
|
||||
}
|
||||
|
||||
this->flush(flushFlags);
|
||||
return fGpu->readPixels(target,
|
||||
left, top, width, height,
|
||||
config, buffer);
|
||||
}
|
||||
|
||||
void GrContext::writePixels(int left, int top, int width, int height,
|
||||
GrTexture::PixelConfig config, const void* buffer,
|
||||
GrPixelConfig config, const void* buffer,
|
||||
size_t stride) {
|
||||
|
||||
// TODO: when underlying api has a direct way to do this we should use it
|
||||
@ -764,6 +789,7 @@ GrContext::GrContext(GrGpu* gpu) :
|
||||
|
||||
fGpu = gpu;
|
||||
fGpu->ref();
|
||||
fGpu->setContext(this);
|
||||
|
||||
fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
|
||||
fGpu->setClipPathRenderer(fCustomPathRenderer);
|
||||
|
@ -492,10 +492,10 @@ bool GrDrawTarget::canDisableBlend() const {
|
||||
for (int s = 0; s < kNumStages; ++s) {
|
||||
if (VertexUsesStage(s, fGeometrySrc.fVertexLayout)) {
|
||||
GrAssert(NULL != fCurrDrawState.fTextures[s]);
|
||||
GrTexture::PixelConfig config = fCurrDrawState.fTextures[s]->config();
|
||||
GrPixelConfig config = fCurrDrawState.fTextures[s]->config();
|
||||
|
||||
if (GrTexture::kRGB_565_PixelConfig != config &&
|
||||
GrTexture::kRGBX_8888_PixelConfig != config) {
|
||||
if (kRGB_565_GrPixelConfig != config &&
|
||||
kRGBX_8888_GrPixelConfig != config) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -28,42 +28,6 @@
|
||||
static const size_t VERTEX_POOL_VB_SIZE = 1 << 12;
|
||||
static const int VERTEX_POOL_VB_COUNT = 1;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
size_t GrTexture::BytesPerPixel(PixelConfig config) {
|
||||
switch (config) {
|
||||
case kAlpha_8_PixelConfig:
|
||||
case kIndex_8_PixelConfig:
|
||||
return 1;
|
||||
case kRGB_565_PixelConfig:
|
||||
case kRGBA_4444_PixelConfig:
|
||||
return 2;
|
||||
case kRGBA_8888_PixelConfig:
|
||||
case kRGBX_8888_PixelConfig:
|
||||
return 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool GrTexture::PixelConfigIsOpaque(PixelConfig config) {
|
||||
switch (config) {
|
||||
case GrTexture::kRGB_565_PixelConfig:
|
||||
case GrTexture::kRGBX_8888_PixelConfig:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool GrTexture::PixelConfigIsAlphaOnly(PixelConfig config) {
|
||||
switch (config) {
|
||||
case GrTexture::kAlpha_8_PixelConfig:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -75,6 +39,7 @@ GrGpu::GrGpu()
|
||||
, fCurrPoolStartVertex(0)
|
||||
, fCurrPoolIndexBuffer(NULL)
|
||||
, fCurrPoolStartIndex(0)
|
||||
, fContext(NULL)
|
||||
, fVertexPool(NULL)
|
||||
, fIndexPool(NULL)
|
||||
, fQuadIndexBuffer(NULL)
|
||||
@ -85,6 +50,7 @@ GrGpu::GrGpu()
|
||||
, fVertexPoolInUse(false)
|
||||
, fIndexPoolInUse(false)
|
||||
, fResourceHead(NULL) {
|
||||
|
||||
#if GR_DEBUG
|
||||
//gr_run_unittests();
|
||||
#endif
|
||||
@ -210,10 +176,17 @@ void GrGpu::forceRenderTargetFlush() {
|
||||
this->forceRenderTargetFlushHelper();
|
||||
}
|
||||
|
||||
bool GrGpu::readPixels(int left, int top, int width, int height,
|
||||
GrTexture::PixelConfig config, void* buffer) {
|
||||
bool GrGpu::readPixels(GrRenderTarget* target,
|
||||
int left, int top, int width, int height,
|
||||
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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -775,12 +748,6 @@ void GrGpu::printStats() const {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GrTexture::~GrTexture() {
|
||||
// use this to set a break-point if needed
|
||||
// Gr_clz(3);
|
||||
}
|
||||
|
||||
const GrSamplerState GrSamplerState::gClampNoFilter(
|
||||
GrSamplerState::kClamp_WrapMode,
|
||||
GrSamplerState::kClamp_WrapMode,
|
||||
|
@ -666,7 +666,7 @@ GrTexture* GrGpuGL::createTextureHelper(const TextureDesc& desc,
|
||||
return return_null_texture();
|
||||
}
|
||||
|
||||
glDesc.fUploadByteCount = GrTexture::BytesPerPixel(desc.fFormat);
|
||||
glDesc.fUploadByteCount = GrBytesPerPixel(desc.fFormat);
|
||||
|
||||
// in case we need a temporary, trimmed copy of the src pixels
|
||||
GrAutoSMalloc<128 * 128> trimStorage;
|
||||
@ -728,7 +728,7 @@ GrTexture* GrGpuGL::createTextureHelper(const TextureDesc& desc,
|
||||
DEFAULT_PARAMS.fWrapT));
|
||||
|
||||
GR_GL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, glDesc.fUploadByteCount));
|
||||
if (GrTexture::kIndex_8_PixelConfig == desc.fFormat &&
|
||||
if (kIndex_8_GrPixelConfig == desc.fFormat &&
|
||||
supports8BitPalette()) {
|
||||
// ES only supports CompressedTexImage2D, not CompressedTexSubimage2D
|
||||
GrAssert(desc.fWidth == glDesc.fAllocWidth);
|
||||
@ -1155,7 +1155,7 @@ void GrGpuGL::forceRenderTargetFlushHelper() {
|
||||
}
|
||||
|
||||
bool GrGpuGL::readPixelsHelper(int left, int top, int width, int height,
|
||||
GrTexture::PixelConfig config, void* buffer) {
|
||||
GrPixelConfig config, void* buffer) {
|
||||
GrGLenum internalFormat; // we don't use this for glReadPixels
|
||||
GrGLenum format;
|
||||
GrGLenum type;
|
||||
@ -1180,7 +1180,7 @@ bool GrGpuGL::readPixelsHelper(int left, int top, int width, int height,
|
||||
// now reverse the order of the rows, since GL's are bottom-to-top, but our
|
||||
// API presents top-to-bottom
|
||||
{
|
||||
size_t stride = width * GrTexture::BytesPerPixel(config);
|
||||
size_t stride = width * GrBytesPerPixel(config);
|
||||
GrAutoMalloc rowStorage(stride);
|
||||
void* tmp = rowStorage.get();
|
||||
|
||||
@ -1767,13 +1767,13 @@ void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) {
|
||||
}
|
||||
}
|
||||
|
||||
bool GrGpuGL::canBeTexture(GrTexture::PixelConfig config,
|
||||
bool GrGpuGL::canBeTexture(GrPixelConfig config,
|
||||
GrGLenum* internalFormat,
|
||||
GrGLenum* format,
|
||||
GrGLenum* type) {
|
||||
switch (config) {
|
||||
case GrTexture::kRGBA_8888_PixelConfig:
|
||||
case GrTexture::kRGBX_8888_PixelConfig: // todo: can we tell it our X?
|
||||
case kRGBA_8888_GrPixelConfig:
|
||||
case kRGBX_8888_GrPixelConfig: // todo: can we tell it our X?
|
||||
*format = GR_GL_32BPP_COLOR_FORMAT;
|
||||
if (GR_GL_SUPPORT_ES) {
|
||||
// according to GL_EXT_texture_format_BGRA8888 the *internal*
|
||||
@ -1784,17 +1784,17 @@ bool GrGpuGL::canBeTexture(GrTexture::PixelConfig config,
|
||||
}
|
||||
*type = GR_GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case GrTexture::kRGB_565_PixelConfig:
|
||||
case kRGB_565_GrPixelConfig:
|
||||
*format = GR_GL_RGB;
|
||||
*internalFormat = GR_GL_RGB;
|
||||
*type = GR_GL_UNSIGNED_SHORT_5_6_5;
|
||||
break;
|
||||
case GrTexture::kRGBA_4444_PixelConfig:
|
||||
case kRGBA_4444_GrPixelConfig:
|
||||
*format = GR_GL_RGBA;
|
||||
*internalFormat = GR_GL_RGBA;
|
||||
*type = GR_GL_UNSIGNED_SHORT_4_4_4_4;
|
||||
break;
|
||||
case GrTexture::kIndex_8_PixelConfig:
|
||||
case kIndex_8_GrPixelConfig:
|
||||
if (this->supports8BitPalette()) {
|
||||
*format = GR_GL_PALETTE8_RGBA8;
|
||||
*internalFormat = GR_GL_PALETTE8_RGBA8;
|
||||
@ -1803,7 +1803,7 @@ bool GrGpuGL::canBeTexture(GrTexture::PixelConfig config,
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case GrTexture::kAlpha_8_PixelConfig:
|
||||
case kAlpha_8_GrPixelConfig:
|
||||
*format = GR_GL_ALPHA;
|
||||
*internalFormat = GR_GL_ALPHA;
|
||||
*type = GR_GL_UNSIGNED_BYTE;
|
||||
@ -1835,23 +1835,23 @@ void GrGpuGL::setSpareTextureUnit() {
|
||||
RenderBufferStorage* has to be a specific format (not a base format like
|
||||
GL_RGBA).
|
||||
*/
|
||||
bool GrGpuGL::fboInternalFormat(GrTexture::PixelConfig config, GrGLenum* format) {
|
||||
bool GrGpuGL::fboInternalFormat(GrPixelConfig config, GrGLenum* format) {
|
||||
switch (config) {
|
||||
case GrTexture::kRGBA_8888_PixelConfig:
|
||||
case GrTexture::kRGBX_8888_PixelConfig:
|
||||
case kRGBA_8888_GrPixelConfig:
|
||||
case kRGBX_8888_GrPixelConfig:
|
||||
if (fRGBA8Renderbuffer) {
|
||||
*format = GR_GL_RGBA8;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case GrTexture::kRGB_565_PixelConfig:
|
||||
case kRGB_565_GrPixelConfig:
|
||||
GrAssert(GR_GL_SUPPORT_ES); // ES2 supports 565. ES1 supports it
|
||||
// with FBO extension desktop GL has
|
||||
// no such internal format
|
||||
*format = GR_GL_RGB565;
|
||||
return true;
|
||||
case GrTexture::kRGBA_4444_PixelConfig:
|
||||
case kRGBA_4444_GrPixelConfig:
|
||||
*format = GR_GL_RGBA4;
|
||||
return true;
|
||||
default:
|
||||
|
@ -87,7 +87,7 @@ protected:
|
||||
virtual void forceRenderTargetFlushHelper();
|
||||
|
||||
virtual bool readPixelsHelper(int left, int top, int width, int height,
|
||||
GrTexture::PixelConfig, void* buffer);
|
||||
GrPixelConfig, void* buffer);
|
||||
|
||||
virtual void drawIndexedHelper(GrPrimitiveType type,
|
||||
uint32_t startVertex,
|
||||
@ -149,11 +149,11 @@ private:
|
||||
void flushStencil();
|
||||
void resolveTextureRenderTarget(GrGLTexture* texture);
|
||||
|
||||
bool canBeTexture(GrTexture::PixelConfig config,
|
||||
bool canBeTexture(GrPixelConfig config,
|
||||
GrGLenum* internalFormat,
|
||||
GrGLenum* format,
|
||||
GrGLenum* type);
|
||||
bool fboInternalFormat(GrTexture::PixelConfig config, GrGLenum* format);
|
||||
bool fboInternalFormat(GrPixelConfig config, GrGLenum* format);
|
||||
|
||||
friend class GrGLVertexBuffer;
|
||||
friend class GrGLIndexBuffer;
|
||||
|
@ -192,7 +192,7 @@ bool GrGpuGLFixed::flushGraphicsState(GrPrimitiveType type) {
|
||||
GrGLTexture* texture = (GrGLTexture*)fCurrDrawState.fTextures[s];
|
||||
if (NULL != texture) {
|
||||
TextureEnvRGBOperands nextRGBOperand0 =
|
||||
(texture->config() == GrTexture::kAlpha_8_PixelConfig) ?
|
||||
(GrPixelConfigIsAlphaOnly(texture->config())) ?
|
||||
kAlpha_TextureEnvRGBOperand :
|
||||
kColor_TextureEnvRGBOperand;
|
||||
if (fHWRGBOperand0[s] != nextRGBOperand0) {
|
||||
|
@ -508,7 +508,7 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (GrTexture::kAlpha_8_PixelConfig == texture->config()) {
|
||||
if (GrPixelConfigIsAlphaOnly(texture->config())) {
|
||||
stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation;
|
||||
} else {
|
||||
stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation;
|
||||
|
@ -1042,7 +1042,7 @@ void GrGpuGLShaders2::getProgramDesc(GrPrimitiveType primType, ProgramDesc* desc
|
||||
GrAssert(!"Unexpected sample mode!");
|
||||
break;
|
||||
}
|
||||
if (GrTexture::kAlpha_8_PixelConfig == texture->config()) {
|
||||
if (GrPixelConfigIsAlphaOnly(texture->config())) {
|
||||
stage.fModulation = StageDesc::kAlpha_Modulation;
|
||||
} else {
|
||||
stage.fModulation = StageDesc::kColor_Modulation;
|
||||
|
@ -47,7 +47,7 @@ void GrTextContext::flushGlyphs() {
|
||||
GrAssert(fCurrTexture);
|
||||
fDrawTarget->setTexture(TEXT_STAGE, fCurrTexture);
|
||||
|
||||
if (!GrTexture::PixelConfigIsAlphaOnly(fCurrTexture->config())) {
|
||||
if (!GrPixelConfigIsAlphaOnly(fCurrTexture->config())) {
|
||||
if (kOne_BlendCoeff != fPaint.fSrcBlendCoeff ||
|
||||
kISA_BlendCoeff != fPaint.fDstBlendCoeff ||
|
||||
NULL != fPaint.getTexture()) {
|
||||
|
45
gpu/src/GrTexture.cpp
Normal file
45
gpu/src/GrTexture.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
Copyright 2011 Google Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "GrTexture.h"
|
||||
#include "GrContext.h"
|
||||
|
||||
bool GrRenderTarget::readPixels(int left, int top, int width, int height,
|
||||
GrPixelConfig config, void* buffer) {
|
||||
// go through context so that all necessary flushing occurs
|
||||
GrContext* context = this->getGpu()->getContext();
|
||||
GrAssert(NULL != context);
|
||||
return context->readRenderTargetPixels(this,
|
||||
left, top,
|
||||
width, height,
|
||||
config, buffer);
|
||||
}
|
||||
|
||||
GrTexture::~GrTexture() {
|
||||
// use this to set a break-point if needed
|
||||
// Gr_clz(3);
|
||||
}
|
||||
|
||||
bool GrTexture::readPixels(int left, int top, int width, int height,
|
||||
GrPixelConfig config, void* buffer) {
|
||||
// go through context so that all necessary flushing occurs
|
||||
GrContext* context = this->getGpu()->getContext();
|
||||
GrAssert(NULL != context);
|
||||
return context->readTexturePixels(this,
|
||||
left, top,
|
||||
width, height,
|
||||
config, buffer);
|
||||
}
|
@ -990,6 +990,7 @@
|
||||
'../gpu/src/GrTextContext.cpp',
|
||||
'../gpu/src/GrTextStrike.cpp',
|
||||
'../gpu/src/GrTextStrike_impl.h',
|
||||
'../gpu/src/GrTexture.cpp',
|
||||
'../gpu/src/GrTextureCache.cpp',
|
||||
'../gpu/src/gr_unittests.cpp',
|
||||
|
||||
|
@ -129,10 +129,10 @@ public:
|
||||
* Convert the SkBitmap::Config to the corresponding PixelConfig, or
|
||||
* kUnknown_PixelConfig if the conversion cannot be done.
|
||||
*/
|
||||
static GrTexture::PixelConfig BitmapConfig2PixelConfig(SkBitmap::Config,
|
||||
bool isOpaque);
|
||||
static GrPixelConfig BitmapConfig2PixelConfig(SkBitmap::Config,
|
||||
bool isOpaque);
|
||||
|
||||
static GrTexture::PixelConfig Bitmap2PixelConfig(const SkBitmap& bm) {
|
||||
static GrPixelConfig Bitmap2PixelConfig(const SkBitmap& bm) {
|
||||
return BitmapConfig2PixelConfig(bm.config(), bm.isOpaque());
|
||||
}
|
||||
|
||||
|
@ -47,5 +47,31 @@ private:
|
||||
typedef SkPixelRef INHERITED;
|
||||
};
|
||||
|
||||
class SkGrRenderTargetPixelRef : public SkPixelRef {
|
||||
public:
|
||||
SkGrRenderTargetPixelRef(GrRenderTarget* rt);
|
||||
virtual ~SkGrRenderTargetPixelRef();
|
||||
|
||||
// override from SkPixelRef
|
||||
virtual SkGpuTexture* getTexture();
|
||||
|
||||
protected:
|
||||
// override from SkPixelRef
|
||||
virtual void* onLockPixels(SkColorTable** ptr) {
|
||||
if (ptr) {
|
||||
*ptr = NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// override from SkPixelRef
|
||||
virtual void onUnlockPixels() {}
|
||||
virtual bool onReadPixels(SkBitmap* dst, const SkIRect* subset);
|
||||
|
||||
private:
|
||||
GrRenderTarget* fRenderTarget;
|
||||
typedef SkPixelRef INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -766,17 +766,12 @@ void SampleWindow::afterChildren(SkCanvas* orig) {
|
||||
|
||||
SkCanvas* canvas = fGpuCanvas ? fGpuCanvas : orig;
|
||||
SkDevice* device = canvas->getDevice();
|
||||
SkBitmap bitmap;
|
||||
SkIRect bounds = {
|
||||
0, 0,
|
||||
SkScalarRound(this->width()),
|
||||
SkScalarRound(this->height())
|
||||
};
|
||||
if (device->readPixels(bounds, &bitmap)) {
|
||||
SkBitmap bmp;
|
||||
if (device->accessBitmap(false).copyTo(&bmp, SkBitmap::kARGB_8888_Config)) {
|
||||
static int gSampleGrabCounter;
|
||||
SkString name;
|
||||
name.printf("sample_grab_%d", gSampleGrabCounter++);
|
||||
SkImageEncoder::EncodeFile(name.c_str(), bitmap,
|
||||
SkImageEncoder::EncodeFile(name.c_str(), bmp,
|
||||
SkImageEncoder::kPNG_Type, 100);
|
||||
}
|
||||
}
|
||||
|
@ -869,10 +869,7 @@ bool SkBitmap::copyTo(SkBitmap* dst, Config dstConfig, Allocator* alloc) const {
|
||||
SkBitmap tmpSrc;
|
||||
const SkBitmap* src = this;
|
||||
|
||||
if (this->getTexture()) {
|
||||
if (!fPixelRef->readPixels(&tmpSrc)) {
|
||||
return false;
|
||||
}
|
||||
if (fPixelRef && fPixelRef->readPixels(&tmpSrc)) {
|
||||
SkASSERT(tmpSrc.width() == this->width());
|
||||
SkASSERT(tmpSrc.height() == this->height());
|
||||
|
||||
|
@ -171,11 +171,15 @@ SkGpuDevice::SkGpuDevice(GrContext* context,
|
||||
this->width(), this->height());
|
||||
GrAssert(false);
|
||||
}
|
||||
} else if (Current3DApiRenderTarget() == renderTargetOrNull) {
|
||||
fRenderTarget = fContext->createRenderTargetFrom3DApiState();
|
||||
} else {
|
||||
fRenderTarget = renderTargetOrNull;
|
||||
fRenderTarget->ref();
|
||||
if (Current3DApiRenderTarget() == renderTargetOrNull) {
|
||||
fRenderTarget = fContext->createRenderTargetFrom3DApiState();
|
||||
} else {
|
||||
fRenderTarget = renderTargetOrNull;
|
||||
fRenderTarget->ref();
|
||||
}
|
||||
SkGrRenderTargetPixelRef* pr = new SkGrRenderTargetPixelRef(fRenderTarget);
|
||||
this->setPixelRef(pr, 0)->unref();
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,15 +237,12 @@ bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
|
||||
}
|
||||
|
||||
SkAutoLockPixels alp(tmp);
|
||||
fContext->setRenderTarget(fRenderTarget);
|
||||
// we aren't setting the clip or matrix, so mark as dirty
|
||||
// we don't need to set them for this call and don't have them anyway
|
||||
fNeedPrepareRenderTarget = true;
|
||||
|
||||
if (!fContext->readPixels(bounds.fLeft, bounds.fTop,
|
||||
bounds.width(), bounds.height(),
|
||||
GrTexture::kRGBA_8888_PixelConfig,
|
||||
tmp.getPixels())) {
|
||||
if (!fContext->readRenderTargetPixels(fRenderTarget,
|
||||
bounds.fLeft, bounds.fTop,
|
||||
bounds.width(), bounds.height(),
|
||||
kRGBA_8888_GrPixelConfig,
|
||||
tmp.getPixels())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -254,8 +255,8 @@ void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
|
||||
if (!bitmap.readyToDraw()) {
|
||||
return;
|
||||
}
|
||||
GrTexture::PixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
|
||||
bitmap.isOpaque());
|
||||
GrPixelConfig config = SkGr::BitmapConfig2PixelConfig(bitmap.config(),
|
||||
bitmap.isOpaque());
|
||||
fContext->setRenderTarget(fRenderTarget);
|
||||
// we aren't setting the clip or matrix, so mark as dirty
|
||||
// we don't need to set them for this call and don't have them anyway
|
||||
@ -709,7 +710,7 @@ static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
|
||||
GrGpu::kNone_AALevel,
|
||||
dstM.fBounds.width(),
|
||||
dstM.fBounds.height(),
|
||||
GrTexture::kAlpha_8_PixelConfig
|
||||
kAlpha_8_GrPixelConfig
|
||||
};
|
||||
|
||||
GrTexture* texture = context->createUncachedTexture(desc, dstM.fImage,
|
||||
|
@ -213,25 +213,25 @@ GrPathFill SkGrClipIterator::getPathFill() const {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GrTexture::PixelConfig SkGr::BitmapConfig2PixelConfig(SkBitmap::Config config,
|
||||
GrPixelConfig SkGr::BitmapConfig2PixelConfig(SkBitmap::Config config,
|
||||
bool isOpaque) {
|
||||
switch (config) {
|
||||
case SkBitmap::kA8_Config:
|
||||
return GrTexture::kAlpha_8_PixelConfig;
|
||||
return kAlpha_8_GrPixelConfig;
|
||||
case SkBitmap::kIndex8_Config:
|
||||
return GrTexture::kIndex_8_PixelConfig;
|
||||
return kIndex_8_GrPixelConfig;
|
||||
case SkBitmap::kRGB_565_Config:
|
||||
return GrTexture::kRGB_565_PixelConfig;
|
||||
return kRGB_565_GrPixelConfig;
|
||||
case SkBitmap::kARGB_4444_Config:
|
||||
return GrTexture::kRGBA_4444_PixelConfig;
|
||||
return kRGBA_4444_GrPixelConfig;
|
||||
case SkBitmap::kARGB_8888_Config:
|
||||
if (isOpaque) {
|
||||
return GrTexture::kRGBX_8888_PixelConfig;
|
||||
return kRGBX_8888_GrPixelConfig;
|
||||
} else {
|
||||
return GrTexture::kRGBA_8888_PixelConfig;
|
||||
return kRGBA_8888_GrPixelConfig;
|
||||
}
|
||||
default:
|
||||
return GrTexture::kUnknown_PixelConfig;
|
||||
return kUnknown_GrPixelConfig;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,8 +16,12 @@
|
||||
|
||||
|
||||
#include "SkGrTexturePixelRef.h"
|
||||
|
||||
#include "GrTexture.h"
|
||||
|
||||
#include "SkRect.h"
|
||||
#include "SkBitmap.h"
|
||||
|
||||
SkGrTexturePixelRef::SkGrTexturePixelRef(GrTexture* tex) {
|
||||
fTexture = tex;
|
||||
GrSafeRef(tex);
|
||||
@ -28,6 +32,71 @@ SkGrTexturePixelRef::~SkGrTexturePixelRef() {
|
||||
}
|
||||
|
||||
bool SkGrTexturePixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
|
||||
return false;
|
||||
if (NULL != fTexture && fTexture->isValid()) {
|
||||
int left, top, width, height;
|
||||
if (NULL != subset) {
|
||||
left = subset->fLeft;
|
||||
width = subset->width();
|
||||
top = subset->fTop;
|
||||
height = subset->height();
|
||||
} else {
|
||||
left = 0;
|
||||
width = fTexture->width();
|
||||
top = 0;
|
||||
height = fTexture->height();
|
||||
}
|
||||
dst->setConfig(SkBitmap::kARGB_8888_Config, width, height);
|
||||
dst->allocPixels();
|
||||
SkAutoLockPixels al(*dst);
|
||||
void* buffer = dst->getPixels();
|
||||
return fTexture->readPixels(left, top, width, height,
|
||||
kRGBA_8888_GrPixelConfig,
|
||||
buffer);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkGrRenderTargetPixelRef::SkGrRenderTargetPixelRef(GrRenderTarget* rt) {
|
||||
fRenderTarget = rt;
|
||||
GrSafeRef(fRenderTarget);
|
||||
}
|
||||
|
||||
SkGrRenderTargetPixelRef::~SkGrRenderTargetPixelRef() {
|
||||
GrSafeUnref(fRenderTarget);
|
||||
}
|
||||
|
||||
SkGpuTexture* SkGrRenderTargetPixelRef::getTexture() {
|
||||
if (NULL != fRenderTarget) {
|
||||
return (SkGpuTexture*) fRenderTarget->asTexture();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool SkGrRenderTargetPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
|
||||
if (NULL != fRenderTarget && fRenderTarget->isValid()) {
|
||||
int left, top, width, height;
|
||||
if (NULL != subset) {
|
||||
left = subset->fLeft;
|
||||
width = subset->width();
|
||||
top = subset->fTop;
|
||||
height = subset->height();
|
||||
} else {
|
||||
left = 0;
|
||||
width = fRenderTarget->width();
|
||||
top = 0;
|
||||
height = fRenderTarget->height();
|
||||
}
|
||||
dst->setConfig(SkBitmap::kARGB_8888_Config, width, height);
|
||||
dst->allocPixels();
|
||||
SkAutoLockPixels al(*dst);
|
||||
void* buffer = dst->getPixels();
|
||||
return fRenderTarget->readPixels(left, top, width, height,
|
||||
kRGBA_8888_GrPixelConfig,
|
||||
buffer);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user