| /* |
| 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 "GrTypes.h" |
| #include "GrTextureCache.h" |
| #include "GrTextStrike.h" |
| #include "GrMemory.h" |
| #include "GrPathIter.h" |
| #include "GrClipIterator.h" |
| #include "GrIndexBuffer.h" |
| #include "GrInOrderDrawBuffer.h" |
| #include "GrBufferAllocPool.h" |
| #include "GrPathRenderer.h" |
| |
| #define DEFER_TEXT_RENDERING 1 |
| |
| #define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB) |
| |
| static const size_t MAX_TEXTURE_CACHE_COUNT = 128; |
| static const size_t MAX_TEXTURE_CACHE_BYTES = 8 * 1024 * 1024; |
| |
| static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18; |
| static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4; |
| |
| // We are currently only batching Text and drawRectToRect, both |
| // of which use the quad index buffer. |
| static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0; |
| static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0; |
| |
| GrContext* GrContext::Create(GrGpu::Engine engine, |
| GrGpu::Platform3DContext context3D) { |
| GrContext* ctx = NULL; |
| GrGpu* fGpu = GrGpu::Create(engine, context3D); |
| if (NULL != fGpu) { |
| ctx = new GrContext(fGpu); |
| fGpu->unref(); |
| } |
| return ctx; |
| } |
| |
| GrContext* GrContext::CreateGLShaderContext() { |
| return GrContext::Create(GrGpu::kOpenGL_Shaders_Engine, NULL); |
| } |
| |
| GrContext::~GrContext() { |
| fGpu->unref(); |
| delete fTextureCache; |
| delete fFontCache; |
| delete fDrawBuffer; |
| delete fDrawBufferVBAllocPool; |
| delete fDrawBufferIBAllocPool; |
| delete fPathRenderer; |
| } |
| |
| void GrContext::abandonAllTextures() { |
| fTextureCache->deleteAll(GrTextureCache::kAbandonTexture_DeleteMode); |
| fFontCache->abandonAll(); |
| } |
| |
| GrTextureEntry* GrContext::findAndLockTexture(GrTextureKey* key, |
| const GrSamplerState& sampler) { |
| finalizeTextureKey(key, sampler); |
| return fTextureCache->findAndLock(*key); |
| } |
| |
| static void stretchImage(void* dst, |
| int dstW, |
| int dstH, |
| void* src, |
| int srcW, |
| int srcH, |
| int bpp) { |
| GrFixed dx = (srcW << 16) / dstW; |
| GrFixed dy = (srcH << 16) / dstH; |
| |
| GrFixed y = dy >> 1; |
| |
| int dstXLimit = dstW*bpp; |
| for (int j = 0; j < dstH; ++j) { |
| GrFixed x = dx >> 1; |
| void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp; |
| void* dstRow = (uint8_t*)dst + j*dstW*bpp; |
| for (int i = 0; i < dstXLimit; i += bpp) { |
| memcpy((uint8_t*) dstRow + i, |
| (uint8_t*) srcRow + (x>>16)*bpp, |
| bpp); |
| x += dx; |
| } |
| y += dy; |
| } |
| } |
| |
| GrTextureEntry* GrContext::createAndLockTexture(GrTextureKey* key, |
| const GrSamplerState& sampler, |
| const GrGpu::TextureDesc& desc, |
| void* srcData, size_t rowBytes) { |
| GrAssert(key->width() == desc.fWidth); |
| GrAssert(key->height() == desc.fHeight); |
| |
| #if GR_DUMP_TEXTURE_UPLOAD |
| GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight); |
| #endif |
| |
| GrTextureEntry* entry = NULL; |
| bool special = finalizeTextureKey(key, sampler); |
| if (special) { |
| GrTextureEntry* clampEntry; |
| GrTextureKey clampKey(*key); |
| clampEntry = findAndLockTexture(&clampKey, GrSamplerState::ClampNoFilter()); |
| |
| if (NULL == clampEntry) { |
| clampEntry = createAndLockTexture(&clampKey, |
| GrSamplerState::ClampNoFilter(), |
| desc, srcData, rowBytes); |
| GrAssert(NULL != clampEntry); |
| if (NULL == clampEntry) { |
| return NULL; |
| } |
| } |
| GrGpu::TextureDesc rtDesc = desc; |
| rtDesc.fFlags |= GrGpu::kRenderTarget_TextureFlag | |
| GrGpu::kNoPathRendering_TextureFlag; |
| rtDesc.fWidth = GrNextPow2(GrMax<int>(desc.fWidth, |
| fGpu->minRenderTargetWidth())); |
| rtDesc.fHeight = GrNextPow2(GrMax<int>(desc.fHeight, |
| fGpu->minRenderTargetHeight())); |
| |
| GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0); |
| |
| if (NULL != texture) { |
| GrDrawTarget::AutoStateRestore asr(fGpu); |
| fGpu->setRenderTarget(texture->asRenderTarget()); |
| fGpu->setTexture(0, clampEntry->texture()); |
| fGpu->setStencilPass(GrDrawTarget::kNone_StencilPass); |
| fGpu->setViewMatrix(GrMatrix::I()); |
| fGpu->setAlpha(0xff); |
| fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff); |
| fGpu->disableState(GrDrawTarget::kDither_StateBit | |
| GrDrawTarget::kClip_StateBit | |
| GrDrawTarget::kAntialias_StateBit); |
| GrSamplerState stretchSampler(GrSamplerState::kClamp_WrapMode, |
| GrSamplerState::kClamp_WrapMode, |
| sampler.isFilter()); |
| fGpu->setSamplerState(0, stretchSampler); |
| |
| static const GrVertexLayout layout = |
| GrDrawTarget::StageTexCoordVertexLayoutBit(0,0); |
| GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0); |
| |
| if (arg.succeeded()) { |
| GrPoint* verts = (GrPoint*) arg.vertices(); |
| verts[0].setIRectFan(0, 0, |
| texture->width(), |
| texture->height(), |
| 2*sizeof(GrPoint)); |
| verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint)); |
| fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, |
| 0, 4); |
| entry = fTextureCache->createAndLock(*key, texture); |
| } |
| texture->removeRenderTarget(); |
| } else { |
| // TODO: Our CPU stretch doesn't filter. But we create separate |
| // stretched textures when the sampler state is either filtered or |
| // not. Either implement filtered stretch blit on CPU or just create |
| // one when FBO case fails. |
| |
| rtDesc.fFlags = 0; |
| // 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); |
| GrAutoSMalloc<128*128*4> stretchedPixels(bpp * |
| rtDesc.fWidth * |
| rtDesc.fHeight); |
| stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight, |
| srcData, desc.fWidth, desc.fHeight, bpp); |
| |
| size_t stretchedRowBytes = rtDesc.fWidth * bpp; |
| |
| GrTexture* texture = fGpu->createTexture(rtDesc, |
| stretchedPixels.get(), |
| stretchedRowBytes); |
| GrAssert(NULL != texture); |
| entry = fTextureCache->createAndLock(*key, texture); |
| } |
| fTextureCache->unlock(clampEntry); |
| |
| } else { |
| GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes); |
| if (NULL != texture) { |
| entry = fTextureCache->createAndLock(*key, texture); |
| } else { |
| entry = NULL; |
| } |
| } |
| return entry; |
| } |
| |
| void GrContext::unlockTexture(GrTextureEntry* entry) { |
| fTextureCache->unlock(entry); |
| } |
| |
| void GrContext::detachCachedTexture(GrTextureEntry* entry) { |
| fTextureCache->detach(entry); |
| } |
| |
| void GrContext::reattachAndUnlockCachedTexture(GrTextureEntry* entry) { |
| fTextureCache->reattachAndUnlock(entry); |
| } |
| |
| GrTexture* GrContext::createUncachedTexture(const GrGpu::TextureDesc& desc, |
| void* srcData, |
| size_t rowBytes) { |
| return fGpu->createTexture(desc, srcData, rowBytes); |
| } |
| |
| void GrContext::getTextureCacheLimits(int* maxTextures, |
| size_t* maxTextureBytes) const { |
| fTextureCache->getLimits(maxTextures, maxTextureBytes); |
| } |
| |
| void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) { |
| fTextureCache->setLimits(maxTextures, maxTextureBytes); |
| } |
| |
| int GrContext::getMaxTextureDimension() { |
| return fGpu->maxTextureDimension(); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| GrRenderTarget* GrContext::createPlatformRenderTarget( |
| intptr_t platformRenderTarget, |
| int stencilBits, |
| int width, int height) { |
| return fGpu->createPlatformRenderTarget(platformRenderTarget, stencilBits, |
| width, height); |
| } |
| |
| bool GrContext::supportsIndex8PixelConfig(const GrSamplerState& sampler, |
| int width, int height) { |
| if (!fGpu->supports8BitPalette()) { |
| return false; |
| } |
| |
| |
| bool isPow2 = GrIsPow2(width) && GrIsPow2(height); |
| |
| if (!isPow2) { |
| if (!fGpu->npotTextureSupport()) { |
| return false; |
| } |
| |
| bool tiled = sampler.getWrapX() != GrSamplerState::kClamp_WrapMode || |
| sampler.getWrapY() != GrSamplerState::kClamp_WrapMode; |
| if (tiled && !fGpu->npotTextureTileSupport()) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| void GrContext::setClip(const GrClip& clip) { |
| fGpu->setClip(clip); |
| fGpu->enableState(GrDrawTarget::kClip_StateBit); |
| } |
| |
| void GrContext::setClip(const GrIRect& rect) { |
| GrClip clip; |
| clip.setRect(rect); |
| fGpu->setClip(clip); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| void GrContext::eraseColor(GrColor color) { |
| fGpu->eraseColor(color); |
| } |
| |
| void GrContext::drawPaint(const GrPaint& paint) { |
| // set rect to be big enough to fill the space, but not super-huge, so we |
| // don't overflow fixed-point implementations |
| GrRect r(fGpu->getClip().getBounds()); |
| GrMatrix inverse; |
| if (fGpu->getViewInverse(&inverse)) { |
| inverse.mapRect(&r); |
| } else { |
| GrPrintf("---- fGpu->getViewInverse failed\n"); |
| } |
| this->drawRect(paint, r); |
| } |
| |
| /* create a triangle strip that strokes the specified triangle. There are 8 |
| unique vertices, but we repreat the last 2 to close up. Alternatively we |
| could use an indices array, and then only send 8 verts, but not sure that |
| would be faster. |
| */ |
| static void setStrokeRectStrip(GrPoint verts[10], const GrRect& rect, |
| GrScalar width) { |
| const GrScalar rad = GrScalarHalf(width); |
| |
| verts[0].set(rect.fLeft + rad, rect.fTop + rad); |
| verts[1].set(rect.fLeft - rad, rect.fTop - rad); |
| verts[2].set(rect.fRight - rad, rect.fTop + rad); |
| verts[3].set(rect.fRight + rad, rect.fTop - rad); |
| verts[4].set(rect.fRight - rad, rect.fBottom - rad); |
| verts[5].set(rect.fRight + rad, rect.fBottom + rad); |
| verts[6].set(rect.fLeft + rad, rect.fBottom - rad); |
| verts[7].set(rect.fLeft - rad, rect.fBottom + rad); |
| verts[8] = verts[0]; |
| verts[9] = verts[1]; |
| } |
| |
| void GrContext::drawRect(const GrPaint& paint, |
| const GrRect& rect, |
| GrScalar width, |
| const GrMatrix* matrix) { |
| |
| bool textured = NULL != paint.getTexture(); |
| |
| GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); |
| |
| if (width >= 0) { |
| // TODO: consider making static vertex buffers for these cases. |
| // Hairline could be done by just adding closing vertex to |
| // unitSquareVertexBuffer() |
| GrVertexLayout layout = (textured) ? |
| GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) : |
| 0; |
| static const int worstCaseVertCount = 10; |
| GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0); |
| |
| if (!geo.succeeded()) { |
| return; |
| } |
| |
| GrPrimitiveType primType; |
| int vertCount; |
| GrPoint* vertex = geo.positions(); |
| |
| if (width > 0) { |
| vertCount = 10; |
| primType = kTriangleStrip_PrimitiveType; |
| setStrokeRectStrip(vertex, rect, width); |
| } else { |
| // hairline |
| vertCount = 5; |
| primType = kLineStrip_PrimitiveType; |
| vertex[0].set(rect.fLeft, rect.fTop); |
| vertex[1].set(rect.fRight, rect.fTop); |
| vertex[2].set(rect.fRight, rect.fBottom); |
| vertex[3].set(rect.fLeft, rect.fBottom); |
| vertex[4].set(rect.fLeft, rect.fTop); |
| } |
| |
| GrDrawTarget::AutoViewMatrixRestore avmr; |
| if (NULL != matrix) { |
| avmr.set(target); |
| target->preConcatViewMatrix(*matrix); |
| target->preConcatSamplerMatrix(0, *matrix); |
| } |
| |
| target->drawNonIndexed(primType, 0, vertCount); |
| } else { |
| #if GR_STATIC_RECT_VB |
| GrVertexLayout layout = (textured) ? |
| GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0) : |
| 0; |
| target->setVertexSourceToBuffer(layout, |
| fGpu->getUnitSquareVertexBuffer()); |
| GrDrawTarget::AutoViewMatrixRestore avmr(target); |
| GrMatrix m; |
| m.setAll(rect.width(), 0, rect.fLeft, |
| 0, rect.height(), rect.fTop, |
| 0, 0, GrMatrix::I()[8]); |
| |
| if (NULL != matrix) { |
| m.postConcat(*matrix); |
| } |
| |
| target->preConcatViewMatrix(m); |
| |
| if (textured) { |
| target->preConcatSamplerMatrix(0, m); |
| } |
| target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4); |
| #else |
| target->drawSimpleRect(rect, matrix, textured ? 1 : 0); |
| #endif |
| } |
| } |
| |
| void GrContext::drawRectToRect(const GrPaint& paint, |
| const GrRect& dstRect, |
| const GrRect& srcRect, |
| const GrMatrix* dstMatrix, |
| const GrMatrix* srcMatrix) { |
| |
| if (NULL == paint.getTexture()) { |
| drawRect(paint, dstRect, -1, dstMatrix); |
| return; |
| } |
| |
| GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB); |
| |
| #if GR_STATIC_RECT_VB |
| GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); |
| |
| GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0); |
| GrDrawTarget::AutoViewMatrixRestore avmr(target); |
| |
| GrMatrix m; |
| |
| m.setAll(dstRect.width(), 0, dstRect.fLeft, |
| 0, dstRect.height(), dstRect.fTop, |
| 0, 0, GrMatrix::I()[8]); |
| if (NULL != dstMatrix) { |
| m.postConcat(*dstMatrix); |
| } |
| target->preConcatViewMatrix(m); |
| |
| m.setAll(srcRect.width(), 0, srcRect.fLeft, |
| 0, srcRect.height(), srcRect.fTop, |
| 0, 0, GrMatrix::I()[8]); |
| if (NULL != srcMatrix) { |
| m.postConcat(*srcMatrix); |
| } |
| target->preConcatSamplerMatrix(0, m); |
| |
| target->setVertexSourceToBuffer(layout, fGpu->getUnitSquareVertexBuffer()); |
| target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4); |
| #else |
| |
| GrDrawTarget* target; |
| #if BATCH_RECT_TO_RECT |
| target = this->prepareToDraw(paint, kBuffered_DrawCategory); |
| #else |
| target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); |
| #endif |
| |
| const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL}; |
| const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL}; |
| srcRects[0] = &srcRect; |
| srcMatrices[0] = srcMatrix; |
| |
| target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices); |
| #endif |
| } |
| |
| void GrContext::drawVertices(const GrPaint& paint, |
| GrPrimitiveType primitiveType, |
| int vertexCount, |
| const GrPoint positions[], |
| const GrPoint texCoords[], |
| const GrColor colors[], |
| const uint16_t indices[], |
| int indexCount) { |
| GrVertexLayout layout = 0; |
| int vertexSize = sizeof(GrPoint); |
| |
| GrDrawTarget::AutoReleaseGeometry geo; |
| |
| GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); |
| |
| if (NULL != paint.getTexture()) { |
| if (NULL == texCoords) { |
| layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0); |
| } else { |
| layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(0,0); |
| vertexSize += sizeof(GrPoint); |
| } |
| } |
| |
| if (NULL != colors) { |
| layout |= GrDrawTarget::kColor_VertexLayoutBit; |
| vertexSize += sizeof(GrColor); |
| } |
| |
| if (sizeof(GrPoint) != vertexSize) { |
| if (!geo.set(target, layout, vertexCount, 0)) { |
| GrPrintf("Failed to get space for vertices!"); |
| return; |
| } |
| int texOffsets[GrDrawTarget::kMaxTexCoords]; |
| int colorOffset; |
| int vsize = GrDrawTarget::VertexSizeAndOffsetsByIdx(layout, |
| texOffsets, |
| &colorOffset); |
| void* curVertex = geo.vertices(); |
| |
| for (int i = 0; i < vertexCount; ++i) { |
| *((GrPoint*)curVertex) = positions[i]; |
| |
| if (texOffsets[0] > 0) { |
| *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i]; |
| } |
| if (colorOffset > 0) { |
| *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i]; |
| } |
| curVertex = (void*)((intptr_t)curVertex + vsize); |
| } |
| } else { |
| target->setVertexSourceToArray(layout, positions, vertexCount); |
| } |
| |
| if (NULL != indices) { |
| target->setIndexSourceToArray(indices, indexCount); |
| target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount); |
| } else { |
| target->drawNonIndexed(primitiveType, 0, vertexCount); |
| } |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| void GrContext::drawPath(const GrPaint& paint, |
| GrPathIter* path, |
| GrPathFill fill, |
| const GrPoint* translate) { |
| |
| |
| GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); |
| |
| GrDrawTarget::StageBitfield enabledStages = 0; |
| if (NULL != paint.getTexture()) { |
| enabledStages |= 1; |
| } |
| fPathRenderer->drawPath(target, enabledStages, path, fill, translate); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| void GrContext::flush(bool flushRenderTarget) { |
| flushDrawBuffer(); |
| if (flushRenderTarget) { |
| fGpu->forceRenderTargetFlush(); |
| } |
| } |
| |
| void GrContext::flushText() { |
| if (kText_DrawCategory == fLastDrawCategory) { |
| flushDrawBuffer(); |
| } |
| } |
| |
| void GrContext::flushDrawBuffer() { |
| #if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING |
| fDrawBuffer->playback(fGpu); |
| fDrawBuffer->reset(); |
| #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); |
| } |
| |
| void GrContext::writePixels(int left, int top, int width, int height, |
| GrTexture::PixelConfig config, const void* buffer, |
| size_t stride) { |
| |
| // TODO: when underlying api has a direct way to do this we should use it |
| // (e.g. glDrawPixels on desktop GL). |
| |
| const GrGpu::TextureDesc desc = { |
| 0, GrGpu::kNone_AALevel, width, height, config |
| }; |
| GrTexture* texture = fGpu->createTexture(desc, buffer, stride); |
| if (NULL == texture) { |
| return; |
| } |
| |
| this->flush(true); |
| |
| GrAutoUnref aur(texture); |
| GrDrawTarget::AutoStateRestore asr(fGpu); |
| |
| GrMatrix matrix; |
| matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top)); |
| fGpu->setViewMatrix(matrix); |
| |
| fGpu->disableState(GrDrawTarget::kClip_StateBit); |
| fGpu->setAlpha(0xFF); |
| fGpu->setBlendFunc(kOne_BlendCoeff, |
| kZero_BlendCoeff); |
| fGpu->setTexture(0, texture); |
| |
| GrSamplerState sampler; |
| sampler.setClampNoFilter(); |
| matrix.setScale(GR_Scalar1 / width, GR_Scalar1 / height); |
| sampler.setMatrix(matrix); |
| fGpu->setSamplerState(0, sampler); |
| |
| GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0); |
| static const int VCOUNT = 4; |
| |
| GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0); |
| if (!geo.succeeded()) { |
| return; |
| } |
| ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height); |
| fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT); |
| } |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) { |
| target->setTexture(0, paint.getTexture()); |
| target->setSamplerState(0, paint.fSampler); |
| target->setColor(paint.fColor); |
| |
| if (paint.fDither) { |
| target->enableState(GrDrawTarget::kDither_StateBit); |
| } else { |
| target->disableState(GrDrawTarget::kDither_StateBit); |
| } |
| if (paint.fAntiAlias) { |
| target->enableState(GrDrawTarget::kAntialias_StateBit); |
| } else { |
| target->disableState(GrDrawTarget::kAntialias_StateBit); |
| } |
| target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff); |
| } |
| |
| GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint, |
| DrawCategory category) { |
| if (category != fLastDrawCategory) { |
| flushDrawBuffer(); |
| fLastDrawCategory = category; |
| } |
| SetPaint(paint, fGpu); |
| GrDrawTarget* target = fGpu; |
| switch (category) { |
| case kText_DrawCategory: |
| #if DEFER_TEXT_RENDERING |
| target = fDrawBuffer; |
| fDrawBuffer->initializeDrawStateAndClip(*fGpu); |
| #else |
| target = fGpu; |
| #endif |
| break; |
| case kUnbuffered_DrawCategory: |
| target = fGpu; |
| break; |
| case kBuffered_DrawCategory: |
| target = fDrawBuffer; |
| fDrawBuffer->initializeDrawStateAndClip(*fGpu); |
| break; |
| } |
| return target; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| void GrContext::resetContext() { |
| fGpu->resetContext(); |
| } |
| |
| void GrContext::setRenderTarget(GrRenderTarget* target) { |
| flush(false); |
| fGpu->setRenderTarget(target); |
| } |
| |
| GrRenderTarget* GrContext::getRenderTarget() { |
| return fGpu->getRenderTarget(); |
| } |
| |
| const GrRenderTarget* GrContext::getRenderTarget() const { |
| return fGpu->getRenderTarget(); |
| } |
| |
| const GrMatrix& GrContext::getMatrix() const { |
| return fGpu->getViewMatrix(); |
| } |
| |
| void GrContext::setMatrix(const GrMatrix& m) { |
| fGpu->setViewMatrix(m); |
| } |
| |
| void GrContext::concatMatrix(const GrMatrix& m) const { |
| fGpu->preConcatViewMatrix(m); |
| } |
| |
| static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) { |
| intptr_t mask = 1 << shift; |
| if (pred) { |
| bits |= mask; |
| } else { |
| bits &= ~mask; |
| } |
| return bits; |
| } |
| |
| void GrContext::resetStats() { |
| fGpu->resetStats(); |
| } |
| |
| const GrGpu::Stats& GrContext::getStats() const { |
| return fGpu->getStats(); |
| } |
| |
| void GrContext::printStats() const { |
| fGpu->printStats(); |
| } |
| |
| GrContext::GrContext(GrGpu* gpu) { |
| fGpu = gpu; |
| fGpu->ref(); |
| fTextureCache = new GrTextureCache(MAX_TEXTURE_CACHE_COUNT, |
| MAX_TEXTURE_CACHE_BYTES); |
| fFontCache = new GrFontCache(fGpu); |
| |
| fLastDrawCategory = kUnbuffered_DrawCategory; |
| |
| #if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT |
| fDrawBufferVBAllocPool = |
| new GrVertexBufferAllocPool(gpu, false, |
| DRAW_BUFFER_VBPOOL_BUFFER_SIZE, |
| DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS); |
| fDrawBufferIBAllocPool = |
| new GrIndexBufferAllocPool(gpu, false, |
| DRAW_BUFFER_IBPOOL_BUFFER_SIZE, |
| DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS); |
| |
| fDrawBuffer = new GrInOrderDrawBuffer(fDrawBufferVBAllocPool, |
| fDrawBufferIBAllocPool); |
| #else |
| fDrawBuffer = NULL; |
| fDrawBufferVBAllocPool = NULL; |
| fDrawBufferIBAllocPool = NULL; |
| #endif |
| |
| #if BATCH_RECT_TO_RECT |
| fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer()); |
| #endif |
| fPathRenderer = new GrDefaultPathRenderer(fGpu->supportsSingleStencilPassWinding()); |
| } |
| |
| bool GrContext::finalizeTextureKey(GrTextureKey* key, |
| const GrSamplerState& sampler) const { |
| uint32_t bits = 0; |
| uint16_t width = key->width(); |
| uint16_t height = key->height(); |
| |
| |
| if (!fGpu->npotTextureTileSupport()) { |
| bool isPow2 = GrIsPow2(width) && GrIsPow2(height); |
| |
| bool tiled = (sampler.getWrapX() != GrSamplerState::kClamp_WrapMode) || |
| (sampler.getWrapY() != GrSamplerState::kClamp_WrapMode); |
| |
| if (tiled && !isPow2) { |
| bits |= 1; |
| bits |= sampler.isFilter() ? 2 : 0; |
| } |
| } |
| key->finalize(bits); |
| return 0 != bits; |
| } |
| |
| GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) { |
| GrDrawTarget* target; |
| #if DEFER_TEXT_RENDERING |
| target = prepareToDraw(paint, kText_DrawCategory); |
| #else |
| target = prepareToDraw(paint, kUnbuffered_DrawCategory); |
| #endif |
| SetPaint(paint, target); |
| return target; |
| } |
| |
| const GrIndexBuffer* GrContext::getQuadIndexBuffer() const { |
| return fGpu->getQuadIndexBuffer(); |
| } |