aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gpu/GrPrintf_skia.cpp39
-rw-r--r--src/gpu/SkGpuCanvas.cpp60
-rw-r--r--src/gpu/SkGpuDevice.cpp1048
-rw-r--r--src/gpu/SkGr.cpp206
-rw-r--r--src/gpu/SkGrFontScaler.cpp142
-rw-r--r--src/gpu/SkGrTexturePixelRef.cpp30
-rw-r--r--src/gpu/skgr_files.mk8
-rw-r--r--src/utils/mac/SkEGLContext_mac.cpp65
8 files changed, 1598 insertions, 0 deletions
diff --git a/src/gpu/GrPrintf_skia.cpp b/src/gpu/GrPrintf_skia.cpp
new file mode 100644
index 0000000000..fa8b6a7647
--- /dev/null
+++ b/src/gpu/GrPrintf_skia.cpp
@@ -0,0 +1,39 @@
+/*
+ Copyright 2010 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 "GrTypes.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "SkTypes.h"
+
+void GrPrintf(const char format[], ...) {
+ const size_t MAX_BUFFER_SIZE = 512;
+
+ char buffer[MAX_BUFFER_SIZE + 1];
+ va_list args;
+
+ va_start(args, format);
+ vsnprintf(buffer, MAX_BUFFER_SIZE, format, args);
+ va_end(args);
+
+ // skia has already mapped this to do the "right thing"
+ SkDebugf("%s", buffer);
+}
+
+
diff --git a/src/gpu/SkGpuCanvas.cpp b/src/gpu/SkGpuCanvas.cpp
new file mode 100644
index 0000000000..19bda4d943
--- /dev/null
+++ b/src/gpu/SkGpuCanvas.cpp
@@ -0,0 +1,60 @@
+/*
+ Copyright 2010 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 "GrContext.h"
+
+#include "SkGpuCanvas.h"
+#include "SkGpuDevice.h"
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkGpuCanvas::SkGpuCanvas(GrContext* context) {
+ SkASSERT(context);
+ fContext = context;
+ fContext->ref();
+}
+
+SkGpuCanvas::~SkGpuCanvas() {
+ // call this now, while our override of restore() is in effect
+ this->restoreToCount(1);
+ fContext->flush(false);
+ fContext->unref();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool SkGpuCanvas::getViewport(SkIPoint* size) const {
+ if (size) {
+ SkDevice* device = this->getDevice();
+ if (device) {
+ size->set(device->width(), device->height());
+ } else {
+ size->set(0, 0);
+ }
+ }
+ return true;
+}
+
+SkDevice* SkGpuCanvas::createDevice(SkBitmap::Config config, int width, int height,
+ bool isOpaque, bool isLayer) {
+ SkBitmap bm;
+ bm.setConfig(config, width, height);
+ bm.setIsOpaque(isOpaque);
+ return new SkGpuDevice(this, bm, isLayer);
+}
+
+
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
new file mode 100644
index 0000000000..832fc6ea75
--- /dev/null
+++ b/src/gpu/SkGpuDevice.cpp
@@ -0,0 +1,1048 @@
+/*
+ Copyright 2010 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 "GrContext.h"
+#include "GrTextContext.h"
+
+#include "SkGpuCanvas.h"
+#include "SkGpuDevice.h"
+#include "SkGrTexturePixelRef.h"
+
+#include "SkDrawProcs.h"
+#include "SkGlyphCache.h"
+
+#define CACHE_LAYER_TEXTURES 1
+
+#if 0
+ extern bool (*gShouldDrawProc)();
+ #define CHECK_SHOULD_DRAW(draw) \
+ do { \
+ if (gShouldDrawProc && !gShouldDrawProc()) return; \
+ this->prepareRenderTarget(draw); \
+ } while (0)
+#else
+ #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw)
+#endif
+
+class SkAutoExtMatrix {
+public:
+ SkAutoExtMatrix(const SkMatrix* extMatrix) {
+ if (extMatrix) {
+ SkGr::SkMatrix2GrMatrix(*extMatrix, &fMatrix);
+ fExtMatrix = &fMatrix;
+ } else {
+ fExtMatrix = NULL;
+ }
+ }
+ const GrMatrix* extMatrix() const { return fExtMatrix; }
+
+private:
+ GrMatrix fMatrix;
+ GrMatrix* fExtMatrix; // NULL or &fMatrix
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkGpuDevice::SkAutoCachedTexture::
+ SkAutoCachedTexture(SkGpuDevice* device,
+ const SkBitmap& bitmap,
+ const GrSamplerState& sampler,
+ GrTexture** texture) {
+ GrAssert(texture);
+ fTex = NULL;
+ *texture = this->set(device, bitmap, sampler);
+}
+
+SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() {
+ fTex = NULL;
+}
+
+GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device,
+ const SkBitmap& bitmap,
+ const GrSamplerState& sampler) {
+ if (fTex) {
+ fDevice->unlockCachedTexture(fTex);
+ }
+ fDevice = device;
+ GrTexture* texture = (GrTexture*)bitmap.getTexture();
+ if (texture) {
+ // return the native texture
+ fTex = NULL;
+ device->context()->setTexture(texture);
+ } else {
+ // look it up in our cache
+ fTex = device->lockCachedTexture(bitmap, sampler, &texture, false);
+ }
+ return texture;
+}
+
+SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() {
+ if (fTex) {
+ fDevice->unlockCachedTexture(fTex);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool gDoTraceDraw;
+
+struct GrSkDrawProcs : public SkDrawProcs {
+public:
+ GrContext* fContext;
+ GrTextContext* fTextContext;
+ GrFontScaler* fFontScaler; // cached in the skia glyphcache
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkGpuDevice::SkGpuDevice(SkGpuCanvas* canvas, const SkBitmap& bitmap, bool isLayer)
+ : SkDevice(canvas, bitmap, false) {
+
+ fNeedPrepareRenderTarget = false;
+ fDrawProcs = NULL;
+
+ fContext = canvas->context();
+
+ fCache = NULL;
+ fTexture = NULL;
+ fRenderTarget = NULL;
+ fNeedClear = false;
+
+ if (isLayer) {
+ SkBitmap::Config c = bitmap.config();
+ if (c != SkBitmap::kRGB_565_Config) {
+ c = SkBitmap::kARGB_8888_Config;
+ }
+ SkBitmap bm;
+ bm.setConfig(c, this->width(), this->height());
+
+#if CACHE_LAYER_TEXTURES
+
+ fCache = this->lockCachedTexture(bm, GrSamplerState::ClampNoFilter(),
+ &fTexture, true);
+ if (fCache) {
+ SkASSERT(NULL != fTexture);
+ SkASSERT(fTexture->isRenderTarget());
+ }
+#else
+ const GrGpu::TextureDesc desc = {
+ GrGpu::kRenderTarget_TextureFlag,
+ GrGpu::kNone_AALevel,
+ this->width(),
+ this->height(),
+ SkGr::Bitmap2PixelConfig(bm)
+ };
+
+ fTexture = fContext->createUncachedTexture(desc, NULL, 0);
+#endif
+ if (NULL != fTexture) {
+ fRenderTarget = fTexture->asRenderTarget();
+
+ GrAssert(NULL != fRenderTarget);
+
+ // we defer the actual clear until our gainFocus()
+ fNeedClear = true;
+
+ // wrap the bitmap with a pixelref to expose our texture
+ SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture);
+ this->setPixelRef(pr, 0)->unref();
+ } else {
+ GrPrintf("--- failed to create gpu-offscreen [%d %d]\n",
+ this->width(), this->height());
+ }
+ }
+
+ if (NULL == fRenderTarget) {
+ GrAssert(NULL == fCache);
+ GrAssert(NULL == fTexture);
+
+ fRenderTarget = fContext->currentRenderTarget();
+ fRenderTarget->ref();
+ fContext->setDefaultRenderTargetSize(this->width(), this->height());
+ }
+}
+
+SkGpuDevice::~SkGpuDevice() {
+ if (fDrawProcs) {
+ delete fDrawProcs;
+ }
+
+ if (fCache) {
+ GrAssert(NULL != fTexture);
+ GrAssert(fRenderTarget == fTexture->asRenderTarget());
+ // IMPORTANT: reattach the rendertarget/tex back to the cache.
+ fContext->reattachAndUnlockCachedTexture((GrTextureEntry*)fCache);
+ } else if (NULL != fTexture) {
+ GrAssert(!CACHE_LAYER_TEXTURES);
+ GrAssert(fRenderTarget == fTexture->asRenderTarget());
+ fTexture->unref();
+ } else if (NULL != fRenderTarget) {
+ fRenderTarget->unref();
+ }
+}
+
+void SkGpuDevice::bindDeviceToTargetHandle(intptr_t handle) {
+ if (fCache) {
+ GrAssert(NULL != fTexture);
+ GrAssert(fRenderTarget == fTexture->asRenderTarget());
+ // IMPORTANT: reattach the rendertarget/tex back to the cache.
+ fContext->reattachAndUnlockCachedTexture((GrTextureEntry*)fCache);
+ } else if (NULL != fTexture) {
+ GrAssert(!CACHE_LAYER_TEXTURES);
+ fTexture->unref();
+ } else if (NULL != fRenderTarget) {
+ fRenderTarget->unref();
+ }
+
+ fCache = NULL;
+ fTexture = NULL;
+ fRenderTarget = fContext->createPlatformRenderTarget(handle,
+ this->width(),
+ this->height());
+}
+
+intptr_t SkGpuDevice::getLayerTextureHandle() const {
+ if (fTexture) {
+ return fTexture->getTextureHandle();
+ } else {
+ return 0;
+ }
+}
+///////////////////////////////////////////////////////////////////////////////
+
+void SkGpuDevice::makeRenderTargetCurrent() {
+ fContext->setRenderTarget(fRenderTarget);
+ fContext->flush(true);
+ fNeedPrepareRenderTarget = true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool SkGpuDevice::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
+ SkIRect bounds;
+ bounds.set(0, 0, this->width(), this->height());
+ if (!bounds.intersect(srcRect)) {
+ return false;
+ }
+
+ const int w = bounds.width();
+ const int h = bounds.height();
+ SkBitmap tmp;
+ // note we explicitly specify our rowBytes to be snug (no gap between rows)
+ tmp.setConfig(SkBitmap::kARGB_8888_Config, w, h, w * 4);
+ if (!tmp.allocPixels()) {
+ return false;
+ }
+
+ 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())) {
+ return false;
+ }
+
+ tmp.swap(*bitmap);
+ return true;
+}
+
+void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y) {
+ SkAutoLockPixels alp(bitmap);
+ if (!bitmap.readyToDraw()) {
+ return;
+ }
+ GrTexture::PixelConfig 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
+ fNeedPrepareRenderTarget = true;
+
+ fContext->writePixels(x, y, bitmap.width(), bitmap.height(),
+ config, bitmap.getPixels(), bitmap.rowBytes());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void convert_matrixclip(GrContext* context, const SkMatrix& matrix,
+ const SkRegion& clip) {
+ GrMatrix grmat;
+ SkGr::SkMatrix2GrMatrix(matrix, &grmat);
+ context->setViewMatrix(grmat);
+
+ SkGrClipIterator iter;
+ iter.reset(clip);
+ GrClip grc(&iter);
+ if (context->getClip() == grc) {
+ } else {
+ context->setClip(grc);
+ }
+}
+
+// call this ever each draw call, to ensure that the context reflects our state,
+// and not the state from some other canvas/device
+void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) {
+ if (fNeedPrepareRenderTarget ||
+ fContext->currentRenderTarget() != fRenderTarget) {
+
+ fContext->setRenderTarget(fRenderTarget);
+ convert_matrixclip(fContext, *draw.fMatrix, *draw.fClip);
+ fNeedPrepareRenderTarget = false;
+ }
+}
+
+void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip) {
+ this->INHERITED::setMatrixClip(matrix, clip);
+
+ convert_matrixclip(fContext, matrix, clip);
+}
+
+void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix,
+ const SkRegion& clip) {
+ fContext->setRenderTarget(fRenderTarget);
+
+ this->INHERITED::gainFocus(canvas, matrix, clip);
+
+ convert_matrixclip(fContext, matrix, clip);
+
+ if (fNeedClear) {
+ fContext->eraseColor(0x0);
+ fNeedClear = false;
+ }
+}
+
+bool SkGpuDevice::bindDeviceAsTexture(SkPoint* max) {
+ if (NULL != fTexture) {
+ fContext->setTexture(fTexture);
+ if (NULL != max) {
+ max->set(SkFixedToScalar((width() << 16) /
+ fTexture->allocWidth()),
+ SkFixedToScalar((height() << 16) /
+ fTexture->allocHeight()));
+ }
+ return true;
+ }
+ return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+// must be in the same order as SkXfermode::Coeff in SkXfermode.h
+
+SkGpuDevice::AutoPaintShader::AutoPaintShader() {
+ fSuccess = false;
+ fTexture = NULL;
+}
+
+SkGpuDevice::AutoPaintShader::AutoPaintShader(SkGpuDevice* device,
+ const SkPaint& paint,
+ const SkMatrix& matrix) {
+ fSuccess = false;
+ fTexture = NULL;
+ this->init(device, paint, matrix);
+}
+
+void SkGpuDevice::AutoPaintShader::init(SkGpuDevice* device,
+ const SkPaint& paint,
+ const SkMatrix& ctm) {
+ fSuccess = true;
+ GrContext* ctx = device->context();
+ sk_gr_set_paint(ctx, paint); // should we pass true for justAlpha if we have a shader/texture?
+
+ SkShader* shader = paint.getShader();
+ if (NULL == shader) {
+ return;
+ }
+
+ if (!shader->setContext(device->accessBitmap(false), paint, ctm)) {
+ fSuccess = false;
+ return;
+ }
+
+ GrSamplerState::SampleMode sampleMode;
+ SkBitmap bitmap;
+ SkMatrix matrix;
+ SkShader::TileMode tileModes[2];
+ SkScalar twoPointParams[3];
+ SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, &matrix,
+ tileModes, twoPointParams);
+
+ switch (bmptype) {
+ case SkShader::kNone_BitmapType:
+ SkDebugf("shader->asABitmap() == kNone_BitmapType");
+ return;
+ case SkShader::kDefault_BitmapType:
+ sampleMode = GrSamplerState::kNormal_SampleMode;
+ break;
+ case SkShader::kRadial_BitmapType:
+ sampleMode = GrSamplerState::kRadial_SampleMode;
+ break;
+ case SkShader::kSweep_BitmapType:
+ sampleMode = GrSamplerState::kSweep_SampleMode;
+ break;
+ case SkShader::kTwoPointRadial_BitmapType:
+ sampleMode = GrSamplerState::kRadial2_SampleMode;
+ break;
+ default:
+ SkASSERT("Unexpected return from asABitmap");
+ return;
+ }
+
+ bitmap.lockPixels();
+ if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
+ return;
+ }
+
+ // see if we've already cached the bitmap from the shader
+ GrSamplerState samplerState(sk_tile_mode_to_grwrap(tileModes[0]),
+ sk_tile_mode_to_grwrap(tileModes[1]),
+ sampleMode,
+ paint.isFilterBitmap());
+
+ if (GrSamplerState::kRadial2_SampleMode == sampleMode) {
+ samplerState.setRadial2Params(twoPointParams[0],
+ twoPointParams[1],
+ twoPointParams[2] < 0);
+ }
+
+ GrTexture* texture = fCachedTexture.set(device, bitmap, samplerState);
+ if (NULL == texture) {
+ return;
+ }
+
+ // the lock has already called setTexture for us
+ ctx->setSamplerState(samplerState);
+
+ // since our texture coords will be in local space, we wack the texture
+ // matrix to map them back into 0...1 before we load it
+ SkMatrix localM;
+ if (shader->getLocalMatrix(&localM)) {
+ SkMatrix inverse;
+ if (localM.invert(&inverse)) {
+ matrix.preConcat(inverse);
+ }
+ }
+ if (SkShader::kDefault_BitmapType == bmptype) {
+ GrScalar sx = (GR_Scalar1 * texture->contentWidth()) /
+ (bitmap.width() * texture->allocWidth());
+ GrScalar sy = (GR_Scalar1 * texture->contentHeight()) /
+ (bitmap.height() * texture->allocHeight());
+ matrix.postScale(sx, sy);
+
+ } else if (SkShader::kRadial_BitmapType == bmptype) {
+ GrScalar s = (GR_Scalar1 * texture->contentWidth()) /
+ (bitmap.width() * texture->allocWidth());
+ matrix.postScale(s, s);
+ }
+ GrMatrix grmat;
+ SkGr::SkMatrix2GrMatrix(matrix, &grmat);
+ ctx->setTextureMatrix(grmat);
+
+ // since we're going to use a shader/texture, we don't want the color,
+ // just its alpha
+ ctx->setAlpha(paint.getAlpha());
+ // report that we have setup the texture
+ fSuccess = true;
+ fTexture = texture;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) {
+ CHECK_SHOULD_DRAW(draw);
+
+ AutoPaintShader shader(this, paint, *draw.fMatrix);
+ if (shader.failed()) {
+ return;
+ }
+ fContext->drawFull(shader.useTex());
+}
+
+// must be in SkCanvas::PointMode order
+static const GrGpu::PrimitiveType gPointMode2PrimtiveType[] = {
+ GrGpu::kPoints_PrimitiveType,
+ GrGpu::kLines_PrimitiveType,
+ GrGpu::kLineStrip_PrimitiveType
+};
+
+void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode,
+ size_t count, const SkPoint pts[], const SkPaint& paint) {
+ CHECK_SHOULD_DRAW(draw);
+
+ SkScalar width = paint.getStrokeWidth();
+ if (width < 0) {
+ return;
+ }
+
+ // we only handle hairlines here, else we let the SkDraw call our drawPath()
+ if (width > 0) {
+ draw.drawPoints(mode, count, pts, paint, true);
+ return;
+ }
+
+ AutoPaintShader shader(this, paint, *draw.fMatrix);
+ if (shader.failed()) {
+ return;
+ }
+
+ GrVertexLayout layout = shader.useTex() ?
+ GrDrawTarget::kPositionAsTexCoord_VertexLayoutBit :
+ 0;
+#if SK_SCALAR_IS_GR_SCALAR
+ fContext->setVertexSourceToArray(pts, layout);
+ fContext->drawNonIndexed(gPointMode2PrimtiveType[mode], 0, count);
+#else
+ GrPoint* v;
+ fContext->reserveAndLockGeometry(layout, count, 0, (void**)&v, NULL);
+ for (int i = 0; i < count; ++i) {
+ v[i].set(SkScalarToGrScalar(pts[i].fX), SkScalarToGrScalar(pts[i].fY));
+ }
+ fContext->drawNonIndexed(gPointMode2PrimtiveType[mode], layout, 0, count);
+ fContext->releaseReservedGeometry();
+#endif
+
+}
+
+void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect,
+ const SkPaint& paint) {
+ CHECK_SHOULD_DRAW(draw);
+
+ bool doStroke = paint.getStyle() == SkPaint::kStroke_Style;
+ SkScalar width = paint.getStrokeWidth();
+
+ /*
+ We have special code for hairline strokes, miter-strokes, and fills.
+ Anything else we just call our path code. (i.e. non-miter thick stroke)
+ */
+ if (doStroke && width > 0 && paint.getStrokeJoin() != SkPaint::kMiter_Join) {
+ SkPath path;
+ path.addRect(rect);
+ this->drawPath(draw, path, paint, NULL, true);
+ return;
+ }
+
+ AutoPaintShader shader(this, paint, *draw.fMatrix);
+ if (shader.failed()) {
+ return;
+ }
+
+ fContext->drawRect(Sk2Gr(rect), shader.useTex(), doStroke ? width : -1);
+}
+
+void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& path,
+ const SkPaint& paint, const SkMatrix* prePathMatrix,
+ bool pathIsMutable) {
+ CHECK_SHOULD_DRAW(draw);
+
+ AutoPaintShader shader(this, paint, *draw.fMatrix);
+ if (shader.failed()) {
+ return;
+ }
+
+ const SkPath* pathPtr = &path;
+ SkPath tmpPath;
+
+ if (prePathMatrix) {
+ if (pathIsMutable) {
+ const_cast<SkPath*>(pathPtr)->transform(*prePathMatrix);
+ } else {
+ path.transform(*prePathMatrix, &tmpPath);
+ pathPtr = &tmpPath;
+ }
+ }
+
+ SkPath fillPath;
+ GrContext::PathFills fill = GrContext::kHairLine_PathFill;
+
+ if (paint.getFillPath(*pathPtr, &fillPath)) {
+ switch (fillPath.getFillType()) {
+ case SkPath::kWinding_FillType:
+ fill = GrContext::kWinding_PathFill;
+ break;
+ case SkPath::kEvenOdd_FillType:
+ fill = GrContext::kEvenOdd_PathFill;
+ break;
+ case SkPath::kInverseWinding_FillType:
+ fill = GrContext::kInverseWinding_PathFill;
+ break;
+ case SkPath::kInverseEvenOdd_FillType:
+ fill = GrContext::kInverseEvenOdd_PathFill;
+ break;
+ default:
+ SkDebugf("Unsupported path fill type");
+ return;
+ }
+ }
+
+ SkGrPathIter iter(fillPath);
+ fContext->drawPath(&iter, fill, shader.useTex());
+}
+
+/*
+ * This value must not exceed the GPU's texture dimension limit, but it can
+ * be smaller, if that helps avoid very large single textures hurting the
+ * cache.
+ */
+#define MAX_TEXTURE_DIM 512
+
+void SkGpuDevice::drawBitmap(const SkDraw& draw,
+ const SkBitmap& bitmap,
+ const SkIRect* srcRectPtr,
+ const SkMatrix& m,
+ const SkPaint& paint) {
+ CHECK_SHOULD_DRAW(draw);
+
+ SkIRect srcRect;
+ if (NULL == srcRectPtr) {
+ srcRect.set(0, 0, bitmap.width(), bitmap.height());
+ } else {
+ srcRect = *srcRectPtr;
+ }
+
+ if (bitmap.getTexture() || (bitmap.width() <= MAX_TEXTURE_DIM &&
+ bitmap.height() <= MAX_TEXTURE_DIM)) {
+ // take the fast case
+ this->internalDrawBitmap(draw, bitmap, srcRect, m, paint);
+ return;
+ }
+
+ // undo the translate done by SkCanvas
+ int DX = SkMax32(0, srcRect.fLeft);
+ int DY = SkMax32(0, srcRect.fTop);
+ // compute clip bounds in local coordinates
+ SkIRect clipRect;
+ {
+ SkRect r;
+ r.set(draw.fClip->getBounds());
+ SkMatrix matrix, inverse;
+ matrix.setConcat(*draw.fMatrix, m);
+ if (!matrix.invert(&inverse)) {
+ return;
+ }
+ inverse.mapRect(&r);
+ r.roundOut(&clipRect);
+ // apply the canvas' translate to our local clip
+ clipRect.offset(DX, DY);
+ }
+
+ int nx = bitmap.width() / MAX_TEXTURE_DIM;
+ int ny = bitmap.height() / MAX_TEXTURE_DIM;
+ for (int x = 0; x <= nx; x++) {
+ for (int y = 0; y <= ny; y++) {
+ SkIRect tileR;
+ tileR.set(x * MAX_TEXTURE_DIM, y * MAX_TEXTURE_DIM,
+ (x + 1) * MAX_TEXTURE_DIM, (y + 1) * MAX_TEXTURE_DIM);
+ if (!SkIRect::Intersects(tileR, clipRect)) {
+ continue;
+ }
+
+ SkIRect srcR = tileR;
+ if (!srcR.intersect(srcRect)) {
+ continue;
+ }
+
+ SkBitmap tmpB;
+ if (bitmap.extractSubset(&tmpB, tileR)) {
+ // now offset it to make it "local" to our tmp bitmap
+ srcR.offset(-tileR.fLeft, -tileR.fTop);
+
+ SkMatrix tmpM(m);
+ {
+ int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft);
+ int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop);
+ tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy));
+ }
+ this->internalDrawBitmap(draw, tmpB, srcR, tmpM, paint);
+ }
+ }
+ }
+}
+
+/*
+ * This is called by drawBitmap(), which has to handle images that may be too
+ * large to be represented by a single texture.
+ *
+ * internalDrawBitmap assumes that the specified bitmap will fit in a texture.
+ */
+void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
+ const SkBitmap& bitmap,
+ const SkIRect& srcRect,
+ const SkMatrix& m,
+ const SkPaint& paint) {
+ SkASSERT(bitmap.width() <= MAX_TEXTURE_DIM &&
+ bitmap.height() <= MAX_TEXTURE_DIM);
+
+ SkAutoLockPixels alp(bitmap);
+ if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
+ return;
+ }
+
+ GrSamplerState sampler(paint.isFilterBitmap()); // defaults to clamp
+ // the lock has already called setTexture for us
+ fContext->setSamplerState(sampler);
+
+ GrTexture* texture;
+ SkAutoCachedTexture act(this, bitmap, sampler, &texture);
+ if (NULL == texture) {
+ return;
+ }
+
+ GrVertexLayout layout = GrDrawTarget::kSeparateTexCoord_VertexLayoutBit;
+
+ GrPoint* vertex;
+ if (!fContext->reserveAndLockGeometry(layout, 4,
+ 0, (void**)&vertex, NULL)) {
+ return;
+ }
+
+ {
+ GrMatrix grmat;
+ SkGr::SkMatrix2GrMatrix(m, &grmat);
+ vertex[0].setIRectFan(0, 0, srcRect.width(), srcRect.height(),
+ 2*sizeof(GrPoint));
+ grmat.mapPointsWithStride(vertex, 2*sizeof(GrPoint), 4);
+ }
+
+ SkScalar left = SkFixedToScalar((srcRect.fLeft << 16) /
+ texture->allocWidth());
+ SkScalar right = SkFixedToScalar((srcRect.fRight << 16) /
+ texture->allocWidth());
+ SkScalar top = SkFixedToScalar((srcRect.fTop << 16) /
+ texture->allocHeight());
+ SkScalar bottom = SkFixedToScalar((srcRect.fBottom << 16) /
+ texture->allocHeight());
+ vertex[1].setRectFan(left, top, right, bottom, 2*sizeof(GrPoint));
+
+ fContext->setTextureMatrix(GrMatrix::I());
+ // now draw the mesh
+ sk_gr_set_paint(fContext, paint, true);
+ fContext->drawNonIndexed(GrGpu::kTriangleFan_PrimitiveType, 0, 4);
+ fContext->releaseReservedGeometry();
+}
+
+static void gl_drawSprite(GrContext* ctx,
+ int x, int y, int w, int h, const SkPoint& max,
+ const SkPaint& paint) {
+ GrAutoViewMatrix avm(ctx, GrMatrix::I());
+
+ ctx->setSamplerState(GrSamplerState::ClampNoFilter());
+ ctx->setTextureMatrix(GrMatrix::I());
+
+ GrPoint* vertex;
+ GrVertexLayout layout = GrGpu::kSeparateTexCoord_VertexLayoutBit;
+ if (!ctx->reserveAndLockGeometry(layout, 4, 0, (void**)&vertex, NULL)) {
+ return;
+ }
+
+ vertex[1].setRectFan(0, 0, max.fX, max.fY, 2*sizeof(GrPoint));
+
+ vertex[0].setIRectFan(x, y, x + w, y + h, 2*sizeof(GrPoint));
+
+ sk_gr_set_paint(ctx, paint, true);
+ // should look to use glDrawTexi() has we do for text...
+ ctx->drawNonIndexed(GrGpu::kTriangleFan_PrimitiveType, 0, 4);
+ ctx->releaseReservedGeometry();
+}
+
+void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
+ int left, int top, const SkPaint& paint) {
+ CHECK_SHOULD_DRAW(draw);
+
+ SkAutoLockPixels alp(bitmap);
+ if (!bitmap.getTexture() && !bitmap.readyToDraw()) {
+ return;
+ }
+
+ SkPoint max;
+ GrTexture* texture;
+ SkAutoCachedTexture act(this, bitmap, GrSamplerState::ClampNoFilter(),
+ &texture);
+
+ max.set(SkFixedToScalar((texture->contentWidth() << 16) /
+ texture->allocWidth()),
+ SkFixedToScalar((texture->contentHeight() << 16) /
+ texture->allocHeight()));
+ gl_drawSprite(fContext, left, top, bitmap.width(), bitmap.height(), max, paint);
+}
+
+void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
+ int x, int y, const SkPaint& paint) {
+ CHECK_SHOULD_DRAW(draw);
+
+ SkPoint max;
+ if (((SkGpuDevice*)dev)->bindDeviceAsTexture(&max)) {
+ const SkBitmap& bm = dev->accessBitmap(false);
+ int w = bm.width();
+ int h = bm.height();
+ gl_drawSprite(fContext, x, y, w, h, max, paint);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+// must be in SkCanvas::VertexMode order
+static const GrGpu::PrimitiveType gVertexMode2PrimitiveType[] = {
+ GrGpu::kTriangles_PrimitiveType,
+ GrGpu::kTriangleStrip_PrimitiveType,
+ GrGpu::kTriangleFan_PrimitiveType,
+};
+
+void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode,
+ int vertexCount, const SkPoint vertices[],
+ const SkPoint texs[], const SkColor colors[],
+ SkXfermode* xmode,
+ const uint16_t indices[], int indexCount,
+ const SkPaint& paint) {
+ CHECK_SHOULD_DRAW(draw);
+
+ sk_gr_set_paint(fContext, paint);
+
+ TexCache* cache = NULL;
+
+ bool useTexture = false;
+
+ AutoPaintShader autoShader;
+
+ if (texs) {
+ autoShader.init(this, paint, *draw.fMatrix);
+
+ if (autoShader.failed()) {
+ return;
+ }
+ useTexture = autoShader.useTex();
+ }
+
+ bool releaseVerts = false;
+ GrVertexLayout layout = 0;
+ if (useTexture) {
+ layout |= GrDrawTarget::kSeparateTexCoord_VertexLayoutBit;
+ }
+ if (NULL != colors) {
+ layout |= GrDrawTarget::kColor_VertexLayoutBit;
+ }
+
+ #if SK_SCALAR_IS_GR_SCALAR
+ if (!layout) {
+ fContext->setVertexSourceToArray(vertices, layout);
+ } else
+ #endif
+ {
+ void* verts;
+ releaseVerts = true;
+ if (!fContext->reserveAndLockGeometry(layout, vertexCount, 0,
+ &verts, NULL)) {
+ return;
+ }
+ int texOffset, colorOffset;
+ uint32_t stride = GrDrawTarget::VertexSizeAndOffsets(layout,
+ &texOffset,
+ &colorOffset);
+ for (int i = 0; i < vertexCount; ++i) {
+ GrPoint* p = (GrPoint*)((intptr_t)verts + i * stride);
+ p->set(SkScalarToGrScalar(vertices[i].fX),
+ SkScalarToGrScalar(vertices[i].fY));
+ if (texOffset > 0) {
+ GrPoint* t = (GrPoint*)((intptr_t)p + texOffset);
+ t->set(SkScalarToGrScalar(texs[i].fX),
+ SkScalarToGrScalar(texs[i].fY));
+ }
+ if (colorOffset > 0) {
+ uint32_t* color = (uint32_t*) ((intptr_t)p + colorOffset);
+ *color = SkGr::SkColor2GrColor(colors[i]);
+ }
+ }
+ }
+ if (indices) {
+ fContext->setIndexSourceToArray(indices);
+ fContext->drawIndexed(gVertexMode2PrimitiveType[vmode], 0, 0,
+ vertexCount, indexCount);
+ } else {
+ fContext->drawNonIndexed(gVertexMode2PrimitiveType[vmode],
+ 0, vertexCount);
+ }
+ if (cache) {
+ this->unlockCachedTexture(cache);
+ }
+ if (releaseVerts) {
+ fContext->releaseReservedGeometry();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void GlyphCacheAuxProc(void* data) {
+ delete (GrFontScaler*)data;
+}
+
+static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) {
+ void* auxData;
+ GrFontScaler* scaler = NULL;
+ if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
+ scaler = (GrFontScaler*)auxData;
+ }
+ if (NULL == scaler) {
+ scaler = new SkGrFontScaler(cache);
+ cache->setAuxProc(GlyphCacheAuxProc, scaler);
+ }
+ return scaler;
+}
+
+static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state,
+ SkFixed fx, SkFixed fy,
+ const SkGlyph& glyph) {
+ SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
+
+ GrSkDrawProcs* procs = (GrSkDrawProcs*)state.fDraw->fProcs;
+
+ if (NULL == procs->fFontScaler) {
+ procs->fFontScaler = get_gr_font_scaler(state.fCache);
+ }
+ procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), fx, 0),
+ SkIntToFixed(SkFixedFloor(fx)), fy,
+ procs->fFontScaler);
+}
+
+SkDrawProcs* SkGpuDevice::initDrawForText(const SkPaint& paint,
+ GrTextContext* context) {
+
+ // deferred allocation
+ if (NULL == fDrawProcs) {
+ fDrawProcs = new GrSkDrawProcs;
+ fDrawProcs->fD1GProc = SkGPU_Draw1Glyph;
+ fDrawProcs->fContext = fContext;
+ }
+
+ // init our (and GL's) state
+ fDrawProcs->fTextContext = context;
+ fDrawProcs->fFontScaler = NULL;
+ return fDrawProcs;
+}
+
+void SkGpuDevice::drawText(const SkDraw& draw, const void* text,
+ size_t byteLength, SkScalar x, SkScalar y,
+ const SkPaint& paint) {
+ CHECK_SHOULD_DRAW(draw);
+
+ if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
+ // this guy will just call our drawPath()
+ draw.drawText((const char*)text, byteLength, x, y, paint);
+ } else {
+ SkAutoExtMatrix aem(draw.fExtMatrix);
+ SkDraw myDraw(draw);
+ sk_gr_set_paint(fContext, paint);
+ GrTextContext context(fContext, aem.extMatrix());
+ myDraw.fProcs = this->initDrawForText(paint, &context);
+ this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint);
+ }
+}
+
+void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text,
+ size_t byteLength, const SkScalar pos[],
+ SkScalar constY, int scalarsPerPos,
+ const SkPaint& paint) {
+ CHECK_SHOULD_DRAW(draw);
+
+ if (draw.fMatrix->getType() & SkMatrix::kPerspective_Mask) {
+ // this guy will just call our drawPath()
+ draw.drawPosText((const char*)text, byteLength, pos, constY,
+ scalarsPerPos, paint);
+ } else {
+ SkAutoExtMatrix aem(draw.fExtMatrix);
+ SkDraw myDraw(draw);
+ sk_gr_set_paint(fContext, paint);
+ GrTextContext context(fContext, aem.extMatrix());
+ myDraw.fProcs = this->initDrawForText(paint, &context);
+ this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY,
+ scalarsPerPos, paint);
+ }
+}
+
+void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text,
+ size_t len, const SkPath& path,
+ const SkMatrix* m, const SkPaint& paint) {
+ CHECK_SHOULD_DRAW(draw);
+
+ SkASSERT(draw.fDevice == this);
+ draw.drawTextOnPath((const char*)text, len, path, m, paint);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkGpuDevice::TexCache* SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap,
+ const GrSamplerState& sampler,
+ GrTexture** texture,
+ bool forDeviceRenderTarget) {
+ GrContext* ctx = this->context();
+ uint32_t p0, p1;
+ if (forDeviceRenderTarget) {
+ p0 = p1 = -1;
+ } else {
+ p0 = bitmap.getGenerationID();
+ p1 = bitmap.pixelRefOffset();
+ }
+
+ GrTexture* newTexture = NULL;
+ GrTextureKey key(p0, p1, bitmap.width(), bitmap.height());
+ GrTextureEntry* entry = ctx->findAndLockTexture(&key, sampler);
+
+ if (NULL == entry) {
+
+ if (forDeviceRenderTarget) {
+ const GrGpu::TextureDesc desc = {
+ GrGpu::kRenderTarget_TextureFlag,
+ GrGpu::kNone_AALevel,
+ bitmap.width(),
+ bitmap.height(),
+ SkGr::Bitmap2PixelConfig(bitmap)
+ };
+ entry = ctx->createAndLockTexture(&key, sampler, desc, NULL, 0);
+
+ } else {
+ entry = sk_gr_create_bitmap_texture(ctx, &key, sampler, bitmap);
+ }
+ if (NULL == entry) {
+ GrPrintf("---- failed to create texture for cache [%d %d]\n",
+ bitmap.width(), bitmap.height());
+ }
+ }
+
+ if (NULL != entry) {
+ newTexture = entry->texture();
+ ctx->setTexture(newTexture);
+ if (texture) {
+ *texture = newTexture;
+ }
+ // IMPORTANT: We can't allow another SkGpuDevice to get this
+ // cache entry until this one is destroyed!
+ if (forDeviceRenderTarget) {
+ ctx->detachCachedTexture(entry);
+ }
+ }
+ return (TexCache*)entry;
+}
+
+void SkGpuDevice::unlockCachedTexture(TexCache* cache) {
+ this->context()->unlockTexture((GrTextureEntry*)cache);
+}
+
+
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
new file mode 100644
index 0000000000..8849db767a
--- /dev/null
+++ b/src/gpu/SkGr.cpp
@@ -0,0 +1,206 @@
+/*
+ Copyright 2010 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 "SkGr.h"
+
+/* Fill out buffer with the compressed format Ganesh expects from a colortable
+ based bitmap. [palette (colortable) + indices].
+
+ At the moment Ganesh only supports 8bit version. If Ganesh allowed we others
+ we could detect that the colortable.count is <= 16, and then repack the
+ indices as nibbles to save RAM, but it would take more time (i.e. a lot
+ slower than memcpy), so skipping that for now.
+
+ Ganesh wants a full 256 palette entry, even though Skia's ctable is only as big
+ as the colortable.count says it is.
+ */
+static void build_compressed_data(void* buffer, const SkBitmap& bitmap) {
+ SkASSERT(SkBitmap::kIndex8_Config == bitmap.config());
+
+ SkAutoLockPixels apl(bitmap);
+ if (!bitmap.readyToDraw()) {
+ SkASSERT(!"bitmap not ready to draw!");
+ return;
+ }
+
+ SkColorTable* ctable = bitmap.getColorTable();
+ char* dst = (char*)buffer;
+
+ memcpy(dst, ctable->lockColors(), ctable->count() * sizeof(SkPMColor));
+ ctable->unlockColors(false);
+
+ // always skip a full 256 number of entries, even if we memcpy'd fewer
+ dst += GrGpu::kColorTableSize;
+
+ if (bitmap.width() == bitmap.rowBytes()) {
+ memcpy(dst, bitmap.getPixels(), bitmap.getSize());
+ } else {
+ // need to trim off the extra bytes per row
+ size_t width = bitmap.width();
+ size_t rowBytes = bitmap.rowBytes();
+ const char* src = (const char*)bitmap.getPixels();
+ for (int y = 0; y < bitmap.height(); y++) {
+ memcpy(dst, src, width);
+ src += rowBytes;
+ dst += width;
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+GrTextureEntry* sk_gr_create_bitmap_texture(GrContext* ctx,
+ GrTextureKey* key,
+ const GrSamplerState& sampler,
+ const SkBitmap& origBitmap) {
+ SkAutoLockPixels alp(origBitmap);
+ if (!origBitmap.readyToDraw()) {
+ return NULL;
+ }
+
+ SkBitmap tmpBitmap;
+
+ const SkBitmap* bitmap = &origBitmap;
+
+ GrGpu::TextureDesc desc = {
+ 0,
+ GrGpu::kNone_AALevel,
+ bitmap->width(),
+ bitmap->height(),
+ SkGr::Bitmap2PixelConfig(*bitmap)
+ };
+
+ if (SkBitmap::kIndex8_Config == bitmap->config()) {
+ // build_compressed_data doesn't do npot->pot expansion
+ // and paletted textures can't be sub-updated
+ if (ctx->supportsIndex8PixelConfig(sampler,
+ bitmap->width(), bitmap->height())) {
+ size_t imagesize = bitmap->width() * bitmap->height() +
+ GrGpu::kColorTableSize;
+ SkAutoMalloc storage(imagesize);
+
+ build_compressed_data(storage.get(), origBitmap);
+
+ // our compressed data will be trimmed, so pass width() for its
+ // "rowBytes", since they are the same now.
+ return ctx->createAndLockTexture(key, sampler, desc, storage.get(),
+ bitmap->width());
+
+ } else {
+ origBitmap.copyTo(&tmpBitmap, SkBitmap::kARGB_8888_Config);
+ // now bitmap points to our temp, which has been promoted to 32bits
+ bitmap = &tmpBitmap;
+ }
+ }
+
+ desc.fFormat = SkGr::Bitmap2PixelConfig(*bitmap);
+ return ctx->createAndLockTexture(key, sampler, desc, bitmap->getPixels(),
+ bitmap->rowBytes());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void sk_gr_set_paint(GrContext* ctx, const SkPaint& paint, bool justAlpha) {
+ ctx->setDither(paint.isDither());
+ ctx->setAntiAlias(paint.isAntiAlias());
+
+ if (justAlpha) {
+ ctx->setAlpha(paint.getAlpha());
+ } else {
+ ctx->setColor(SkGr::SkColor2GrColor(paint.getColor()));
+ }
+
+ SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
+ SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
+
+ SkXfermode* mode = paint.getXfermode();
+ if (mode) {
+ mode->asCoeff(&sm, &dm);
+ }
+ ctx->setBlendFunc(sk_blend_to_grblend(sm), sk_blend_to_grblend(dm));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+SkGrPathIter::Command SkGrPathIter::next(GrPoint pts[]) {
+ GrAssert(NULL != pts);
+#if SK_SCALAR_IS_GR_SCALAR
+ return sk_path_verb_to_gr_path_command(fIter.next((SkPoint*)pts));
+#else
+ Command cmd = sk_path_verb_to_gr_path_command(fIter.next(fPoints));
+ int n = NumCommandPoints(cmd);
+ for (int i = 0; i < n; ++i) {
+ pts[i].fX = SkScalarToGrScalar(fPoints[i].fX);
+ pts[i].fY = SkScalarToGrScalar(fPoints[i].fY);
+ }
+ return cmd;
+#endif
+}
+
+SkGrPathIter::Command SkGrPathIter::next() {
+ return sk_path_verb_to_gr_path_command(fIter.next(NULL));
+}
+
+void SkGrPathIter::rewind() {
+ fIter.setPath(fPath, false);
+}
+
+GrPathIter::ConvexHint SkGrPathIter::hint() const {
+ return fPath.isConvex() ? GrPathIter::kConvex_ConvexHint :
+ GrPathIter::kNone_ConvexHint;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void SkGrClipIterator::computeBounds(GrIRect* bounds) {
+ const SkRegion* rgn = fIter.rgn();
+ if (rgn) {
+ SkGr::SetIRect(bounds, rgn->getBounds());
+ } else {
+ bounds->setEmpty();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrTexture::PixelConfig SkGr::BitmapConfig2PixelConfig(SkBitmap::Config config,
+ bool isOpaque) {
+ switch (config) {
+ case SkBitmap::kA8_Config:
+ return GrTexture::kAlpha_8_PixelConfig;
+ case SkBitmap::kIndex8_Config:
+ return GrTexture::kIndex_8_PixelConfig;
+ case SkBitmap::kRGB_565_Config:
+ return GrTexture::kRGB_565_PixelConfig;
+ case SkBitmap::kARGB_4444_Config:
+ return GrTexture::kRGBA_4444_PixelConfig;
+ case SkBitmap::kARGB_8888_Config:
+ if (isOpaque) {
+ return GrTexture::kRGBX_8888_PixelConfig;
+ } else {
+ return GrTexture::kRGBA_8888_PixelConfig;
+ }
+ default:
+ return GrTexture::kUnknown_PixelConfig;
+ }
+}
+
+void SkGr::AbandonAllTextures(GrContext* ctx) {
+ ctx->abandonAllTextures();
+}
+
+
diff --git a/src/gpu/SkGrFontScaler.cpp b/src/gpu/SkGrFontScaler.cpp
new file mode 100644
index 0000000000..5c88717b88
--- /dev/null
+++ b/src/gpu/SkGrFontScaler.cpp
@@ -0,0 +1,142 @@
+/*
+ Copyright 2010 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 "SkGr.h"
+#include "SkDescriptor.h"
+#include "SkGlyphCache.h"
+
+class SkGrDescKey : public GrKey {
+public:
+ explicit SkGrDescKey(const SkDescriptor& desc);
+ virtual ~SkGrDescKey();
+
+protected:
+ // overrides
+ virtual bool lt(const GrKey& rh) const;
+ virtual bool eq(const GrKey& rh) const;
+
+private:
+ SkDescriptor* fDesc;
+ enum {
+ kMaxStorageInts = 16
+ };
+ uint32_t fStorage[kMaxStorageInts];
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkGrDescKey::SkGrDescKey(const SkDescriptor& desc) : GrKey(desc.getChecksum()) {
+ size_t size = desc.getLength();
+ if (size <= sizeof(fStorage)) {
+ fDesc = (SkDescriptor*)fStorage;
+ } else {
+ fDesc = SkDescriptor::Alloc(size);
+ }
+ memcpy(fDesc, &desc, size);
+}
+
+SkGrDescKey::~SkGrDescKey() {
+ if (fDesc != (SkDescriptor*)fStorage) {
+ SkDescriptor::Free(fDesc);
+ }
+}
+
+bool SkGrDescKey::lt(const GrKey& rh) const {
+ const SkDescriptor* srcDesc = ((const SkGrDescKey*)&rh)->fDesc;
+ size_t lenLH = fDesc->getLength();
+ size_t lenRH = srcDesc->getLength();
+ int cmp = memcmp(fDesc, srcDesc, SkMin32(lenLH, lenRH));
+ if (0 == cmp) {
+ return lenLH < lenRH;
+ } else {
+ return cmp < 0;
+ }
+}
+
+bool SkGrDescKey::eq(const GrKey& rh) const {
+ const SkDescriptor* srcDesc = ((const SkGrDescKey*)&rh)->fDesc;
+ return fDesc->equals(*srcDesc);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkGrFontScaler::SkGrFontScaler(SkGlyphCache* strike) {
+ fStrike = strike;
+ fKey = NULL;
+}
+
+SkGrFontScaler::~SkGrFontScaler() {
+ GrSafeUnref(fKey);
+}
+
+const GrKey* SkGrFontScaler::getKey() {
+ if (NULL == fKey) {
+ fKey = new SkGrDescKey(fStrike->getDescriptor());
+ }
+ return fKey;
+}
+
+bool SkGrFontScaler::getPackedGlyphBounds(GrGlyph::PackedID packed,
+ GrIRect* bounds) {
+ const SkGlyph& glyph = fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(packed),
+ GrGlyph::UnpackFixedX(packed),
+ GrGlyph::UnpackFixedY(packed));
+ bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight);
+ return true;
+
+}
+
+bool SkGrFontScaler::getPackedGlyphImage(GrGlyph::PackedID packed,
+ int width, int height,
+ int dstRB, void* dst) {
+ const SkGlyph& glyph = fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(packed),
+ GrGlyph::UnpackFixedX(packed),
+ GrGlyph::UnpackFixedY(packed));
+ GrAssert(glyph.fWidth == width);
+ GrAssert(glyph.fHeight == height);
+ const void* src = fStrike->findImage(glyph);
+ if (NULL == src) {
+ return false;
+ }
+
+ int srcRB = glyph.rowBytes();
+ if (srcRB == dstRB) {
+ memcpy(dst, src, dstRB * height);
+ } else {
+ for (int y = 0; y < height; y++) {
+ memcpy(dst, src, width);
+ src = (const char*)src + srcRB;
+ dst = (char*)dst + dstRB;
+ }
+ }
+ return true;
+}
+
+bool SkGrFontScaler::getGlyphPath(uint16_t glyphID, GrPath* path) {
+
+ const SkGlyph& glyph = fStrike->getGlyphIDMetrics(glyphID);
+ const SkPath* skPath = fStrike->findPath(glyph);
+ if (skPath) {
+ SkGrPathIter iter(*skPath);
+ path->resetFromIter(&iter);
+ return true;
+ }
+ return false;
+}
+
+
+
diff --git a/src/gpu/SkGrTexturePixelRef.cpp b/src/gpu/SkGrTexturePixelRef.cpp
new file mode 100644
index 0000000000..da9ac1a692
--- /dev/null
+++ b/src/gpu/SkGrTexturePixelRef.cpp
@@ -0,0 +1,30 @@
+/*
+ Copyright 2010 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 "SkGrTexturePixelRef.h"
+#include "GrTexture.h"
+
+SkGrTexturePixelRef::SkGrTexturePixelRef(GrTexture* tex) {
+ fTexture = tex;
+ GrSafeRef(tex);
+}
+
+SkGrTexturePixelRef::~SkGrTexturePixelRef() {
+ GrSafeUnref(fTexture);
+}
+
+
diff --git a/src/gpu/skgr_files.mk b/src/gpu/skgr_files.mk
new file mode 100644
index 0000000000..7623fca241
--- /dev/null
+++ b/src/gpu/skgr_files.mk
@@ -0,0 +1,8 @@
+SOURCE := \
+ SkGpuCanvas.cpp \
+ SkGpuDevice.cpp \
+ SkGr.cpp \
+ SkGrTexturePixelRef.cpp \
+ SkGrFontScaler.cpp \
+ GrPrintf_skia.cpp
+
diff --git a/src/utils/mac/SkEGLContext_mac.cpp b/src/utils/mac/SkEGLContext_mac.cpp
new file mode 100644
index 0000000000..13bb5922ac
--- /dev/null
+++ b/src/utils/mac/SkEGLContext_mac.cpp
@@ -0,0 +1,65 @@
+#include "SkEGLContext.h"
+#include <AGL/agl.h>
+
+SkEGLContext::SkEGLContext() : fContext(NULL) {
+}
+
+SkEGLContext::~SkEGLContext() {
+ if (fContext) {
+ aglDestroyContext((AGLContext)fContext);
+ }
+}
+
+bool SkEGLContext::init(int width, int height) {
+ GLint major, minor;
+ AGLContext ctx;
+
+ aglGetVersion(&major, &minor);
+ SkDebugf("---- agl version %d %d\n", major, minor);
+
+ const GLint pixelAttrs[] = {
+ AGL_RGBA,
+ AGL_STENCIL_SIZE, 8,
+/*
+ AGL_SAMPLE_BUFFERS_ARB, 1,
+ AGL_MULTISAMPLE,
+ AGL_SAMPLES_ARB, 2,
+*/
+ AGL_ACCELERATED,
+ AGL_NONE
+ };
+ AGLPixelFormat format = aglChoosePixelFormat(NULL, 0, pixelAttrs);
+ //AGLPixelFormat format = aglCreatePixelFormat(pixelAttrs);
+ SkDebugf("----- agl format %p\n", format);
+ ctx = aglCreateContext(format, NULL);
+ SkDebugf("----- agl context %p\n", ctx);
+ aglDestroyPixelFormat(format);
+
+ SkDebugf("---- sizeof aglcontext %d\n", sizeof(AGLContext));
+/*
+ static const GLint interval = 1;
+ aglSetInteger(ctx, AGL_SWAP_INTERVAL, &interval);
+*/
+
+ aglSetCurrentContext(ctx);
+ fContext = (void*)ctx;
+
+ // Now create our FBO render target
+
+ GLuint fboID;
+ GLuint cbID;
+ GLuint dsID;
+ glGenFramebuffersEXT(1, &fboID);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboID);
+ glGenRenderbuffers(1, &cbID);
+ glBindRenderbuffer(GL_RENDERBUFFER, cbID);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, width, height);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, cbID);
+ glGenRenderbuffers(1, &dsID);
+ glBindRenderbuffer(GL_RENDERBUFFER, dsID);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, width, height);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, dsID);
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ return GL_FRAMEBUFFER_COMPLETE == status;
+}