Make all pixel ops go thru ctx so we can correctly flush. Unify two texture upload code paths.

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



git-svn-id: http://skia.googlecode.com/svn/trunk@2701 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
bsalomon@google.com 2011-11-16 20:36:03 +00:00
parent aa336da083
commit 6f3795105b
18 changed files with 426 additions and 252 deletions

View File

@ -124,9 +124,9 @@ protected:
((x + y) % 2) ? (i ? green : red) : blue;
}
}
// BUG: uploadTextureData doesn't force a flush
ctx->flush();
texture->uploadTextureData(S, i ? 0 : S, S, S, gTextureData, 4 * stride);
texture->writePixels(S, (i ? 0 : S), S, S,
texture->config(), gTextureData,
4 * stride);
ctx->drawRect(paint, GrRect::MakeWH(2*S, 2*S));
}
}

View File

@ -445,10 +445,10 @@ public:
* FlushBits.
*/
void flush(int flagsBitfield = 0);
/**
* Reads a rectangle of pixels from a render target.
* @param renderTarget the render target to read from. NULL means the
* @param target 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)
@ -456,42 +456,88 @@ public:
* @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.
* @param rowBytes number of bytes bewtween consecueive rows. Zero
* @param rowBytes number of bytes bewtween consecutive rows. Zero
* means rows are tightly packed.
*
* @return true if the read succeeded, false if not. The read can fail
* because of a unsupported pixel config or because no render
* because of an unsupported pixel config or because no render
* target is currently set.
*/
bool readRenderTargetPixels(GrRenderTarget* target,
int left, int top, int width, int height,
GrPixelConfig config, void* buffer,
size_t rowBytes = 0);
size_t rowBytes) {
return this->internalReadRenderTargetPixels(target, left, top,
width, height,
config, buffer,
rowBytes, 0);
}
/**
* Copy the src pixels [buffer, rowbytes, pixelconfig] into a render target
* at the specified rectangle.
* @param target the render target to write into. NULL means the
* current render target.
* @param left left edge of the rectangle to write (inclusive)
* @param top top edge of the rectangle to write (inclusive)
* @param width width of rectangle to write in pixels.
* @param height height of rectangle to write in pixels.
* @param config the pixel config of the source buffer
* @param buffer memory to read the rectangle from.
* @param rowBytes number of bytes bewtween consecutive rows. Zero
* means rows are tightly packed.
*/
void writeRenderTargetPixels(GrRenderTarget* target,
int left, int top, int width, int height,
GrPixelConfig config, const void* buffer,
size_t rowBytes) {
this->internalWriteRenderTargetPixels(target, left, top, width, height,
config, buffer, rowBytes, 0);
}
/**
* Reads a rectangle of pixels from a texture.
* @param texture the render target to read from.
* @param texture the texture 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.
* @param rowBytes number of bytes bewtween consecutive rows. Zero
* means rows are tightly packed.
*
* @return true if the read succeeded, false if not. The read can fail
* because of a unsupported pixel config.
* because of an unsupported pixel config.
*/
bool readTexturePixels(GrTexture* target,
bool readTexturePixels(GrTexture* texture,
int left, int top, int width, int height,
GrPixelConfig config, void* buffer);
GrPixelConfig config, void* buffer,
size_t rowBytes) {
return this->internalReadTexturePixels(texture, left, top,
width, height,
config, buffer, rowBytes, 0);
}
/**
* Copy the src pixels [buffer, stride, pixelconfig] into the current
* render-target at the specified rectangle.
* Writes a rectangle of pixels to a texture.
* @param texture the render target to read from.
* @param left left edge of the rectangle to write (inclusive)
* @param top top edge of the rectangle to write (inclusive)
* @param width width of rectangle to write in pixels.
* @param height height of rectangle to write in pixels.
* @param config the pixel config of the source buffer
* @param buffer memory to read pixels from
* @param rowBytes number of bytes bewtween consecutive rows. Zero
* means rows are tightly packed.
*/
void writePixels(int left, int top, int width, int height,
GrPixelConfig, const void* buffer, size_t stride);
void writeTexturePixels(GrTexture* texture,
int left, int top, int width, int height,
GrPixelConfig config, const void* buffer,
size_t rowBytes) {
this->internalWriteTexturePixels(texture, left, top, width, height,
config, buffer, rowBytes, 0);
}
/**
* Applies a 1D convolution kernel in the X direction to a rectangle of
* pixels from a given texture.
@ -654,7 +700,43 @@ private:
float imageIncrement[2],
const float* kernel,
int kernelWidth);
/**
* Flags to the internal read/write pixels funcs
*/
enum PixelOpsFlags {
kDontFlush_PixelOpsFlag = 0x1,
};
bool internalReadRenderTargetPixels(GrRenderTarget* target,
int left, int top,
int width, int height,
GrPixelConfig config, void* buffer,
size_t rowBytes, uint32_t flags);
void internalWriteRenderTargetPixels(GrRenderTarget* target,
int left, int top,
int width, int height,
GrPixelConfig, const void* buffer,
size_t rowBytes, uint32_t flags);
bool internalReadTexturePixels(GrTexture* texture,
int left, int top,
int width, int height,
GrPixelConfig config, void* buffer,
size_t rowBytes, uint32_t flags);
void internalWriteTexturePixels(GrTexture* texture,
int left, int top,
int width, int height,
GrPixelConfig config, const void* buffer,
size_t rowBytes, uint32_t flags);
// needed for access to internalWriteTexturePixels. TODO: make GrContext
// be a facade for an internal class. Then functions that are public on the
// internal class would have only be callable in src/gpu. The facade would
// only have to functions necessary for clients.
friend class GrAtlas;
// computes vertex layout bits based on the paint. If paint expresses
// a texture for a stage, the stage coords will be bound to postitions
// unless hasTexCoords[s]==true in which case stage s's input coords

View File

@ -123,12 +123,29 @@ public:
* @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.
* @param rowBytes number of bytes bewtween consecutive rows. Zero
* means rows are tightly packed.
*
* @return true if the read succeeded, false if not. The read can fail
* because of a unsupported pixel config.
* because of an unsupported pixel config.
*/
bool readPixels(int left, int top, int width, int height,
GrPixelConfig config, void* buffer);
GrPixelConfig config, void* buffer, size_t rowBytes);
/**
* Copy the src pixels [buffer, rowbytes, pixelconfig] into the render
* target at the specified rectangle.
* @param left left edge of the rectangle to write (inclusive)
* @param top top edge of the rectangle to write (inclusive)
* @param width width of rectangle to write in pixels.
* @param height height of rectangle to write in pixels.
* @param config the pixel config of the source buffer
* @param buffer memory to read the rectangle from.
* @param rowBytes number of bytes bewtween consecutive rows. Zero
* means rows are tightly packed.
*/
void writePixels(int left, int top, int width, int height,
GrPixelConfig config, const void* buffer, size_t rowBytes);
// 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

View File

@ -54,38 +54,37 @@ public:
}
/**
* Updates a subrectangle of texels in the texture.
*
* @param x left edge of rectangle to update
* @param y top edge of rectangle to update
* @param width width of rectangle to update
* @param height height of rectangle to update
* @param srcData width*height texels of data in same format that was
* used at texture creation.
* @param rowBytes number of bytes per row in srcData, 0 means rows are
* packed
*/
virtual void uploadTextureData(int x,
int y,
int width,
int height,
const void* srcData,
size_t rowBytes) = 0;
/**
* Reads a rectangle of pixels from the texture.
* Read 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.
* @param rowBytes number of bytes bewtween consecutive rows. Zero
* means rows are tightly packed.
*
* @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);
GrPixelConfig config, void* buffer,
size_t rowBytes);
/**
* Writes a rectangle of pixels to the texture.
* @param left left edge of the rectangle to write (inclusive)
* @param top top edge of the rectangle to write (inclusive)
* @param width width of rectangle to write in pixels.
* @param height height of rectangle to write in pixels.
* @param config the pixel config of the source buffer
* @param buffer memory to read pixels from
* @param rowBytes number of bytes bewtween consecutive rows. Zero
* means rows are tightly packed.
*/
void writePixels(int left, int top, int width, int height,
GrPixelConfig config, const void* buffer,
size_t rowBytes);
/**
* Retrieves the render target underlying this texture that can be passed to

View File

@ -177,10 +177,10 @@ public:
// need to send the raster bits to the (gpu) window
fGrContext->setRenderTarget(fGrRenderTarget);
const SkBitmap& bm = win->getBitmap();
fGrContext->writePixels(0, 0, bm.width(), bm.height(),
kSkia8888_PM_GrPixelConfig,
bm.getPixels(),
bm.rowBytes());
fGrRenderTarget->writePixels(0, 0, bm.width(), bm.height(),
kSkia8888_PM_GrPixelConfig,
bm.getPixels(),
bm.rowBytes());
}
}
win->presentGL();
@ -211,7 +211,7 @@ public:
desc.fStencilBits = 8;
desc.fSampleCnt = 0;
desc.fRenderTargetHandle = 0;
fGrRenderTarget = fNullGrContext->createPlatformRenderTarget(desc);
fNullGrRenderTarget = fNullGrContext->createPlatformRenderTarget(desc);
}
}

View File

@ -9,6 +9,7 @@
#include "GrAtlas.h"
#include "GrContext.h"
#include "GrGpu.h"
#include "GrRectanizer.h"
#include "GrPlotMgr.h"
@ -109,7 +110,14 @@ bool GrAtlas::addSubImage(int width, int height, const void* image,
image = storage.get();
}
adjustForPlot(loc, fPlot);
fTexture->uploadTextureData(loc->fX, loc->fY, dstW, dstH, image, 0);
GrContext* context = fTexture->getContext();
// We call the internal version so that we don't force a flush. We assume
// our caller is smart and hasn't referenced the part of the texture we're
// about to update since the last flush.
context->internalWriteTexturePixels(fTexture, loc->fX, loc->fY,
dstW, dstH, fTexture->config(),
image, 0,
GrContext::kDontFlush_PixelOpsFlag);
// now tell the caller to skip the top/left BORDER
loc->fX += BORDER;

View File

@ -1637,28 +1637,59 @@ void GrContext::flushDrawBuffer() {
#endif
}
bool GrContext::readTexturePixels(GrTexture* texture,
int left, int top, int width, int height,
GrPixelConfig config, void* buffer) {
void GrContext::internalWriteTexturePixels(GrTexture* texture,
int left, int top,
int width, int height,
GrPixelConfig config,
const void* buffer,
size_t rowBytes,
uint32_t flags) {
SK_TRACE_EVENT0("GrContext::writeTexturePixels");
if (!(kDontFlush_PixelOpsFlag & flags)) {
this->flush();
}
// TODO: use scratch texture to perform conversion
if (GrPixelConfigIsUnpremultiplied(texture->config()) !=
GrPixelConfigIsUnpremultiplied(config)) {
return;
}
fGpu->writeTexturePixels(texture, left, top, width, height,
config, buffer, rowBytes);
}
bool GrContext::internalReadTexturePixels(GrTexture* texture,
int left, int top,
int width, int height,
GrPixelConfig config,
void* buffer,
size_t rowBytes,
uint32_t flags) {
SK_TRACE_EVENT0("GrContext::readTexturePixels");
// TODO: code read pixels for textures that aren't rendertargets
this->flush();
if (!(kDontFlush_PixelOpsFlag & flags)) {
this->flush();
}
GrRenderTarget* target = texture->asRenderTarget();
if (NULL != target) {
return this->readRenderTargetPixels(target,
left, top, width, height,
config, buffer, 0);
return this->internalReadRenderTargetPixels(target,
left, top, width, height,
config, buffer, rowBytes,
flags);
} else {
return false;
}
}
bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
int left, int top, int width, int height,
GrPixelConfig config, void* buffer,
size_t rowBytes) {
bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target,
int left, int top,
int width, int height,
GrPixelConfig config,
void* buffer,
size_t rowBytes,
uint32_t flags) {
SK_TRACE_EVENT0("GrContext::readRenderTargetPixels");
if (NULL == target) {
target = fGpu->getRenderTarget();
@ -1675,7 +1706,9 @@ bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
return false;
}
this->flush();
if (!(kDontFlush_PixelOpsFlag & flags)) {
this->flush();
}
GrTexture* src = target->asTexture();
bool swapRAndB = NULL != src &&
@ -1751,16 +1784,25 @@ bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
config, buffer, rowBytes, flipY);
}
void GrContext::writePixels(int left, int top, int width, int height,
GrPixelConfig config, const void* buffer,
size_t stride) {
SK_TRACE_EVENT0("GrContext::writePixels");
void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target,
int left, int top,
int width, int height,
GrPixelConfig config,
const void* buffer,
size_t rowBytes,
uint32_t flags) {
SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels");
if (NULL == target) {
target = fGpu->getRenderTarget();
if (NULL == target) {
return;
}
}
// TODO: when underlying api has a direct way to do this we should use it
// (e.g. glDrawPixels on desktop GL).
this->flush(kForceCurrentRenderTarget_FlushBit);
const GrTextureDesc desc = {
kNone_GrTextureFlags, kNone_GrAALevel, width, height, { config }
};
@ -1769,7 +1811,8 @@ void GrContext::writePixels(int left, int top, int width, int height,
if (NULL == texture) {
return;
}
texture->uploadTextureData(0, 0, width, height, buffer, stride);
this->internalWriteTexturePixels(texture, 0, 0, width, height,
config, buffer, rowBytes, flags);
GrDrawTarget::AutoStateRestore asr(fGpu);
reset_target_state(fGpu);
@ -1777,7 +1820,7 @@ void GrContext::writePixels(int left, int top, int width, int height,
GrMatrix matrix;
matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top));
fGpu->setViewMatrix(matrix);
fGpu->setRenderTarget(target);
fGpu->setTexture(0, texture);
GrSamplerState sampler;

View File

@ -35,8 +35,7 @@ void GrGLTexture::init(GrGpuGL* gpu,
fTexIDObj = new GrGLTexID(GPUGL->glInterface(),
textureDesc.fTextureID,
textureDesc.fOwnsID);
fUploadFormat = textureDesc.fUploadFormat;
fUploadType = textureDesc.fUploadType;
fInternalFormat = textureDesc.fInternalFormat;
fOrientation = textureDesc.fOrientation;
if (NULL != rtDesc) {
@ -86,83 +85,6 @@ void GrGLTexture::onAbandon() {
}
}
void GrGLTexture::uploadTextureData(int x,
int y,
int width,
int height,
const void* srcData,
size_t rowBytes) {
GrIRect bounds = GrIRect::MakeWH(this->width(), this->height());
GrIRect subrect = GrIRect::MakeXYWH(x,y,width, height);
if (!bounds.contains(subrect)) {
return;
}
GPUGL->setSpareTextureUnit();
// ES2 glCompressedTexSubImage2D doesn't support any formats
// (at least without extensions)
GrAssert(fUploadFormat != GR_GL_PALETTE8_RGBA8);
// in case we need a temporary, trimmed copy of the src pixels
SkAutoSMalloc<128 * 128> tempStorage;
size_t bpp = GrBytesPerPixel(this->config());
size_t trimRowBytes = width * bpp;
if (!rowBytes) {
rowBytes = trimRowBytes;
}
/*
* check whether to allocate a temporary buffer for flipping y or
* because our srcData has extra bytes past each row. If so, we need
* to trim those off here, since GL ES may not let us specify
* GL_UNPACK_ROW_LENGTH.
*/
bool restoreGLRowLength = false;
bool flipY = kBottomUp_Orientation == fOrientation;
if (GPUGL->glCaps().fUnpackRowLengthSupport && !flipY) {
// can't use this for flipping, only non-neg values allowed. :(
if (srcData && rowBytes != trimRowBytes) {
GrGLint rowLength = static_cast<GrGLint>(rowBytes / bpp);
GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength));
restoreGLRowLength = true;
}
} else {
if (srcData && (trimRowBytes != rowBytes || flipY)) {
// copy the data into our new storage, skipping the trailing bytes
size_t trimSize = height * trimRowBytes;
const char* src = (const char*)srcData;
if (flipY) {
src += (height - 1) * rowBytes;
}
char* dst = (char*)tempStorage.reset(trimSize);
for (int y = 0; y < height; y++) {
memcpy(dst, src, trimRowBytes);
if (flipY) {
src -= rowBytes;
} else {
src += rowBytes;
}
dst += trimRowBytes;
}
// now point srcData to our copied version
srcData = tempStorage.get();
}
}
if (flipY) {
y = this->height() - (y + height);
}
GL_CALL(BindTexture(GR_GL_TEXTURE_2D, fTexIDObj->id()));
GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, static_cast<GrGLint>(bpp)));
GL_CALL(TexSubImage2D(GR_GL_TEXTURE_2D, 0, x, y, width, height,
fUploadFormat, fUploadType, srcData));
if (restoreGLRowLength) {
GrAssert(GPUGL->glCaps().fUnpackRowLengthSupport);
GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
}
}
intptr_t GrGLTexture::getTextureHandle() const {
return fTexIDObj->id();
}

View File

@ -64,9 +64,8 @@ public:
int fHeight;
GrPixelConfig fConfig;
GrGLuint fTextureID;
GrGLenum fInternalFormat;
bool fOwnsID;
GrGLenum fUploadFormat;
GrGLenum fUploadType;
Orientation fOrientation;
};
@ -82,13 +81,6 @@ public:
virtual ~GrGLTexture() { this->release(); }
// overrides of GrTexture
virtual void uploadTextureData(int x,
int y,
int width,
int height,
const void* srcData,
size_t rowBytes);
virtual intptr_t getTextureHandle() const;
// these functions
@ -103,8 +95,7 @@ public:
}
GrGLuint textureID() const { return fTexIDObj->id(); }
GrGLenum uploadFormat() const { return fUploadFormat; }
GrGLenum uploadType() const { return fUploadType; }
GrGLenum internalFormat() const { return fInternalFormat; }
// Ganesh assumes texture coordinates have their origin
// in the top-left corner of the image. OpenGL, however,
@ -128,8 +119,7 @@ private:
TexParams fTexParams;
GrGpu::ResetTimestamp fTexParamsTimestamp;
GrGLTexID* fTexIDObj;
GrGLenum fUploadFormat;
GrGLenum fUploadType;
GrGLenum fInternalFormat;
Orientation fOrientation;
void init(GrGpuGL* gpu,

View File

@ -253,6 +253,17 @@ bool GrGpu::readPixels(GrRenderTarget* target,
config, buffer, rowBytes, invertY);
}
void GrGpu::writeTexturePixels(GrTexture* texture,
int left, int top, int width, int height,
GrPixelConfig config, const void* buffer,
size_t rowBytes) {
GrAssert(GrPixelConfigIsUnpremultiplied(config) ==
GrPixelConfigIsUnpremultiplied(texture->config()));
this->handleDirtyContext();
this->onWriteTexturePixels(texture, left, top, width, height,
config, buffer, rowBytes);
}
////////////////////////////////////////////////////////////////////////////////
static const int MAX_QUADS = 1 << 12; // max possible: (1 << 14) - 1;

View File

@ -245,6 +245,22 @@ public:
GrPixelConfig config, void* buffer, size_t rowBytes,
bool invertY);
/**
* Updates the pixels in a rectangle of a texture.
* @param left left edge of the rectangle to write (inclusive)
* @param top top edge of the rectangle to write (inclusive)
* @param width width of rectangle to write in pixels.
* @param height height of rectangle to write in pixels.
* @param config the pixel config of the source buffer
* @param buffer memory to read pixels from
* @param rowBytes number of bytes bewtween consecutive rows. Zero
* means rows are tightly packed.
*/
void writeTexturePixels(GrTexture* texture,
int left, int top, int width, int height,
GrPixelConfig config, const void* buffer,
size_t rowBytes);
const GrGpuStats& getStats() const;
void resetStats();
void printStats() const;
@ -402,6 +418,12 @@ protected:
size_t rowBytes,
bool invertY) = 0;
// overridden by API-specific derived class to perform the texture update
virtual void onWriteTexturePixels(GrTexture* texture,
int left, int top, int width, int height,
GrPixelConfig config, const void* buffer,
size_t rowBytes) = 0;
// called to program the vertex data, indexCount will be 0 if drawing non-
// indexed geometry. The subclass may adjust the startVertex and/or
// startIndex since it may have already accounted for these in the setup.

View File

@ -523,10 +523,10 @@ void GrGpuGL::onResetContext() {
}
GrTexture* GrGpuGL::onCreatePlatformTexture(const GrPlatformTextureDesc& desc) {
GrGLenum internalFormat; // we don't need this value
GrGLenum dontCare;
GrGLTexture::Desc glTexDesc;
if (!this->canBeTexture(desc.fConfig, &internalFormat,
&glTexDesc.fUploadFormat, &glTexDesc.fUploadType)) {
if (!this->canBeTexture(desc.fConfig, &glTexDesc.fInternalFormat,
&dontCare, &dontCare)) {
return NULL;
}
@ -639,9 +639,8 @@ GrResource* GrGpuGL::onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc)
if (isTexture) {
GrGLTexture::Desc texDesc;
GrGLenum dontCare;
if (!canBeTexture(desc.fConfig, &dontCare,
&texDesc.fUploadFormat,
&texDesc.fUploadType)) {
if (!canBeTexture(desc.fConfig, &texDesc.fInternalFormat,
&dontCare, &dontCare)) {
return NULL;
}
texDesc.fWidth = desc.fWidth;
@ -675,44 +674,82 @@ GrResource* GrGpuGL::onCreatePlatformSurface(const GrPlatformSurfaceDesc& desc)
////////////////////////////////////////////////////////////////////////////////
void GrGpuGL::allocateAndUploadTexData(const GrGLTexture::Desc& desc,
GrGLenum internalFormat,
const void* data,
size_t rowBytes) {
// we assume the texture is bound
void GrGpuGL::onWriteTexturePixels(GrTexture* texture,
int left, int top, int width, int height,
GrPixelConfig config, const void* buffer,
size_t rowBytes) {
GrGLTexture* glTex = static_cast<GrGLTexture*>(texture);
size_t bpp = GrBytesPerPixel(desc.fConfig);
size_t trimRowBytes = desc.fWidth * bpp;
this->setSpareTextureUnit();
GL_CALL(BindTexture(GR_GL_TEXTURE_2D, glTex->textureID()));
GrGLTexture::Desc desc;
desc.fConfig = glTex->config();
desc.fWidth = glTex->width();
desc.fHeight = glTex->height();
desc.fOrientation = glTex->orientation();
desc.fTextureID = glTex->textureID();
desc.fInternalFormat = glTex->internalFormat();
if (!rowBytes) {
rowBytes = trimRowBytes;
this->uploadTexData(desc, left, top, width, height, config, buffer, rowBytes);
}
void GrGpuGL::uploadTexData(const GrGLTexture::Desc& desc,
int left, int top, int width, int height,
GrPixelConfig dataConfig,
const void* data,
size_t rowBytes) {
GrIRect bounds = GrIRect::MakeWH(desc.fWidth, desc.fHeight);
GrIRect subrect = GrIRect::MakeXYWH(left, top, width, height);
if (!bounds.contains(subrect)) {
return;
}
// ES2 glCompressedTexSubImage2D doesn't support any formats
// (at least without extensions)
GrAssert(desc.fInternalFormat != GR_GL_PALETTE8_RGBA8 ||
bounds == subrect);
// in case we need a temporary, trimmed copy of the src pixels
SkAutoSMalloc<128 * 128> tempStorage;
GrGLenum dontCare;
GrGLenum externalFormat;
GrGLenum externalType;
if (!this->canBeTexture(dataConfig, &dontCare,
&externalFormat, &externalType)) {
return;
}
size_t bpp = GrBytesPerPixel(dataConfig);
size_t trimRowBytes = width * bpp;
if (!rowBytes) {
rowBytes = trimRowBytes;
}
/*
* check whether to allocate a temporary buffer for flipping y or
* because our data has extra bytes past each row. If so, we need
* to trim those off here, since GL ES doesn't let us specify
* GL_UNPACK_ROW_LENGTH.
* check whether to allocate a temporary buffer for flipping y or
* because our srcData has extra bytes past each row. If so, we need
* to trim those off here, since GL ES may not let us specify
* GL_UNPACK_ROW_LENGTH.
*/
bool restoreGLRowLength = false;
bool flipY = GrGLTexture::kBottomUp_Orientation == desc.fOrientation;
if (this->glCaps().fUnpackRowLengthSupport && !flipY) {
if (data && rowBytes != trimRowBytes) {
// can't use this for flipping, only non-neg values allowed. :(
if (rowBytes != trimRowBytes) {
GrGLint rowLength = static_cast<GrGLint>(rowBytes / bpp);
GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength));
restoreGLRowLength = true;
}
} else {
if (data && (trimRowBytes != rowBytes || flipY)) {
if (trimRowBytes != rowBytes || flipY) {
// copy the data into our new storage, skipping the trailing bytes
size_t trimSize = desc.fHeight * trimRowBytes;
size_t trimSize = height * trimRowBytes;
const char* src = (const char*)data;
if (flipY) {
src += (desc.fHeight - 1) * rowBytes;
src += (height - 1) * rowBytes;
}
char* dst = (char*)tempStorage.reset(trimSize);
for (int y = 0; y < desc.fHeight; y++) {
for (int y = 0; y < height; y++) {
memcpy(dst, src, trimRowBytes);
if (flipY) {
src -= rowBytes;
@ -721,31 +758,27 @@ void GrGpuGL::allocateAndUploadTexData(const GrGLTexture::Desc& desc,
}
dst += trimRowBytes;
}
// now point data to our trimmed version
// now point dat to our copied version
data = tempStorage.get();
rowBytes = trimRowBytes;
}
}
GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, static_cast<GrGLint>(bpp)));
if (kIndex_8_GrPixelConfig == desc.fConfig &&
this->getCaps().f8BitPaletteSupport) {
// ES only supports CompressedTexImage2D, not CompressedTexSubimage2D
GrGLsizei imageSize = desc.fWidth * desc.fHeight +
kGrColorTableSize;
GL_CALL(CompressedTexImage2D(GR_GL_TEXTURE_2D, 0, desc.fUploadFormat,
desc.fWidth, desc.fHeight,
0, imageSize, data));
if (this->glCaps().fUnpackRowLengthSupport) {
GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
}
if (bounds == subrect) {
GL_CALL(TexImage2D(GR_GL_TEXTURE_2D, 0, desc.fInternalFormat,
desc.fWidth, desc.fHeight, 0,
externalFormat, externalType, data));
} else {
GL_CALL(TexImage2D(GR_GL_TEXTURE_2D, 0, internalFormat,
desc.fWidth, desc.fHeight, 0,
desc.fUploadFormat, desc.fUploadType, data));
if (this->glCaps().fUnpackRowLengthSupport) {
GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
if (flipY) {
top = desc.fHeight - (top + height);
}
GL_CALL(TexSubImage2D(GR_GL_TEXTURE_2D, 0, left, top, width, height,
externalFormat, externalType, data));
}
if (restoreGLRowLength) {
GrAssert(this->glCaps().fUnpackRowLengthSupport);
GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
}
}
@ -856,7 +889,8 @@ GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc,
GrGLTexture::Desc glTexDesc;
GrGLRenderTarget::Desc glRTDesc;
GrGLenum internalFormat;
GrGLenum externalFormat;
GrGLenum externalType;
glTexDesc.fWidth = desc.fWidth;
glTexDesc.fHeight = desc.fHeight;
@ -871,9 +905,9 @@ GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc,
bool renderTarget = 0 != (desc.fFlags & kRenderTarget_GrTextureFlagBit);
if (!canBeTexture(desc.fConfig,
&internalFormat,
&glTexDesc.fUploadFormat,
&glTexDesc.fUploadType)) {
&glTexDesc.fInternalFormat,
&externalFormat,
&externalType)) {
return return_null_texture();
}
@ -928,7 +962,14 @@ GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc,
GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
GR_GL_TEXTURE_WRAP_T,
initialTexParams.fWrapT));
this->allocateAndUploadTexData(glTexDesc, internalFormat,srcData, rowBytes);
if (NULL == srcData) {
GL_CALL(TexImage2D(GR_GL_TEXTURE_2D, 0, glTexDesc.fInternalFormat,
glTexDesc.fWidth, glTexDesc.fHeight, 0,
externalFormat, externalType, NULL));
} else {
this->uploadTexData(glTexDesc, 0, 0, glTexDesc.fWidth, glTexDesc.fHeight,
desc.fConfig, srcData, rowBytes);
}
GrGLTexture* tex;
if (renderTarget) {
@ -2075,51 +2116,51 @@ void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) {
bool GrGpuGL::canBeTexture(GrPixelConfig config,
GrGLenum* internalFormat,
GrGLenum* format,
GrGLenum* type) {
GrGLenum* externalFormat,
GrGLenum* externalType) {
switch (config) {
case kRGBA_8888_PM_GrPixelConfig:
case kRGBA_8888_UPM_GrPixelConfig:
*format = GR_GL_RGBA;
*externalFormat = GR_GL_RGBA;
*internalFormat = GR_GL_RGBA;
*type = GR_GL_UNSIGNED_BYTE;
*externalType = GR_GL_UNSIGNED_BYTE;
break;
case kBGRA_8888_PM_GrPixelConfig:
case kBGRA_8888_UPM_GrPixelConfig:
if (!fGLCaps.fBGRAFormatSupport) {
return false;
}
*format = GR_GL_BGRA;
*externalFormat = GR_GL_BGRA;
if (fGLCaps.fBGRAIsInternalFormat) {
*internalFormat = GR_GL_BGRA;
} else {
*internalFormat = GR_GL_RGBA;
}
*type = GR_GL_UNSIGNED_BYTE;
*externalType = GR_GL_UNSIGNED_BYTE;
break;
case kRGB_565_GrPixelConfig:
*format = GR_GL_RGB;
*externalFormat = GR_GL_RGB;
*internalFormat = GR_GL_RGB;
*type = GR_GL_UNSIGNED_SHORT_5_6_5;
*externalType = GR_GL_UNSIGNED_SHORT_5_6_5;
break;
case kRGBA_4444_GrPixelConfig:
*format = GR_GL_RGBA;
*externalFormat = GR_GL_RGBA;
*internalFormat = GR_GL_RGBA;
*type = GR_GL_UNSIGNED_SHORT_4_4_4_4;
*externalType = GR_GL_UNSIGNED_SHORT_4_4_4_4;
break;
case kIndex_8_GrPixelConfig:
if (this->getCaps().f8BitPaletteSupport) {
*format = GR_GL_PALETTE8_RGBA8;
*externalFormat = GR_GL_PALETTE8_RGBA8;
*internalFormat = GR_GL_PALETTE8_RGBA8;
*type = GR_GL_UNSIGNED_BYTE; // unused I think
*externalType = GR_GL_UNSIGNED_BYTE; // unused I think
} else {
return false;
}
break;
case kAlpha_8_GrPixelConfig:
*format = GR_GL_ALPHA;
*externalFormat = GR_GL_ALPHA;
*internalFormat = GR_GL_ALPHA;
*type = GR_GL_UNSIGNED_BYTE;
*externalType = GR_GL_UNSIGNED_BYTE;
break;
default:
return false;

View File

@ -175,6 +175,11 @@ protected:
size_t rowBytes,
bool invertY) SK_OVERRIDE;
virtual void onWriteTexturePixels(GrTexture* texture,
int left, int top, int width, int height,
GrPixelConfig config, const void* buffer,
size_t rowBytes) SK_OVERRIDE;
virtual void onGpuDrawIndexed(GrPrimitiveType type,
uint32_t startVertex,
uint32_t startIndex,
@ -262,13 +267,14 @@ private:
bool canBeTexture(GrPixelConfig config,
GrGLenum* internalFormat,
GrGLenum* format,
GrGLenum* type);
// helpers for onCreateTexture
void allocateAndUploadTexData(const GrGLTexture::Desc& desc,
GrGLenum internalFormat,
const void* data,
size_t rowBytes);
GrGLenum* externalFormat,
GrGLenum* externalType);
// helper for onCreateTexture and writeTexturePixels
void uploadTexData(const GrGLTexture::Desc& desc,
int left, int top, int width, int height,
GrPixelConfig dataConfig,
const void* data,
size_t rowBytes);
bool createRenderTargetObjects(int width, int height,
GrGLuint texID,

View File

@ -14,14 +14,31 @@
#include "GrStencilBuffer.h"
bool GrRenderTarget::readPixels(int left, int top, int width, int height,
GrPixelConfig config, void* buffer) {
GrPixelConfig config, void* buffer,
size_t rowBytes) {
// go through context so that all necessary flushing occurs
GrContext* context = this->getGpu()->getContext();
GrAssert(NULL != context);
GrContext* context = this->getContext();
if (NULL == context) {
return false;
}
return context->readRenderTargetPixels(this,
left, top,
left, top,
width, height,
config, buffer);
config, buffer, rowBytes);
}
void GrRenderTarget::writePixels(int left, int top, int width, int height,
GrPixelConfig config, const void* buffer,
size_t rowBytes) {
// go through context so that all necessary flushing occurs
GrContext* context = this->getContext();
if (NULL == context) {
return;
}
context->writeRenderTargetPixels(this,
left, top,
width, height,
config, buffer, rowBytes);
}
size_t GrRenderTarget::sizeInBytes() const {

View File

@ -14,14 +14,31 @@
#include "GrRenderTarget.h"
bool GrTexture::readPixels(int left, int top, int width, int height,
GrPixelConfig config, void* buffer) {
GrPixelConfig config, void* buffer,
size_t rowBytes) {
// go through context so that all necessary flushing occurs
GrContext* context = this->getGpu()->getContext();
GrAssert(NULL != context);
GrContext* context = this->getContext();
if (NULL == context) {
return false;
}
return context->readTexturePixels(this,
left, top,
width, height,
config, buffer);
left, top,
width, height,
config, buffer, rowBytes);
}
void GrTexture::writePixels(int left, int top, int width, int height,
GrPixelConfig config, const void* buffer,
size_t rowBytes) {
// go through context so that all necessary flushing occurs
GrContext* context = this->getContext();
if (NULL == context) {
return;
}
context->writeTexturePixels(this,
left, top,
width, height,
config, buffer, rowBytes);
}
void GrTexture::releaseRenderTarget() {

View File

@ -314,13 +314,8 @@ void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y,
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
fNeedPrepareRenderTarget = true;
fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
config, bitmap.getPixels(), bitmap.rowBytes());
fRenderTarget->writePixels(x, y, bitmap.width(), bitmap.height(),
config, bitmap.getPixels(), bitmap.rowBytes());
}
///////////////////////////////////////////////////////////////////////////////
@ -1031,7 +1026,7 @@ static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
if (NULL == texture) {
return false;
}
texture->uploadTextureData(0, 0, desc.fWidth, desc.fHeight,
texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
dstM.fImage, dstM.fRowBytes);
if (grp->hasTextureOrMask() && ivm.invert(&ivm)) {

View File

@ -99,8 +99,9 @@ GrContext::TextureCacheEntry sk_gr_create_bitmap_texture(GrContext* ctx,
} else {
entry = ctx->lockScratchTexture(desc,
GrContext::kExact_ScratchTexMatch);
entry.texture()->uploadTextureData(0, 0, bitmap->width(),
bitmap->height(), storage.get(), 0);
entry.texture()->writePixels(0, 0, bitmap->width(),
bitmap->height(), desc.fConfig,
storage.get(), 0);
return entry;
}
@ -119,8 +120,11 @@ GrContext::TextureCacheEntry sk_gr_create_bitmap_texture(GrContext* ctx,
} else {
entry = ctx->lockScratchTexture(desc,
GrContext::kExact_ScratchTexMatch);
entry.texture()->uploadTextureData(0, 0, bitmap->width(),
bitmap->height(), bitmap->getPixels(), bitmap->rowBytes());
entry.texture()->writePixels(0, 0,
bitmap->width(), bitmap->height(),
desc.fConfig,
bitmap->getPixels(),
bitmap->rowBytes());
return entry;
}
}

View File

@ -79,7 +79,7 @@ bool SkGrTexturePixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) {
void* buffer = dst->getPixels();
return fTexture->readPixels(left, top, width, height,
kSkia8888_PM_GrPixelConfig,
buffer);
buffer, dst->rowBytes());
} else {
return false;
}
@ -123,7 +123,7 @@ bool SkGrRenderTargetPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset
void* buffer = dst->getPixels();
return fRenderTarget->readPixels(left, top, width, height,
kSkia8888_PM_GrPixelConfig,
buffer);
buffer, dst->rowBytes());
} else {
return false;
}